diff --git a/app/package-lock.json b/app/package-lock.json
index 5d92f68..fa04c9f 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -30,6 +30,7 @@
"glob": "^11.0.0",
"gsap": "^3.12.5",
"html2canvas": "^1.4.1",
+ "immer": "^10.1.1",
"leva": "^0.10.0",
"mqtt": "^5.10.4",
"postprocessing": "^6.36.4",
@@ -12746,9 +12747,10 @@
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
},
"node_modules/immer": {
- "version": "9.0.21",
- "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
- "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
+ "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
+ "license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
@@ -18010,6 +18012,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/react-dev-utils/node_modules/immer": {
+ "version": "9.0.21",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+ "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/react-dev-utils/node_modules/loader-utils": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz",
diff --git a/app/package.json b/app/package.json
index e555d5f..66158c0 100644
--- a/app/package.json
+++ b/app/package.json
@@ -25,6 +25,7 @@
"glob": "^11.0.0",
"gsap": "^3.12.5",
"html2canvas": "^1.4.1",
+ "immer": "^10.1.1",
"leva": "^0.10.0",
"mqtt": "^5.10.4",
"postprocessing": "^6.36.4",
diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx
index 5477790..66e185a 100644
--- a/app/src/components/layout/sidebarLeft/Assets.tsx
+++ b/app/src/components/layout/sidebarLeft/Assets.tsx
@@ -73,7 +73,7 @@ const Assets: React.FC = () => {
try {
const filt = await fetchAssets();
setFiltereredAssets(filt);
- } catch { }
+ } catch {}
};
filteredAssets();
}, [categoryAssets]);
@@ -135,7 +135,7 @@ const Assets: React.FC = () => {
const res = await getCategoryAsset(asset);
setCategoryAssets(res);
setFiltereredAssets(res);
- } catch (error) { }
+ } catch (error) {}
}
};
return (
@@ -151,7 +151,12 @@ const Assets: React.FC = () => {
{categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
-
+

{
{categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
-
+

+ onPointerDown={() => {
setSelectedItem({
name: asset.filename,
id: asset.AssetID,
- })
- }
+ type:
+ asset.type === "undefined" ? undefined : asset.type,
+ });
+ }}
/>
diff --git a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx
index e0b56d4..dc412f7 100644
--- a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx
+++ b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx
@@ -5,8 +5,8 @@ import Header from "./Header";
import useToggleStore from "../../../store/useUIToggleStore";
import Assets from "./Assets";
import useModuleStore from "../../../store/useModuleStore";
-import Widgets from "./visualization/widgets/Widgets";
-import Templates from "../../../modules/visualization/template/Templates";
+import Widgets from ".//visualization/widgets/Widgets";
+import Templates from "../../../modules//visualization/template/Templates";
import Search from "../../ui/inputs/Search";
const SideBarLeft: React.FC = () => {
diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx
index b5ae0bb..50d9712 100644
--- a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx
+++ b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx
@@ -5,11 +5,11 @@ import {
GlobeIcon,
WalletIcon,
} from "../../../../icons/3dChartIcons";
-import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
+import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
-import WarehouseThroughput from "../../../../../modules/visualization/widgets/floating/cards/WarehouseThroughput";
-import ProductivityDashboard from "../../../../../modules/visualization/widgets/floating/cards/ProductivityDashboard";
-import FleetEfficiency from "../../../../../modules/visualization/widgets/floating/cards/FleetEfficiency";
+import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput";
+import ProductivityDashboard from "../../../../../modules//visualization/widgets/floating/cards/ProductivityDashboard";
+import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency";
interface Widget {
id: string;
diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx
index 6922314..f9f48fb 100644
--- a/app/src/components/layout/sidebarRight/Header.tsx
+++ b/app/src/components/layout/sidebarRight/Header.tsx
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
import { AppDockIcon } from "../../icons/HeaderIcons";
import orgImg from "../../../assets/orgTemp.png";
import { useActiveUsers } from "../../../store/store";
-import { getAvatarColor } from "../../../modules/collaboration/users/functions/getAvatarColor";
+import { getAvatarColor } from "../../../functions/users/functions/getAvatarColor";
import { ActiveUser } from "../../../types/users";
import CollaborationPopup from "../../templates/CollaborationPopup";
diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx
index f991478..277637a 100644
--- a/app/src/components/layout/sidebarRight/SideBarRight.tsx
+++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx
@@ -10,33 +10,61 @@ import {
SimulationIcon,
} from "../../icons/SimulationIcons";
import useToggleStore from "../../../store/useUIToggleStore";
-import ConveyorMechanics from "./mechanics/ConveyorMechanics";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
-import {
- useSelectedActionSphere,
- useSelectedFloorItem,
-} from "../../../store/store";
+import { useSelectedFloorItem } from "../../../store/store";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties";
-import VehicleMechanics from "./mechanics/VehicleMechanics";
-import StaticMachineMechanics from "./mechanics/StaticMachineMechanics";
-import ArmBotMechanics from "./mechanics/ArmBotMechanics";
+import EventProperties from "./properties/eventProperties/EventProperties";
const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore();
const { toggleUI } = useToggleStore();
- const { selectedActionSphere } = useSelectedActionSphere();
const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem();
+
// Reset activeList whenever activeModule changes
useEffect(() => {
if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("mechanics");
}, [activeModule]);
+ // romove late
+ const dummyData = {
+ assetType: "store",
+ selectedPoint: {
+ name: "Point A",
+ uuid: "123e4567-e89b-12d3-a456-426614174000",
+ actions: [
+ {
+ uuid: "action-1",
+ name: "Action One",
+ },
+ {
+ uuid: "action-2",
+ name: "Action Two",
+ },
+ {
+ uuid: "action-3",
+ name: "Action Three",
+ },
+ ],
+ },
+ selectedItem: {
+ item: {
+ uuid: "item-1",
+ name: "Item One",
+ isUsed: false,
+ },
+ },
+ setSelectedPoint: (value: string) => {
+ console.log(`Selected point updated to: ${value}`);
+ },
+ selectedActionSphere: "Sphere A",
+ };
+
return (
@@ -44,8 +72,9 @@ const SideBarRight: React.FC = () => {
{/* {activeModule === "builder" && ( */}
setSubModule("properties")}
>
@@ -54,22 +83,25 @@ const SideBarRight: React.FC = () => {
{activeModule === "simulation" && (
<>
setSubModule("mechanics")}
>
setSubModule("simulations")}
>
setSubModule("analysis")}
>
@@ -112,46 +144,10 @@ const SideBarRight: React.FC = () => {
{toggleUI && activeModule === "simulation" && (
<>
- {subModule === "mechanics" &&
- selectedActionSphere &&
- selectedActionSphere.path.type === "Conveyor" && (
-
- )}
- {subModule === "mechanics" &&
- selectedActionSphere &&
- selectedActionSphere.path.type === "Vehicle" && (
-
- )}
- {subModule === "mechanics" &&
- selectedActionSphere &&
- selectedActionSphere.path.type === "StaticMachine" && (
-
- )}
- {subModule === "mechanics" &&
- selectedActionSphere &&
- selectedActionSphere.path.type === "ArmBot" && (
-
- )}
- {subModule === "mechanics" && !selectedActionSphere && (
+ {subModule === "mechanics" && (
)}
diff --git a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx
deleted file mode 100644
index 70e297b..0000000
--- a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx
+++ /dev/null
@@ -1,411 +0,0 @@
-import React, { useRef, useMemo, useCallback, useState } from "react";
-import { InfoIcon, AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons";
-import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
-import { useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
-import * as SimulationTypes from '../../../../types/simulationTypes';
-import LabledDropdown from "../../../ui/inputs/LabledDropdown";
-import { handleResize } from "../../../../functions/handleResizePannel";
-
-interface ConnectedModel {
- modelUUID: string;
- modelName: string;
- points: {
- uuid: string;
- position: [number, number, number];
- index?: number;
- }[];
- triggers?: {
- uuid: string;
- name: string;
- type: string;
- isUsed: boolean;
- }[];
-}
-
-const ArmBotMechanics: React.FC = () => {
- const { selectedActionSphere } = useSelectedActionSphere();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { socket } = useSocketStore();
- const [selectedProcessIndex, setSelectedProcessIndex] = useState
(null);
- const actionsContainerRef = useRef(null);
-
- // Get connected models and their triggers
- const connectedModels = useMemo(() => {
- if (!selectedActionSphere?.points?.uuid) return [];
-
- const armBotPaths = simulationStates.filter(
- (path): path is SimulationTypes.ArmBotEventsSchema => path.type === "ArmBot"
- );
-
- const currentPoint = armBotPaths.find(
- (path) => path.points.uuid === selectedActionSphere.points.uuid
- )?.points;
-
- if (!currentPoint?.connections?.targets) return [];
-
- return currentPoint.connections.targets.reduce((acc, target) => {
- const connectedModel = simulationStates.find(
- (model) => model.modeluuid === target.modelUUID
- );
-
- if (!connectedModel) return acc;
-
- let triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] = [];
- let points: { uuid: string; position: [number, number, number] }[] = [];
-
- if (connectedModel.type === "Conveyor") {
- const conveyor = connectedModel as SimulationTypes.ConveyorEventsSchema;
-
- const connectedPointUUIDs = currentPoint?.connections?.targets
- .filter(t => t.modelUUID === connectedModel.modeluuid)
- .map(t => t.pointUUID) || [];
-
- points = conveyor.points
- .map((point, idx) => ({
- uuid: point.uuid,
- position: point.position,
- index: idx
- }))
- .filter(point => connectedPointUUIDs.includes(point.uuid));
-
-
- triggers = conveyor.points.flatMap(p => p.triggers?.filter(t => t.isUsed) || []);
- }
- else if (connectedModel.type === "StaticMachine") {
- const staticMachine = connectedModel as SimulationTypes.StaticMachineEventsSchema;
-
- points = [{
- uuid: staticMachine.points.uuid,
- position: staticMachine.points.position
- }];
-
- triggers = staticMachine.points.triggers ?
- [{
- uuid: staticMachine.points.triggers.uuid,
- name: staticMachine.points.triggers.name,
- type: staticMachine.points.triggers.type,
- isUsed: true // StaticMachine triggers are always considered used
- }] : [];
- }
-
- if (!acc.some(m => m.modelUUID === connectedModel.modeluuid)) {
- acc.push({
- modelUUID: connectedModel.modeluuid,
- modelName: connectedModel.modelName,
- points,
- triggers
- });
- }
-
- return acc;
- }, []);
- }, [selectedActionSphere, simulationStates]);
-
- // Get triggers from connected models
- const connectedTriggers = useMemo(() => {
- return connectedModels.flatMap(model =>
- (model.triggers || []).map(trigger => ({
- ...trigger,
- displayName: `${model.modelName} - ${trigger.name}`,
- modelUUID: model.modelUUID
- }))
- );
- }, [connectedModels]);
-
- // Get all points from connected models
- const connectedPoints = useMemo(() => {
- return connectedModels.flatMap(model =>
- model.points.map(point => ({
- ...point,
- displayName: `${model.modelName} - Point${typeof point.index === 'number' ? ` ${point.index}` : ''}`,
- modelUUID: model.modelUUID
- }))
- );
- }, [connectedModels]);
-
-
- const { selectedPoint } = useMemo(() => {
- if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null };
-
- const armBotPaths = simulationStates.filter(
- (path): path is SimulationTypes.ArmBotEventsSchema => path.type === "ArmBot"
- );
-
- const points = armBotPaths.find(
- (path) => path.points.uuid === selectedActionSphere.points.uuid
- )?.points;
-
- return {
- selectedPoint: points || null
- };
- }, [selectedActionSphere, simulationStates]);
-
- const updateBackend = async (updatedPath: SimulationTypes.ArmBotEventsSchema | undefined) => {
- if (!updatedPath) return;
- const email = localStorage.getItem("email");
- const organization = email ? email.split("@")[1].split(".")[0] : "";
-
- const data = {
- organization: organization,
- modeluuid: updatedPath.modeluuid,
- eventData: { type: "ArmBot", points: updatedPath.points }
- }
-
- socket.emit('v2:model-asset:updateEventData', data);
- }
-
- const handleActionUpdate = useCallback((updatedAction: Partial) => {
- if (!selectedActionSphere?.points?.uuid || !selectedPoint) return;
-
- const updatedPaths = simulationStates.map((path) => {
- if (path.type === "ArmBot" && path.points.uuid === selectedActionSphere.points.uuid) {
- return {
- ...path,
- points: {
- ...path.points,
- actions: {
- ...path.points.actions,
- ...updatedAction
- }
- }
- };
- }
- return path;
- });
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ArmBotEventsSchema =>
- path.type === "ArmBot" &&
- path.points.uuid === selectedActionSphere.points.uuid
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- }, [selectedActionSphere?.points?.uuid, selectedPoint, simulationStates, setSimulationStates]);
-
- const handleSpeedChange = useCallback((speed: number) => {
- handleActionUpdate({ speed });
- }, [handleActionUpdate]);
-
- const handleProcessChange = useCallback((processes: SimulationTypes.ArmBotEventsSchema['points']['actions']['processes']) => {
- handleActionUpdate({ processes });
- }, [handleActionUpdate]);
-
- const handleAddProcess = useCallback(() => {
- if (!selectedPoint) return;
-
- const newProcess: any = {
- triggerId: "",
- startPoint: "",
- endPoint: ""
- };
-
- const updatedProcesses = selectedPoint.actions.processes ? [...selectedPoint.actions.processes, newProcess] : [newProcess];
-
- handleProcessChange(updatedProcesses);
- setSelectedProcessIndex(updatedProcesses.length - 1);
- }, [selectedPoint, handleProcessChange]);
-
- const handleDeleteProcess = useCallback((index: number) => {
- if (!selectedPoint?.actions.processes) return;
-
- const updatedProcesses = [...selectedPoint.actions.processes];
- updatedProcesses.splice(index, 1);
-
- handleProcessChange(updatedProcesses);
-
- // Reset selection if deleting the currently selected process
- if (selectedProcessIndex === index) {
- setSelectedProcessIndex(null);
- } else if (selectedProcessIndex !== null && selectedProcessIndex > index) {
- // Adjust selection index if needed
- setSelectedProcessIndex(selectedProcessIndex - 1);
- }
- }, [selectedPoint, selectedProcessIndex, handleProcessChange]);
-
- const handleTriggerSelect = useCallback((displayName: string, index: number) => {
- const availableOptions = getFilteredTriggerOptions(index);
- const selectedDisplayIndex = availableOptions.indexOf(displayName);
-
- const filteredTriggers = connectedTriggers.filter(trigger =>
- !selectedPoint?.actions.processes
- ?.filter((_, i) => i !== index)
- .map(p => p.triggerId)
- .includes(trigger.uuid)
- );
-
- const selected = filteredTriggers[selectedDisplayIndex];
-
- if (!selected || !selectedPoint?.actions.processes) return;
-
- const oldProcess = selectedPoint.actions.processes[index];
-
- const updatedProcesses = [...selectedPoint.actions.processes];
- updatedProcesses[index] = {
- ...oldProcess,
- triggerId: selected.uuid,
- startPoint: oldProcess.startPoint || "",
- endPoint: oldProcess.endPoint || ""
- };
-
- handleProcessChange(updatedProcesses);
- }, [connectedTriggers, selectedPoint, handleProcessChange]);
-
- const handleStartPointSelect = useCallback((displayName: string, index: number) => {
- if (!selectedPoint?.actions.processes) return;
-
- const point = connectedPoints.find(p => p.displayName === displayName);
- if (!point) return;
-
- const updatedProcesses = [...selectedPoint.actions.processes];
- updatedProcesses[index] = {
- ...updatedProcesses[index],
- startPoint: point.uuid
- };
-
- handleProcessChange(updatedProcesses);
- }, [selectedPoint, connectedPoints, handleProcessChange]);
-
- const handleEndPointSelect = useCallback((displayName: string, index: number) => {
- if (!selectedPoint?.actions.processes) return;
-
- const point = connectedPoints.find(p => p.displayName === displayName);
- if (!point) return;
-
- const updatedProcesses = [...selectedPoint.actions.processes];
- updatedProcesses[index] = {
- ...updatedProcesses[index],
- endPoint: point.uuid
- };
-
- handleProcessChange(updatedProcesses);
- }, [selectedPoint, connectedPoints, handleProcessChange]);
-
- const getProcessByIndex = useCallback((index: number) => {
- if (!selectedPoint?.actions.processes || index >= selectedPoint.actions.processes.length) return null;
- return selectedPoint.actions.processes[index];
- }, [selectedPoint]);
-
- const getFilteredTriggerOptions = (currentIndex: number) => {
- const usedTriggerUUIDs = selectedPoint?.actions.processes?.filter((_, i) => i !== currentIndex).map(p => p.triggerId).filter(Boolean) ?? [];
-
- return connectedTriggers.filter(trigger => !usedTriggerUUIDs.includes(trigger.uuid)).map(trigger => trigger.displayName);
- };
-
- return (
-
-
- {selectedActionSphere?.path?.modelName || "ArmBot point not found"}
-
-
-
-
-
ArmBot Properties
-
- {selectedPoint && (
- <>
-
handleSpeedChange(parseFloat(value))}
- />
-
-
-
-
-
- {selectedPoint.actions.processes?.map((process, index) => (
-
-
setSelectedProcessIndex(index)}
- >
- Process {index + 1}
-
-
handleDeleteProcess(index)}
- >
-
-
-
- ))}
-
-
handleResize(e, actionsContainerRef)}
- >
-
-
-
-
-
- {selectedProcessIndex !== null && (
-
-
- t.uuid === getProcessByIndex(selectedProcessIndex)?.triggerId
- )?.displayName || 'Select a trigger'
- }
- onSelect={(value) => handleTriggerSelect(value, selectedProcessIndex)}
- options={getFilteredTriggerOptions(selectedProcessIndex)}
- />
-
-
- p.uuid === getProcessByIndex(selectedProcessIndex)?.startPoint
- )?.displayName || 'Select start point'
- }
- onSelect={(value) => handleStartPointSelect(value, selectedProcessIndex)}
- options={connectedPoints.map(point => point.displayName)}
- />
-
-
- p.uuid === getProcessByIndex(selectedProcessIndex)?.endPoint
- )?.displayName || 'Select end point'
- }
- onSelect={(value) => handleEndPointSelect(value, selectedProcessIndex)}
- options={connectedPoints.map(point => point.displayName)}
- />
-
- )}
- >
- )}
-
-
-
-
- Configure ArmBot properties and trigger-based processes.
-
-
-
- );
-};
-
-export default React.memo(ArmBotMechanics);
\ No newline at end of file
diff --git a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx
deleted file mode 100644
index 5e84d10..0000000
--- a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx
+++ /dev/null
@@ -1,879 +0,0 @@
-import React, { useRef, useState, useMemo, useEffect } from "react";
-import {
- AddIcon,
- InfoIcon,
- RemoveIcon,
- ResizeHeightIcon,
-} from "../../../icons/ExportCommonIcons";
-import RenameInput from "../../../ui/inputs/RenameInput";
-import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
-import LabledDropdown from "../../../ui/inputs/LabledDropdown";
-import { handleResize } from "../../../../functions/handleResizePannel";
-import {
- useFloorItems,
- useSelectedActionSphere,
- useSelectedPath,
- useSimulationStates,
- useSocketStore,
-} from "../../../../store/store";
-import * as THREE from "three";
-import * as SimulationTypes from "../../../../types/simulationTypes";
-import InputToggle from "../../../ui/inputs/InputToggle";
-import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
-import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
-
-const ConveyorMechanics: React.FC = () => {
- const { selectedActionSphere } = useSelectedActionSphere();
- const { selectedPath, setSelectedPath } = useSelectedPath();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { floorItems, setFloorItems } = useFloorItems();
- const { socket } = useSocketStore();
-
- const actionsContainerRef = useRef(null);
- const triggersContainerRef = useRef(null);
-
- const selectedPoint = useMemo(() => {
- if (!selectedActionSphere) return null;
- return simulationStates
- .filter(
- (path): path is SimulationTypes.ConveyorEventsSchema => path.type === "Conveyor"
- )
- .flatMap((path) => path.points)
- .find((point) => point.uuid === selectedActionSphere.points.uuid);
- }, [selectedActionSphere, simulationStates]);
-
- const updateBackend = async (updatedPath: SimulationTypes.ConveyorEventsSchema | undefined) => {
- if (!updatedPath) return;
- const email = localStorage.getItem("email");
- const organization = email ? email.split("@")[1].split(".")[0] : "";
-
- // 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);
-
- }
-
- const handleAddAction = () => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) => {
- if (path.type === "Conveyor") {
- return {
- ...path,
- points: path.points.map((point) => {
- if (point.uuid === selectedActionSphere.points.uuid) {
- const actionIndex = point.actions.length;
- const newAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: `Action ${actionIndex + 1}`,
- type: "Inherit",
- material: "Inherit",
- delay: "Inherit",
- spawnInterval: "Inherit",
- isUsed: false,
- };
-
- return { ...point, actions: [...point.actions, newAction] };
- }
- return point;
- }),
- };
- }
- return path;
- });
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- };
-
- const handleDeleteAction = (uuid: string) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- actions: point.actions.filter(
- (action) => action.uuid !== uuid
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- };
-
- const handleActionSelect = (uuid: string, actionType: string) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- actions: point.actions.map((action) =>
- action.uuid === uuid
- ? {
- ...action,
- type: actionType,
- material:
- actionType === "Spawn" || actionType === "Swap"
- ? "Inherit"
- : action.material,
- delay:
- actionType === "Delay" ? "Inherit" : action.delay,
- spawnInterval:
- actionType === "Spawn"
- ? "Inherit"
- : action.spawnInterval,
- }
- : action
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
-
- // Update the selected item to reflect changes
- if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
- const updatedAction = updatedPaths
- .filter(
- (path): path is SimulationTypes.ConveyorEventsSchema => path.type === "Conveyor"
- )
- .flatMap((path) => path.points)
- .find((p) => p.uuid === selectedActionSphere.points.uuid)
- ?.actions.find((a) => a.uuid === uuid);
-
- if (updatedAction) {
- setSelectedItem({
- type: "action",
- item: updatedAction,
- });
- }
- }
- };
-
- // Modified handleMaterialSelect to ensure it only applies to relevant action types
- const handleMaterialSelect = (uuid: string, material: string) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- actions: point.actions.map((action) =>
- action.uuid === uuid &&
- (action.type === "Spawn" || action.type === "Swap")
- ? { ...action, material }
- : action
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
-
- // Update selected item if it's the current action
- if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
- setSelectedItem({
- ...selectedItem,
- item: {
- ...selectedItem.item,
- material,
- },
- });
- }
- };
-
- const handleDelayChange = (uuid: string, delay: number | string) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- actions: point.actions.map((action) =>
- action.uuid === uuid ? { ...action, delay } : action
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- };
-
- const handleSpawnIntervalChange = (
- uuid: string,
- spawnInterval: number | string
- ) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- actions: point.actions.map((action) =>
- action.uuid === uuid
- ? { ...action, spawnInterval }
- : action
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- };
-
- const handleSpeedChange = (speed: number | string) => {
- if (!selectedPath) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.modeluuid === selectedPath.path.modeluuid
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
- };
-
- const handleAddTrigger = () => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) => {
- if (point.uuid === selectedActionSphere.points.uuid) {
- const triggerIndex = point.triggers.length;
- const newTrigger = {
- uuid: THREE.MathUtils.generateUUID(),
- name: `Trigger ${triggerIndex + 1}`,
- type: "",
- bufferTime: 0,
- isUsed: false,
- };
-
- return { ...point, triggers: [...point.triggers, newTrigger] };
- }
- return point;
- }),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- };
-
- const handleDeleteTrigger = (uuid: string) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- triggers: point.triggers.filter(
- (trigger) => trigger.uuid !== uuid
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- };
-
- const handleTriggerSelect = (uuid: string, triggerType: string) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- triggers: point.triggers.map((trigger) =>
- trigger.uuid === uuid
- ? { ...trigger, type: triggerType }
- : trigger
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
-
- // Ensure the selectedItem is updated immediately
- const updatedTrigger = updatedPaths
- .flatMap((path) => (path.type === "Conveyor" ? path.points : []))
- .flatMap((point) => point.triggers)
- .find((trigger) => trigger.uuid === uuid);
-
- if (updatedTrigger) {
- setSelectedItem({ type: "trigger", item: updatedTrigger });
- }
- };
-
- // Update the toggle handlers to immediately update the selected item
- const handleActionToggle = (uuid: string) => {
- if (!selectedActionSphere) return;
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- actions: point.actions.map((action) => ({
- ...action,
- isUsed: action.uuid === uuid ? !action.isUsed : false,
- })),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
-
- // Immediately update the selected item if it's the one being toggled
- if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
- setSelectedItem({
- ...selectedItem,
- item: {
- ...selectedItem.item,
- isUsed: !selectedItem.item.isUsed,
- },
- });
- }
- };
-
- // Do the same for trigger toggle
- const handleTriggerToggle = (uuid: string) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- triggers: point.triggers.map((trigger) => ({
- ...trigger,
- isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
- })),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
-
- // Immediately update the selected item if it's the one being toggled
- if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
- setSelectedItem({
- ...selectedItem,
- item: {
- ...selectedItem.item,
- isUsed: !selectedItem.item.isUsed,
- },
- });
- }
- };
-
- const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => {
- if (!selectedActionSphere) return;
-
- const updatedPaths = simulationStates.map((path) =>
- path.type === "Conveyor"
- ? {
- ...path,
- points: path.points.map((point) =>
- point.uuid === selectedActionSphere.points.uuid
- ? {
- ...point,
- triggers: point.triggers.map((trigger) =>
- trigger.uuid === uuid
- ? { ...trigger, bufferTime }
- : trigger
- ),
- }
- : point
- ),
- }
- : path
- );
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.ConveyorEventsSchema =>
- path.type === "Conveyor" &&
- path.points.some(
- (point) => point.uuid === selectedActionSphere.points.uuid
- )
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
-
- // Immediately update selectedItem if it's the currently selected trigger
- if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
- setSelectedItem({
- ...selectedItem,
- item: {
- ...selectedItem.item,
- bufferTime,
- },
- });
- }
- };
-
- const [selectedItem, setSelectedItem] = useState<{
- type: "action" | "trigger";
- item: any;
- } | null>(null);
-
- useEffect(() => {
- setSelectedItem(null);
- }, [selectedActionSphere]);
-
- return (
-
- {!selectedPath && (
-
- {selectedActionSphere?.path?.modelName || "point name not found"}
-
- )}
-
- {selectedPath && (
-
- {selectedPath.path.modelName || "path name not found"}
-
- )}
-
-
- {!selectedPath && (
- <>
-
-
-
-
- {selectedPoint?.actions.map((action) => (
-
-
- setSelectedItem({ type: "action", item: action })
- }
- >
-
-
-
-
handleDeleteAction(action.uuid)}
- >
-
-
-
- ))}
-
-
handleResize(e, actionsContainerRef)}
- >
-
-
-
-
-
-
-
-
- {selectedPoint?.triggers.map((trigger) => (
-
-
- setSelectedItem({ type: "trigger", item: trigger })
- }
- >
-
-
-
-
handleDeleteTrigger(trigger.uuid)}
- >
-
-
-
- ))}
-
-
handleResize(e, triggersContainerRef)}
- >
-
-
-
-
- >
- )}
-
-
- {selectedItem && (
- <>
-
{selectedItem.item.name}
-
- {selectedItem.type === "action" && (
- <>
-
handleActionToggle(selectedItem.item.uuid)}
- />
-
- handleActionSelect(selectedItem.item.uuid, option)
- }
- />
-
- {/* Only show material dropdown for Spawn/Swap actions */}
- {(selectedItem.item.type === "Spawn" ||
- selectedItem.item.type === "Swap") && (
-
- handleMaterialSelect(selectedItem.item.uuid, option)
- }
- />
- )}
-
- {/* Only show delay input for Delay actions */}
- {selectedItem.item.type === "Delay" && (
- {
- const numValue = parseInt(value);
- handleDelayChange(
- selectedItem.item.uuid,
- !value ? "Inherit" : numValue
- );
- }}
- />
- )}
-
- {/* Only show spawn interval for Spawn actions */}
- {selectedItem.item.type === "Spawn" && (
- {
- handleSpawnIntervalChange(
- selectedItem.item.uuid,
- value === "" ? "Inherit" : parseInt(value)
- );
- }}
- />
- )}
- >
- )}
-
- {selectedItem.type === "trigger" && (
- <>
- handleTriggerToggle(selectedItem.item.uuid)}
- />
-
-
- handleTriggerSelect(selectedItem.item.uuid, option)
- }
- />
-
- {selectedItem.item.type === "Buffer" && (
- {
- handleTriggerBufferTimeChange(
- selectedItem.item.uuid,
- parseInt(value)
- );
- }}
- />
- )}
- >
- )}
- >
- )}
-
- {selectedPath && !selectedItem && (
-
-
- handleSpeedChange(value === "" ? "Inherit" : parseInt(value))
- }
- />
-
- )}
-
- {!selectedPath && (
-
-
- Configure the point's action and trigger properties.
-
- )}
- {selectedPath && (
-
-
- Configure the path properties.
-
- )}
-
-
- );
-};
-
-export default ConveyorMechanics;
diff --git a/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx
deleted file mode 100644
index 6342bac..0000000
--- a/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx
+++ /dev/null
@@ -1,188 +0,0 @@
-import React, { useRef, useMemo, useCallback } from "react";
-import { InfoIcon } from "../../../icons/ExportCommonIcons";
-import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
-import { useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
-import * as SimulationTypes from '../../../../types/simulationTypes';
-import LabledDropdown from "../../../ui/inputs/LabledDropdown";
-import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
-
-const StaticMachineMechanics: React.FC = () => {
- const { selectedActionSphere } = useSelectedActionSphere();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { socket } = useSocketStore();
-
- const propertiesContainerRef = useRef(null);
-
- const { selectedPoint, connectedPointUuids } = useMemo(() => {
- if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
-
- const staticMachinePaths = simulationStates.filter(
- (path): path is SimulationTypes.StaticMachineEventsSchema => path.type === "StaticMachine"
- );
-
- const points = staticMachinePaths.find(
- (path) => path.points.uuid === selectedActionSphere.points.uuid
- )?.points;
-
- if (!points) return { selectedPoint: null, connectedPointUuids: [] };
-
- const connectedUuids: string[] = [];
- if (points.connections?.targets) {
- points.connections.targets.forEach(target => {
- connectedUuids.push(target.pointUUID);
- });
- }
-
- return {
- selectedPoint: points,
- connectedPointUuids: connectedUuids
- };
- }, [selectedActionSphere, simulationStates]);
-
- const updateBackend = async (updatedPath: SimulationTypes.StaticMachineEventsSchema | 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 data = {
- organization: organization,
- modeluuid: updatedPath.modeluuid,
- eventData: { type: "StaticMachine", points: updatedPath.points }
- }
-
- socket.emit('v2:model-asset:updateEventData', data);
- }
-
- const handleActionUpdate = useCallback((updatedAction: Partial) => {
- if (!selectedActionSphere?.points?.uuid) return;
-
- const updatedPaths = simulationStates.map((path) => {
- if (path.type === "StaticMachine" && path.points.uuid === selectedActionSphere.points.uuid) {
- return {
- ...path,
- points: {
- ...path.points,
- actions: {
- ...path.points.actions,
- ...updatedAction
- }
- }
- };
- }
- return path;
- });
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.StaticMachineEventsSchema =>
- path.type === "StaticMachine" &&
- path.points.uuid === selectedActionSphere.points.uuid
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
-
- const handleBufferChange = useCallback((buffer: number) => {
- handleActionUpdate({ buffer });
- }, [handleActionUpdate]);
-
- const handleMaterialChange = useCallback((material: string) => {
- handleActionUpdate({ material });
- }, [handleActionUpdate]);
-
- const handleTriggerChange = useCallback((updatedTrigger: Partial) => {
- if (!selectedActionSphere?.points?.uuid) return;
-
- const updatedPaths = simulationStates.map((path) => {
- if (path.type === "StaticMachine" && path.points.uuid === selectedActionSphere.points.uuid) {
- return {
- ...path,
- points: {
- ...path.points,
- triggers: {
- ...path.points.triggers,
- ...updatedTrigger
- }
- }
- };
- }
- return path;
- });
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.StaticMachineEventsSchema =>
- path.type === "StaticMachine" &&
- path.points.uuid === selectedActionSphere.points.uuid
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
-
- const handleTriggerTypeChange = useCallback((type: string) => {
- handleTriggerChange({ type });
- }, [handleTriggerChange]);
-
- return (
-
-
- {selectedActionSphere?.path?.modelName || "Machine point not found"}
-
-
-
-
-
-
Machine Properties
-
- {selectedPoint && (
- <>
-
handleBufferChange(parseInt(value))}
- />
-
- handleMaterialChange(value)}
- options={["Inherit", "Crate", "Box"]}
- />
-
- handleTriggerTypeChange(value)}
- options={["OnComplete", "OnStart"]}
- />
-
- {/* {
- // Implement reset functionality if needed
- }}
- /> */}
- >
- )}
-
-
-
-
- Configure machine interaction properties and triggers.
-
-
-
- );
-};
-
-export default React.memo(StaticMachineMechanics);
\ No newline at end of file
diff --git a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx
deleted file mode 100644
index 147d5cb..0000000
--- a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx
+++ /dev/null
@@ -1,265 +0,0 @@
-import React, { useRef, useMemo } from "react";
-import { InfoIcon } from "../../../icons/ExportCommonIcons";
-import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
-import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
-import * as SimulationTypes from '../../../../types/simulationTypes';
-import PositionInput from "../customInput/PositionInputs";
-import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
-import LabeledButton from "../../../ui/inputs/LabledButton";
-
-const VehicleMechanics: React.FC = () => {
- const { selectedActionSphere } = useSelectedActionSphere();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
- const { editingPoint, setEditingPoint } = useEditingPoint();
- const { previewPosition, setPreviewPosition } = usePreviewPosition();
- const { socket } = useSocketStore();
-
- const propertiesContainerRef = useRef(null);
-
- const { selectedPoint, connectedPointUuids } = useMemo(() => {
- if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
-
- const vehiclePaths = simulationStates.filter(
- (path): path is SimulationTypes.VehicleEventsSchema => path.type === "Vehicle"
- );
-
- const points = vehiclePaths.find(
- (path) => path.points.uuid === selectedActionSphere.points.uuid
- )?.points;
-
- if (!points) return { selectedPoint: null, connectedPointUuids: [] };
-
- const connectedUuids: string[] = [];
- if (points.connections?.targets) {
- points.connections.targets.forEach(target => {
- connectedUuids.push(target.pointUUID);
- });
- }
-
- return {
- selectedPoint: points,
- connectedPointUuids: connectedUuids
- };
- }, [selectedActionSphere, simulationStates]);
-
- const updateBackend = async (updatedPath: SimulationTypes.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 data = {
- organization: organization,
- modeluuid: updatedPath.modeluuid,
- eventData: { type: "Vehicle", points: updatedPath.points }
- }
-
- socket.emit('v2:model-asset:updateEventData', data);
-
- }
-
- const handleActionUpdate = React.useCallback((updatedAction: Partial) => {
- if (!selectedActionSphere?.points?.uuid) return;
-
- const updatedPaths = simulationStates.map((path) => {
- if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
- return {
- ...path,
- points: {
- ...path.points,
- actions: {
- ...path.points.actions,
- ...updatedAction
- }
- }
- };
- }
- return path;
- });
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.VehicleEventsSchema =>
- path.type === "Vehicle" &&
- path.points.uuid === selectedActionSphere.points.uuid
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
-
- const handleHitCountChange = React.useCallback((hitCount: number) => {
- handleActionUpdate({ hitCount });
- }, [handleActionUpdate]);
-
- const handleBufferChange = React.useCallback((buffer: number) => {
- handleActionUpdate({ buffer });
- }, [handleActionUpdate]);
-
- const handleSpeedChange = React.useCallback((speed: number) => {
- if (!selectedActionSphere?.points?.uuid) return;
-
- const updatedPaths = simulationStates.map((path) => {
- if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
- return {
- ...path,
- points: {
- ...path.points,
- speed: speed
- }
- };
- }
- return path;
- });
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.VehicleEventsSchema =>
- path.type === "Vehicle" &&
- path.points.uuid === selectedActionSphere.points.uuid
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
-
-
- const ResetVehicleState = React.useCallback(() => {
- if (!selectedActionSphere?.points?.uuid) return;
-
- const updatedPaths = simulationStates.map((state) => {
- if (state.type === "Vehicle" && state.points.uuid === selectedActionSphere.points.uuid) {
- return {
- ...state,
- points: {
- ...state.points,
- actions: { ...state.points.actions, start: {}, end: {} }
- }
- };
- }
- return state;
- });
-
- const updatedPath = updatedPaths.find(
- (path): path is SimulationTypes.VehicleEventsSchema =>
- path.type === "Vehicle" &&
- path.points.uuid === selectedActionSphere.points.uuid
- );
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
-
- const handleStartEyeDropClick = () => {
- setEditingPoint('start');
- setEyeDropMode(true);
- };
-
- const handleEndEyeDropClick = () => {
- setEditingPoint('end');
- setEyeDropMode(true);
- };
-
- return (
-
-
- {selectedActionSphere?.path?.modelName || "Vehicle point not found"}
-
-
-
-
-
Vehicle Properties
-
- {selectedPoint && (
- <>
-
{ }}
- disabled={true}
- value1={
- editingPoint === 'start' && previewPosition
- ? parseFloat(previewPosition.x.toFixed(4))
- : selectedPoint.actions.start && 'x' in selectedPoint.actions.start
- ? parseFloat(selectedPoint.actions.start.x.toFixed(4))
- : 0
- }
- value2={
- editingPoint === 'start' && previewPosition
- ? parseFloat(previewPosition.y.toFixed(4))
- : selectedPoint.actions.start && 'y' in selectedPoint.actions.start
- ? parseFloat(selectedPoint.actions.start.y.toFixed(4))
- : 0
- }
-
- isEyedrop={true}
- handleEyeDropClick={handleStartEyeDropClick}
- />
-
- { }}
- disabled={true}
- value1={
- editingPoint === 'end' && previewPosition
- ? parseFloat(previewPosition.x.toFixed(4))
- : selectedPoint.actions.end && 'x' in selectedPoint.actions.end
- ? parseFloat(selectedPoint.actions.end.x.toFixed(4))
- : 0
- }
- value2={
- editingPoint === 'end' && previewPosition
- ? parseFloat(previewPosition.y.toFixed(4))
- : selectedPoint.actions.end && 'y' in selectedPoint.actions.end
- ? parseFloat(selectedPoint.actions.end.y.toFixed(4))
- : 0
- }
- isEyedrop={true}
- handleEyeDropClick={handleEndEyeDropClick}
- />
-
- {
- ResetVehicleState();
- }}
- />
-
- handleHitCountChange(parseInt(value))}
- />
-
- handleBufferChange(parseInt(value))}
- />
-
- handleSpeedChange(parseFloat(value))}
- />
- >
- )}
-
-
-
-
- Configure vehicle's movement and interaction properties.
-
-
-
- );
-};
-
-export default React.memo(VehicleMechanics);
\ No newline at end of file
diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx
index ab1430c..a9f8cc0 100644
--- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx
+++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx
@@ -1,9 +1,9 @@
import React, { useEffect, useState } from "react";
import RenameInput from "../../../ui/inputs/RenameInput";
import Vector3Input from "../customInput/Vector3Input";
-import { useSelectedZoneStore } from "../../../../store/useZoneStore";
+import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore";
import { useEditPosition, usezonePosition, useZones, usezoneTarget } from "../../../../store/store";
-import { zoneCameraUpdate } from "../../../../services/realTimeVisulization/zoneData/zoneCameraUpdation";
+import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation";
const ZoneProperties: React.FC = () => {
const { Edit, setEdit } = useEditPosition();
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx
new file mode 100644
index 0000000..c3ec6e7
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx
@@ -0,0 +1,210 @@
+import React, { useRef, useState } from "react";
+import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown";
+import LabledDropdown from "../../../../ui/inputs/LabledDropdown";
+import {
+ AddIcon,
+ RemoveIcon,
+ ResizeHeightIcon,
+} from "../../../../icons/ExportCommonIcons";
+import RenameInput from "../../../../ui/inputs/RenameInput";
+import { handleResize } from "../../../../../functions/handleResizePannel";
+import { handleActionToggle } from "./functions/handleActionToggle";
+import { handleDeleteAction } from "./functions/handleDeleteAction";
+import DefaultAction from "./actions/DefaultAction";
+import SpawnAction from "./actions/SpawnAction";
+import SwapAction from "./actions/SwapAction";
+import DespawnAction from "./actions/DespawnAction";
+import TravelAction from "./actions/TravelAction";
+import PickAndPlaceAction from "./actions/PickAndPlaceAction";
+import ProcessAction from "./actions/ProcessAction";
+import StorageAction from "./actions/StorageAction";
+import Trigger from "./trigger/Trigger";
+
+interface EventPropertiesProps {
+ assetType: string;
+ selectedPoint: {
+ name: string;
+ uuid: string;
+ actions: {
+ uuid: string;
+ name: string;
+ }[];
+ };
+ selectedItem: {
+ item: {
+ uuid: string;
+ name: string;
+ } | null;
+ };
+ setSelectedPoint: (value: string) => void;
+ selectedActionSphere: string;
+}
+
+const EventProperties: React.FC = ({
+ assetType,
+ selectedPoint,
+ selectedItem,
+ setSelectedPoint,
+ selectedActionSphere,
+}) => {
+ const actionsContainerRef = useRef(null);
+
+ const [activeOption, setActiveOption] = useState("default");
+ const [dummyactiveOption, setTypeOption] = useState("default");
+
+ const getAvailableActions = () => {
+ if (assetType === "conveyor") {
+ return {
+ defaultOption: "default",
+ options: ["default", "spawn", "swap", "despawn"],
+ };
+ }
+ if (assetType === "vehicle") {
+ return {
+ defaultOption: "travel",
+ options: ["travel"],
+ };
+ }
+ if (assetType === "roboticArm") {
+ return {
+ defaultOption: "pickAndPlace",
+ options: ["pickAndPlace"],
+ };
+ }
+ if (assetType === "machine") {
+ return {
+ defaultOption: "process",
+ options: ["process"],
+ };
+ }
+ if (assetType === "store") {
+ return {
+ defaultOption: "store",
+ options: ["store", "spawn"],
+ };
+ } else {
+ return {
+ defaultOption: "default",
+ options: ["default"],
+ };
+ }
+ };
+
+ return (
+
+
+
+
+ {/*
+ setTypeOption(option)}
+ />
+
*/}
+
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+
+
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+
+
+
+
+
+
+
+
+ {selectedPoint?.actions.map((action) => (
+
+
handleActionToggle(action.uuid)}
+ >
+
+
+ {selectedPoint?.actions.length > 1 && (
+
handleDeleteAction(action.uuid)}
+ >
+
+
+ )}
+
+ ))}
+
+
handleResize(e, actionsContainerRef)}
+ >
+
+
+
+
+
+
+
+
+
+
+
setActiveOption(option)}
+ />
+ {activeOption === "default" && } {/* done */}
+ {activeOption === "spawn" && } {/* done */}
+ {activeOption === "swap" && } {/* done */}
+ {activeOption === "despawn" && } {/* done */}
+ {activeOption === "travel" && } {/* done */}
+ {activeOption === "pickAndPlace" && } {/* done */}
+ {activeOption === "process" && } {/* done */}
+ {activeOption === "store" && } {/* done */}
+
+
+
+
+
+
+ );
+};
+
+export default EventProperties;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DefaultAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DefaultAction.tsx
new file mode 100644
index 0000000..88f515e
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DefaultAction.tsx
@@ -0,0 +1,7 @@
+import React from "react";
+
+const DefaultAction:React.FC = () => {
+ return <>>;
+};
+
+export default DefaultAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx
new file mode 100644
index 0000000..a0f081f
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx
@@ -0,0 +1,22 @@
+import React from "react";
+import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
+
+const DespawnAction: React.FC = () => {
+ return (
+ <>
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+ >
+ );
+};
+
+export default DespawnAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx
new file mode 100644
index 0000000..9574669
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx
@@ -0,0 +1,13 @@
+import React from "react";
+import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
+
+const PickAndPlaceAction: React.FC = () => {
+ return (
+ <>
+ {}} />
+ {}} />
+ >
+ );
+};
+
+export default PickAndPlaceAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx
new file mode 100644
index 0000000..a27894e
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
+import SwapAction from "./SwapAction";
+
+const ProcessAction: React.FC = () => {
+ return (
+ <>
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+
+ >
+ );
+};
+
+export default ProcessAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx
new file mode 100644
index 0000000..0c37cdb
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx
@@ -0,0 +1,35 @@
+import React from "react";
+import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
+import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
+
+const SpawnAction: React.FC = () => {
+ return (
+ <>
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+
+ >
+ );
+};
+
+export default SpawnAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx
new file mode 100644
index 0000000..ab2109b
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx
@@ -0,0 +1,20 @@
+import React from "react";
+import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
+
+const StorageAction: React.FC = () => {
+ return (
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+ );
+};
+
+export default StorageAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx
new file mode 100644
index 0000000..2e18d80
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
+
+const SwapAction: React.FC = () => {
+ return (
+ <>
+
+ >
+ );
+};
+
+export default SwapAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx
new file mode 100644
index 0000000..ee4bda0
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx
@@ -0,0 +1,36 @@
+import React from "react";
+import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
+import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
+
+const TravelAction: React.FC = () => {
+ return (
+ <>
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+ {}}
+ onChange={(value) => console.log(value)}
+ />
+ {}} />
+ {}} />
+ >
+ );
+};
+
+export default TravelAction;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleActionToggle.ts b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleActionToggle.ts
new file mode 100644
index 0000000..96e986a
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleActionToggle.ts
@@ -0,0 +1,6 @@
+export function handleActionToggle(uuid: string) {
+ // This function handles the action toggle for the event properties.
+ // It updates the selected action and its properties based on the provided UUID.
+ // The function is currently empty and needs to be implemented.
+ // You can add your logic here to handle the action toggle.
+}
\ No newline at end of file
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleDeleteAction.ts b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleDeleteAction.ts
new file mode 100644
index 0000000..6a367d5
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleDeleteAction.ts
@@ -0,0 +1,6 @@
+export function handleDeleteAction(uuid: string) {
+ // This function handles the action toggle for the event properties.
+ // It updates the selected action and its properties based on the provided UUID.
+ // The function is currently empty and needs to be implemented.
+ // You can add your logic here to handle the action toggle.
+}
\ No newline at end of file
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx
new file mode 100644
index 0000000..f287b63
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx
@@ -0,0 +1,107 @@
+import React, { useState } from "react";
+import { AddIcon, RemoveIcon } from "../../../../../icons/ExportCommonIcons";
+import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
+
+const Trigger: React.FC = () => {
+ // State to hold the list of triggers
+ const [triggers, setTriggers] = useState([]);
+ const [activeOption, setActiveOption] = useState("onComplete");
+
+ // States for dropdowns
+ const [triggeredModel, setTriggeredModel] = useState([]);
+ const [triggeredPoint, setTriggeredPoint] = useState([]);
+ const [triggeredAction, setTriggeredAction] = useState([]);
+
+ // Function to handle adding a new trigger
+ const addTrigger = (): void => {
+ const newTrigger = `Trigger ${triggers.length + 1}`;
+ setTriggers([...triggers, newTrigger]); // Add new trigger to the state
+
+ // Initialize the states for the new trigger
+ setTriggeredModel([...triggeredModel, ""]);
+ setTriggeredPoint([...triggeredPoint, ""]);
+ setTriggeredAction([...triggeredAction, ""]);
+ };
+
+ // Function to handle removing a trigger
+ const removeTrigger = (index: number): void => {
+ setTriggers(triggers.filter((_, i) => i !== index)); // Remove trigger by index
+ setTriggeredModel(triggeredModel.filter((_, i) => i !== index));
+ setTriggeredPoint(triggeredPoint.filter((_, i) => i !== index));
+ setTriggeredAction(triggeredAction.filter((_, i) => i !== index));
+ };
+
+ return (
+
+
+
+ {/* Map over triggers and render them */}
+ {triggers.map((trigger, index) => (
+
+
+ {trigger}
+
removeTrigger(index)}
+ style={{ cursor: "pointer" }}
+ >
+
+
+
+
setActiveOption(option)}
+ />
+
+
+ {
+ const newModel = [...triggeredModel];
+ newModel[index] = option;
+ setTriggeredModel(newModel);
+ }}
+ />
+
+
+ {
+ const newPoint = [...triggeredPoint];
+ newPoint[index] = option;
+ setTriggeredPoint(newPoint);
+ }}
+ />
+
+
+ {
+ const newAction = [...triggeredAction];
+ newAction[index] = option;
+ setTriggeredAction(newAction);
+ }}
+ />
+
+
+
+ ))}
+
+
+ );
+};
+
+export default Trigger;
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx
index 9fb7b78..a729a9e 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx
index 78b82c8..9c6c831 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx
index 271b4fc..0165257 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx
index 50330d1..cb51491 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx
@@ -121,8 +121,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx
index e7486f2..9dff7d6 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx
index 797f63a..ed84458 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx
index a7d2934..c97a380 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx
index 764be54..d48f2ee 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx
index 345de09..62edae4 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx
index c41447a..7481622 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx
index 20369bd..f8cdef6 100644
--- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
-import useChartStore from "../../../../../store/useChartStore";
-import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
+import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
diff --git a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx
index 234b936..04a569a 100644
--- a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx
@@ -1,9 +1,9 @@
import { useState, useEffect, useRef } from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
-import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
+import ChartComponent from "../../../sidebarLeft//visualization/widgets/ChartComponent";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import { WalletIcon } from "../../../../icons/3dChartIcons";
-import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
+import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
interface Widget {
id: string;
diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx
index 0f125ad..70b1461 100644
--- a/app/src/components/ui/Tools.tsx
+++ b/app/src/components/ui/Tools.tsx
@@ -15,10 +15,10 @@ import {
} from "../icons/ExportToolsIcons";
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
-import { handleSaveTemplate } from "../../modules/visualization/functions/handleSaveTemplate";
+import { handleSaveTemplate } from "../../modules//visualization/functions/handleSaveTemplate";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
-import { useSelectedZoneStore } from "../../store/useZoneStore";
+import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
import {
useActiveTool,
useAddAction,
@@ -38,7 +38,7 @@ import {
use3DWidget,
useDroppedObjectsStore,
useFloatingWidget,
-} from "../../store/useDroppedObjectsStore";
+} from "../../store/visualization/useDroppedObjectsStore";
const Tools: React.FC = () => {
const { templates } = useTemplateStore();
diff --git a/app/src/components/ui/inputs/InputWithDropDown.tsx b/app/src/components/ui/inputs/InputWithDropDown.tsx
index b672313..3d42917 100644
--- a/app/src/components/ui/inputs/InputWithDropDown.tsx
+++ b/app/src/components/ui/inputs/InputWithDropDown.tsx
@@ -5,6 +5,7 @@ type InputWithDropDownProps = {
label: string;
value: string;
min?: number;
+ max?: number;
step?: number;
defaultValue?: string;
options?: string[]; // Array of dropdown options
@@ -19,6 +20,7 @@ const InputWithDropDown: React.FC = ({
label,
value,
min,
+ max,
step,
defaultValue,
options,
@@ -47,6 +49,7 @@ const InputWithDropDown: React.FC = ({
{
+ const [showPreview, setSetshowPreview] = useState(false);
+ return (
+
+
setSetshowPreview(!showPreview)}
+ >
+
Preview
+
+
+ {showPreview && (
+
+ )}
+
+
+
Upload Product
+
+
+
+
console.log(option)}
+ />
+
+
+ );
+};
+
+export default PreviewSelectionWithUpload;
diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx
index b2f05b9..0416a9e 100644
--- a/app/src/components/ui/list/DropDownList.tsx
+++ b/app/src/components/ui/list/DropDownList.tsx
@@ -3,8 +3,7 @@ import List from "./List";
import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons";
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
import { useFloorItems, useZones } from "../../../store/store";
-import { useSelectedZoneStore } from "../../../store/useZoneStore";
-import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/getZoneData";
+import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
interface DropDownListProps {
value?: string; // Value to display in the DropDownList
diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx
index 49e86f4..cac0b43 100644
--- a/app/src/components/ui/list/List.tsx
+++ b/app/src/components/ui/list/List.tsx
@@ -1,8 +1,8 @@
import React, { useEffect, useState } from "react";
import RenameInput from "../inputs/RenameInput";
-import { useSelectedZoneStore } from "../../../store/useZoneStore";
-import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones";
+import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
+import { getZoneData } from "../../../services/visulization/zone/getZones";
import useModuleStore, {
useSubModuleStore,
} from "../../../store/useModuleStore";
@@ -14,7 +14,7 @@ import {
} from "../../icons/ExportCommonIcons";
import { useThree } from "@react-three/fiber";
import { useFloorItems, useZoneAssetId, useZones } from "../../../store/store";
-import { zoneCameraUpdate } from "../../../services/realTimeVisulization/zoneData/zoneCameraUpdation";
+import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation";
import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
interface Asset {
diff --git a/app/src/components/ui/menu/EditWidgetOption.tsx b/app/src/components/ui/menu/EditWidgetOption.tsx
index 1c1fa2e..6fd1e94 100644
--- a/app/src/components/ui/menu/EditWidgetOption.tsx
+++ b/app/src/components/ui/menu/EditWidgetOption.tsx
@@ -5,7 +5,7 @@ import {
useRightClickSelected,
useRightSelected,
useTopData,
-} from "../../../store/useZone3DWidgetStore";
+} from "../../../store/visualization/useZone3DWidgetStore";
interface EditWidgetOptionProps {
options: string[];
diff --git a/app/src/modules/collaboration/collabUserIcon.tsx b/app/src/functions/collabUserIcon.tsx
similarity index 95%
rename from app/src/modules/collaboration/collabUserIcon.tsx
rename to app/src/functions/collabUserIcon.tsx
index a8738ce..9e6802b 100644
--- a/app/src/modules/collaboration/collabUserIcon.tsx
+++ b/app/src/functions/collabUserIcon.tsx
@@ -1,31 +1,31 @@
-import React from "react";
-import CustomAvatar from "./users/Avatar";
-
-interface CollabUserIconProps {
- userName: string;
- userImage?: string;
- color: string;
-}
-
-const CollabUserIcon: React.FC
= ({
- userImage,
- userName,
- color,
-}) => {
- return (
-
-
- {userImage ? (
-

- ) : (
-
- )}
-
-
- {userName}
-
-
- );
-};
-
-export default CollabUserIcon;
+import React from "react";
+import CustomAvatar from "./users/Avatar";
+
+interface CollabUserIconProps {
+ userName: string;
+ userImage?: string;
+ color: string;
+}
+
+const CollabUserIcon: React.FC = ({
+ userImage,
+ userName,
+ color,
+}) => {
+ return (
+
+
+ {userImage ? (
+

+ ) : (
+
+ )}
+
+
+ {userName}
+
+
+ );
+};
+
+export default CollabUserIcon;
diff --git a/app/src/modules/collaboration/users/Avatar.tsx b/app/src/functions/users/Avatar.tsx
similarity index 100%
rename from app/src/modules/collaboration/users/Avatar.tsx
rename to app/src/functions/users/Avatar.tsx
diff --git a/app/src/modules/collaboration/users/functions/getAvatarColor.ts b/app/src/functions/users/functions/getAvatarColor.ts
similarity index 82%
rename from app/src/modules/collaboration/users/functions/getAvatarColor.ts
rename to app/src/functions/users/functions/getAvatarColor.ts
index f2bd816..d9a5d37 100644
--- a/app/src/modules/collaboration/users/functions/getAvatarColor.ts
+++ b/app/src/functions/users/functions/getAvatarColor.ts
@@ -25,19 +25,8 @@ const avatarColors: string[] = [
export function getAvatarColor(index: number, name?: string): string {
// Check if the color is already stored in localStorage
const localStorageKey = "userAvatarColors";
- // Helper function to check if local storage is available
- function isLocalStorageAvailable(): boolean {
- try {
- const testKey = "__test__";
- localStorage.setItem(testKey, "test");
- localStorage.removeItem(testKey);
- return true;
- } catch (e) {
- return false;
- }
- }
// Check if local storage is available
- if (isLocalStorageAvailable() && name) {
+ if (name) {
let userColors = JSON.parse(localStorage.getItem(localStorageKey) || "{}");
// Check if the user already has an assigned color
diff --git a/app/src/modules/collaboration/users/functions/getInitials.ts b/app/src/functions/users/functions/getInitials.ts
similarity index 100%
rename from app/src/modules/collaboration/users/functions/getInitials.ts
rename to app/src/functions/users/functions/getInitials.ts
diff --git a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts
similarity index 68%
rename from app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts
rename to app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts
index 7ca7db9..e88dc3c 100644
--- a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts
+++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts
@@ -1,270 +1,202 @@
-import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
-import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
-import gsap from 'gsap';
-import * as THREE from 'three';
-import * as CONSTANTS from '../../../types/world/worldConstants';
-import { toast } from 'react-toastify';
-import * as Types from "../../../types/world/worldTypes";
-import * as SimulationTypes from "../../../types/simulationTypes";
-import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
-import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
-import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
-
-async function loadInitialFloorItems(
- itemsGroup: Types.RefGroup,
- setFloorItems: Types.setFloorItemSetState,
- setSimulationStates: (paths: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => void
-): Promise {
- if (!itemsGroup.current) return;
- let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
- const email = localStorage.getItem('email');
- const organization = (email!.split("@")[1]).split(".")[0];
-
- const items = await getFloorAssets(organization);
- localStorage.setItem("FloorItems", JSON.stringify(items));
- await initializeDB();
-
- if (items.message === "floorItems not found") return;
-
- if (items) {
- const storedFloorItems: SimulationTypes.EventData[] = items;
- const loader = new GLTFLoader();
- const dracoLoader = new DRACOLoader();
-
- dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
- loader.setDRACOLoader(dracoLoader);
-
- let modelsLoaded = 0;
- const modelsToLoad = storedFloorItems.length;
-
- const camData = await getCamera(organization, localStorage.getItem('userId')!);
- let storedPosition;
- if (camData && camData.position) {
- storedPosition = camData?.position;
- } else {
- storedPosition = new THREE.Vector3(0, 40, 30);
- }
- if (!storedPosition) return;
- const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
-
- storedFloorItems.sort((a, b) => {
- const aPosition = new THREE.Vector3(a.position[0], a.position[1], a.position[2]);
- const bPosition = new THREE.Vector3(b.position[0], b.position[1], b.position[2]);
- return cameraPosition.distanceTo(aPosition) - cameraPosition.distanceTo(bPosition);
- });
-
- for (const item of storedFloorItems) {
- if (!item.modelfileID) return;
- const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
- let storedPosition;
- if (localStorage.getItem("cameraPosition")) {
- storedPosition = JSON.parse(localStorage.getItem("cameraPosition")!);
- } else {
- storedPosition = new THREE.Vector3(0, 40, 30);
- }
-
- const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
-
- if (cameraPosition.distanceTo(itemPosition) < 50) {
- await new Promise(async (resolve) => {
-
- // Check Three.js Cache
- const cachedModel = THREE.Cache.get(item.modelfileID!);
- if (cachedModel) {
- // console.log(`[Cache] Fetching ${item.modelname}`);
- processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
- modelsLoaded++;
- checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
- return;
- }
-
- // Check IndexedDB
- const indexedDBModel = await retrieveGLTF(item.modelfileID!);
- if (indexedDBModel) {
- // console.log(`[IndexedDB] Fetching ${item.modelname}`);
- const blobUrl = URL.createObjectURL(indexedDBModel);
- loader.load(blobUrl, (gltf) => {
- URL.revokeObjectURL(blobUrl);
- THREE.Cache.remove(blobUrl);
- THREE.Cache.add(item.modelfileID!, gltf);
- processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
- modelsLoaded++;
- checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
- },
- undefined,
- (error) => {
- toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
- URL.revokeObjectURL(blobUrl);
- resolve();
- }
- );
- return;
- }
-
- // Fetch from Backend
- // console.log(`[Backend] Fetching ${item.modelname}`);
- const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`;
- loader.load(modelUrl, async (gltf) => {
- 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, setSimulationStates);
- modelsLoaded++;
- checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
- },
- undefined,
- (error) => {
- toast.error(`[Backend] Error loading ${item.modelname}:`);
- resolve();
- }
- );
- });
- } else {
- // console.log(`Item ${item.modelname} is not near`);
- setFloorItems((prevItems) => [
- ...(prevItems || []),
- {
- modeluuid: item.modeluuid,
- modelname: item.modelname,
- position: item.position,
- rotation: item.rotation,
- modelfileID: item.modelfileID,
- isLocked: item.isLocked,
- isVisible: item.isVisible,
- },
- ]);
-
- if (item.eventData) {
- processEventData(item, setSimulationStates);
- }
-
- modelsLoaded++;
- checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, () => { });
- }
- }
-
- // Dispose loader after all models
- dracoLoader.dispose();
- }
-}
-
-
-function processLoadedModel(
- gltf: any,
- item: SimulationTypes.EventData,
- itemsGroup: Types.RefGroup,
- setFloorItems: Types.setFloorItemSetState,
- setSimulationStates: (paths: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => void
-) {
- const model = gltf;
- model.uuid = item.modeluuid;
- model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
- model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
- model.position.set(...item.position);
- model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
-
- model.traverse((child: any) => {
- if (child.isMesh) {
- // Clone the material to ensure changes are independent
- // child.material = child.material.clone();
-
- child.castShadow = true;
- child.receiveShadow = true;
- }
- });
-
-
- itemsGroup?.current?.add(model);
-
- setFloorItems((prevItems) => [
- ...(prevItems || []),
- {
- modeluuid: item.modeluuid,
- modelname: item.modelname,
- position: item.position,
- rotation: item.rotation,
- modelfileID: item.modelfileID,
- isLocked: item.isLocked,
- isVisible: item.isVisible,
- },
- ]);
-
- if (item.eventData) {
- 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: SimulationTypes.EventData, setSimulationStates: any) {
-
- if (item.eventData?.type === 'Conveyor') {
-
- const data: any = item.eventData;
- data.modeluuid = item.modeluuid;
- data.modelName = item.modelname;
- data.position = item.position;
- data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- data as SimulationTypes.ConveyorEventsSchema
- ]);
-
- } else if (item.eventData?.type === 'Vehicle') {
-
- const data: any = item.eventData;
- data.modeluuid = item.modeluuid;
- data.modelName = item.modelname;
- data.position = item.position;
- data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- data as SimulationTypes.VehicleEventsSchema
- ]);
-
- } else if (item.eventData?.type === 'StaticMachine') {
-
- const data: any = item.eventData;
- data.modeluuid = item.modeluuid;
- data.modelName = item.modelname;
- data.position = item.position;
- data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- data as SimulationTypes.StaticMachineEventsSchema
- ]);
-
- } else if (item.eventData?.type === 'ArmBot') {
-
- const data: any = item.eventData;
- data.modeluuid = item.modeluuid;
- data.modelName = item.modelname;
- data.position = item.position;
- data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- data as SimulationTypes.ArmBotEventsSchema
- ]);
-
- }
-}
-
-function checkLoadingCompletion(
- modelsLoaded: number,
- modelsToLoad: number,
- dracoLoader: DRACOLoader,
- resolve: () => void
-) {
- if (modelsLoaded === modelsToLoad) {
- toast.success("Models Loaded!");
- dracoLoader.dispose();
- }
- resolve();
-}
-
+import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
+import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
+import gsap from 'gsap';
+import * as THREE from 'three';
+import * as CONSTANTS from '../../../types/world/worldConstants';
+import { toast } from 'react-toastify';
+import * as Types from "../../../types/world/worldTypes";
+import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
+import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
+import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
+
+async function loadInitialFloorItems(
+ itemsGroup: Types.RefGroup,
+ setFloorItems: Types.setFloorItemSetState,
+): Promise {
+ if (!itemsGroup.current) return;
+ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
+ const email = localStorage.getItem('email');
+ const organization = (email!.split("@")[1]).split(".")[0];
+
+ const items = await getFloorAssets(organization);
+ localStorage.setItem("FloorItems", JSON.stringify(items));
+ await initializeDB();
+
+ if (items.message === "floorItems not found") return;
+
+ if (items) {
+ const storedFloorItems: Types.FloorItems = items;
+ const loader = new GLTFLoader();
+ const dracoLoader = new DRACOLoader();
+
+ dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
+ loader.setDRACOLoader(dracoLoader);
+
+ let modelsLoaded = 0;
+ const modelsToLoad = storedFloorItems.length;
+
+ const camData = await getCamera(organization, localStorage.getItem('userId')!);
+ let storedPosition;
+ if (camData && camData.position) {
+ storedPosition = camData?.position;
+ } else {
+ storedPosition = new THREE.Vector3(0, 40, 30);
+ }
+ if (!storedPosition) return;
+ const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
+
+ storedFloorItems.sort((a, b) => {
+ const aPosition = new THREE.Vector3(a.position[0], a.position[1], a.position[2]);
+ const bPosition = new THREE.Vector3(b.position[0], b.position[1], b.position[2]);
+ return cameraPosition.distanceTo(aPosition) - cameraPosition.distanceTo(bPosition);
+ });
+
+ for (const item of storedFloorItems) {
+ if (!item.modelfileID) return;
+ const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
+ let storedPosition;
+ if (localStorage.getItem("cameraPosition")) {
+ storedPosition = JSON.parse(localStorage.getItem("cameraPosition")!);
+ } else {
+ storedPosition = new THREE.Vector3(0, 40, 30);
+ }
+
+ const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
+
+ if (cameraPosition.distanceTo(itemPosition) < 50) {
+ await new Promise(async (resolve) => {
+
+ // Check Three.js Cache
+ const cachedModel = THREE.Cache.get(item.modelfileID!);
+ if (cachedModel) {
+ // console.log(`[Cache] Fetching ${item.modelname}`);
+ processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
+ modelsLoaded++;
+ checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
+ return;
+ }
+
+ // Check IndexedDB
+ const indexedDBModel = await retrieveGLTF(item.modelfileID!);
+ if (indexedDBModel) {
+ // console.log(`[IndexedDB] Fetching ${item.modelname}`);
+ const blobUrl = URL.createObjectURL(indexedDBModel);
+ loader.load(blobUrl, (gltf) => {
+ URL.revokeObjectURL(blobUrl);
+ THREE.Cache.remove(blobUrl);
+ THREE.Cache.add(item.modelfileID!, gltf);
+ processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
+ modelsLoaded++;
+ checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
+ },
+ undefined,
+ (error) => {
+ toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
+ URL.revokeObjectURL(blobUrl);
+ resolve();
+ }
+ );
+ return;
+ }
+
+ // Fetch from Backend
+ // console.log(`[Backend] Fetching ${item.modelname}`);
+ const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`;
+ loader.load(modelUrl, async (gltf) => {
+ 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);
+ modelsLoaded++;
+ checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
+ },
+ undefined,
+ (error) => {
+ toast.error(`[Backend] Error loading ${item.modelname}:`);
+ resolve();
+ }
+ );
+ });
+ } else {
+ // console.log(`Item ${item.modelname} is not near`);
+ setFloorItems((prevItems) => [
+ ...(prevItems || []),
+ {
+ modeluuid: item.modeluuid,
+ modelname: item.modelname,
+ position: item.position,
+ rotation: item.rotation,
+ modelfileID: item.modelfileID,
+ isLocked: item.isLocked,
+ isVisible: item.isVisible,
+ },
+ ]);
+
+ modelsLoaded++;
+ checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, () => { });
+ }
+ }
+
+ // Dispose loader after all models
+ dracoLoader.dispose();
+ }
+}
+
+
+function processLoadedModel(
+ gltf: any,
+ item: Types.FloorItemType,
+ itemsGroup: Types.RefGroup,
+ setFloorItems: Types.setFloorItemSetState,
+) {
+ const model = gltf;
+ model.uuid = item.modeluuid;
+ model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
+ model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
+ model.position.set(...item.position);
+ model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
+
+ model.traverse((child: any) => {
+ if (child.isMesh) {
+ // Clone the material to ensure changes are independent
+ // child.material = child.material.clone();
+
+ child.castShadow = true;
+ child.receiveShadow = true;
+ }
+ });
+
+
+ itemsGroup?.current?.add(model);
+
+ setFloorItems((prevItems) => [
+ ...(prevItems || []),
+ {
+ modeluuid: item.modeluuid,
+ modelname: item.modelname,
+ position: item.position,
+ rotation: item.rotation,
+ modelfileID: item.modelfileID,
+ isLocked: item.isLocked,
+ isVisible: item.isVisible,
+ },
+ ]);
+
+ 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 checkLoadingCompletion(
+ modelsLoaded: number,
+ modelsToLoad: number,
+ dracoLoader: DRACOLoader,
+ resolve: () => void
+) {
+ if (modelsLoaded === modelsToLoad) {
+ toast.success("Models Loaded!");
+ dracoLoader.dispose();
+ }
+ resolve();
+}
+
export default loadInitialFloorItems;
\ No newline at end of file
diff --git a/app/src/modules/scene/IntialLoad/loadInitialLine.ts b/app/src/modules/builder/IntialLoad/loadInitialLine.ts
similarity index 97%
rename from app/src/modules/scene/IntialLoad/loadInitialLine.ts
rename to app/src/modules/builder/IntialLoad/loadInitialLine.ts
index 231d5aa..f8c3132 100644
--- a/app/src/modules/scene/IntialLoad/loadInitialLine.ts
+++ b/app/src/modules/builder/IntialLoad/loadInitialLine.ts
@@ -1,30 +1,30 @@
-import addLineToScene from '../../builder/geomentries/lines/addLineToScene';
-import * as CONSTANTS from '../../../types/world/worldConstants';
-import * as Types from "../../../types/world/worldTypes";
-
-function loadInitialLine(
- floorPlanGroupLine: Types.RefGroup,
- lines: Types.RefLines
-): void {
-
- if (!floorPlanGroupLine.current) return
-
- ////////// Load the Lines initially if there are any //////////
-
- floorPlanGroupLine.current.children = [];
- lines.current.forEach((line) => {
- let colour;
- if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName) {
- colour = CONSTANTS.lineConfig.wallColor;
- } else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName) {
- colour = CONSTANTS.lineConfig.floorColor;
- } else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName) {
- colour = CONSTANTS.lineConfig.aisleColor;
- }
- if (colour) {
- addLineToScene(line[0][0], line[1][0], colour, line, floorPlanGroupLine);
- }
- });
-}
-
-export default loadInitialLine;
+import addLineToScene from '../../builder/geomentries/lines/addLineToScene';
+import * as CONSTANTS from '../../../types/world/worldConstants';
+import * as Types from "../../../types/world/worldTypes";
+
+function loadInitialLine(
+ floorPlanGroupLine: Types.RefGroup,
+ lines: Types.RefLines
+): void {
+
+ if (!floorPlanGroupLine.current) return
+
+ ////////// Load the Lines initially if there are any //////////
+
+ floorPlanGroupLine.current.children = [];
+ lines.current.forEach((line) => {
+ let colour;
+ if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName) {
+ colour = CONSTANTS.lineConfig.wallColor;
+ } else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName) {
+ colour = CONSTANTS.lineConfig.floorColor;
+ } else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName) {
+ colour = CONSTANTS.lineConfig.aisleColor;
+ }
+ if (colour) {
+ addLineToScene(line[0][0], line[1][0], colour, line, floorPlanGroupLine);
+ }
+ });
+}
+
+export default loadInitialLine;
diff --git a/app/src/modules/scene/IntialLoad/loadInitialPoint.ts b/app/src/modules/builder/IntialLoad/loadInitialPoint.ts
similarity index 97%
rename from app/src/modules/scene/IntialLoad/loadInitialPoint.ts
rename to app/src/modules/builder/IntialLoad/loadInitialPoint.ts
index f042427..7dfdf1d 100644
--- a/app/src/modules/scene/IntialLoad/loadInitialPoint.ts
+++ b/app/src/modules/builder/IntialLoad/loadInitialPoint.ts
@@ -1,87 +1,87 @@
-import * as THREE from 'three';
-
-import * as CONSTANTS from '../../../types/world/worldConstants';
-import * as Types from "../../../types/world/worldTypes";
-
-////////// Load the Boxes initially if there are any //////////
-
-function loadInitialPoint(
- lines: Types.RefLines,
- floorPlanGroupPoint: Types.RefGroup,
- currentLayerPoint: Types.RefMeshArray,
- dragPointControls: Types.RefDragControl
-): void {
-
- if (!floorPlanGroupPoint.current) return
-
- floorPlanGroupPoint.current.children = [];
- currentLayerPoint.current = [];
- lines.current.forEach((line) => {
- const colour = getPointColor(line[0][3]);
- line.forEach((pointData) => {
- const [point, id] = pointData;
-
- /////////// Check if a box with this id already exists //////////
-
- const existingBox = floorPlanGroupPoint.current?.getObjectByProperty('uuid', id);
- if (existingBox) {
- return;
- }
-
- const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
- const material = new THREE.ShaderMaterial({
- uniforms: {
- uColor: { value: new THREE.Color(colour) }, // Blue color for the border
- uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
- },
- vertexShader: `
- varying vec2 vUv;
-
- void main() {
- vUv = uv;
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `,
- fragmentShader: `
- varying vec2 vUv;
- uniform vec3 uColor;
- uniform vec3 uInnerColor;
-
- void main() {
- // Define the size of the white square as a proportion of the face
- float borderThickness = 0.2; // Adjust this value for border thickness
- if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
- vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
- gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
- } else {
- gl_FragColor = vec4(uColor, 1.0); // Blue border
- }
- }
- `,
- });
- const box = new THREE.Mesh(geometry, material);
- box.name = "point";
- box.uuid = id;
- box.userData = { type: line[0][3], color: colour };
- box.position.set(point.x, point.y, point.z);
- currentLayerPoint.current.push(box);
-
- floorPlanGroupPoint.current?.add(box);
- });
- });
-
- function getPointColor(lineType: string | undefined): string {
- switch (lineType) {
- case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
- case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
- case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
- default: return CONSTANTS.pointConfig.defaultOuterColor;
- }
- }
-
- if (dragPointControls.current) {
- dragPointControls.current!.objects = currentLayerPoint.current;
- }
-}
-
-export default loadInitialPoint;
+import * as THREE from 'three';
+
+import * as CONSTANTS from '../../../types/world/worldConstants';
+import * as Types from "../../../types/world/worldTypes";
+
+////////// Load the Boxes initially if there are any //////////
+
+function loadInitialPoint(
+ lines: Types.RefLines,
+ floorPlanGroupPoint: Types.RefGroup,
+ currentLayerPoint: Types.RefMeshArray,
+ dragPointControls: Types.RefDragControl
+): void {
+
+ if (!floorPlanGroupPoint.current) return
+
+ floorPlanGroupPoint.current.children = [];
+ currentLayerPoint.current = [];
+ lines.current.forEach((line) => {
+ const colour = getPointColor(line[0][3]);
+ line.forEach((pointData) => {
+ const [point, id] = pointData;
+
+ /////////// Check if a box with this id already exists //////////
+
+ const existingBox = floorPlanGroupPoint.current?.getObjectByProperty('uuid', id);
+ if (existingBox) {
+ return;
+ }
+
+ const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
+ const material = new THREE.ShaderMaterial({
+ uniforms: {
+ uColor: { value: new THREE.Color(colour) }, // Blue color for the border
+ uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
+ },
+ vertexShader: `
+ varying vec2 vUv;
+
+ void main() {
+ vUv = uv;
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
+ }
+ `,
+ fragmentShader: `
+ varying vec2 vUv;
+ uniform vec3 uColor;
+ uniform vec3 uInnerColor;
+
+ void main() {
+ // Define the size of the white square as a proportion of the face
+ float borderThickness = 0.2; // Adjust this value for border thickness
+ if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
+ vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
+ gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
+ } else {
+ gl_FragColor = vec4(uColor, 1.0); // Blue border
+ }
+ }
+ `,
+ });
+ const box = new THREE.Mesh(geometry, material);
+ box.name = "point";
+ box.uuid = id;
+ box.userData = { type: line[0][3], color: colour };
+ box.position.set(point.x, point.y, point.z);
+ currentLayerPoint.current.push(box);
+
+ floorPlanGroupPoint.current?.add(box);
+ });
+ });
+
+ function getPointColor(lineType: string | undefined): string {
+ switch (lineType) {
+ case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
+ case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
+ case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
+ default: return CONSTANTS.pointConfig.defaultOuterColor;
+ }
+ }
+
+ if (dragPointControls.current) {
+ dragPointControls.current!.objects = currentLayerPoint.current;
+ }
+}
+
+export default loadInitialPoint;
diff --git a/app/src/modules/scene/IntialLoad/loadInitialWallItems.ts b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts
similarity index 97%
rename from app/src/modules/scene/IntialLoad/loadInitialWallItems.ts
rename to app/src/modules/builder/IntialLoad/loadInitialWallItems.ts
index c5184bb..34273af 100644
--- a/app/src/modules/scene/IntialLoad/loadInitialWallItems.ts
+++ b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts
@@ -1,54 +1,54 @@
-import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
-
-import * as Types from "../../../types/world/worldTypes";
-import { getWallItems } from '../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi';
-
-////////// Load the Wall Items's intially of there is any //////////
-
-async function loadInitialWallItems(
- setWallItems: Types.setWallItemSetState,
- AssetConfigurations: Types.AssetConfigurations
-): Promise {
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- const items = await getWallItems(organization);
-
- localStorage.setItem("WallItems", JSON.stringify(items));
- if (items.length > 0) {
- const storedWallItems: Types.wallItems = items;
-
- const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => {
- const loader = new GLTFLoader();
- return new Promise((resolve) => {
- loader.load(AssetConfigurations[item.modelname!].modelUrl, (gltf) => {
- const model = gltf.scene;
- model.uuid = item.modeluuid!;
-
- model.children[0].children.forEach((child: any) => {
- if (child.name !== "CSG_REF") {
- child.castShadow = true;
- child.receiveShadow = true;
- }
- });
-
- resolve({
- type: item.type,
- model: model,
- modelname: item.modelname,
- scale: item.scale,
- csgscale: item.csgscale,
- csgposition: item.csgposition,
- position: item.position,
- quaternion: item.quaternion,
- });
- });
- });
- }));
-
- setWallItems(loadedWallItems);
- }
-}
-
-export default loadInitialWallItems;
+import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
+
+import * as Types from "../../../types/world/worldTypes";
+import { getWallItems } from '../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi';
+
+////////// Load the Wall Items's intially of there is any //////////
+
+async function loadInitialWallItems(
+ setWallItems: Types.setWallItemSetState,
+ AssetConfigurations: Types.AssetConfigurations
+): Promise {
+
+ const email = localStorage.getItem('email')
+ const organization = (email!.split("@")[1]).split(".")[0];
+
+ const items = await getWallItems(organization);
+
+ localStorage.setItem("WallItems", JSON.stringify(items));
+ if (items.length > 0) {
+ const storedWallItems: Types.wallItems = items;
+
+ const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => {
+ const loader = new GLTFLoader();
+ return new Promise((resolve) => {
+ loader.load(AssetConfigurations[item.modelname!].modelUrl, (gltf) => {
+ const model = gltf.scene;
+ model.uuid = item.modeluuid!;
+
+ model.children[0].children.forEach((child: any) => {
+ if (child.name !== "CSG_REF") {
+ child.castShadow = true;
+ child.receiveShadow = true;
+ }
+ });
+
+ resolve({
+ type: item.type,
+ model: model,
+ modelname: item.modelname,
+ scale: item.scale,
+ csgscale: item.csgscale,
+ csgposition: item.csgposition,
+ position: item.position,
+ quaternion: item.quaternion,
+ });
+ });
+ });
+ }));
+
+ setWallItems(loadedWallItems);
+ }
+}
+
+export default loadInitialWallItems;
diff --git a/app/src/modules/builder/agv/agv.tsx b/app/src/modules/builder/agv/agv.tsx
deleted file mode 100644
index 0a2d14e..0000000
--- a/app/src/modules/builder/agv/agv.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { useEffect, useRef, useState } from "react";
-import { Line } from "@react-three/drei";
-import {
- useNavMesh,
- usePlayAgv,
- useSimulationStates,
-} from "../../../store/store";
-import PathNavigator from "./pathNavigator";
-import { useAnimationPlaySpeed, usePlayButtonStore, useResetButtonStore } from "../../../store/usePlayButtonStore";
-
-type PathPoints = {
- modelUuid: string;
- modelSpeed: number;
- bufferTime: number;
- points: { x: number; y: number; z: number }[];
- hitCount: number;
-};
-interface ProcessContainerProps {
- processes: any[];
- agvRef: any;
- MaterialRef: any;
-}
-
-const Agv: React.FC = ({
- processes,
- agvRef,
- MaterialRef,
-}) => {
- const [pathPoints, setPathPoints] = useState([]);
- const { simulationStates } = useSimulationStates();
- const { navMesh } = useNavMesh();
- const { isPlaying } = usePlayButtonStore();
- const { isReset, setReset } = useResetButtonStore();
- const { speed } = useAnimationPlaySpeed();
- const globalSpeed = useRef(1);
-
- useEffect(() => { globalSpeed.current = speed }, [speed])
-
- useEffect(() => {
- if (!isPlaying || isReset) {
- agvRef.current = [];
- }
- }, [isPlaying, isReset])
-
- useEffect(() => {
- if (simulationStates.length > 0) {
- const agvModels = simulationStates.filter(
- (val) => val.modelName === "agv" && val.type === "Vehicle"
- );
-
- 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, },
- ],
- }));
-
- 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/navMeshDetails.tsx b/app/src/modules/builder/agv/navMeshDetails.tsx
deleted file mode 100644
index 697d89b..0000000
--- a/app/src/modules/builder/agv/navMeshDetails.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { init as initRecastNavigation } from "@recast-navigation/core";
-import { generateSoloNavMesh } from "@recast-navigation/generators";
-import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three";
-import { useThree } from "@react-three/fiber";
-import * as THREE from "three";
-import * as Types from "../../../types/world/worldTypes";
-
-interface NavMeshDetailsProps {
- setNavMesh: (navMesh: any) => void;
- groupRef: React.MutableRefObject;
- lines: Types.RefLines;
-}
-
-export default function NavMeshDetails({
- lines,
- setNavMesh,
- groupRef,
-}: NavMeshDetailsProps) {
- const { scene } = useThree();
-
- useEffect(() => {
- const initializeNavigation = async () => {
- try {
- await initRecastNavigation();
-
- if (!groupRef.current || groupRef.current.children.length === 0) {
- return;
- }
-
- const meshes = groupRef?.current?.children as THREE.Mesh[];
-
- const [positions, indices] = getPositionsAndIndices(meshes);
-
- const cellSize = 0.2;
- const cellHeight = 0.7;
- const walkableRadius = 0.5;
- const { success, navMesh } = generateSoloNavMesh(positions, indices, {
- cs: cellSize,
- ch: cellHeight,
- walkableRadius: Math.round(walkableRadius / cellHeight),
- });
-
- if (!success || !navMesh) {
- return;
- }
-
- setNavMesh(navMesh);
-
- scene.children
- .filter((child) => child instanceof DebugDrawer)
- .forEach((child) => scene.remove(child));
-
- const debugDrawer = new DebugDrawer();
- debugDrawer.drawNavMesh(navMesh);
- // scene.add(debugDrawer);
- } catch (error) { }
- };
-
- initializeNavigation();
- }, [scene, groupRef, lines.current]);
-
- return null;
-}
diff --git a/app/src/modules/builder/agv/pathNavigator.tsx b/app/src/modules/builder/agv/pathNavigator.tsx
deleted file mode 100644
index a82b53c..0000000
--- a/app/src/modules/builder/agv/pathNavigator.tsx
+++ /dev/null
@@ -1,480 +0,0 @@
-import React, { useEffect, useState, useRef, useMemo } from "react";
-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 {
- useAnimationPlaySpeed,
- usePlayButtonStore,
-} from "../../../store/usePlayButtonStore";
-import { usePlayAgv } from "../../../store/store";
-
-interface PathNavigatorProps {
- navMesh: any;
- pathPoints: any;
- id: string;
- speed: number;
- globalSpeed: number;
- bufferTime: number;
- hitCount: number;
- processes: any[];
- agvRef: any;
- MaterialRef: any;
-}
-interface AGVData {
- processId: string;
- vehicleId: string;
- hitCount: number;
- totalHits: number;
-}
-type Phase = "initial" | "toDrop" | "toPickup";
-type MaterialType = "Box" | "Crate";
-export default function PathNavigator({
- navMesh,
- pathPoints,
- id,
- speed,
- globalSpeed,
- bufferTime,
- hitCount,
- processes,
- agvRef,
- MaterialRef,
-}: PathNavigatorProps) {
- const [currentPhase, setCurrentPhase] = useState("initial");
- const [path, setPath] = useState<[number, number, number][]>([]);
- 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 [boxVisible, setBoxVisible] = useState(false);
-
- const distancesRef = useRef([]);
- const totalDistanceRef = useRef(0);
- const progressRef = useRef(0);
- const isWaiting = useRef(false);
- const timeoutRef = useRef(null);
- const hasStarted = useRef(false);
- const hasReachedPickup = useRef(false);
-
- const { scene } = useThree();
- const { isPlaying } = usePlayButtonStore();
- const { PlayAgv, setPlayAgv } = usePlayAgv();
-
- const boxRef = useRef(null);
-
- const baseMaterials = useMemo(
- () => ({
- Box: new THREE.MeshStandardMaterial({ color: 0x8b4513 }),
- Crate: new THREE.MeshStandardMaterial({ color: 0x00ff00 }),
- Default: new THREE.MeshStandardMaterial({ color: 0xcccccc }),
- }),
- []
- );
-
- useEffect(() => {
- const object = scene.getObjectByProperty("uuid", id);
- if (object) {
- setInitialPosition(object.position.clone());
- setInitialRotation(object.rotation.clone());
- }
- }, [scene, id]);
-
- 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 [];
- }
- };
-
- const resetState = () => {
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- timeoutRef.current = null;
- }
-
- setPath([]);
- setCurrentPhase("initial");
- setToPickupPath([]);
- setPickupDropPath([]);
- setDropPickupPath([]);
- setBoxVisible(false);
- distancesRef.current = [];
- totalDistanceRef.current = 0;
- progressRef.current = 0;
- isWaiting.current = false;
- hasStarted.current = false;
- hasReachedPickup.current = false;
-
- if (initialPosition && initialRotation) {
- const object = scene.getObjectByProperty("uuid", id);
- if (object) {
- object.position.copy(initialPosition);
- object.rotation.copy(initialRotation);
- }
- }
- };
-
- useEffect(() => {
- if (!isPlaying) {
- resetState();
- }
-
- if (!navMesh || pathPoints.length < 2) return;
-
- const [pickup, drop] = pathPoints.slice(-2);
-
- const object = scene.getObjectByProperty("uuid", id);
- if (!object) return;
-
- const currentPosition = object.position;
-
- const toPickupPath = computePath(currentPosition, pickup);
- const pickupToDropPath = computePath(pickup, drop);
- const dropToPickupPath = computePath(drop, pickup);
-
- if (
- toPickupPath.length &&
- pickupToDropPath.length &&
- dropToPickupPath.length
- ) {
- setPickupDropPath(pickupToDropPath);
- setDropPickupPath(dropToPickupPath);
- setToPickupPath(toPickupPath);
- setPath(toPickupPath);
- setCurrentPhase("initial");
- }
- }, [navMesh, pathPoints, hitCount, isPlaying, PlayAgv]);
-
- useEffect(() => {
- if (path.length < 2) return;
-
- 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;
- });
-
- distancesRef.current = segmentDistances;
- totalDistanceRef.current = total;
- progressRef.current = 0;
- isWaiting.current = false;
- }, [path]);
-
- function logAgvStatus(id: string, status: string) {
- // console.log(
- // `AGV ${id}: ${status}`
-
- // );
- }
-
- function findProcessByTargetModelUUID(processes: any, targetModelUUID: any) {
- for (const process of processes) {
- for (const path of process.paths) {
- for (const point of path.points) {
- if (
- point.connections?.targets?.some(
- (target: any) => target.modelUUID === targetModelUUID
- )
- ) {
- return process.id;
- }
- }
- }
- }
- return null;
- }
-
- useEffect(() => {
- if (!scene || !boxRef || !processes || !MaterialRef.current) return;
-
- const existingObject = scene.getObjectByProperty("uuid", id);
- if (!existingObject) return;
-
- if (boxRef.current?.parent) {
- boxRef.current.parent.remove(boxRef.current);
- boxRef.current = null;
- }
-
- if (boxVisible) {
- const matchedProcess = findProcessByTargetModelUUID(processes, id);
- let materialType: "Box" | "Crate" | "Default" = "Default";
-
- if (matchedProcess) {
- const materialEntry = MaterialRef.current.find((item: any) =>
- item.objects.some((obj: any) => obj.processId === matchedProcess)
- );
- if (materialEntry) {
- materialType = materialEntry.material;
- }
- }
-
- const boxGeometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
- const boxMesh = new THREE.Mesh(boxGeometry, baseMaterials[materialType]);
- boxMesh.position.y = 1;
- boxMesh.name = `box-${id}`;
- existingObject.add(boxMesh);
- boxRef.current = boxMesh;
- }
-
- return () => {
- if (boxRef.current?.parent) {
- boxRef.current.parent.remove(boxRef.current);
- }
- };
- }, [processes, MaterialRef, boxVisible, scene, id, baseMaterials]);
-
- useFrame((_, delta) => {
- const currentAgv = (agvRef.current || []).find(
- (agv: AGVData) => agv.vehicleId === id
- );
-
- if (!scene || !id || !isPlaying) return;
-
- const object = scene.getObjectByProperty("uuid", id);
- if (!object) return;
-
- if (isPlaying && !hasStarted.current) {
- hasStarted.current = false;
- progressRef.current = 0;
- isWaiting.current = false;
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- timeoutRef.current = null;
- }
- }
-
- const isAgvReady = () => {
- if (!agvRef.current || agvRef.current.length === 0) return false;
- if (!currentAgv) return false;
-
- return currentAgv.isActive && hitCount >= currentAgv.maxHitCount;
- };
-
- if (isPlaying && !hasStarted.current && toPickupPath.length > 0) {
- setBoxVisible(false);
- const startPoint = new THREE.Vector3(...toPickupPath[0]);
- object.position.copy(startPoint);
-
- if (toPickupPath.length > 1) {
- const nextPoint = new THREE.Vector3(...toPickupPath[1]);
- const direction = nextPoint.clone().sub(startPoint).normalize();
- object.rotation.y = Math.atan2(direction.x, direction.z);
- }
-
- hasStarted.current = true;
- progressRef.current = 0;
- hasReachedPickup.current = false;
- setToPickupPath(toPickupPath.slice(-1));
- logAgvStatus(id, "Started from station, heading to pickup");
- return;
- }
-
- if (isPlaying && currentPhase === "initial" && !hasReachedPickup.current) {
- const reached = moveAlongPath(
- object,
- path,
- distancesRef.current,
- speed,
- delta,
- progressRef
- );
-
- if (reached) {
- hasReachedPickup.current = true;
- if (currentAgv) {
- currentAgv.status = "picking";
- }
- logAgvStatus(id, "Reached pickup point, Waiting for material");
- }
- return;
- }
-
- if (isPlaying && currentAgv?.isActive && currentPhase === "initial") {
- if (!isAgvReady()) return;
- setTimeout(() => {
- setBoxVisible(true);
- setPath([...pickupDropPath]);
- setCurrentPhase("toDrop");
- progressRef.current = 0;
- logAgvStatus(id, "Started from pickup point, heading to drop point");
- if (currentAgv) {
- currentAgv.status = "toDrop";
- }
- }, 0);
- return;
- }
-
- if (isPlaying && currentPhase === "toDrop") {
- const reached = moveAlongPath(
- object,
- path,
- distancesRef.current,
- speed,
- delta,
- progressRef
- );
-
- if (reached && !isWaiting.current) {
- isWaiting.current = true;
- logAgvStatus(id, "Reached drop point");
- if (currentAgv) {
- currentAgv.status = "droping";
- currentAgv.hitCount = currentAgv.hitCount--;
- }
- timeoutRef.current = setTimeout(() => {
- setPath([...dropPickupPath]);
- setCurrentPhase("toPickup");
- progressRef.current = 0;
- isWaiting.current = false;
- setBoxVisible(false);
- if (currentAgv) {
- currentAgv.status = "toPickup";
- }
- logAgvStatus(
- id,
- "Started from droping point, heading to pickup point"
- );
- }, bufferTime * 1000);
- }
- return;
- }
-
- if (isPlaying && currentPhase === "toPickup") {
- const reached = moveAlongPath(
- object,
- path,
- distancesRef.current,
- speed,
- delta,
- progressRef
- );
-
- if (reached) {
- if (currentAgv) {
- currentAgv.isActive = false;
- }
- setCurrentPhase("initial");
- if (currentAgv) {
- currentAgv.status = "picking";
- }
- logAgvStatus(id, "Reached pickup point again, cycle complete");
- }
- return;
- }
-
- moveAlongPath(
- object,
- path,
- distancesRef.current,
- speed,
- delta,
- progressRef
- );
- });
-
- function moveAlongPath(
- object: THREE.Object3D,
- path: [number, number, number][],
- distances: number[],
- speed: number,
- delta: number,
- progressRef: React.MutableRefObject
- ): boolean {
- if (path.length < 2) return false;
-
- progressRef.current += delta * (speed * globalSpeed);
- let covered = progressRef.current;
- let accumulated = 0;
- let index = 0;
-
- for (; index < distances.length; index++) {
- const dist = distances[index];
- if (accumulated + dist >= covered) break;
- accumulated += dist;
- }
-
- if (index >= path.length - 1) {
- if (path.length > 1) {
- const lastDirection = new THREE.Vector3(...path[path.length - 1])
- .sub(new THREE.Vector3(...path[path.length - 2]))
- .normalize();
- object.rotation.y = Math.atan2(lastDirection.x, lastDirection.z);
- }
- return true;
- }
-
- const start = new THREE.Vector3(...path[index]);
- const end = new THREE.Vector3(...path[index + 1]);
- const dist = distances[index];
-
- const t = THREE.MathUtils.clamp((covered - accumulated) / dist, 0, 1);
- object.position.copy(start.clone().lerp(end, t));
-
- if (dist > 0.1) {
- const targetDirection = end.clone().sub(start).normalize();
- const targetRotationY = Math.atan2(targetDirection.x, targetDirection.z);
-
- const rotationSpeed = Math.min(5 * delta, 1);
- object.rotation.y = THREE.MathUtils.lerp(
- object.rotation.y,
- targetRotationY,
- rotationSpeed
- );
- }
-
- return false;
- }
-
- useEffect(() => {
- return () => {
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- }
- };
- }, []);
-
- return (
-
- {toPickupPath.length > 0 && (
-
- )}
-
- {pickupDropPath.length > 0 && (
-
- )}
-
- {dropPickupPath.length > 0 && (
-
- )}
-
- );
-}
diff --git a/app/src/modules/builder/agv/polygonGenerator.tsx b/app/src/modules/builder/agv/polygonGenerator.tsx
deleted file mode 100644
index 2462018..0000000
--- a/app/src/modules/builder/agv/polygonGenerator.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-import * as THREE from "three";
-import { useEffect, useState } from "react";
-import * as turf from "@turf/turf";
-import * as Types from "../../../types/world/worldTypes";
-import arrayLinesToObject from "../geomentries/lines/lineConvertions/arrayLinesToObject";
-interface PolygonGeneratorProps {
- groupRef: React.MutableRefObject;
- lines: Types.RefLines;
-}
-
-export default function PolygonGenerator({
- groupRef,
- lines,
-}: PolygonGeneratorProps) {
-
- useEffect(() => {
- let allLines = arrayLinesToObject(lines.current);
- const wallLines = allLines?.filter((line) => line?.type === "WallLine");
- const aisleLines = allLines?.filter((line) => line?.type === "AisleLine");
-
- const wallPoints = wallLines
- .map((pair) => pair?.line.map((vals) => vals.position))
- .filter((wall): wall is THREE.Vector3[] => !!wall);
-
- const result = aisleLines.map((pair) =>
- pair?.line.map((point) => ({
- position: [point.position.x, point.position.z],
- uuid: point.uuid,
- }))
- );
-
- if (!result || result.some((line) => !line)) {
- return;
- }
-
- const lineFeatures = result?.map((line: any) =>
- turf.lineString(line.map((p: any) => p?.position))
- );
-
- const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
- renderWallGeometry(wallPoints);
-
- if (polygons.features.length > 1) {
- polygons.features.forEach((feature) => {
- if (feature.geometry.type === "Polygon") {
-
- const shape = new THREE.Shape();
- const coords = feature.geometry.coordinates[0];
-
- shape.moveTo(coords[0][0], coords[0][1]);
-
- for (let i = 1; i < coords.length; i++) {
- shape.lineTo(coords[i][0], coords[i][1]);
- }
- shape.lineTo(coords[0][0], coords[0][1]);
-
- const extrudeSettings = {
- depth: 5,
- bevelEnabled: false,
- };
-
- const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
-
- const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 });
- const mesh = new THREE.Mesh(geometry, material);
- mesh.rotateX(Math.PI / 2);
- mesh.name = "agv-collider";
- mesh.position.y = 5;
-
- mesh.receiveShadow = true;
- groupRef.current?.add(mesh);
- }
- });
- }
-
- }, [lines.current]);
-
- const renderWallGeometry = (walls: THREE.Vector3[][]) => {
- walls.forEach((wall) => {
- if (wall.length < 2) return;
-
- for (let i = 0; i < wall.length - 1; i++) {
- const start = new THREE.Vector3(wall[i].x, wall[i].y, wall[i].z);
- const end = new THREE.Vector3(
- wall[i + 1].x,
- wall[i + 1].y,
- wall[i + 1].z
- );
-
- const wallHeight = 10;
- const direction = new THREE.Vector3().subVectors(end, start);
- const length = direction.length();
- direction.normalize();
-
- const wallGeometry = new THREE.BoxGeometry(length, wallHeight);
- const wallMaterial = new THREE.MeshBasicMaterial({
- color: "#aaa",
- transparent: true,
- opacity: 0.5,
- });
-
- const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
- const midPoint = new THREE.Vector3()
- .addVectors(start, end)
- .multiplyScalar(0.5);
- wallMesh.position.set(midPoint.x, wallHeight / 2, midPoint.z);
-
- const quaternion = new THREE.Quaternion();
- quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction);
- wallMesh.quaternion.copy(quaternion);
-
- groupRef.current?.add(wallMesh);
- }
- });
- };
-
- return null;
-}
diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx
new file mode 100644
index 0000000..e7f83e2
--- /dev/null
+++ b/app/src/modules/builder/builder.tsx
@@ -0,0 +1,355 @@
+////////// Three and React Three Fiber Imports //////////
+
+import * as THREE from "three";
+import { useEffect, useRef, useState } from "react";
+import { useThree, useFrame } from "@react-three/fiber";
+
+////////// Component Imports //////////
+
+import DistanceText from "./geomentries/lines/distanceText/distanceText";
+import ReferenceDistanceText from "./geomentries/lines/distanceText/referenceDistanceText";
+
+////////// Assests Imports //////////
+
+import arch from "../../assets/gltf-glb/arch.glb";
+import door from "../../assets/gltf-glb/door.glb";
+import Window from "../../assets/gltf-glb/window.glb";
+
+////////// Zustand State Imports //////////
+
+import {
+ useToggleView,
+ useDeletePointOrLine,
+ useMovePoint,
+ useActiveLayer,
+ useSocketStore,
+ useWallVisibility,
+ useRoofVisibility,
+ useShadows,
+ useUpdateScene,
+ useWalls,
+ useToolMode,
+ useRefTextUpdate,
+ useRenderDistance,
+ useLimitDistance,
+} from "../../store/store";
+
+////////// 3D Function Imports //////////
+
+import loadWalls from "./geomentries/walls/loadWalls";
+
+import * as Types from "../../types/world/worldTypes";
+
+import SocketResponses from "../collaboration/socket/socketResponses.dev";
+import FloorItemsGroup from "./groups/floorItemsGroup";
+import FloorPlanGroup from "./groups/floorPlanGroup";
+import FloorGroup from "./groups/floorGroup";
+import FloorGroupAilse from "./groups/floorGroupAisle";
+import Draw from "./functions/draw";
+import WallsAndWallItems from "./groups/wallsAndWallItems";
+import Ground from "../scene/environment/ground";
+// import ZoneGroup from "../groups/zoneGroup1";
+import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
+import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
+import DrieHtmlTemp from "..//visualization/mqttTemp/drieHtmlTemp";
+import ZoneGroup from "./groups/zoneGroup";
+import useModuleStore from "../../store/useModuleStore";
+import MeasurementTool from "../scene/tools/measurementTool";
+import NavMesh from "../simulation/vehicle/navMesh/navMesh";
+
+export default function Builder() {
+ const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
+ const csg = useRef(); // Reference for CSG object, used for 3D modeling.
+ const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
+ const scene = useRef() as Types.RefScene; // Reference to the scene.
+ const camera = useRef() as Types.RefCamera; // Reference to the camera object.
+ const controls = useRef(); // Reference to the controls object.
+ const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
+ const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
+
+ // Assigning the scene and camera from the Three.js state to the references.
+
+ scene.current = state.scene;
+ camera.current = state.camera;
+ controls.current = state.controls;
+ raycaster.current = state.raycaster;
+
+ const plane = useRef(null); // Reference for a plane object for raycaster reference.
+ const grid = useRef() as any; // Reference for a grid object for raycaster reference.
+ const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
+ const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
+ const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
+ const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
+ const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
+ const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
+ const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
+ const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
+ const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
+ const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
+ const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
+ const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
+ const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn.
+ const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
+ const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
+ const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
+ const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
+ const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
+ const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
+ const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
+ const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
+ const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
+ const floorGroupAisle = useRef() as Types.RefGroup;
+ const zoneGroup = useRef() as Types.RefGroup;
+ const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
+ const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
+ const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
+ const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
+ const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
+ const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
+ const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
+
+ const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
+
+ const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item.
+ const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
+ const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
+ const { toolMode, setToolMode } = useToolMode();
+ const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
+ const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
+ const { socket } = useSocketStore();
+ const { roofVisibility, setRoofVisibility } = useRoofVisibility();
+ const { wallVisibility, setWallVisibility } = useWallVisibility();
+ const { shadows, setShadows } = useShadows();
+ const { renderDistance, setRenderDistance } = useRenderDistance();
+ const { limitDistance, setLimitDistance } = useLimitDistance();
+ const { updateScene, setUpdateScene } = useUpdateScene();
+ const { walls, setWalls } = useWalls();
+ const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
+ const { activeModule } = useModuleStore();
+
+ // const loader = new GLTFLoader();
+ // const dracoLoader = new DRACOLoader();
+
+ // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
+ // loader.setDRACOLoader(dracoLoader);
+
+ ////////// Assest Configuration Values //////////
+
+ const AssetConfigurations: Types.AssetConfigurations = {
+ arch: {
+ modelUrl: arch,
+ scale: [0.75, 0.75, 0.75],
+ csgscale: [2, 4, 0.5],
+ csgposition: [0, 2, 0],
+ positionY: () => 0,
+ type: "Fixed-Move",
+ },
+ door: {
+ modelUrl: door,
+ scale: [0.75, 0.75, 0.75],
+ csgscale: [2, 4, 0.5],
+ csgposition: [0, 2, 0],
+ positionY: () => 0,
+ type: "Fixed-Move",
+ },
+ window: {
+ modelUrl: Window,
+ scale: [0.75, 0.75, 0.75],
+ csgscale: [5, 3, 0.5],
+ csgposition: [0, 1.5, 0],
+ positionY: (intersectionPoint) => intersectionPoint.point.y,
+ type: "Free-Move",
+ },
+ };
+
+ ////////// All Toggle's //////////
+
+ useEffect(() => {
+ setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
+ if (dragPointControls.current) {
+ dragPointControls.current.enabled = false;
+ }
+ if (toggleView) {
+ Layer2DVisibility(
+ activeLayer,
+ floorPlanGroup,
+ floorPlanGroupLine,
+ floorPlanGroupPoint,
+ currentLayerPoint,
+ dragPointControls
+ );
+ } else {
+ setToolMode(null);
+ setDeletePointOrLine(false);
+ setMovePoint(false);
+ loadWalls(lines, setWalls);
+ setUpdateScene(true);
+ line.current = [];
+ }
+ }, [toggleView]);
+
+ useEffect(() => {
+ THREE.Cache.clear();
+ THREE.Cache.enabled = true;
+ }, []);
+
+ useEffect(() => {
+ const email = localStorage.getItem("email");
+ const organization = email!.split("@")[1].split(".")[0];
+
+ async function fetchVisibility() {
+ const visibility = await findEnvironment(
+ organization,
+ localStorage.getItem("userId")!
+ );
+ if (visibility) {
+ setRoofVisibility(visibility.roofVisibility);
+ setWallVisibility(visibility.wallVisibility);
+ setShadows(visibility.shadowVisibility);
+ setRenderDistance(visibility.renderDistance);
+ setLimitDistance(visibility.limitDistance);
+ }
+ }
+ fetchVisibility();
+ }, []);
+
+ ////////// UseFrame is Here //////////
+
+ useFrame(() => {
+ if (toolMode) {
+ Draw(
+ state,
+ plane,
+ cursorPosition,
+ floorPlanGroupPoint,
+ floorPlanGroupLine,
+ snappedPoint,
+ isSnapped,
+ isSnappedUUID,
+ line,
+ lines,
+ ispreSnapped,
+ floorPlanGroup,
+ ReferenceLineMesh,
+ LineCreated,
+ setRefTextUpdate,
+ Tube,
+ anglesnappedPoint,
+ isAngleSnapped,
+ toolMode
+ );
+ }
+ });
+
+ ////////// Return //////////
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts
index 29b0627..193dd41 100644
--- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts
+++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts
@@ -5,13 +5,12 @@ import { toast } from 'react-toastify';
import TempLoader from './tempLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import * as Types from "../../../../types/world/worldTypes";
-import * as SimulationTypes from "../../../../types/simulationTypes";
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { Socket } from 'socket.io-client';
import * as CONSTANTS from '../../../../types/world/worldConstants';
-import { getAssetEventType } from '../../../../services/simulation/getAssetEventType';
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
+import PointsCalculator from '../../../simulation/events/points/pointsCalculator';
async function addAssetModel(
raycaster: THREE.Raycaster,
@@ -25,7 +24,7 @@ async function addAssetModel(
socket: Socket,
selectedItem: any,
setSelectedItem: any,
- setSimulationStates: any,
+ addEvent: (event: EventsSchema) => void,
plane: Types.RefMesh,
): Promise {
@@ -66,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, setSimulationStates, socket);
+ handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket);
return;
} else {
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
@@ -79,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, setSimulationStates, socket);
+ handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
@@ -91,7 +90,7 @@ async function addAssetModel(
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/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, setSimulationStates, socket);
+ await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
@@ -114,7 +113,7 @@ async function handleModelLoad(
tempLoader: Types.RefMesh,
isTempLoader: Types.RefBoolean,
setFloorItems: Types.setFloorItemSetState,
- setSimulationStates: any,
+ addEvent: (event: EventsSchema) => void,
socket: Socket
) {
const model = gltf.scene.clone();
@@ -137,7 +136,7 @@ async function handleModelLoad(
tempLoader.current = undefined;
}
- const newFloorItem: SimulationTypes.EventData = {
+ const newFloorItem: Types.FloorItemType = {
modeluuid: model.uuid,
modelname: selectedItem.name,
modelfileID: selectedItem.id,
@@ -150,316 +149,159 @@ async function handleModelLoad(
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "";
- getAssetEventType(selectedItem.id, organization).then(async (res) => {
+ // API
- if (res.type === "Conveyor") {
- const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
+ // 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,
+ // );
- const backendEventData: Extract = {
- type: 'Conveyor',
- points: res.points.map((point: any, index: number) => ({
- uuid: pointUUIDs[index],
- position: point.position as [number, number, number],
- rotation: point.rotation as [number, number, number],
- actions: [{
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- type: 'Inherit',
- material: 'Inherit',
- delay: 'Inherit',
- spawnInterval: 'Inherit',
- isUsed: true
- }],
- triggers: [],
- connections: {
- source: { modelUUID: model.uuid, pointUUID: pointUUIDs[index] },
- targets: []
+ // 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
+ };
+
+ if (selectedItem.type) {
+ const data = PointsCalculator(
+ selectedItem.type,
+ gltf.scene.clone(),
+ new THREE.Vector3(...model.rotation)
+ );
+
+ if (!data || !data.points) return;
+
+ if (selectedItem.type === "Conveyor") {
+ const ConveyorEvent: ConveyorEventSchema = {
+ modelUuid: newFloorItem.modeluuid,
+ modelName: newFloorItem.modelname,
+ position: newFloorItem.position,
+ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
+ state: "idle",
+ type: 'transfer',
+ speed: 1,
+ points: data.points.map((point: THREE.Vector3, index: number) => ({
+ uuid: THREE.MathUtils.generateUUID(),
+ position: [point.x, point.y, point.z],
+ rotation: [0, 0, 0],
+ action: {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: `Action ${index}`,
+ actionType: 'default',
+ material: 'inherit',
+ delay: 0,
+ spawnInterval: 5,
+ spawnCount: 1,
+ triggers: []
}
- })),
- speed: 'Inherit'
- };
-
- // 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,
- // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
- // );
-
- // 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,
- eventData: backendEventData,
- socketId: socket.id
- };
-
- setFloorItems((prevItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- const eventData: any = backendEventData;
- eventData.modeluuid = newFloorItem.modeluuid;
- eventData.modelName = newFloorItem.modelname;
- eventData.position = newFloorItem.position;
- eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- eventData as SimulationTypes.ConveyorEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (res.type === "Vehicle") {
-
- const pointUUID = THREE.MathUtils.generateUUID();
-
- const backendEventData: Extract = {
- type: "Vehicle",
- points: {
- uuid: pointUUID,
- position: res.points.position as [number, number, number],
- rotation: res.points.rotation as [number, number, number],
- 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,
- }
+ }))
}
-
- // 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,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
+ addEvent(ConveyorEvent);
+ } else if (selectedItem.type === "Vehicle") {
+ const vehicleEvent: VehicleEventSchema = {
+ modelUuid: newFloorItem.modeluuid,
+ modelName: newFloorItem.modelname,
position: newFloorItem.position,
- rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id
- };
-
- const eventData: any = backendEventData;
- eventData.modeluuid = newFloorItem.modeluuid;
- eventData.modelName = newFloorItem.modelname;
- eventData.position = newFloorItem.position;
-
- setFloorItems((prevItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- eventData as SimulationTypes.VehicleEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (res.type === "StaticMachine") {
-
- const pointUUID = THREE.MathUtils.generateUUID();
-
- const backendEventData: Extract = {
- type: "StaticMachine",
- points: {
- uuid: pointUUID,
- position: res.points.position as [number, number, number],
- rotation: res.points.rotation as [number, number, number],
- actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', buffer: 0, material: 'Inherit' },
- triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
- connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
+ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
+ state: "idle",
+ type: "vehicle",
+ speed: 1,
+ point: {
+ uuid: THREE.MathUtils.generateUUID(),
+ position: [data.points[0].x, data.points[0].y, data.points[0].z],
+ rotation: [0, 0, 0],
+ action: {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: "Vehicle Action",
+ actionType: "travel",
+ material: null,
+ unLoadDuration: 5,
+ loadCapacity: 10,
+ pickUpPoint: null,
+ unLoadPoint: null,
+ triggers: []
+ }
}
- }
-
- // 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,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // 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,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id
};
-
- const eventData: any = backendEventData;
- eventData.modeluuid = newFloorItem.modeluuid;
- eventData.modelName = newFloorItem.modelname;
- eventData.position = newFloorItem.position;
- eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
-
- setFloorItems((prevItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- eventData as SimulationTypes.StaticMachineEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (res.type === "ArmBot") {
-
- const pointUUID = THREE.MathUtils.generateUUID();
-
- const backendEventData: Extract = {
- type: "ArmBot",
- points: {
- uuid: pointUUID,
- position: res.points.position as [number, number, number],
- rotation: res.points.rotation as [number, number, number],
- actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 0.2, processes: [] },
- triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
- connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
+ addEvent(vehicleEvent);
+ } else if (selectedItem.type === "ArmBot") {
+ const roboticArmEvent: RoboticArmEventSchema = {
+ modelUuid: newFloorItem.modeluuid,
+ modelName: newFloorItem.modelname,
+ position: newFloorItem.position,
+ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
+ state: "idle",
+ type: "roboticArm",
+ speed: 1,
+ point: {
+ uuid: THREE.MathUtils.generateUUID(),
+ position: [data.points[0].x, data.points[0].y, data.points[0].z],
+ rotation: [0, 0, 0],
+ actions: [
+ {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: "Pick and Place",
+ actionType: "pickAndPlace",
+ process: {
+ startPoint: [0, 0, 0],
+ endPoint: [0, 0, 0]
+ },
+ triggers: []
+ }
+ ]
}
- }
-
- // 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,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // 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,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id
};
-
- const eventData: any = backendEventData;
- eventData.modeluuid = newFloorItem.modeluuid;
- eventData.modelName = newFloorItem.modelname;
- eventData.position = newFloorItem.position;
- eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
-
- setFloorItems((prevItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- eventData as SimulationTypes.ArmBotEventsSchema
- ]);
-
- 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,
+ addEvent(roboticArmEvent);
+ } else if (selectedItem.type === "Machine") {
+ const machineEvent: MachineEventSchema = {
+ modelUuid: newFloorItem.modeluuid,
+ modelName: newFloorItem.modelname,
position: newFloorItem.position,
- rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id
+ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
+ state: "idle",
+ type: "machine",
+ point: {
+ uuid: THREE.MathUtils.generateUUID(),
+ position: [data.points[0].x, data.points[0].y, data.points[0].z],
+ rotation: [0, 0, 0],
+ action: {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: "Process Action",
+ actionType: "process",
+ processTime: 10,
+ swapMaterial: "material-id",
+ triggers: []
+ }
+ }
};
-
-
- setFloorItems((prevItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- socket.emit("v2:model-asset:add", data);
+ addEvent(machineEvent);
}
+ }
- gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
- gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
+ 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" });
+ gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
}
export default addAssetModel;
diff --git a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts
index dbd7e9b..18136b3 100644
--- a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts
+++ b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts
@@ -2,7 +2,6 @@ import { toast } from 'react-toastify';
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
-import * as SimulationTypes from "../../../../types/simulationTypes";
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
import { Socket } from 'socket.io-client';
import { getFloorAssets } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
@@ -11,7 +10,6 @@ async function DeleteFloorItems(
itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh,
setFloorItems: Types.setFloorItemSetState,
- setSimulationStates: any,
socket: Socket
): Promise {
@@ -77,11 +75,6 @@ async function DeleteFloorItems(
}
setFloorItems(updatedItems);
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid);
- return updatedEvents;
- });
-
toast.success("Model Removed!");
}
}
diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx
index acc284f..2a3c2cc 100644
--- a/app/src/modules/builder/groups/floorItemsGroup.tsx
+++ b/app/src/modules/builder/groups/floorItemsGroup.tsx
@@ -1,5 +1,5 @@
import { useFrame, useThree } from "@react-three/fiber";
-import { useActiveTool, useAsset3dWidget, useCamMode, useDeletableFloorItem, useDeleteTool, useFloorItems, useLoadingProgress, useRenderDistance, useSelectedFloorItem, useSelectedItem, useSimulationStates, useSocketStore, useToggleView, useTransformMode, } from "../../../store/store";
+import { useActiveTool, useAsset3dWidget, useCamMode, useDeletableFloorItem, useDeleteTool, useFloorItems, useLoadingProgress, useRenderDistance, useSelectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode, } from "../../../store/store";
import assetVisibility from "../geomentries/assets/assetVisibility";
import { useEffect } from "react";
import * as THREE from "three";
@@ -11,11 +11,13 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import DeletableHoveredFloorItems from "../geomentries/assets/deletableHoveredFloorItems";
import DeleteFloorItems from "../geomentries/assets/deleteFloorItems";
-import loadInitialFloorItems from "../../scene/IntialLoad/loadInitialFloorItems";
+import loadInitialFloorItems from "../IntialLoad/loadInitialFloorItems";
import addAssetModel from "../geomentries/assets/addAssetModel";
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
import useModuleStore from "../../../store/useModuleStore";
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
+import { useEventsStore } from "../../../store/simulation/useEventsStore";
+
const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url));
const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
@@ -32,12 +34,12 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
const { setSelectedFloorItem } = useSelectedFloorItem();
const { activeTool } = useActiveTool();
const { selectedItem, setSelectedItem } = useSelectedItem();
- const { simulationStates, setSimulationStates } = useSimulationStates();
const { setLoadingProgress } = useLoadingProgress();
const { activeModule } = useModuleStore();
const { socket } = useSocketStore();
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
+ const { addEvent } = useEventsStore();
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
loader.setDRACOLoader(dracoLoader);
@@ -73,7 +75,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
gltfLoaderWorker.postMessage({ floorItems: data });
} else {
gltfLoaderWorker.postMessage({ floorItems: [] });
- loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
+ loadInitialFloorItems(itemsGroup, setFloorItems);
updateLoadingProgress(100);
}
});
@@ -92,7 +94,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
updateLoadingProgress(progress);
if (loadedAssets === totalAssets) {
- loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
+ loadInitialFloorItems(itemsGroup, setFloorItems);
updateLoadingProgress(100);
}
});
@@ -192,9 +194,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
if (drag) return;
if (deleteTool) {
- DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, setSimulationStates, socket);
-
- // Remove EventData if there are any in the asset.
+ DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, socket);
}
const Mode = transformMode;
@@ -278,7 +278,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
if (!event.dataTransfer?.files[0]) return;
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
- addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, setSimulationStates, plane);
+ addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, addEvent, plane);
}
};
@@ -314,14 +314,14 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
useFrame(() => {
if (controls)
// assetVisibility(itemsGroup, state.camera.position, renderDistance);
- if (deleteTool && activeModule === "builder") {
- DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem);
- } else if (!deleteTool) {
- if (hoveredDeletableFloorItem.current) {
- hoveredDeletableFloorItem.current = undefined;
- setDeletableFloorItem(null);
+ if (deleteTool && activeModule === "builder") {
+ DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem);
+ } else if (!deleteTool) {
+ if (hoveredDeletableFloorItem.current) {
+ hoveredDeletableFloorItem.current = undefined;
+ setDeletableFloorItem(null);
+ }
}
- }
});
return ;
diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx
index 6369e1e..12d75f0 100644
--- a/app/src/modules/builder/groups/floorPlanGroup.tsx
+++ b/app/src/modules/builder/groups/floorPlanGroup.tsx
@@ -9,15 +9,14 @@ import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
import DeleteLayer from "../geomentries/layers/deleteLayer";
import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
-import loadInitialPoint from "../../scene/IntialLoad/loadInitialPoint";
-import loadInitialLine from "../../scene/IntialLoad/loadInitialLine";
+import loadInitialPoint from "../IntialLoad/loadInitialPoint";
+import loadInitialLine from "../IntialLoad/loadInitialLine";
import deletePoint from "../geomentries/points/deletePoint";
import deleteLine from "../geomentries/lines/deleteLine";
import drawWall from "../geomentries/lines/drawWall";
import drawOnlyFloor from "../geomentries/floors/drawOnlyFloor";
import addDragControl from "../eventDeclaration/dragControlDeclaration";
-
const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, floorGroup, currentLayerPoint, dragPointControls, hoveredDeletablePoint, hoveredDeletableLine, plane, line, lines, onlyFloorline, onlyFloorlines, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
const state = useThree();
const { scene, camera, gl, raycaster, controls } = state;
diff --git a/app/src/modules/builder/groups/wallItemsGroup.tsx b/app/src/modules/builder/groups/wallItemsGroup.tsx
index cdc326e..43845e7 100644
--- a/app/src/modules/builder/groups/wallItemsGroup.tsx
+++ b/app/src/modules/builder/groups/wallItemsGroup.tsx
@@ -7,7 +7,7 @@ import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
import DeleteWallItems from "../geomentries/walls/deleteWallItems";
-import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems";
+import loadInitialWallItems from "../IntialLoad/loadInitialWallItems";
import AddWallItems from "../geomentries/walls/addWallItems";
import useModuleStore from "../../../store/useModuleStore";
@@ -37,51 +37,6 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
////////// Update the Rotation value changes in the selected item //////////
- useEffect(() => {
- if (objectScale.x && objectScale.y && objectScale.z) {
- let ScaledWallItems: Types.wallItems = [];
- wallItems.forEach((items: any) => {
- if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
- items.scale = [objectScale.x, objectScale.y, objectScale.z];
- }
- ScaledWallItems.push(items);
- });
- setWallItems(ScaledWallItems);
- }
- }, [objectScale]);
-
- useEffect(() => {
- if (objectPosition.x && objectPosition.y && objectPosition.z) {
- let ScaledWallItems: Types.wallItems = [];
- wallItems.forEach((items: any) => {
- if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
- items.position = [objectPosition.x, objectPosition.y, objectPosition.z];
- }
- ScaledWallItems.push(items);
- });
- setWallItems(ScaledWallItems);
- }
- }, [objectPosition]);
-
- useEffect(() => {
- if (objectRotation.x && objectRotation.y && objectRotation.z) {
- let ScaledWallItems: Types.wallItems = [];
- wallItems.forEach((items: any) => {
- if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
- const radiansX = objectRotation.x * (Math.PI / 180);
- const radiansY = objectRotation.y * (Math.PI / 180);
- const radiansZ = objectRotation.z * (Math.PI / 180);
- const quaternion = new THREE.Quaternion().setFromEuler(
- new THREE.Euler(radiansX, radiansY, radiansZ)
- );
- items.quaternion = [quaternion.x, quaternion.y, quaternion.z, quaternion.w];
- }
- ScaledWallItems.push(items);
- });
- setWallItems(ScaledWallItems);
- }
- }, [objectRotation]);
-
useEffect(() => {
const canvasElement = state.gl.domElement;
function handlePointerMove(e: any) {
diff --git a/app/src/modules/builder/groups/zoneGroup1.tsx b/app/src/modules/builder/groups/zoneGroup1.tsx
deleted file mode 100644
index 80be9a3..0000000
--- a/app/src/modules/builder/groups/zoneGroup1.tsx
+++ /dev/null
@@ -1,245 +0,0 @@
-import { useEffect } from "react";
-import * as THREE from 'three';
-import * as Types from '../../../types/world/worldTypes';
-import * as CONSTANTS from "../../../types/world/worldConstants";
-import { useActiveLayer, useSocketStore, useDeleteTool, useDeletePointOrLine, useMovePoint, useToggleView, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
-import { useThree } from "@react-three/fiber";
-import arrayLineToObject from "../geomentries/lines/lineConvertions/arrayLineToObject";
-import addPointToScene from "../geomentries/points/addPointToScene";
-import addLineToScene from "../geomentries/lines/addLineToScene";
-import removeSoloPoint from "../geomentries/points/removeSoloPoint";
-import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
-import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
-import loadZones from "../geomentries/zones/loadZones";
-
-const ZoneGroup = ({ zoneGroup, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
- const { toggleView, setToggleView } = useToggleView();
- const { deleteTool, setDeleteTool } = useDeleteTool();
- const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
- const { toolMode, setToolMode } = useToolMode();
- const { movePoint, setMovePoint } = useMovePoint();
- const { socket } = useSocketStore();
- const { activeLayer } = useActiveLayer();
- const { gl, raycaster, camera, pointer } = useThree();
- const { updateScene, setUpdateScene } = useUpdateScene();
- const { newLines, setNewLines } = useNewLines();
-
- useEffect(() => {
- if (updateScene) {
- loadZones(lines, zoneGroup);
- setUpdateScene(false);
- }
- }, [updateScene])
-
- useEffect(() => {
- if (toolMode === "Zone") {
- setDeletePointOrLine(false);
- setMovePoint(false);
- setDeleteTool(false);
- } else {
- removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
- removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
- }
- }, [toolMode])
-
- useEffect(() => {
-
- const canvasElement = gl.domElement;
-
- let drag = false;
- let isLeftMouseDown = false;
-
- const onMouseDown = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = true;
- drag = false;
- }
- };
-
- const onMouseUp = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = false;
- }
- }
-
- const onMouseMove = () => {
- if (isLeftMouseDown) {
- drag = true;
- }
- };
-
- const onContextMenu = (e: any) => {
- e.preventDefault();
- if (toolMode === "Zone") {
- removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
- removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
- }
- };
-
- const onMouseClick = (evt: any) => {
- if (!plane.current || drag) return;
- const intersects = raycaster.intersectObject(plane.current, true);
- let intersectionPoint = intersects[0].point;
- const points = floorPlanGroupPoint.current?.children ?? [];
- const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible);
- let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
-
- if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) {
- const lineType = intersectsLines[0].object.userData.linePoints[0][3];
- if (lineType === CONSTANTS.lineConfig.zoneName) {
- // console.log("intersected a zone line");
-
- const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(300);
- let intersection = getClosestIntersection(ThroughPoint, intersectionPoint);
- if (!intersection) return;
- const point = addPointToScene(intersection, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
- (line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.zoneName,]);
- if (line.current.length >= 2 && line.current[0] && line.current[1]) {
- lines.current.push(line.current as Types.Line);
-
- const data = arrayLineToObject(line.current as Types.Line);
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- //REST
-
- // setLine(organization, data.layer!, data.line!, data.type!);
-
- //SOCKET
-
- const input = {
- organization: organization,
- layer: data.layer,
- line: data.line,
- type: data.type,
- socketId: socket.id
- }
-
- socket.emit('v1:Line:create', input);
-
- setNewLines([line.current]);
-
- addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
- let lastPoint = line.current[line.current.length - 1];
- line.current = [lastPoint];
- }
- }
- } else if (intersectsPoint && intersects && intersects.length > 0) {
- if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.zoneName) {
- // console.log("intersected a zone point");
-
- intersectionPoint = intersectsPoint.object.position;
- (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
- if (line.current.length >= 2 && line.current[0] && line.current[1]) {
- lines.current.push(line.current as Types.Line);
-
- const data = arrayLineToObject(line.current as Types.Line);
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- //REST
-
- // setLine(organization, data.layer!, data.line!, data.type!);
-
- //SOCKET
-
- const input = {
- organization: organization,
- layer: data.layer,
- line: data.line,
- type: data.type,
- socketId: socket.id
- }
-
- socket.emit('v1:Line:create', input);
-
- setNewLines([line.current]);
-
- addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
- let lastPoint = line.current[line.current.length - 1];
- line.current = [lastPoint];
- ispreSnapped.current = false;
- isSnapped.current = false;
- }
- }
- } else if (intersects && intersects.length > 0) {
- // console.log("intersected a empty area");
-
- let uuid: string = "";
- if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) {
- intersectionPoint = anglesnappedPoint.current;
- const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
- uuid = point.uuid;
- } else if (isSnapped.current && snappedPoint.current && line.current.length > 0) {
- intersectionPoint = snappedPoint.current;
- uuid = isSnappedUUID.current!;
- } else if (ispreSnapped.current && snappedPoint.current) {
- intersectionPoint = snappedPoint.current;
- uuid = isSnappedUUID.current!;
- } else {
- const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
- uuid = point.uuid;
- }
-
- (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
- if (line.current.length >= 2 && line.current[0] && line.current[1]) {
- lines.current.push(line.current as Types.Line);
-
- const data = arrayLineToObject(line.current as Types.Line);
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- //REST
-
- // setLine(organization, data.layer!, data.line!, data.type!);
-
- //SOCKET
-
- const input = {
- organization: organization,
- layer: data.layer,
- line: data.line,
- type: data.type,
- socketId: socket.id
- }
-
- socket.emit('v1:Line:create', input);
-
- setNewLines([line.current]);
-
- addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
- let lastPoint = line.current[line.current.length - 1];
- line.current = [lastPoint];
- ispreSnapped.current = false;
- isSnapped.current = false;
- }
- }
- }
-
- if (toolMode === 'Zone') {
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
- canvasElement.addEventListener("click", onMouseClick);
- canvasElement.addEventListener("contextmenu", onContextMenu);
- }
-
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- canvasElement.removeEventListener("click", onMouseClick);
- canvasElement.removeEventListener("contextmenu", onContextMenu);
- };
- }, [toolMode])
-
- return (
-
-
- )
-}
-
-export default ZoneGroup;
\ No newline at end of file
diff --git a/app/src/modules/collaboration/camera/collabCams.tsx b/app/src/modules/collaboration/camera/collabCams.tsx
new file mode 100644
index 0000000..1347a2a
--- /dev/null
+++ b/app/src/modules/collaboration/camera/collabCams.tsx
@@ -0,0 +1,231 @@
+import * as THREE from "three";
+import { useEffect, useRef, useState } from "react";
+import { useFrame } from "@react-three/fiber";
+import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
+import camModel from "../../../assets/gltf-glb/camera face 2.gltf";
+import getActiveUsersData from "../../../services/factoryBuilder/collab/getActiveUsers";
+import { useActiveUsers, useSocketStore } from "../../../store/store";
+import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
+import { useNavigate } from "react-router-dom";
+import { Html } from "@react-three/drei";
+import CollabUserIcon from "../../../functions/collabUserIcon";
+import { getAvatarColor } from "../../../functions/users/functions/getAvatarColor";
+import useModuleStore from "../../../store/useModuleStore";
+
+const CamModelsGroup = () => {
+ const navigate = useNavigate();
+ const groupRef = useRef(null);
+ const email = localStorage.getItem("email");
+ const { setActiveUsers } = useActiveUsers();
+ const { socket } = useSocketStore();
+ const { activeModule } = useModuleStore();
+
+ const loader = new GLTFLoader();
+ const dracoLoader = new DRACOLoader();
+ dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
+ loader.setDRACOLoader(dracoLoader);
+
+ const [cams, setCams] = useState([]);
+ const [models, setModels] = useState>({});
+
+ 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 dedupeUsers = (users: any[]) => {
+ const seen = new Set();
+ return users.filter((user) => {
+ if (seen.has(user._id)) return false;
+ seen.add(user._id);
+ return true;
+ });
+ };
+
+ useEffect(() => {
+ if (!email) navigate("/");
+
+ if (!socket) return;
+ const organization = email!.split("@")[1].split(".")[0];
+
+ 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 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) => 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;
+
+ setCams((prev) =>
+ prev.filter((cam) => cam.uuid !== data.data.userData._id)
+ );
+ setActiveUsers((prev: any) =>
+ prev.filter((user: any) => user._id !== data.data.userData._id)
+ );
+ });
+
+ socket.on("cameraUpdateResponse", (data: any) => {
+ if (
+ !groupRef.current ||
+ socket.id === data.socketId ||
+ organization !== data.organization
+ )
+ 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
+ ),
+ },
+ }));
+ });
+
+ return () => {
+ socket.off("userConnectResponse");
+ socket.off("userDisConnectResponse");
+ socket.off("cameraUpdateResponse");
+ };
+ }, [socket]);
+
+ useFrame(() => {
+ if (!groupRef.current) return;
+ Object.keys(models).forEach((uuid) => {
+ const model = groupRef.current!.getObjectByProperty("uuid", uuid);
+ if (!model) return;
+
+ 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/collabCams.tsx b/app/src/modules/collaboration/collabCams.tsx
deleted file mode 100644
index ca0d1c5..0000000
--- a/app/src/modules/collaboration/collabCams.tsx
+++ /dev/null
@@ -1,231 +0,0 @@
-import * as THREE from "three";
-import { useEffect, useRef, useState } from "react";
-import { useFrame } from "@react-three/fiber";
-import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
-import camModel from "../../assets/gltf-glb/camera face 2.gltf";
-import getActiveUsersData from "../../services/factoryBuilder/collab/getActiveUsers";
-import { useActiveUsers, useSocketStore } from "../../store/store";
-import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
-import { useNavigate } from "react-router-dom";
-import { Html } from "@react-three/drei";
-import CollabUserIcon from "./collabUserIcon";
-import { getAvatarColor } from "./users/functions/getAvatarColor";
-import useModuleStore from "../../store/useModuleStore";
-
-const CamModelsGroup = () => {
- const navigate = useNavigate();
- const groupRef = useRef(null);
- const email = localStorage.getItem("email");
- const { setActiveUsers } = useActiveUsers();
- const { socket } = useSocketStore();
- const { activeModule } = useModuleStore();
-
- const loader = new GLTFLoader();
- const dracoLoader = new DRACOLoader();
- dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
- loader.setDRACOLoader(dracoLoader);
-
- const [cams, setCams] = useState([]);
- const [models, setModels] = useState>({});
-
- 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 dedupeUsers = (users: any[]) => {
- const seen = new Set();
- return users.filter((user) => {
- if (seen.has(user._id)) return false;
- seen.add(user._id);
- return true;
- });
- };
-
- useEffect(() => {
- if (!email) navigate("/");
-
- if (!socket) return;
- const organization = email!.split("@")[1].split(".")[0];
-
- 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 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) => 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;
-
- setCams((prev) =>
- prev.filter((cam) => cam.uuid !== data.data.userData._id)
- );
- setActiveUsers((prev: any) =>
- prev.filter((user: any) => user._id !== data.data.userData._id)
- );
- });
-
- socket.on("cameraUpdateResponse", (data: any) => {
- if (
- !groupRef.current ||
- socket.id === data.socketId ||
- organization !== data.organization
- )
- 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
- ),
- },
- }));
- });
-
- return () => {
- socket.off("userConnectResponse");
- socket.off("userDisConnectResponse");
- socket.off("cameraUpdateResponse");
- };
- }, [socket]);
-
- useFrame(() => {
- if (!groupRef.current) return;
- Object.keys(models).forEach((uuid) => {
- const model = groupRef.current!.getObjectByProperty("uuid", uuid);
- if (!model) return;
-
- 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/collaboration.tsx b/app/src/modules/collaboration/collaboration.tsx
new file mode 100644
index 0000000..84d3ab1
--- /dev/null
+++ b/app/src/modules/collaboration/collaboration.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import CamModelsGroup from './camera/collabCams'
+
+const Collaboration = () => {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default Collaboration
\ No newline at end of file
diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx
similarity index 94%
rename from app/src/modules/collaboration/socketResponses.dev.tsx
rename to app/src/modules/collaboration/socket/socketResponses.dev.tsx
index 6e578a1..3d9cddf 100644
--- a/app/src/modules/collaboration/socketResponses.dev.tsx
+++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx
@@ -1,827 +1,827 @@
-import { useEffect } from "react";
-import * as THREE from 'three';
-import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
-import gsap from 'gsap';
-import { toast } from 'react-toastify';
-import { useSocketStore, useActiveLayer, useWallItems, useFloorItems, useLayers, useUpdateScene, useWalls, useDeletedLines, useNewLines, useZonePoints, useZones } from "../../store/store";
-
-import * as Types from "../../types/world/worldTypes";
-import * as CONSTANTS from '../../types/world/worldConstants';
-import TempLoader from "../builder/geomentries/assets/tempLoader";
-
-// import { setFloorItemApi } from "../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
-import objectLineToArray from "../builder/geomentries/lines/lineConvertions/objectLineToArray";
-import addLineToScene from "../builder/geomentries/lines/addLineToScene";
-import updateLinesPositions from "../builder/geomentries/lines/updateLinesPositions";
-import updateLines from "../builder/geomentries/lines/updateLines";
-import updateDistanceText from "../builder/geomentries/lines/updateDistanceText";
-import updateFloorLines from "../builder/geomentries/floors/updateFloorLines";
-import loadWalls from "../builder/geomentries/walls/loadWalls";
-import RemoveConnectedLines from "../builder/geomentries/lines/removeConnectedLines";
-import Layer2DVisibility from "../builder/geomentries/layers/layer2DVisibility";
-import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
-import { retrieveGLTF, storeGLTF } from "../../utils/indexDB/idbUtils";
-import { getZonesApi } from "../../services/factoryBuilder/zones/getZonesApi";
-
-
-export default function SocketResponses({
- floorPlanGroup,
- lines,
- floorGroup,
- floorGroupAisle,
- scene,
- onlyFloorlines,
- AssetConfigurations,
- itemsGroup,
- isTempLoader,
- tempLoader,
- currentLayerPoint,
- floorPlanGroupPoint,
- floorPlanGroupLine,
- zoneGroup,
- dragPointControls
-}: any) {
-
- const { socket } = useSocketStore();
- const { activeLayer, setActiveLayer } = useActiveLayer();
- const { wallItems, setWallItems } = useWallItems();
- const { layers, setLayers } = useLayers();
- const { floorItems, setFloorItems } = useFloorItems();
- const { updateScene, setUpdateScene } = useUpdateScene();
- const { walls, setWalls } = useWalls();
- const { deletedLines, setDeletedLines } = useDeletedLines();
- const { newLines, setNewLines } = useNewLines();
- const { zones, setZones } = useZones();
- const { zonePoints, setZonePoints } = useZonePoints();
-
- useEffect(() => {
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- if (!socket) return
-
- socket.on('cameraCreateResponse', (data: any) => {
- // console.log('data: ', data);
- })
-
- socket.on('userConnectRespones', (data: any) => {
- // console.log('data: ', data);
- })
-
- socket.on('userDisConnectRespones', (data: any) => {
- // console.log('data: ', data);
- })
-
- socket.on('cameraUpdateResponse', (data: any) => {
- // console.log('data: ', data);
- })
-
- socket.on('EnvironmentUpdateResponse', (data: any) => {
- // console.log('data: ', data);
- })
-
- socket.on('model-asset:response:updates', async (data: any) => {
- // console.log('data: ', data);
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "Model created successfully") {
- const loader = new GLTFLoader();
- const dracoLoader = new DRACOLoader();
-
- dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
- loader.setDRACOLoader(dracoLoader);
- let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
-
- try {
- isTempLoader.current = true;
- const cachedModel = THREE.Cache.get(data.data.modelname);
- let url;
- if (cachedModel) {
- // console.log(`Getting ${data.data.modelname} from cache`);
- const model = cachedModel.scene.clone();
- model.uuid = data.data.modeluuid;
- model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid };
- model.position.set(...data.data.position as [number, number, number]);
- model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
- model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
-
- model.traverse((child: any) => {
- if (child.isMesh) {
- // Clone the material to ensure changes are independent
- // child.material = child.material.clone();
-
- child.castShadow = true;
- child.receiveShadow = true;
- }
- });
-
- itemsGroup.current.add(model);
-
- if (tempLoader.current) {
- tempLoader.current.material.dispose();
- tempLoader.current.geometry.dispose();
- itemsGroup.current.remove(tempLoader.current);
- tempLoader.current = undefined;
- }
-
- const newFloorItem: Types.FloorItemType = {
- modeluuid: data.data.modeluuid,
- modelname: data.data.modelname,
- modelfileID: data.data.modelfileID,
- position: [...data.data.position as [number, number, number]],
- rotation: {
- x: model.rotation.x,
- y: model.rotation.y,
- z: model.rotation.z,
- },
- isLocked: data.data.isLocked,
- isVisible: data.data.isVisible,
- };
-
- setFloorItems((prevItems: any) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' });
- gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } });
-
- } else {
- const indexedDBModel = await retrieveGLTF(data.data.modelname);
- if (indexedDBModel) {
- // console.log(`Getting ${data.data.modelname} from IndexedDB`);
- url = URL.createObjectURL(indexedDBModel);
- } else {
- // console.log(`Getting ${data.data.modelname} from Backend`);
- url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`;
- const modelBlob = await fetch(url).then((res) => res.blob());
- await storeGLTF(data.data.modelfileID, modelBlob);
- }
- }
-
- if (url) {
- loadModel(url);
- }
-
- } catch (error) {
- console.error('Error fetching asset model:', error);
- }
-
- function loadModel(url: string) {
- loader.load(url, (gltf) => {
- URL.revokeObjectURL(url);
- THREE.Cache.remove(url);
- const model = gltf.scene;
- model.uuid = data.data.modeluuid;
- model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid };
- model.position.set(...data.data.position as [number, number, number]);
- model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
- model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
-
- model.traverse((child: any) => {
- if (child.isMesh) {
- // Clone the material to ensure changes are independent
- // child.material = child.material.clone();
-
- child.castShadow = true;
- child.receiveShadow = true;
- }
- });
-
- itemsGroup.current.add(model);
-
- if (tempLoader.current) {
- tempLoader.current.material.dispose();
- tempLoader.current.geometry.dispose();
- itemsGroup.current.remove(tempLoader.current);
- tempLoader.current = undefined;
- }
-
- const newFloorItem: Types.FloorItemType = {
- modeluuid: data.data.modeluuid,
- modelname: data.data.modelname,
- modelfileID: data.data.modelfileID,
- position: [...data.data.position as [number, number, number]],
- rotation: {
- x: model.rotation.x,
- y: model.rotation.y,
- z: model.rotation.z,
- },
- isLocked: data.data.isLocked,
- isVisible: data.data.isVisible,
- };
-
- setFloorItems((prevItems: any) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' });
- gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } });
-
- THREE.Cache.add(data.data.modelname, gltf);
- }, () => {
- TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup);
- });
- }
-
- } else if (data.message === "Model updated successfully") {
- 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);
- }
- })
-
- setFloorItems((prevItems: Types.FloorItems) => {
- if (!prevItems) {
- return
- }
- let updatedItem: any = null;
- const updatedItems = prevItems.map((item) => {
- if (item.modeluuid === data.data.modeluuid) {
- updatedItem = {
- ...item,
- position: [...data.data.position] as [number, number, number],
- rotation: { x: data.data.rotation.x, y: data.data.rotation.y, z: data.data.rotation.z, },
- };
- return updatedItem;
- }
- return item;
- });
- return updatedItems;
- })
- }
- })
-
- socket.on('model-asset:response:updates', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "Model deleted successfully") {
- const deletedUUID = data.data.modeluuid;
- let items = JSON.parse(localStorage.getItem("FloorItems")!);
-
- const updatedItems = items.filter(
- (item: { modeluuid: string }) => item.modeluuid !== deletedUUID
- );
-
- const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
- const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== deletedUUID);
- localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
-
- itemsGroup.current.children.forEach((item: any) => {
- if (item.uuid === deletedUUID) {
- itemsGroup.current.remove(item);
- }
- })
- setFloorItems(updatedItems);
- toast.success("Model Removed!");
- }
- })
-
- socket.on('Line:response:update', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "line updated") {
- const DraggedUUID = data.data.uuid;
- const DraggedPosition = new THREE.Vector3(data.data.position.x, data.data.position.y, data.data.position.z);
-
- const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', DraggedUUID);
- point.position.set(DraggedPosition.x, DraggedPosition.y, DraggedPosition.z);
- const affectedLines = updateLinesPositions({ uuid: DraggedUUID, position: DraggedPosition }, lines);
-
- updateLines(floorPlanGroupLine, affectedLines);
- updateDistanceText(scene, floorPlanGroupLine, affectedLines);
- updateFloorLines(onlyFloorlines, { uuid: DraggedUUID, position: DraggedPosition });
-
- loadWalls(lines, setWalls);
- setUpdateScene(true);
-
- }
- })
-
- socket.on('Line:response:delete', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "line deleted") {
- const line = objectLineToArray(data.data);
- const linePoints = line;
- const connectedpoints = [linePoints[0][1], linePoints[1][1]];
-
-
- onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) =>
- floorline.filter((line: any) => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1])
- ).filter((floorline: any) => floorline.length > 0);
-
- const removedLine = lines.current.find((item: any) => (item[0][1] === linePoints[0][1] && item[1][1] === linePoints[1][1] || (item[0][1] === linePoints[1][1] && item[1][1] === linePoints[0][1])));
- lines.current = lines.current.filter((item: any) => item !== removedLine);
-
- floorPlanGroupLine.current.children.forEach((line: any) => {
- const linePoints = line.userData.linePoints as [number, string, number][];
- const uuid1 = linePoints[0][1];
- const uuid2 = linePoints[1][1];
-
- if ((uuid1 === connectedpoints[0] && uuid2 === connectedpoints[1] || (uuid1 === connectedpoints[1] && uuid2 === connectedpoints[0]))) {
- line.material.dispose();
- line.geometry.dispose();
- floorPlanGroupLine.current.remove(line);
- setDeletedLines([line.userData.linePoints])
- }
- });
-
- connectedpoints.forEach((pointUUID) => {
- let isConnected = false;
- floorPlanGroupLine.current.children.forEach((line: any) => {
- const linePoints = line.userData.linePoints;
- const uuid1 = linePoints[0][1];
- const uuid2 = linePoints[1][1];
- if (uuid1 === pointUUID || uuid2 === pointUUID) {
- isConnected = true;
- }
- });
-
- if (!isConnected) {
- floorPlanGroupPoint.current.children.forEach((point: any) => {
- if (point.uuid === pointUUID) {
- point.material.dispose();
- point.geometry.dispose();
- floorPlanGroupPoint.current.remove(point);
- }
- });
- }
- });
-
- loadWalls(lines, setWalls);
- setUpdateScene(true);
-
- toast.success("Line Removed!");
- }
- })
-
- socket.on('Line:response:delete:point', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "point deleted") {
- const point = floorPlanGroupPoint.current?.getObjectByProperty('uuid', data.data);
- point.material.dispose();
- point.geometry.dispose();
- floorPlanGroupPoint.current.remove(point);
-
- onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) =>
- floorline.filter((line: any) => line[0][1] !== data.data && line[1][1] !== data.data)
- ).filter((floorline: any) => floorline.length > 0);
-
- RemoveConnectedLines(data.data, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
-
- loadWalls(lines, setWalls);
- setUpdateScene(true);
-
- toast.success("Point Removed!");
- }
- })
-
- socket.on('Line:response:delete:layer', async (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "layer deleted") {
- setActiveLayer(1)
- const removedLayer = data.data;
- const removedLines: Types.Lines = lines.current.filter((line: any) => line[0][2] === removedLayer);
-
- ////////// Remove Points and lines from the removed layer //////////
-
- removedLines.forEach(async (line) => {
- line.forEach(async (removedPoint) => {
- const removableLines: THREE.Mesh[] = [];
- const connectedpoints: string[] = [];
-
- floorPlanGroupLine.current.children.forEach((line: any) => {
- const linePoints = line.userData.linePoints as [number, string, number][];
- const uuid1 = linePoints[0][1];
- const uuid2 = linePoints[1][1];
-
- if (uuid1 === removedPoint[1] || uuid2 === removedPoint[1]) {
- connectedpoints.push(uuid1 === removedPoint[1] ? uuid2 : uuid1);
- removableLines.push(line as THREE.Mesh);
- }
- });
-
- if (removableLines.length > 0) {
- removableLines.forEach((line: any) => {
- lines.current = lines.current.filter((item: any) => JSON.stringify(item) !== JSON.stringify(line.userData.linePoints));
- line.material.dispose();
- line.geometry.dispose();
- floorPlanGroupLine.current.remove(line);
- });
- }
-
- const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', removedPoint[1]);
- if (point) {
- point.material.dispose();
- point.geometry.dispose();
- floorPlanGroupPoint.current.remove(point)
- }
- });
- });
-
- ////////// Update the remaining lines layer values in the userData and in lines.current //////////
-
- let remaining = lines.current.filter((line: any) => line[0][2] !== removedLayer);
- let updatedLines: Types.Lines = [];
- remaining.forEach((line: any) => {
- let newLines = JSON.parse(JSON.stringify(line));
- if (newLines[0][2] > removedLayer) {
- newLines[0][2] -= 1;
- newLines[1][2] -= 1;
- }
-
- const matchingLine = floorPlanGroupLine.current.children.find((l: any) => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]);
- if (matchingLine) {
- const updatedUserData = JSON.parse(JSON.stringify(matchingLine.userData));
- updatedUserData.linePoints[0][2] = newLines[0][2];
- updatedUserData.linePoints[1][2] = newLines[1][2];
- matchingLine.userData = updatedUserData;
- }
- updatedLines.push(newLines);
- });
-
- lines.current = updatedLines;
- localStorage.setItem("Lines", JSON.stringify(lines.current));
-
- ////////// Also remove OnlyFloorLines and update it in localstorage //////////
-
- onlyFloorlines.current = onlyFloorlines.current.filter((floor: any) => {
- return floor[0][0][2] !== removedLayer;
- });
- const meshToRemove = floorGroup.current?.children.find((mesh: any) =>
- mesh.name === `Only_Floor_Line_${removedLayer}`
- );
- if (meshToRemove) {
- meshToRemove.geometry.dispose();
- meshToRemove.material.dispose();
- floorGroup.current?.remove(meshToRemove);
- }
-
- const zonesData = await getZonesApi(organization);
- const highestLayer = Math.max(
- 1,
- lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
- zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
- );
-
- setLayers(highestLayer);
-
- loadWalls(lines, setWalls);
- setUpdateScene(true);
-
- toast.success("Layer Removed!");
- }
- })
- }, [socket])
-
- useEffect(() => {
- if (!socket) return
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- socket.on('wallItemsDeleteResponse', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "wallitem deleted") {
- const deletedUUID = data.data.modeluuid;
- let WallItemsRef = wallItems;
- const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID);
-
- setWallItems([]);
- setTimeout(async () => {
- WallItemsRef = Items;
- setWallItems(WallItemsRef);
- const WallItemsForStorage = WallItemsRef.map((item: any) => {
- const { model, ...rest } = item;
- return {
- ...rest,
- modeluuid: model?.uuid,
- };
- });
-
- localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
- toast.success("Model Removed!");
- }, 50);
- }
- })
-
- socket.on('wallItemsUpdateResponse', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "wallIitem created") {
- const loader = new GLTFLoader();
- loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => {
- const model = gltf.scene;
- model.uuid = data.data.modeluuid;
- model.children[0].children.forEach((child) => {
- if (child.name !== "CSG_REF") {
- child.castShadow = true;
- child.receiveShadow = true;
- }
- });
-
- const newWallItem = {
- type: data.data.type,
- model: model,
- modelname: data.data.modelname,
- scale: data.data.scale,
- csgscale: data.data.csgscale,
- csgposition: data.data.csgposition,
- position: data.data.position,
- quaternion: data.data.quaternion
- };
-
- setWallItems((prevItems: any) => {
- const updatedItems = [...prevItems, newWallItem];
-
- const WallItemsForStorage = updatedItems.map(item => {
- const { model, ...rest } = item;
- return {
- ...rest,
- modeluuid: model?.uuid,
- };
- });
-
- localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
- toast.success("Model Added!");
-
- return updatedItems;
- });
- });
- } else if (data.message === "wallIitem updated") {
- const updatedUUID = data.data.modeluuid;
-
- setWallItems((prevItems: any) => {
- const updatedItems = prevItems.map((item: any) => {
- if (item.model.uuid === updatedUUID) {
- return {
- ...item,
- position: data.data.position,
- quaternion: data.data.quaternion,
- scale: data.data.scale,
- csgscale: data.data.csgscale,
- csgposition: data.data.csgposition,
- };
- }
- return item;
- });
-
- const WallItemsForStorage = updatedItems.map((item: any) => {
- const { model, ...rest } = item;
- return {
- ...rest,
- modeluuid: model?.uuid,
- };
- });
-
- localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
- toast.success("Model Updated!");
-
- return updatedItems;
- });
-
- }
-
- })
-
- return () => {
- socket.off('wallItemsDeleteResponse');
- socket.off('wallItemsUpdateResponse');
- };
- }, [wallItems])
-
- function getPointColor(lineType: string | undefined): string {
- switch (lineType) {
- case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
- case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
- case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
- default: return CONSTANTS.pointConfig.defaultOuterColor;
- }
- }
-
- function getLineColor(lineType: string | undefined): string {
- switch (lineType) {
- case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor;
- case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor;
- case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor;
- default: return CONSTANTS.lineConfig.defaultColor;
- }
- }
-
- useEffect(() => {
- if (!socket) return
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- socket.on('Line:response:create', async (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "line create") {
- const line: Types.Line = objectLineToArray(data.data);
- const type = line[0][3];
- const pointColour = getPointColor(type);
- const lineColour = getLineColor(type);
- setNewLines([line])
-
- line.forEach((line) => {
- const existingPoint = floorPlanGroupPoint.current?.getObjectByProperty('uuid', line[1]);
- if (existingPoint) {
- return;
- }
- const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
- const material = new THREE.ShaderMaterial({
- uniforms: {
- uColor: { value: new THREE.Color(pointColour) }, // Blue color for the border
- uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
- },
- vertexShader: `
- varying vec2 vUv;
-
- void main() {
- vUv = uv;
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `,
- fragmentShader: `
- varying vec2 vUv;
- uniform vec3 uColor;
- uniform vec3 uInnerColor;
-
- void main() {
- // Define the size of the white square as a proportion of the face
- float borderThickness = 0.2; // Adjust this value for border thickness
- if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
- vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
- gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
- } else {
- gl_FragColor = vec4(uColor, 1.0); // Blue border
- }
- }
- `,
- });
- const point = new THREE.Mesh(geometry, material);
- point.name = "point";
- point.uuid = line[1];
- point.userData = { type: type, color: pointColour };
- point.position.set(line[0].x, line[0].y, line[0].z);
- currentLayerPoint.current.push(point);
-
- floorPlanGroupPoint.current?.add(point);
- })
- if (dragPointControls.current) {
- dragPointControls.current!.objects = currentLayerPoint.current;
- }
- addLineToScene(
- new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z),
- new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z),
- lineColour,
- line,
- floorPlanGroupLine
- )
- lines.current.push(line);
-
- const zonesData = await getZonesApi(organization);
- const highestLayer = Math.max(
- 1,
- lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
- zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
- );
-
- setLayers(highestLayer);
-
- Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls)
-
- loadWalls(lines, setWalls);
- setUpdateScene(true);
- }
- })
-
- return () => {
- socket.off('Line:response:create');
- };
- }, [socket, activeLayer])
-
- useEffect(() => {
- if (!socket) return
- const email = localStorage.getItem('email');
- const organization = (email!.split("@")[1]).split(".")[0];
-
- socket.on('zone:response:updates', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
-
- if (data.message === "zone created") {
- const pointsArray: [number, number, number][] = data.data.points;
- const vector3Array = pointsArray.map(([x, y, z]) => new THREE.Vector3(x, y, z));
- const newZones = [...zones, data.data];
- setZones(newZones);
- const updatedZonePoints = [...zonePoints, ...vector3Array];
- setZonePoints(updatedZonePoints);
-
- const highestLayer = Math.max(
- 1,
- lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
- newZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
- );
-
- setLayers(highestLayer);
- setUpdateScene(true);
- }
-
- if (data.message === "zone updated") {
- const updatedZones = zones.map((zone: any) =>
- zone.zoneId === data.data.zoneId ? data.data : zone
- );
- setZones(updatedZones);
- setUpdateScene(true);
- }
-
-
- })
-
- socket.on('zone:response:delete', (data: any) => {
- if (socket.id === data.socketId) {
- return
- }
- if (organization !== data.organization) {
- return
- }
- if (data.message === "zone deleted") {
- const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId);
- setZones(updatedZones);
-
- const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === data.data.zoneId);
- if (zoneIndex !== -1) {
- const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4);
- setZonePoints(updatedzonePoints);
- }
-
- const highestLayer = Math.max(
- 1,
- lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
- updatedZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
- );
-
- setLayers(highestLayer);
- setUpdateScene(true);
- }
- })
-
- return () => {
- socket.off('zone:response:updates');
- socket.off('zone:response:delete');
- };
- }, [socket, zones, zonePoints])
-
- return (
- <>>
- )
+import { useEffect } from "react";
+import * as THREE from 'three';
+import gsap from 'gsap';
+import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
+import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
+import { toast } from 'react-toastify';
+import { useSocketStore, useActiveLayer, useWallItems, useFloorItems, useLayers, useUpdateScene, useWalls, useDeletedLines, useNewLines, useZonePoints, useZones } from "../../../store/store";
+
+import * as Types from "../../../types/world/worldTypes";
+import * as CONSTANTS from '../../../types/world/worldConstants';
+import TempLoader from "../../builder/geomentries/assets/tempLoader";
+
+// import { setFloorItemApi } from "../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
+import objectLineToArray from "../../builder/geomentries/lines/lineConvertions/objectLineToArray";
+import addLineToScene from "../../builder/geomentries/lines/addLineToScene";
+import updateLinesPositions from "../../builder/geomentries/lines/updateLinesPositions";
+import updateLines from "../../builder/geomentries/lines/updateLines";
+import updateDistanceText from "../../builder/geomentries/lines/updateDistanceText";
+import updateFloorLines from "../../builder/geomentries/floors/updateFloorLines";
+import loadWalls from "../../builder/geomentries/walls/loadWalls";
+import RemoveConnectedLines from "../../builder/geomentries/lines/removeConnectedLines";
+import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
+import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
+import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
+
+
+export default function SocketResponses({
+ floorPlanGroup,
+ lines,
+ floorGroup,
+ floorGroupAisle,
+ scene,
+ onlyFloorlines,
+ AssetConfigurations,
+ itemsGroup,
+ isTempLoader,
+ tempLoader,
+ currentLayerPoint,
+ floorPlanGroupPoint,
+ floorPlanGroupLine,
+ zoneGroup,
+ dragPointControls
+}: any) {
+
+ const { socket } = useSocketStore();
+ const { activeLayer, setActiveLayer } = useActiveLayer();
+ const { wallItems, setWallItems } = useWallItems();
+ const { layers, setLayers } = useLayers();
+ const { floorItems, setFloorItems } = useFloorItems();
+ const { updateScene, setUpdateScene } = useUpdateScene();
+ const { walls, setWalls } = useWalls();
+ const { deletedLines, setDeletedLines } = useDeletedLines();
+ const { newLines, setNewLines } = useNewLines();
+ const { zones, setZones } = useZones();
+ const { zonePoints, setZonePoints } = useZonePoints();
+
+ useEffect(() => {
+
+ const email = localStorage.getItem('email')
+ const organization = (email!.split("@")[1]).split(".")[0];
+
+ if (!socket) return
+
+ socket.on('cameraCreateResponse', (data: any) => {
+ // console.log('data: ', data);
+ })
+
+ socket.on('userConnectRespones', (data: any) => {
+ // console.log('data: ', data);
+ })
+
+ socket.on('userDisConnectRespones', (data: any) => {
+ // console.log('data: ', data);
+ })
+
+ socket.on('cameraUpdateResponse', (data: any) => {
+ // console.log('data: ', data);
+ })
+
+ socket.on('EnvironmentUpdateResponse', (data: any) => {
+ // console.log('data: ', data);
+ })
+
+ socket.on('model-asset:response:updates', async (data: any) => {
+ // console.log('data: ', data);
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "Model created successfully") {
+ const loader = new GLTFLoader();
+ const dracoLoader = new DRACOLoader();
+
+ dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
+ loader.setDRACOLoader(dracoLoader);
+ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
+
+ try {
+ isTempLoader.current = true;
+ const cachedModel = THREE.Cache.get(data.data.modelname);
+ let url;
+ if (cachedModel) {
+ // console.log(`Getting ${data.data.modelname} from cache`);
+ const model = cachedModel.scene.clone();
+ model.uuid = data.data.modeluuid;
+ model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid };
+ model.position.set(...data.data.position as [number, number, number]);
+ model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
+ model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
+
+ model.traverse((child: any) => {
+ if (child.isMesh) {
+ // Clone the material to ensure changes are independent
+ // child.material = child.material.clone();
+
+ child.castShadow = true;
+ child.receiveShadow = true;
+ }
+ });
+
+ itemsGroup.current.add(model);
+
+ if (tempLoader.current) {
+ tempLoader.current.material.dispose();
+ tempLoader.current.geometry.dispose();
+ itemsGroup.current.remove(tempLoader.current);
+ tempLoader.current = undefined;
+ }
+
+ const newFloorItem: Types.FloorItemType = {
+ modeluuid: data.data.modeluuid,
+ modelname: data.data.modelname,
+ modelfileID: data.data.modelfileID,
+ position: [...data.data.position as [number, number, number]],
+ rotation: {
+ x: model.rotation.x,
+ y: model.rotation.y,
+ z: model.rotation.z,
+ },
+ isLocked: data.data.isLocked,
+ isVisible: data.data.isVisible,
+ };
+
+ setFloorItems((prevItems: any) => {
+ const updatedItems = [...(prevItems || []), newFloorItem];
+ localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
+ return updatedItems;
+ });
+
+ gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' });
+ gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } });
+
+ } else {
+ const indexedDBModel = await retrieveGLTF(data.data.modelname);
+ if (indexedDBModel) {
+ // console.log(`Getting ${data.data.modelname} from IndexedDB`);
+ url = URL.createObjectURL(indexedDBModel);
+ } else {
+ // console.log(`Getting ${data.data.modelname} from Backend`);
+ url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`;
+ const modelBlob = await fetch(url).then((res) => res.blob());
+ await storeGLTF(data.data.modelfileID, modelBlob);
+ }
+ }
+
+ if (url) {
+ loadModel(url);
+ }
+
+ } catch (error) {
+ console.error('Error fetching asset model:', error);
+ }
+
+ function loadModel(url: string) {
+ loader.load(url, (gltf) => {
+ URL.revokeObjectURL(url);
+ THREE.Cache.remove(url);
+ const model = gltf.scene;
+ model.uuid = data.data.modeluuid;
+ model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid };
+ model.position.set(...data.data.position as [number, number, number]);
+ model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
+ model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
+
+ model.traverse((child: any) => {
+ if (child.isMesh) {
+ // Clone the material to ensure changes are independent
+ // child.material = child.material.clone();
+
+ child.castShadow = true;
+ child.receiveShadow = true;
+ }
+ });
+
+ itemsGroup.current.add(model);
+
+ if (tempLoader.current) {
+ tempLoader.current.material.dispose();
+ tempLoader.current.geometry.dispose();
+ itemsGroup.current.remove(tempLoader.current);
+ tempLoader.current = undefined;
+ }
+
+ const newFloorItem: Types.FloorItemType = {
+ modeluuid: data.data.modeluuid,
+ modelname: data.data.modelname,
+ modelfileID: data.data.modelfileID,
+ position: [...data.data.position as [number, number, number]],
+ rotation: {
+ x: model.rotation.x,
+ y: model.rotation.y,
+ z: model.rotation.z,
+ },
+ isLocked: data.data.isLocked,
+ isVisible: data.data.isVisible,
+ };
+
+ setFloorItems((prevItems: any) => {
+ const updatedItems = [...(prevItems || []), newFloorItem];
+ localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
+ return updatedItems;
+ });
+
+ gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' });
+ gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } });
+
+ THREE.Cache.add(data.data.modelname, gltf);
+ }, () => {
+ TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup);
+ });
+ }
+
+ } else if (data.message === "Model updated successfully") {
+ 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);
+ }
+ })
+
+ setFloorItems((prevItems: Types.FloorItems) => {
+ if (!prevItems) {
+ return
+ }
+ let updatedItem: any = null;
+ const updatedItems = prevItems.map((item) => {
+ if (item.modeluuid === data.data.modeluuid) {
+ updatedItem = {
+ ...item,
+ position: [...data.data.position] as [number, number, number],
+ rotation: { x: data.data.rotation.x, y: data.data.rotation.y, z: data.data.rotation.z, },
+ };
+ return updatedItem;
+ }
+ return item;
+ });
+ return updatedItems;
+ })
+ }
+ })
+
+ socket.on('model-asset:response:updates', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "Model deleted successfully") {
+ const deletedUUID = data.data.modeluuid;
+ let items = JSON.parse(localStorage.getItem("FloorItems")!);
+
+ const updatedItems = items.filter(
+ (item: { modeluuid: string }) => item.modeluuid !== deletedUUID
+ );
+
+ const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
+ const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== deletedUUID);
+ localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
+
+ itemsGroup.current.children.forEach((item: any) => {
+ if (item.uuid === deletedUUID) {
+ itemsGroup.current.remove(item);
+ }
+ })
+ setFloorItems(updatedItems);
+ toast.success("Model Removed!");
+ }
+ })
+
+ socket.on('Line:response:update', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "line updated") {
+ const DraggedUUID = data.data.uuid;
+ const DraggedPosition = new THREE.Vector3(data.data.position.x, data.data.position.y, data.data.position.z);
+
+ const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', DraggedUUID);
+ point.position.set(DraggedPosition.x, DraggedPosition.y, DraggedPosition.z);
+ const affectedLines = updateLinesPositions({ uuid: DraggedUUID, position: DraggedPosition }, lines);
+
+ updateLines(floorPlanGroupLine, affectedLines);
+ updateDistanceText(scene, floorPlanGroupLine, affectedLines);
+ updateFloorLines(onlyFloorlines, { uuid: DraggedUUID, position: DraggedPosition });
+
+ loadWalls(lines, setWalls);
+ setUpdateScene(true);
+
+ }
+ })
+
+ socket.on('Line:response:delete', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "line deleted") {
+ const line = objectLineToArray(data.data);
+ const linePoints = line;
+ const connectedpoints = [linePoints[0][1], linePoints[1][1]];
+
+
+ onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) =>
+ floorline.filter((line: any) => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1])
+ ).filter((floorline: any) => floorline.length > 0);
+
+ const removedLine = lines.current.find((item: any) => (item[0][1] === linePoints[0][1] && item[1][1] === linePoints[1][1] || (item[0][1] === linePoints[1][1] && item[1][1] === linePoints[0][1])));
+ lines.current = lines.current.filter((item: any) => item !== removedLine);
+
+ floorPlanGroupLine.current.children.forEach((line: any) => {
+ const linePoints = line.userData.linePoints as [number, string, number][];
+ const uuid1 = linePoints[0][1];
+ const uuid2 = linePoints[1][1];
+
+ if ((uuid1 === connectedpoints[0] && uuid2 === connectedpoints[1] || (uuid1 === connectedpoints[1] && uuid2 === connectedpoints[0]))) {
+ line.material.dispose();
+ line.geometry.dispose();
+ floorPlanGroupLine.current.remove(line);
+ setDeletedLines([line.userData.linePoints])
+ }
+ });
+
+ connectedpoints.forEach((pointUUID) => {
+ let isConnected = false;
+ floorPlanGroupLine.current.children.forEach((line: any) => {
+ const linePoints = line.userData.linePoints;
+ const uuid1 = linePoints[0][1];
+ const uuid2 = linePoints[1][1];
+ if (uuid1 === pointUUID || uuid2 === pointUUID) {
+ isConnected = true;
+ }
+ });
+
+ if (!isConnected) {
+ floorPlanGroupPoint.current.children.forEach((point: any) => {
+ if (point.uuid === pointUUID) {
+ point.material.dispose();
+ point.geometry.dispose();
+ floorPlanGroupPoint.current.remove(point);
+ }
+ });
+ }
+ });
+
+ loadWalls(lines, setWalls);
+ setUpdateScene(true);
+
+ toast.success("Line Removed!");
+ }
+ })
+
+ socket.on('Line:response:delete:point', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "point deleted") {
+ const point = floorPlanGroupPoint.current?.getObjectByProperty('uuid', data.data);
+ point.material.dispose();
+ point.geometry.dispose();
+ floorPlanGroupPoint.current.remove(point);
+
+ onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) =>
+ floorline.filter((line: any) => line[0][1] !== data.data && line[1][1] !== data.data)
+ ).filter((floorline: any) => floorline.length > 0);
+
+ RemoveConnectedLines(data.data, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
+
+ loadWalls(lines, setWalls);
+ setUpdateScene(true);
+
+ toast.success("Point Removed!");
+ }
+ })
+
+ socket.on('Line:response:delete:layer', async (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "layer deleted") {
+ setActiveLayer(1)
+ const removedLayer = data.data;
+ const removedLines: Types.Lines = lines.current.filter((line: any) => line[0][2] === removedLayer);
+
+ ////////// Remove Points and lines from the removed layer //////////
+
+ removedLines.forEach(async (line) => {
+ line.forEach(async (removedPoint) => {
+ const removableLines: THREE.Mesh[] = [];
+ const connectedpoints: string[] = [];
+
+ floorPlanGroupLine.current.children.forEach((line: any) => {
+ const linePoints = line.userData.linePoints as [number, string, number][];
+ const uuid1 = linePoints[0][1];
+ const uuid2 = linePoints[1][1];
+
+ if (uuid1 === removedPoint[1] || uuid2 === removedPoint[1]) {
+ connectedpoints.push(uuid1 === removedPoint[1] ? uuid2 : uuid1);
+ removableLines.push(line as THREE.Mesh);
+ }
+ });
+
+ if (removableLines.length > 0) {
+ removableLines.forEach((line: any) => {
+ lines.current = lines.current.filter((item: any) => JSON.stringify(item) !== JSON.stringify(line.userData.linePoints));
+ line.material.dispose();
+ line.geometry.dispose();
+ floorPlanGroupLine.current.remove(line);
+ });
+ }
+
+ const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', removedPoint[1]);
+ if (point) {
+ point.material.dispose();
+ point.geometry.dispose();
+ floorPlanGroupPoint.current.remove(point)
+ }
+ });
+ });
+
+ ////////// Update the remaining lines layer values in the userData and in lines.current //////////
+
+ let remaining = lines.current.filter((line: any) => line[0][2] !== removedLayer);
+ let updatedLines: Types.Lines = [];
+ remaining.forEach((line: any) => {
+ let newLines = JSON.parse(JSON.stringify(line));
+ if (newLines[0][2] > removedLayer) {
+ newLines[0][2] -= 1;
+ newLines[1][2] -= 1;
+ }
+
+ const matchingLine = floorPlanGroupLine.current.children.find((l: any) => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]);
+ if (matchingLine) {
+ const updatedUserData = JSON.parse(JSON.stringify(matchingLine.userData));
+ updatedUserData.linePoints[0][2] = newLines[0][2];
+ updatedUserData.linePoints[1][2] = newLines[1][2];
+ matchingLine.userData = updatedUserData;
+ }
+ updatedLines.push(newLines);
+ });
+
+ lines.current = updatedLines;
+ localStorage.setItem("Lines", JSON.stringify(lines.current));
+
+ ////////// Also remove OnlyFloorLines and update it in localstorage //////////
+
+ onlyFloorlines.current = onlyFloorlines.current.filter((floor: any) => {
+ return floor[0][0][2] !== removedLayer;
+ });
+ const meshToRemove = floorGroup.current?.children.find((mesh: any) =>
+ mesh.name === `Only_Floor_Line_${removedLayer}`
+ );
+ if (meshToRemove) {
+ meshToRemove.geometry.dispose();
+ meshToRemove.material.dispose();
+ floorGroup.current?.remove(meshToRemove);
+ }
+
+ const zonesData = await getZonesApi(organization);
+ const highestLayer = Math.max(
+ 1,
+ lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
+ zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
+ );
+
+ setLayers(highestLayer);
+
+ loadWalls(lines, setWalls);
+ setUpdateScene(true);
+
+ toast.success("Layer Removed!");
+ }
+ })
+ }, [socket])
+
+ useEffect(() => {
+ if (!socket) return
+ const email = localStorage.getItem('email')
+ const organization = (email!.split("@")[1]).split(".")[0];
+
+ socket.on('wallItemsDeleteResponse', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "wallitem deleted") {
+ const deletedUUID = data.data.modeluuid;
+ let WallItemsRef = wallItems;
+ const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID);
+
+ setWallItems([]);
+ setTimeout(async () => {
+ WallItemsRef = Items;
+ setWallItems(WallItemsRef);
+ const WallItemsForStorage = WallItemsRef.map((item: any) => {
+ const { model, ...rest } = item;
+ return {
+ ...rest,
+ modeluuid: model?.uuid,
+ };
+ });
+
+ localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
+ toast.success("Model Removed!");
+ }, 50);
+ }
+ })
+
+ socket.on('wallItemsUpdateResponse', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "wallIitem created") {
+ const loader = new GLTFLoader();
+ loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => {
+ const model = gltf.scene;
+ model.uuid = data.data.modeluuid;
+ model.children[0].children.forEach((child) => {
+ if (child.name !== "CSG_REF") {
+ child.castShadow = true;
+ child.receiveShadow = true;
+ }
+ });
+
+ const newWallItem = {
+ type: data.data.type,
+ model: model,
+ modelname: data.data.modelname,
+ scale: data.data.scale,
+ csgscale: data.data.csgscale,
+ csgposition: data.data.csgposition,
+ position: data.data.position,
+ quaternion: data.data.quaternion
+ };
+
+ setWallItems((prevItems: any) => {
+ const updatedItems = [...prevItems, newWallItem];
+
+ const WallItemsForStorage = updatedItems.map(item => {
+ const { model, ...rest } = item;
+ return {
+ ...rest,
+ modeluuid: model?.uuid,
+ };
+ });
+
+ localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
+ toast.success("Model Added!");
+
+ return updatedItems;
+ });
+ });
+ } else if (data.message === "wallIitem updated") {
+ const updatedUUID = data.data.modeluuid;
+
+ setWallItems((prevItems: any) => {
+ const updatedItems = prevItems.map((item: any) => {
+ if (item.model.uuid === updatedUUID) {
+ return {
+ ...item,
+ position: data.data.position,
+ quaternion: data.data.quaternion,
+ scale: data.data.scale,
+ csgscale: data.data.csgscale,
+ csgposition: data.data.csgposition,
+ };
+ }
+ return item;
+ });
+
+ const WallItemsForStorage = updatedItems.map((item: any) => {
+ const { model, ...rest } = item;
+ return {
+ ...rest,
+ modeluuid: model?.uuid,
+ };
+ });
+
+ localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
+ toast.success("Model Updated!");
+
+ return updatedItems;
+ });
+
+ }
+
+ })
+
+ return () => {
+ socket.off('wallItemsDeleteResponse');
+ socket.off('wallItemsUpdateResponse');
+ };
+ }, [wallItems])
+
+ function getPointColor(lineType: string | undefined): string {
+ switch (lineType) {
+ case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
+ case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
+ case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
+ default: return CONSTANTS.pointConfig.defaultOuterColor;
+ }
+ }
+
+ function getLineColor(lineType: string | undefined): string {
+ switch (lineType) {
+ case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor;
+ case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor;
+ case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor;
+ default: return CONSTANTS.lineConfig.defaultColor;
+ }
+ }
+
+ useEffect(() => {
+ if (!socket) return
+ const email = localStorage.getItem('email')
+ const organization = (email!.split("@")[1]).split(".")[0];
+
+ socket.on('Line:response:create', async (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "line create") {
+ const line: Types.Line = objectLineToArray(data.data);
+ const type = line[0][3];
+ const pointColour = getPointColor(type);
+ const lineColour = getLineColor(type);
+ setNewLines([line])
+
+ line.forEach((line) => {
+ const existingPoint = floorPlanGroupPoint.current?.getObjectByProperty('uuid', line[1]);
+ if (existingPoint) {
+ return;
+ }
+ const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
+ const material = new THREE.ShaderMaterial({
+ uniforms: {
+ uColor: { value: new THREE.Color(pointColour) }, // Blue color for the border
+ uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
+ },
+ vertexShader: `
+ varying vec2 vUv;
+
+ void main() {
+ vUv = uv;
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
+ }
+ `,
+ fragmentShader: `
+ varying vec2 vUv;
+ uniform vec3 uColor;
+ uniform vec3 uInnerColor;
+
+ void main() {
+ // Define the size of the white square as a proportion of the face
+ float borderThickness = 0.2; // Adjust this value for border thickness
+ if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
+ vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
+ gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
+ } else {
+ gl_FragColor = vec4(uColor, 1.0); // Blue border
+ }
+ }
+ `,
+ });
+ const point = new THREE.Mesh(geometry, material);
+ point.name = "point";
+ point.uuid = line[1];
+ point.userData = { type: type, color: pointColour };
+ point.position.set(line[0].x, line[0].y, line[0].z);
+ currentLayerPoint.current.push(point);
+
+ floorPlanGroupPoint.current?.add(point);
+ })
+ if (dragPointControls.current) {
+ dragPointControls.current!.objects = currentLayerPoint.current;
+ }
+ addLineToScene(
+ new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z),
+ new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z),
+ lineColour,
+ line,
+ floorPlanGroupLine
+ )
+ lines.current.push(line);
+
+ const zonesData = await getZonesApi(organization);
+ const highestLayer = Math.max(
+ 1,
+ lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
+ zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
+ );
+
+ setLayers(highestLayer);
+
+ Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls)
+
+ loadWalls(lines, setWalls);
+ setUpdateScene(true);
+ }
+ })
+
+ return () => {
+ socket.off('Line:response:create');
+ };
+ }, [socket, activeLayer])
+
+ useEffect(() => {
+ if (!socket) return
+ const email = localStorage.getItem('email');
+ const organization = (email!.split("@")[1]).split(".")[0];
+
+ socket.on('zone:response:updates', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+
+ if (data.message === "zone created") {
+ const pointsArray: [number, number, number][] = data.data.points;
+ const vector3Array = pointsArray.map(([x, y, z]) => new THREE.Vector3(x, y, z));
+ const newZones = [...zones, data.data];
+ setZones(newZones);
+ const updatedZonePoints = [...zonePoints, ...vector3Array];
+ setZonePoints(updatedZonePoints);
+
+ const highestLayer = Math.max(
+ 1,
+ lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
+ newZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
+ );
+
+ setLayers(highestLayer);
+ setUpdateScene(true);
+ }
+
+ if (data.message === "zone updated") {
+ const updatedZones = zones.map((zone: any) =>
+ zone.zoneId === data.data.zoneId ? data.data : zone
+ );
+ setZones(updatedZones);
+ setUpdateScene(true);
+ }
+
+
+ })
+
+ socket.on('zone:response:delete', (data: any) => {
+ if (socket.id === data.socketId) {
+ return
+ }
+ if (organization !== data.organization) {
+ return
+ }
+ if (data.message === "zone deleted") {
+ const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId);
+ setZones(updatedZones);
+
+ const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === data.data.zoneId);
+ if (zoneIndex !== -1) {
+ const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4);
+ setZonePoints(updatedzonePoints);
+ }
+
+ const highestLayer = Math.max(
+ 1,
+ lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
+ updatedZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
+ );
+
+ setLayers(highestLayer);
+ setUpdateScene(true);
+ }
+ })
+
+ return () => {
+ socket.off('zone:response:updates');
+ socket.off('zone:response:delete');
+ };
+ }, [socket, zones, zonePoints])
+
+ return (
+ <>>
+ )
}
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx
index 0e7581f..8bdd3aa 100644
--- a/app/src/modules/scene/controls/controls.tsx
+++ b/app/src/modules/scene/controls/controls.tsx
@@ -9,128 +9,135 @@ import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi"
import updateCamPosition from "../camera/updateCameraPosition";
import CamMode from "../camera/camMode";
import SwitchView from "../camera/switchView";
+import SelectionControls from "./selectionControls/selectionControls";
export default function Controls() {
- const controlsRef = useRef(null);
+ const controlsRef = useRef(null);
- const { toggleView } = useToggleView();
- const { resetCamera, setResetCamera } = useResetCamera();
- const { socket } = useSocketStore();
- const state = useThree();
+ const { toggleView } = useToggleView();
+ const { resetCamera, setResetCamera } = useResetCamera();
+ const { socket } = useSocketStore();
+ const state = useThree();
- useEffect(() => {
- if (controlsRef.current) {
- (controlsRef.current as any).mouseButtons.left = CONSTANTS.thirdPersonControls.leftMouse;
- (controlsRef.current as any).mouseButtons.right = CONSTANTS.thirdPersonControls.rightMouse;
- }
- const email = localStorage.getItem("email");
- const organization = email!.split("@")[1].split(".")[0];
- getCamera(organization, localStorage.getItem("userId")!).then((data) => {
- if (data && data.position && data.target) {
- controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
- controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
- } else {
- controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
- controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
- }
- })
- .catch((error) => console.error("Failed to fetch camera data:", error));
- }, []);
+ useEffect(() => {
+ if (controlsRef.current) {
+ (controlsRef.current as any).mouseButtons.left = CONSTANTS.thirdPersonControls.leftMouse;
+ (controlsRef.current as any).mouseButtons.right = CONSTANTS.thirdPersonControls.rightMouse;
+ }
+ const email = localStorage.getItem("email");
+ const organization = email!.split("@")[1].split(".")[0];
+ getCamera(organization, localStorage.getItem("userId")!).then((data) => {
+ if (data && data.position && data.target) {
+ controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
+ controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
+ } else {
+ controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
+ controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
+ }
+ })
+ .catch((error) => console.error("Failed to fetch camera data:", error));
+ }, []);
- useEffect(() => {
- if (resetCamera) {
- controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
- controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
- controlsRef.current?.rotateAzimuthTo(CONSTANTS.threeDimension.defaultAzimuth);
+ useEffect(() => {
+ if (resetCamera) {
+ controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
+ controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
+ controlsRef.current?.rotateAzimuthTo(CONSTANTS.threeDimension.defaultAzimuth);
- localStorage.setItem("cameraPosition", JSON.stringify(new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition)));
- localStorage.setItem("controlTarget", JSON.stringify(new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget)));
+ localStorage.setItem("cameraPosition", JSON.stringify(new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition)));
+ localStorage.setItem("controlTarget", JSON.stringify(new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget)));
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
+ const email = localStorage.getItem('email')
+ const organization = (email!.split("@")[1]).split(".")[0];
- const camData = {
- organization: organization,
- userId: localStorage.getItem('userId')!,
- position: new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
- target: new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
- rotation: new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
- socketId: socket.id
- };
- socket.emit('v1:Camera:set', camData)
+ const camData = {
+ organization: organization,
+ userId: localStorage.getItem('userId')!,
+ position: new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
+ target: new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
+ rotation: new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
+ socketId: socket.id
+ };
+ socket.emit('v1:Camera:set', camData)
- setResetCamera(false);
- }
- }, [resetCamera]);
+ setResetCamera(false);
+ }
+ }, [resetCamera]);
- useEffect(() => {
- controlsRef.current?.setBoundary(new THREE.Box3(new THREE.Vector3(...CONSTANTS.threeDimension.boundaryBottom), new THREE.Vector3(...CONSTANTS.threeDimension.boundaryTop)));
- // state.scene.add(new THREE.Box3Helper(new THREE.Box3(new THREE.Vector3(...CONSTANTS.threeDimension.boundaryBottom), new THREE.Vector3(...CONSTANTS.threeDimension.boundaryTop)), 0xffff00));
- let hasInteracted = false;
- let intervalId: NodeJS.Timeout | null = null;
+ useEffect(() => {
+ controlsRef.current?.setBoundary(new THREE.Box3(new THREE.Vector3(...CONSTANTS.threeDimension.boundaryBottom), new THREE.Vector3(...CONSTANTS.threeDimension.boundaryTop)));
+ // state.scene.add(new THREE.Box3Helper(new THREE.Box3(new THREE.Vector3(...CONSTANTS.threeDimension.boundaryBottom), new THREE.Vector3(...CONSTANTS.threeDimension.boundaryTop)), 0xffff00));
+ let hasInteracted = false;
+ let intervalId: NodeJS.Timeout | null = null;
- const handleRest = () => {
- if (hasInteracted && controlsRef.current && state.camera.position && !toggleView) {
- const position = state.camera.position;
- if (position.x === 0 && position.y === 0 && position.z === 0) return;
- updateCamPosition(controlsRef, socket, position, state.camera.rotation);
- stopInterval();
- }
- };
+ const handleRest = () => {
+ if (hasInteracted && controlsRef.current && state.camera.position && !toggleView) {
+ const position = state.camera.position;
+ if (position.x === 0 && position.y === 0 && position.z === 0) return;
+ updateCamPosition(controlsRef, socket, position, state.camera.rotation);
+ stopInterval();
+ }
+ };
- const startInterval = () => {
- hasInteracted = true;
- if (!intervalId) {
- intervalId = setInterval(() => {
- if (controlsRef.current && !toggleView) {
- handleRest();
- }
- }, CONSTANTS.camPositionUpdateInterval);
- }
- };
+ const startInterval = () => {
+ hasInteracted = true;
+ if (!intervalId) {
+ intervalId = setInterval(() => {
+ if (controlsRef.current && !toggleView) {
+ handleRest();
+ }
+ }, CONSTANTS.camPositionUpdateInterval);
+ }
+ };
- const stopInterval = () => {
- if (intervalId) {
- clearInterval(intervalId);
- intervalId = null;
- }
- };
+ const stopInterval = () => {
+ if (intervalId) {
+ clearInterval(intervalId);
+ intervalId = null;
+ }
+ };
- const controls = controlsRef.current;
- if (controls) {
- controls.addEventListener("sleep", handleRest);
- controls.addEventListener("control", startInterval);
- controls.addEventListener("controlend", stopInterval);
- }
+ const controls = controlsRef.current;
+ if (controls) {
+ controls.addEventListener("sleep", handleRest);
+ controls.addEventListener("control", startInterval);
+ controls.addEventListener("controlend", stopInterval);
+ }
- return () => {
- if (controls) {
- controls.removeEventListener("sleep", handleRest);
- controls.removeEventListener("control", startInterval);
- controls.removeEventListener("controlend", stopInterval);
- }
- stopInterval();
- };
- }, [toggleView, state, socket]);
+ return () => {
+ if (controls) {
+ controls.removeEventListener("sleep", handleRest);
+ controls.removeEventListener("control", startInterval);
+ controls.removeEventListener("controlend", stopInterval);
+ }
+ stopInterval();
+ };
+ }, [toggleView, state, socket]);
- return (
- <>
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
}
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selection/copyPasteControls.tsx b/app/src/modules/scene/controls/selection/copyPasteControls.tsx
deleted file mode 100644
index 1f83513..0000000
--- a/app/src/modules/scene/controls/selection/copyPasteControls.tsx
+++ /dev/null
@@ -1,581 +0,0 @@
-import * as THREE from "three";
-import { useEffect, useMemo } from "react";
-import { useFrame, useThree } from "@react-three/fiber";
-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";
-import * as SimulationTypes from "../../../../types/simulationTypes";
-import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
-
-const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, selectionGroup, setDuplicatedObjects, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
- const { camera, controls, gl, scene, pointer, raycaster } = useThree();
- const { toggleView } = useToggleView();
- const { selectedAssets, setSelectedAssets } = useSelectedAssets();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
- const { floorItems, setFloorItems } = useFloorItems();
- const { socket } = useSocketStore()
-
- useEffect(() => {
- if (!camera || !scene || toggleView) return;
- const canvasElement = gl.domElement;
- canvasElement.tabIndex = 0;
-
- let isMoving = false;
-
- const onPointerDown = () => {
- isMoving = false;
- };
-
- const onPointerMove = () => {
- isMoving = true;
- };
-
- const onPointerUp = (event: PointerEvent) => {
- if (!isMoving && pastedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
- event.preventDefault();
- addPastedObjects();
- }
- };
-
- const onKeyDown = (event: KeyboardEvent) => {
- const keyCombination = detectModifierKeys(event);
-
- if (keyCombination === "Ctrl+C" && movedObjects.length === 0 && rotatedObjects.length === 0) {
- copySelection();
- }
- if (keyCombination === "Ctrl+V" && copiedObjects.length > 0 && pastedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
- pasteCopiedObjects();
- }
- };
-
- if (!toggleView) {
- canvasElement.addEventListener("pointerdown", onPointerDown);
- canvasElement.addEventListener("pointermove", onPointerMove);
- canvasElement.addEventListener("pointerup", onPointerUp);
- canvasElement.addEventListener("keydown", onKeyDown);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onPointerDown);
- canvasElement.removeEventListener("pointermove", onPointerMove);
- canvasElement.removeEventListener("pointerup", onPointerUp);
- canvasElement.removeEventListener("keydown", onKeyDown);
- };
-
- }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, floorItems, rotatedObjects]);
-
- useFrame(() => {
- if (pastedObjects.length > 0) {
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
- if (point) {
- const position = new THREE.Vector3();
- if (boundingBoxRef.current) {
- boundingBoxRef.current?.getWorldPosition(position)
- selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
- } else {
- const box = new THREE.Box3();
- pastedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
- const center = new THREE.Vector3();
- box.getCenter(center);
- selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
- }
- }
- }
- });
-
- const copySelection = () => {
- if (selectedAssets.length > 0) {
- const newClones = selectedAssets.map((asset: any) => {
- const clone = asset.clone();
- clone.position.copy(asset.position);
- return clone;
- });
- setCopiedObjects(newClones);
- toast.info("Objects copied!");
- }
- };
-
- const pasteCopiedObjects = () => {
- if (copiedObjects.length > 0 && pastedObjects.length === 0) {
- const newClones = copiedObjects.map((obj: THREE.Object3D) => {
- const clone = obj.clone();
- clone.position.copy(obj.position);
- return clone;
- });
- selectionGroup.current.add(...newClones);
- setpastedObjects([...newClones]);
- setSelectedAssets([...newClones]);
-
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
-
- if (point) {
- const position = new THREE.Vector3();
- if (boundingBoxRef.current) {
- boundingBoxRef.current?.getWorldPosition(position)
- selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
- } else {
- const box = new THREE.Box3();
- newClones.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
- const center = new THREE.Vector3();
- box.getCenter(center);
- selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
- }
- }
- }
- };
-
- const addPastedObjects = () => {
- if (pastedObjects.length === 0) return;
- pastedObjects.forEach(async (obj: THREE.Object3D) => {
- const worldPosition = new THREE.Vector3();
- obj.getWorldPosition(worldPosition);
- obj.position.copy(worldPosition);
-
- if (itemsGroupRef.current) {
-
- const newFloorItem: Types.FloorItemType = {
- modeluuid: obj.uuid,
- modelname: obj.userData.name,
- modelfileID: obj.userData.modelId,
- position: [worldPosition.x, worldPosition.y, worldPosition.z],
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
- isLocked: false,
- isVisible: true
- };
-
- setFloorItems((prevItems: Types.FloorItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- let eventData: SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema | 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.type === 'Conveyor' && eventData) {
- const createConveyorPoint = (index: number) => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const hasActions = (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].actions.length > 0;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- type: 'Inherit',
- material: 'Inherit',
- delay: 'Inherit',
- spawnInterval: 'Inherit',
- isUsed: true
- };
-
- return {
- uuid: pointUUID,
- position: (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].position,
- rotation: (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].rotation,
- actions: hasActions
- ? (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].actions.map(action => ({
- ...action,
- uuid: THREE.MathUtils.generateUUID()
- }))
- : [defaultAction],
- triggers: (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].triggers.map(trigger => ({
- ...trigger,
- uuid: THREE.MathUtils.generateUUID()
- })),
- connections: {
- source: { modelUUID: obj.uuid, pointUUID },
- targets: []
- }
- };
- };
-
- const backendEventData = {
- type: 'Conveyor',
- points: [
- createConveyorPoint(0), // point1
- createConveyorPoint(1), // middlePoint
- createConveyorPoint(2) // point2
- ],
- speed: (eventData as SimulationTypes.ConveyorEventsSchema)?.speed
- };
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // backendEventData
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
- socketId: socket.id,
- };
-
- 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];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.ConveyorEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'Vehicle' && eventData) {
- const createVehiclePoint = () => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const vehiclePoint = (eventData as SimulationTypes.VehicleEventsSchema)?.points;
- const hasActions = vehiclePoint?.actions !== undefined;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- type: 'Inherit',
- start: {},
- hitCount: 0,
- end: {},
- buffer: 0
- };
-
- return {
- uuid: pointUUID,
- position: vehiclePoint?.position,
- // rotation: vehiclePoint?.rotation,
- actions: hasActions
- ? {
- ...vehiclePoint.actions,
- uuid: THREE.MathUtils.generateUUID()
- }
- : defaultAction,
- connections: {
- source: { modelUUID: obj.uuid, pointUUID },
- targets: []
- },
- speed: vehiclePoint?.speed || 1
- };
- };
-
- const backendEventData = {
- type: 'Vehicle',
- points: createVehiclePoint(),
- };
-
- // API
-
- // setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.VehicleEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'StaticMachine' && eventData) {
- const createStaticMachinePoint = () => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const staticMachinePoint = (eventData as SimulationTypes.StaticMachineEventsSchema)?.points;
- const hasActions = staticMachinePoint?.actions !== undefined;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- buffer: 0,
- material: 'Inherit',
- };
-
- return {
- uuid: pointUUID,
- position: staticMachinePoint?.position,
- rotation: staticMachinePoint?.rotation,
- actions: hasActions
- ? {
- ...staticMachinePoint.actions,
- uuid: THREE.MathUtils.generateUUID()
- }
- : defaultAction,
- triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
- connections: {
- source: { modelUUID: obj.uuid, pointUUID },
- targets: []
- }
- };
- };
-
- const backendEventData = {
- type: 'StaticMachine',
- points: createStaticMachinePoint()
- };
-
- // API
-
- // setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.StaticMachineEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'ArmBot' && eventData) {
- const createArmBotPoint = () => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const armBotPoint = (eventData as SimulationTypes.ArmBotEventsSchema)?.points;
- const hasActions = armBotPoint?.actions !== undefined;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- buffer: 0,
- material: 'Inherit',
- };
-
- return {
- uuid: pointUUID,
- position: armBotPoint?.position,
- rotation: armBotPoint?.rotation,
- actions: hasActions
- ? {
- ...armBotPoint.actions,
- uuid: THREE.MathUtils.generateUUID(),
- processes: []
- }
- : defaultAction,
- triggers: {
- uuid: THREE.MathUtils.generateUUID(),
- name: armBotPoint.triggers.name,
- type: armBotPoint.triggers.type,
- },
- connections: {
- source: { modelUUID: obj.uuid, pointUUID },
- targets: []
- }
- };
- };
-
- const backendEventData = {
- type: 'ArmBot',
- points: createArmBotPoint()
- };
-
- // API
-
- // setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.ArmBotEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else {
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:add", data);
-
- }
- } else {
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:add", data);
-
- }
-
- obj.userData.modeluuid = newFloorItem.modeluuid;
- itemsGroupRef.current.add(obj);
- }
- });
-
- toast.success("Object added!");
- clearSelection();
- };
-
- const clearSelection = () => {
- selectionGroup.current.children = [];
- selectionGroup.current.position.set(0, 0, 0);
- selectionGroup.current.rotation.set(0, 0, 0);
- setMovedObjects([]);
- setpastedObjects([]);
- setDuplicatedObjects([]);
- setRotatedObjects([]);
- setSelectedAssets([]);
- }
-
- return null; // No visible output, but the component handles copy-paste functionality
-};
-
-export default CopyPasteControls;
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selection/duplicationControls.tsx b/app/src/modules/scene/controls/selection/duplicationControls.tsx
deleted file mode 100644
index 915cb61..0000000
--- a/app/src/modules/scene/controls/selection/duplicationControls.tsx
+++ /dev/null
@@ -1,560 +0,0 @@
-import * as THREE from "three";
-import { useEffect, useMemo } from "react";
-import { useFrame, useThree } from "@react-three/fiber";
-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";
-import * as SimulationTypes from "../../../../types/simulationTypes";
-import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
-import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
-
-const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
- const { camera, controls, gl, scene, pointer, raycaster } = useThree();
- const { toggleView } = useToggleView();
- const { selectedAssets, setSelectedAssets } = useSelectedAssets();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
- const { floorItems, setFloorItems } = useFloorItems();
- const { socket } = useSocketStore();
-
- useEffect(() => {
- if (!camera || !scene || toggleView) return;
- const canvasElement = gl.domElement;
- canvasElement.tabIndex = 0;
-
- let isMoving = false;
-
- const onPointerDown = () => {
- isMoving = false;
- };
-
- const onPointerMove = () => {
- isMoving = true;
- };
-
- const onPointerUp = (event: PointerEvent) => {
- if (!isMoving && duplicatedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
- event.preventDefault();
- addDuplicatedAssets();
- }
- };
-
- const onKeyDown = (event: KeyboardEvent) => {
- const keyCombination = detectModifierKeys(event);
-
- if (keyCombination === "Ctrl+D" && selectedAssets.length > 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
- duplicateSelection();
- }
- };
-
- if (!toggleView) {
- canvasElement.addEventListener("pointerdown", onPointerDown);
- canvasElement.addEventListener("pointermove", onPointerMove);
- canvasElement.addEventListener("pointerup", onPointerUp);
- canvasElement.addEventListener("keydown", onKeyDown);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onPointerDown);
- canvasElement.removeEventListener("pointermove", onPointerMove);
- canvasElement.removeEventListener("pointerup", onPointerUp);
- canvasElement.removeEventListener("keydown", onKeyDown);
- };
-
- }, [camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects]);
-
- useFrame(() => {
- if (duplicatedObjects.length > 0) {
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
- if (point) {
- const position = new THREE.Vector3();
- if (boundingBoxRef.current) {
- boundingBoxRef.current?.getWorldPosition(position)
- selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
- } else {
- const box = new THREE.Box3();
- duplicatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
- const center = new THREE.Vector3();
- box.getCenter(center);
- selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
- }
- }
- }
- });
-
- const duplicateSelection = () => {
- if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
- const newClones = selectedAssets.map((asset: any) => {
- const clone = asset.clone();
- clone.position.copy(asset.position);
- return clone;
- });
-
- selectionGroup.current.add(...newClones);
- setDuplicatedObjects(newClones);
-
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
-
- if (point) {
- const position = new THREE.Vector3();
- boundingBoxRef.current?.getWorldPosition(position)
- selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
- }
- }
- };
-
- const addDuplicatedAssets = () => {
- if (duplicatedObjects.length === 0) return;
- duplicatedObjects.forEach(async (obj: THREE.Object3D) => {
- const worldPosition = new THREE.Vector3();
- obj.getWorldPosition(worldPosition);
- obj.position.copy(worldPosition);
-
- if (itemsGroupRef.current) {
-
- const newFloorItem: Types.FloorItemType = {
- modeluuid: obj.uuid,
- modelname: obj.userData.name,
- modelfileID: obj.userData.modelId,
- position: [worldPosition.x, worldPosition.y, worldPosition.z],
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
- isLocked: false,
- isVisible: true
- };
-
- setFloorItems((prevItems: Types.FloorItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- let eventData: SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema | 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.type === 'Conveyor' && eventData) {
- const createConveyorPoint = (index: number) => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const hasActions = (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].actions.length > 0;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- type: 'Inherit',
- material: 'Inherit',
- delay: 'Inherit',
- spawnInterval: 'Inherit',
- isUsed: true
- };
-
- return {
- uuid: pointUUID,
- position: (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].position,
- rotation: (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].rotation,
- actions: hasActions
- ? (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].actions.map(action => ({
- ...action,
- uuid: THREE.MathUtils.generateUUID()
- }))
- : [defaultAction],
- triggers: (eventData as SimulationTypes.ConveyorEventsSchema)?.points[index].triggers.map(trigger => ({
- ...trigger,
- uuid: THREE.MathUtils.generateUUID()
- })),
- connections: {
- source: { modelUUID: newFloorItem.modeluuid, pointUUID },
- targets: []
- }
- };
- };
-
- const backendEventData = {
- type: 'Conveyor',
- points: [
- createConveyorPoint(0),
- createConveyorPoint(1),
- createConveyorPoint(2)
- ],
- speed: (eventData as SimulationTypes.ConveyorEventsSchema)?.speed
- };
-
- //REST
-
- // setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
- socketId: socket.id,
- };
-
- 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];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.ConveyorEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'Vehicle' && eventData) {
- const createVehiclePoint = () => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const vehiclePoint = (eventData as SimulationTypes.VehicleEventsSchema)?.points;
- const hasActions = vehiclePoint?.actions !== undefined;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- type: 'Inherit',
- start: {},
- hitCount: 0,
- end: {},
- buffer: 0
- };
-
- return {
- uuid: pointUUID,
- position: vehiclePoint?.position,
- rotation: vehiclePoint?.rotation,
- actions: hasActions
- ? {
- ...vehiclePoint.actions,
- uuid: THREE.MathUtils.generateUUID()
- }
- : defaultAction,
- connections: {
- source: { modelUUID: obj.uuid, pointUUID },
- targets: []
- },
- speed: vehiclePoint?.speed || 2
- };
- };
-
- const backendEventData = {
- type: 'Vehicle',
- points: createVehiclePoint()
- };
-
- // API
-
- // setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.VehicleEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'StaticMachine' && eventData) {
- const createStaticMachinePoint = () => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const staticMachinePoint = (eventData as SimulationTypes.StaticMachineEventsSchema)?.points;
- const hasActions = staticMachinePoint?.actions !== undefined;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- buffer: 0,
- material: 'Inherit',
- };
-
- return {
- uuid: pointUUID,
- position: staticMachinePoint?.position,
- rotation: staticMachinePoint?.rotation,
- actions: hasActions
- ? {
- ...staticMachinePoint.actions,
- uuid: THREE.MathUtils.generateUUID()
- }
- : defaultAction,
- triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
- connections: {
- source: { modelUUID: obj.uuid, pointUUID },
- targets: []
- }
- };
- };
-
- const backendEventData = {
- type: 'StaticMachine',
- points: createStaticMachinePoint()
- };
-
- // API
-
- // setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.StaticMachineEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'ArmBot' && eventData) {
- const createArmBotPoint = () => {
- const pointUUID = THREE.MathUtils.generateUUID();
- const armBotPoint = (eventData as SimulationTypes.ArmBotEventsSchema)?.points;
- const hasActions = armBotPoint?.actions !== undefined;
-
- const defaultAction = {
- uuid: THREE.MathUtils.generateUUID(),
- name: 'Action 1',
- buffer: 0,
- material: 'Inherit',
- };
-
- return {
- uuid: pointUUID,
- position: armBotPoint?.position,
- rotation: armBotPoint?.rotation,
- actions: hasActions
- ? {
- ...armBotPoint.actions,
- uuid: THREE.MathUtils.generateUUID(),
- processes: []
- }
- : defaultAction,
- triggers: {
- uuid: THREE.MathUtils.generateUUID(),
- name: armBotPoint.triggers.name,
- type: armBotPoint.triggers.type,
- },
- connections: {
- source: { modelUUID: obj.uuid, pointUUID },
- targets: []
- }
- };
- };
-
- const backendEventData = {
- type: 'ArmBot',
- points: createArmBotPoint()
- };
-
- // API
-
- // setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- // SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => [
- ...(prevEvents || []),
- newEventData as SimulationTypes.ArmBotEventsSchema
- ]);
-
- socket.emit("v2:model-asset:add", data);
-
- } else {
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:add", data);
-
- }
- } else {
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:add", data);
-
- }
-
- obj.userData.modeluuid = newFloorItem.modeluuid;
- itemsGroupRef.current.add(obj);
- }
- });
-
- toast.success("Object duplicated!");
- clearSelection();
- }
-
- const clearSelection = () => {
- selectionGroup.current.children = [];
- selectionGroup.current.position.set(0, 0, 0);
- selectionGroup.current.rotation.set(0, 0, 0);
- setMovedObjects([]);
- setpastedObjects([]);
- setDuplicatedObjects([]);
- setRotatedObjects([]);
- setSelectedAssets([]);
- }
-
- return null; // This component does not render any UI
-};
-
-export default DuplicationControls;
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selection/moveControls.tsx b/app/src/modules/scene/controls/selection/moveControls.tsx
deleted file mode 100644
index d717ecb..0000000
--- a/app/src/modules/scene/controls/selection/moveControls.tsx
+++ /dev/null
@@ -1,463 +0,0 @@
-import * as THREE from "three";
-import { useEffect, useMemo, useRef, useState } from "react";
-import { useFrame, useThree } from "@react-three/fiber";
-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";
-import * as SimulationTypes from "../../../../types/simulationTypes";
-import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
-
-function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) {
- const { camera, controls, gl, scene, pointer, raycaster } = useThree();
- const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
-
- const { toggleView } = useToggleView();
- const { selectedAssets, setSelectedAssets } = useSelectedAssets();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { floorItems, setFloorItems } = useFloorItems();
- const { socket } = useSocketStore();
- const itemsData = useRef([]);
-
- useEffect(() => {
- if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
-
- const canvasElement = gl.domElement;
- canvasElement.tabIndex = 0;
-
- let isMoving = false;
-
- const onPointerDown = () => {
- isMoving = false;
- };
-
- const onPointerMove = () => {
- isMoving = true;
- };
-
- const onPointerUp = (event: PointerEvent) => {
- if (!isMoving && movedObjects.length > 0 && event.button === 0) {
- event.preventDefault();
- placeMovedAssets();
- }
- if (!isMoving && movedObjects.length > 0 && event.button === 2) {
- event.preventDefault();
-
- clearSelection();
- movedObjects.forEach((asset: any) => {
- if (itemsGroupRef.current) {
- itemsGroupRef.current.attach(asset);
- }
- });
-
- setFloorItems([...floorItems, ...itemsData.current]);
-
- setMovedObjects([]);
- itemsData.current = [];
- }
- };
-
- const onKeyDown = (event: KeyboardEvent) => {
- const keyCombination = detectModifierKeys(event);
-
- if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return;
- if (keyCombination === "G") {
- if (selectedAssets.length > 0) {
- moveAssets();
- itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
- }
- }
- if (keyCombination === "ESCAPE") {
- event.preventDefault();
-
- clearSelection();
- movedObjects.forEach((asset: any) => {
- if (itemsGroupRef.current) {
- itemsGroupRef.current.attach(asset);
- }
- });
-
- setFloorItems([...floorItems, ...itemsData.current]);
-
- setMovedObjects([]);
- itemsData.current = [];
- }
- };
-
- if (!toggleView) {
- canvasElement.addEventListener("pointerdown", onPointerDown);
- canvasElement.addEventListener("pointermove", onPointerMove);
- canvasElement.addEventListener("pointerup", onPointerUp);
- canvasElement.addEventListener("keydown", onKeyDown);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onPointerDown);
- canvasElement.removeEventListener("pointermove", onPointerMove);
- canvasElement.removeEventListener("pointerup", onPointerUp);
- canvasElement.removeEventListener("keydown", onKeyDown);
- };
- }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects]);
-
- const gridSize = 0.25;
- const moveSpeed = 0.25;
- const isGridSnap = false;
-
- useFrame(() => {
- if (movedObjects.length > 0) {
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
-
- if (point) {
- let targetX = point.x;
- let targetZ = point.z;
-
- if (isGridSnap) {
- targetX = Math.round(point.x / gridSize) * gridSize;
- targetZ = Math.round(point.z / gridSize) * gridSize;
- }
-
- const position = new THREE.Vector3();
- if (boundingBoxRef.current) {
- boundingBoxRef.current.getWorldPosition(position);
- selectionGroup.current.position.lerp(
- new THREE.Vector3(
- targetX - (position.x - selectionGroup.current.position.x),
- selectionGroup.current.position.y,
- targetZ - (position.z - selectionGroup.current.position.z)
- ),
- moveSpeed
- );
- } else {
- const box = new THREE.Box3();
- movedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
- const center = new THREE.Vector3();
- box.getCenter(center);
-
- selectionGroup.current.position.lerp(
- new THREE.Vector3(
- targetX - (center.x - selectionGroup.current.position.x),
- selectionGroup.current.position.y,
- targetZ - (center.z - selectionGroup.current.position.z)
- ),
- moveSpeed
- );
- }
- }
- }
- });
-
-
- const moveAssets = () => {
- const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
- setFloorItems(updatedItems);
- setMovedObjects(selectedAssets);
- selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); });
- }
-
- const placeMovedAssets = () => {
- if (movedObjects.length === 0) return;
-
- movedObjects.forEach(async (obj: THREE.Object3D) => {
- const worldPosition = new THREE.Vector3();
- obj.getWorldPosition(worldPosition);
-
- selectionGroup.current.remove(obj);
- obj.position.copy(worldPosition);
-
- if (itemsGroupRef.current) {
-
- const newFloorItem: Types.FloorItemType = {
- modeluuid: obj.uuid,
- modelname: obj.userData.name,
- modelfileID: obj.userData.modelId,
- position: [worldPosition.x, worldPosition.y, worldPosition.z],
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
- isLocked: false,
- isVisible: true
- };
-
- setFloorItems((prevItems: Types.FloorItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- let eventData: SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema | 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.type === 'Conveyor' && eventData) {
-
- const backendEventData = {
- type: 'Conveyor',
- points: eventData.points,
- speed: (eventData as SimulationTypes.ConveyorEventsSchema)?.speed
- };
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
- socketId: socket.id,
- };
-
- 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];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
- } else if (eventData.type === 'Vehicle' && eventData) {
-
- const backendEventData = {
- type: 'Vehicle',
- points: eventData.points
- };
-
- // REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'StaticMachine' && eventData) {
-
- const backendEventData = {
- type: 'StaticMachine',
- points: eventData.points,
- };
-
- // REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'ArmBot' && eventData) {
-
- const backendEventData = {
- type: 'ArmBot',
- points: eventData.points,
- };
-
- // REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
-
- }
- } else {
-
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:add", data);
-
- }
-
- itemsGroupRef.current.add(obj);
- }
- });
- toast.success("Object moved!");
-
- itemsData.current = [];
- clearSelection();
- }
-
- const clearSelection = () => {
- selectionGroup.current.children = [];
- selectionGroup.current.position.set(0, 0, 0);
- selectionGroup.current.rotation.set(0, 0, 0);
- setpastedObjects([]);
- setDuplicatedObjects([]);
- setMovedObjects([]);
- setRotatedObjects([]);
- setSelectedAssets([]);
- }
-
- return null; // No need to return anything, as this component is used for its side effects
-}
-
-export default MoveControls
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selection/rotateControls.tsx b/app/src/modules/scene/controls/selection/rotateControls.tsx
deleted file mode 100644
index f602bc4..0000000
--- a/app/src/modules/scene/controls/selection/rotateControls.tsx
+++ /dev/null
@@ -1,464 +0,0 @@
-import * as THREE from "three";
-import { useEffect, useMemo, useRef, useState } from "react";
-import { useFrame, useThree } from "@react-three/fiber";
-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";
-import * as SimulationTypes from "../../../../types/simulationTypes";
-import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
-
-function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
- const { camera, controls, gl, scene, pointer, raycaster } = useThree();
- const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
-
- const { toggleView } = useToggleView();
- const { selectedAssets, setSelectedAssets } = useSelectedAssets();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { floorItems, setFloorItems } = useFloorItems();
- const { socket } = useSocketStore();
- const itemsData = useRef([]);
-
- const prevPointerPosition = useRef(null);
-
- useEffect(() => {
- if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
-
- const canvasElement = gl.domElement;
- canvasElement.tabIndex = 0;
-
- let isMoving = false;
-
- const onPointerDown = () => {
- isMoving = false;
- };
-
- const onPointerMove = () => {
- isMoving = true;
- };
-
- const onPointerUp = (event: PointerEvent) => {
- if (!isMoving && rotatedObjects.length > 0 && event.button === 0) {
- event.preventDefault();
- placeRotatedAssets();
- }
- if (!isMoving && rotatedObjects.length > 0 && event.button === 2) {
- event.preventDefault();
-
- clearSelection();
- rotatedObjects.forEach((asset: any) => {
- if (itemsGroupRef.current) {
- itemsGroupRef.current.attach(asset);
- }
- });
-
- setFloorItems([...floorItems, ...itemsData.current]);
-
- setRotatedObjects([]);
- itemsData.current = [];
- }
- };
-
- const onKeyDown = (event: KeyboardEvent) => {
- if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || movedObjects.length > 0) return;
- if (event.key.toLowerCase() === "r") {
- if (selectedAssets.length > 0) {
- rotateAssets();
- itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
- }
- }
- if (event.key.toLowerCase() === "escape") {
- event.preventDefault();
-
- clearSelection();
- rotatedObjects.forEach((asset: any) => {
- if (itemsGroupRef.current) {
- itemsGroupRef.current.attach(asset);
- }
- });
-
- setFloorItems([...floorItems, ...itemsData.current]);
-
- setRotatedObjects([]);
- itemsData.current = [];
- }
- };
-
- if (!toggleView) {
- canvasElement.addEventListener("pointerdown", onPointerDown);
- canvasElement.addEventListener("pointermove", onPointerMove);
- canvasElement.addEventListener("pointerup", onPointerUp);
- canvasElement.addEventListener("keydown", onKeyDown);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onPointerDown);
- canvasElement.removeEventListener("pointermove", onPointerMove);
- canvasElement.removeEventListener("pointerup", onPointerUp);
- canvasElement.removeEventListener("keydown", onKeyDown);
- };
- }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, rotatedObjects, movedObjects]);
-
- useFrame(() => {
- if (rotatedObjects.length > 0) {
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
-
- if (point && prevPointerPosition.current) {
- const box = new THREE.Box3();
- rotatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
- const center = new THREE.Vector3();
- box.getCenter(center);
-
- const delta = new THREE.Vector3().subVectors(point, center);
- const prevPointerPosition3D = new THREE.Vector3(prevPointerPosition.current.x, 0, prevPointerPosition.current.y);
-
- const angle = Math.atan2(delta.z, delta.x) - Math.atan2(prevPointerPosition3D.z - center.z, prevPointerPosition3D.x - center.x);
-
- selectionGroup.current.rotation.y += -angle;
-
- selectionGroup.current.position.sub(center);
- selectionGroup.current.position.applyAxisAngle(new THREE.Vector3(0, 1, 0), -angle);
- selectionGroup.current.position.add(center);
-
- prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
- }
- }
- });
-
- const rotateAssets = () => {
- const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
- setFloorItems(updatedItems);
-
- const box = new THREE.Box3();
- selectedAssets.forEach((asset: any) => box.expandByObject(asset));
- const center = new THREE.Vector3();
- box.getCenter(center);
-
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
-
- if (point) {
- prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
- }
-
- selectedAssets.forEach((asset: any) => {
- selectionGroup.current.attach(asset);
- });
-
- setRotatedObjects(selectedAssets);
- };
-
- const placeRotatedAssets = () => {
- if (rotatedObjects.length === 0) return;
-
- rotatedObjects.forEach(async (obj: THREE.Object3D) => {
- const worldPosition = new THREE.Vector3();
- const worldQuaternion = new THREE.Quaternion();
-
- obj.getWorldPosition(worldPosition);
- obj.getWorldQuaternion(worldQuaternion);
-
- selectionGroup.current.remove(obj);
-
- obj.position.copy(worldPosition);
- obj.quaternion.copy(worldQuaternion);
-
-
- if (itemsGroupRef.current) {
-
- const newFloorItem: Types.FloorItemType = {
- modeluuid: obj.uuid,
- modelname: obj.userData.name,
- modelfileID: obj.userData.modelId,
- position: [worldPosition.x, worldPosition.y, worldPosition.z],
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
- isLocked: false,
- isVisible: true
- };
-
- setFloorItems((prevItems: Types.FloorItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- let eventData: SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema | 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.type === 'Conveyor' && eventData) {
-
- const backendEventData = {
- type: 'Conveyor',
- points: eventData.points,
- speed: (eventData as SimulationTypes.ConveyorEventsSchema)?.speed
- };
-
- // REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
- socketId: socket.id,
- };
-
- 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];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'Vehicle' && eventData) {
-
- const backendEventData = {
- type: 'Vehicle',
- points: eventData.points
- };
-
- // REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'StaticMachine' && eventData) {
-
- const backendEventData = {
- type: 'StaticMachine',
- points: eventData.points,
- };
-
- // REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
-
- } else if (eventData.type === 'ArmBot' && eventData) {
-
- const backendEventData = {
- type: 'ArmBot',
- points: eventData.points,
- };
-
- // REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // obj.userData.modelId,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // false,
- // true,
- // { type: backendEventData.type, points: backendEventData.points }
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- eventData: { type: backendEventData.type, points: backendEventData.points },
- socketId: socket.id,
- };
-
- const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
- newEventData.modeluuid = newFloorItem.modeluuid;
- newEventData.modelName = newFloorItem.modelname;
- newEventData.position = newFloorItem.position;
- newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
-
- setSimulationStates((prevEvents: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).map(event =>
- event.modeluuid === newFloorItem.modeluuid
- ? { ...event, ...newEventData }
- : event
- );
- return updatedEvents;
- });
-
- socket.emit("v2:model-asset:add", data);
-
- }
- } else {
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modeluuid: newFloorItem.modeluuid,
- modelname: newFloorItem.modelname,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:add", data);
-
- }
-
- itemsGroupRef.current.add(obj);
- }
- });
- toast.success("Object rotated!");
-
- itemsData.current = [];
- clearSelection();
- }
-
- const clearSelection = () => {
- selectionGroup.current.children = [];
- selectionGroup.current.position.set(0, 0, 0);
- selectionGroup.current.rotation.set(0, 0, 0);
- setpastedObjects([]);
- setDuplicatedObjects([]);
- setMovedObjects([]);
- setRotatedObjects([]);
- setSelectedAssets([]);
- }
-
- return null; // No need to return anything, as this component is used for its side effects
-}
-
-export default RotateControls
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selection/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx
similarity index 97%
rename from app/src/modules/scene/controls/selection/boundingBoxHelper.tsx
rename to app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx
index dd9d251..df57bf9 100644
--- a/app/src/modules/scene/controls/selection/boundingBoxHelper.tsx
+++ b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx
@@ -1,64 +1,64 @@
-import { Line } from "@react-three/drei";
-import { useMemo } from "react";
-import * as THREE from "three";
-import { useSelectedAssets } from "../../../../store/store";
-
-const BoundingBox = ({ boundingBoxRef }: any) => {
- const { selectedAssets } = useSelectedAssets();
-
- const { points, boxProps } = useMemo(() => {
- if (selectedAssets.length === 0) return { points: [], boxProps: {} };
-
- const box = new THREE.Box3();
- selectedAssets.forEach((obj: any) => box.expandByObject(obj.clone()));
-
- const size = new THREE.Vector3();
- box.getSize(size);
- const center = new THREE.Vector3();
- box.getCenter(center);
-
- const halfSize = size.clone().multiplyScalar(0.5);
- const min = center.clone().sub(halfSize);
- const max = center.clone().add(halfSize);
-
- const points: any = [
- [min.x, min.y, min.z], [max.x, min.y, min.z],
- [max.x, min.y, min.z], [max.x, max.y, min.z],
- [max.x, max.y, min.z], [min.x, max.y, min.z],
- [min.x, max.y, min.z], [min.x, min.y, min.z],
-
- [min.x, min.y, max.z], [max.x, min.y, max.z],
- [max.x, min.y, max.z], [max.x, max.y, max.z],
- [max.x, max.y, max.z], [min.x, max.y, max.z],
- [min.x, max.y, max.z], [min.x, min.y, max.z],
-
- [min.x, min.y, min.z], [min.x, min.y, max.z],
- [max.x, min.y, min.z], [max.x, min.y, max.z],
- [max.x, max.y, min.z], [max.x, max.y, max.z],
- [min.x, max.y, min.z], [min.x, max.y, max.z],
- ];
-
- return {
- points,
- boxProps: { position: center.toArray(), args: size.toArray() }
- };
- }, [selectedAssets]);
-
- const savedTheme: string | null = localStorage.getItem("theme") || "light";
-
- return (
- <>
- {points.length > 0 && (
- <>
-
-
-
-
-
- >
- )}
- >
- );
-};
-
-export default BoundingBox;
+import { Line } from "@react-three/drei";
+import { useMemo } from "react";
+import * as THREE from "three";
+import { useSelectedAssets } from "../../../../store/store";
+
+const BoundingBox = ({ boundingBoxRef }: any) => {
+ const { selectedAssets } = useSelectedAssets();
+
+ const { points, boxProps } = useMemo(() => {
+ if (selectedAssets.length === 0) return { points: [], boxProps: {} };
+
+ const box = new THREE.Box3();
+ selectedAssets.forEach((obj: any) => box.expandByObject(obj.clone()));
+
+ const size = new THREE.Vector3();
+ box.getSize(size);
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+
+ const halfSize = size.clone().multiplyScalar(0.5);
+ const min = center.clone().sub(halfSize);
+ const max = center.clone().add(halfSize);
+
+ const points: any = [
+ [min.x, min.y, min.z], [max.x, min.y, min.z],
+ [max.x, min.y, min.z], [max.x, max.y, min.z],
+ [max.x, max.y, min.z], [min.x, max.y, min.z],
+ [min.x, max.y, min.z], [min.x, min.y, min.z],
+
+ [min.x, min.y, max.z], [max.x, min.y, max.z],
+ [max.x, min.y, max.z], [max.x, max.y, max.z],
+ [max.x, max.y, max.z], [min.x, max.y, max.z],
+ [min.x, max.y, max.z], [min.x, min.y, max.z],
+
+ [min.x, min.y, min.z], [min.x, min.y, max.z],
+ [max.x, min.y, min.z], [max.x, min.y, max.z],
+ [max.x, max.y, min.z], [max.x, max.y, max.z],
+ [min.x, max.y, min.z], [min.x, max.y, max.z],
+ ];
+
+ return {
+ points,
+ boxProps: { position: center.toArray(), args: size.toArray() }
+ };
+ }, [selectedAssets]);
+
+ const savedTheme: string | null = localStorage.getItem("theme") || "light";
+
+ return (
+ <>
+ {points.length > 0 && (
+ <>
+
+
+
+
+
+ >
+ )}
+ >
+ );
+};
+
+export default BoundingBox;
diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx
new file mode 100644
index 0000000..9ca4dd0
--- /dev/null
+++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx
@@ -0,0 +1,211 @@
+import * as THREE from "three";
+import { useEffect, useMemo } from "react";
+import { useFrame, useThree } from "@react-three/fiber";
+import { useFloorItems, useSelectedAssets, 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";
+import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
+
+const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, selectionGroup, setDuplicatedObjects, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
+ const { camera, controls, gl, scene, pointer, raycaster } = useThree();
+ const { toggleView } = useToggleView();
+ const { selectedAssets, setSelectedAssets } = useSelectedAssets();
+ const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
+ const { floorItems, setFloorItems } = useFloorItems();
+ const { socket } = useSocketStore()
+
+ useEffect(() => {
+ if (!camera || !scene || toggleView) return;
+ const canvasElement = gl.domElement;
+ canvasElement.tabIndex = 0;
+
+ let isMoving = false;
+
+ const onPointerDown = () => {
+ isMoving = false;
+ };
+
+ const onPointerMove = () => {
+ isMoving = true;
+ };
+
+ const onPointerUp = (event: PointerEvent) => {
+ if (!isMoving && pastedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
+ event.preventDefault();
+ addPastedObjects();
+ }
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(event);
+
+ if (keyCombination === "Ctrl+C" && movedObjects.length === 0 && rotatedObjects.length === 0) {
+ copySelection();
+ }
+ if (keyCombination === "Ctrl+V" && copiedObjects.length > 0 && pastedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
+ pasteCopiedObjects();
+ }
+ };
+
+ if (!toggleView) {
+ canvasElement.addEventListener("pointerdown", onPointerDown);
+ canvasElement.addEventListener("pointermove", onPointerMove);
+ canvasElement.addEventListener("pointerup", onPointerUp);
+ canvasElement.addEventListener("keydown", onKeyDown);
+ }
+
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onPointerDown);
+ canvasElement.removeEventListener("pointermove", onPointerMove);
+ canvasElement.removeEventListener("pointerup", onPointerUp);
+ canvasElement.removeEventListener("keydown", onKeyDown);
+ };
+
+ }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, floorItems, rotatedObjects]);
+
+ useFrame(() => {
+ if (pastedObjects.length > 0) {
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+ if (point) {
+ const position = new THREE.Vector3();
+ if (boundingBoxRef.current) {
+ boundingBoxRef.current?.getWorldPosition(position)
+ selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
+ } else {
+ const box = new THREE.Box3();
+ pastedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+ selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
+ }
+ }
+ }
+ });
+
+ const copySelection = () => {
+ if (selectedAssets.length > 0) {
+ const newClones = selectedAssets.map((asset: any) => {
+ const clone = asset.clone();
+ clone.position.copy(asset.position);
+ return clone;
+ });
+ setCopiedObjects(newClones);
+ toast.info("Objects copied!");
+ }
+ };
+
+ const pasteCopiedObjects = () => {
+ if (copiedObjects.length > 0 && pastedObjects.length === 0) {
+ const newClones = copiedObjects.map((obj: THREE.Object3D) => {
+ const clone = obj.clone();
+ clone.position.copy(obj.position);
+ return clone;
+ });
+ selectionGroup.current.add(...newClones);
+ setpastedObjects([...newClones]);
+ setSelectedAssets([...newClones]);
+
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+
+ if (point) {
+ const position = new THREE.Vector3();
+ if (boundingBoxRef.current) {
+ boundingBoxRef.current?.getWorldPosition(position)
+ selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
+ } else {
+ const box = new THREE.Box3();
+ newClones.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+ selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
+ }
+ }
+ }
+ };
+
+ const addPastedObjects = () => {
+ if (pastedObjects.length === 0) return;
+ pastedObjects.forEach(async (obj: THREE.Object3D) => {
+ const worldPosition = new THREE.Vector3();
+ obj.getWorldPosition(worldPosition);
+ obj.position.copy(worldPosition);
+
+ if (itemsGroupRef.current) {
+
+ const newFloorItem: Types.FloorItemType = {
+ modeluuid: obj.uuid,
+ modelname: obj.userData.name,
+ modelfileID: obj.userData.modelId,
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
+ isLocked: false,
+ isVisible: true
+ };
+
+ setFloorItems((prevItems: Types.FloorItems) => {
+ const updatedItems = [...(prevItems || []), newFloorItem];
+ localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
+ return updatedItems;
+ });
+
+ const email = localStorage.getItem("email");
+ const organization = email ? email.split("@")[1].split(".")[0] : "default";
+
+ //REST
+
+ // await setFloorItemApi(
+ // organization,
+ // obj.uuid,
+ // obj.userData.name,
+ // [worldPosition.x, worldPosition.y, worldPosition.z],
+ // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
+ // obj.userData.modelId,
+ // false,
+ // true,
+ // );
+
+ //SOCKET
+
+ const data = {
+ organization,
+ modeluuid: newFloorItem.modeluuid,
+ modelname: newFloorItem.modelname,
+ modelfileID: newFloorItem.modelfileID,
+ position: newFloorItem.position,
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
+ isLocked: false,
+ isVisible: true,
+ socketId: socket.id,
+ };
+
+ socket.emit("v2:model-asset:add", data);
+
+ obj.userData.modeluuid = newFloorItem.modeluuid;
+ itemsGroupRef.current.add(obj);
+ }
+ });
+
+ toast.success("Object added!");
+ clearSelection();
+ };
+
+ const clearSelection = () => {
+ selectionGroup.current.children = [];
+ selectionGroup.current.position.set(0, 0, 0);
+ selectionGroup.current.rotation.set(0, 0, 0);
+ setMovedObjects([]);
+ setpastedObjects([]);
+ setDuplicatedObjects([]);
+ setRotatedObjects([]);
+ setSelectedAssets([]);
+ }
+
+ return null; // No visible output, but the component handles copy-paste functionality
+};
+
+export default CopyPasteControls;
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx
new file mode 100644
index 0000000..39c3e49
--- /dev/null
+++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx
@@ -0,0 +1,189 @@
+import * as THREE from "three";
+import { useEffect, useMemo } from "react";
+import { useFrame, useThree } from "@react-three/fiber";
+import { useFloorItems, useSelectedAssets, 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";
+import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
+import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
+
+const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
+ const { camera, controls, gl, scene, pointer, raycaster } = useThree();
+ const { toggleView } = useToggleView();
+ const { selectedAssets, setSelectedAssets } = useSelectedAssets();
+ const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
+ const { floorItems, setFloorItems } = useFloorItems();
+ const { socket } = useSocketStore();
+
+ useEffect(() => {
+ if (!camera || !scene || toggleView) return;
+ const canvasElement = gl.domElement;
+ canvasElement.tabIndex = 0;
+
+ let isMoving = false;
+
+ const onPointerDown = () => {
+ isMoving = false;
+ };
+
+ const onPointerMove = () => {
+ isMoving = true;
+ };
+
+ const onPointerUp = (event: PointerEvent) => {
+ if (!isMoving && duplicatedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
+ event.preventDefault();
+ addDuplicatedAssets();
+ }
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(event);
+
+ if (keyCombination === "Ctrl+D" && selectedAssets.length > 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
+ duplicateSelection();
+ }
+ };
+
+ if (!toggleView) {
+ canvasElement.addEventListener("pointerdown", onPointerDown);
+ canvasElement.addEventListener("pointermove", onPointerMove);
+ canvasElement.addEventListener("pointerup", onPointerUp);
+ canvasElement.addEventListener("keydown", onKeyDown);
+ }
+
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onPointerDown);
+ canvasElement.removeEventListener("pointermove", onPointerMove);
+ canvasElement.removeEventListener("pointerup", onPointerUp);
+ canvasElement.removeEventListener("keydown", onKeyDown);
+ };
+
+ }, [camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects]);
+
+ useFrame(() => {
+ if (duplicatedObjects.length > 0) {
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+ if (point) {
+ const position = new THREE.Vector3();
+ if (boundingBoxRef.current) {
+ boundingBoxRef.current?.getWorldPosition(position)
+ selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
+ } else {
+ const box = new THREE.Box3();
+ duplicatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+ selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
+ }
+ }
+ }
+ });
+
+ const duplicateSelection = () => {
+ if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
+ const newClones = selectedAssets.map((asset: any) => {
+ const clone = asset.clone();
+ clone.position.copy(asset.position);
+ return clone;
+ });
+
+ selectionGroup.current.add(...newClones);
+ setDuplicatedObjects(newClones);
+
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+
+ if (point) {
+ const position = new THREE.Vector3();
+ boundingBoxRef.current?.getWorldPosition(position)
+ selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
+ }
+ }
+ };
+
+ const addDuplicatedAssets = () => {
+ if (duplicatedObjects.length === 0) return;
+ duplicatedObjects.forEach(async (obj: THREE.Object3D) => {
+ const worldPosition = new THREE.Vector3();
+ obj.getWorldPosition(worldPosition);
+ obj.position.copy(worldPosition);
+
+ if (itemsGroupRef.current) {
+
+ const newFloorItem: Types.FloorItemType = {
+ modeluuid: obj.uuid,
+ modelname: obj.userData.name,
+ modelfileID: obj.userData.modelId,
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
+ isLocked: false,
+ isVisible: true
+ };
+
+ setFloorItems((prevItems: Types.FloorItems) => {
+ const updatedItems = [...(prevItems || []), newFloorItem];
+ localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
+ return updatedItems;
+ });
+
+ const email = localStorage.getItem("email");
+ const organization = email ? email.split("@")[1].split(".")[0] : "default";
+
+ //REST
+
+ // await setFloorItemApi(
+ // organization,
+ // obj.uuid,
+ // obj.userData.name,
+ // [worldPosition.x, worldPosition.y, worldPosition.z],
+ // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
+ // obj.userData.modelId,
+ // false,
+ // true,
+ // );
+
+ //SOCKET
+
+ const data = {
+ organization,
+ modeluuid: newFloorItem.modeluuid,
+ modelname: newFloorItem.modelname,
+ modelfileID: newFloorItem.modelfileID,
+ position: newFloorItem.position,
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
+ isLocked: false,
+ isVisible: true,
+ socketId: socket.id,
+ };
+
+ socket.emit("v2:model-asset:add", data);
+
+ obj.userData.modeluuid = newFloorItem.modeluuid;
+ itemsGroupRef.current.add(obj);
+ }
+ });
+
+ toast.success("Object duplicated!");
+ clearSelection();
+ }
+
+ const clearSelection = () => {
+ selectionGroup.current.children = [];
+ selectionGroup.current.position.set(0, 0, 0);
+ selectionGroup.current.rotation.set(0, 0, 0);
+ setMovedObjects([]);
+ setpastedObjects([]);
+ setDuplicatedObjects([]);
+ setRotatedObjects([]);
+ setSelectedAssets([]);
+ }
+
+ return null; // This component does not render any UI
+};
+
+export default DuplicationControls;
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx
new file mode 100644
index 0000000..2cde3e4
--- /dev/null
+++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx
@@ -0,0 +1,240 @@
+import * as THREE from "three";
+import { useEffect, useMemo, useRef, useState } from "react";
+import { useFrame, useThree } from "@react-three/fiber";
+import { useFloorItems, useSelectedAssets, 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";
+import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
+
+function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) {
+ const { camera, controls, gl, scene, pointer, raycaster } = useThree();
+ const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
+
+ const { toggleView } = useToggleView();
+ const { selectedAssets, setSelectedAssets } = useSelectedAssets();
+ const { floorItems, setFloorItems } = useFloorItems();
+ const { socket } = useSocketStore();
+ const itemsData = useRef([]);
+
+ useEffect(() => {
+ if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
+
+ const canvasElement = gl.domElement;
+ canvasElement.tabIndex = 0;
+
+ let isMoving = false;
+
+ const onPointerDown = () => {
+ isMoving = false;
+ };
+
+ const onPointerMove = () => {
+ isMoving = true;
+ };
+
+ const onPointerUp = (event: PointerEvent) => {
+ if (!isMoving && movedObjects.length > 0 && event.button === 0) {
+ event.preventDefault();
+ placeMovedAssets();
+ }
+ if (!isMoving && movedObjects.length > 0 && event.button === 2) {
+ event.preventDefault();
+
+ clearSelection();
+ movedObjects.forEach((asset: any) => {
+ if (itemsGroupRef.current) {
+ itemsGroupRef.current.attach(asset);
+ }
+ });
+
+ setFloorItems([...floorItems, ...itemsData.current]);
+
+ setMovedObjects([]);
+ itemsData.current = [];
+ }
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(event);
+
+ if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return;
+ if (keyCombination === "G") {
+ if (selectedAssets.length > 0) {
+ moveAssets();
+ itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
+ }
+ }
+ if (keyCombination === "ESCAPE") {
+ event.preventDefault();
+
+ clearSelection();
+ movedObjects.forEach((asset: any) => {
+ if (itemsGroupRef.current) {
+ itemsGroupRef.current.attach(asset);
+ }
+ });
+
+ setFloorItems([...floorItems, ...itemsData.current]);
+
+ setMovedObjects([]);
+ itemsData.current = [];
+ }
+ };
+
+ if (!toggleView) {
+ canvasElement.addEventListener("pointerdown", onPointerDown);
+ canvasElement.addEventListener("pointermove", onPointerMove);
+ canvasElement.addEventListener("pointerup", onPointerUp);
+ canvasElement.addEventListener("keydown", onKeyDown);
+ }
+
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onPointerDown);
+ canvasElement.removeEventListener("pointermove", onPointerMove);
+ canvasElement.removeEventListener("pointerup", onPointerUp);
+ canvasElement.removeEventListener("keydown", onKeyDown);
+ };
+ }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects]);
+
+ const gridSize = 0.25;
+ const moveSpeed = 0.25;
+ const isGridSnap = false;
+
+ useFrame(() => {
+ if (movedObjects.length > 0) {
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+
+ if (point) {
+ let targetX = point.x;
+ let targetZ = point.z;
+
+ if (isGridSnap) {
+ targetX = Math.round(point.x / gridSize) * gridSize;
+ targetZ = Math.round(point.z / gridSize) * gridSize;
+ }
+
+ const position = new THREE.Vector3();
+ if (boundingBoxRef.current) {
+ boundingBoxRef.current.getWorldPosition(position);
+ selectionGroup.current.position.lerp(
+ new THREE.Vector3(
+ targetX - (position.x - selectionGroup.current.position.x),
+ selectionGroup.current.position.y,
+ targetZ - (position.z - selectionGroup.current.position.z)
+ ),
+ moveSpeed
+ );
+ } else {
+ const box = new THREE.Box3();
+ movedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+
+ selectionGroup.current.position.lerp(
+ new THREE.Vector3(
+ targetX - (center.x - selectionGroup.current.position.x),
+ selectionGroup.current.position.y,
+ targetZ - (center.z - selectionGroup.current.position.z)
+ ),
+ moveSpeed
+ );
+ }
+ }
+ }
+ });
+
+
+ const moveAssets = () => {
+ const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
+ setFloorItems(updatedItems);
+ setMovedObjects(selectedAssets);
+ selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); });
+ }
+
+ const placeMovedAssets = () => {
+ if (movedObjects.length === 0) return;
+
+ movedObjects.forEach(async (obj: THREE.Object3D) => {
+ const worldPosition = new THREE.Vector3();
+ obj.getWorldPosition(worldPosition);
+
+ selectionGroup.current.remove(obj);
+ obj.position.copy(worldPosition);
+
+ if (itemsGroupRef.current) {
+
+ const newFloorItem: Types.FloorItemType = {
+ modeluuid: obj.uuid,
+ modelname: obj.userData.name,
+ modelfileID: obj.userData.modelId,
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
+ isLocked: false,
+ isVisible: true
+ };
+
+ setFloorItems((prevItems: Types.FloorItems) => {
+ const updatedItems = [...(prevItems || []), newFloorItem];
+ localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
+ return updatedItems;
+ });
+
+ const email = localStorage.getItem("email");
+ const organization = email ? email.split("@")[1].split(".")[0] : "default";
+
+ //REST
+
+ // await setFloorItemApi(
+ // organization,
+ // obj.uuid,
+ // obj.userData.name,
+ // [worldPosition.x, worldPosition.y, worldPosition.z],
+ // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
+ // obj.userData.modelId,
+ // false,
+ // true,
+ // );
+
+ //SOCKET
+
+ const data = {
+ organization,
+ modeluuid: newFloorItem.modeluuid,
+ modelname: newFloorItem.modelname,
+ modelfileID: newFloorItem.modelfileID,
+ position: newFloorItem.position,
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
+ isLocked: false,
+ isVisible: true,
+ socketId: socket.id,
+ };
+
+ socket.emit("v2:model-asset:add", data);
+
+ itemsGroupRef.current.add(obj);
+ }
+ });
+ toast.success("Object moved!");
+
+ itemsData.current = [];
+ clearSelection();
+ }
+
+ const clearSelection = () => {
+ selectionGroup.current.children = [];
+ selectionGroup.current.position.set(0, 0, 0);
+ selectionGroup.current.rotation.set(0, 0, 0);
+ setpastedObjects([]);
+ setDuplicatedObjects([]);
+ setMovedObjects([]);
+ setRotatedObjects([]);
+ setSelectedAssets([]);
+ }
+
+ return null; // No need to return anything, as this component is used for its side effects
+}
+
+export default MoveControls
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx
new file mode 100644
index 0000000..5dfaf08
--- /dev/null
+++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx
@@ -0,0 +1,241 @@
+import * as THREE from "three";
+import { useEffect, useMemo, useRef, useState } from "react";
+import { useFrame, useThree } from "@react-three/fiber";
+import { useFloorItems, useSelectedAssets, 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";
+import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
+
+function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
+ const { camera, controls, gl, scene, pointer, raycaster } = useThree();
+ const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
+
+ const { toggleView } = useToggleView();
+ const { selectedAssets, setSelectedAssets } = useSelectedAssets();
+ const { floorItems, setFloorItems } = useFloorItems();
+ const { socket } = useSocketStore();
+ const itemsData = useRef([]);
+
+ const prevPointerPosition = useRef(null);
+
+ useEffect(() => {
+ if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
+
+ const canvasElement = gl.domElement;
+ canvasElement.tabIndex = 0;
+
+ let isMoving = false;
+
+ const onPointerDown = () => {
+ isMoving = false;
+ };
+
+ const onPointerMove = () => {
+ isMoving = true;
+ };
+
+ const onPointerUp = (event: PointerEvent) => {
+ if (!isMoving && rotatedObjects.length > 0 && event.button === 0) {
+ event.preventDefault();
+ placeRotatedAssets();
+ }
+ if (!isMoving && rotatedObjects.length > 0 && event.button === 2) {
+ event.preventDefault();
+
+ clearSelection();
+ rotatedObjects.forEach((asset: any) => {
+ if (itemsGroupRef.current) {
+ itemsGroupRef.current.attach(asset);
+ }
+ });
+
+ setFloorItems([...floorItems, ...itemsData.current]);
+
+ setRotatedObjects([]);
+ itemsData.current = [];
+ }
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || movedObjects.length > 0) return;
+ if (event.key.toLowerCase() === "r") {
+ if (selectedAssets.length > 0) {
+ rotateAssets();
+ itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
+ }
+ }
+ if (event.key.toLowerCase() === "escape") {
+ event.preventDefault();
+
+ clearSelection();
+ rotatedObjects.forEach((asset: any) => {
+ if (itemsGroupRef.current) {
+ itemsGroupRef.current.attach(asset);
+ }
+ });
+
+ setFloorItems([...floorItems, ...itemsData.current]);
+
+ setRotatedObjects([]);
+ itemsData.current = [];
+ }
+ };
+
+ if (!toggleView) {
+ canvasElement.addEventListener("pointerdown", onPointerDown);
+ canvasElement.addEventListener("pointermove", onPointerMove);
+ canvasElement.addEventListener("pointerup", onPointerUp);
+ canvasElement.addEventListener("keydown", onKeyDown);
+ }
+
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onPointerDown);
+ canvasElement.removeEventListener("pointermove", onPointerMove);
+ canvasElement.removeEventListener("pointerup", onPointerUp);
+ canvasElement.removeEventListener("keydown", onKeyDown);
+ };
+ }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, rotatedObjects, movedObjects]);
+
+ useFrame(() => {
+ if (rotatedObjects.length > 0) {
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+
+ if (point && prevPointerPosition.current) {
+ const box = new THREE.Box3();
+ rotatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+
+ const delta = new THREE.Vector3().subVectors(point, center);
+ const prevPointerPosition3D = new THREE.Vector3(prevPointerPosition.current.x, 0, prevPointerPosition.current.y);
+
+ const angle = Math.atan2(delta.z, delta.x) - Math.atan2(prevPointerPosition3D.z - center.z, prevPointerPosition3D.x - center.x);
+
+ selectionGroup.current.rotation.y += -angle;
+
+ selectionGroup.current.position.sub(center);
+ selectionGroup.current.position.applyAxisAngle(new THREE.Vector3(0, 1, 0), -angle);
+ selectionGroup.current.position.add(center);
+
+ prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
+ }
+ }
+ });
+
+ const rotateAssets = () => {
+ const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid));
+ setFloorItems(updatedItems);
+
+ const box = new THREE.Box3();
+ selectedAssets.forEach((asset: any) => box.expandByObject(asset));
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+
+ if (point) {
+ prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
+ }
+
+ selectedAssets.forEach((asset: any) => {
+ selectionGroup.current.attach(asset);
+ });
+
+ setRotatedObjects(selectedAssets);
+ };
+
+ const placeRotatedAssets = () => {
+ if (rotatedObjects.length === 0) return;
+
+ rotatedObjects.forEach(async (obj: THREE.Object3D) => {
+ const worldPosition = new THREE.Vector3();
+ const worldQuaternion = new THREE.Quaternion();
+
+ obj.getWorldPosition(worldPosition);
+ obj.getWorldQuaternion(worldQuaternion);
+
+ selectionGroup.current.remove(obj);
+
+ obj.position.copy(worldPosition);
+ obj.quaternion.copy(worldQuaternion);
+
+
+ if (itemsGroupRef.current) {
+
+ const newFloorItem: Types.FloorItemType = {
+ modeluuid: obj.uuid,
+ modelname: obj.userData.name,
+ modelfileID: obj.userData.modelId,
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
+ isLocked: false,
+ isVisible: true
+ };
+
+ setFloorItems((prevItems: Types.FloorItems) => {
+ const updatedItems = [...(prevItems || []), newFloorItem];
+ localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
+ return updatedItems;
+ });
+
+ const email = localStorage.getItem("email");
+ const organization = email ? email.split("@")[1].split(".")[0] : "default";
+
+ //REST
+
+ // await setFloorItemApi(
+ // organization,
+ // obj.uuid,
+ // obj.userData.name,
+ // [worldPosition.x, worldPosition.y, worldPosition.z],
+ // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
+ // obj.userData.modelId,
+ // false,
+ // true,
+ // );
+
+ //SOCKET
+
+ const data = {
+ organization,
+ modeluuid: newFloorItem.modeluuid,
+ modelname: newFloorItem.modelname,
+ modelfileID: newFloorItem.modelfileID,
+ position: newFloorItem.position,
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
+ isLocked: false,
+ isVisible: true,
+ socketId: socket.id,
+ };
+
+ socket.emit("v2:model-asset:add", data);
+
+ itemsGroupRef.current.add(obj);
+ }
+ });
+ toast.success("Object rotated!");
+
+ itemsData.current = [];
+ clearSelection();
+ }
+
+ const clearSelection = () => {
+ selectionGroup.current.children = [];
+ selectionGroup.current.position.set(0, 0, 0);
+ selectionGroup.current.rotation.set(0, 0, 0);
+ setpastedObjects([]);
+ setDuplicatedObjects([]);
+ setMovedObjects([]);
+ setRotatedObjects([]);
+ setSelectedAssets([]);
+ }
+
+ return null; // No need to return anything, as this component is used for its side effects
+}
+
+export default RotateControls
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selection/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
similarity index 54%
rename from app/src/modules/scene/controls/selection/selectionControls.tsx
rename to app/src/modules/scene/controls/selectionControls/selectionControls.tsx
index 8998bc9..49b86d2 100644
--- a/app/src/modules/scene/controls/selection/selectionControls.tsx
+++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
@@ -1,479 +1,272 @@
-import * as THREE from "three";
-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, useSimulationStates, useSocketStore, useToggleView, } from "../../../../store/store";
-import BoundingBox from "./boundingBoxHelper";
-import { toast } from "react-toastify";
-// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
-import * as Types from "../../../../types/world/worldTypes";
-import * as SimulationTypes from "../../../../types/simulationTypes";
-
-import DuplicationControls from "./duplicationControls";
-import CopyPasteControls from "./copyPasteControls";
-import MoveControls from "./moveControls";
-import RotateControls from "./rotateControls";
-import useModuleStore from "../../../../store/useModuleStore";
-
-const SelectionControls: React.FC = () => {
- const { camera, controls, gl, scene, pointer } = useThree();
- const itemsGroupRef = useRef(undefined);
- const selectionGroup = useRef() as Types.RefGroup;
- const { toggleView } = useToggleView();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { selectedAssets, setSelectedAssets } = useSelectedAssets();
- const [movedObjects, setMovedObjects] = useState([]);
- const [rotatedObjects, setRotatedObjects] = useState([]);
- const [copiedObjects, setCopiedObjects] = useState([]);
- const [pastedObjects, setpastedObjects] = useState([]);
- const [duplicatedObjects, setDuplicatedObjects] = useState([]);
- const boundingBoxRef = useRef();
- const { floorItems, setFloorItems } = useFloorItems();
- const { activeModule } = useModuleStore();
- const { socket } = useSocketStore();
- const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
-
- useEffect(() => {
- if (!camera || !scene || toggleView) return;
-
- const canvasElement = gl.domElement;
- canvasElement.tabIndex = 0;
-
- const itemsGroup: any = scene.getObjectByName("itemsGroup");
- itemsGroupRef.current = itemsGroup;
-
- let isSelecting = false;
- let isRightClick = false;
- let rightClickMoved = false;
- let isCtrlSelecting = false;
-
- const helper = new SelectionHelper(gl);
-
- if (!itemsGroup) {
- toast.warn("itemsGroup not found in the scene.");
- return;
- }
-
- const onPointerDown = (event: PointerEvent) => {
- if (event.button === 2) {
- isRightClick = true;
- rightClickMoved = false;
- } else if (event.button === 0) {
- isSelecting = false;
- isCtrlSelecting = event.ctrlKey;
- if (event.ctrlKey && duplicatedObjects.length === 0) {
- if (controls) (controls as any).enabled = false;
- selectionBox.startPoint.set(pointer.x, pointer.y, 0);
- }
- }
- };
-
- const onPointerMove = (event: PointerEvent) => {
- if (isRightClick) {
- rightClickMoved = true;
- }
- isSelecting = true;
- if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting) {
- selectionBox.endPoint.set(pointer.x, pointer.y, 0);
- }
- };
-
- const onPointerUp = (event: PointerEvent) => {
- if (event.button === 2) {
- isRightClick = false;
- if (!rightClickMoved) {
- clearSelection();
- }
- return;
- }
-
- if (isSelecting && isCtrlSelecting) {
- isCtrlSelecting = false;
- isSelecting = false;
- if (event.ctrlKey && duplicatedObjects.length === 0) {
- selectAssets();
- }
- } else if (!isSelecting && selectedAssets.length > 0 && ((pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) || event.button !== 0)) {
- clearSelection();
- helper.enabled = true;
- isCtrlSelecting = false;
- }
- };
-
- const onKeyDown = (event: KeyboardEvent) => {
- if (movedObjects.length > 0 || rotatedObjects.length > 0) return;
- if (event.key.toLowerCase() === "escape") {
- event.preventDefault();
- clearSelection();
- }
- if (event.key.toLowerCase() === "delete") {
- event.preventDefault();
- deleteSelection();
- }
- };
-
- const onContextMenu = (event: MouseEvent) => {
- event.preventDefault();
- if (!rightClickMoved) {
- clearSelection();
- }
- };
-
- if (!toggleView && activeModule === "builder") {
- helper.enabled = true;
- if (duplicatedObjects.length === 0 && pastedObjects.length === 0) {
- canvasElement.addEventListener("pointerdown", onPointerDown);
- canvasElement.addEventListener("pointermove", onPointerMove);
- canvasElement.addEventListener("pointerup", onPointerUp);
- } else {
- helper.enabled = false;
- helper.dispose();
- }
- canvasElement.addEventListener("contextmenu", onContextMenu);
- canvasElement.addEventListener("keydown", onKeyDown);
- } else {
- helper.enabled = false;
- helper.dispose();
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onPointerDown);
- canvasElement.removeEventListener("pointermove", onPointerMove);
- canvasElement.removeEventListener("contextmenu", onContextMenu);
- canvasElement.removeEventListener("pointerup", onPointerUp);
- canvasElement.removeEventListener("keydown", onKeyDown);
- helper.enabled = false;
- helper.dispose();
- };
- }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects, activeModule,]);
-
- useEffect(() => {
- if (activeModule !== "builder") {
- clearSelection();
- }
- }, [activeModule]);
-
- useFrame(() => {
- if (pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
- selectionGroup.current.position.set(0, 0, 0);
- }
- });
-
- const selectAssets = () => {
- selectionBox.endPoint.set(pointer.x, pointer.y, 0);
- if (controls) (controls as any).enabled = true;
-
- let selectedObjects = selectionBox.select();
- let Objects = new Set();
-
- selectedObjects.map((object) => {
- let currentObject: THREE.Object3D | null = object;
- while (currentObject) {
- if (currentObject.userData.modelId) {
- Objects.add(currentObject);
- break;
- }
- currentObject = currentObject.parent || null;
- }
- });
-
- if (Objects.size === 0) {
- clearSelection();
- return;
- }
-
- const updatedSelections = new Set(selectedAssets);
- Objects.forEach((obj) => { updatedSelections.has(obj) ? updatedSelections.delete(obj) : updatedSelections.add(obj); });
-
- const selected = Array.from(updatedSelections);
-
- setSelectedAssets(selected);
- };
-
- const clearSelection = () => {
- selectionGroup.current.children = [];
- selectionGroup.current.position.set(0, 0, 0);
- selectionGroup.current.rotation.set(0, 0, 0);
- setpastedObjects([]);
- setDuplicatedObjects([]);
- setSelectedAssets([]);
- };
- const updateBackend = async (updatedPaths: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- 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);
- } else if (updatedPath.type === "StaticMachine") {
- // await setEventApi(
- // organization,
- // updatedPath.modeluuid,
- // { type: "StaticMachine", points: updatedPath.points }
- // );
-
- const data = {
- organization: organization,
- modeluuid: updatedPath.modeluuid,
- eventData: { type: "StaticMachine", points: updatedPath.points },
- };
-
- socket.emit("v2:model-asset:updateEventData", data);
- } else if (updatedPath.type === "ArmBot") {
- // await setEventApi(
- // organization,
- // updatedPath.modeluuid,
- // { type: "ArmBot", points: updatedPath.points }
- // );
-
- const data = {
- organization: organization,
- modeluuid: updatedPath.modeluuid,
- eventData: { type: "ArmBot", points: updatedPath.points },
- };
-
- socket.emit("v2:model-asset:updateEventData", data);
- }
- });
- };
-
- const removeConnections = (deletedModelUUIDs: string[]) => {
-
- const deletedPointUUIDs = new Set();
- simulationStates.forEach(state => {
- if (deletedModelUUIDs.includes(state.modeluuid)) {
- if (state.type === "Conveyor" && state.points) {
- state.points.forEach(point => {
- deletedPointUUIDs.add(point.uuid);
- });
- } else if (state.points && 'uuid' in state.points) {
- deletedPointUUIDs.add(state.points.uuid);
- }
- }
- });
-
- const updatedStates = simulationStates.map((state) => {
- // Handle Conveyor
- if (state.type === "Conveyor") {
- const updatedConveyor: SimulationTypes.ConveyorEventsSchema = {
- ...state,
- points: state.points.map((point) => {
- return {
- ...point,
- connections: {
- ...point.connections,
- targets: point.connections.targets.filter(
- (target) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- };
- }),
- };
- return updatedConveyor;
- }
-
- // Handle Vehicle
- else if (state.type === "Vehicle") {
- const updatedVehicle: SimulationTypes.VehicleEventsSchema = {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter(
- (target) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- },
- };
- return updatedVehicle;
- }
-
- // Handle StaticMachine
- else if (state.type === "StaticMachine") {
- const updatedStaticMachine: SimulationTypes.StaticMachineEventsSchema =
- {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter(
- (target) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- },
- };
- return updatedStaticMachine;
- }
-
- // Handle ArmBot
- else if (state.type === "ArmBot") {
- const updatedArmBot: SimulationTypes.ArmBotEventsSchema = {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter(
- (target: any) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- actions: {
- ...state.points.actions,
- processes: state.points.actions.processes?.filter((process) => {
- // Check if trigger is from deleted model
- const matchedStates = simulationStates.filter((s) => deletedModelUUIDs.includes(s.modeluuid));
-
- if (matchedStates.length > 0) {
- if (matchedStates[0]?.type === "StaticMachine") {
- const trigPoints = matchedStates[0]?.points;
- if (process.triggerId === trigPoints?.triggers?.uuid) {
- return false;
- }
- } else if (matchedStates[0]?.type === "Conveyor") {
- const trigPoints = matchedStates[0]?.points;
- if (Array.isArray(trigPoints)) {
- const nonEmptyTriggers = trigPoints.filter((point) => point && point.triggers && point.triggers.length > 0);
- const allTriggerUUIDs = nonEmptyTriggers.flatMap((point) => point.triggers).map((trigger) => trigger.uuid);
- if (allTriggerUUIDs.includes(process.triggerId)) {
- return false;
- }
- }
- }
- }
-
- // Check if startPoint or endPoint is from deleted model
- if (deletedPointUUIDs.has(process.startPoint) || deletedPointUUIDs.has(process.endPoint)) {
- return false;
- }
-
- return true;
- }),
- },
- },
- };
- return updatedArmBot;
- }
-
- return state;
- });
-
- const filteredStates = updatedStates.filter((state) => !deletedModelUUIDs.includes(state.modeluuid));
-
- updateBackend(filteredStates);
- setSimulationStates(filteredStates);
- };
-
- const deleteSelection = () => {
- if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
- const email = localStorage.getItem("email");
- const organization = email!.split("@")[1].split(".")[0];
-
- const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]");
- const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
-
- const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid));
- localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
-
- selectedAssets.forEach((selectedMesh: THREE.Object3D) => {
- //REST
-
- // const response = await deleteFloorItem(organization, selectedMesh.uuid, selectedMesh.userData.name);
-
- //SOCKET
-
- const data = {
- organization: organization,
- modeluuid: selectedMesh.uuid,
- modelname: selectedMesh.userData.name,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:delete", data);
-
- selectedMesh.traverse((child: THREE.Object3D) => {
- if (child instanceof THREE.Mesh) {
- if (child.geometry) child.geometry.dispose();
- if (Array.isArray(child.material)) {
- child.material.forEach((material) => {
- if (material.map) material.map.dispose();
- material.dispose();
- });
- } else if (child.material) {
- if (child.material.map) child.material.map.dispose();
- child.material.dispose();
- }
- }
- });
-
- setSimulationStates((prevEvents: (| SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- const updatedEvents = (prevEvents || []).filter((event) => event.modeluuid !== selectedMesh.uuid);
- return updatedEvents;
- });
-
- itemsGroupRef.current?.remove(selectedMesh);
- });
-
- const allUUIDs = selectedAssets.map((val: any) => val.uuid);
- removeConnections(allUUIDs);
-
- const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid));
- setFloorItems(updatedItems);
- }
- toast.success("Selected models removed!");
- clearSelection();
- };
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-export default SelectionControls;
+import * as THREE from "three";
+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, useSocketStore, useToggleView, } from "../../../../store/store";
+import BoundingBox from "./boundingBoxHelper";
+import { toast } from "react-toastify";
+// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
+import * as Types from "../../../../types/world/worldTypes";
+
+import DuplicationControls from "./duplicationControls";
+import CopyPasteControls from "./copyPasteControls";
+import MoveControls from "./moveControls";
+import RotateControls from "./rotateControls";
+import useModuleStore from "../../../../store/useModuleStore";
+
+const SelectionControls: React.FC = () => {
+ const { camera, controls, gl, scene, pointer } = useThree();
+ const itemsGroupRef = useRef(undefined);
+ const selectionGroup = useRef() as Types.RefGroup;
+ const { toggleView } = useToggleView();
+ const { selectedAssets, setSelectedAssets } = useSelectedAssets();
+ const [movedObjects, setMovedObjects] = useState([]);
+ const [rotatedObjects, setRotatedObjects] = useState([]);
+ const [copiedObjects, setCopiedObjects] = useState([]);
+ const [pastedObjects, setpastedObjects] = useState([]);
+ const [duplicatedObjects, setDuplicatedObjects] = useState([]);
+ const boundingBoxRef = useRef();
+ const { floorItems, setFloorItems } = useFloorItems();
+ const { activeModule } = useModuleStore();
+ const { socket } = useSocketStore();
+ const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
+
+ useEffect(() => {
+ if (!camera || !scene || toggleView) return;
+
+ const canvasElement = gl.domElement;
+ canvasElement.tabIndex = 0;
+
+ const itemsGroup: any = scene.getObjectByName("itemsGroup");
+ itemsGroupRef.current = itemsGroup;
+
+ let isSelecting = false;
+ let isRightClick = false;
+ let rightClickMoved = false;
+ let isCtrlSelecting = false;
+
+ const helper = new SelectionHelper(gl);
+
+ if (!itemsGroup) {
+ toast.warn("itemsGroup not found in the scene.");
+ return;
+ }
+
+ const onPointerDown = (event: PointerEvent) => {
+ if (event.button === 2) {
+ isRightClick = true;
+ rightClickMoved = false;
+ } else if (event.button === 0) {
+ isSelecting = false;
+ isCtrlSelecting = event.ctrlKey;
+ if (event.ctrlKey && duplicatedObjects.length === 0) {
+ if (controls) (controls as any).enabled = false;
+ selectionBox.startPoint.set(pointer.x, pointer.y, 0);
+ }
+ }
+ };
+
+ const onPointerMove = (event: PointerEvent) => {
+ if (isRightClick) {
+ rightClickMoved = true;
+ }
+ isSelecting = true;
+ if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting) {
+ selectionBox.endPoint.set(pointer.x, pointer.y, 0);
+ }
+ };
+
+ const onPointerUp = (event: PointerEvent) => {
+ if (event.button === 2) {
+ isRightClick = false;
+ if (!rightClickMoved) {
+ clearSelection();
+ }
+ return;
+ }
+
+ if (isSelecting && isCtrlSelecting) {
+ isCtrlSelecting = false;
+ isSelecting = false;
+ if (event.ctrlKey && duplicatedObjects.length === 0) {
+ selectAssets();
+ }
+ } else if (!isSelecting && selectedAssets.length > 0 && ((pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) || event.button !== 0)) {
+ clearSelection();
+ helper.enabled = true;
+ isCtrlSelecting = false;
+ }
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ if (movedObjects.length > 0 || rotatedObjects.length > 0) return;
+ if (event.key.toLowerCase() === "escape") {
+ event.preventDefault();
+ clearSelection();
+ }
+ if (event.key.toLowerCase() === "delete") {
+ event.preventDefault();
+ deleteSelection();
+ }
+ };
+
+ const onContextMenu = (event: MouseEvent) => {
+ event.preventDefault();
+ if (!rightClickMoved) {
+ clearSelection();
+ }
+ };
+
+ if (!toggleView && activeModule === "builder") {
+ helper.enabled = true;
+ if (duplicatedObjects.length === 0 && pastedObjects.length === 0) {
+ canvasElement.addEventListener("pointerdown", onPointerDown);
+ canvasElement.addEventListener("pointermove", onPointerMove);
+ canvasElement.addEventListener("pointerup", onPointerUp);
+ } else {
+ helper.enabled = false;
+ helper.dispose();
+ }
+ canvasElement.addEventListener("contextmenu", onContextMenu);
+ canvasElement.addEventListener("keydown", onKeyDown);
+ } else {
+ helper.enabled = false;
+ helper.dispose();
+ }
+
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onPointerDown);
+ canvasElement.removeEventListener("pointermove", onPointerMove);
+ canvasElement.removeEventListener("contextmenu", onContextMenu);
+ canvasElement.removeEventListener("pointerup", onPointerUp);
+ canvasElement.removeEventListener("keydown", onKeyDown);
+ helper.enabled = false;
+ helper.dispose();
+ };
+ }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects, activeModule,]);
+
+ useEffect(() => {
+ if (activeModule !== "builder") {
+ clearSelection();
+ }
+ }, [activeModule]);
+
+ useFrame(() => {
+ if (pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
+ selectionGroup.current.position.set(0, 0, 0);
+ }
+ });
+
+ const selectAssets = () => {
+ selectionBox.endPoint.set(pointer.x, pointer.y, 0);
+ if (controls) (controls as any).enabled = true;
+
+ let selectedObjects = selectionBox.select();
+ let Objects = new Set();
+
+ selectedObjects.map((object) => {
+ let currentObject: THREE.Object3D | null = object;
+ while (currentObject) {
+ if (currentObject.userData.modelId) {
+ Objects.add(currentObject);
+ break;
+ }
+ currentObject = currentObject.parent || null;
+ }
+ });
+
+ if (Objects.size === 0) {
+ clearSelection();
+ return;
+ }
+
+ const updatedSelections = new Set(selectedAssets);
+ Objects.forEach((obj) => { updatedSelections.has(obj) ? updatedSelections.delete(obj) : updatedSelections.add(obj); });
+
+ const selected = Array.from(updatedSelections);
+
+ setSelectedAssets(selected);
+ };
+
+ const clearSelection = () => {
+ selectionGroup.current.children = [];
+ selectionGroup.current.position.set(0, 0, 0);
+ selectionGroup.current.rotation.set(0, 0, 0);
+ setpastedObjects([]);
+ setDuplicatedObjects([]);
+ setSelectedAssets([]);
+ };
+
+ const deleteSelection = () => {
+ if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
+ const email = localStorage.getItem("email");
+ const organization = email!.split("@")[1].split(".")[0];
+
+ const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]");
+ const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
+
+ const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid));
+ localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
+
+ selectedAssets.forEach((selectedMesh: THREE.Object3D) => {
+ //REST
+
+ // const response = await deleteFloorItem(organization, selectedMesh.uuid, selectedMesh.userData.name);
+
+ //SOCKET
+
+ const data = {
+ organization: organization,
+ modeluuid: selectedMesh.uuid,
+ modelname: selectedMesh.userData.name,
+ socketId: socket.id,
+ };
+
+ socket.emit("v2:model-asset:delete", data);
+
+ selectedMesh.traverse((child: THREE.Object3D) => {
+ if (child instanceof THREE.Mesh) {
+ if (child.geometry) child.geometry.dispose();
+ if (Array.isArray(child.material)) {
+ child.material.forEach((material) => {
+ if (material.map) material.map.dispose();
+ material.dispose();
+ });
+ } else if (child.material) {
+ if (child.material.map) child.material.map.dispose();
+ child.material.dispose();
+ }
+ }
+ });
+
+ itemsGroupRef.current?.remove(selectedMesh);
+ });
+
+ const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid));
+ setFloorItems(updatedItems);
+ }
+ toast.success("Selected models removed!");
+ clearSelection();
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default SelectionControls;
diff --git a/app/src/modules/scene/controls/selection/selectionHelper.ts b/app/src/modules/scene/controls/selectionControls/selectionHelper.ts
similarity index 96%
rename from app/src/modules/scene/controls/selection/selectionHelper.ts
rename to app/src/modules/scene/controls/selectionControls/selectionHelper.ts
index ae37e67..c1acaf6 100644
--- a/app/src/modules/scene/controls/selection/selectionHelper.ts
+++ b/app/src/modules/scene/controls/selectionControls/selectionHelper.ts
@@ -1,115 +1,115 @@
-import { Vector2, WebGLRenderer } from 'three';
-
-class SelectionHelper {
- element: HTMLDivElement;
- renderer: WebGLRenderer;
- startPoint: Vector2;
- pointTopLeft: Vector2;
- pointBottomRight: Vector2;
- isDown: boolean;
- enabled: boolean;
-
- constructor(renderer: WebGLRenderer) {
- this.element = document.createElement('div');
- this.element.style.position = 'fixed';
- this.element.style.border = '1px solid #55aaff';
- this.element.style.backgroundColor = 'rgba(75, 160, 255, 0.3)';
- this.element.style.pointerEvents = 'none';
- this.element.style.display = 'none';
-
- this.renderer = renderer;
-
- this.startPoint = new Vector2();
- this.pointTopLeft = new Vector2();
- this.pointBottomRight = new Vector2();
-
- this.isDown = false;
- this.enabled = true;
-
- this.onPointerDown = this.onPointerDown.bind(this);
- this.onPointerMove = this.onPointerMove.bind(this);
- this.onPointerUp = this.onPointerUp.bind(this);
-
- this.renderer.domElement.addEventListener('pointerdown', this.onPointerDown);
- this.renderer.domElement.addEventListener('pointermove', this.onPointerMove);
- this.renderer.domElement.addEventListener('pointerup', this.onPointerUp);
- window.addEventListener("blur", this.cleanup.bind(this));
- }
-
- dispose() {
- this.enabled = false;
- this.isDown = false;
- this.cleanup();
-
- this.renderer.domElement.removeEventListener("pointerdown", this.onPointerDown);
- this.renderer.domElement.removeEventListener("pointermove", this.onPointerMove);
- this.renderer.domElement.removeEventListener("pointerup", this.onPointerUp);
- window.removeEventListener("blur", this.cleanup);
- }
-
- private cleanup() {
- this.isDown = false;
- this.element.style.display = 'none';
- if (this.element.parentElement) {
- this.element.parentElement.removeChild(this.element);
- }
- }
-
- onPointerDown(event: PointerEvent) {
- if (!this.enabled || !event.ctrlKey || event.button !== 0) return;
-
- this.isDown = true;
- this.onSelectStart(event);
- }
-
- onPointerMove(event: PointerEvent) {
- if (!this.enabled || !this.isDown || !event.ctrlKey) return;
-
- this.onSelectMove(event);
- }
-
- onPointerUp() {
- if (!this.enabled) return;
-
- this.isDown = false;
- this.onSelectOver();
- }
-
- onSelectStart(event: PointerEvent) {
- this.element.style.display = 'none';
- this.renderer.domElement.parentElement?.appendChild(this.element);
-
- this.element.style.left = `${event.clientX}px`;
- this.element.style.top = `${event.clientY}px`;
- this.element.style.width = '0px';
- this.element.style.height = '0px';
-
- this.startPoint.x = event.clientX;
- this.startPoint.y = event.clientY;
- }
-
- onSelectMove(event: PointerEvent) {
- if (!this.isDown) return;
-
- this.element.style.display = 'block';
-
- this.pointBottomRight.x = Math.max(this.startPoint.x, event.clientX);
- this.pointBottomRight.y = Math.max(this.startPoint.y, event.clientY);
- this.pointTopLeft.x = Math.min(this.startPoint.x, event.clientX);
- this.pointTopLeft.y = Math.min(this.startPoint.y, event.clientY);
-
- this.element.style.left = `${this.pointTopLeft.x}px`;
- this.element.style.top = `${this.pointTopLeft.y}px`;
- this.element.style.width = `${this.pointBottomRight.x - this.pointTopLeft.x}px`;
- this.element.style.height = `${this.pointBottomRight.y - this.pointTopLeft.y}px`;
- }
-
- onSelectOver() {
- this.element.style.display = 'none';
- if (this.element.parentElement) {
- this.element.parentElement.removeChild(this.element);
- }
- }
-}
-
+import { Vector2, WebGLRenderer } from 'three';
+
+class SelectionHelper {
+ element: HTMLDivElement;
+ renderer: WebGLRenderer;
+ startPoint: Vector2;
+ pointTopLeft: Vector2;
+ pointBottomRight: Vector2;
+ isDown: boolean;
+ enabled: boolean;
+
+ constructor(renderer: WebGLRenderer) {
+ this.element = document.createElement('div');
+ this.element.style.position = 'fixed';
+ this.element.style.border = '1px solid #55aaff';
+ this.element.style.backgroundColor = 'rgba(75, 160, 255, 0.3)';
+ this.element.style.pointerEvents = 'none';
+ this.element.style.display = 'none';
+
+ this.renderer = renderer;
+
+ this.startPoint = new Vector2();
+ this.pointTopLeft = new Vector2();
+ this.pointBottomRight = new Vector2();
+
+ this.isDown = false;
+ this.enabled = true;
+
+ this.onPointerDown = this.onPointerDown.bind(this);
+ this.onPointerMove = this.onPointerMove.bind(this);
+ this.onPointerUp = this.onPointerUp.bind(this);
+
+ this.renderer.domElement.addEventListener('pointerdown', this.onPointerDown);
+ this.renderer.domElement.addEventListener('pointermove', this.onPointerMove);
+ this.renderer.domElement.addEventListener('pointerup', this.onPointerUp);
+ window.addEventListener("blur", this.cleanup.bind(this));
+ }
+
+ dispose() {
+ this.enabled = false;
+ this.isDown = false;
+ this.cleanup();
+
+ this.renderer.domElement.removeEventListener("pointerdown", this.onPointerDown);
+ this.renderer.domElement.removeEventListener("pointermove", this.onPointerMove);
+ this.renderer.domElement.removeEventListener("pointerup", this.onPointerUp);
+ window.removeEventListener("blur", this.cleanup);
+ }
+
+ private cleanup() {
+ this.isDown = false;
+ this.element.style.display = 'none';
+ if (this.element.parentElement) {
+ this.element.parentElement.removeChild(this.element);
+ }
+ }
+
+ onPointerDown(event: PointerEvent) {
+ if (!this.enabled || !event.ctrlKey || event.button !== 0) return;
+
+ this.isDown = true;
+ this.onSelectStart(event);
+ }
+
+ onPointerMove(event: PointerEvent) {
+ if (!this.enabled || !this.isDown || !event.ctrlKey) return;
+
+ this.onSelectMove(event);
+ }
+
+ onPointerUp() {
+ if (!this.enabled) return;
+
+ this.isDown = false;
+ this.onSelectOver();
+ }
+
+ onSelectStart(event: PointerEvent) {
+ this.element.style.display = 'none';
+ this.renderer.domElement.parentElement?.appendChild(this.element);
+
+ this.element.style.left = `${event.clientX}px`;
+ this.element.style.top = `${event.clientY}px`;
+ this.element.style.width = '0px';
+ this.element.style.height = '0px';
+
+ this.startPoint.x = event.clientX;
+ this.startPoint.y = event.clientY;
+ }
+
+ onSelectMove(event: PointerEvent) {
+ if (!this.isDown) return;
+
+ this.element.style.display = 'block';
+
+ this.pointBottomRight.x = Math.max(this.startPoint.x, event.clientX);
+ this.pointBottomRight.y = Math.max(this.startPoint.y, event.clientY);
+ this.pointTopLeft.x = Math.min(this.startPoint.x, event.clientX);
+ this.pointTopLeft.y = Math.min(this.startPoint.y, event.clientY);
+
+ this.element.style.left = `${this.pointTopLeft.x}px`;
+ this.element.style.top = `${this.pointTopLeft.y}px`;
+ this.element.style.width = `${this.pointBottomRight.x - this.pointTopLeft.x}px`;
+ this.element.style.height = `${this.pointBottomRight.y - this.pointTopLeft.y}px`;
+ }
+
+ onSelectOver() {
+ this.element.style.display = 'none';
+ if (this.element.parentElement) {
+ this.element.parentElement.removeChild(this.element);
+ }
+ }
+}
+
export { SelectionHelper };
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/transformControls.tsx b/app/src/modules/scene/controls/transformControls.tsx
deleted file mode 100644
index 2e586cc..0000000
--- a/app/src/modules/scene/controls/transformControls.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-import { TransformControls } from "@react-three/drei";
-import * as THREE from "three";
-import { useSelectedFloorItem, useObjectPosition, useObjectScale, useObjectRotation, useTransformMode, useFloorItems, useSocketStore, useActiveTool } from "../../../store/store";
-import { useThree } from "@react-three/fiber";
-
-import * as Types from '../../../types/world/worldTypes';
-import { useEffect } from "react";
-
-export default function TransformControl() {
- const state = useThree();
- const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
- const { objectPosition, setObjectPosition } = useObjectPosition();
- const { objectScale, setObjectScale } = useObjectScale();
- const { objectRotation, setObjectRotation } = useObjectRotation();
- const { transformMode, setTransformMode } = useTransformMode();
- const { floorItems, setFloorItems } = useFloorItems();
- const { activeTool, setActiveTool } = useActiveTool();
- const { socket } = useSocketStore();
-
- function handleObjectChange() {
- if (selectedFloorItem && transformMode) {
- setObjectPosition(selectedFloorItem.position);
- setObjectScale(selectedFloorItem.scale);
- setObjectRotation({
- x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x),
- y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y),
- z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z),
- });
- }
- }
- function handleMouseUp() {
- if (selectedFloorItem) {
- setObjectPosition(selectedFloorItem.position);
- setObjectScale(selectedFloorItem.scale);
- setObjectRotation({
- x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x),
- y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y),
- z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z),
- });
- }
- setFloorItems((prevItems: Types.FloorItems) => {
- if (!prevItems) {
- return
- }
- let updatedItem: any = null;
- const updatedItems = prevItems.map((item) => {
- if (item.modeluuid === selectedFloorItem?.uuid) {
- updatedItem = {
- ...item,
- position: [selectedFloorItem.position.x, selectedFloorItem.position.y, selectedFloorItem.position.z,] as [number, number, number],
- rotation: { x: selectedFloorItem.rotation.x, y: selectedFloorItem.rotation.y, z: selectedFloorItem.rotation.z, },
- };
- return updatedItem;
- }
- return item;
- });
- if (updatedItem && selectedFloorItem) {
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- //REST
-
- // setFloorItemApi(
- // organization,
- // updatedItem.modeluuid,
- // updatedItem.modelname,
- // [selectedFloorItem.position.x, selectedFloorItem.position.y, selectedFloorItem.position.z,],
- // { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z },
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization: organization,
- modeluuid: updatedItem.modeluuid,
- modelname: updatedItem.modelname,
- position: [selectedFloorItem.position.x, selectedFloorItem.position.y, selectedFloorItem.position.z],
- rotation: { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id
- }
-
- socket.emit('v2:model-asset:add', data);
- }
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
- }
-
- useEffect(() => {
- if (activeTool === "Add pillar" || activeTool === "Delete") {
- if (state.controls) {
- const target = (state.controls as any).getTarget(new THREE.Vector3());
- (state.controls as any).setTarget(target.x, 0, target.z, true);
- }
- setSelectedFloorItem(null);
- {
- setObjectPosition({ x: undefined, y: undefined, z: undefined });
- setObjectScale({ x: undefined, y: undefined, z: undefined });
- setObjectRotation({ x: undefined, y: undefined, z: undefined });
- }
- }
- }, [activeTool]);
-
- return (
- <>
- {(selectedFloorItem && transformMode) &&
-
- }
- >
- );
-}
diff --git a/app/src/modules/scene/environment/sky.tsx b/app/src/modules/scene/environment/sky.tsx
index 3be57ce..dbfda22 100644
--- a/app/src/modules/scene/environment/sky.tsx
+++ b/app/src/modules/scene/environment/sky.tsx
@@ -5,6 +5,7 @@ import { useEffect, useRef, useState } from "react";
import * as CONSTANTS from '../../../types/world/worldConstants';
export default function Sun() {
+ const savedTheme: string | null = localStorage.getItem("theme");
const { elevation, setElevation } = useElevation();
const { sunPosition, setSunPosition } = useSunPosition();
const { azimuth, setAzimuth } = useAzimuth();
@@ -28,7 +29,7 @@ export default function Sun() {
return (
<>
- {(azimuth !== undefined && elevation !== undefined) && (
+ {(azimuth !== undefined && elevation !== undefined && savedTheme !== "dark") && (
<>
)}
- {selectedActionSphere && (
-
- )}
- {selectedPath && (
-
- )}
>
);
diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx
index 941616c..6564032 100644
--- a/app/src/modules/scene/scene.tsx
+++ b/app/src/modules/scene/scene.tsx
@@ -1,63 +1,36 @@
import { useMemo } from "react";
import { Canvas } from "@react-three/fiber";
-import { Environment, KeyboardControls, Stars } from "@react-three/drei";
+import { KeyboardControls } from "@react-three/drei";
-import World from "./world/world";
-import Controls from "./controls/controls";
-import TransformControl from "./controls/transformControls";
-import PostProcessing from "./postProcessing/postProcessing";
-import Sun from "./environment/sky";
-import CamModelsGroup from "../collaboration/collabCams";
-import Shadows from "./environment/shadow";
-import MqttEvents from "../../services/factoryBuilder/mqtt/mqttEvents";
-
-import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr";
-import SelectionControls from "./controls/selection/selectionControls";
-import MeasurementTool from "./tools/measurementTool";
+import Builder from "../builder/builder";
+import Visualization from "../visualization/visualization";
+import Setup from "./setup/setup";
import Simulation from "../simulation/simulation";
-
-// import Simulation from "./simulationtemp/simulation";
-import ZoneCentreTarget from "../visualization/functions/zoneCameraTarget";
-import Dropped3dWidgets from "../../modules/visualization/widgets/3d/Dropped3dWidget";
-import ZoneAssets from "../visualization/zoneAssets";
+import Collaboration from "../collaboration/collaboration";
export default function Scene() {
- const map = useMemo(
- () => [
- { name: "forward", keys: ["ArrowUp", "w", "W"] },
- { name: "backward", keys: ["ArrowDown", "s", "S"] },
- { name: "left", keys: ["ArrowLeft", "a", "A"] },
- { name: "right", keys: ["ArrowRight", "d", "D"] },
- ],
- []
- );
- const savedTheme: string | null = localStorage.getItem("theme");
+ const map = useMemo(() => [
+ { name: "forward", keys: ["ArrowUp", "w", "W"] },
+ { name: "backward", keys: ["ArrowDown", "s", "S"] },
+ { name: "left", keys: ["ArrowLeft", "a", "A"] },
+ { name: "right", keys: ["ArrowRight", "d", "D"] },],
+ []);
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
diff --git a/app/src/modules/scene/setup/setup.tsx b/app/src/modules/scene/setup/setup.tsx
new file mode 100644
index 0000000..34289f9
--- /dev/null
+++ b/app/src/modules/scene/setup/setup.tsx
@@ -0,0 +1,25 @@
+import Sun from '../environment/sky'
+import Shadows from '../environment/shadow'
+import PostProcessing from '../postProcessing/postProcessing'
+import Controls from '../controls/controls';
+import { Environment } from '@react-three/drei'
+
+import background from "../../../assets/hdr/mudroadpuresky2k.hdr";
+
+function Setup() {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
+export default Setup
\ No newline at end of file
diff --git a/app/src/modules/scene/tools/measurementTool.tsx b/app/src/modules/scene/tools/measurementTool.tsx
index 9f9fa03..9a30da3 100644
--- a/app/src/modules/scene/tools/measurementTool.tsx
+++ b/app/src/modules/scene/tools/measurementTool.tsx
@@ -5,240 +5,225 @@ import { useToolMode } from "../../../store/store";
import { Html } from "@react-three/drei";
const MeasurementTool = () => {
- const { gl, raycaster, pointer, camera, scene } = useThree();
- const { toolMode } = useToolMode();
+ const { gl, raycaster, pointer, camera, scene } = useThree();
+ const { toolMode } = useToolMode();
- const [points, setPoints] = useState([]);
- const [tubeGeometry, setTubeGeometry] = useState(
- null
- );
- const groupRef = useRef(null);
- const [startConePosition, setStartConePosition] =
- useState(null);
- const [endConePosition, setEndConePosition] = useState(
- null
- );
- const [startConeQuaternion, setStartConeQuaternion] = useState(
- new THREE.Quaternion()
- );
- const [endConeQuaternion, setEndConeQuaternion] = useState(
- new THREE.Quaternion()
- );
- const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
+ const [points, setPoints] = useState([]);
+ const [tubeGeometry, setTubeGeometry] = useState(
+ null
+ );
+ const groupRef = useRef(null);
+ const [startConePosition, setStartConePosition] =
+ useState(null);
+ const [endConePosition, setEndConePosition] = useState(
+ null
+ );
+ const [startConeQuaternion, setStartConeQuaternion] = useState(
+ new THREE.Quaternion()
+ );
+ const [endConeQuaternion, setEndConeQuaternion] = useState(
+ new THREE.Quaternion()
+ );
+ const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
- const MIN_RADIUS = 0.001,
- MAX_RADIUS = 0.1;
- const MIN_CONE_RADIUS = 0.01,
- MAX_CONE_RADIUS = 0.4;
- const MIN_CONE_HEIGHT = 0.035,
- MAX_CONE_HEIGHT = 2.0;
+ const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1;
+ const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4;
+ const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0;
- useEffect(() => {
- const canvasElement = gl.domElement;
- let drag = false;
- let isLeftMouseDown = false;
+ useEffect(() => {
+ const canvasElement = gl.domElement;
+ let drag = false;
+ let isLeftMouseDown = false;
- const onMouseDown = () => {
- isLeftMouseDown = true;
- drag = false;
- };
+ const onMouseDown = () => {
+ isLeftMouseDown = true;
+ drag = false;
+ };
- const onMouseUp = (evt: any) => {
- isLeftMouseDown = false;
- if (evt.button === 0 && !drag) {
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster
- .intersectObjects(scene.children, true)
- .filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.name.includes("agv-collider") &&
- !(intersect.object.type === "GridHelper")
- );
+ const onMouseUp = (evt: any) => {
+ isLeftMouseDown = false;
+ if (evt.button === 0 && !drag) {
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster
+ .intersectObjects(scene.children, true)
+ .filter(
+ (intersect) =>
+ !intersect.object.name.includes("Roof") &&
+ !intersect.object.name.includes("MeasurementReference") &&
+ !intersect.object.name.includes("agv-collider") &&
+ !(intersect.object.type === "GridHelper")
+ );
- if (intersects.length > 0) {
- const intersectionPoint = intersects[0].point.clone();
- if (points.length < 2) {
- setPoints([...points, intersectionPoint]);
- } else {
- setPoints([intersectionPoint]);
- }
+ if (intersects.length > 0) {
+ const intersectionPoint = intersects[0].point.clone();
+ if (points.length < 2) {
+ setPoints([...points, intersectionPoint]);
+ } else {
+ setPoints([intersectionPoint]);
+ }
+ }
+ }
+ };
+
+ const onMouseMove = () => {
+ if (isLeftMouseDown) drag = true;
+ };
+
+ const onContextMenu = (evt: any) => {
+ evt.preventDefault();
+ if (!drag) {
+ evt.preventDefault();
+ setPoints([]);
+ setTubeGeometry(null);
+ }
+ };
+
+ if (toolMode === "MeasurementScale") {
+ canvasElement.addEventListener("pointerdown", onMouseDown);
+ canvasElement.addEventListener("pointermove", onMouseMove);
+ canvasElement.addEventListener("pointerup", onMouseUp);
+ canvasElement.addEventListener("contextmenu", onContextMenu);
+ } else {
+ resetMeasurement();
+ setPoints([]);
}
- }
+
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onMouseDown);
+ canvasElement.removeEventListener("pointermove", onMouseMove);
+ canvasElement.removeEventListener("pointerup", onMouseUp);
+ canvasElement.removeEventListener("contextmenu", onContextMenu);
+ };
+ }, [toolMode, camera, raycaster, pointer, scene, points]);
+
+ useFrame(() => {
+ if (points.length === 1) {
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster
+ .intersectObjects(scene.children, true)
+ .filter(
+ (intersect) =>
+ !intersect.object.name.includes("Roof") &&
+ !intersect.object.name.includes("MeasurementReference") &&
+ !intersect.object.name.includes("agv-collider") &&
+ !(intersect.object.type === "GridHelper")
+ );
+
+ if (intersects.length > 0) {
+ updateMeasurement(points[0], intersects[0].point);
+ }
+ } else if (points.length === 2) {
+ updateMeasurement(points[0], points[1]);
+ } else {
+ resetMeasurement();
+ }
+ });
+
+ const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
+ const distance = start.distanceTo(end);
+
+ const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS);
+ const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS);
+ const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT);
+
+ setConeSize({ radius: coneRadius, height: coneHeight });
+
+ const direction = new THREE.Vector3().subVectors(end, start).normalize();
+
+ const offset = direction.clone().multiplyScalar(coneHeight * 0.5);
+
+ let tubeStart = start.clone().add(offset);
+ let tubeEnd = end.clone().sub(offset);
+
+ tubeStart.y = Math.max(tubeStart.y, 0);
+ tubeEnd.y = Math.max(tubeEnd.y, 0);
+
+ const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
+ setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));
+
+ setStartConePosition(tubeStart);
+ setEndConePosition(tubeEnd);
+ setStartConeQuaternion(getArrowOrientation(start, end));
+ setEndConeQuaternion(getArrowOrientation(end, start));
};
- const onMouseMove = () => {
- if (isLeftMouseDown) drag = true;
- };
-
- const onContextMenu = (evt: any) => {
- evt.preventDefault();
- if (!drag) {
- evt.preventDefault();
- setPoints([]);
+ const resetMeasurement = () => {
setTubeGeometry(null);
- }
+ setStartConePosition(null);
+ setEndConePosition(null);
};
- if (toolMode === "MeasurementScale") {
- canvasElement.addEventListener("pointerdown", onMouseDown);
- canvasElement.addEventListener("pointermove", onMouseMove);
- canvasElement.addEventListener("pointerup", onMouseUp);
- canvasElement.addEventListener("contextmenu", onContextMenu);
- } else {
- resetMeasurement();
- setPoints([]);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onMouseDown);
- canvasElement.removeEventListener("pointermove", onMouseMove);
- canvasElement.removeEventListener("pointerup", onMouseUp);
- canvasElement.removeEventListener("contextmenu", onContextMenu);
+ const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
+ const direction = new THREE.Vector3()
+ .subVectors(end, start)
+ .normalize()
+ .negate();
+ const quaternion = new THREE.Quaternion();
+ quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
+ return quaternion;
};
- }, [toolMode, camera, raycaster, pointer, scene, points]);
- useFrame(() => {
- if (points.length === 1) {
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster
- .intersectObjects(scene.children, true)
- .filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.name.includes("agv-collider") &&
- !(intersect.object.type === "GridHelper")
- );
+ useEffect(() => {
+ if (points.length === 2) {
+ // console.log(points[0].distanceTo(points[1]));
+ }
+ }, [points]);
- if (intersects.length > 0) {
- updateMeasurement(points[0], intersects[0].point);
- }
- } else if (points.length === 2) {
- updateMeasurement(points[0], points[1]);
- } else {
- resetMeasurement();
- }
- });
+ return (
+
+ {startConePosition && (
+
+
+
+
+ )}
+ {endConePosition && (
+
+
+
+
+ )}
+ {tubeGeometry && (
+
+
+
+ )}
- const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
- const distance = start.distanceTo(end);
-
- const radius = THREE.MathUtils.clamp(
- distance * 0.02,
- MIN_RADIUS,
- MAX_RADIUS
+ {startConePosition && endConePosition && (
+
+
+ {startConePosition.distanceTo(endConePosition).toFixed(2)} m
+
+
+ )}
+
);
- const coneRadius = THREE.MathUtils.clamp(
- distance * 0.05,
- MIN_CONE_RADIUS,
- MAX_CONE_RADIUS
- );
- const coneHeight = THREE.MathUtils.clamp(
- distance * 0.2,
- MIN_CONE_HEIGHT,
- MAX_CONE_HEIGHT
- );
-
- setConeSize({ radius: coneRadius, height: coneHeight });
-
- const direction = new THREE.Vector3().subVectors(end, start).normalize();
-
- const offset = direction.clone().multiplyScalar(coneHeight * 0.5);
-
- let tubeStart = start.clone().add(offset);
- let tubeEnd = end.clone().sub(offset);
-
- tubeStart.y = Math.max(tubeStart.y, 0);
- tubeEnd.y = Math.max(tubeEnd.y, 0);
-
- const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
- setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));
-
- setStartConePosition(tubeStart);
- setEndConePosition(tubeEnd);
- setStartConeQuaternion(getArrowOrientation(start, end));
- setEndConeQuaternion(getArrowOrientation(end, start));
- };
-
- const resetMeasurement = () => {
- setTubeGeometry(null);
- setStartConePosition(null);
- setEndConePosition(null);
- };
-
- const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
- const direction = new THREE.Vector3()
- .subVectors(end, start)
- .normalize()
- .negate();
- const quaternion = new THREE.Quaternion();
- quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
- return quaternion;
- };
-
- useEffect(() => {
- if (points.length === 2) {
- console.log(points[0].distanceTo(points[1]));
- }
- }, [points]);
-
- return (
-
- {startConePosition && (
-
-
-
-
- )}
- {endConePosition && (
-
-
-
-
- )}
- {tubeGeometry && (
-
-
-
- )}
-
- {startConePosition && endConePosition && (
-
-
- {startConePosition.distanceTo(endConePosition).toFixed(2)} m
-
-
- )}
-
- );
};
export default MeasurementTool;
diff --git a/app/src/modules/scene/world/world.tsx b/app/src/modules/scene/world/world.tsx
deleted file mode 100644
index dcd1adb..0000000
--- a/app/src/modules/scene/world/world.tsx
+++ /dev/null
@@ -1,374 +0,0 @@
-////////// Three and React Three Fiber Imports //////////
-
-import * as THREE from "three";
-import { useEffect, useRef, useState } from "react";
-import { useThree, useFrame } from "@react-three/fiber";
-
-////////// Component Imports //////////
-
-import DistanceText from "../../builder/geomentries/lines/distanceText/distanceText";
-import ReferenceDistanceText from "../../builder/geomentries/lines/distanceText/referenceDistanceText";
-
-////////// Assests Imports //////////
-
-import arch from "../../../assets/gltf-glb/arch.glb";
-import door from "../../../assets/gltf-glb/door.glb";
-import Window from "../../../assets/gltf-glb/window.glb";
-
-////////// Zustand State Imports //////////
-
-import {
- useToggleView,
- useDeletePointOrLine,
- useMovePoint,
- useActiveLayer,
- useSocketStore,
- useWallVisibility,
- useRoofVisibility,
- useShadows,
- useUpdateScene,
- useWalls,
- useToolMode,
- useRefTextUpdate,
- useRenderDistance,
- useLimitDistance,
-} from "../../../store/store";
-
-////////// 3D Function Imports //////////
-
-import loadWalls from "../../builder/geomentries/walls/loadWalls";
-
-import * as Types from "../../../types/world/worldTypes";
-
-import SocketResponses from "../../collaboration/socketResponses.dev";
-import FloorItemsGroup from "../../builder/groups/floorItemsGroup";
-import FloorPlanGroup from "../../builder/groups/floorPlanGroup";
-import FloorGroup from "../../builder/groups/floorGroup";
-import FloorGroupAilse from "../../builder/groups/floorGroupAisle";
-import Draw from "../../builder/functions/draw";
-import WallsAndWallItems from "../../builder/groups/wallsAndWallItems";
-import Ground from "../environment/ground";
-// import ZoneGroup from "../groups/zoneGroup1";
-import { findEnvironment } from "../../../services/factoryBuilder/environment/findEnvironment";
-import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
-import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp";
-import ZoneGroup from "../../builder/groups/zoneGroup";
-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.
- const csg = useRef(); // Reference for CSG object, used for 3D modeling.
- const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
- const scene = useRef() as Types.RefScene; // Reference to the scene.
- const camera = useRef() as Types.RefCamera; // Reference to the camera object.
- const controls = useRef(); // Reference to the controls object.
- const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
- const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
-
- // Assigning the scene and camera from the Three.js state to the references.
-
- scene.current = state.scene;
- camera.current = state.camera;
- controls.current = state.controls;
- raycaster.current = state.raycaster;
-
- const plane = useRef(null); // Reference for a plane object for raycaster reference.
- const grid = useRef() as any; // Reference for a grid object for raycaster reference.
- const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
- const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
- const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
- const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
- const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
- const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
- const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
- const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
- const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
- const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
- const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
- const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
- const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn.
- const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
- const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
- const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
- const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
- const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
- const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
- const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
- const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
- const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
- const floorGroupAisle = useRef() as Types.RefGroup;
- const zoneGroup = useRef() as Types.RefGroup;
- const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
- const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
- const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
- const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
- const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
- const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
- const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
-
- const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
-
- const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item.
- const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
- const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
- const { toolMode, setToolMode } = useToolMode();
- const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
- const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
- const { socket } = useSocketStore();
- const { roofVisibility, setRoofVisibility } = useRoofVisibility();
- const { wallVisibility, setWallVisibility } = useWallVisibility();
- const { shadows, setShadows } = useShadows();
- const { renderDistance, setRenderDistance } = useRenderDistance();
- const { limitDistance, setLimitDistance } = useLimitDistance();
- const { updateScene, setUpdateScene } = useUpdateScene();
- const { walls, setWalls } = useWalls();
- const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
- const { activeModule } = useModuleStore();
-
- // const loader = new GLTFLoader();
- // const dracoLoader = new DRACOLoader();
-
- // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
- // loader.setDRACOLoader(dracoLoader);
-
- ////////// Assest Configuration Values //////////
-
- const AssetConfigurations: Types.AssetConfigurations = {
- arch: {
- modelUrl: arch,
- scale: [0.75, 0.75, 0.75],
- csgscale: [2, 4, 0.5],
- csgposition: [0, 2, 0],
- positionY: () => 0,
- type: "Fixed-Move",
- },
- door: {
- modelUrl: door,
- scale: [0.75, 0.75, 0.75],
- csgscale: [2, 4, 0.5],
- csgposition: [0, 2, 0],
- positionY: () => 0,
- type: "Fixed-Move",
- },
- window: {
- modelUrl: Window,
- scale: [0.75, 0.75, 0.75],
- csgscale: [5, 3, 0.5],
- csgposition: [0, 1.5, 0],
- positionY: (intersectionPoint) => intersectionPoint.point.y,
- type: "Free-Move",
- },
- };
-
- ////////// All Toggle's //////////
-
- useEffect(() => {
- setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
- if (dragPointControls.current) {
- dragPointControls.current.enabled = false;
- }
- if (toggleView) {
- Layer2DVisibility(
- activeLayer,
- floorPlanGroup,
- floorPlanGroupLine,
- floorPlanGroupPoint,
- currentLayerPoint,
- dragPointControls
- );
- } else {
- setToolMode(null);
- setDeletePointOrLine(false);
- setMovePoint(false);
- loadWalls(lines, setWalls);
- setUpdateScene(true);
- line.current = [];
- }
- }, [toggleView]);
-
- useEffect(() => {
- THREE.Cache.clear();
- THREE.Cache.enabled = true;
- }, []);
-
- useEffect(() => {
- const email = localStorage.getItem("email");
- const organization = email!.split("@")[1].split(".")[0];
-
- async function fetchVisibility() {
- const visibility = await findEnvironment(
- organization,
- localStorage.getItem("userId")!
- );
- if (visibility) {
- setRoofVisibility(visibility.roofVisibility);
- setWallVisibility(visibility.wallVisibility);
- setShadows(visibility.shadowVisibility);
- setRenderDistance(visibility.renderDistance);
- setLimitDistance(visibility.limitDistance);
- }
- }
- fetchVisibility();
- }, []);
-
- ////////// UseFrame is Here //////////
-
- useFrame(() => {
- if (toolMode) {
- Draw(
- state,
- plane,
- cursorPosition,
- floorPlanGroupPoint,
- floorPlanGroupLine,
- snappedPoint,
- isSnapped,
- isSnappedUUID,
- line,
- lines,
- ispreSnapped,
- floorPlanGroup,
- ReferenceLineMesh,
- LineCreated,
- setRefTextUpdate,
- Tube,
- anglesnappedPoint,
- isAngleSnapped,
- toolMode
- );
- }
- });
-
- ////////// Return //////////
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* */}
-
-
-
-
-
- {/* */}
-
-
-
- >
- );
-}
diff --git a/app/src/modules/builder/temp.md b/app/src/modules/simulation/actions/temp.md
similarity index 100%
rename from app/src/modules/builder/temp.md
rename to app/src/modules/simulation/actions/temp.md
diff --git a/app/src/modules/simulation/armbot/ArmBot.tsx b/app/src/modules/simulation/armbot/ArmBot.tsx
deleted file mode 100644
index 066779a..0000000
--- a/app/src/modules/simulation/armbot/ArmBot.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { useThree } from "@react-three/fiber";
-import useModuleStore from "../../../store/useModuleStore";
-import { useSimulationStates } from "../../../store/store";
-import * as SimulationTypes from '../../../types/simulationTypes';
-import { ArmbotInstances } from "./ArmBotInstances";
-import { useResetButtonStore } from "../../../store/usePlayButtonStore";
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-
-interface StaticMachineState {
- uuid: string;
- status: string;
- actions: { uuid: string; name: string; buffer: number; material: string; };
- machineTriggerId: string;
- connectedArmBot: string;
-}
-
-interface ArmBotProps {
- armBots: ArmBotState[];
- setArmBots: React.Dispatch>;
- setStaticMachines: React.Dispatch>;
-}
-
-const ArmBot = ({ armBots, setArmBots, setStaticMachines }: ArmBotProps) => {
- const { activeModule } = useModuleStore();
- const { scene } = useThree();
- const { simulationStates } = useSimulationStates();
- const { isReset } = useResetButtonStore();
-
- useEffect(() => {
- const filtered = simulationStates.filter((s): s is SimulationTypes.ArmBotEventsSchema => s.type === "ArmBot");
- const initialStates: ArmBotState[] = filtered
- .filter(bot => bot.points.connections.targets.length > 0)
- .map(bot => ({
- uuid: bot.modeluuid,
- position: bot.position,
- rotation: bot.rotation,
- status: "idle",
- material: "default",
- triggerId: '',
- actions: bot.points.actions,
- connections: bot.points.connections,
- isActive: false
- }));
- setArmBots(initialStates);
- }, [simulationStates, isReset]);
-
- useEffect(() => {
- armBots.forEach((bot) => {
- const object = scene.getObjectByProperty("uuid", bot.uuid);
- if (object) {
- object.visible = activeModule !== "simulation";
- }
- });
- }, [scene, activeModule, armBots]);
-
- return (
- <>
- {activeModule === "simulation" &&
- armBots.map((bot, i) => (
-
- ))}
- >
- );
-};
-
-export default ArmBot;
diff --git a/app/src/modules/simulation/armbot/ArmBotInstances.tsx b/app/src/modules/simulation/armbot/ArmBotInstances.tsx
deleted file mode 100644
index a0657db..0000000
--- a/app/src/modules/simulation/armbot/ArmBotInstances.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import IkInstances from "./IkInstances";
-import armModel from "../../../assets/gltf-glb/rigged/ik_arm_4.glb";
-import { useEffect, useState } from "react";
-import { useThree } from "@react-three/fiber";
-import { Vector3 } from "three";
-
-interface Process {
- triggerId: string;
- startPoint?: Vector3;
- endPoint?: Vector3;
- speed: number;
-}
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-
-interface StaticMachineState {
- uuid: string;
- status: string;
- actions: { uuid: string; name: string; buffer: number; material: string; };
- machineTriggerId: string;
- connectedArmBot: string;
-}
-
-interface ArmbotInstancesProps {
- index: number;
- armBot: ArmBotState;
- setArmBots: React.Dispatch>;
- setStaticMachines: React.Dispatch>;
-}
-
-export const ArmbotInstances: React.FC = ({ index, armBot, setArmBots, setStaticMachines }) => {
- const { scene } = useThree();
- const [processes, setProcesses] = useState([]);
-
- useEffect(() => {
- if (armBot.actions.processes.length > 0) {
- const mappedProcesses = armBot.actions.processes.map((process) => {
- return {
- triggerId: process.triggerId,
- startPoint: scene.getObjectByProperty('uuid', process.startPoint)?.getWorldPosition(new Vector3()),
- endPoint: scene.getObjectByProperty('uuid', process.endPoint)?.getWorldPosition(new Vector3()),
- speed: armBot.actions.speed
- };
- });
- setProcesses(mappedProcesses);
- } else {
- setProcesses([]);
- }
- }, [armBot, scene]);
-
- const updateArmBotStatus = (status: string) => {
- setArmBots((prevArmBots) => {
- return prevArmBots.map(bot => {
- if (bot.uuid === armBot.uuid) {
- return { ...bot, status, triggerId: status === 'idle' ? '' : armBot.triggerId };
- }
- return bot;
- });
- });
- };
-
- return (
-
- );
-};
\ No newline at end of file
diff --git a/app/src/modules/simulation/armbot/IKAnimationController.tsx b/app/src/modules/simulation/armbot/IKAnimationController.tsx
deleted file mode 100644
index e2df7f5..0000000
--- a/app/src/modules/simulation/armbot/IKAnimationController.tsx
+++ /dev/null
@@ -1,379 +0,0 @@
-import { useEffect, useMemo, useState, useRef } from "react";
-import { useFrame } from "@react-three/fiber";
-import * as THREE from "three";
-import { usePlayButtonStore, useResetButtonStore } from "../../../store/usePlayButtonStore";
-import { useSimulationStates } from "../../../store/store";
-import MaterialInstances from "./MaterialInstances";
-import { Line } from "react-chartjs-2";
-import { QuadraticBezierLine } from "@react-three/drei";
-
-
-interface StaticMachineState {
- uuid: string;
- status: string;
- actions: { uuid: string; name: string; buffer: number; material: string; };
- machineTriggerId: string;
- connectedArmBot: string;
-}
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-
-type IKAnimationControllerProps = {
- ikSolver: any;
- processes: {
- triggerId: string;
- startPoint: THREE.Vector3;
- endPoint: THREE.Vector3;
- speed: number;
- }[];
- selectedTrigger: string;
- targetBoneName: string;
- uuid: string;
- logStatus: (status: string) => void;
- groupRef: React.RefObject;
- armBot: ArmBotState;
- setArmBots: React.Dispatch>;
- setStaticMachines: React.Dispatch>;
- updateArmBotStatus: (status: string) => void;
-}
-
-const IKAnimationController = ({
- ikSolver,
- processes,
- selectedTrigger,
- targetBoneName,
- uuid,
- logStatus,
- groupRef,
- armBot,
- setArmBots,
- setStaticMachines,
- updateArmBotStatus
-}: IKAnimationControllerProps) => {
- const [progress, setProgress] = useState(0);
- const [initialProgress, setInitialProgress] = useState(0);
- const [needsInitialMovement, setNeedsInitialMovement] = useState(true);
- const [isInitializing, setIsInitializing] = useState(true);
- const restSpeed = 0.1;
- const restPosition = new THREE.Vector3(0, 2, 1.6);
- const { isPlaying } = usePlayButtonStore();;
- const statusRef = useRef("idle");
- const { simulationStates } = useSimulationStates();
- const { isReset } = useResetButtonStore();
-
- const initialCurveRef = useRef(null);
- const initialStartPositionRef = useRef(null);
-
- useEffect(() => {
- setProgress(0);
- }, [selectedTrigger]);
-
- useEffect(() => {
- setProgress(0);
- setNeedsInitialMovement(true);
- setInitialProgress(0);
- setIsInitializing(true);
- }, [isReset]);
-
- useEffect(() => {
- if (ikSolver) {
- const targetBone = ikSolver.mesh.skeleton.bones.find(
- (b: any) => b.name === targetBoneName
- );
- if (targetBone) {
- initialStartPositionRef.current = targetBone.position.clone();
- calculateInitialCurve(targetBone.position);
- logStatus(`[Arm ${uuid}] Initializing IK system, starting position: ${targetBone.position.toArray()}`);
- }
- }
- }, [ikSolver]);
-
-
- const calculateInitialCurve = (startPosition: THREE.Vector3) => {
- const direction = new THREE.Vector3().subVectors(restPosition, startPosition);
- const distance = direction.length();
- direction.normalize();
-
- const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
-
- const midHeight = 0.5;
- const tiltAmount = 1;
- const mid = new THREE.Vector3()
- .addVectors(startPosition, restPosition)
- .multiplyScalar(0.5)
- .add(perpendicular.clone().multiplyScalar(distance * 0.3 * tiltAmount))
- .add(new THREE.Vector3(0, midHeight, 0));
-
- initialCurveRef.current = new THREE.CatmullRomCurve3([
- startPosition,
- new THREE.Vector3().lerpVectors(startPosition, mid, 0.33),
- mid,
- new THREE.Vector3().lerpVectors(mid, restPosition, 0.66),
- restPosition
- ]);
- };
-
- const processedCurves = useMemo(() => {
- if (!isPlaying) return [];
-
- return processes.map(process => {
- const localStart = groupRef.current?.worldToLocal(process.startPoint.clone());
- const localEnd = groupRef.current?.worldToLocal(process.endPoint.clone());
-
- if (!localStart || !localEnd) return null;
-
- const midPoint = new THREE.Vector3(
- (localStart.x + localEnd.x) / 2,
- Math.max(localStart.y, localEnd.y) + 1,
- (localStart.z + localEnd.z) / 2
- );
- const restToStartCurve = new THREE.CatmullRomCurve3([
- restPosition,
- new THREE.Vector3().lerpVectors(restPosition, localStart, 0.5),
- localStart
- ]);
-
- const processCurve = new THREE.CatmullRomCurve3([
- localStart,
- midPoint,
- localEnd
- ]);
-
- const endToRestCurve = new THREE.CatmullRomCurve3([
- localEnd,
- new THREE.Vector3().lerpVectors(localEnd, restPosition, 0.5),
- restPosition
- ]);
-
- return {
- triggerId: process.triggerId,
- restToStartCurve,
- processCurve,
- endToRestCurve,
- speed: process.speed,
- totalDistance:
- restPosition.distanceTo(localStart) +
- localStart.distanceTo(localEnd) +
- localEnd.distanceTo(restPosition)
- };
- }).filter(Boolean);
- }, [processes, isPlaying]);
-
- const activeProcess = useMemo(() => {
- if (!selectedTrigger) return null;
- return processedCurves.find(p => p?.triggerId === selectedTrigger);
- }, [processedCurves, selectedTrigger]);
-
- // Initial movement to rest position
- useFrame((_, delta) => {
- if (!ikSolver || !needsInitialMovement || !isInitializing || !initialCurveRef.current) return;
-
- const targetBone = ikSolver.mesh.skeleton.bones.find(
- (b: any) => b.name === targetBoneName
- );
- if (!targetBone) return;
-
- setInitialProgress((prev) => {
- const next = prev + delta * 0.5;
- if (next >= 1) {
- targetBone.position.copy(restPosition);
- setNeedsInitialMovement(false);
- setIsInitializing(false);
- return 1;
- }
- targetBone.position.copy(initialCurveRef.current!.getPoint(next));
- return next;
- });
-
- ikSolver.update();
- });
-
- // Main animation loop
- useFrame((_, delta) => {
- if (isInitializing || !isPlaying || !selectedTrigger || !activeProcess || !ikSolver) return;
-
- const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBoneName);
- if (!bone) return;
-
- const {
- restToStartCurve,
- processCurve,
- endToRestCurve,
- speed,
- totalDistance
- } = activeProcess;
-
- // Calculate current segment and progress
- const restToStartDist = restPosition.distanceTo(restToStartCurve.points[2]);
- const processDist = processCurve.getLength();
- const endToRestDist = endToRestCurve.getLength();
-
- const restToStartEnd = restToStartDist / totalDistance;
- const processEnd = (restToStartDist + processDist) / totalDistance;
-
- setProgress(prev => {
- let currentStatus = statusRef.current;
- let currentPosition: THREE.Vector3;
- const newProgress = Math.min(prev + delta * ((currentStatus === 'returning to rest') ? restSpeed : speed), 1);
-
- if (newProgress < restToStartEnd) {
- // Moving from rest to start position
- currentStatus = "moving to start";
- const segmentProgress = newProgress / restToStartEnd;
- currentPosition = restToStartCurve.getPoint(segmentProgress);
- } else if (newProgress < processEnd) {
- // Processing - moving from start to end
- currentStatus = "processing";
- const segmentProgress = (newProgress - restToStartEnd) / (processEnd - restToStartEnd);
- currentPosition = processCurve.getPoint(segmentProgress);
- if (statusRef.current !== "processing") {
- updateConveyorOrStaticMachineStatusOnStart(selectedTrigger);
- }
- } else {
- // Returning to rest position
- currentStatus = "returning to rest";
- const segmentProgress = (newProgress - processEnd) / (1 - processEnd);
- currentPosition = endToRestCurve.getPoint(segmentProgress);
- }
-
- // Update status if changed
- if (currentStatus !== statusRef.current) {
- statusRef.current = currentStatus;
- // updateArmBotStatus(currentStatus);
- logStatus(`[Arm ${uuid}] Status: ${currentStatus}`);
- }
-
- // Only trigger when the entire animation is complete (newProgress === 1)
- if (newProgress === 1 && currentStatus === "returning to rest") {
- updateConveyorOrStaticMachineStatusOnEnd(selectedTrigger);
- }
-
- bone.position.copy(currentPosition);
- ikSolver.update();
- return newProgress;
- });
- });
-
- const updateConveyorOrStaticMachineStatusOnStart = (selectedTrigger: string) => {
- const currentProcess = processes.find(p => p.triggerId === selectedTrigger);
- if (currentProcess) {
- const triggerId = currentProcess.triggerId;
-
- const startPoint = armBot.actions.processes.find((process) => process.triggerId === triggerId)?.startPoint;
-
- const matchedMachine = simulationStates.find((state) => {
- if (state.type === "Conveyor") {
- return (state).points.some(
- (point) => point.uuid === startPoint
- );
- } else if (state.type === "StaticMachine") {
- return state.points.uuid === startPoint;
- }
- return false;
- });
-
- if (matchedMachine) {
- if (matchedMachine.type === "Conveyor") {
- logStatus(`[Arm ${uuid}] start point which is a conveyor (${matchedMachine.modelName})`);
- } else {
- logStatus(`[Arm ${uuid}] started form start point which is a static machine (${matchedMachine.modelName})`);
- }
-
- setTimeout(() => {
- if (matchedMachine.type === "StaticMachine") {
- updateArmBotStatus('dropping');
- }
-
- if (matchedMachine.type === "Conveyor") {
- updateArmBotStatus('picking');
- }
- }, 0);
- }
- }
- }
-
- const updateConveyorOrStaticMachineStatusOnEnd = (selectedTrigger: string) => {
- const currentProcess = processes.find(p => p.triggerId === selectedTrigger);
- if (currentProcess) {
- const triggerId = currentProcess.triggerId;
-
- const endPoint = armBot.actions.processes.find((process) => process.triggerId === triggerId)?.endPoint;
-
- const matchedMachine = simulationStates.find((state) => {
- if (state.type === "Conveyor") {
- return (state).points.some(
- (point) => point.uuid === endPoint
- );
- } else if (state.type === "StaticMachine") {
- return state.points.uuid === endPoint;
- }
- return false;
- });
-
- if (matchedMachine) {
- if (matchedMachine.type === "Conveyor") {
- logStatus(`[Arm ${uuid}] Reached end point which is a conveyor (${matchedMachine.modelName})`);
- } else {
- logStatus(`[Arm ${uuid}] Reached end point which is a static machine (${matchedMachine.modelName})`);
- }
-
- setTimeout(() => {
- if (matchedMachine.type === "StaticMachine") {
- setStaticMachines((machines) => {
- return machines.map((machine) => {
- if (machine.uuid === matchedMachine.modeluuid) {
- return { ...machine, status: "running" };
- } else {
- return machine;
- }
- });
- });
- updateArmBotStatus('idle');
- }
-
- if (matchedMachine.type === "Conveyor") {
- setArmBots((prev) =>
- prev.map((arm) => {
- if (arm.uuid === uuid && arm.isActive === true) {
- return {
- ...arm,
- isActive: false,
- status: "idle",
- };
- }
- else {
- return arm;
- }
- })
- );
- }
- }, 0);
- }
- }
- }
-
- return (
- <>
-
- >
- );
-};
-
-export default IKAnimationController;
\ No newline at end of file
diff --git a/app/src/modules/simulation/armbot/IkInstances.tsx b/app/src/modules/simulation/armbot/IkInstances.tsx
deleted file mode 100644
index 6e7dc13..0000000
--- a/app/src/modules/simulation/armbot/IkInstances.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-import * as THREE from "three";
-import { useEffect, useMemo, useRef, useState } from "react";
-import { useFrame, useLoader } from "@react-three/fiber";
-import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
-import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
-import { clone } from "three/examples/jsm/utils/SkeletonUtils";
-import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSolver";
-import IKAnimationController from "./IKAnimationController";
-import { TransformControls } from "@react-three/drei";
-
-interface StaticMachineState {
- uuid: string;
- status: string;
- actions: { uuid: string; name: string; buffer: number; material: string; };
- machineTriggerId: string;
- connectedArmBot: string;
-}
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-
-const IkInstances = ({
- uuid,
- selectedTrigger,
- modelUrl,
- processes,
- position,
- rotation,
- armBot,
- setArmBots,
- setStaticMachines,
- updateArmBotStatus
-}: {
- uuid: string;
- selectedTrigger: string;
- modelUrl: string;
- processes: any;
- position: [number, number, number];
- rotation: [number, number, number];
- armBot: ArmBotState;
- setArmBots: React.Dispatch>;
- setStaticMachines: React.Dispatch>;
- updateArmBotStatus: (status: string) => void;
-}) => {
- const [ikSolver, setIkSolver] = useState(null);
- const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
- const draco = new DRACOLoader();
- draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/");
- loader.setDRACOLoader(draco);
- });
- const cloned = useMemo(() => clone(gltf.scene), [gltf]);
- const groupRef = useRef(null);
- const targetBoneName = "Target";
- const skinnedMeshName = "link_0";
-
- useEffect(() => {
- if (!gltf) return;
- const OOI: any = {};
- cloned.traverse((n: any) => {
- if (n.name === targetBoneName) OOI.Target_Bone = n;
- if (n.name === skinnedMeshName) OOI.Skinned_Mesh = n;
- });
-
- if (!OOI.Target_Bone || !OOI.Skinned_Mesh) return;
-
- const iks = [
- {
- target: 7,
- effector: 6,
- links: [
- {
- index: 5,
- enabled: true,
- rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0),
- rotationMax: new THREE.Vector3(Math.PI / 2, 0, 0),
- },
- {
- index: 4,
- enabled: true,
- rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0),
- rotationMax: new THREE.Vector3(0, 0, 0),
- },
- {
- index: 3,
- enabled: true,
- rotationMin: new THREE.Vector3(0, 0, 0),
- rotationMax: new THREE.Vector3(2, 0, 0),
- },
- { index: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) },
- { index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) },
- ],
- },
- ];
-
- const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks);
- setIkSolver(solver);
-
- const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05);
- // groupRef.current.add(helper);
-
- }, [gltf]);
-
-
- const logStatus = (status: string) => {
- // console.log(status);
- }
-
- return (
- <>
-
-
-
-
- >
- );
-};
-
-export default IkInstances;
\ No newline at end of file
diff --git a/app/src/modules/simulation/armbot/MaterialInstances.tsx b/app/src/modules/simulation/armbot/MaterialInstances.tsx
deleted file mode 100644
index c83cd51..0000000
--- a/app/src/modules/simulation/armbot/MaterialInstances.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import * as THREE from 'three';
-import { Box } from '@react-three/drei';
-
-type MaterialInstancesProps = {
- statusRef: React.RefObject;
- ikSolver: any;
- targetBoneName: string;
-};
-
-function MaterialInstances({
- statusRef,
- ikSolver,
- targetBoneName
-}: MaterialInstancesProps) {
- if (!ikSolver) return null;
-
- const targetBone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBoneName);
- if (!targetBone) return null;
-
- const worldPos = new THREE.Vector3();
- targetBone.getWorldPosition(worldPos);
-
- return (
-
-
-
- );
-}
-
-export default MaterialInstances;
\ No newline at end of file
diff --git a/app/src/modules/simulation/conveyor/conveyor.tsx b/app/src/modules/simulation/conveyor/conveyor.tsx
new file mode 100644
index 0000000..bd21523
--- /dev/null
+++ b/app/src/modules/simulation/conveyor/conveyor.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import ConveyorInstances from './instances/conveyorInstances'
+
+function Conveyor() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default Conveyor
\ No newline at end of file
diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx
new file mode 100644
index 0000000..9c9d612
--- /dev/null
+++ b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+
+function ConveyorInstance() {
+ return (
+ <>
+ >
+ )
+}
+
+export default ConveyorInstance
\ No newline at end of file
diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx
new file mode 100644
index 0000000..3f53784
--- /dev/null
+++ b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import ConveyorInstance from './conveyorInstance/conveyorInstance'
+
+function ConveyorInstances() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default ConveyorInstances
\ No newline at end of file
diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
new file mode 100644
index 0000000..335f1f5
--- /dev/null
+++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
@@ -0,0 +1,148 @@
+import React, { useEffect, useRef, useState } from 'react';
+import * as THREE from 'three';
+import { useEventsStore } from '../../../../../store/simulation/useEventsStore';
+import useModuleStore from '../../../../../store/useModuleStore';
+import { TransformControls } from '@react-three/drei';
+import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys';
+
+function PointsCreator() {
+ const { events, updatePoint, getPointByUuid } = useEventsStore();
+ const { activeModule } = useModuleStore();
+ const transformRef = useRef(null);
+ const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
+ const [selectedPoint, setSelectedPoint] = useState(null);
+ const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
+
+ useEffect(() => {
+ setTransformMode(null);
+ const handleKeyDown = (e: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(e);
+ if (!selectedPoint) return;
+ if (keyCombination === "G") {
+ setTransformMode((prev) => (prev === "translate" ? null : "translate"));
+ }
+ if (keyCombination === "R") {
+ setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
+ }
+ };
+
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [selectedPoint]);
+
+ const updatePointToState = (selectedPoint: THREE.Mesh) => {
+ let point = JSON.parse(JSON.stringify(getPointByUuid(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid)));
+ if (point) {
+ point.position = [selectedPoint.position.x, selectedPoint.position.y, selectedPoint.position.z];
+ updatePoint(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid, point)
+ }
+ }
+
+ return (
+ <>
+ {activeModule === 'simulation' &&
+ <>
+
+ {events.map((event, i) => {
+ if (event.type === 'transfer') {
+ return (
+
+ {event.points.map((point, j) => (
+ (sphereRefs.current[point.uuid] = el!)}
+ onClick={(e) => {
+ e.stopPropagation();
+ setSelectedPoint(sphereRefs.current[point.uuid]);
+ }}
+ onPointerMissed={() => {
+ setSelectedPoint(null);
+ }}
+ key={`${i}-${j}`}
+ position={new THREE.Vector3(...point.position)}
+ userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }}
+ >
+
+
+
+ ))}
+
+ );
+ } else if (event.type === 'vehicle') {
+ return (
+
+ (sphereRefs.current[event.point.uuid] = el!)}
+ onClick={(e) => {
+ e.stopPropagation();
+ setSelectedPoint(sphereRefs.current[event.point.uuid]);
+ }}
+ onPointerMissed={() => {
+ setSelectedPoint(null);
+ }}
+ position={new THREE.Vector3(...event.point.position)}
+ userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
+ >
+
+
+
+
+ );
+ } else if (event.type === 'roboticArm') {
+ return (
+
+ (sphereRefs.current[event.point.uuid] = el!)}
+ onClick={(e) => {
+ e.stopPropagation();
+ setSelectedPoint(sphereRefs.current[event.point.uuid]);
+ }}
+ onPointerMissed={() => {
+ setSelectedPoint(null);
+ }}
+ position={new THREE.Vector3(...event.point.position)}
+ userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
+ >
+
+
+
+
+ );
+ } else if (event.type === 'machine') {
+ return (
+
+ (sphereRefs.current[event.point.uuid] = el!)}
+ onClick={(e) => {
+ e.stopPropagation();
+ setSelectedPoint(sphereRefs.current[event.point.uuid]);
+ }}
+ onPointerMissed={() => {
+ setSelectedPoint(null);
+ }}
+ position={new THREE.Vector3(...event.point.position)}
+ userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
+ >
+
+
+
+
+ );
+ } else {
+ return null;
+ }
+ })}
+
+ {(selectedPoint && transformMode) &&
+ { updatePointToState(selectedPoint) }} />
+ }
+ >
+ }
+ >
+ );
+}
+
+export default PointsCreator;
diff --git a/app/src/modules/simulation/events/points/points.tsx b/app/src/modules/simulation/events/points/points.tsx
new file mode 100644
index 0000000..2a50f2d
--- /dev/null
+++ b/app/src/modules/simulation/events/points/points.tsx
@@ -0,0 +1,12 @@
+import React from 'react'
+import PointsCreator from './creator/pointsCreator'
+
+function Points() {
+ return (
+ <>
+
+ >
+ )
+}
+
+export default Points
\ No newline at end of file
diff --git a/app/src/modules/simulation/events/points/pointsCalculator.ts b/app/src/modules/simulation/events/points/pointsCalculator.ts
new file mode 100644
index 0000000..86d368e
--- /dev/null
+++ b/app/src/modules/simulation/events/points/pointsCalculator.ts
@@ -0,0 +1,47 @@
+import * as THREE from 'three';
+import { Group } from '../../../../types/world/worldTypes';
+
+function PointsCalculator(
+ type: string,
+ model: Group,
+ rotation: THREE.Vector3 = new THREE.Vector3()
+): { points?: THREE.Vector3[] } | null {
+ if (!model) return null;
+
+ const box = new THREE.Box3().setFromObject(model);
+
+ const size = new THREE.Vector3();
+ box.getSize(size);
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+
+ const rotationMatrix = new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(rotation.x, rotation.y, rotation.z));
+
+ const localTopMiddle = new THREE.Vector3(0, size.y / 2, 0);
+ const worldTopMiddle = localTopMiddle.clone().applyMatrix4(rotationMatrix).add(center);
+
+ if (type === 'Conveyor') {
+ const isWidthLonger = size.x > size.z;
+ const longerSize = isWidthLonger ? size.x : size.z;
+ const shorterSize = isWidthLonger ? size.z : size.x;
+ const halfLongerSize = longerSize / 2;
+ const halfShorterSize = shorterSize / 2;
+
+ const localEndPoint1 = new THREE.Vector3(isWidthLonger ? -halfLongerSize + halfShorterSize : 0, size.y / 2, isWidthLonger ? 0 : -halfLongerSize + halfShorterSize);
+
+ const localEndPoint2 = new THREE.Vector3(isWidthLonger ? halfLongerSize - halfShorterSize : 0, size.y / 2, isWidthLonger ? 0 : halfLongerSize - halfShorterSize);
+
+ const worldEndPoint1 = localEndPoint1.applyMatrix4(rotationMatrix).add(center);
+ const worldEndPoint2 = localEndPoint2.applyMatrix4(rotationMatrix).add(center);
+
+ return {
+ points: [worldEndPoint1, worldTopMiddle, worldEndPoint2]
+ };
+ }
+
+ return {
+ points: [worldTopMiddle]
+ };
+}
+
+export default PointsCalculator;
diff --git a/app/src/modules/simulation/temp.md b/app/src/modules/simulation/events/temp.md
similarity index 100%
rename from app/src/modules/simulation/temp.md
rename to app/src/modules/simulation/events/temp.md
diff --git a/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx
new file mode 100644
index 0000000..1445e70
--- /dev/null
+++ b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+function MaterialAnimator() {
+ return (
+ <>>
+ )
+}
+
+export default MaterialAnimator
\ No newline at end of file
diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
new file mode 100644
index 0000000..466e235
--- /dev/null
+++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+function MaterialInstance() {
+ return (
+ <>>
+ )
+}
+
+export default MaterialInstance
\ No newline at end of file
diff --git a/app/src/modules/simulation/materials/instances/materialInstances.tsx b/app/src/modules/simulation/materials/instances/materialInstances.tsx
new file mode 100644
index 0000000..519cba9
--- /dev/null
+++ b/app/src/modules/simulation/materials/instances/materialInstances.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import MaterialInstance from './instance/materialInstance'
+import MaterialAnimator from './animator/materialAnimator'
+
+function MaterialInstances() {
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
+
+export default MaterialInstances
\ No newline at end of file
diff --git a/app/src/modules/simulation/materials/materials.tsx b/app/src/modules/simulation/materials/materials.tsx
new file mode 100644
index 0000000..432d815
--- /dev/null
+++ b/app/src/modules/simulation/materials/materials.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import MaterialInstances from './instances/materialInstances'
+
+function Materials() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default Materials
\ No newline at end of file
diff --git a/app/src/modules/simulation/path/pathConnector.tsx b/app/src/modules/simulation/path/pathConnector.tsx
deleted file mode 100644
index 3db399e..0000000
--- a/app/src/modules/simulation/path/pathConnector.tsx
+++ /dev/null
@@ -1,1428 +0,0 @@
-import { useFrame, useThree } from "@react-three/fiber";
-import React, { useEffect, useRef, useState } from "react";
-import * as THREE from "three";
-import * as Types from "../../../types/world/worldTypes";
-import * as SimulationTypes from "../../../types/simulationTypes";
-import { QuadraticBezierLine } from "@react-three/drei";
-import { useDeleteTool, useIsConnecting, useRenderDistance, 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 { deleteTool } = useDeleteTool();
- const { renderDistance } = useRenderDistance();
- const { setIsConnecting } = useIsConnecting();
- const { simulationStates, setSimulationStates } = useSimulationStates();
- const { isPlaying } = usePlayButtonStore();
- const { socket } = useSocketStore();
- const groupRefs = useRef<{ [key: string]: any }>({});
-
- const [firstSelected, setFirstSelected] = useState<{ modelUUID: string; sphereUUID: string; position: THREE.Vector3; isCorner: boolean; } | null>(null);
- const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3; end: THREE.Vector3; mid: THREE.Vector3; } | null>(null);
- const [helperlineColor, setHelperLineColor] = useState("red");
- const [hoveredLineKey, setHoveredLineKey] = useState(null);
-
- const updatePathConnections = (fromModelUUID: string, fromPointUUID: string, toModelUUID: string, toPointUUID: string) => {
- const updatedPaths = simulationStates.map((path) => {
- if (path.type === "Conveyor") {
- // Handle outgoing connections from Conveyor
- if (path.modeluuid === fromModelUUID) {
- return {
- ...path,
- points: path.points.map((point) => {
- if (point.uuid === fromPointUUID) {
- const newTarget = {
- modelUUID: toModelUUID,
- pointUUID: toPointUUID,
- };
- const existingTargets = point.connections.targets || [];
-
- // Check connection limits
- const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
- if (toPath) {
- // Check if we already have this type of connection
- const hasConveyor = existingTargets.some(t => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === "Conveyor";
- });
- const hasArmBot = existingTargets.some(t => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === "ArmBot";
- });
- const hasVehicle = existingTargets.some(t => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === "Vehicle";
- });
-
- if (toPath.type === "Conveyor" && hasConveyor) {
- console.log("Conveyor can only connect to one other conveyor");
- return point;
- }
- if (toPath.type === "ArmBot" && hasArmBot) {
- console.log("Conveyor can only connect to one ArmBot");
- return point;
- }
- if (toPath.type === "Vehicle" && hasVehicle) {
- console.log("Conveyor can only connect to one Vehicle");
- return point;
- }
- }
-
- if (!existingTargets.some((target) => target.modelUUID === newTarget.modelUUID && target.pointUUID === newTarget.pointUUID)) {
- return {
- ...point,
- connections: {
- ...point.connections,
- targets: [...existingTargets, newTarget],
- },
- };
- }
- }
- return point;
- }),
- };
- }
- // Handle incoming connections to Conveyor
- else if (path.modeluuid === toModelUUID) {
- return {
- ...path,
- points: path.points.map((point) => {
- if (point.uuid === toPointUUID) {
- const reverseTarget = {
- modelUUID: fromModelUUID,
- pointUUID: fromPointUUID,
- };
- const existingTargets = point.connections.targets || [];
-
- // Check connection limits
- const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
- if (fromPath) {
- const hasConveyor = existingTargets.some(t => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === "Conveyor";
- });
- const hasArmBot = existingTargets.some(t => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === "ArmBot";
- });
- const hasVehicle = existingTargets.some(t => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === "Vehicle";
- });
-
- if (fromPath.type === "Conveyor" && hasConveyor) {
- console.log("Conveyor can only connect to one other conveyor");
- return point;
- }
- if (fromPath.type === "ArmBot" && hasArmBot) {
- console.log("Conveyor can only connect to one ArmBot");
- return point;
- }
- if (fromPath.type === "Vehicle" && hasVehicle) {
- console.log("Conveyor can only connect to one Vehicle");
- return point;
- }
- }
-
- if (!existingTargets.some((target) => target.modelUUID === reverseTarget.modelUUID && target.pointUUID === reverseTarget.pointUUID)) {
- return {
- ...point,
- connections: {
- ...point.connections,
- targets: [...existingTargets, reverseTarget],
- },
- };
- }
- }
- return point;
- }),
- };
- }
- } else if (path.type === "Vehicle") {
- // Handle outgoing connections from Vehicle
- if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
- const newTarget = {
- modelUUID: toModelUUID,
- pointUUID: toPointUUID,
- };
- const existingTargets = path.points.connections.targets || [];
-
- // Check if target is a Conveyor
- const toPath = simulationStates.find((p) => p.modeluuid === toModelUUID);
- if (toPath?.type !== "Conveyor") {
- console.log("Vehicle can only connect to Conveyors");
- return path;
- }
-
- // Check if already has a connection
- if (existingTargets.length >= 1) {
- console.log("Vehicle 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 Vehicle
- 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 a Conveyor
- const fromPath = simulationStates.find((p) => p.modeluuid === fromModelUUID);
- if (fromPath?.type !== "Conveyor") {
- console.log("Vehicle can only connect to Conveyors");
- return path;
- }
-
- // Check if already has a connection
- if (existingTargets.length >= 1) {
- console.log("Vehicle 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;
- } else if (path.type === "StaticMachine") {
- // Handle outgoing connections from StaticMachine
- if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
- const newTarget = {
- modelUUID: toModelUUID,
- pointUUID: toPointUUID,
- };
-
- // Ensure 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;
- }
-
- const existingTargets = path.points.connections.targets || [];
-
- // Allow only one connection
- if (existingTargets.length >= 1) {
- console.log("StaticMachine can only have 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 fromPath = simulationStates.find((p) => p.modeluuid === fromModelUUID);
- if (fromPath?.type !== "ArmBot") {
- console.log("StaticMachine can only be connected from ArmBot");
- return path;
- }
-
- const existingTargets = path.points.connections.targets || [];
-
- if (existingTargets.length >= 1) {
- console.log("StaticMachine can only have 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;
- } else if (path.type === "ArmBot") {
- // Handle outgoing connections from ArmBot
- if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
- const newTarget = {
- modelUUID: toModelUUID,
- pointUUID: toPointUUID,
- };
-
- const toPath = simulationStates.find((p) => p.modeluuid === toModelUUID);
- if (!toPath) return path;
-
- const existingTargets = path.points.connections.targets || [];
-
- // Check if connecting to a StaticMachine and already connected to one
- const alreadyConnectedToStatic = existingTargets.some((target) => {
- const targetPath = simulationStates.find((p) => p.modeluuid === target.modelUUID);
- return targetPath?.type === "StaticMachine";
- });
-
- if (toPath.type === "StaticMachine") {
- if (alreadyConnectedToStatic) {
- console.log("ArmBot can only connect to one StaticMachine");
- 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 ArmBot
- else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
- const reverseTarget = {
- modelUUID: fromModelUUID,
- pointUUID: fromPointUUID,
- };
-
- const fromPath = simulationStates.find((p) => p.modeluuid === fromModelUUID);
- if (!fromPath) return path;
-
- const existingTargets = path.points.connections.targets || [];
-
- const alreadyConnectedFromStatic = existingTargets.some((target) => {
- const targetPath = simulationStates.find((p) => p.modeluuid === target.modelUUID);
- return targetPath?.type === "StaticMachine";
- });
-
- if (fromPath.type === "StaticMachine") {
- if (alreadyConnectedFromStatic) {
- console.log(
- "ArmBot can only be connected from one StaticMachine"
- );
- 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;
- });
-
- setSimulationStates(updatedPaths);
-
- const updatedPathDetails = updatedPaths.filter((path) => path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID);
-
- updateBackend(updatedPathDetails);
- };
-
- const updateBackend = async (updatedPaths: (| SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]) => {
- 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);
- } else if (updatedPath.type === "StaticMachine") {
- // await setEventApi(
- // organization,
- // updatedPath.modeluuid,
- // { type: "StaticMachine", points: updatedPath.points }
- // );
-
- const data = {
- organization: organization,
- modeluuid: updatedPath.modeluuid,
- eventData: { type: "StaticMachine", points: updatedPath.points },
- };
-
- socket.emit("v2:model-asset:updateEventData", data);
- } else if (updatedPath.type === "ArmBot") {
- // await setEventApi(
- // organization,
- // updatedPath.modeluuid,
- // { type: "ArmBot", points: updatedPath.points }
- // );
-
- const data = {
- organization: organization,
- modeluuid: updatedPath.modeluuid,
- eventData: { type: "ArmBot", 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);
- };
-
- useEffect(() => {
- const canvasElement = gl.domElement;
- let drag = false;
- let MouseDown = false;
-
- const onMouseDown = () => {
- MouseDown = true;
- drag = false;
- };
-
- const onMouseUp = () => {
- MouseDown = false;
- };
-
- const onMouseMove = () => {
- if (MouseDown) {
- drag = true;
- }
- };
-
- const onContextMenu = (evt: MouseEvent) => {
- evt.preventDefault();
- if (drag || evt.button === 0) return;
-
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster.intersectObjects(
- pathsGroupRef.current.children,
- true
- );
-
- if (intersects.length > 0) {
- const intersected = intersects[0].object;
-
- if (intersected.name.includes("events-sphere")) {
- const modelUUID = intersected.userData.path.modeluuid;
- const sphereUUID = intersected.uuid;
- const worldPosition = new THREE.Vector3();
- intersected.getWorldPosition(worldPosition);
-
- let isStartOrEnd = false;
-
- if (intersected.userData.path.points && intersected.userData.path.points.length > 1) {
- isStartOrEnd = intersected.userData.path.points.length > 0
- && (sphereUUID === intersected.userData.path.points[0].uuid || sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid);
- } else if (intersected.userData.path.points) {
- isStartOrEnd = sphereUUID === intersected.userData.path.points.uuid;
- }
-
- 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") {
- console.log("Cannot connect two vehicle paths together");
- return;
- }
-
- // Prevent conveyor middle point to conveyor connections
- if (firstPath && secondPath && firstPath.type === "Conveyor" && secondPath.type === "Conveyor" && (!firstSelected?.isCorner || !isStartOrEnd)) {
- console.log("Conveyor connections must be between start/end points");
- return;
- }
-
- // Check if this specific connection already exists
- const isDuplicateConnection = firstSelected
- ? 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.modelUUID === modelUUID &&
- t.pointUUID === sphereUUID
- );
- } else if (path.type === "Vehicle") {
- return path.points.connections.targets.some(
- (t) =>
- t.modelUUID === modelUUID &&
- t.pointUUID === sphereUUID
- );
- }
- }
- return false;
- })
- : false;
-
- if (isDuplicateConnection) {
- console.log("These points are already connected. Ignoring.");
- return;
- }
-
- // For Vehicles, check if they're already connected to anything
- if (intersected.userData.path.type === "Vehicle") {
- const vehicleConnections =
- intersected.userData.path.points.connections.targets.length;
- if (vehicleConnections >= 1) {
- console.log("Vehicle can only have one connection");
- return;
- }
- }
-
- // For Conveyors, check connection limits in BOTH DIRECTIONS
- if (firstSelected && (firstPath?.type === "Conveyor" || secondPath?.type === "Conveyor")) {
- const checkConveyorLimits = (path: any, pointUUID: string) => {
- if (path?.type === "Conveyor") {
- const point = path.points.find((p: { uuid: string }) => p.uuid === pointUUID);
- if (point) {
- return {
- hasConveyor: point.connections.targets.some((t: { modelUUID: string }) => {
- const targetPath = simulationStates.find((p: { modeluuid: string }) => p.modeluuid === t.modelUUID);
- return targetPath?.type === "Conveyor";
- }),
- hasArmBot: point.connections.targets.some((t: { modelUUID: string }) => {
- const targetPath = simulationStates.find((p: { modeluuid: string }) => p.modeluuid === t.modelUUID);
- return targetPath?.type === "ArmBot";
- }),
- hasVehicle: point.connections.targets.some((t: { modelUUID: string }) => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === "Vehicle";
- })
- };
- }
- }
- return { hasConveyor: false, hasArmBot: false, hasVehicle: false };
- };
-
- const firstConveyorLimits = checkConveyorLimits(firstPath, firstSelected?.sphereUUID);
- const secondConveyorLimits = checkConveyorLimits(secondPath, sphereUUID);
-
- // Check if trying to connect two conveyors
- if (firstPath?.type === "Conveyor" && secondPath?.type === "Conveyor") {
- if (firstConveyorLimits.hasConveyor || secondConveyorLimits.hasConveyor) {
- console.log("Conveyor can only connect to one other conveyor");
- return;
- }
- }
-
- // Check if trying to connect to an ArmBot when already connected to one
- if (secondPath?.type === "ArmBot" && firstConveyorLimits.hasArmBot) {
- console.log("Conveyor can only connect to one ArmBot");
- return;
- }
- if (firstPath?.type === "ArmBot" && secondConveyorLimits.hasArmBot) {
- console.log("Conveyor can only connect to one ArmBot");
- return;
- }
-
- // Check if trying to connect to a Vehicle when already connected to one
- if (secondPath?.type === "Vehicle" && firstConveyorLimits.hasVehicle) {
- console.log("Conveyor can only connect to one Vehicle");
- return;
- }
- if (firstPath?.type === "Vehicle" && secondConveyorLimits.hasVehicle) {
- console.log("Conveyor can only connect to one Vehicle");
- return;
- }
- }
-
- if (firstSelected) {
- // Check if trying to connect Vehicle to non-Conveyor
- if ((firstPath?.type === "Vehicle" && secondPath?.type !== "Conveyor") || (secondPath?.type === "Vehicle" && firstPath?.type !== "Conveyor")) {
- console.log("Vehicle can only connect to Conveyors");
- return;
- }
-
- // Prevent same-path connections
- if (firstSelected.modelUUID === modelUUID) {
- console.log("Cannot connect spheres on the same path.");
- return;
- }
-
- // Check if StaticMachine is involved in the connection
- if ((firstPath?.type === "StaticMachine" && secondPath?.type !== "ArmBot") || (secondPath?.type === "StaticMachine" && firstPath?.type !== "ArmBot")) {
- console.log("StaticMachine can only connect to ArmBot");
- return;
- }
-
- // Check if StaticMachine already has a connection
- if (firstPath?.type === "StaticMachine") {
- const staticConnections = firstPath.points.connections.targets.length;
- if (staticConnections >= 1) {
- console.log("StaticMachine can only have one connection");
- return;
- }
- }
- if (secondPath?.type === "StaticMachine") {
- const staticConnections = secondPath.points.connections.targets.length;
- if (staticConnections >= 1) {
- console.log("StaticMachine can only have one connection");
- return;
- }
- }
-
- // Check if ArmBot is involved
- if ((firstPath?.type === "ArmBot" && secondPath?.type === "StaticMachine") || (secondPath?.type === "ArmBot" && firstPath?.type === "StaticMachine")) {
- const armBotPath = firstPath?.type === "ArmBot" ? firstPath : secondPath;
- const staticPath = firstPath?.type === "StaticMachine" ? firstPath : secondPath;
-
- const armBotConnections = armBotPath.points.connections.targets || [];
- const alreadyConnectedToStatic = armBotConnections.some(
- (target) => {
- const targetPath = simulationStates.find((p) => p.modeluuid === target.modelUUID);
- return targetPath?.type === "StaticMachine";
- }
- );
-
- if (alreadyConnectedToStatic) {
- console.log("ArmBot can only connect to one StaticMachine");
- return;
- }
-
- const staticConnections = staticPath.points.connections.targets.length;
- if (staticConnections >= 1) {
- console.log("StaticMachine can only have one connection");
- return;
- }
- }
-
- // Prevent ArmBot ↔ ArmBot
- if (firstPath?.type === "ArmBot" && secondPath?.type === "ArmBot") {
- console.log("Cannot connect two ArmBots together");
- return;
- }
-
- // If one is ArmBot, ensure the other is StaticMachine or Conveyor
- if (firstPath?.type === "ArmBot" || secondPath?.type === "ArmBot") {
- const otherType = firstPath?.type === "ArmBot" ? secondPath?.type : firstPath?.type;
- if (otherType !== "StaticMachine" && otherType !== "Conveyor") {
- console.log("ArmBot can only connect to Conveyors or one StaticMachine");
- return;
- }
- }
-
- // At least one must be start/end point
- if (!firstSelected.isCorner && !isStartOrEnd) {
- console.log("At least one of the selected spheres must be a start or end point.");
- return;
- }
-
- // All checks passed - make the connection
- handleAddConnection(firstSelected.modelUUID, firstSelected.sphereUUID, modelUUID, sphereUUID);
- } else {
- // First selection - just store it
- setFirstSelected({ modelUUID, sphereUUID, position: worldPosition, isCorner: isStartOrEnd });
- setIsConnecting(true);
- }
- }
- }
- } else {
- // Clicked outside - cancel connection
- setFirstSelected(null);
- setCurrentLine(null);
- setIsConnecting(false);
- }
- };
-
- if (activeModule === "simulation" && !deleteTool) {
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
- canvasElement.addEventListener("contextmenu", onContextMenu);
- } else {
- setFirstSelected(null);
- setCurrentLine(null);
- setIsConnecting(false);
- }
-
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- canvasElement.removeEventListener("contextmenu", onContextMenu);
- };
- }, [camera, scene, raycaster, firstSelected, simulationStates, deleteTool]);
-
- 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(() => {
- if (firstSelected) {
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster.intersectObjects(scene.children, true).filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("agv-collider") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.userData.isPathObject &&
- !(intersect.object.type === "GridHelper")
- );
-
- let point: THREE.Vector3 | null = null;
- let snappedSphere: { sphereUUID: string; position: THREE.Vector3; modelUUID: string; isCorner: boolean; } | null = null;
- let isInvalidConnection = false;
-
- if (intersects.length > 0) {
- point = intersects[0].point;
- if (point.y < 0.05) {
- point = new THREE.Vector3(point.x, 0.05, point.z);
- }
- }
-
- const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) => obj.object.name.includes("events-sphere"));
-
- if (sphereIntersects.length > 0) {
- const sphere = sphereIntersects[0].object;
- const sphereUUID = sphere.uuid;
- const spherePosition = new THREE.Vector3();
- sphere.getWorldPosition(spherePosition);
- const pathData = sphere.userData.path;
- const modelUUID = pathData.modeluuid;
-
- 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:
- const isConnectable = (
- pathData.type === 'Vehicle' ||
- pathData.type === 'ArmBot' ||
- (pathData.points.length > 0 && (
- sphereUUID === pathData.points[0].uuid ||
- sphereUUID === pathData.points[pathData.points.length - 1].uuid ||
- (pathData.type === 'Conveyor' && firstPath?.type === 'ArmBot') // Allow ArmBot to connect to middle points
- ))
- ) &&
- !isVehicleToVehicle &&
- !(
- firstPath?.type === 'Conveyor' &&
- pathData.type === 'Conveyor' &&
- !firstSelected.isCorner
- );
-
- // Check for duplicate connection (regardless of path type)
- 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.modelUUID === modelUUID && t.pointUUID === sphereUUID
- );
- } else if (path.type === 'Vehicle') {
- return path.points.connections.targets.some(t =>
- t.modelUUID === modelUUID && t.pointUUID === sphereUUID
- );
- }
- }
- return false;
- });
-
- // For non-Vehicle paths, check if already connected
- const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' &&
- simulationStates.some(path => {
- if (path.type === 'Conveyor') {
- return path.points.some(point =>
- point.uuid === sphereUUID &&
- point.connections.targets.length > 0
- );
- }
- return false;
- });
-
- // Check vehicle connection rules
- const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
- pathData.points.connections.targets.length >= 1;
- const isVehicleConnectingToNonConveyor =
- (firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
- (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
-
- // Check if StaticMachine is connecting to non-ArmBot
- const isStaticMachineToNonArmBot =
- (firstPath?.type === 'StaticMachine' && secondPath?.type !== 'ArmBot') ||
- (secondPath?.type === 'StaticMachine' && firstPath?.type !== 'ArmBot');
-
- // Check if StaticMachine already has a connection
- const isStaticMachineAtMaxConnections =
- (firstPath?.type === 'StaticMachine' && firstPath.points.connections.targets.length >= 1) ||
- (secondPath?.type === 'StaticMachine' && secondPath.points.connections.targets.length >= 1);
-
- // Check if ArmBot is connecting to StaticMachine
- const isArmBotToStaticMachine =
- (firstPath?.type === 'ArmBot' && secondPath?.type === 'StaticMachine') ||
- (secondPath?.type === 'ArmBot' && firstPath?.type === 'StaticMachine');
-
- // Prevent multiple StaticMachine connections to ArmBot
- let isArmBotAlreadyConnectedToStatic = false;
- if (isArmBotToStaticMachine) {
- const armBotPath = firstPath?.type === 'ArmBot' ? firstPath : secondPath;
- isArmBotAlreadyConnectedToStatic = armBotPath.points.connections.targets.some(target => {
- const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
- return targetPath?.type === 'StaticMachine';
- });
- }
-
- // Prevent ArmBot to ArmBot
- const isArmBotToArmBot = firstPath?.type === 'ArmBot' && secondPath?.type === 'ArmBot';
-
- // If ArmBot is involved, other must be Conveyor or StaticMachine
- const isArmBotToInvalidType = (firstPath?.type === 'ArmBot' || secondPath?.type === 'ArmBot') &&
- !(firstPath?.type === 'Conveyor' || firstPath?.type === 'StaticMachine' ||
- secondPath?.type === 'Conveyor' || secondPath?.type === 'StaticMachine');
-
- // NEW: Check conveyor connection limits
- let isConveyorAtMaxConnections = false;
- if (firstPath?.type === 'Conveyor' || secondPath?.type === 'Conveyor') {
- const conveyorPath = firstPath?.type === 'Conveyor' ? firstPath : secondPath;
- const otherPath = firstPath?.type === 'Conveyor' ? secondPath : firstPath;
-
- if (conveyorPath) {
- const conveyorPoint = Array.isArray(conveyorPath.points)
- ? conveyorPath.points.find((p: { uuid: string }) => p.uuid ===
- (firstPath?.type === 'Conveyor' ? firstSelected.sphereUUID : sphereUUID))
- : undefined;
-
- if (conveyorPoint) {
- const hasConveyor = conveyorPoint.connections.targets.some((t: { modelUUID: string }) => {
- const targetPath = simulationStates.find((p: { modeluuid: string }) => p.modeluuid === t.modelUUID);
- return targetPath?.type === 'Conveyor';
- });
- const hasArmBot = conveyorPoint.connections.targets.some((t: { modelUUID: string }) => {
- const targetPath = simulationStates.find((p: { modeluuid: string }) => p.modeluuid === t.modelUUID);
- return targetPath?.type === 'ArmBot';
- });
- const hasVehicle = conveyorPoint.connections.targets.some((t: { modelUUID: string }) => {
- const targetPath = simulationStates.find(p => p.modeluuid === t.modelUUID);
- return targetPath?.type === 'Vehicle';
- });
-
- if (otherPath?.type === 'Conveyor' && hasConveyor) {
- isConveyorAtMaxConnections = true;
- }
- if (otherPath?.type === 'ArmBot' && hasArmBot) {
- isConveyorAtMaxConnections = true;
- }
- if (otherPath?.type === 'Vehicle' && hasVehicle) {
- isConveyorAtMaxConnections = true;
- }
- }
- }
- }
-
- if (
- !isDuplicateConnection &&
- !isVehicleToVehicle &&
- !isNonVehicleAlreadyConnected &&
- !isVehicleAtMaxConnections &&
- !isVehicleConnectingToNonConveyor &&
- !isStaticMachineToNonArmBot &&
- !isStaticMachineAtMaxConnections &&
- !isArmBotToArmBot &&
- !isArmBotToInvalidType &&
- !isArmBotAlreadyConnectedToStatic &&
- !isConveyorAtMaxConnections && // NEW: Check conveyor limits
- firstSelected.sphereUUID !== sphereUUID &&
- firstSelected.modelUUID !== modelUUID &&
- (firstSelected.isCorner || isConnectable) &&
- !(firstPath?.type === 'Conveyor' &&
- pathData.type === 'Conveyor' &&
- !(firstSelected.isCorner && isConnectable))
- ) {
- snappedSphere = {
- sphereUUID,
- position: spherePosition,
- modelUUID,
- isCorner: isConnectable
- };
- } else {
- isInvalidConnection = true;
- }
- }
-
- if (snappedSphere) {
- point = snappedSphere.position;
- }
-
- if (point) {
- const distance = firstSelected.position.distanceTo(point);
- const heightFactor = Math.max(0.5, distance * 0.2);
- const midPoint = new THREE.Vector3(
- (firstSelected.position.x + point.x) / 2,
- Math.max(firstSelected.position.y, point.y) + heightFactor,
- (firstSelected.position.z + point.z) / 2
- );
-
- setCurrentLine({
- start: firstSelected.position,
- end: point,
- mid: midPoint,
- });
-
- if (sphereIntersects.length > 0) {
- setHelperLineColor(isInvalidConnection ? "red" : "#6cf542");
- } else {
- setHelperLineColor("yellow");
- }
- } else {
- setCurrentLine(null);
- setIsConnecting(false);
- }
- } else {
- setCurrentLine(null);
- setIsConnecting(false);
- }
- });
-
- const removeConnection = (connection1: { model: string; point: string }, connection2: { model: string; point: string }) => {
- const updatedStates = simulationStates.map((state) => {
-
- // Handle Conveyor (which has multiple points)
- if (state.type === "Conveyor") {
- const updatedConveyor: SimulationTypes.ConveyorEventsSchema = {
- ...state,
- points: state.points.map((point) => {
- // Check if this point is either connection1 or connection2
- if ((state.modeluuid === connection1.model && point.uuid === connection1.point) || (state.modeluuid === connection2.model && point.uuid === connection2.point)) {
- return {
- ...point,
- connections: {
- ...point.connections,
- targets: point.connections.targets.filter((target) => {
- // Remove the target that matches the other connection
- return !(
- (target.modelUUID === connection1.model &&
- target.pointUUID === connection1.point) ||
- (target.modelUUID === connection2.model &&
- target.pointUUID === connection2.point)
- );
- }),
- },
- };
- }
- return point;
- }),
- };
- return updatedConveyor;
- }
-
- // Handle Vehicle
- else if (state.type === "Vehicle") {
- if ((state.modeluuid === connection1.model && state.points.uuid === connection1.point) || (state.modeluuid === connection2.model && state.points.uuid === connection2.point)) {
- const updatedVehicle: SimulationTypes.VehicleEventsSchema = {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter((target) => {
- return !(
- (target.modelUUID === connection1.model &&
- target.pointUUID === connection1.point) ||
- (target.modelUUID === connection2.model &&
- target.pointUUID === connection2.point)
- );
- }),
- },
- // Ensure all required Vehicle point properties are included
- speed: state.points.speed,
- actions: state.points.actions,
- },
- };
- return updatedVehicle;
- }
- }
-
- // Handle StaticMachine
- else if (state.type === "StaticMachine") {
- if ((state.modeluuid === connection1.model && state.points.uuid === connection1.point) || (state.modeluuid === connection2.model && state.points.uuid === connection2.point)) {
- const updatedStaticMachine: SimulationTypes.StaticMachineEventsSchema =
- {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter((target) => {
- return !(
- (target.modelUUID === connection1.model &&
- target.pointUUID === connection1.point) ||
- (target.modelUUID === connection2.model &&
- target.pointUUID === connection2.point)
- );
- }),
- },
- // Ensure all required StaticMachine point properties are included
- actions: state.points.actions,
- triggers: state.points.triggers,
- },
- };
- return updatedStaticMachine;
- }
- }
-
- // Handle ArmBot
- else if (state.type === "ArmBot") {
- if ((state.modeluuid === connection1.model && state.points.uuid === connection1.point) || (state.modeluuid === connection2.model && state.points.uuid === connection2.point)) {
- const updatedArmBot: SimulationTypes.ArmBotEventsSchema = {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter((target) => {
- return !(
- (target.modelUUID === connection1.model &&
- target.pointUUID === connection1.point) ||
- (target.modelUUID === connection2.model &&
- target.pointUUID === connection2.point)
- );
- }),
- },
- actions: {
- ...state.points.actions,
- processes:
- state.points.actions.processes?.filter((process) => {
- return !(
- process.startPoint === connection1.point ||
- process.endPoint === connection1.point ||
- process.startPoint === connection2.point ||
- process.endPoint === connection2.point
- );
- }) || [],
- },
- triggers: state.points.triggers,
- },
- };
- return updatedArmBot;
- }
- }
- return state;
- });
-
- const updatedPaths = updatedStates.filter(
- (state) =>
- state.modeluuid === connection1.model ||
- state.modeluuid === connection2.model
- );
-
- updateBackend(updatedPaths);
-
- setSimulationStates(updatedStates);
- };
-
- const removeConnections = (deletedModelUUIDs: string[]) => {
-
- const deletedPointUUIDs = new Set();
- simulationStates.forEach(state => {
- if (deletedModelUUIDs.includes(state.modeluuid)) {
- if (state.type === "Conveyor" && state.points) {
- state.points.forEach(point => {
- deletedPointUUIDs.add(point.uuid);
- });
- } else if (state.points && 'uuid' in state.points) {
- deletedPointUUIDs.add(state.points.uuid);
- }
- }
- });
-
- const updatedStates = simulationStates.map((state) => {
- // Handle Conveyor
- if (state.type === "Conveyor") {
- const updatedConveyor: SimulationTypes.ConveyorEventsSchema = {
- ...state,
- points: state.points.map((point) => {
- return {
- ...point,
- connections: {
- ...point.connections,
- targets: point.connections.targets.filter(
- (target) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- };
- }),
- };
- return updatedConveyor;
- }
-
- // Handle Vehicle
- else if (state.type === "Vehicle") {
- const updatedVehicle: SimulationTypes.VehicleEventsSchema = {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter(
- (target) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- },
- };
- return updatedVehicle;
- }
-
- // Handle StaticMachine
- else if (state.type === "StaticMachine") {
- const updatedStaticMachine: SimulationTypes.StaticMachineEventsSchema =
- {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter(
- (target) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- },
- };
- return updatedStaticMachine;
- }
-
- // Handle ArmBot
- else if (state.type === "ArmBot") {
- const updatedArmBot: SimulationTypes.ArmBotEventsSchema = {
- ...state,
- points: {
- ...state.points,
- connections: {
- ...state.points.connections,
- targets: state.points.connections.targets.filter(
- (target: any) => !deletedModelUUIDs.includes(target.modelUUID)
- ),
- },
- actions: {
- ...state.points.actions,
- processes: state.points.actions.processes?.filter((process) => {
- // Check if trigger is from deleted model
- const matchedStates = simulationStates.filter((s) => deletedModelUUIDs.includes(s.modeluuid));
-
- if (matchedStates.length > 0) {
- if (matchedStates[0]?.type === "StaticMachine") {
- const trigPoints = matchedStates[0]?.points;
- if (process.triggerId === trigPoints?.triggers?.uuid) {
- return false;
- }
- } else if (matchedStates[0]?.type === "Conveyor") {
- const trigPoints = matchedStates[0]?.points;
- if (Array.isArray(trigPoints)) {
- const nonEmptyTriggers = trigPoints.filter((point) => point && point.triggers && point.triggers.length > 0);
- const allTriggerUUIDs = nonEmptyTriggers.flatMap((point) => point.triggers).map((trigger) => trigger.uuid);
- if (allTriggerUUIDs.includes(process.triggerId)) {
- return false;
- }
- }
- }
- }
-
- // Check if startPoint or endPoint is from deleted model
- if (deletedPointUUIDs.has(process.startPoint) || deletedPointUUIDs.has(process.endPoint)) {
- return false;
- }
-
- return true;
- }),
- },
- },
- };
- return updatedArmBot;
- }
-
- return state;
- });
-
- const filteredStates = updatedStates.filter((state) => !deletedModelUUIDs.includes(state.modeluuid));
-
- updateBackend(filteredStates);
- setSimulationStates(filteredStates);
- };
-
- return (
-
- {simulationStates.flatMap((path) => {
- if (path.type === "Conveyor") {
- return path.points.flatMap((point) =>
- point.connections.targets.map((target, index) => {
- const targetPath = simulationStates.find((p) => p.modeluuid === target.modelUUID);
- if (targetPath?.type !== "Conveyor" && targetPath?.type !== "ArmBot") return null;
-
- const fromSphere = pathsGroupRef.current?.getObjectByProperty("uuid", point.uuid);
- const toSphere = pathsGroupRef.current?.getObjectByProperty("uuid", target.pointUUID);
-
- if (fromSphere && toSphere) {
- const fromWorldPosition = new THREE.Vector3();
- const toWorldPosition = new THREE.Vector3();
- fromSphere.getWorldPosition(fromWorldPosition);
- toSphere.getWorldPosition(toWorldPosition);
-
- const distance = fromWorldPosition.distanceTo(toWorldPosition);
- const heightFactor = Math.max(0.5, distance * 0.2);
- const midPoint = new THREE.Vector3(
- (fromWorldPosition.x + toWorldPosition.x) / 2,
- Math.max(fromWorldPosition.y, toWorldPosition.y) +
- heightFactor,
- (fromWorldPosition.z + toWorldPosition.z) / 2
- );
-
- return (
- (groupRefs.current[`${point.uuid}-${target.pointUUID}-${index}`] = el!)}
- start={fromWorldPosition.toArray()}
- end={toWorldPosition.toArray()}
- mid={midPoint.toArray()}
- color={deleteTool && hoveredLineKey === `${point.uuid}-${target.pointUUID}-${index}` ? "red" : targetPath?.type === "ArmBot" ? "#42a5f5" : "white"}
- lineWidth={4}
- dashed={deleteTool && hoveredLineKey === `${point.uuid}-${target.pointUUID}-${index}` ? false : true}
- dashSize={0.75}
- dashScale={20}
- onPointerOver={() => setHoveredLineKey(`${point.uuid}-${target.pointUUID}-${index}`)}
- onPointerOut={() => setHoveredLineKey(null)}
- onClick={() => {
- if (deleteTool) {
- const connection1 = {
- model: path.modeluuid,
- point: point.uuid,
- };
- const connection2 = {
- model: target.modelUUID,
- point: target.pointUUID,
- };
-
- removeConnection(connection1, connection2);
- }
- }}
- userData={target}
- />
- );
- }
- return null;
- })
- );
- }
-
- if (path.type === "Vehicle") {
- return path.points.connections.targets.map((target, index) => {
- const fromSphere = pathsGroupRef.current?.getObjectByProperty("uuid", path.points.uuid);
- const toSphere = pathsGroupRef.current?.getObjectByProperty("uuid", target.pointUUID);
-
- if (fromSphere && toSphere) {
- const fromWorldPosition = new THREE.Vector3();
- const toWorldPosition = new THREE.Vector3();
- fromSphere.getWorldPosition(fromWorldPosition);
- toSphere.getWorldPosition(toWorldPosition);
-
- const distance = fromWorldPosition.distanceTo(toWorldPosition);
- const heightFactor = Math.max(0.5, distance * 0.2);
- const midPoint = new THREE.Vector3(
- (fromWorldPosition.x + toWorldPosition.x) / 2,
- Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
- (fromWorldPosition.z + toWorldPosition.z) / 2
- );
-
- return (
- (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)}
- start={fromWorldPosition.toArray()}
- end={toWorldPosition.toArray()}
- mid={midPoint.toArray()}
- color={deleteTool && hoveredLineKey === `${path.points.uuid}-${target.pointUUID}-${index}` ? "red" : "orange"}
- lineWidth={4}
- dashed={deleteTool && hoveredLineKey === `${path.points.uuid}-${target.pointUUID}-${index}` ? false : true}
- dashSize={0.75}
- dashScale={20}
- onPointerOver={() => setHoveredLineKey(`${path.points.uuid}-${target.pointUUID}-${index}`)}
- onPointerOut={() => setHoveredLineKey(null)}
- onClick={() => {
- if (deleteTool) {
- const connection1 = {
- model: path.modeluuid,
- point: path.points.uuid,
- };
- const connection2 = {
- model: target.modelUUID,
- point: target.pointUUID,
- };
-
- removeConnection(connection1, connection2);
- }
- }}
- userData={target}
- />
- );
- }
- return null;
- });
- }
-
- if (path.type === "StaticMachine") {
- return path.points.connections.targets.map((target, index) => {
- const targetPath = simulationStates.find((p) => p.modeluuid === target.modelUUID);
- if (targetPath?.type !== "ArmBot") return null;
-
- const fromSphere = pathsGroupRef.current?.getObjectByProperty("uuid", path.points.uuid);
- const toSphere = pathsGroupRef.current?.getObjectByProperty("uuid", target.pointUUID);
-
- if (fromSphere && toSphere) {
- const fromWorldPosition = new THREE.Vector3();
- const toWorldPosition = new THREE.Vector3();
- fromSphere.getWorldPosition(fromWorldPosition);
- toSphere.getWorldPosition(toWorldPosition);
-
- const distance = fromWorldPosition.distanceTo(toWorldPosition);
- const heightFactor = Math.max(0.5, distance * 0.2);
- const midPoint = new THREE.Vector3(
- (fromWorldPosition.x + toWorldPosition.x) / 2,
- Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
- (fromWorldPosition.z + toWorldPosition.z) / 2
- );
-
- return (
- (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)}
- start={fromWorldPosition.toArray()}
- end={toWorldPosition.toArray()}
- mid={midPoint.toArray()}
- color={deleteTool && hoveredLineKey === `${path.points.uuid}-${target.pointUUID}-${index}` ? "red" : "#42a5f5"}
- lineWidth={4}
- dashed={deleteTool && hoveredLineKey === `${path.points.uuid}-${target.pointUUID}-${index}` ? false : true}
- dashSize={0.75}
- dashScale={20}
- onPointerOver={() => setHoveredLineKey(`${path.points.uuid}-${target.pointUUID}-${index}`)}
- onPointerOut={() => setHoveredLineKey(null)}
- onClick={() => {
- if (deleteTool) {
- const connection1 = {
- model: path.modeluuid,
- point: path.points.uuid,
- };
- const connection2 = {
- model: target.modelUUID,
- point: target.pointUUID,
- };
-
- removeConnection(connection1, connection2);
- }
- }}
- userData={target}
- />
- );
- }
- return null;
- });
- }
-
- return [];
- })}
-
- {currentLine && (
-
- )}
-
- );
-}
-
-export default PathConnector;
diff --git a/app/src/modules/simulation/path/pathCreation.tsx b/app/src/modules/simulation/path/pathCreation.tsx
deleted file mode 100644
index 1e9601d..0000000
--- a/app/src/modules/simulation/path/pathCreation.tsx
+++ /dev/null
@@ -1,415 +0,0 @@
-import * as THREE from "three";
-import * as SimulationTypes from "../../../types/simulationTypes";
-import { useRef, useState, useEffect, useMemo } from "react";
-import { Sphere, TransformControls } from "@react-three/drei";
-import {
- 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";
-import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys";
-
-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);
-
- useEffect(() => {
- setTransformMode(null);
- const handleKeyDown = (e: KeyboardEvent) => {
- const keyCombination = detectModifierKeys(e);
- if (!selectedActionSphere) return;
- if (keyCombination === "G") {
- setTransformMode((prev) => (prev === "translate" ? null : "translate"));
- }
- if (keyCombination === "R") {
- setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
- }
- };
-
- window.addEventListener("keydown", handleKeyDown);
- return () => window.removeEventListener("keydown", handleKeyDown);
- }, [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(() => {
- if (eyeDropMode) {
- raycaster.setFromCamera(pointer, camera);
- const intersectionPoint = new THREE.Vector3();
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
-
- if (point) {
- setPreviewPosition({ x: point.x, y: point.z });
- }
- } else {
- setPreviewPosition(null);
- }
- });
-
- useEffect(() => {
- if (!camera) return;
- const canvasElement = gl.domElement;
- canvasElement.tabIndex = 0;
-
- const onPointerDown = () => {
- isMovingRef.current = false;
- };
-
- const onPointerMove = () => {
- isMovingRef.current = true;
- };
-
- 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);
- }
- }
- };
-
- if (eyeDropMode) {
- canvasElement.addEventListener("pointerdown", onPointerDown);
- canvasElement.addEventListener("pointermove", onPointerMove);
- canvasElement.addEventListener("pointerup", onPointerUp);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onPointerDown);
- canvasElement.removeEventListener("pointermove", onPointerMove);
- canvasElement.removeEventListener("pointerup", onPointerUp);
- };
- }, [eyeDropMode, editingPoint, previewPosition]);
-
- const updateBackend = async (updatedPath: SimulationTypes.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 handlePointUpdate = (pointType: "start" | "end", x: number, z: number) => {
- if (!selectedActionSphere?.points?.uuid) return;
- const updatedPaths = simulationStates.map((path) => {
-
- 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 updatedPath = updatedPaths.find((path): path is SimulationTypes.VehicleEventsSchema => path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid);
- updateBackend(updatedPath);
-
- setSimulationStates(updatedPaths);
- };
-
- return (
-
- {simulationStates.map((path) => {
- if (path.type === "Conveyor") {
- const points = path.points.map(
- (point) => new THREE.Vector3(...point.position)
- );
-
- 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);
- }}
- >
-
-
- ))}
-
- {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") {
- 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");
- }}
- >
- (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);
- }}
- >
-
-
-
- );
- } else if (path.type === "StaticMachine") {
- 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");
- }}
- >
- (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);
- }}
- >
-
-
-
- );
- } else if (path.type === "ArmBot") {
- 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");
- }}
- >
- (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
deleted file mode 100644
index 2cd574f..0000000
--- a/app/src/modules/simulation/process/processAnimator.tsx
+++ /dev/null
@@ -1,611 +0,0 @@
-import React, { useRef, useEffect, useMemo, useCallback } from "react";
-import { useLoader, useFrame } from "@react-three/fiber";
-import { GLTFLoader } from "three-stdlib";
-import * as THREE from "three";
-import { GLTF } from "three-stdlib";
-import crate from "../../../assets/gltf-glb/crate_box.glb";
-
-import { useProcessAnimation } from "./useProcessAnimations";
-import ProcessObject from "./processObject";
-import { ProcessData } from "./types";
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: {
- uuid: string;
- name: string;
- speed: number;
- processes: { triggerId: string; startPoint: string; endPoint: string }[];
- };
- isActive?: boolean;
-}
-interface ProcessContainerProps {
- processes: ProcessData[];
- setProcesses: React.Dispatch>;
- agvRef: any;
- MaterialRef: any;
- armBots: ArmBotState[];
- setArmBots: React.Dispatch>;
-}
-
-const ProcessAnimator: React.FC = ({
- processes,
- setProcesses,
- agvRef,
- MaterialRef,
- armBots,
- setArmBots,
-}) => {
- const gltf = useLoader(GLTFLoader, crate) as GLTF;
- const groupRef = useRef(null);
- const tempStackedObjectsRef = useRef>({});
-
- const {
- animationStates,
- setAnimationStates,
- clockRef,
- elapsedBeforePauseRef,
- speedRef,
- debugRef,
- findSpawnPoint,
- createSpawnedObject,
- handlePointActions,
- hasNonInheritActions,
- getPointDataForAnimationIndex,
- processes: processedProcesses,
- checkAndCountTriggers,
- } = useProcessAnimation(processes, setProcesses, agvRef, armBots, setArmBots);
-
- const baseMaterials = useMemo(
- () => ({
- Box: new THREE.MeshStandardMaterial({ color: 0x8b4513 }),
- Crate: new THREE.MeshStandardMaterial({ color: 0x00ff00 }),
- Default: new THREE.MeshStandardMaterial(),
- }),
- []
- );
-
- useEffect(() => {
- // Update material references for all spawned objects
- Object.entries(animationStates).forEach(([processId, processState]) => {
- Object.keys(processState.spawnedObjects).forEach((objectId) => {
- const entry = { processId, objectId };
-
- const materialType =
- processState.spawnedObjects[objectId]?.currentMaterialType;
-
- if (!materialType) {
- return;
- }
-
- const matRefArray = MaterialRef.current;
-
- // Find existing material group
- const existing = matRefArray.find(
- (entryGroup: { material: string; objects: any[] }) =>
- entryGroup.material === materialType
- );
-
- if (existing) {
- // Check if this processId + objectId already exists
- const alreadyExists = existing.objects.some(
- (o: any) =>
- o.processId === entry.processId && o.objectId === entry.objectId
- );
-
- if (!alreadyExists) {
- existing.objects.push(entry);
- }
- } else {
- // Create new group for this material type
- matRefArray.push({
- material: materialType,
- objects: [entry],
- });
- }
- });
- });
- }, [animationStates, MaterialRef, agvRef]);
-
- // In processAnimator.tsx - only the relevant spawn logic part that needs fixes
-
- // Add this function to ProcessAnimator component
- const isConnectedToActiveArmBot = useCallback(
- (processId: any) => {
- // Check if any active armbot is connected to this process
- return armBots.some((armbot) => {
- if (!armbot.isActive) return false;
-
- // Check if this armbot is connected to the process
- return armbot.connections?.targets?.some((connection) => {
- // Find the process that owns this modelUUID
- const connectedProcess = processes.find((p) =>
- p.paths?.some((path) => path.modeluuid === connection.modelUUID)
- );
- return connectedProcess?.id === processId;
- });
- });
- },
- [armBots, processes]
- );
-
- // First useFrame for spawn logic
- useFrame(() => {
- // Spawn logic frame
- const currentTime =
- clockRef.current.getElapsedTime() - elapsedBeforePauseRef.current;
-
- setAnimationStates((prev) => {
- const newStates = { ...prev };
-
- processedProcesses.forEach((process) => {
- const processState = newStates[process.id];
- if (!processState) return;
-
- // Check connection status
- const isConnected = isConnectedToActiveArmBot(process.id);
-
- if (processState.isProcessDelaying) {
- // Existing delay handling logic...
- return;
- }
-
- if (isConnected) {
- newStates[process.id] = {
- ...processState,
- nextSpawnTime: Infinity, // Prevent future spawns
- };
- return;
- }
-
- const spawnPoint = findSpawnPoint(process);
- if (!spawnPoint || !spawnPoint.actions) {
- // console.log(
- // `Process ${process.id} has no valid spawn point or actions`
- // );
- return;
- }
-
- const spawnAction = spawnPoint.actions.find(
- (a) => a.isUsed && a.type === "Spawn"
- );
- if (!spawnAction) {
- return;
- }
-
- const spawnInterval =
- typeof spawnAction.spawnInterval === "number"
- ? spawnAction.spawnInterval
- : parseFloat(spawnAction.spawnInterval || "0") || 0;
-
- // Check if this is a zero interval spawn and we already spawned an object
- if (
- spawnInterval === 0 &&
- processState.hasSpawnedZeroIntervalObject === true
- ) {
- return; // Don't spawn more objects for zero interval
- }
-
- const effectiveSpawnInterval = spawnInterval / speedRef.current;
-
- if (currentTime >= processState.nextSpawnTime) {
- const objectId = `obj-${process.id}-${processState.objectIdCounter}`;
- const newObject = createSpawnedObject(
- process,
- currentTime,
- spawnAction.material || "Default",
- spawnPoint,
- baseMaterials
- );
-
- // Initialize state properly to ensure animation
- newObject.state = {
- ...newObject.state,
- isAnimating: true,
- isDelaying: false,
- delayComplete: false,
- progress: 0.005, // Start with tiny progress to ensure animation begins
- };
-
- // Update state with the new object and flag for zero interval
- newStates[process.id] = {
- ...processState,
- spawnedObjects: {
- ...processState.spawnedObjects,
- [objectId]: newObject,
- },
- objectIdCounter: processState.objectIdCounter + 1,
- nextSpawnTime: currentTime + effectiveSpawnInterval,
- // Mark that we've spawned an object for zero interval case
- hasSpawnedZeroIntervalObject:
- spawnInterval === 0
- ? true
- : processState.hasSpawnedZeroIntervalObject,
- };
- }
- });
-
- return newStates;
- });
- });
-
- // Second useFrame for animation logic
- useFrame((_, delta) => {
- // Animation logic frame
- const currentTime =
- clockRef.current.getElapsedTime() - elapsedBeforePauseRef.current;
-
- setAnimationStates((prev) => {
- const newStates = { ...prev };
-
- processedProcesses.forEach((process) => {
- const processState = newStates[process.id];
- if (!processState) {
- return;
- }
-
- // Check connection status with debugging
- const isConnected = isConnectedToActiveArmBot(process.id);
- // console.log(
- // `Process ${process.id} animation - connected:`,
- // isConnected
- // );
-
- if (isConnected) {
- // Stop all animations when connected to active arm bot
- newStates[process.id] = {
- ...processState,
- spawnedObjects: Object.entries(processState.spawnedObjects).reduce(
- (acc, [id, obj]) => ({
- ...acc,
- [id]: {
- ...obj,
- state: {
- ...obj.state,
- isAnimating: false, // Stop animation
- isDelaying: false, // Clear delays
- delayComplete: false, // Reset delays
- progress: 0, // Reset progress
- },
- },
- }),
- {}
- ),
- };
- return;
- }
-
- // Process delay handling
- if (processState.isProcessDelaying) {
- const effectiveDelayTime =
- processState.processDelayDuration / speedRef.current;
-
- if (
- currentTime - processState.processDelayStartTime >=
- effectiveDelayTime
- ) {
- // console.log(
- // `Process ${process.id} delay completed, resuming animation`
- // );
- newStates[process.id] = {
- ...processState,
- isProcessDelaying: false,
- spawnedObjects: Object.entries(
- processState.spawnedObjects
- ).reduce(
- (acc, [id, obj]) => ({
- ...acc,
- [id]: {
- ...obj,
- state: {
- ...obj.state,
- isDelaying: false,
- delayComplete: true,
- isAnimating: true,
- progress:
- obj.state.progress === 0 ? 0.005 : obj.state.progress,
- },
- },
- }),
- {}
- ),
- };
- return;
- } else {
- return;
- }
- }
-
- // Ensure we have a valid path to follow
- const path =
- process.animationPath?.map((p) => new THREE.Vector3(p.x, p.y, p.z)) ||
- [];
-
- if (path.length < 2) {
- // console.log(
- // `Process ${process.id} has insufficient path points: ${path.length}`
- // );
- return;
- }
-
- const updatedObjects = { ...processState.spawnedObjects };
- let animationOccurring = false; // Track if any animation is happening
-
- Object.entries(processState.spawnedObjects).forEach(
- ([objectId, obj]) => {
- if (!obj.visible) {
- return;
- }
-
- const currentRef = gltf?.scene ? obj.ref.current : obj.ref.current;
- if (!currentRef) {
- // console.log(
- // `No reference for object ${objectId}, skipping animation`
- // );
- return;
- }
-
- // Initialize position for new objects
- if (
- obj.position &&
- obj.state.currentIndex === 0 &&
- obj.state.progress === 0
- ) {
- currentRef.position.copy(obj.position);
- }
-
- const stateRef = obj.state;
-
- // Ensure animation state is properly set for objects
- if (!stateRef.isAnimating && !stateRef.isDelaying && !isConnected) {
- stateRef.isAnimating = true;
- stateRef.progress =
- stateRef.progress > 0 ? stateRef.progress : 0.005;
- }
-
- // Handle delay logic
- if (stateRef.isDelaying) {
- const effectiveDelayTime =
- stateRef.currentDelayDuration / speedRef.current;
-
- if (currentTime - stateRef.delayStartTime >= effectiveDelayTime) {
- // console.log(
- // `Delay complete for object ${objectId}, resuming animation`
- // );
- stateRef.isDelaying = false;
- stateRef.delayComplete = true;
- stateRef.isAnimating = true;
-
- if (stateRef.progress === 0) {
- stateRef.progress = 0.005;
- }
-
- const nextPointIdx = stateRef.currentIndex + 1;
- if (nextPointIdx < path.length) {
- const slightProgress = Math.max(stateRef.progress, 0.005);
- currentRef.position.lerpVectors(
- path[stateRef.currentIndex],
- nextPointIdx < path.length
- ? path[nextPointIdx]
- : path[stateRef.currentIndex],
- slightProgress
- );
- }
- } else {
- updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
- return;
- }
- }
-
- // Skip non-animating objects
- if (!stateRef.isAnimating) {
- // console.log(
- // `Object ${objectId} not animating, skipping animation updates`
- // );
- return;
- }
-
- animationOccurring = true; // Mark that animation is happening
-
- // Handle point actions
- const currentPointData = getPointDataForAnimationIndex(
- process,
- stateRef.currentIndex
- );
-
- // Handle point actions when first arriving at point
- if (stateRef.progress === 0 && currentPointData?.actions) {
- const shouldStop = handlePointActions(
- process.id,
- objectId,
- currentPointData.actions,
- currentTime,
- processedProcesses,
- baseMaterials
- );
- if (shouldStop) {
- updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
- return;
- }
- }
-
- const nextPointIdx = stateRef.currentIndex + 1;
- const isLastPoint = nextPointIdx >= path.length;
-
- // Handle objects at the last point
- if (isLastPoint) {
- const isAgvPicking = agvRef.current.some(
- (agv: any) =>
- agv.processId === process.id && agv.status === "picking"
- );
-
- const shouldHide =
- !currentPointData?.actions ||
- !hasNonInheritActions(currentPointData.actions);
-
- if (shouldHide) {
- if (isAgvPicking) {
- // console.log(
- // `AGV picking at last point for object ${objectId}, hiding object`
- // );
- updatedObjects[objectId] = {
- ...obj,
- visible: false,
- state: {
- ...stateRef,
- isAnimating: false,
- },
- };
- } else {
- tempStackedObjectsRef.current[objectId] = true;
-
- updatedObjects[objectId] = {
- ...obj,
- visible: true,
- state: {
- ...stateRef,
- isAnimating: true,
- },
- };
- }
-
- return;
- }
- }
-
- // Handle stacked objects when AGV picks
- if (tempStackedObjectsRef.current[objectId]) {
- const isAgvPicking = agvRef.current.some(
- (agv: any) =>
- agv.processId === process.id && agv.status === "picking"
- );
-
- if (isAgvPicking) {
- delete tempStackedObjectsRef.current[objectId];
-
- updatedObjects[objectId] = {
- ...obj,
- visible: false,
- state: {
- ...stateRef,
- isAnimating: false,
- },
- };
-
- return;
- }
- }
-
- // Handle normal animation progress for objects not at last point
- if (!isLastPoint) {
- const nextPoint = path[nextPointIdx];
- const distance =
- path[stateRef.currentIndex].distanceTo(nextPoint);
- const effectiveSpeed = stateRef.speed * speedRef.current;
- const movement = effectiveSpeed * delta;
-
- // Ensure progress is always moving forward
- if (stateRef.delayComplete && stateRef.progress < 0.01) {
- stateRef.progress = 0.05;
- stateRef.delayComplete = false;
- // console.log(
- // `Boosting progress for object ${objectId} after delay`
- // );
- } else {
- stateRef.progress += movement / distance;
- // console.log(
- // `Object ${objectId} progress: ${stateRef.progress.toFixed(3)}`
- // );
- }
-
- // Handle point transition
- if (stateRef.progress >= 1) {
- stateRef.currentIndex = nextPointIdx;
- stateRef.progress = 0;
- currentRef.position.copy(nextPoint);
-
- // TRIGGER CHECK - When object arrives at new point
- checkAndCountTriggers(
- process.id,
- objectId,
- stateRef.currentIndex, // The new point index
- processedProcesses,
- currentTime
- );
-
- const newPointData = getPointDataForAnimationIndex(
- process,
- stateRef.currentIndex
- );
-
- // No action needed with newPointData here - will be handled in next frame
- } else {
- // Update position with lerp
- currentRef.position.lerpVectors(
- path[stateRef.currentIndex],
- nextPoint,
- stateRef.progress
- );
- }
- }
-
- updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
- }
- );
-
- // Log if no animation is occurring when it should
- if (!animationOccurring && !isConnected) {
- // console.log(
- // `Warning: No animation occurring for process ${process.id} despite not being connected`
- // );
- }
-
- newStates[process.id] = {
- ...processState,
- spawnedObjects: updatedObjects,
- };
- });
-
- return newStates;
- });
- });
-
- if (!processedProcesses || processedProcesses.length === 0) {
- return null;
- }
-
- return (
-
- {Object.entries(animationStates).flatMap(([processId, processState]) =>
- Object.entries(processState.spawnedObjects)
- .filter(([_, obj]) => obj.visible)
- .map(([objectId, obj]) => {
- const process = processedProcesses.find((p) => p.id === processId);
-
- const renderAs = process?.renderAs || "custom";
-
- return (
-
- );
- })
- )}
-
- );
-};
-
-export default ProcessAnimator;
diff --git a/app/src/modules/simulation/process/processContainer.tsx b/app/src/modules/simulation/process/processContainer.tsx
deleted file mode 100644
index 0bcdb13..0000000
--- a/app/src/modules/simulation/process/processContainer.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React, { useState } from "react";
-import ProcessCreator from "./processCreator";
-import ProcessAnimator from "./processAnimator";
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-
-interface ProcessContainerProps {
- processes: any[];
- setProcesses: React.Dispatch>;
- agvRef: any;
- MaterialRef: any;
- armBots: ArmBotState[];
- setArmBots: React.Dispatch>;
-}
-
-const ProcessContainer: React.FC = ({
- processes,
- setProcesses,
- agvRef,
- MaterialRef,
- armBots,
- setArmBots
-}) => {
- return (
- <>
-
-
- >
- );
-};
-
-export default ProcessContainer;
diff --git a/app/src/modules/simulation/process/processCreator.tsx b/app/src/modules/simulation/process/processCreator.tsx
deleted file mode 100644
index 0a486c9..0000000
--- a/app/src/modules/simulation/process/processCreator.tsx
+++ /dev/null
@@ -1,492 +0,0 @@
-import React, {
- useEffect,
- useMemo,
- useState,
- useCallback,
- useRef,
-} from "react";
-import { useSimulationStates } from "../../../store/store";
-import * as THREE from "three";
-import { useThree } from "@react-three/fiber";
-import {
- ArmBotEventsSchema,
- ConveyorEventsSchema,
- VehicleEventsSchema,
-} from "../../../types/simulationTypes";
-import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
-
-// Type definitions
-export interface PointAction {
- uuid: string;
- name: string;
- type: string;
- material: string;
- delay: number | string;
- spawnInterval: string | number;
- isUsed: boolean;
-}
-
-export interface PointTrigger {
- uuid: string;
- bufferTime: number;
- name: string;
- type: string;
- isUsed: boolean;
-}
-
-// Update the connections type in your interfaces
-export interface PathPoint {
- uuid: string;
- position: [number, number, number];
- actions: PointAction[];
- triggers: PointTrigger[];
- connections: {
- targets: Array<{ modelUUID: string; pointUUID?: string }>;
- };
-}
-
-export interface SimulationPath {
- type: string;
- modeluuid: string;
- points: PathPoint[];
- pathPosition: [number, number, number];
- speed?: number;
- isActive: boolean;
-}
-export interface ArmBot {
- type: string;
- modeluuid: string;
- points: PathPoint[];
- pathPosition: [number, number, number];
- speed?: number;
- isActive: boolean;
-}
-
-export interface Process {
- id: string;
- paths: SimulationPath[];
- animationPath: THREE.Vector3[];
- pointActions: PointAction[][];
- pointTriggers: PointTrigger[][];
- speed: number;
- isActive: boolean;
-}
-
-interface ProcessCreatorProps {
- onProcessesCreated: (processes: Process[]) => void;
-}
-
-// Convert event schemas to SimulationPath
-function convertToSimulationPath(
- path: ConveyorEventsSchema | VehicleEventsSchema | ArmBotEventsSchema
-): SimulationPath {
- const { modeluuid } = path;
-
- // Normalized action handler
- const normalizeAction = (action: any): PointAction => {
- return { ...action }; // Return exact copy with no modifications
- };
-
- // Normalized trigger handler
- const normalizeTrigger = (trigger: any): PointTrigger => {
- return { ...trigger }; // Return exact copy with no modifications
- };
-
- if (path.type === "Conveyor") {
- return {
- type: path.type,
- modeluuid,
- points: path.points.map((point) => ({
- uuid: point.uuid,
- position: point.position,
- actions: Array.isArray(point.actions)
- ? point.actions.map(normalizeAction)
- : point.actions
- ? [normalizeAction(point.actions)]
- : [],
- triggers: Array.isArray(point.triggers)
- ? point.triggers.map(normalizeTrigger)
- : point.triggers
- ? [normalizeTrigger(point.triggers)]
- : [],
- connections: {
- targets: point.connections.targets.map((target) => ({
- modelUUID: target.modelUUID,
- })),
- },
- })),
- pathPosition: path.position,
- speed:
- typeof path.speed === "string"
- ? parseFloat(path.speed) || 1
- : path.speed || 1,
- isActive: false, // Added missing property
- };
- } else if (path.type === "ArmBot") {
- return {
- type: path.type,
- modeluuid,
- points: [
- {
- uuid: path.points.uuid,
- position: path.points.position,
- actions: Array.isArray(path.points.actions)
- ? path.points.actions.map(normalizeAction)
- : path.points.actions
- ? [normalizeAction(path.points.actions)]
- : [],
- triggers: Array.isArray(path.points.triggers)
- ? path.points.triggers.map(normalizeTrigger)
- : path.points.triggers
- ? [normalizeTrigger(path.points.triggers)]
- : [],
- connections: {
- targets: path.points.connections.targets.map((target) => ({
- modelUUID: target.modelUUID,
- pointUUID: target.pointUUID, // Include if available
- })),
- },
- },
- ],
- pathPosition: path.position,
- speed: path.points.actions?.speed || 1,
- isActive: false,
- };
- } else {
- // For vehicle paths, handle the case where triggers might not exist
- return {
- type: path.type,
- modeluuid,
- points: [
- {
- uuid: path.points.uuid,
- position: path.points.position,
- actions: Array.isArray(path.points.actions)
- ? path.points.actions.map(normalizeAction)
- : path.points.actions
- ? [normalizeAction(path.points.actions)]
- : [],
- triggers: [],
- connections: {
- targets: path.points.connections.targets.map((target) => ({
- modelUUID: target.modelUUID,
- })),
- },
- },
- ],
- pathPosition: path.position,
- speed: path.points.speed || 1,
- isActive: false,
- };
- }
-}
-
-// Helper function to create an empty process
-const createEmptyProcess = (): Process => ({
- id: `process-${Math.random().toString(36).substring(2, 11)}`,
- paths: [],
- animationPath: [],
- pointActions: [],
- pointTriggers: [], // Added point triggers array
- speed: 1,
- isActive: false,
-});
-
-// Enhanced connection checking function
-function shouldReverseNextPath(
- currentPath: SimulationPath,
- nextPath: SimulationPath
-): boolean {
- if (nextPath.points.length !== 3) return false;
-
- const currentLastPoint = currentPath.points[currentPath.points.length - 1];
- const nextFirstPoint = nextPath.points[0];
- const nextLastPoint = nextPath.points[nextPath.points.length - 1];
-
- // Check if current last connects to next last (requires reversal)
- const connectsToLast = currentLastPoint.connections.targets.some(
- (target) =>
- target.modelUUID === nextPath.modeluuid &&
- nextLastPoint.connections.targets.some(
- (t) => t.modelUUID === currentPath.modeluuid
- )
- );
-
- // Check if current last connects to next first (no reversal needed)
- const connectsToFirst = currentLastPoint.connections.targets.some(
- (target) =>
- target.modelUUID === nextPath.modeluuid &&
- nextFirstPoint.connections.targets.some(
- (t) => t.modelUUID === currentPath.modeluuid
- )
- );
-
- // Only reverse if connected to last point and not to first point
- return connectsToLast && !connectsToFirst;
-}
-
-// Check if a point has a spawn action
-function hasSpawnAction(point: PathPoint): boolean {
- return point.actions.some((action) => action.type.toLowerCase() === "spawn");
-}
-
-// Ensure spawn point is always at the beginning of the path
-function ensureSpawnPointIsFirst(path: SimulationPath): SimulationPath {
- if (path.points.length !== 3) return path;
-
- // If the third point has spawn action and first doesn't, reverse the array
- if (hasSpawnAction(path.points[2]) && !hasSpawnAction(path.points[0])) {
- return {
- ...path,
- points: [...path.points].reverse(),
- };
- }
-
- return path;
-}
-
-// Updated path adjustment function
-function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
- if (paths.length < 1) return paths;
-
- const adjustedPaths = [...paths];
-
- // First ensure all paths have spawn points at the beginning
- for (let i = 0; i < adjustedPaths.length; i++) {
- adjustedPaths[i] = ensureSpawnPointIsFirst(adjustedPaths[i]);
- }
-
- // Then handle connections between paths
- for (let i = 0; i < adjustedPaths.length - 1; i++) {
- const currentPath = adjustedPaths[i];
- const nextPath = adjustedPaths[i + 1];
-
- if (shouldReverseNextPath(currentPath, nextPath)) {
- const reversedPoints = [
- nextPath.points[2],
- nextPath.points[1],
- nextPath.points[0],
- ];
-
- adjustedPaths[i + 1] = {
- ...nextPath,
- points: reversedPoints,
- };
- }
- }
-
- return adjustedPaths;
-}
-
-// Main hook for process creation
-export function useProcessCreation() {
- const { scene } = useThree();
- 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")
- );
- }, []);
-
- const createProcess = useCallback(
- (paths: SimulationPath[]): Process => {
- if (!paths || paths.length === 0) {
- return createEmptyProcess();
- }
-
- const animationPath: THREE.Vector3[] = [];
- const pointActions: PointAction[][] = [];
- const pointTriggers: PointTrigger[][] = []; // Added point triggers collection
- const processSpeed = paths[0]?.speed || 1;
-
- for (const path of paths) {
- for (const point of path.points) {
- if (path.type === "Conveyor") {
- const obj = scene.getObjectByProperty("uuid", point.uuid);
- if (!obj) {
- console.warn(`Object with UUID ${point.uuid} not found in scene`);
- continue;
- }
-
- const position = obj.getWorldPosition(new THREE.Vector3());
- animationPath.push(position.clone());
- pointActions.push(point.actions);
- pointTriggers.push(point.triggers); // Collect triggers for each point
- }
- }
- }
-
- return {
- id: `process-${Math.random().toString(36).substring(2, 11)}`,
- paths,
- animationPath,
- pointActions,
- pointTriggers,
- speed: processSpeed,
- isActive: false,
- };
- },
- [scene]
- );
-
- const getAllConnectedPaths = useCallback(
- (
- initialPath: SimulationPath,
- allPaths: SimulationPath[],
- visited: Set = new Set()
- ): SimulationPath[] => {
- const connectedPaths: SimulationPath[] = [];
- const queue: SimulationPath[] = [initialPath];
- visited.add(initialPath.modeluuid);
-
- const pathMap = new Map();
- allPaths.forEach((path) => pathMap.set(path.modeluuid, path));
-
- while (queue.length > 0) {
- const currentPath = queue.shift()!;
- connectedPaths.push(currentPath);
-
- // Process outgoing connections
- for (const point of currentPath.points) {
- for (const target of point.connections.targets) {
- if (!visited.has(target.modelUUID)) {
- const targetPath = pathMap.get(target.modelUUID);
- if (targetPath) {
- visited.add(target.modelUUID);
- queue.push(targetPath);
- }
- }
- }
- }
-
- // Process incoming connections
- for (const [uuid, path] of pathMap) {
- if (!visited.has(uuid)) {
- const hasConnectionToCurrent = path.points.some((point) =>
- point.connections.targets.some(
- (t) => t.modelUUID === currentPath.modeluuid
- )
- );
- if (hasConnectionToCurrent) {
- visited.add(uuid);
- queue.push(path);
- }
- }
- }
- }
-
- return connectedPaths;
- },
- []
- );
-
- const createProcessesFromPaths = useCallback(
- (paths: SimulationPath[]): Process[] => {
- if (!paths || paths.length === 0) return [];
-
- const visited = new Set();
- const processes: Process[] = [];
- const pathMap = new Map();
- paths.forEach((path) => pathMap.set(path.modeluuid, path));
-
- for (const path of paths) {
- if (!visited.has(path.modeluuid) && hasSpawnAction(path)) {
- const connectedPaths = getAllConnectedPaths(path, paths, visited);
- const adjustedPaths = adjustPathPointsOrder(connectedPaths);
- const process = createProcess(adjustedPaths);
- processes.push(process);
- }
- }
-
- return processes;
- },
- [createProcess, getAllConnectedPaths, hasSpawnAction]
- );
-
- return {
- processes,
- createProcessesFromPaths,
- setProcesses,
- };
-}
-
-const ProcessCreator: React.FC = React.memo(
- ({ onProcessesCreated }) => {
- const { simulationStates } = useSimulationStates();
- const { createProcessesFromPaths } = useProcessCreation();
- const prevPathsRef = useRef([]);
- const prevProcessesRef = useRef([]);
- const { isPlaying } = usePlayButtonStore();
-
- const convertedPaths = useMemo((): SimulationPath[] => {
- if (!simulationStates) return [];
- return simulationStates.map((path) =>
- convertToSimulationPath(
- path as
- | ConveyorEventsSchema
- | VehicleEventsSchema
- | ArmBotEventsSchema
- )
- );
- }, [simulationStates]);
-
- // Enhanced dependency tracking that includes action and trigger types
- const pathsDependency = useMemo(() => {
- if (!convertedPaths) return null;
- return convertedPaths.map((path) => ({
- id: path.modeluuid,
- // Track all action types for each point
- actionSignature: path.points
- .map((point, index) =>
- point.actions.map((action) => `${index}-${action.type}`).join("|")
- )
- .join(","),
- // Track all trigger types for each point
- triggerSignature: path.points
- .map((point, index) =>
- point.triggers
- .map((trigger) => `${index}-${trigger.type}`)
- .join("|")
- )
- .join(","),
- connections: path.points
- .flatMap((p: PathPoint) =>
- p.connections.targets.map((t: { modelUUID: string }) => t.modelUUID)
- )
- .join(","),
- isActive: false,
- }));
- }, [convertedPaths]);
-
- // Force process recreation when paths change
- useEffect(() => {
- if (!convertedPaths || convertedPaths.length === 0) {
- if (prevProcessesRef.current.length > 0) {
- onProcessesCreated([]);
- prevProcessesRef.current = [];
- }
- return;
- }
-
- // Always regenerate processes if the pathsDependency has changed
- // This ensures action and trigger type changes will be detected
- const newProcesses = createProcessesFromPaths(convertedPaths);
- prevPathsRef.current = convertedPaths;
-
- // Always update processes when action or trigger types change
- onProcessesCreated(newProcesses);
- prevProcessesRef.current = newProcesses;
- }, [
- pathsDependency, // This now includes action and trigger types
- onProcessesCreated,
- convertedPaths,
- createProcessesFromPaths,
- ]);
-
- return null;
- }
-);
-
-export default ProcessCreator;
diff --git a/app/src/modules/simulation/process/processObject.tsx b/app/src/modules/simulation/process/processObject.tsx
deleted file mode 100644
index 01ef41d..0000000
--- a/app/src/modules/simulation/process/processObject.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import React, { useMemo } from "react";
-import * as THREE from "three";
-import { GLTF } from "three-stdlib";
-import { SpawnedObject } from "./types";
-
-interface ProcessObjectProps {
- objectId: string;
- obj: SpawnedObject;
- renderAs?: "box" | "custom";
- gltf?: GLTF;
-}
-
-const ProcessObject: React.FC = ({
- objectId,
- obj,
- renderAs = "custom",
- gltf,
-}) => {
- const renderedObject = useMemo(() => {
- if (renderAs === "box") {
- return (
- }
- material={obj.material}
- position={obj.position}
- >
-
-
- );
- }
-
- if (gltf?.scene) {
- const clonedScene = gltf.scene.clone();
- clonedScene.traverse((child) => {
- if (child instanceof THREE.Mesh) {
- child.material = obj.material;
- }
- });
-
- return (
- }
- position={obj.position}
- >
-
-
- );
- }
-
- return null;
- }, [objectId, obj, renderAs, gltf]);
-
- return renderedObject;
-};
-
-export default ProcessObject;
diff --git a/app/src/modules/simulation/process/types.ts b/app/src/modules/simulation/process/types.ts
deleted file mode 100644
index 9c9a1bc..0000000
--- a/app/src/modules/simulation/process/types.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import * as THREE from "three";
-
-export interface Trigger {
- uuid: string;
- name: string;
- type: string;
- bufferTime: number;
- isUsed: boolean;
-}
-
-export interface PointAction {
- uuid: string;
- name: string;
- type: "Inherit" | "Spawn" | "Despawn" | "Delay" | "Swap";
- objectType: string;
- material: string;
- delay: string | number;
- spawnInterval: string | number;
- isUsed: boolean;
- hitCount?: number;
-}
-
-export interface ProcessPoint {
- uuid: string;
- position: number[];
- rotation: number[];
- actions: PointAction[];
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- triggers?: Trigger[];
-}
-export interface ProcessPath {
- modeluuid: string;
- modelName: string;
- points: ProcessPoint[];
- pathPosition: number[];
- pathRotation: number[];
- speed: number;
- type: "Conveyor" | "Vehicle" | "ArmBot";
- isActive: boolean
-}
-
-export interface ProcessData {
- id: string;
- paths: ProcessPath[];
- animationPath: { x: number; y: number; z: number }[];
- pointActions: PointAction[][];
- speed: number;
- customMaterials?: Record;
- renderAs?: "box" | "custom";
- pointTriggers: [];
-}
-
-export interface AnimationState {
- currentIndex: number;
- progress: number;
- isAnimating: boolean;
- speed: number;
- isDelaying: boolean;
- delayStartTime: number;
- currentDelayDuration: number;
- delayComplete: boolean;
- currentPathIndex: number;
-}
-
-export interface SpawnedObject {
- ref: React.RefObject;
- state: AnimationState;
- visible: boolean;
- material: THREE.Material;
- spawnTime: number;
- currentMaterialType: string;
- position: THREE.Vector3;
-}
-
-export interface ProcessAnimationState {
- spawnedObjects: { [objectId: string]: SpawnedObject };
- nextSpawnTime: number;
- objectIdCounter: number;
- isProcessDelaying: boolean;
- processDelayStartTime: number;
- processDelayDuration: number;
- hasSpawnedZeroIntervalObject?: boolean;
-}
diff --git a/app/src/modules/simulation/process/useProcessAnimations.tsx b/app/src/modules/simulation/process/useProcessAnimations.tsx
deleted file mode 100644
index 579ee3f..0000000
--- a/app/src/modules/simulation/process/useProcessAnimations.tsx
+++ /dev/null
@@ -1,665 +0,0 @@
-import { useCallback, useEffect, useRef, useState } from "react";
-import * as THREE from "three";
-import {
- ProcessData,
- ProcessAnimationState,
- SpawnedObject,
- AnimationState,
- ProcessPoint,
- PointAction,
- Trigger,
-} from "./types";
-import {
- useAnimationPlaySpeed,
- usePauseButtonStore,
- usePlayButtonStore,
- useResetButtonStore,
-} from "../../../store/usePlayButtonStore";
-import { usePlayAgv } from "../../../store/store";
-
-interface ArmBotProcess {
- triggerId: string;
- startPoint: string;
- endPoint: string;
-}
-
-// Enhanced ProcessAnimationState with trigger tracking
-interface EnhancedProcessAnimationState extends ProcessAnimationState {
- triggerCounts: Record;
- triggerLogs: Array<{
- timestamp: number;
- pointId: string;
- objectId: string;
- triggerId: string;
- }>;
-}
-
-interface ProcessContainerProps {
- processes: ProcessData[];
- setProcesses: React.Dispatch>;
- agvRef: any;
-}
-
-interface PlayAgvState {
- playAgv: Record;
- setPlayAgv: (data: any) => void;
-}
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-
-export const useProcessAnimation = (
- processes: ProcessData[],
- setProcesses: React.Dispatch>,
- agvRef: any,
- armBots: ArmBotState[],
- setArmBots: React.Dispatch>
-) => {
- // State and refs initialization
- const { isPlaying, setIsPlaying } = usePlayButtonStore();
- const { isPaused, setIsPaused } = usePauseButtonStore();
- const { isReset, setReset } = useResetButtonStore();
- const debugRef = useRef(false);
- const clockRef = useRef(new THREE.Clock());
- const pauseTimeRef = useRef(0);
- const elapsedBeforePauseRef = useRef(0);
- const animationStatesRef = useRef>({});
- const { speed } = useAnimationPlaySpeed();
- const prevIsPlaying = useRef(null);
- const [internalResetFlag, setInternalResetFlag] = useState(false);
- const [animationStates, setAnimationStates] = useState>({});
- const speedRef = useRef(speed);
- const { PlayAgv, setPlayAgv } = usePlayAgv();
-
- // Effect hooks
- useEffect(() => {
- speedRef.current = speed;
- }, [speed]);
-
- useEffect(() => {
- if (prevIsPlaying.current !== null || !isPlaying) {
- setAnimationStates({});
- }
- prevIsPlaying.current = isPlaying;
- }, [isPlaying]);
-
- useEffect(() => {
- animationStatesRef.current = animationStates;
- }, [animationStates]);
-
- // Reset handler
- useEffect(() => {
- if (isReset) {
- setInternalResetFlag(true);
- setIsPlaying(false);
- setIsPaused(false);
- setAnimationStates({});
- animationStatesRef.current = {};
- clockRef.current = new THREE.Clock();
- elapsedBeforePauseRef.current = 0;
- pauseTimeRef.current = 0;
- setReset(false);
- setTimeout(() => {
- setInternalResetFlag(false);
- setIsPlaying(true);
- }, 0);
- }
- }, [isReset, setReset, setIsPlaying, setIsPaused]);
-
- // Pause handler
- useEffect(() => {
- if (isPaused) {
- pauseTimeRef.current = clockRef.current.getElapsedTime();
- } else if (pauseTimeRef.current > 0) {
- const pausedDuration = clockRef.current.getElapsedTime() - pauseTimeRef.current;
- elapsedBeforePauseRef.current += pausedDuration;
- }
- }, [isPaused]);
-
- // Initialize animation states with trigger tracking
- useEffect(() => {
- if (isPlaying && !internalResetFlag) {
- const newStates: Record = {};
-
- processes.forEach((process) => {
- const triggerCounts: Record = {};
-
- // Initialize trigger counts for all On-Hit triggers
- process.paths?.forEach((path) => {
- path.points?.forEach((point) => {
- point.triggers?.forEach((trigger: Trigger) => {
- if (trigger.type === "On-Hit" && trigger.isUsed) {
- triggerCounts[`${point.uuid}-${trigger.uuid}`] = 0;
- }
- });
- });
- });
-
- newStates[process.id] = {
- spawnedObjects: {},
- nextSpawnTime: 0,
- objectIdCounter: 0,
- isProcessDelaying: false,
- processDelayStartTime: 0,
- processDelayDuration: 0,
- triggerCounts,
- triggerLogs: [],
- };
- });
-
- setAnimationStates(newStates);
- animationStatesRef.current = newStates;
- clockRef.current.start();
- }
- }, [isPlaying, processes, internalResetFlag]);
-
- useEffect(() => {
- if (isPlaying && !internalResetFlag) {
- const newStates: Record = {};
-
- // Initialize AGVs for each process first
- processes.forEach((process) => {
- // Find all vehicle paths for this process
- const vehiclePaths = process.paths?.filter(
- (path) => path.type === "Vehicle"
- ) || [];
-
- // Initialize AGVs for each vehicle path
- vehiclePaths.forEach((vehiclePath) => {
- if (vehiclePath.points?.length > 0) {
- const vehiclePoint = vehiclePath.points[0];
- const action = vehiclePoint.actions?.[0];
- const maxHitCount = action?.hitCount;
-
- const vehicleId = vehiclePath.modeluuid;
- const processId = process.id;
-
- // Check if this AGV already exists
- const existingAgv = agvRef.current.find(
- (v: any) => v.vehicleId === vehicleId && v.processId === processId
- );
-
- if (!existingAgv) {
- // Initialize the AGV in a stationed state
- agvRef.current.push({
- processId,
- vehicleId,
- maxHitCount: maxHitCount || 0,
- isActive: false,
- hitCount: 0,
- status: 'stationed',
- lastUpdated: 0
- });
- }
- }
- });
-
- // Then initialize trigger counts as before
- const triggerCounts: Record = {};
- process.paths?.forEach((path) => {
- path.points?.forEach((point) => {
- point.triggers?.forEach((trigger: Trigger) => {
- if (trigger.type === "On-Hit" && trigger.isUsed) {
- triggerCounts[`${point.uuid}-${trigger.uuid}`] = 0;
- }
- });
- });
- });
-
- newStates[process.id] = {
- spawnedObjects: {},
- nextSpawnTime: 0,
- objectIdCounter: 0,
- isProcessDelaying: false,
- processDelayStartTime: 0,
- processDelayDuration: 0,
- triggerCounts,
- triggerLogs: [],
- };
- });
-
- setAnimationStates(newStates);
- animationStatesRef.current = newStates;
- clockRef.current.start();
- }
- }, [isPlaying, processes, internalResetFlag]);
-
- // Helper functions
- const findSpawnPoint = (process: ProcessData): ProcessPoint | null => {
- for (const path of process.paths || []) {
- for (const point of path.points || []) {
- const spawnAction = point.actions?.find(
- (a) => a.isUsed && a.type === "Spawn"
- );
- if (spawnAction) {
- return point;
- }
- }
- }
- return null;
- };
-
- const findAnimationPathPoint = (
- process: ProcessData,
- spawnPoint: ProcessPoint
- ): THREE.Vector3 => {
- if (process.animationPath && process.animationPath.length > 0) {
- let pointIndex = 0;
- for (const path of process.paths || []) {
- for (let i = 0; i < (path.points?.length || 0); i++) {
- const point = path.points?.[i];
- if (point && point.uuid === spawnPoint.uuid) {
- if (process.animationPath[pointIndex]) {
- const p = process.animationPath[pointIndex];
- return new THREE.Vector3(p.x, p.y, p.z);
- }
- }
- pointIndex++;
- }
- }
- }
- return new THREE.Vector3(
- spawnPoint.position[0],
- spawnPoint.position[1],
- spawnPoint.position[2]
- );
- };
-
- // Optimized object creation
- const createSpawnedObject = useCallback(
- (
- process: ProcessData,
- currentTime: number,
- materialType: string,
- spawnPoint: ProcessPoint,
- baseMaterials: Record
- ): SpawnedObject => {
- const processMaterials = {
- ...baseMaterials,
- ...(process.customMaterials || {}),
- };
-
- const spawnPosition = findAnimationPathPoint(process, spawnPoint);
- const material =
- processMaterials[materialType as keyof typeof processMaterials] ||
- baseMaterials.Default;
-
- return {
- ref: { current: null },
- state: {
- currentIndex: 0,
- progress: 0,
- isAnimating: true,
- speed: process.speed || 1,
- isDelaying: false,
- delayStartTime: 0,
- currentDelayDuration: 0,
- delayComplete: false,
- currentPathIndex: 0,
- },
- visible: true,
- material: material,
- currentMaterialType: materialType,
- spawnTime: currentTime,
- position: spawnPosition,
- };
- },
- []
- );
-
- // Material handling
- const handleMaterialSwap = useCallback(
- (
- processId: string,
- objectId: string,
- materialType: string,
- processes: ProcessData[],
- baseMaterials: Record
- ) => {
- setAnimationStates((prev) => {
- const processState = prev[processId];
- if (!processState || !processState.spawnedObjects[objectId])
- return prev;
-
- const process = processes.find((p) => p.id === processId);
- if (!process) return prev;
-
- const processMaterials = {
- ...baseMaterials,
- ...(process.customMaterials || {}),
- };
-
- const newMaterial =
- processMaterials[materialType as keyof typeof processMaterials];
- if (!newMaterial) return prev;
-
- return {
- ...prev,
- [processId]: {
- ...processState,
- spawnedObjects: {
- ...processState.spawnedObjects,
- [objectId]: {
- ...processState.spawnedObjects[objectId],
- material: newMaterial,
- currentMaterialType: materialType,
- },
- },
- },
- };
- });
- },
- []
- );
-
- // Point action handler with trigger counting
- const handlePointActions = useCallback(
- (
- processId: string,
- objectId: string,
- actions: PointAction[] = [],
- currentTime: number,
- processes: ProcessData[],
- baseMaterials: Record
- ): boolean => {
- let shouldStopAnimation = false;
-
- actions.forEach((action) => {
- if (!action.isUsed) return;
-
- switch (action.type) {
- case "Delay":
- setAnimationStates((prev) => {
- const processState = prev[processId];
- if (!processState || processState.isProcessDelaying) return prev;
-
- const delayDuration =
- typeof action.delay === "number"
- ? action.delay
- : parseFloat(action.delay as string) || 0;
-
- if (delayDuration > 0) {
- return {
- ...prev,
- [processId]: {
- ...processState,
- isProcessDelaying: true,
- processDelayStartTime: currentTime,
- processDelayDuration: delayDuration,
- spawnedObjects: {
- ...processState.spawnedObjects,
- [objectId]: {
- ...processState.spawnedObjects[objectId],
- state: {
- ...processState.spawnedObjects[objectId].state,
- isAnimating: false,
- isDelaying: true,
- delayStartTime: currentTime,
- currentDelayDuration: delayDuration,
- delayComplete: false,
- },
- },
- },
- },
- };
- }
- return prev;
- });
- shouldStopAnimation = true;
- break;
-
- case "Despawn":
- setAnimationStates((prev) => {
- const processState = prev[processId];
- if (!processState) return prev;
-
- const newSpawnedObjects = { ...processState.spawnedObjects };
- delete newSpawnedObjects[objectId];
-
- return {
- ...prev,
- [processId]: {
- ...processState,
- spawnedObjects: newSpawnedObjects,
- },
- };
- });
- shouldStopAnimation = true;
- break;
-
- case "Swap":
- if (action.material) {
- handleMaterialSwap(
- processId,
- objectId,
- action.material,
- processes,
- baseMaterials
- );
- }
- break;
-
- default:
- break;
- }
- });
-
- return shouldStopAnimation;
- },
- [handleMaterialSwap]
- );
-
- const deferredArmBotUpdates = useRef<{ uuid: string; triggerId: string }[]>([]);
-
- // Trigger counting system
- const checkAndCountTriggers = useCallback(
- (
- processId: string,
- objectId: string,
- currentPointIndex: number,
- processes: ProcessData[],
- currentTime: number
- ) => {
- setAnimationStates((prev) => {
- const processState = prev[processId];
- if (!processState) return prev;
-
- const process = processes.find((p) => p.id === processId);
- if (!process) return prev;
-
- const point = getPointDataForAnimationIndex(process, currentPointIndex);
- if (!point?.triggers) return prev;
-
- const onHitTriggers = point.triggers.filter((t: Trigger) => t.type === "On-Hit" && t.isUsed);
-
- if (onHitTriggers.length === 0) return prev;
-
- let newTriggerCounts = { ...processState.triggerCounts };
- const newTriggerLogs = [...processState.triggerLogs];
- let shouldLog = false;
-
- const vehiclePaths = process.paths.filter((path) => path.type === "Vehicle");
- const armBotPaths = process.paths.filter((path) => path.type === "ArmBot");
-
- const activeVehicles = vehiclePaths.filter((path) => {
- const vehicleId = path.modeluuid;
- const vehicleEntry = agvRef.current.find((v: any) => v.vehicleId === vehicleId && v.processId === processId);
- return vehicleEntry?.isActive;
- });
-
- // Check if any ArmBot is active for this process
- // const activeArmBots = armBotPaths.filter((path) => {
- // const armBotId = path.modeluuid;
- // const armBotEntry = armBots.find((a: any) => a.uuid === armBotId);
- // return armBotEntry;
- // });
-
- // Only count triggers if no vehicles and no ArmBots are active for this process
-
- if (activeVehicles.length === 0) {
- onHitTriggers.forEach((trigger: Trigger) => {
- const triggerKey = `${point.uuid}-${trigger.uuid}`;
-
- newTriggerCounts[triggerKey] = (newTriggerCounts[triggerKey] || 0) + 1;
-
- newTriggerLogs.push({ timestamp: currentTime, pointId: point.uuid, objectId, triggerId: trigger.uuid, });
-
- const connections = point.connections?.targets || [];
-
- connections.forEach((connection) => {
- const connectedModelUUID = connection.modelUUID;
-
- const matchingArmPath = armBotPaths.find((path) => path.modeluuid === connectedModelUUID);
-
- if (matchingArmPath) {
- deferredArmBotUpdates.current.push({
- uuid: connectedModelUUID,
- triggerId: trigger.uuid,
- });
- } else {
- shouldLog = true;
- }
- });
- });
- }
-
- let processTotalHits = Object.values(newTriggerCounts).reduce((a, b) => a + b, 0);
-
- // Handle logic for vehicles when a trigger is hit
- if (shouldLog) {
- vehiclePaths.forEach((vehiclePath) => {
- if (vehiclePath.points?.length > 0) {
- const vehiclePoint = vehiclePath.points[0];
- const action = vehiclePoint.actions?.[0];
- const maxHitCount = action?.hitCount;
-
- if (maxHitCount !== undefined) {
- const vehicleId = vehiclePath.modeluuid;
- let vehicleEntry = agvRef.current.find(
- (v: any) =>
- v.vehicleId === vehicleId && v.processId === processId
- );
-
- if (!vehicleEntry) {
- vehicleEntry = {
- processId,
- vehicleId,
- maxHitCount: maxHitCount,
- isActive: false,
- hitCount: 0,
- status: "stationed",
- };
- agvRef.current.push(vehicleEntry);
- }
-
- if (!vehicleEntry.isActive) {
- vehicleEntry.hitCount++;
- vehicleEntry.lastUpdated = currentTime;
-
- if (vehicleEntry.hitCount >= vehicleEntry.maxHitCount) {
- vehicleEntry.isActive = true;
- newTriggerCounts = {};
- processTotalHits = 0;
- }
- }
- }
- }
- });
- }
-
- return {
- ...prev,
- [processId]: {
- ...processState,
- triggerCounts: newTriggerCounts,
- triggerLogs: newTriggerLogs,
- totalHits: processTotalHits,
- },
- };
- });
- }, []);
-
- useEffect(() => {
- if (deferredArmBotUpdates.current.length > 0) {
- const updates = [...deferredArmBotUpdates.current];
- deferredArmBotUpdates.current = [];
-
- setArmBots((prev) =>
- prev.map((bot) => {
- const update = updates.find((u) => u.uuid === bot.uuid);
-
- return update
- ? { ...bot, triggerId: update.triggerId, isActive: true }
- : bot;
- })
- );
- }
- }, [animationStates]);
-
- // Utility functions
- const hasNonInheritActions = useCallback(
- (actions: PointAction[] = []): boolean => {
- return actions.some(
- (action) => action.isUsed && action.type !== "Inherit"
- );
- }, []);
-
- const getPointDataForAnimationIndex = useCallback(
- (process: ProcessData, index: number): ProcessPoint | null => {
- if (!process.paths) return null;
-
- let cumulativePoints = 0;
- for (const path of process.paths) {
- const pointCount = path.points?.length || 0;
-
- if (index < cumulativePoints + pointCount) {
- const pointIndex = index - cumulativePoints;
- return path.points?.[pointIndex] || null;
- }
-
- cumulativePoints += pointCount;
- }
-
- return null;
- },
- []
- );
-
- const getTriggerCounts = useCallback((processId: string) => {
- return animationStatesRef.current[processId]?.triggerCounts || {};
- }, []);
-
- const getTriggerLogs = useCallback((processId: string) => {
- return animationStatesRef.current[processId]?.triggerLogs || [];
- }, []);
-
- return {
- animationStates,
- setAnimationStates,
- clockRef,
- elapsedBeforePauseRef,
- speedRef,
- debugRef,
- findSpawnPoint,
- createSpawnedObject,
- handlePointActions,
- hasNonInheritActions,
- getPointDataForAnimationIndex,
- checkAndCountTriggers,
- getTriggerCounts,
- getTriggerLogs,
- processes,
- };
-};
diff --git a/app/src/services/temp.md b/app/src/modules/simulation/products/temp.md
similarity index 100%
rename from app/src/services/temp.md
rename to app/src/modules/simulation/products/temp.md
diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
new file mode 100644
index 0000000..0cd4fe2
--- /dev/null
+++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+function RoboticArmAnimator() {
+ return (
+ <>>
+ )
+}
+
+export default RoboticArmAnimator;
\ No newline at end of file
diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
new file mode 100644
index 0000000..2817906
--- /dev/null
+++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import IKInstance from '../ikInstance/ikInstance';
+import RoboticArmAnimator from '../animator/roboticArmAnimator';
+
+function RoboticArmInstance() {
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
+
+export default RoboticArmInstance;
\ No newline at end of file
diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx
new file mode 100644
index 0000000..52a8610
--- /dev/null
+++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+function IKInstance() {
+ return (
+ <>>
+ )
+}
+
+export default IKInstance;
\ No newline at end of file
diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx
new file mode 100644
index 0000000..d44ddd2
--- /dev/null
+++ b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import IKInstance from './ikInstance/ikInstance';
+
+function IkInstances() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default IkInstances;
\ No newline at end of file
diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx
new file mode 100644
index 0000000..6e8a70a
--- /dev/null
+++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import RoboticArmInstance from './armInstance/roboticArmInstance';
+
+function RoboticArmInstances() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default RoboticArmInstances;
\ No newline at end of file
diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx
new file mode 100644
index 0000000..1270d93
--- /dev/null
+++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx
@@ -0,0 +1,15 @@
+import React from 'react'
+import RoboticArmInstances from './instances/roboticArmInstances';
+import IkInstances from './instances/ikInstances';
+
+function RoboticArm() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default RoboticArm;
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx
index 84d3651..b7bf36d 100644
--- a/app/src/modules/simulation/simulation.tsx
+++ b/app/src/modules/simulation/simulation.tsx
@@ -1,74 +1,36 @@
-import { useState, useRef } from "react";
-import * as THREE from "three";
-import PathCreation from "./path/pathCreation";
-import PathConnector from "./path/pathConnector";
-import useModuleStore from "../../store/useModuleStore";
-import ProcessContainer from "./process/processContainer";
-import Agv from "../builder/agv/agv";
-import ArmBot from "./armbot/ArmBot";
-import StaticMachine from "./staticMachine/staticMachine";
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-
-interface StaticMachineState {
- uuid: string;
- status: string;
- actions: { uuid: string; name: string; buffer: number; material: string; };
- machineTriggerId: string;
- connectedArmBot: string;
-}
+import React, { useEffect } from 'react';
+import { useEventsStore } from '../../store/simulation/useEventsStore';
+import { useProductStore } from '../../store/simulation/useProductStore';
+import Vehicles from './vehicle/vehicles';
+import Points from './events/points/points';
+import Conveyor from './conveyor/conveyor';
+import RoboticArm from './roboticArm/roboticArm';
function Simulation() {
- const { activeModule } = useModuleStore();
- const pathsGroupRef = useRef() as React.MutableRefObject;
- const [armBots, setArmBots] = useState([]);
- const [staticMachines, setStaticMachines] = useState([]);
- const [processes, setProcesses] = useState([]);
- const agvRef = useRef([]);
- const MaterialRef = useRef([]);
+ const { events } = useEventsStore();
+ const { products } = useProductStore();
+
+ useEffect(() => {
+ // console.log('events: ', events);
+ }, [events])
+
+ useEffect(() => {
+ // console.log('products: ', products);
+ }, [products])
return (
<>
- {activeModule === "simulation" && (
- <>
-
-
+
-
+
-
+
+
+
- >
- )}
-
-
>
- );
+ )
}
-export default Simulation;
+export default Simulation
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulationUI.tsx b/app/src/modules/simulation/simulationUI.tsx
deleted file mode 100644
index 055fb36..0000000
--- a/app/src/modules/simulation/simulationUI.tsx
+++ /dev/null
@@ -1,409 +0,0 @@
-// import { useMemo, useState } from 'react';
-// import { useSelectedActionSphere, useToggleView, useSimulationStates, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
-// import * as THREE from 'three';
-// import useModuleStore from '../../store/useModuleStore';
-
-// function SimulationUI() {
-// const { ToggleView } = useToggleView();
-// const { activeModule } = useModuleStore();
-// const { startSimulation, setStartSimulation } = useStartSimulation();
-// const { selectedActionSphere } = useSelectedActionSphere();
-// const { selectedPath, setSelectedPath } = useSelectedPath();
-// const { simulationStates, setSimulationStates } = useSimulationStates();
-// const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
-// const [activeButton, setActiveButton] = useState(null);
-
-// const handleAddAction = () => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) => {
-// if (point.uuid === selectedActionSphere.points.uuid) {
-// const actionIndex = point.actions.length;
-// const newAction = {
-// uuid: THREE.MathUtils.generateUUID(),
-// name: `Action ${actionIndex + 1}`, // Assign action name based on index
-// type: 'Inherit',
-// material: 'Inherit',
-// delay: 'Inherit',
-// spawnInterval: 'Inherit',
-// isUsed: false
-// };
-
-// return { ...point, actions: [...point.actions, newAction] };
-// }
-// return point;
-// }),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleDeleteAction = (uuid: string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleActionSelect = (uuid: string, actionType: string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? {
-// ...point,
-// actions: point.actions.map((action) =>
-// action.uuid === uuid ? { ...action, type: actionType } : action
-// ),
-// }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleMaterialSelect = (uuid: string, material: string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? {
-// ...point,
-// actions: point.actions.map((action) =>
-// action.uuid === uuid ? { ...action, material } : action
-// ),
-// }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleDelayChange = (uuid: string, delay: number | string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? {
-// ...point,
-// actions: point.actions.map((action) =>
-// action.uuid === uuid ? { ...action, delay } : action
-// ),
-// }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? {
-// ...point,
-// actions: point.actions.map((action) =>
-// action.uuid === uuid ? { ...action, spawnInterval } : action
-// ),
-// }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleSpeedChange = (speed: number) => {
-// if (!selectedPath) return;
-
-// const updatedPaths = simulationStates.map((path) =>
-// path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
-// );
-
-// setSimulationStates(updatedPaths);
-// setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
-// };
-
-// const handleAddTrigger = () => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) => {
-// if (point.uuid === selectedActionSphere.points.uuid) {
-// const triggerIndex = point.triggers.length;
-// const newTrigger = {
-// uuid: THREE.MathUtils.generateUUID(),
-// name: `Trigger ${triggerIndex + 1}`, // Assign name based on index
-// type: '',
-// isUsed: false
-// };
-
-// return { ...point, triggers: [...point.triggers, newTrigger] };
-// }
-// return point;
-// }),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleDeleteTrigger = (uuid: string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleTriggerSelect = (uuid: string, triggerType: string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? {
-// ...point,
-// triggers: point.triggers.map((trigger) =>
-// trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
-// ),
-// }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleResetPath = () => {
-// if (!selectedPath) return;
-
-// };
-
-
-// const handleActionToggle = (uuid: string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? {
-// ...point,
-// actions: point.actions.map((action) => ({
-// ...action,
-// isUsed: action.uuid === uuid ? !action.isUsed : false,
-// })),
-// }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const handleTriggerToggle = (uuid: string) => {
-// if (!selectedActionSphere) return;
-
-// const updatedPaths = simulationStates.map((path) => ({
-// ...path,
-// points: path.points.map((point) =>
-// point.uuid === selectedActionSphere.points.uuid
-// ? {
-// ...point,
-// triggers: point.triggers.map((trigger) => ({
-// ...trigger,
-// isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
-// })),
-// }
-// : point
-// ),
-// }));
-
-// setSimulationStates(updatedPaths);
-// };
-
-// const selectedPoint = useMemo(() => {
-// if (!selectedActionSphere) return null;
-// return simulationStates.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.points.uuid);
-// }, [selectedActionSphere, simulationStates]);
-
-// const createPath = () => {
-// setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
-// setDrawMaterialPath(!drawMaterialPath);
-// }
-
-// return (
-// <>
-// {activeModule === "simulation" && (
-//
-// {!ToggleView && (
-// <>
-//
-
-//
-// {!ToggleView && }
-//
-
-// {selectedPath && (
-//
-//
-// handleSpeedChange(parseFloat(e.target.value))}
-// />
-//
-// )}
-
-// {selectedActionSphere && (
-//
-//
-//
-
-// {selectedPoint?.actions.map((action) => (
-//
-//
-//
-//
-
-// {(action.type === 'Spawn' || action.type === 'Swap') && (
-//
-//
-//
-// )}
-
-// {action.type === 'Delay' && (
-//
-//
-// handleDelayChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
-// />
-
-//
-// )}
-
-// {action.type === 'Spawn' && (
-//
-//
-// handleSpawnIntervalChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
-// />
-
-//
-// )}
-//
-//
-// ))}
-
-//
-
-// {selectedPoint?.triggers.map((trigger) => (
-//
-//
-//
-//
-//
-//
-// ))}
-
-
-//
-// )}
-
-// {selectedPath && (
-//
-//
-//
-// )}
-// >
-// )}
-//
-// )}
-// >
-// );
-// }
-
-// export default SimulationUI;
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulationtemp/collider/colliderCreator.tsx b/app/src/modules/simulation/simulationtemp/collider/colliderCreator.tsx
deleted file mode 100644
index ec5e14b..0000000
--- a/app/src/modules/simulation/simulationtemp/collider/colliderCreator.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react'
-
-function ColliderCreator() {
- return (
- <>>
- )
-}
-
-export default ColliderCreator
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulationtemp/path/pathCreator.tsx b/app/src/modules/simulation/simulationtemp/path/pathCreator.tsx
deleted file mode 100644
index c9dd36b..0000000
--- a/app/src/modules/simulation/simulationtemp/path/pathCreator.tsx
+++ /dev/null
@@ -1,407 +0,0 @@
-import { useEffect, useState } from 'react';
-import * as THREE from 'three';
-import { useThree, useFrame } from '@react-three/fiber';
-import { Line, TransformControls } from '@react-three/drei';
-import { useDrawMaterialPath } from '../../../../store/store';
-
-type PathPoint = {
- position: THREE.Vector3;
- rotation: THREE.Quaternion;
- uuid: string;
-};
-
-type PathCreatorProps = {
- simulationStates: PathPoint[][];
- setSimulationStates: React.Dispatch>;
- connections: { start: PathPoint; end: PathPoint }[];
- setConnections: React.Dispatch>
-};
-
-const PathCreator = ({ simulationStates, setSimulationStates, connections, setConnections }: PathCreatorProps) => {
- const { camera, scene, raycaster, pointer, gl } = useThree();
- const { drawMaterialPath } = useDrawMaterialPath();
-
- const [currentPath, setCurrentPath] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }[]>([]);
- const [temporaryPoint, setTemporaryPoint] = useState(null);
- const [selectedPoint, setSelectedPoint] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string } | null>(null);
- const [selectedConnectionPoint, setSelectedConnectionPoint] = useState<{ point: PathPoint; pathIndex: number } | null>(null);
- const [previewConnection, setPreviewConnection] = useState<{ start: PathPoint; end?: THREE.Vector3 } | null>(null);
- const [transformMode, setTransformMode] = useState<'translate' | 'rotate'>('translate');
-
- useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
- if (selectedPoint) {
- if (event.key === 'g') {
- setTransformMode('translate');
- } else if (event.key === 'r') {
- setTransformMode('rotate');
- }
- }
- };
-
- document.addEventListener('keydown', handleKeyDown);
-
- return () => {
- document.removeEventListener('keydown', handleKeyDown);
- };
- }, [selectedPoint]);
-
- useEffect(() => {
- const canvasElement = gl.domElement;
-
- let drag = false;
- let MouseDown = false;
-
- const onMouseDown = () => {
- MouseDown = true;
- drag = false;
- };
-
- const onMouseUp = () => {
- MouseDown = false;
- };
-
- const onMouseMove = () => {
- if (MouseDown) {
- drag = true;
- }
- };
-
- const onContextMenu = (e: any) => {
- e.preventDefault();
- if (drag || e.button === 0) return;
- if (currentPath.length > 1) {
- setSimulationStates((prevPaths) => [...prevPaths, currentPath]);
- }
- setCurrentPath([]);
- setTemporaryPoint(null);
- setPreviewConnection(null);
- setSelectedConnectionPoint(null);
- };
-
- const onMouseClick = (evt: any) => {
- if (drag || evt.button !== 0) return;
-
- evt.preventDefault();
- raycaster.setFromCamera(pointer, camera);
-
- let intersects = raycaster.intersectObjects(scene.children, true);
-
- if (intersects.some((intersect) => intersect.object.name.includes("path-point"))) {
- intersects = [];
- } else {
- intersects = intersects.filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("agv-collider") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.userData.isPathObject &&
- !(intersect.object.type === "GridHelper")
- );
- }
-
- if (intersects.length > 0 && selectedPoint === null) {
- let point = intersects[0].point;
- if (point.y < 0.05) {
- point = new THREE.Vector3(point.x, 0.05, point.z);
- }
- const newPoint = {
- position: point,
- rotation: new THREE.Quaternion(),
- uuid: THREE.MathUtils.generateUUID(),
- };
- setCurrentPath((prevPath) => [...prevPath, newPoint]);
- setTemporaryPoint(null);
- } else {
- setSelectedPoint(null);
- }
- };
-
- if (drawMaterialPath) {
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
- canvasElement.addEventListener("click", onMouseClick);
- canvasElement.addEventListener("contextmenu", onContextMenu);
- } else {
- if (currentPath.length > 1) {
- setSimulationStates((prevPaths) => [...prevPaths, currentPath]);
- }
- setCurrentPath([]);
- setTemporaryPoint(null);
- }
-
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- canvasElement.removeEventListener("click", onMouseClick);
- canvasElement.removeEventListener("contextmenu", onContextMenu);
- };
- }, [camera, scene, raycaster, currentPath, drawMaterialPath, selectedPoint]);
-
- useFrame(() => {
- if (drawMaterialPath && currentPath.length > 0) {
- raycaster.setFromCamera(pointer, camera);
-
- const intersects = raycaster.intersectObjects(scene.children, true).filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("agv-collider") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.userData.isPathObject &&
- !(intersect.object.type === "GridHelper")
- );
-
- if (intersects.length > 0) {
- let point = intersects[0].point;
- if (point.y < 0.05) {
- point = new THREE.Vector3(point.x, 0.05, point.z);
- }
- setTemporaryPoint(point);
- } else {
- setTemporaryPoint(null);
- }
- } else {
- setTemporaryPoint(null);
- }
- });
-
- const handlePointClick = (point: { position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }) => {
- if (currentPath.length === 0 && drawMaterialPath) {
- setSelectedPoint(point);
- } else {
- setSelectedPoint(null);
- }
- };
-
- const handleTransform = (e: any) => {
- if (selectedPoint) {
- const updatedPosition = e.target.object.position.clone();
- const updatedRotation = e.target.object.quaternion.clone();
- const updatedPaths = simulationStates.map((path) =>
- path.map((p) =>
- p.uuid === selectedPoint.uuid ? { ...p, position: updatedPosition, rotation: updatedRotation } : p
- )
- );
- setSimulationStates(updatedPaths);
- }
- };
-
-
- const meshContext = (uuid: string) => {
- const pathIndex = simulationStates.findIndex(path => path.some(point => point.uuid === uuid));
- if (pathIndex === -1) return;
-
- const clickedPoint = simulationStates[pathIndex].find(point => point.uuid === uuid);
- if (!clickedPoint) return;
-
- 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.");
- setSelectedConnectionPoint(null);
- setPreviewConnection(null);
- return;
- }
-
- if (!isStart && !isEnd) {
- console.log("Selected point is not a valid connection point (not start or end)");
- setSelectedConnectionPoint(null);
- setPreviewConnection(null);
- return;
- }
-
- if (connections.some(conn => conn.start.uuid === uuid || conn.end.uuid === uuid)) {
- console.log("The selected point is already connected.");
- setSelectedConnectionPoint(null);
- setPreviewConnection(null);
- return;
- }
-
- if (!selectedConnectionPoint) {
- setSelectedConnectionPoint({ point: clickedPoint, pathIndex });
- setPreviewConnection({ start: clickedPoint });
- console.log("First point selected for connection:", clickedPoint);
- return;
- }
-
- if (selectedConnectionPoint.pathIndex === pathIndex) {
- console.log("Cannot connect points within the same path.");
- setSelectedConnectionPoint(null);
- setPreviewConnection(null);
- return;
- }
-
- if (connections.some(conn => conn.start.uuid === clickedPoint.uuid || conn.end.uuid === clickedPoint.uuid)) {
- console.log("The target point is already connected.");
- setSelectedConnectionPoint(null);
- setPreviewConnection(null);
- return;
- }
-
- setConnections(prevConnections => [
- ...prevConnections,
- { start: selectedConnectionPoint.point, end: clickedPoint },
- ]);
-
-
- setSelectedConnectionPoint(null);
- setPreviewConnection(null);
- };
-
- useEffect(() => {
- if (!selectedConnectionPoint) {
- setPreviewConnection(null);
- }
- }, [selectedConnectionPoint, connections]);
-
- useFrame(() => {
- if (selectedConnectionPoint) {
- raycaster.setFromCamera(pointer, camera);
-
- const intersects = raycaster.intersectObjects(scene.children, true).filter(
- (intersect) =>
- !intersect.object.name.includes("Roof") &&
- !intersect.object.name.includes("agv-collider") &&
- !intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.userData.isPathObject &&
- !(intersect.object.type === "GridHelper")
- );
-
- if (intersects.length > 0) {
- let point = intersects[0].point;
- if (point.y < 0.05) {
- point = new THREE.Vector3(point.x, 0.05, point.z);
- }
- setPreviewConnection({ start: selectedConnectionPoint.point, end: point });
- } else {
- setPreviewConnection(null);
- }
- }
- });
-
- return (
- <>
-
- {/* Render finalized simulationStates */}
- {simulationStates.map((path, pathIndex) => (
-
- point.position)}
- color="yellow"
- lineWidth={5}
- userData={{ isPathObject: true }}
- />
-
- ))}
-
- {/* Render finalized points */}
- {simulationStates.map((path) =>
- path.map((point) => (
- handlePointClick(point)}
- onPointerMissed={() => { setSelectedPoint(null) }}
- onContextMenu={() => { meshContext(point.uuid); }}
- >
-
-
-
- ))
- )}
-
- {connections.map((conn, index) => (
-
- ))}
-
-
-
- {/* Render current path */}
- {currentPath.length > 1 && (
-
- point.position)}
- color="red"
- lineWidth={5}
- userData={{ isPathObject: true }}
- />
-
- )}
-
- {/* Render current path points */}
- {currentPath.map((point) => (
-
-
-
-
- ))}
-
- {/* Render temporary indicator line */}
- {temporaryPoint && currentPath.length > 0 && (
-
-
-
- )}
-
- {/* Render dashed preview connection */}
- {previewConnection && previewConnection.end && (
-
- )}
-
- {/* Render temporary point */}
- {temporaryPoint && (
-
-
-
-
- )}
-
- {/* Attach TransformControls to the selected point */}
- {selectedPoint && (
-
- )}
- >
- );
-};
-
-export default PathCreator;
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulationtemp/path/pathFlow.tsx b/app/src/modules/simulation/simulationtemp/path/pathFlow.tsx
deleted file mode 100644
index 586fd3a..0000000
--- a/app/src/modules/simulation/simulationtemp/path/pathFlow.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-import * as THREE from 'three';
-import { useState, useEffect, useRef, useMemo } from "react";
-import { useLoader, useFrame } from "@react-three/fiber";
-import { GLTFLoader } from "three-stdlib";
-import crate from "../../../../assets/gltf-glb/crate_box.glb";
-import { useOrganization } from '../../../../store/store';
-import { useControls } from 'leva';
-
-type PathPoint = {
- position: THREE.Vector3;
- rotation: THREE.Quaternion;
- uuid: string;
-};
-
-type PathFlowProps = {
- path: PathPoint[];
- connections: { start: PathPoint; end: PathPoint }[];
-};
-
-export default function PathFlow({ path, connections }: PathFlowProps) {
- const { organization } = useOrganization();
- const [isPaused, setIsPaused] = useState(false);
- const [isStopped, setIsStopped] = useState(false);
-
- const { spawnInterval, speed, pauseResume, startStop } = useControls({
- spawnInterval: { value: 1000, min: 500, max: 5000, step: 100 },
- speed: { value: 2, min: 1, max: 20, step: 0.5 },
- pauseResume: { value: false, label: "Pause/Resume" },
- startStop: { value: false, label: "Start/Stop" },
- });
-
- const [meshes, setMeshes] = useState<{ id: number }[]>([]);
- const gltf = useLoader(GLTFLoader, crate);
-
- const meshIdRef = useRef(0);
- const lastSpawnTime = useRef(performance.now());
- const totalPausedTime = useRef(0);
- const pauseStartTime = useRef(null);
-
- useEffect(() => {
- setIsPaused(pauseResume);
- setIsStopped(startStop);
- }, [pauseResume, startStop]);
-
- const removeMesh = (id: number) => {
- setMeshes((prev) => prev.filter((m) => m.id !== id));
- };
-
- useFrame(() => {
- if (isStopped || !path) return;
-
- const now = performance.now();
-
- if (isPaused) {
- if (pauseStartTime.current === null) {
- pauseStartTime.current = now;
- }
- return;
- }
-
- if (pauseStartTime.current !== null) {
- totalPausedTime.current += now - pauseStartTime.current;
- pauseStartTime.current = null;
- }
-
- const adjustedTime = now - totalPausedTime.current;
-
- if (adjustedTime - lastSpawnTime.current >= spawnInterval) {
- setMeshes((prev) => [...prev, { id: meshIdRef.current++ }]);
- lastSpawnTime.current = adjustedTime;
- }
- });
-
- return (
- <>
- {meshes.map((mesh) => (
-
- ))}
- >
- );
-}
-
-function MovingMesh({ meshId, points, speed, gltf, removeMesh, isPaused }: any) {
- const meshRef = useRef();
- const startTime = useRef(null); // Initialize as null
- const pausedTime = useRef(0);
- const pauseStartTime = useRef(null);
-
- const distances = useMemo(() => {
- if (!points || points.length < 2) return [];
- return points.slice(1).map((point: any, i: number) => points[i].position.distanceTo(point.position));
- }, [points]);
-
- useFrame(() => {
- if (!points || points.length < 2) return;
-
- if (startTime.current === null && points.length > 0) {
- startTime.current = performance.now();
- }
-
- if (!meshRef.current) return;
-
- if (isPaused) {
- if (pauseStartTime.current === null) {
- pauseStartTime.current = performance.now();
- }
- return;
- }
-
- if (pauseStartTime.current !== null) {
- pausedTime.current += performance.now() - pauseStartTime.current;
- pauseStartTime.current = null;
- }
-
- if (startTime.current === null) return;
-
- const elapsed = performance.now() - startTime.current - pausedTime.current;
-
- const distanceTraveled = elapsed / 1000 * speed;
-
- let remainingDistance = distanceTraveled;
- let currentSegmentIndex = 0;
-
- while (currentSegmentIndex < distances.length && remainingDistance > distances[currentSegmentIndex]) {
- remainingDistance -= distances[currentSegmentIndex];
- currentSegmentIndex++;
- }
-
- if (currentSegmentIndex >= distances.length) {
- removeMesh(meshId);
- return;
- }
-
- const progress = remainingDistance / distances[currentSegmentIndex];
- const start = points[currentSegmentIndex].position;
- const end = points[currentSegmentIndex + 1].position;
-
- meshRef.current.position.lerpVectors(start, end, Math.min(progress, 1));
-
- const startRotation = points[currentSegmentIndex].rotation;
- const endRotation = points[currentSegmentIndex + 1].rotation;
- const interpolatedRotation = new THREE.Quaternion().slerpQuaternions(startRotation, endRotation, Math.min(progress, 1));
-
- meshRef.current.quaternion.copy(interpolatedRotation);
- });
-
- return (
- <>
- {points && points.length > 0 &&
-
-
-
- }
- >
- );
-}
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulationtemp/process/processCreator.tsx b/app/src/modules/simulation/simulationtemp/process/processCreator.tsx
deleted file mode 100644
index 1c5241d..0000000
--- a/app/src/modules/simulation/simulationtemp/process/processCreator.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react'
-
-function ProcessCreator() {
- return (
- <>>
- )
-}
-
-export default ProcessCreator
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulationtemp/simulation.tsx b/app/src/modules/simulation/simulationtemp/simulation.tsx
deleted file mode 100644
index 1c7847b..0000000
--- a/app/src/modules/simulation/simulationtemp/simulation.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React, { useState } from 'react';
-import * as THREE from 'three';
-import PathCreator from './path/pathCreator';
-import PathFlow from './path/pathFlow';
-
-type PathPoint = {
- position: THREE.Vector3;
- rotation: THREE.Quaternion;
- uuid: string;
-};
-
-function Simulation() {
- const [simulationStates, setSimulationStates] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }[][]>([]);
- const [connections, setConnections] = useState<{ start: PathPoint; end: PathPoint }[]>([]);
-
- return (
- <>
-
- {simulationStates.map((path, index) => (
-
- ))}
- >
- );
-}
-
-export default Simulation;
\ No newline at end of file
diff --git a/app/src/modules/simulation/staticMachine/staticMachine.tsx b/app/src/modules/simulation/staticMachine/staticMachine.tsx
deleted file mode 100644
index 3f61993..0000000
--- a/app/src/modules/simulation/staticMachine/staticMachine.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import React, { useEffect } from 'react'
-import * as SimulationTypes from '../../../types/simulationTypes';
-import { useSimulationStates } from '../../../store/store';
-import StaticMachineInstances from './staticMachineInstances';
-import { useResetButtonStore } from '../../../store/usePlayButtonStore';
-
-interface ArmBotState {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- status: string;
- material: string;
- triggerId: string;
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
- isActive?: boolean;
-}
-interface StaticMachineState {
- uuid: string;
- status: string;
- actions: { uuid: string; name: string; buffer: number; material: string; };
- machineTriggerId: string;
- connectedArmBot: string;
-}
-
-type StaticMachineProps = {
- setArmBots: React.Dispatch>;
- staticMachines: StaticMachineState[];
- setStaticMachines: React.Dispatch>;
-}
-
-function StaticMachine({ setArmBots, staticMachines, setStaticMachines }: StaticMachineProps) {
-
- const { simulationStates } = useSimulationStates();
- const { isReset } = useResetButtonStore();
-
- useEffect(() => {
- const filtered = simulationStates.filter((s): s is SimulationTypes.StaticMachineEventsSchema => s.type === "StaticMachine");
- const initialStates: StaticMachineState[] = filtered
- .filter(machine => machine.points.connections.targets.length > 0)
- .map(machine => ({
- uuid: machine.modeluuid,
- status: "idle",
- actions: machine.points.actions,
- machineTriggerId: machine.points.triggers.uuid,
- connectedArmBot: machine.points.connections.targets[0].modelUUID
- }));
- setStaticMachines(initialStates);
- }, [simulationStates, isReset]);
-
- const updateArmBotTriggerAndMachineStatus = (armBotUuid: string, triggerId: string, machineId: string) => {
- setArmBots((prevArmBots) => {
- return prevArmBots.map(bot => {
- if (bot.uuid === armBotUuid) {
- return { ...bot, triggerId: triggerId };
- }
- return bot;
- });
- });
- setStaticMachines((prevStaticMachines) => {
- return prevStaticMachines.map(machine => {
- if (machine.uuid === machineId) {
- return { ...machine, status: "idle" };
- } else {
- return machine;
- }
- });
- });
- }
-
- return (
- <>
- {staticMachines.map((machine, index) => (
-
- ))}
- >
- )
-}
-
-export default StaticMachine;
\ No newline at end of file
diff --git a/app/src/modules/simulation/staticMachine/staticMachineInstances.tsx b/app/src/modules/simulation/staticMachine/staticMachineInstances.tsx
deleted file mode 100644
index 94a2faa..0000000
--- a/app/src/modules/simulation/staticMachine/staticMachineInstances.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import React, { useEffect } from 'react'
-import { useAnimationPlaySpeed } from '../../../store/usePlayButtonStore';
-
-interface StaticMachineState {
- uuid: string;
- status: string;
- actions: { uuid: string; name: string; buffer: number; material: string; };
- machineTriggerId: string;
- connectedArmBot: string;
-}
-
-type StaticMachineInstancesProps = {
- machine: StaticMachineState,
- updateArmBotTriggerAndMachineStatus: (armBotUuid: string, triggerId: string, machineId: string) => void;
-}
-
-function StaticMachineInstances({ machine, updateArmBotTriggerAndMachineStatus }: StaticMachineInstancesProps) {
- const { speed } = useAnimationPlaySpeed();
-
- useEffect(() => {
- if (machine.status === 'running') {
- setTimeout(() => {
- updateArmBotTriggerAndMachineStatus(machine.connectedArmBot, machine.machineTriggerId, machine.uuid);
- }, machine.actions.buffer * 1000 * speed);
- }
- }, [machine])
-
- return (
- <>>
- )
-}
-
-export default StaticMachineInstances
\ No newline at end of file
diff --git a/app/src/modules/simulation/triggers/temp.md b/app/src/modules/simulation/triggers/temp.md
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/modules/simulation/ui/temp.md b/app/src/modules/simulation/ui/temp.md
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx
new file mode 100644
index 0000000..cf5fd81
--- /dev/null
+++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx
@@ -0,0 +1,62 @@
+import { useEffect, useState } from 'react'
+import { useFrame, useThree } from '@react-three/fiber';
+
+interface VehicleAnimatorProps {
+ path: [number, number, number][];
+ handleCallBack: () => void;
+ currentPhase: string;
+ agvUuid: number
+}
+
+
+function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) {
+ const [progress, setProgress] = useState(0)
+ const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
+ const { scene } = useThree();
+
+ useEffect(() => {
+
+ if (currentPhase === 'stationed-pickup' && path.length > 0) {
+ setCurrentPath(path);
+ }
+
+ }, [currentPhase, path])
+
+ useFrame((_, delta) => {
+ if (!path || path.length < 2) return;
+
+ const object = scene.getObjectByProperty("uuid", agvUuid)
+ if (!object) return;
+
+ setProgress(prev => {
+ const next = prev + delta * 0.1; // speed
+ return next >= 1 ? 1 : next;
+ });
+
+ const totalSegments = path.length - 1;
+ const segmentIndex = Math.floor(progress * totalSegments);
+ const t = progress * totalSegments - segmentIndex;
+
+ const start = path[segmentIndex];
+ const end = path[segmentIndex + 1] || start;
+
+ // Directly set position without creating a new Vector3
+ object.position.x = start[0] + (end[0] - start[0]) * t;
+ object.position.y = start[1] + (end[1] - start[1]) * t;
+ object.position.z = start[2] + (end[2] - start[2]) * t;
+ });
+ // useFrame(() => {
+ // if (currentPath.length === 0) return;
+ // const object = scene.getObjectByProperty("uuid", agvUuid);
+ // if (!object) return;
+
+
+
+ // })
+ return (
+ <>
+ >
+ )
+}
+
+export default VehicleAnimator
\ No newline at end of file
diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx
new file mode 100644
index 0000000..bf767ec
--- /dev/null
+++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx
@@ -0,0 +1,66 @@
+import React, { useCallback, useEffect, useState } from 'react'
+import VehicleAnimator from '../animator/vehicleAnimator'
+import * as THREE from "three";
+import { NavMeshQuery } from '@recast-navigation/core';
+import { useNavMesh } from '../../../../../store/store';
+import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
+import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
+
+function VehicleInstance({ agvDetails }: any) {
+ const { navMesh } = useNavMesh();
+ const { isPlaying } = usePlayButtonStore();
+ const { setVehicleActive, setVehicleState } = useVehicleStore();
+ const [currentPhase, setCurrentPhase] = useState<(string)>("stationed");
+ const [path, setPath] = useState<[number, number, number][]>([]);
+
+ const computePath = useCallback((start: any, end: any) => {
+
+
+ try {
+ const navMeshQuery = new NavMeshQuery(navMesh);
+ const { path: segmentPath } = navMeshQuery.computePath(start, end);
+ return (
+ segmentPath?.map(
+ ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]
+ ) || []
+ );
+ } catch {
+ return [];
+ }
+ }, [navMesh]);
+
+ useEffect(() => {
+
+
+ if (isPlaying) {
+ if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") {
+ const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint);
+ setPath(toPickupPath)
+ setVehicleActive(agvDetails.modelUuid, true)
+ setVehicleState(agvDetails.modelUuid, "running")
+ setCurrentPhase("stationed-pickup")
+ //
+ }
+ }
+ }, [agvDetails, currentPhase, path, isPlaying])
+
+ function handleCallBack() {
+ if (currentPhase === "stationed-pickup") {
+ setVehicleActive(agvDetails.modelUuid, false)
+ setVehicleState(agvDetails.modelUuid, "idle")
+ setCurrentPhase("picking")
+ setPath([])
+ }
+ }
+
+
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default VehicleInstance
\ No newline at end of file
diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
new file mode 100644
index 0000000..0848883
--- /dev/null
+++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
@@ -0,0 +1,19 @@
+import React from 'react'
+import VehicleInstance from './instance/vehicleInstance'
+import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
+
+function VehicleInstances() {
+ const { vehicles } = useVehicleStore();
+
+ return (
+ <>
+
+ {vehicles.map((val: any, i: any) =>
+
+ )}
+
+ >
+ )
+}
+
+export default VehicleInstances
\ No newline at end of file
diff --git a/app/src/modules/builder/agv/navMeshCreator.tsx b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx
similarity index 73%
rename from app/src/modules/builder/agv/navMeshCreator.tsx
rename to app/src/modules/simulation/vehicle/navMesh/navMesh.tsx
index c0f8808..8652172 100644
--- a/app/src/modules/builder/agv/navMeshCreator.tsx
+++ b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx
@@ -1,15 +1,15 @@
import { useRef } from "react";
-import { useNavMesh } from "../../../store/store";
+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";
+import * as CONSTANTS from "../../../../types/world/worldConstants";
+import * as Types from "../../../../types/world/worldTypes";
-type NavMeshCreatorProps = {
+type NavMeshProps = {
lines: Types.RefLines
};
-function NavMeshCreator({ lines }: NavMeshCreatorProps) {
+function NavMesh({ lines }: NavMeshProps) {
let groupRef = useRef() as Types.RefGroup;
const { setNavMesh } = useNavMesh();
@@ -28,4 +28,4 @@ function NavMeshCreator({ lines }: NavMeshCreatorProps) {
)
}
-export default NavMeshCreator
\ No newline at end of file
+export default NavMesh
\ No newline at end of file
diff --git a/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx
new file mode 100644
index 0000000..aee91e0
--- /dev/null
+++ b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx
@@ -0,0 +1,64 @@
+import React, { useEffect } from "react";
+import { init as initRecastNavigation } from "@recast-navigation/core";
+import { generateSoloNavMesh } from "@recast-navigation/generators";
+import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three";
+import { useThree } from "@react-three/fiber";
+import * as THREE from "three";
+import * as Types from "../../../../types/world/worldTypes";
+
+interface NavMeshDetailsProps {
+ setNavMesh: (navMesh: any) => void;
+ groupRef: React.MutableRefObject;
+ lines: Types.RefLines;
+}
+
+export default function NavMeshDetails({
+ lines,
+ setNavMesh,
+ groupRef,
+}: NavMeshDetailsProps) {
+ const { scene } = useThree();
+
+ useEffect(() => {
+ const initializeNavigation = async () => {
+ try {
+ await initRecastNavigation();
+
+ if (!groupRef.current || groupRef.current.children.length === 0) {
+ return;
+ }
+
+ const meshes = groupRef?.current?.children as THREE.Mesh[];
+
+ const [positions, indices] = getPositionsAndIndices(meshes);
+
+ const cellSize = 0.2;
+ const cellHeight = 0.7;
+ const walkableRadius = 0.5;
+ const { success, navMesh } = generateSoloNavMesh(positions, indices, {
+ cs: cellSize,
+ ch: cellHeight,
+ walkableRadius: Math.round(walkableRadius / cellHeight),
+ });
+
+ if (!success || !navMesh) {
+ return;
+ }
+
+ setNavMesh(navMesh);
+
+ scene.children
+ .filter((child) => child instanceof DebugDrawer)
+ .forEach((child) => scene.remove(child));
+
+ const debugDrawer = new DebugDrawer();
+ debugDrawer.drawNavMesh(navMesh);
+ // scene.add(debugDrawer);
+ } catch (error) { }
+ };
+
+ initializeNavigation();
+ }, [scene, groupRef, lines.current]);
+
+ return null;
+}
diff --git a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
new file mode 100644
index 0000000..fa0d9dd
--- /dev/null
+++ b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
@@ -0,0 +1,119 @@
+import * as THREE from "three";
+import { useEffect } from "react";
+import * as turf from "@turf/turf";
+import * as Types from "../../../../types/world/worldTypes";
+import arrayLinesToObject from "../../../builder/geomentries/lines/lineConvertions/arrayLinesToObject";
+
+interface PolygonGeneratorProps {
+ groupRef: React.MutableRefObject;
+ lines: Types.RefLines;
+}
+
+export default function PolygonGenerator({
+ groupRef,
+ lines,
+}: PolygonGeneratorProps) {
+
+ useEffect(() => {
+ let allLines = arrayLinesToObject(lines.current);
+ const wallLines = allLines?.filter((line) => line?.type === "WallLine");
+ const aisleLines = allLines?.filter((line) => line?.type === "AisleLine");
+
+ const wallPoints = wallLines
+ .map((pair) => pair?.line.map((vals) => vals.position))
+ .filter((wall): wall is THREE.Vector3[] => !!wall);
+
+ const result = aisleLines.map((pair) =>
+ pair?.line.map((point) => ({
+ position: [point.position.x, point.position.z],
+ uuid: point.uuid,
+ }))
+ );
+
+ if (!result || result.some((line) => !line)) {
+ return;
+ }
+
+ const lineFeatures = result?.map((line: any) =>
+ turf.lineString(line.map((p: any) => p?.position))
+ );
+
+ const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
+ renderWallGeometry(wallPoints);
+
+ if (polygons.features.length > 1) {
+ polygons.features.forEach((feature) => {
+ if (feature.geometry.type === "Polygon") {
+
+ const shape = new THREE.Shape();
+ const coords = feature.geometry.coordinates[0];
+
+ shape.moveTo(coords[0][0], coords[0][1]);
+
+ for (let i = 1; i < coords.length; i++) {
+ shape.lineTo(coords[i][0], coords[i][1]);
+ }
+ shape.lineTo(coords[0][0], coords[0][1]);
+
+ const extrudeSettings = {
+ depth: 5,
+ bevelEnabled: false,
+ };
+
+ const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
+
+ const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 });
+ const mesh = new THREE.Mesh(geometry, material);
+ mesh.rotateX(Math.PI / 2);
+ mesh.name = "agv-collider";
+ mesh.position.y = 5;
+
+ mesh.receiveShadow = true;
+ groupRef.current?.add(mesh);
+ }
+ });
+ }
+
+ }, [lines.current]);
+
+ const renderWallGeometry = (walls: THREE.Vector3[][]) => {
+ walls.forEach((wall) => {
+ if (wall.length < 2) return;
+
+ for (let i = 0; i < wall.length - 1; i++) {
+ const start = new THREE.Vector3(wall[i].x, wall[i].y, wall[i].z);
+ const end = new THREE.Vector3(
+ wall[i + 1].x,
+ wall[i + 1].y,
+ wall[i + 1].z
+ );
+
+ const wallHeight = 10;
+ const direction = new THREE.Vector3().subVectors(end, start);
+ const length = direction.length();
+ direction.normalize();
+
+ const wallGeometry = new THREE.BoxGeometry(length, wallHeight);
+ const wallMaterial = new THREE.MeshBasicMaterial({
+ color: "#aaa",
+ transparent: true,
+ opacity: 0.5,
+ });
+
+ const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
+ const midPoint = new THREE.Vector3()
+ .addVectors(start, end)
+ .multiplyScalar(0.5);
+ wallMesh.position.set(midPoint.x, wallHeight / 2, midPoint.z);
+
+ const quaternion = new THREE.Quaternion();
+ quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction);
+ wallMesh.quaternion.copy(quaternion);
+
+ groupRef.current?.add(wallMesh);
+ }
+ });
+ };
+
+ return null;
+}
diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx
new file mode 100644
index 0000000..3364717
--- /dev/null
+++ b/app/src/modules/simulation/vehicle/vehicles.tsx
@@ -0,0 +1,121 @@
+import React, { useEffect } from 'react'
+import VehicleInstances from './instances/vehicleInstances';
+
+import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
+
+function Vehicles() {
+
+ const { vehicles, addVehicle } = useVehicleStore();
+
+ const vehicleStatusSample: VehicleEventSchema[] = [
+ {
+ modelUuid: "veh-123",
+ modelName: "Autonomous Truck A1",
+ position: [10, 0, 5],
+ rotation: [0, 0, 0],
+ state: "idle",
+ type: "vehicle",
+ speed: 2.5,
+ point: {
+ uuid: "point-789",
+ position: [0, 1, 0],
+ rotation: [0, 0, 0],
+ action: {
+ actionUuid: "action-456",
+ actionName: "Deliver to Zone A",
+ actionType: "travel",
+ material: "crate",
+ unLoadDuration: 15,
+ loadCapacity: 5,
+ pickUpPoint: { x: 5, y: 0, z: 3 },
+ unLoadPoint: { x: 20, y: 0, z: 10 },
+ triggers: [
+ {
+ triggerUuid: "trig-001",
+ triggerName: "Start Travel",
+ triggerType: "onComplete",
+ delay: 0,
+ triggeredAsset: {
+ triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
+ triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
+ triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
+ }
+ },
+ {
+ triggerUuid: "trig-002",
+ triggerName: "Complete Travel",
+ triggerType: "onComplete",
+ delay: 2,
+ triggeredAsset: null
+ }
+ ]
+ }
+ }
+ },
+ {
+ modelUuid: "veh-123",
+ modelName: "Autonomous Truck A1",
+ position: [10, 0, 5],
+ rotation: [0, 0, 0],
+ state: "idle",
+ type: "vehicle",
+ speed: 2.5,
+ point: {
+ uuid: "point-789",
+ position: [0, 1, 0],
+ rotation: [0, 0, 0],
+ action: {
+ actionUuid: "action-456",
+ actionName: "Deliver to Zone A",
+ actionType: "travel",
+ material: "crate",
+ unLoadDuration: 15,
+ loadCapacity: 5,
+ pickUpPoint: { x: 5, y: 0, z: 3 },
+ unLoadPoint: { x: 20, y: 0, z: 10 },
+ triggers: [
+ {
+ triggerUuid: "trig-001",
+ triggerName: "Start Travel",
+ triggerType: "onStart",
+ delay: 0,
+ triggeredAsset: {
+ triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
+ triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
+ triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
+ }
+ },
+ {
+ triggerUuid: "trig-002",
+ triggerName: "Complete Travel",
+ triggerType: "onComplete",
+ delay: 2,
+ triggeredAsset: null
+ }
+ ]
+ }
+ }
+ }
+ ];
+
+
+ useEffect(() => {
+ addVehicle('123', vehicleStatusSample[0]);
+ addVehicle('123', vehicleStatusSample[1]);
+ }, [])
+
+ useEffect(() => {
+ // console.log('vehicles: ', vehicles);
+ }, [vehicles])
+
+
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+export default Vehicles;
\ No newline at end of file
diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx
index e039592..cd2c57c 100644
--- a/app/src/modules/visualization/RealTimeVisulization.tsx
+++ b/app/src/modules/visualization/RealTimeVisulization.tsx
@@ -2,25 +2,25 @@ import React, { useEffect, useState, useRef } from "react";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import Panel from "./widgets/panel/Panel";
import AddButtons from "./widgets/panel/AddButtons";
-import { useSelectedZoneStore } from "../../store/useZoneStore";
-import DisplayZone from "./DisplayZone";
+import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
+import DisplayZone from "./zone/DisplayZone";
import Scene from "../scene/scene";
import useModuleStore from "../../store/useModuleStore";
import {
useDroppedObjectsStore,
useFloatingWidget,
-} from "../../store/useDroppedObjectsStore";
+} from "../../store/visualization/useDroppedObjectsStore";
import {
useAsset3dWidget,
useSocketStore,
useWidgetSubOption,
useZones,
} from "../../store/store";
-import { getZone2dData } from "../../services/realTimeVisulization/zoneData/getZoneData";
+import { getZone2dData } from "../../services/visulization/zone/getZoneData";
import { generateUniqueId } from "../../functions/generateUniqueId";
import { determinePosition } from "./functions/determinePosition";
-import { addingFloatingWidgets } from "../../services/realTimeVisulization/zoneData/addFloatingWidgets";
+import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets";
import SocketRealTimeViz from "./socket/realTimeVizSocket.dev";
import RenderOverlay from "../../components/templates/Overlay";
import ConfirmationPopup from "../../components/layout/confirmationPopup/ConfirmationPopup";
@@ -30,8 +30,7 @@ import {
useEditWidgetOptionsStore,
useRightClickSelected,
useRightSelected,
-} from "../../store/useZone3DWidgetStore";
-import Dropped3dWidgets from "./widgets/3d/Dropped3dWidget";
+} from "../../store/visualization/useZone3DWidgetStore";
import OuterClick from "../../utils/outerClick";
import { useWidgetStore } from "../../store/useWidgetStore";
import { getActiveProperties } from "./functions/getActiveProperties";
diff --git a/app/src/modules/scene/mqttTemp/drieHtmlTemp.tsx b/app/src/modules/visualization/mqttTemp/drieHtmlTemp.tsx
similarity index 89%
rename from app/src/modules/scene/mqttTemp/drieHtmlTemp.tsx
rename to app/src/modules/visualization/mqttTemp/drieHtmlTemp.tsx
index 68c8c37..3e0adba 100644
--- a/app/src/modules/scene/mqttTemp/drieHtmlTemp.tsx
+++ b/app/src/modules/visualization/mqttTemp/drieHtmlTemp.tsx
@@ -1,109 +1,109 @@
-import { Html } from "@react-three/drei";
-import * as THREE from "three";
-import * as Types from "../../../types/world/worldTypes";
-import { useDrieTemp, useDrieUIValue } from "../../../store/store"
-import UI from "./ui";
-import { useEffect } from "react";
-import { useThree } from "@react-three/fiber";
-
-export default function DrieHtmlTemp({ itemsGroup }: { itemsGroup: Types.RefGroup }) {
- const { drieTemp, setDrieTemp } = useDrieTemp();
- const { drieUIValue, setDrieUIValue } = useDrieUIValue();
- const state = useThree();
- const { camera, raycaster } = state;
-
- useEffect(() => {
- const canvasElement = state.gl.domElement;
- let drag = false;
- let isLeftMouseDown = false;
-
- const onMouseDown = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = true;
- drag = false;
- }
- };
-
- const onMouseMove = () => {
- if (isLeftMouseDown) {
- drag = true;
- }
- };
-
- const onMouseUp = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = false;
- if (drag) return;
- if (!itemsGroup.current) return
- let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
- if (intersects.length > 0) {
- let currentObject = intersects[0].object;
-
- while (currentObject) {
- if (currentObject.name === "Scene") {
- break;
- }
- currentObject = currentObject.parent as THREE.Object3D;
- }
- if (currentObject && (currentObject.userData.name === "SV2 Controll pannel" || currentObject.userData.name === "forklift")) {
- const worldPos = new THREE.Vector3();
- currentObject.getWorldPosition(worldPos);
-
- const rightOffset = new THREE.Vector3(1, 0, 0);
- const upOffset = new THREE.Vector3(0, 1, 0);
-
- currentObject.localToWorld(rightOffset);
- currentObject.localToWorld(upOffset);
-
- const finalPosition = worldPos.clone().addScaledVector(rightOffset.sub(currentObject.position).normalize(), 2.5).addScaledVector(upOffset.sub(currentObject.position).normalize(), 2.3);
-
- setDrieTemp(finalPosition);
- } else {
- setDrieTemp(undefined);
- }
- }
- else {
- setDrieTemp(undefined);
- }
- }
- };
-
-
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
-
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- };
- }, [])
-
- return (
- <>
- {drieTemp &&
-
-
-
-
-
- }
- >
- )
+import { Html } from "@react-three/drei";
+import * as THREE from "three";
+import * as Types from "../../../types/world/worldTypes";
+import { useDrieTemp, useDrieUIValue } from "../../../store/store"
+import UI from "./ui";
+import { useEffect } from "react";
+import { useThree } from "@react-three/fiber";
+
+export default function DrieHtmlTemp() {
+ const { drieTemp, setDrieTemp } = useDrieTemp();
+ const { drieUIValue, setDrieUIValue } = useDrieUIValue();
+ const state = useThree();
+ const { camera, raycaster, scene } = state;
+
+ useEffect(() => {
+ const canvasElement = state.gl.domElement;
+ let drag = false;
+ let isLeftMouseDown = false;
+
+ const onMouseDown = (evt: any) => {
+ if (evt.button === 0) {
+ isLeftMouseDown = true;
+ drag = false;
+ }
+ };
+
+ const onMouseMove = () => {
+ if (isLeftMouseDown) {
+ drag = true;
+ }
+ };
+
+ const onMouseUp = (evt: any) => {
+ if (evt.button === 0) {
+ isLeftMouseDown = false;
+ if (drag) return;
+ if (!scene) return
+ let intersects = raycaster.intersectObjects(scene.children, true);
+ if (intersects.length > 0) {
+ let currentObject = intersects[0].object;
+
+ while (currentObject) {
+ if (currentObject.name === "Scene") {
+ break;
+ }
+ currentObject = currentObject.parent as THREE.Object3D;
+ }
+ if (currentObject && (currentObject.userData.name === "SV2 Controll pannel" || currentObject.userData.name === "forklift")) {
+ const worldPos = new THREE.Vector3();
+ currentObject.getWorldPosition(worldPos);
+
+ const rightOffset = new THREE.Vector3(1, 0, 0);
+ const upOffset = new THREE.Vector3(0, 1, 0);
+
+ currentObject.localToWorld(rightOffset);
+ currentObject.localToWorld(upOffset);
+
+ const finalPosition = worldPos.clone().addScaledVector(rightOffset.sub(currentObject.position).normalize(), 2.5).addScaledVector(upOffset.sub(currentObject.position).normalize(), 2.3);
+
+ setDrieTemp(finalPosition);
+ } else {
+ setDrieTemp(undefined);
+ }
+ }
+ else {
+ setDrieTemp(undefined);
+ }
+ }
+ };
+
+
+ canvasElement.addEventListener("mousedown", onMouseDown);
+ canvasElement.addEventListener("mouseup", onMouseUp);
+ canvasElement.addEventListener("mousemove", onMouseMove);
+
+ return () => {
+ canvasElement.removeEventListener("mousedown", onMouseDown);
+ canvasElement.removeEventListener("mouseup", onMouseUp);
+ canvasElement.removeEventListener("mousemove", onMouseMove);
+ };
+ }, [])
+
+ return (
+ <>
+ {drieTemp &&
+
+
+
+
+
+ }
+ >
+ )
}
\ No newline at end of file
diff --git a/app/src/modules/scene/mqttTemp/ui.jsx b/app/src/modules/visualization/mqttTemp/ui.jsx
similarity index 97%
rename from app/src/modules/scene/mqttTemp/ui.jsx
rename to app/src/modules/visualization/mqttTemp/ui.jsx
index 4d4c5fb..cafff38 100644
--- a/app/src/modules/scene/mqttTemp/ui.jsx
+++ b/app/src/modules/visualization/mqttTemp/ui.jsx
@@ -1,141 +1,141 @@
-export default function UI({ temperature, humidity, touch, header }) {
- return (
-
-
- {header ? header : "Sensor Details"}
-
-
-
-
-
- Temperature
-
-
- {temperature}
-
-
-
-
-
- Humidity
-
-
- {humidity}
-
-
-
-
-
-
- Touch Sensor
-
-
- {touch === "True" ? "Active" : "In active"}
-
-
-
-
- );
-}
+export default function UI({ temperature, humidity, touch, header }) {
+ return (
+
+
+ {header ? header : "Sensor Details"}
+
+
+
+
+
+ Temperature
+
+
+ {temperature}
+
+
+
+
+
+ Humidity
+
+
+ {humidity}
+
+
+
+
+
+
+ Touch Sensor
+
+
+ {touch === "True" ? "Active" : "In active"}
+
+
+
+
+ );
+}
diff --git a/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx b/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx
index b5291a3..1dbc175 100644
--- a/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx
+++ b/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx
@@ -1,8 +1,8 @@
import { useEffect } from "react";
import { useSocketStore } from "../../../store/store";
-import { useSelectedZoneStore } from "../../../store/useZoneStore";
-import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
-import { useZoneWidgetStore } from "../../../store/useZone3DWidgetStore";
+import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
+import { useDroppedObjectsStore } from "../../../store/visualization/useDroppedObjectsStore";
+import { useZoneWidgetStore } from "../../../store/visualization/useZone3DWidgetStore";
import useTemplateStore from "../../../store/useTemplateStore";
type WidgetData = {
diff --git a/app/src/modules/visualization/template/Templates.tsx b/app/src/modules/visualization/template/Templates.tsx
index 8370112..e0ece1c 100644
--- a/app/src/modules/visualization/template/Templates.tsx
+++ b/app/src/modules/visualization/template/Templates.tsx
@@ -1,9 +1,9 @@
import { useEffect } from "react";
import useTemplateStore from "../../../store/useTemplateStore";
-import { useSelectedZoneStore } from "../../../store/useZoneStore";
+import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
import { useSocketStore } from "../../../store/store";
-import { getTemplateData } from "../../../services/realTimeVisulization/zoneData/getTemplate";
-import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
+import { getTemplateData } from "../../../services/visulization/zone/getTemplate";
+import { useDroppedObjectsStore } from "../../../store/visualization/useDroppedObjectsStore";
import RenameInput from "../../../components/ui/inputs/RenameInput";
diff --git a/app/src/modules/visualization/visualization.tsx b/app/src/modules/visualization/visualization.tsx
new file mode 100644
index 0000000..e5b1692
--- /dev/null
+++ b/app/src/modules/visualization/visualization.tsx
@@ -0,0 +1,26 @@
+import React from 'react'
+import Dropped3dWidgets from './widgets/3d/Dropped3dWidget'
+import ZoneCentreTarget from './zone/zoneCameraTarget'
+import ZoneAssets from './zone/zoneAssets'
+import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents'
+import DrieHtmlTemp from './mqttTemp/drieHtmlTemp'
+
+const Visualization = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+ >
+ )
+}
+
+export default Visualization;
\ No newline at end of file
diff --git a/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx b/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx
index f865719..0c8fe6f 100644
--- a/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx
+++ b/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx
@@ -13,13 +13,11 @@ import {
KebabIcon,
} from "../../../../components/icons/ExportCommonIcons";
import { useEffect, useRef, useState } from "react";
-import { duplicateWidgetApi } from "../../../../services/realTimeVisulization/zoneData/duplicateWidget";
-import { deleteWidgetApi } from "../../../../services/realTimeVisulization/zoneData/deleteWidgetApi";
import { useClickOutside } from "../../functions/handleWidgetsOuterClick";
import { useSocketStore } from "../../../../store/store";
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
import OuterClick from "../../../../utils/outerClick";
-import useChartStore from "../../../../store/useChartStore";
+import useChartStore from "../../../../store/visualization/useChartStore";
type Side = "top" | "bottom" | "left" | "right";
diff --git a/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx
index 4f3cfd9..e68e1d3 100644
--- a/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx
+++ b/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx
@@ -192,7 +192,7 @@ import io from "socket.io-client";
import axios from "axios";
import { useThemeStore } from "../../../../../store/useThemeStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
interface ChartComponentProps {
id: string;
diff --git a/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx
index 3108d09..74d3fec 100644
--- a/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx
+++ b/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx
@@ -5,7 +5,7 @@ import io from "socket.io-client";
import axios from "axios";
import { useThemeStore } from "../../../../../store/useThemeStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
interface ChartComponentProps {
id: string;
diff --git a/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx
index 4a6906a..9e5d616 100644
--- a/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx
+++ b/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx
@@ -4,7 +4,7 @@ import io from "socket.io-client";
import axios from "axios";
import { useThemeStore } from "../../../../../store/useThemeStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
interface ChartComponentProps {
diff --git a/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx
index b77e964..931d567 100644
--- a/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx
+++ b/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx
@@ -189,7 +189,7 @@ import io from "socket.io-client";
import axios from "axios";
import { useThemeStore } from "../../../../../store/useThemeStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
interface ChartComponentProps {
diff --git a/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx
index e4056dc..d5024d6 100644
--- a/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx
+++ b/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx
@@ -4,7 +4,7 @@ import io from "socket.io-client";
import axios from "axios";
import { useThemeStore } from "../../../../../store/useThemeStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
interface ChartComponentProps {
diff --git a/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx b/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx
index 70f09a2..5d1f59e 100644
--- a/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx
+++ b/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx
@@ -3,7 +3,7 @@ import { Line } from "react-chartjs-2";
import io from "socket.io-client";
import axios from "axios";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { StockIncreseIcon } from "../../../../../components/icons/RealTimeVisulationIcons";
diff --git a/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx b/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx
index 67ae415..325445c 100644
--- a/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx
+++ b/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx
@@ -3,7 +3,7 @@ import { Line } from "react-chartjs-2";
import io from "socket.io-client";
import axios from "axios";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { StockIncreseIcon } from "../../../../../components/icons/RealTimeVisulationIcons";
diff --git a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx
index 6acc994..4ca3c31 100644
--- a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx
+++ b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx
@@ -4,21 +4,17 @@ import React, { useEffect, useRef, useState } from "react";
import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../../store/store";
import useModuleStore from "../../../../store/useModuleStore";
import { ThreeState } from "../../../../types/world/worldTypes";
-import { useSelectedZoneStore } from "../../../../store/useZoneStore";
-import { useEditWidgetOptionsStore, useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../../store/useZone3DWidgetStore";
-import { use3DWidget } from "../../../../store/useDroppedObjectsStore";
-import { get3dWidgetZoneData } from "../../../../services/realTimeVisulization/zoneData/get3dWidgetData";
+import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore";
+import { useEditWidgetOptionsStore, useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../../store/visualization/useZone3DWidgetStore";
+import { use3DWidget } from "../../../../store/visualization/useDroppedObjectsStore";
+import { get3dWidgetZoneData } from "../../../../services/visulization/zone/get3dWidgetData";
import { generateUniqueId } from "../../../../functions/generateUniqueId";
import ProductionCapacity from "./cards/ProductionCapacity";
import ReturnOfInvestment from "./cards/ReturnOfInvestment";
import StateWorking from "./cards/StateWorking";
import Throughput from "./cards/Throughput";
import { useWidgetStore } from "../../../../store/useWidgetStore";
-import useChartStore from "../../../../store/useChartStore";
-
-
-
-
+import useChartStore from "../../../../store/visualization/useChartStore";
type WidgetData = {
id: string;
@@ -48,7 +44,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 });
const { setSelectedChartId } = useWidgetStore();
- const { measurements, duration} = useChartStore();
+ const { measurements, duration } = useChartStore();
let [floorPlanesVertical, setFloorPlanesVertical] = useState(
new THREE.Plane(new THREE.Vector3(0, 1, 0))
);
@@ -121,7 +117,6 @@ export default function Dropped3dWidgets() {
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
);
@@ -158,7 +153,6 @@ export default function Dropped3dWidgets() {
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
- !intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
);
// Update widget's position in memory
@@ -173,28 +167,28 @@ export default function Dropped3dWidgets() {
const onDrop = (event: any) => {
event.preventDefault();
event.stopPropagation();
-
+
hasEntered.current = false;
-
+
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
-
+
const newWidget = createdWidgetRef.current;
if (!newWidget || !widgetSelect.startsWith("ui")) return;
-
+
// ✅ Extract 2D drop position
let [x, y, z] = newWidget.position;
-
+
// ✅ Clamp Y to at least 0
y = Math.max(y, 0);
newWidget.position = [x, y, z];
-
+
// ✅ Prepare polygon from selectedZone.points
const points3D = selectedZone.points as Array<[number, number, number]>;
const zonePolygonXZ = points3D.map(([x, , z]) => [x, z] as [number, number]);
-
+
const isInside = isPointInPolygon([x, z], zonePolygonXZ);
-
+
// ✅ Remove temp widget
const prevWidgets = useZoneWidgetStore.getState().zoneWidgetData[selectedZone.zoneId] || [];
const cleanedWidgets = prevWidgets.filter(w => w.id !== newWidget.id);
@@ -204,29 +198,29 @@ export default function Dropped3dWidgets() {
[selectedZone.zoneId]: cleanedWidgets,
},
}));
-
+
// (Optional) Prevent adding if dropped outside zone
// if (!isInside) {
// createdWidgetRef.current = null;
// return;
// }
-
+
// ✅ Add widget
addWidget(selectedZone.zoneId, newWidget);
-
+
const add3dWidget = {
organization,
widget: newWidget,
zoneId: selectedZone.zoneId,
};
-
+
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget);
}
-
+
createdWidgetRef.current = null;
};
-
+
canvasElement.addEventListener("dragenter", handleDragEnter);
@@ -262,7 +256,7 @@ export default function Dropped3dWidgets() {
widgetToDuplicate.position[2] + 0.5,
],
rotation: widgetToDuplicate.rotation || [0, 0, 0],
- Data:{
+ Data: {
measurements: measurements,
duration: duration
},
@@ -369,7 +363,7 @@ export default function Dropped3dWidgets() {
// floorPlanesVertical,
// planeIntersect.current
// );
-
+
// setintersectcontextmenu(intersect1.y);
if (rightSelect === "RotateX" || rightSelect === "RotateY") {
@@ -389,7 +383,7 @@ export default function Dropped3dWidgets() {
rotationStartRef.current = selectedWidget.rotation || [0, 0, 0];
}
}
-
+
};
const handleMouseMove = (event: MouseEvent) => {
@@ -433,7 +427,7 @@ export default function Dropped3dWidgets() {
intersect.z + horizontalZ,
];
-
+
updateWidgetPosition(selectedZoneId, rightClickSelected, newPosition);
}
}
@@ -441,24 +435,24 @@ export default function Dropped3dWidgets() {
if (rightSelect === "Vertical Move") {
const intersect = raycaster.ray.intersectPlane(floorPlanesVertical, planeIntersect.current);
-
+
if (intersect && typeof intersectcontextmenu === "number") {
const diff = intersect.y - intersectcontextmenu;
const unclampedY = selectedWidget.position[1] + diff;
const newY = Math.max(0, unclampedY); // Prevent going below floor (y=0)
-
+
setintersectcontextmenu(intersect.y);
-
+
const newPosition: [number, number, number] = [
selectedWidget.position[0],
newY,
selectedWidget.position[2],
];
-
+
updateWidgetPosition(selectedZoneId, rightClickSelected, newPosition);
}
}
-
+
if (rightSelect?.startsWith("Rotate")) {
const axis = rightSelect.slice(-1).toLowerCase(); // "x", "y", or "z"
const currentX = event.pageX;
diff --git a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx
index 274d6dd..6666452 100644
--- a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx
+++ b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx
@@ -15,7 +15,7 @@ import {
import axios from "axios";
import io from "socket.io-client";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
// Register ChartJS components
ChartJS.register(
diff --git a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx
index 5a975f1..6aeafa6 100644
--- a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx
+++ b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx
@@ -16,7 +16,7 @@ import {
import axios from "axios";
import io from "socket.io-client";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { WavyIcon } from "../../../../../components/icons/3dChartIcons";
// Register Chart.js components
diff --git a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx
index 4d10955..048dd7d 100644
--- a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx
+++ b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx
@@ -4,7 +4,7 @@ import React, { useEffect, useMemo, useState } from "react";
import axios from "axios";
import io from "socket.io-client";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
// import image from "../../../../assets/image/temp/image.png";
interface StateWorkingProps {
diff --git a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx
index 67397bd..857813c 100644
--- a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx
+++ b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx
@@ -18,7 +18,7 @@ import {
import axios from "axios";
import io from "socket.io-client";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { ThroughputIcon } from "../../../../../components/icons/3dChartIcons";
// Register Chart.js components
diff --git a/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx b/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx
index cfe29aa..b4a328e 100644
--- a/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx
+++ b/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx
@@ -3,18 +3,18 @@ import { useEffect, useRef, useState } from "react";
import {
useDroppedObjectsStore,
Zones,
-} from "../../../../store/useDroppedObjectsStore";
+} from "../../../../store/visualization/useDroppedObjectsStore";
import useModuleStore from "../../../../store/useModuleStore";
import { determinePosition } from "../../functions/determinePosition";
import { getActiveProperties } from "../../functions/getActiveProperties";
-import { addingFloatingWidgets } from "../../../../services/realTimeVisulization/zoneData/addFloatingWidgets";
+import { addingFloatingWidgets } from "../../../../services/visulization/zone/addFloatingWidgets";
import {
DublicateIcon,
KebabIcon,
DeleteIcon,
} from "../../../../components/icons/ExportCommonIcons";
import DistanceLines from "./DistanceLines"; // Import the DistanceLines component
-import { deleteFloatingWidgetApi } from "../../../../services/realTimeVisulization/zoneData/deleteFloatingWidget";
+import { deleteFloatingWidgetApi } from "../../../../services/visulization/zone/deleteFloatingWidget";
import TotalCardComponent from "./cards/TotalCardComponent";
import WarehouseThroughputComponent from "./cards/WarehouseThroughputComponent";
@@ -23,7 +23,7 @@ import { useWidgetStore } from "../../../../store/useWidgetStore";
import { useSocketStore } from "../../../../store/store";
import { useClickOutside } from "../../functions/handleWidgetsOuterClick";
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
-import { useSelectedZoneStore } from "../../../../store/useZoneStore";
+import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore";
interface DraggingState {
zone: string;
index: number;
diff --git a/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx b/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx
index f50bec9..bdaf648 100644
--- a/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx
+++ b/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { Line } from "react-chartjs-2";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import io from "socket.io-client";
diff --git a/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx b/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx
index 6e8d692..61096c5 100644
--- a/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx
+++ b/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { Line } from "react-chartjs-2";
-import useChartStore from "../../../../../store/useChartStore";
+import useChartStore from "../../../../../store/visualization/useChartStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import io from "socket.io-client";
diff --git a/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx b/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx
index 012c2e7..67793f9 100644
--- a/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx
+++ b/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'
import { Line } from 'react-chartjs-2'
-import useChartStore from '../../../../../store/useChartStore';
+import useChartStore from '../../../../../store/visualization/useChartStore';
import { useWidgetStore } from '../../../../../store/useWidgetStore';
import axios from 'axios';
import io from "socket.io-client";
diff --git a/app/src/modules/visualization/widgets/panel/AddButtons.tsx b/app/src/modules/visualization/widgets/panel/AddButtons.tsx
index 5d45d3f..d066cd4 100644
--- a/app/src/modules/visualization/widgets/panel/AddButtons.tsx
+++ b/app/src/modules/visualization/widgets/panel/AddButtons.tsx
@@ -6,8 +6,8 @@ import {
} from "../../../../components/icons/RealTimeVisulationIcons";
import { AddIcon } from "../../../../components/icons/ExportCommonIcons";
import { useSocketStore } from "../../../../store/store";
-import { clearPanel } from "../../../../services/realTimeVisulization/zoneData/clearPanel";
-import { lockPanel } from "../../../../services/realTimeVisulization/zoneData/lockPanel";
+import { clearPanel } from "../../../../services/visulization/zone/clearPanel";
+import { lockPanel } from "../../../../services/visulization/zone/lockPanel";
// Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right";
diff --git a/app/src/modules/visualization/DisplayZone.tsx b/app/src/modules/visualization/zone/DisplayZone.tsx
similarity index 92%
rename from app/src/modules/visualization/DisplayZone.tsx
rename to app/src/modules/visualization/zone/DisplayZone.tsx
index e2f3b2f..578bdab 100644
--- a/app/src/modules/visualization/DisplayZone.tsx
+++ b/app/src/modules/visualization/zone/DisplayZone.tsx
@@ -1,18 +1,18 @@
import React, { useEffect, useRef, useState, useCallback } from "react";
-import { useWidgetStore, Widget } from "../../store/useWidgetStore";
+import { useWidgetStore, Widget } from "../../../store/useWidgetStore";
import {
useDroppedObjectsStore,
useFloatingWidget,
-} from "../../store/useDroppedObjectsStore";
-import { getSelect2dZoneData } from "../../services/realTimeVisulization/zoneData/getSelect2dZoneData";
-import { getFloatingZoneData } from "../../services/realTimeVisulization/zoneData/getFloatingData";
-import { get3dWidgetZoneData } from "../../services/realTimeVisulization/zoneData/get3dWidgetData";
+} from "../../../store/visualization/useDroppedObjectsStore";
+import { getSelect2dZoneData } from "../../../services/visulization/zone/getSelect2dZoneData";
+import { getFloatingZoneData } from "../../../services/visulization/zone/getFloatingData";
+import { get3dWidgetZoneData } from "../../../services/visulization/zone/get3dWidgetData";
import {
MoveArrowLeft,
MoveArrowRight,
-} from "../../components/icons/SimulationIcons";
-import { InfoIcon } from "../../components/icons/ExportCommonIcons";
+} from "../../../components/icons/SimulationIcons";
+import { InfoIcon } from "../../../components/icons/ExportCommonIcons";
// Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right";
diff --git a/app/src/modules/visualization/zoneAssets.tsx b/app/src/modules/visualization/zone/zoneAssets.tsx
similarity index 89%
rename from app/src/modules/visualization/zoneAssets.tsx
rename to app/src/modules/visualization/zone/zoneAssets.tsx
index 7a48196..af8b849 100644
--- a/app/src/modules/visualization/zoneAssets.tsx
+++ b/app/src/modules/visualization/zone/zoneAssets.tsx
@@ -1,8 +1,8 @@
import React, { useEffect, useRef } from 'react'
-import { useSelectedFloorItem, useZoneAssetId } from '../../store/store';
+import { useSelectedFloorItem, useZoneAssetId } from '../../../store/store';
import * as THREE from "three";
import { useThree } from '@react-three/fiber';
-import * as Types from "../../types/world/worldTypes";
+import * as Types from "../../../types/world/worldTypes";
export default function ZoneAssets() {
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
const { setSelectedFloorItem } = useSelectedFloorItem();
@@ -10,7 +10,6 @@ export default function ZoneAssets() {
useEffect(() => {
// console.log('zoneAssetId: ', zoneAssetId);
if (!zoneAssetId) return
- console.log('zoneAssetId: ', zoneAssetId);
let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id);
if (AssetMesh) {
const bbox = new THREE.Box3().setFromObject(AssetMesh);
@@ -30,20 +29,17 @@ export default function ZoneAssets() {
setSelectedFloorItem(AssetMesh);
} else {
- console.log('zoneAssetId: ', zoneAssetId)
if (Array.isArray(zoneAssetId.position) && zoneAssetId.position.length >= 3) {
let selectedAssetPosition = [
zoneAssetId.position[0],
10,
zoneAssetId.position[2]
];
- console.log('selectedAssetPosition: ', selectedAssetPosition);
let selectedAssetTarget = [
zoneAssetId.position[0],
zoneAssetId.position[1],
zoneAssetId.position[2]
];
- console.log('selectedAssetTarget: ', selectedAssetTarget);
const setCam = async () => {
await controls?.setLookAt(...selectedAssetPosition, ...selectedAssetTarget, true);
setTimeout(() => {
diff --git a/app/src/modules/visualization/functions/zoneCameraTarget.tsx b/app/src/modules/visualization/zone/zoneCameraTarget.tsx
similarity index 97%
rename from app/src/modules/visualization/functions/zoneCameraTarget.tsx
rename to app/src/modules/visualization/zone/zoneCameraTarget.tsx
index f022b32..d1587de 100644
--- a/app/src/modules/visualization/functions/zoneCameraTarget.tsx
+++ b/app/src/modules/visualization/zone/zoneCameraTarget.tsx
@@ -1,7 +1,7 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
-import { useSelectedZoneStore } from "../../../store/useZoneStore";
+import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
import { useEditPosition, usezonePosition, usezoneTarget } from "../../../store/store";
export default function ZoneCentreTarget() {
diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setEventsApt.ts b/app/src/services/factoryBuilder/assest/floorAsset/setEventsApt.ts
deleted file mode 100644
index b419963..0000000
--- a/app/src/services/factoryBuilder/assest/floorAsset/setEventsApt.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
-
-export const setEventApi = async (
- organization: string,
- modeluuid: string,
- eventData: any
-) => {
- try {
- const body: any = { organization, modeluuid, eventData };
-
- const response = await fetch(`${url_Backend_dwinzo}/api/v2/eventDataUpdate`, {
- method: "PATCH",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(body),
- });
-
- if (!response.ok) {
- throw new Error("Failed to set or Update Event Data");
- }
-
- const result = await response.json();
- return result;
- } catch (error) {
- if (error instanceof Error) {
- throw new Error(error.message);
- } else {
- throw new Error("An unknown error occurred");
- }
- }
-};
\ No newline at end of file
diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts
index 3e156cb..d587f06 100644
--- a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts
+++ b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts
@@ -8,13 +8,9 @@ export const setFloorItemApi = async (
rotation?: Object,
isLocked?: boolean,
isVisible?: boolean,
- eventData?: any
) => {
try {
const body: any = { organization, modeluuid, modelname, position, rotation, modelfileID, isLocked, isVisible };
- if (eventData) {
- body.eventData = eventData;
- }
const response = await fetch(`${url_Backend_dwinzo}/api/v2/setasset`, {
method: "POST",
diff --git a/app/src/services/simulation/getAssetEventType.ts b/app/src/services/simulation/getAssetEventType.ts
deleted file mode 100644
index 84433ec..0000000
--- a/app/src/services/simulation/getAssetEventType.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
-
-export const getAssetEventType = async (modelId: string, organization: string) => {
- try {
- const response = await fetch(`${url_Backend_dwinzo}/api/v2/pointData/${modelId}/${organization}`, {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- },
- });
-
- if (!response.ok) {
- throw new Error("Failed to fetch model event type");
- }
-
- const result = await response.json();
- return result;
- } catch (error) {
- if (error instanceof Error) {
- throw new Error(error.message);
- } else {
- throw new Error("An unknown error occurred");
- }
- }
-};
\ No newline at end of file
diff --git a/app/src/services/simulation/temp.md b/app/src/services/simulation/temp.md
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/services/visulization/temp.md b/app/src/services/visulization/temp.md
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts b/app/src/services/visulization/zone/add3dWidget.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/add3dWidget.ts
rename to app/src/services/visulization/zone/add3dWidget.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts b/app/src/services/visulization/zone/addFloatingWidgets.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts
rename to app/src/services/visulization/zone/addFloatingWidgets.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts b/app/src/services/visulization/zone/addWidgets.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/addWidgets.ts
rename to app/src/services/visulization/zone/addWidgets.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/clearPanel.ts b/app/src/services/visulization/zone/clearPanel.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/clearPanel.ts
rename to app/src/services/visulization/zone/clearPanel.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/delete3dWidget.ts b/app/src/services/visulization/zone/delete3dWidget.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/delete3dWidget.ts
rename to app/src/services/visulization/zone/delete3dWidget.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts b/app/src/services/visulization/zone/deleteFloatingWidget.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts
rename to app/src/services/visulization/zone/deleteFloatingWidget.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/deletePanel.ts b/app/src/services/visulization/zone/deletePanel.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/deletePanel.ts
rename to app/src/services/visulization/zone/deletePanel.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts b/app/src/services/visulization/zone/deleteTemplate.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts
rename to app/src/services/visulization/zone/deleteTemplate.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts b/app/src/services/visulization/zone/deleteWidgetApi.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts
rename to app/src/services/visulization/zone/deleteWidgetApi.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts b/app/src/services/visulization/zone/duplicateWidget.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts
rename to app/src/services/visulization/zone/duplicateWidget.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts b/app/src/services/visulization/zone/get3dWidgetData.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts
rename to app/src/services/visulization/zone/get3dWidgetData.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts b/app/src/services/visulization/zone/getFloatingData.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/getFloatingData.ts
rename to app/src/services/visulization/zone/getFloatingData.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/visulization/zone/getSelect2dZoneData.ts
similarity index 85%
rename from app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts
rename to app/src/services/visulization/zone/getSelect2dZoneData.ts
index 00d4dfe..b2c39e9 100644
--- a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts
+++ b/app/src/services/visulization/zone/getSelect2dZoneData.ts
@@ -7,7 +7,7 @@ export const getSelect2dZoneData = async (
) => {
try {
const response = await fetch(
- `${url_Backend_dwinzo}/api/v2/ZoneVisualization/${ZoneId}?organization=${organization}`,
+ `${url_Backend_dwinzo}/api/v2/Zone/visualization/${ZoneId}?organization=${organization}`,
{
method: "GET",
headers: {
diff --git a/app/src/services/realTimeVisulization/zoneData/getTemplate.ts b/app/src/services/visulization/zone/getTemplate.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/getTemplate.ts
rename to app/src/services/visulization/zone/getTemplate.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts b/app/src/services/visulization/zone/getZoneData.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/getZoneData.ts
rename to app/src/services/visulization/zone/getZoneData.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/visulization/zone/getZones.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/getZones.ts
rename to app/src/services/visulization/zone/getZones.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts b/app/src/services/visulization/zone/loadTemplate.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/loadTemplate.ts
rename to app/src/services/visulization/zone/loadTemplate.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/lockPanel.ts b/app/src/services/visulization/zone/lockPanel.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/lockPanel.ts
rename to app/src/services/visulization/zone/lockPanel.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/panel.ts b/app/src/services/visulization/zone/panel.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/panel.ts
rename to app/src/services/visulization/zone/panel.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts b/app/src/services/visulization/zone/saveTempleteApi.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts
rename to app/src/services/visulization/zone/saveTempleteApi.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts b/app/src/services/visulization/zone/update3dWidget.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/update3dWidget.ts
rename to app/src/services/visulization/zone/update3dWidget.ts
diff --git a/app/src/services/realTimeVisulization/zoneData/zoneCameraUpdation.ts b/app/src/services/visulization/zone/zoneCameraUpdation.ts
similarity index 100%
rename from app/src/services/realTimeVisulization/zoneData/zoneCameraUpdation.ts
rename to app/src/services/visulization/zone/zoneCameraUpdation.ts
diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts
new file mode 100644
index 0000000..493a068
--- /dev/null
+++ b/app/src/store/simulation/useArmBotStore.ts
@@ -0,0 +1,160 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+interface ArmBotStore {
+ armBots: ArmBotStatus[];
+
+ addArmBot: (productId: string, event: RoboticArmEventSchema) => void;
+ removeArmBot: (modelUuid: string) => void;
+ updateArmBot: (
+ modelUuid: string,
+ updates: Partial>
+ ) => void;
+
+ addCurrentAction: (modelUuid: string, actionUuid: string) => void;
+ removeCurrentAction: (modelUuid: string) => void;
+
+ addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void;
+ removeAction: (modelUuid: string, actionUuid: string) => void;
+
+ setArmBotActive: (modelUuid: string, isActive: boolean) => void;
+
+ incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
+ incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
+
+ getArmBotById: (modelUuid: string) => ArmBotStatus | undefined;
+ getArmBotsByProduct: (productId: string) => ArmBotStatus[];
+ getArmBotsByState: (state: string) => ArmBotStatus[];
+ getActiveArmBots: () => ArmBotStatus[];
+ getIdleArmBots: () => ArmBotStatus[];
+ getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[];
+}
+
+export const useArmBotStore = create()(
+ immer((set, get) => ({
+ armBots: [],
+
+ addArmBot: (productId, event) => {
+ set((state) => {
+ state.armBots.push({
+ ...event,
+ productId,
+ isActive: false,
+ idleTime: 0,
+ activeTime: 0,
+ state: 'idle',
+ });
+ });
+ },
+
+ removeArmBot: (modelUuid) => {
+ set((state) => {
+ state.armBots = state.armBots.filter(a => a.modelUuid !== modelUuid);
+ });
+ },
+
+ updateArmBot: (modelUuid, updates) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ Object.assign(armBot, updates);
+ }
+ });
+ },
+
+ addCurrentAction: (modelUuid, actionUuid) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ const action = armBot.point.actions.find(a => a.actionUuid === actionUuid);
+ if (action) {
+ armBot.currentAction = {
+ actionUuid: action.actionUuid,
+ actionName: action.actionName,
+ };
+ armBot.isActive = true;
+ }
+ }
+ });
+ },
+
+ removeCurrentAction: (modelUuid) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ armBot.currentAction = undefined;
+ armBot.isActive = false;
+ }
+ });
+ },
+
+ addAction: (modelUuid, action) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ armBot.point.actions.push(action);
+ }
+ });
+ },
+
+ removeAction: (modelUuid, actionUuid) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ armBot.point.actions = armBot.point.actions.filter(a => a.actionUuid !== actionUuid);
+ }
+ });
+ },
+
+ setArmBotActive: (modelUuid, isActive) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ armBot.isActive = isActive;
+ }
+ });
+ },
+
+ incrementActiveTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ armBot.activeTime += incrementBy;
+ }
+ });
+ },
+
+ incrementIdleTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
+ if (armBot) {
+ armBot.idleTime += incrementBy;
+ }
+ });
+ },
+
+ getArmBotById: (modelUuid) => {
+ return get().armBots.find(a => a.modelUuid === modelUuid);
+ },
+
+ getArmBotsByProduct: (productId) => {
+ return get().armBots.filter(a => a.productId === productId);
+ },
+
+ getArmBotsByState: (state) => {
+ return get().armBots.filter(a => a.state === state);
+ },
+
+ getActiveArmBots: () => {
+ return get().armBots.filter(a => a.isActive);
+ },
+
+ getIdleArmBots: () => {
+ return get().armBots.filter(a => !a.isActive && a.state === 'idle');
+ },
+
+ getArmBotsByCurrentAction: (actionUuid) => {
+ return get().armBots.filter(a => a.currentAction?.actionUuid === actionUuid);
+ }
+ }))
+);
diff --git a/app/src/store/simulation/useConveyorStore.ts b/app/src/store/simulation/useConveyorStore.ts
new file mode 100644
index 0000000..15dbf34
--- /dev/null
+++ b/app/src/store/simulation/useConveyorStore.ts
@@ -0,0 +1,115 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+interface ConveyorStore {
+ conveyors: ConveyorStatus[];
+
+ addConveyor: (productId: string, event: ConveyorEventSchema) => void;
+ removeConveyor: (modelUuid: string) => void;
+ updateConveyor: (
+ modelUuid: string,
+ updates: Partial>
+ ) => void;
+
+ setConveyorActive: (modelUuid: string, isActive: boolean) => void;
+ setConveyorState: (modelUuid: string, newState: ConveyorStatus['state']) => void;
+
+ incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
+ incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
+
+ getConveyorById: (modelUuid: string) => ConveyorStatus | undefined;
+ getConveyorsByProduct: (productId: string) => ConveyorStatus[];
+ getConveyorsByState: (state: string) => ConveyorStatus[];
+ getActiveConveyors: () => ConveyorStatus[];
+ getIdleConveyors: () => ConveyorStatus[];
+}
+
+export const useConveyorStore = create()(
+ immer((set, get) => ({
+ conveyors: [],
+
+ addConveyor: (productId, event) => {
+ set((state) => {
+ state.conveyors.push({
+ ...event,
+ productId,
+ isActive: false,
+ idleTime: 0,
+ activeTime: 0,
+ state: 'idle',
+ });
+ });
+ },
+
+ removeConveyor: (modelUuid) => {
+ set((state) => {
+ state.conveyors = state.conveyors.filter(c => c.modelUuid !== modelUuid);
+ });
+ },
+
+ updateConveyor: (modelUuid, updates) => {
+ set((state) => {
+ const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
+ if (conveyor) {
+ Object.assign(conveyor, updates);
+ }
+ });
+ },
+
+ setConveyorActive: (modelUuid, isActive) => {
+ set((state) => {
+ const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
+ if (conveyor) {
+ conveyor.isActive = isActive;
+ }
+ });
+ },
+
+ setConveyorState: (modelUuid, newState) => {
+ set((state) => {
+ const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
+ if (conveyor) {
+ conveyor.state = newState;
+ }
+ });
+ },
+
+ incrementActiveTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
+ if (conveyor) {
+ conveyor.activeTime += incrementBy;
+ }
+ });
+ },
+
+ incrementIdleTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
+ if (conveyor) {
+ conveyor.idleTime += incrementBy;
+ }
+ });
+ },
+
+ getConveyorById: (modelUuid) => {
+ return get().conveyors.find(c => c.modelUuid === modelUuid);
+ },
+
+ getConveyorsByProduct: (productId) => {
+ return get().conveyors.filter(c => c.productId === productId);
+ },
+
+ getConveyorsByState: (state) => {
+ return get().conveyors.filter(c => c.state === state);
+ },
+
+ getActiveConveyors: () => {
+ return get().conveyors.filter(c => c.isActive);
+ },
+
+ getIdleConveyors: () => {
+ return get().conveyors.filter(c => !c.isActive && c.state === 'idle');
+ },
+ }))
+);
diff --git a/app/src/store/simulation/useEventsStore.ts b/app/src/store/simulation/useEventsStore.ts
new file mode 100644
index 0000000..2d92fc2
--- /dev/null
+++ b/app/src/store/simulation/useEventsStore.ts
@@ -0,0 +1,331 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+type EventsStore = {
+ events: EventsSchema[];
+
+ // Event-level actions
+ addEvent: (event: EventsSchema) => void;
+ removeEvent: (modelUuid: string) => void;
+ updateEvent: (modelUuid: string, updates: Partial) => void;
+
+ // Point-level actions
+ addPoint: (modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
+ removePoint: (modelUuid: string, pointUuid: string) => void;
+ updatePoint: (
+ modelUuid: string,
+ pointUuid: string,
+ updates: Partial
+ ) => void;
+
+ // Action-level actions
+ addAction: (
+ modelUuid: string,
+ pointUuid: string,
+ action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
+ ) => void;
+ removeAction: (actionUuid: string) => void;
+ updateAction: (
+ actionUuid: string,
+ updates: Partial
+ ) => void;
+
+ // Trigger-level actions
+ addTrigger: (actionUuid: string, trigger: TriggerSchema) => void;
+ removeTrigger: (triggerUuid: string) => void;
+ updateTrigger: (triggerUuid: string, updates: Partial) => void;
+
+ // Helper functions
+ getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined;
+ getPointByUuid: (modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
+ getActionByUuid: (actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
+ getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined;
+};
+
+export const useEventsStore = create()(
+ immer((set, get) => ({
+ events: [],
+
+ // Event-level actions
+ addEvent: (event) => {
+ set((state) => {
+ state.events.push(event);
+ });
+ },
+
+ removeEvent: (modelUuid) => {
+ set((state) => {
+ state.events = state.events.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
+ });
+ },
+
+ updateEvent: (modelUuid, updates) => {
+ set((state) => {
+ const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event) {
+ Object.assign(event, updates);
+ }
+ });
+ },
+
+ // Point-level actions
+ addPoint: (modelUuid, point) => {
+ set((state) => {
+ const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ (event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
+ } else if (event && 'point' in event) {
+ (event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
+ }
+ });
+ },
+
+ removePoint: (modelUuid, pointUuid) => {
+ set((state) => {
+ const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ (event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
+ }
+ // For single-point events, you might want to handle differently
+ });
+ },
+
+ updatePoint: (modelUuid, pointUuid, updates) => {
+ set((state) => {
+ const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
+ if (point) {
+ Object.assign(point, updates);
+ }
+ } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
+ Object.assign((event as any).point, updates);
+ }
+ });
+ },
+
+ // Action-level actions
+ addAction: (modelUuid, pointUuid, action) => {
+ set((state) => {
+ const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
+ if (point) {
+ point.action = action as any;
+ }
+ } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
+ if ('action' in (event as any).point) {
+ (event as any).point.action = action;
+ } else if ('actions' in (event as any).point) {
+ (event as any).point.actions.push(action);
+ }
+ }
+ });
+ },
+
+ removeAction: (actionUuid) => {
+ set((state) => {
+ for (const event of state.events) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && point.action.actionUuid === actionUuid) {
+ // Handle removal for single action points
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if (event.type === "roboticArm") {
+ if ('actions' in point) {
+ point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid);
+ }
+ } else if ('action' in point && point.action?.actionUuid === actionUuid) {
+ // Handle single action
+ }
+ }
+ }
+ });
+ },
+
+ updateAction: (actionUuid, updates) => {
+ set((state) => {
+ for (const event of state.events) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && point.action.actionUuid === actionUuid) {
+ Object.assign(point.action, updates);
+ return;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && point.action.actionUuid === actionUuid) {
+ Object.assign(point.action, updates);
+ return;
+ } else if ('actions' in point) {
+ const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
+ if (action) {
+ Object.assign(action, updates);
+ return;
+ }
+ }
+ }
+ }
+ });
+ },
+
+ // Trigger-level actions
+ addTrigger: (actionUuid, trigger) => {
+ set((state) => {
+ for (const event of state.events) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && point.action.actionUuid === actionUuid) {
+ point.action.triggers.push(trigger);
+ return;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && point.action.actionUuid === actionUuid) {
+ point.action.triggers.push(trigger);
+ return;
+ } else if ('actions' in point) {
+ const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
+ if (action) {
+ action.triggers.push(trigger);
+ return;
+ }
+ }
+ }
+ }
+ });
+ },
+
+ removeTrigger: (triggerUuid) => {
+ set((state) => {
+ for (const event of state.events) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && 'triggers' in point.action) {
+ point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && 'triggers' in point.action) {
+ point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
+ } else if ('actions' in point) {
+ for (const action of point.actions) {
+ if ('triggers' in action) {
+ action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
+ }
+ }
+ }
+ }
+ }
+ });
+ },
+
+ updateTrigger: (triggerUuid, updates) => {
+ set((state) => {
+ for (const event of state.events) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && 'triggers' in point.action) {
+ const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
+ if (trigger) {
+ Object.assign(trigger, updates);
+ return;
+ }
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && 'triggers' in point.action) {
+ const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
+ if (trigger) {
+ Object.assign(trigger, updates);
+ return;
+ }
+ } else if ('actions' in point) {
+ for (const action of point.actions) {
+ if ('triggers' in action) {
+ const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
+ if (trigger) {
+ Object.assign(trigger, updates);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ },
+
+ // Helper functions
+ getEventByModelUuid: (modelUuid) => {
+ return get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ },
+
+ getPointByUuid: (modelUuid, pointUuid) => {
+ const event = get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
+ } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
+ return (event as any).point;
+ }
+ return undefined;
+ },
+
+ getActionByUuid: (actionUuid) => {
+ const state = get();
+ for (const event of state.events) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && point.action.actionUuid === actionUuid) {
+ return point.action;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && point.action.actionUuid === actionUuid) {
+ return point.action;
+ } else if ('actions' in point) {
+ const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
+ if (action) return action;
+ }
+ }
+ }
+ return undefined;
+ },
+
+ getTriggerByUuid: (triggerUuid) => {
+ const state = get();
+ for (const event of state.events) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && 'triggers' in point.action) {
+ const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
+ if (trigger) return trigger;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && 'triggers' in point.action) {
+ const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
+ if (trigger) return trigger;
+ } else if ('actions' in point) {
+ for (const action of point.actions) {
+ if ('triggers' in action) {
+ const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
+ if (trigger) return trigger;
+ }
+ }
+ }
+ }
+ }
+ return undefined;
+ }
+ }))
+);
diff --git a/app/src/store/simulation/useMachineStore.ts b/app/src/store/simulation/useMachineStore.ts
new file mode 100644
index 0000000..cc927f7
--- /dev/null
+++ b/app/src/store/simulation/useMachineStore.ts
@@ -0,0 +1,123 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+interface MachineStore {
+ machines: MachineStatus[];
+
+ // Actions
+ addMachine: (productId: string, machine: MachineEventSchema) => void;
+ removeMachine: (modelUuid: string) => void;
+ updateMachine: (
+ modelUuid: string,
+ updates: Partial>
+ ) => void;
+
+ // Status updates
+ setMachineActive: (modelUuid: string, isActive: boolean) => void;
+ setMachineState: (modelUuid: string, newState: MachineStatus['state']) => void;
+
+ // Time tracking
+ incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
+ incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
+
+ // Helpers
+ getMachineById: (modelUuid: string) => MachineStatus | undefined;
+ getMachinesByProduct: (productId: string) => MachineStatus[];
+ getMachinesBystate: (state: string) => MachineStatus[];
+ getActiveMachines: () => MachineStatus[];
+ getIdleMachines: () => MachineStatus[];
+}
+
+export const useMachineStore = create()(
+ immer((set, get) => ({
+ machines: [],
+
+ // Actions
+ addMachine: (productId, machine) => {
+ set((state) => {
+ state.machines.push({
+ ...machine,
+ productId,
+ isActive: false,
+ idleTime: 0,
+ activeTime: 0,
+ state: 'idle',
+ });
+ });
+ },
+
+ removeMachine: (modelUuid) => {
+ set((state) => {
+ state.machines = state.machines.filter(m => m.modelUuid !== modelUuid);
+ });
+ },
+
+ updateMachine: (modelUuid, updates) => {
+ set((state) => {
+ const machine = state.machines.find(m => m.modelUuid === modelUuid);
+ if (machine) {
+ Object.assign(machine, updates);
+ }
+ });
+ },
+
+ // Status updates
+ setMachineActive: (modelUuid, isActive) => {
+ set((state) => {
+ const machine = state.machines.find(m => m.modelUuid === modelUuid);
+ if (machine) {
+ machine.isActive = isActive;
+ }
+ });
+ },
+
+ setMachineState: (modelUuid, newState) => {
+ set((state) => {
+ const machine = state.machines.find(m => m.modelUuid === modelUuid);
+ if (machine) {
+ machine.state = newState;
+ }
+ });
+ },
+
+ // Time tracking
+ incrementActiveTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const machine = state.machines.find(m => m.modelUuid === modelUuid);
+ if (machine) {
+ machine.activeTime += incrementBy;
+ }
+ });
+ },
+
+ incrementIdleTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const machine = state.machines.find(m => m.modelUuid === modelUuid);
+ if (machine) {
+ machine.idleTime += incrementBy;
+ }
+ });
+ },
+
+ // Helpers
+ getMachineById: (modelUuid) => {
+ return get().machines.find(m => m.modelUuid === modelUuid);
+ },
+
+ getMachinesByProduct: (productId) => {
+ return get().machines.filter(m => m.productId === productId);
+ },
+
+ getMachinesBystate: (state) => {
+ return get().machines.filter(m => m.state === state);
+ },
+
+ getActiveMachines: () => {
+ return get().machines.filter(m => m.isActive);
+ },
+
+ getIdleMachines: () => {
+ return get().machines.filter(m => !m.isActive && m.state === 'idle');
+ },
+ }))
+);
diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts
new file mode 100644
index 0000000..41a13f6
--- /dev/null
+++ b/app/src/store/simulation/useProductStore.ts
@@ -0,0 +1,339 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+type ProductsStore = {
+ products: productsSchema;
+
+ // Product-level actions
+ addProduct: (productName: string, productId: string) => void;
+ removeProduct: (productId: string) => void;
+ updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void;
+
+ // Event-level actions
+ addEvent: (productId: string, event: EventsSchema) => void;
+ removeEvent: (productId: string, modelUuid: string) => void;
+ updateEvent: (productId: string, modelUuid: string, updates: Partial) => void;
+
+ // Point-level actions
+ addPoint: (productId: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
+ removePoint: (productId: string, modelUuid: string, pointUuid: string) => void;
+ updatePoint: (
+ productId: string,
+ modelUuid: string,
+ pointUuid: string,
+ updates: Partial
+ ) => void;
+
+ // Action-level actions
+ addAction: (
+ productId: string,
+ modelUuid: string,
+ pointUuid: string,
+ action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
+ ) => void;
+ removeAction: (actionUuid: string) => void;
+ updateAction: (
+ actionUuid: string,
+ updates: Partial
+ ) => void;
+
+ // Trigger-level actions
+ addTrigger: (
+ actionUuid: string,
+ trigger: TriggerSchema
+ ) => void;
+ removeTrigger: (triggerUuid: string) => void;
+ updateTrigger: (
+ triggerUuid: string,
+ updates: Partial
+ ) => void;
+
+ // Helper functions
+ getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined;
+};
+
+export const useProductStore = create()(
+ immer((set, get) => ({
+ products: [],
+
+ // Product-level actions
+ addProduct: (productName, productId) => {
+ set((state) => {
+ const newProduct = {
+ productName,
+ productId: productId,
+ eventsData: []
+ };
+ state.products.push(newProduct);
+ });
+ },
+
+ removeProduct: (productId) => {
+ set((state) => {
+ state.products = state.products.filter(p => p.productId !== productId);
+ });
+ },
+
+ updateProduct: (productId, updates) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ Object.assign(product, updates);
+ }
+ });
+ },
+
+ // Event-level actions
+ addEvent: (productId, event) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ product.eventsData.push(event);
+ }
+ });
+ },
+
+ removeEvent: (productId, modelUuid) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ product.eventsData = product.eventsData.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
+ }
+ });
+ },
+
+ updateEvent: (productId, modelUuid, updates) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event) {
+ Object.assign(event, updates);
+ }
+ }
+ });
+ },
+
+ // Point-level actions
+ addPoint: (productId, modelUuid, point) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ (event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
+ } else if (event && 'point' in event) {
+ (event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
+ }
+ }
+ });
+ },
+
+ removePoint: (productId, modelUuid, pointUuid) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ (event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
+ } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
+ // For events with single point, we can't remove it, only reset to empty
+ }
+ }
+ });
+ },
+
+ updatePoint: (productId, modelUuid, pointUuid, updates) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
+ if (point) {
+ Object.assign(point, updates);
+ }
+ } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
+ Object.assign((event as any).point, updates);
+ }
+ }
+ });
+ },
+
+ // Action-level actions
+ addAction: (productId, modelUuid, pointUuid, action) => {
+ set((state) => {
+ const product = state.products.find(p => p.productId === productId);
+ if (product) {
+ const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
+ if (event && 'points' in event) {
+ const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
+ if (point) {
+ point.action = action as any;
+ }
+ } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
+ if ('action' in (event as any).point) {
+ (event as any).point.action = action;
+ } else if ('actions' in (event as any).point) {
+ (event as any).point.actions.push(action);
+ }
+ }
+ }
+ });
+ },
+
+ removeAction: (actionUuid: string) => {
+ set((state) => {
+ for (const product of state.products) {
+ for (const event of product.eventsData) {
+ if ('points' in event) {
+ // Handle ConveyorEventSchema
+ for (const point of (event as ConveyorEventSchema).points) {
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if (event.type === "roboticArm") {
+ // Handle RoboticArmEventSchema
+ if ('actions' in point) {
+ point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid);
+ }
+ } else if ('action' in point && point.action?.actionUuid === actionUuid) {
+ // For other schemas with a single 'action'
+ }
+ }
+ }
+ }
+ });
+ },
+
+ updateAction: (actionUuid, updates) => {
+ set((state) => {
+ for (const product of state.products) {
+ for (const event of product.eventsData) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && point.action.actionUuid === actionUuid) {
+ Object.assign(point.action, updates);
+ return;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && point.action.actionUuid === actionUuid) {
+ Object.assign(point.action, updates);
+ return;
+ } else if ('actions' in point) {
+ const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
+ if (action) {
+ Object.assign(action, updates);
+ return;
+ }
+ }
+ }
+ }
+ }
+ });
+ },
+
+ // Trigger-level actions
+ addTrigger: (actionUuid, trigger) => {
+ set((state) => {
+ for (const product of state.products) {
+ for (const event of product.eventsData) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && point.action.actionUuid === actionUuid) {
+ point.action.triggers.push(trigger);
+ return;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && point.action.actionUuid === actionUuid) {
+ point.action.triggers.push(trigger);
+ return;
+ } else if ('actions' in point) {
+ const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
+ if (action) {
+ action.triggers.push(trigger);
+ return;
+ }
+ }
+ }
+ }
+ }
+ });
+ },
+
+ removeTrigger: (triggerUuid) => {
+ set((state) => {
+ for (const product of state.products) {
+ for (const event of product.eventsData) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && 'triggers' in point.action) {
+ point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && 'triggers' in point.action) {
+ point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
+ } else if ('actions' in point) {
+ for (const action of point.actions) {
+ if ('triggers' in action) {
+ action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ },
+
+ updateTrigger: (triggerUuid, updates) => {
+ set((state) => {
+ for (const product of state.products) {
+ for (const event of product.eventsData) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action && 'triggers' in point.action) {
+ const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
+ if (trigger) {
+ Object.assign(trigger, updates);
+ return;
+ }
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && 'triggers' in point.action) {
+ const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
+ if (trigger) {
+ Object.assign(trigger, updates);
+ return;
+ }
+ } else if ('actions' in point) {
+ for (const action of point.actions) {
+ if ('triggers' in action) {
+ const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
+ if (trigger) {
+ Object.assign(trigger, updates);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ },
+
+ // Helper functions
+ getProductById: (productId) => {
+ return get().products.find(p => p.productId === productId);
+ }
+ }))
+);
diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts
new file mode 100644
index 0000000..d729708
--- /dev/null
+++ b/app/src/store/simulation/useStorageUnitStore.ts
@@ -0,0 +1,149 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+interface StorageUnitStore {
+ storageUnits: StorageUnitStatus[];
+
+ // Actions
+ addStorageUnit: (productId: string, storageUnit: StorageEventSchema) => void;
+ removeStorageUnit: (modelUuid: string) => void;
+ updateStorageUnit: (
+ modelUuid: string,
+ updates: Partial>
+ ) => void;
+
+ // Status updates
+ setStorageUnitActive: (modelUuid: string, isActive: boolean) => void;
+ setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void;
+
+ // Load updates
+ updateStorageUnitLoad: (modelUuid: string, incrementBy: number) => void;
+
+ // Time tracking
+ incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
+ incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
+
+ // Helpers
+ getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined;
+ getStorageUnitsByProduct: (productId: string) => StorageUnitStatus[];
+ getStorageUnitsBystate: (state: string) => StorageUnitStatus[];
+ getActiveStorageUnits: () => StorageUnitStatus[];
+ getIdleStorageUnits: () => StorageUnitStatus[];
+ getFullStorageUnits: () => StorageUnitStatus[];
+ getEmptyStorageUnits: () => StorageUnitStatus[];
+}
+
+export const useStorageUnitStore = create()(
+ immer((set, get) => ({
+ storageUnits: [],
+
+ // Actions
+ addStorageUnit: (productId, storageUnit) => {
+ set((state) => {
+ state.storageUnits.push({
+ ...storageUnit,
+ productId,
+ isActive: false,
+ idleTime: 0,
+ activeTime: 0,
+ currentLoad: 0,
+ state: 'idle',
+ });
+ });
+ },
+
+ removeStorageUnit: (modelUuid) => {
+ set((state) => {
+ state.storageUnits = state.storageUnits.filter(s => s.modelUuid !== modelUuid);
+ });
+ },
+
+ updateStorageUnit: (modelUuid, updates) => {
+ set((state) => {
+ const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
+ if (unit) {
+ Object.assign(unit, updates);
+ }
+ });
+ },
+
+ // Status updates
+ setStorageUnitActive: (modelUuid, isActive) => {
+ set((state) => {
+ const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
+ if (unit) {
+ unit.isActive = isActive;
+ }
+ });
+ },
+
+ setStorageUnitState: (modelUuid, newState) => {
+ set((state) => {
+ const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
+ if (unit) {
+ unit.state = newState;
+ }
+ });
+ },
+
+ // Load updates
+ updateStorageUnitLoad: (modelUuid, incrementBy) => {
+ set((state) => {
+ const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
+ if (unit) {
+ unit.currentLoad += incrementBy;
+ }
+ });
+ },
+
+ // Time tracking
+ incrementActiveTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
+ if (unit) {
+ unit.activeTime += incrementBy;
+ }
+ });
+ },
+
+ incrementIdleTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
+ if (unit) {
+ unit.idleTime += incrementBy;
+ }
+ });
+ },
+
+ // Helpers
+ getStorageUnitById: (modelUuid) => {
+ return get().storageUnits.find(s => s.modelUuid === modelUuid);
+ },
+
+ getStorageUnitsByProduct: (productId) => {
+ return get().storageUnits.filter(s => s.productId === productId);
+ },
+
+ getStorageUnitsBystate: (state) => {
+ return get().storageUnits.filter(s => s.state === state);
+ },
+
+ getActiveStorageUnits: () => {
+ return get().storageUnits.filter(s => s.isActive);
+ },
+
+ getIdleStorageUnits: () => {
+ return get().storageUnits.filter(s => !s.isActive && s.state === 'idle');
+ },
+
+ getFullStorageUnits: () => {
+ return get().storageUnits.filter(
+ s => s.currentLoad >= s.point.action.storageCapacity
+ );
+ },
+
+ getEmptyStorageUnits: () => {
+ return get().storageUnits.filter(s => s.currentLoad === 0);
+ },
+ }))
+);
diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts
new file mode 100644
index 0000000..ce28916
--- /dev/null
+++ b/app/src/store/simulation/useVehicleStore.ts
@@ -0,0 +1,139 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+interface VehicleStatus extends VehicleEventSchema {
+ productId: string;
+ isActive: boolean;
+ idleTime: number;
+ activeTime: number;
+ currentLoad: number;
+ distanceTraveled: number;
+}
+
+interface VehiclesStore {
+ vehicles: VehicleStatus[];
+
+ addVehicle: (productId: string, event: VehicleEventSchema) => void;
+ removeVehicle: (modelUuid: string) => void;
+ updateVehicle: (
+ modelUuid: string,
+ updates: Partial>
+ ) => void;
+
+ setVehicleActive: (modelUuid: string, isActive: boolean) => void;
+ incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
+ decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
+ setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void;
+ incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
+ incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
+
+ getVehicleById: (modelUuid: string) => VehicleStatus | undefined;
+ getVehiclesByProduct: (productId: string) => VehicleStatus[];
+ getVehiclesByState: (state: string) => VehicleStatus[];
+ getActiveVehicles: () => VehicleStatus[];
+}
+
+export const useVehicleStore = create()(
+ immer((set, get) => ({
+ vehicles: [],
+
+ addVehicle: (productId, event) => {
+ set((state) => {
+ state.vehicles.push({
+ ...event,
+ productId,
+ isActive: false,
+ idleTime: 0,
+ activeTime: 0,
+ currentLoad: 0,
+ distanceTraveled: 0,
+ });
+ });
+ },
+
+ removeVehicle: (modelUuid) => {
+ set((state) => {
+ state.vehicles = state.vehicles.filter(v => v.modelUuid !== modelUuid);
+ });
+ },
+
+ updateVehicle: (modelUuid, updates) => {
+ set((state) => {
+ const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
+ if (vehicle) {
+ Object.assign(vehicle, updates);
+ }
+ });
+ },
+
+ setVehicleActive: (modelUuid, isActive) => {
+ set((state) => {
+ const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
+ if (vehicle) {
+ vehicle.isActive = isActive;
+ }
+ });
+ },
+
+ incrementVehicleLoad: (modelUuid, incrementBy) => {
+ set((state) => {
+ const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
+ if (vehicle) {
+ vehicle.currentLoad += incrementBy;
+ }
+ });
+ },
+
+ decrementVehicleLoad: (modelUuid, decrementBy) => {
+ set((state) => {
+ const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
+ if (vehicle) {
+ vehicle.currentLoad = decrementBy;
+ }
+ });
+ },
+
+ setVehicleState: (modelUuid, newState) => {
+ set((state) => {
+ const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
+ if (vehicle) {
+ vehicle.state = newState;
+ }
+ });
+ },
+
+ incrementActiveTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
+ if (vehicle) {
+ vehicle.activeTime += incrementBy;
+ }
+ });
+ },
+
+ incrementIdleTime: (modelUuid, incrementBy) => {
+ set((state) => {
+ const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
+ if (vehicle) {
+ vehicle.idleTime += incrementBy;
+ }
+ });
+ },
+
+ getVehicleById: (modelUuid) => {
+ return get().vehicles.find(v => v.modelUuid === modelUuid);
+ },
+
+ getVehiclesByProduct: (productId) => {
+ return get().vehicles.filter(v => v.productId === productId);
+ },
+
+ getVehiclesByState: (state) => {
+ return get().vehicles.filter(v => v.state === state);
+ },
+
+ getActiveVehicles: () => {
+ return get().vehicles.filter(v => v.isActive);
+ }
+ }))
+);
diff --git a/app/src/store/store.ts b/app/src/store/store.ts
index 765712b..b16e1ff 100644
--- a/app/src/store/store.ts
+++ b/app/src/store/store.ts
@@ -1,6 +1,5 @@
import * as THREE from "three";
import * as Types from "../types/world/worldTypes";
-import * as SimulationTypes from "../types/simulationTypes";
import { create } from "zustand";
import { io } from "socket.io-client";
@@ -86,10 +85,15 @@ export const useZonePoints = create((set) => ({
}));
export const useSelectedItem = create((set: any) => ({
- selectedItem: { name: "", id: "" },
+ selectedItem: { name: "", id: "", type: undefined },
setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
}));
+export const useNavMesh = create((set: any) => ({
+ navMesh: null,
+ setNavMesh: (x: any) => set({ navMesh: x }),
+}));
+
export const useSelectedAssets = create((set: any) => ({
selectedAssets: [],
setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })),
@@ -338,49 +342,6 @@ export const useDrieUIValue = create((set: any) => ({
})),
}));
-export const useDrawMaterialPath = create((set: any) => ({
- drawMaterialPath: false,
- setDrawMaterialPath: (x: any) => set({ drawMaterialPath: x }),
-}));
-
-export const useSelectedActionSphere = create((set: any) => ({
- selectedActionSphere: undefined,
- setSelectedActionSphere: (x: any) => set({ selectedActionSphere: x }),
-}));
-
-export const useSelectedPath = create((set: any) => ({
- selectedPath: undefined,
- setSelectedPath: (x: any) => set({ selectedPath: x }),
-}));
-
-interface SimulationPathsStore {
- simulationStates: (SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[];
- setSimulationStates: (
- paths: (| SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[]
- | ((prev: (| SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[])
- => (| SimulationTypes.ConveyorEventsSchema | SimulationTypes.VehicleEventsSchema | SimulationTypes.StaticMachineEventsSchema | SimulationTypes.ArmBotEventsSchema)[])
- ) => void;
-}
-
-export const useSimulationStates = create((set) => ({
- simulationStates: [],
- setSimulationStates: (paths) =>
- set((state) => ({
- 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 }),
-}));
-
export const useStartSimulation = create((set: any) => ({
startSimulation: false,
setStartSimulation: (x: any) => set({ startSimulation: x }),
@@ -396,14 +357,6 @@ export const useEditingPoint = create((set: any) => ({
setEditingPoint: (x: any) => set({ editingPoint: x }),
}));
-export const usePreviewPosition = create<{
- previewPosition: { x: number; y: number } | null;
- setPreviewPosition: (position: { x: number; y: number } | null) => void;
-}>((set) => ({
- previewPosition: null,
- setPreviewPosition: (position) => set({ previewPosition: position }),
-}));
-
export const usezoneTarget = create((set: any) => ({
zoneTarget: [],
setZoneTarget: (x: any) => set({ zoneTarget: x }),
@@ -421,7 +374,7 @@ interface EditPositionState {
export const useEditPosition = create((set) => ({
Edit: false,
- setEdit: (value) => set({ Edit: value }), // Properly updating the state
+ setEdit: (value) => set({ Edit: value }),
}));
export const useAsset3dWidget = create((set: any) => ({
diff --git a/app/src/store/useChartStore.ts b/app/src/store/visualization/useChartStore.ts
similarity index 100%
rename from app/src/store/useChartStore.ts
rename to app/src/store/visualization/useChartStore.ts
diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/visualization/useDroppedObjectsStore.ts
similarity index 96%
rename from app/src/store/useDroppedObjectsStore.ts
rename to app/src/store/visualization/useDroppedObjectsStore.ts
index 0c03eec..5c4527b 100644
--- a/app/src/store/useDroppedObjectsStore.ts
+++ b/app/src/store/visualization/useDroppedObjectsStore.ts
@@ -1,6 +1,6 @@
import { create } from "zustand";
-import { addingFloatingWidgets } from "../services/realTimeVisulization/zoneData/addFloatingWidgets";
-import { useSocketStore } from "./store";
+import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets";
+import { useSocketStore } from "../store";
import useChartStore from "./useChartStore";
type DroppedObject = {
@@ -114,7 +114,7 @@ export const useDroppedObjectsStore = create((set) => ({
// Create a shallow copy of the object with a unique ID and slightly adjusted position
const duplicatedObject: DroppedObject = {
...originalObject,
- Data:{
+ Data: {
measurements: iotMeasurements,
duration: iotDuration,
},
@@ -132,8 +132,8 @@ export const useDroppedObjectsStore = create((set) => ({
: originalObject.position.left,
},
};
- console.log("duplicated object",duplicatedObject);
-
+ console.log("duplicated object", duplicatedObject);
+
let duplicateFloatingWidget = {
organization: organization,
widget: duplicatedObject,
diff --git a/app/src/store/useZone3DWidgetStore.ts b/app/src/store/visualization/useZone3DWidgetStore.ts
similarity index 100%
rename from app/src/store/useZone3DWidgetStore.ts
rename to app/src/store/visualization/useZone3DWidgetStore.ts
diff --git a/app/src/store/useZoneStore.ts b/app/src/store/visualization/useZoneStore.ts
similarity index 95%
rename from app/src/store/useZoneStore.ts
rename to app/src/store/visualization/useZoneStore.ts
index b06824b..eb05790 100644
--- a/app/src/store/useZoneStore.ts
+++ b/app/src/store/visualization/useZoneStore.ts
@@ -1,53 +1,53 @@
-import { create } from "zustand";
-
-type Side = "top" | "bottom" | "left" | "right";
-
-interface Widget {
- id: string;
- type: string;
- title: string;
- panel: Side;
- data: any;
-}
-
-interface SelectedZoneState {
- zoneName: string;
- activeSides: Side[];
- panelOrder: Side[];
- points: []
- lockedPanels: Side[];
- zoneId: string;
- zoneViewPortTarget: number[];
- zoneViewPortPosition: number[];
- widgets: Widget[];
-}
-
-interface SelectedZoneStore {
- selectedZone: SelectedZoneState;
- setSelectedZone: (
- zone:
- | Partial
- | ((prev: SelectedZoneState) => SelectedZoneState)
- ) => void;
-}
-
-export const useSelectedZoneStore = create((set) => ({
- selectedZone: {
- zoneName: "", // Empty string initially
- activeSides: [], // Empty array
- panelOrder: [], // Empty array
- lockedPanels: [], // Empty array
- points: [],
- zoneId: "",
- zoneViewPortTarget: [],
- zoneViewPortPosition: [],
- widgets: [], // Empty array
- },
- setSelectedZone: (zone) =>
- set((state) => ({
- selectedZone:
- typeof zone === "function"
- ? zone(state.selectedZone) // Handle functional updates
- : { ...state.selectedZone, ...zone }, // Handle partial updates
- })),
-}));
+import { create } from "zustand";
+
+type Side = "top" | "bottom" | "left" | "right";
+
+interface Widget {
+ id: string;
+ type: string;
+ title: string;
+ panel: Side;
+ data: any;
+}
+
+interface SelectedZoneState {
+ zoneName: string;
+ activeSides: Side[];
+ panelOrder: Side[];
+ points: []
+ lockedPanels: Side[];
+ zoneId: string;
+ zoneViewPortTarget: number[];
+ zoneViewPortPosition: number[];
+ widgets: Widget[];
+}
+
+interface SelectedZoneStore {
+ selectedZone: SelectedZoneState;
+ setSelectedZone: (
+ zone:
+ | Partial
+ | ((prev: SelectedZoneState) => SelectedZoneState)
+ ) => void;
+}
+
+export const useSelectedZoneStore = create((set) => ({
+ selectedZone: {
+ zoneName: "", // Empty string initially
+ activeSides: [], // Empty array
+ panelOrder: [], // Empty array
+ lockedPanels: [], // Empty array
+ points: [],
+ zoneId: "",
+ zoneViewPortTarget: [],
+ zoneViewPortPosition: [],
+ widgets: [], // Empty array
+ },
+ setSelectedZone: (zone) =>
+ set((state) => ({
+ selectedZone:
+ typeof zone === "function"
+ ? zone(state.selectedZone) // Handle functional updates
+ : { ...state.selectedZone, ...zone }, // Handle partial updates
+ })),
+}));
diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss
index 883f6c2..21554e8 100644
--- a/app/src/styles/components/input.scss
+++ b/app/src/styles/components/input.scss
@@ -7,8 +7,8 @@ input {
width: 100%;
padding: 2px 4px;
border-radius: #{$border-radius-small};
- outline: 2px solid var(--border-color);
- outline-offset: -2px;
+ outline: 1px solid var(--border-color);
+ outline-offset: -1px;
border: none;
background: transparent;
color: var(--input-text-color);
@@ -30,6 +30,24 @@ input {
background-color: var(--background-color) !important;
-webkit-box-shadow: 0 0 0px 1000px var(--background-color) inset !important;
}
+
+ // File input specific style adjustments
+ &::file-selector-button {
+ font-size: 14px;
+ color: var(--accent-color);
+ background-color: var(--background-color-secondary);
+ border: none;
+ outline: none;
+ border-radius: #{$border-radius-small};
+ padding: 2px;
+ cursor: pointer;
+
+ // Hover effect for the file button
+ &:hover {
+ color: var(--primary-color);
+ background-color: var(--accent-color);
+ }
+ }
}
.input-value {
@@ -712,3 +730,47 @@ input {
border: 1px solid var(--accent-color);
}
}
+
+.preview-selection-with-upload-wrapper {
+ .input-header-container {
+ padding: 6px 12px;
+ @include flex-space-between;
+ .arrow-container {
+ transition: all 0.2s;
+ @include flex-center;
+ }
+ }
+ .upload-custom-asset-button{
+ padding: 6px 12px;
+ @include flex-space-between;
+ .title{
+ white-space: nowrap;
+ width: 40%;
+ }
+ input{
+ display: none;
+ }
+ .upload-button{
+ width: 60%;
+ background: var(--highlight-accent-color);
+ color: var(--accent-color);
+ padding: 3px 6px;
+ border-radius: #{$border-radius-small};
+ text-align: center;
+ }
+ }
+ .canvas-wrapper {
+ height: 150px;
+ width: 100%;
+ padding: 8px;
+ padding-right: 4px;
+ overflow: hidden;
+ position: relative;
+ .canvas-container {
+ width: 100%;
+ height: 100%;
+ border-radius: #{$border-radius-small};
+ background-color: var(--background-color-gray);
+ }
+ }
+}
diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss
index 305206a..cab078e 100644
--- a/app/src/styles/layout/sidebar.scss
+++ b/app/src/styles/layout/sidebar.scss
@@ -7,6 +7,7 @@
top: 32px;
left: 8px;
background-color: var(--background-color);
+ backdrop-filter: blur(150px);
border-radius: #{$border-radius-extra-large};
box-shadow: #{$box-shadow-medium};
z-index: #{$z-index-tools};
@@ -131,15 +132,12 @@
}
.widgets-wrapper {
-
min-height: 50vh;
max-height: 60vh;
overflow: auto;
}
.widget-left-sideBar {
-
-
.widget2D {
overflow: auto;
@@ -246,6 +244,7 @@
top: 32px;
right: 8px;
background-color: var(--background-color);
+ backdrop-filter: blur(150px);
border-radius: #{$border-radius-extra-large};
box-shadow: #{$box-shadow-medium};
z-index: #{$z-index-tools};
@@ -643,7 +642,7 @@
path {
stroke: var(--accent-color);
- strokewidth: 1.5px;
+ stroke-width: 1.5px;
}
&:hover {
@@ -658,7 +657,8 @@
}
.machine-mechanics-content-container,
- .simulations-container {
+ .simulations-container,
+ .event-proprties-wrapper {
max-height: calc(60vh - (47px - 35px));
overflow: auto;
overflow-y: scroll;
@@ -682,6 +682,52 @@
}
}
+ .global-props {
+ .property-list-container {
+ .property-item {
+ .value-field-container {
+ margin: 0;
+ input {
+ padding: 5px 4px;
+ }
+ .dropdown {
+ top: 4px;
+ right: 4px;
+ }
+ }
+ }
+ }
+ }
+
+ .selected-actions-details {
+ .selected-actions-header .input-value {
+ padding: 8px 12px;
+ color: var(--accent-color);
+ }
+ .selected-actions-list {
+ margin-bottom: 8px;
+ .eye-dropper-input-container{
+ padding: 6px 12px;
+ .regularDropdown-container {
+ padding: 5px 8px;
+ outline: 2px solid var(--border-color);
+ outline-offset: -2px;
+ border: none;
+ }
+ }
+ .value-field-container {
+ margin: 0;
+ input {
+ padding: 5px 4px;
+ }
+ .dropdown {
+ top: 4px;
+ right: 4px;
+ }
+ }
+ }
+ }
+
.lists-main-container {
margin: 2px 8px;
width: calc(100% - 12px);
@@ -712,6 +758,7 @@
input {
width: fit-content;
+ outline: none;
accent-color: var(--accent-color);
}
}
@@ -1183,25 +1230,21 @@
z-index: 3;
padding: 8px;
width: 100%;
+ max-height: 38px;
font-size: var(--font-size-regular);
- background: color-mix(in srgb,
- var(--background-color) 40%,
- transparent);
+ background: color-mix(
+ in srgb,
+ var(--background-color) 40%,
+ transparent
+ );
backdrop-filter: blur(5px);
opacity: 0;
transition: opacity 0.3s ease;
-
- /* Added properties for ellipsis */
display: -webkit-box;
- /* Necessary for multiline truncation */
-webkit-line-clamp: 2;
- /* Number of lines to show */
-webkit-box-orient: vertical;
- /* Box orientation for the ellipsis */
overflow: hidden;
- /* Hide overflowing content */
text-overflow: ellipsis;
- /* Add ellipsis for truncated content */
}
.asset-image {
@@ -1271,4 +1314,4 @@
.assets-wrapper {
margin: 0;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts
index 75efcd3..f6b0a0c 100644
--- a/app/src/types/simulationTypes.d.ts
+++ b/app/src/types/simulationTypes.d.ts
@@ -1,163 +1,171 @@
+interface AssetEventSchema {
+ modelUuid: string;
+ modelName: string;
+ position: [number, number, number];
+ rotation: [number, number, number];
+ state: "idle" | "running" | "stopped" | "disabled" | "error";
+}
-interface PathConnection {
- fromModelUUID: string;
- fromUUID: string;
- toConnections: {
- toModelUUID: string;
- toUUID: string;
+interface TriggerSchema {
+ triggerUuid: string;
+ triggerName: string;
+ triggerType: "onComplete" | "onStart" | "onStop" | "delay" | "onError";
+ delay: number;
+ triggeredAsset: {
+ triggeredModel: { modelName: string, modelUuid: string };
+ triggeredPoint: { pointName: string, pointUuid: string };
+ triggeredAction: { actionName: string, actionUuid: string };
+ } | null;
+}
+
+interface ConveyorPointSchema {
+ uuid: string;
+ position: [number, number, number];
+ rotation: [number, number, number];
+ action: {
+ actionUuid: string;
+ actionName: string;
+ actionType: "default" | "spawn" | "swap" | "despawn";
+ material: string;
+ delay: number | "inherit";
+ spawnInterval: number | "inherit";
+ spawnCount: number | "inherit";
+ triggers: TriggerSchema[];
+ };
+}
+
+interface VehiclePointSchema {
+ uuid: string;
+ position: [number, number, number];
+ rotation: [number, number, number];
+ action: {
+ actionUuid: string;
+ actionName: string;
+ actionType: "travel";
+ material: string | null;
+ unLoadDuration: number;
+ loadCapacity: number;
+ pickUpPoint: { x: number; y: number, z: number } | null;
+ unLoadPoint: { x: number; y: number, z: number } | null;
+ triggers: TriggerSchema[];
+ };
+}
+
+interface RoboticArmPointSchema {
+ uuid: string;
+ position: [number, number, number];
+ rotation: [number, number, number];
+ actions: {
+ actionUuid: string;
+ actionName: string;
+ actionType: "pickAndPlace";
+ process: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; };
+ triggers: TriggerSchema[];
}[];
}
-interface ConnectionStore {
- connections: PathConnection[];
- setConnections: (connections: PathConnection[]) => void;
- addConnection: (newConnection: PathConnection) => void;
- removeConnection: (fromUUID: string, toUUID: string) => void;
-}
-
-interface ConveyorEventsSchema {
- modeluuid: string;
- modelName: string;
- type: "Conveyor";
- points: {
- uuid: string;
- position: [number, number, number];
- 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: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- }[];
+interface MachinePointSchema {
+ uuid: string;
position: [number, number, number];
rotation: [number, number, number];
- speed: number | string;
+ action: {
+ actionUuid: string;
+ actionName: string;
+ actionType: "process";
+ processTime: number;
+ swapMaterial: string;
+ triggers: TriggerSchema[];
+ };
}
-interface VehicleEventsSchema {
- modeluuid: string;
- modelName: string;
- type: "Vehicle";
- points: {
- uuid: string;
- position: [number, number, number];
- rotation: [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: { modelUUID: string; pointUUID: string }[];
- };
- speed: number;
- isPlaying: boolean;
- };
-
+interface StoragePointSchema {
+ uuid: string;
position: [number, number, number];
rotation: [number, number, number];
+ action: {
+ actionUuid: string;
+ actionName: string;
+ actionType: "store";
+ materials: { materialName: string; materialId: string; }[];
+ storageCapacity: number;
+ };
}
-interface StaticMachineEventsSchema {
- modeluuid: string;
- modelName: string;
- type: "StaticMachine";
- points: {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- actions: { uuid: string; name: string; buffer: number; material: string; };
- triggers: { uuid: string; name: string; type: string };
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- };
- position: [number, number, number];
- rotation: [number, number, number];
+interface ConveyorEventSchema extends AssetEventSchema {
+ type: "transfer";
+ speed: number;
+ points: ConveyorPointSchema[];
}
-interface ArmBotEventsSchema {
- modeluuid: string;
- modelName: string;
- type: "ArmBot";
- points: {
- uuid: string;
- position: [number, number, number];
- rotation: [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];
- rotation: [number, number, number];
+interface VehicleEventSchema extends AssetEventSchema {
+ type: "vehicle";
+ speed: number;
+ point: VehiclePointSchema;
}
-export type EventData = {
- modeluuid: string;
- modelname: string;
- position: [number, number, number];
- rotation: { x: number; y: number; z: number };
- modelfileID: string;
- isLocked: boolean;
- isVisible: boolean;
- eventData?:
- {
- type: "Conveyor";
- points: {
- uuid: string;
- position: [number, number, number];
- 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: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- }[];
- speed: number | string;
- }
- | {
- type: "Vehicle";
- points: {
- uuid: string;
- position: [number, number, number];
- rotation: [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: { modelUUID: string; pointUUID: string }[];
- };
- speed: number;
- };
- }
- | {
- type: "StaticMachine";
- points: {
- uuid: string;
- position: [number, number, number];
- rotation: [number, number, number];
- actions: { uuid: string; name: string; buffer: number; material: string; };
- triggers: { uuid: string; name: string; type: string };
- connections: {
- source: { modelUUID: string; pointUUID: string };
- targets: { modelUUID: string; pointUUID: string }[];
- };
- };
- }
- | {
- type: "ArmBot";
- points: {
- uuid: string;
- position: [number, number, number];
- rotation: [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 }[];
- };
- };
+interface RoboticArmEventSchema extends AssetEventSchema {
+ type: "roboticArm";
+ speed: number;
+ point: RoboticArmPointSchema;
+}
+
+interface MachineEventSchema extends AssetEventSchema {
+ type: "machine";
+ point: MachinePointSchema;
+}
+
+interface StorageEventSchema extends AssetEventSchema {
+ type: "storageUnit";
+ point: StoragePointSchema;
+}
+
+type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema;
+
+type productsSchema = {
+ productName: string;
+ productId: string;
+ eventsData: EventsSchema[];
+}[]
+
+
+interface ConveyorStatus extends ConveyorEventSchema {
+ productId: string;
+ isActive: boolean;
+ idleTime: number;
+ activeTime: number;
+}
+
+interface MachineStatus extends MachineEventSchema {
+ productId: string;
+ isActive: boolean;
+ idleTime: number;
+ activeTime: number;
+}
+
+interface ArmBotStatus extends RoboticArmEventSchema {
+ productId: string;
+ isActive: boolean;
+ idleTime: number;
+ activeTime: number;
+ currentAction?: {
+ actionUuid: string;
+ actionName: string;
};
-};
+}
+
+interface VehicleStatus extends VehicleEventSchema {
+ productId: string;
+ isActive: boolean;
+ idleTime: number;
+ activeTime: number;
+ currentLoad: number;
+ distanceTraveled: number;
+}
+
+interface StorageUnitStatus extends StorageEventSchema {
+ productId: string;
+ isActive: boolean;
+ idleTime: number;
+ activeTime: number;
+ currentLoad: number;
+}
\ No newline at end of file