From 1258d11ee87e15e5d2e71855db720e697c3fe727 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 26 May 2025 14:29:37 +0530 Subject: [PATCH 01/34] converting asset loading and other functionalities to r3f from three js --- .../builder/assetGroup/assetsGroup.tsx | 130 +++++++++++++++++- .../models/model/assetBoundingBox.tsx | 20 +++ .../builder/assetGroup/models/model/model.tsx | 100 ++++++++++++-- .../builder/assetGroup/models/models.tsx | 21 ++- app/src/modules/builder/builder.tsx | 6 +- .../selectionControls/selectionControls.tsx | 10 +- .../scene/postProcessing/postProcessing.tsx | 14 +- 7 files changed, 269 insertions(+), 32 deletions(-) create mode 100644 app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx diff --git a/app/src/modules/builder/assetGroup/assetsGroup.tsx b/app/src/modules/builder/assetGroup/assetsGroup.tsx index 9e57fb7..5fabe2d 100644 --- a/app/src/modules/builder/assetGroup/assetsGroup.tsx +++ b/app/src/modules/builder/assetGroup/assetsGroup.tsx @@ -6,8 +6,8 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { FloorItems } from "../../../types/world/worldTypes"; import { useAssetsStore } from "../../../store/builder/useAssetStore"; +import { useEventsStore } from "../../../store/simulation/useEventsStore"; import Models from "./models/models"; -import { useGLTF } from "@react-three/drei"; const gltfLoaderWorker = new Worker( new URL( @@ -19,6 +19,7 @@ const gltfLoaderWorker = new Worker( function AssetsGroup() { const { setLoadingProgress } = useLoadingProgress(); const { setAssets } = useAssetsStore(); + const { addEvent } = useEventsStore(); const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); @@ -92,6 +93,133 @@ function AssetsGroup() { opacity: 1, eventData: item.eventData }) + + if (item.eventData.type === "Vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "travel", + unLoadDuration: 5, + loadCapacity: 1, + steeringAngle: 0, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + } else if (item.eventData.type === "Conveyor") { + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "transfer", + speed: 1, + points: item.eventData.points?.map((point: any, index: number) => ({ + uuid: point.uuid || THREE.MathUtils.generateUUID(), + position: [point.position[0], point.position[1], point.position[2]], + rotation: [point.rotation[0], point.rotation[1], point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action 1`, + actionType: 'default', + material: 'Default material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) || [], + }; + addEvent(ConveyorEvent); + } else if (item.eventData.type === "StaticMachine") { + const machineEvent: MachineEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "process", + processTime: 10, + swapMaterial: "material-id", + triggers: [] + } + } + }; + addEvent(machineEvent); + } else if (item.eventData.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + } else if (item.eventData.type === 'Storage') { + const storageEvent: StorageEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", + type: "storageUnit", + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "store", + storageCapacity: 10, + triggers: [] + } + } + }; + addEvent(storageEvent); + } } else { assets.push({ modelUuid: item.modelUuid, diff --git a/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx b/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx new file mode 100644 index 0000000..c1d4881 --- /dev/null +++ b/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx @@ -0,0 +1,20 @@ +import { Box3, BoxGeometry, EdgesGeometry, Vector3 } from "three"; + +export const AssetBoundingBox = ({ asset, boundingBox }: { asset: Asset, boundingBox: Box3 | null }) => { + if (!boundingBox) return null; + + const size = boundingBox.getSize(new Vector3()); + const center = boundingBox.getCenter(new Vector3()); + + const boxGeometry = new BoxGeometry(size.x, size.y, size.z); + const edges = new EdgesGeometry(boxGeometry); + + return ( + + + + + + + ); +}; \ No newline at end of file diff --git a/app/src/modules/builder/assetGroup/models/model/model.tsx b/app/src/modules/builder/assetGroup/models/model/model.tsx index 55eb1a6..e58ef9f 100644 --- a/app/src/modules/builder/assetGroup/models/model/model.tsx +++ b/app/src/modules/builder/assetGroup/models/model/model.tsx @@ -1,13 +1,24 @@ -import { Outlines } from '@react-three/drei'; -import { useEffect, useState } from 'react'; +import * as THREE from 'three'; +import { useEffect, useRef, useState } from 'react'; import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; -import * as THREE from 'three'; +import { useFrame, useThree } from '@react-three/fiber'; +import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem } from '../../../../../store/builder/store'; +import { AssetBoundingBox } from './assetBoundingBox'; +import { CameraControls } from '@react-three/drei'; function Model({ asset }: { asset: Asset }) { + const { camera, controls } = useThree(); + const { activeTool } = useActiveTool(); + const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); + const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { renderDistance } = useRenderDistance(); + const [isRendered, setIsRendered] = useState(false); const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; const [gltfScene, setGltfScene] = useState(null); + const [boundingBox, setBoundingBox] = useState(null); + const groupRef = useRef(null); useEffect(() => { const loader = new GLTFLoader(); @@ -17,9 +28,11 @@ function Model({ asset }: { asset: Asset }) { loader.setDRACOLoader(dracoLoader); const loadModel = async () => { try { + // Check Cache const cachedModel = THREE.Cache.get(asset.assetId!); if (cachedModel) { setGltfScene(cachedModel); + calculateBoundingBox(cachedModel.scene); return; } @@ -32,6 +45,7 @@ function Model({ asset }: { asset: Asset }) { THREE.Cache.remove(blobUrl); THREE.Cache.add(asset.assetId!, gltf); setGltfScene(gltf); + calculateBoundingBox(gltf.scene); }, undefined, (error) => { @@ -49,6 +63,7 @@ function Model({ asset }: { asset: Asset }) { await storeGLTF(asset.assetId!, modelBlob); THREE.Cache.add(asset.assetId!, gltf); setGltfScene(gltf); + calculateBoundingBox(gltf.scene); }, undefined, (error) => { @@ -60,22 +75,79 @@ function Model({ asset }: { asset: Asset }) { } }; + const calculateBoundingBox = (scene: THREE.Object3D) => { + const box = new THREE.Box3().setFromObject(scene); + setBoundingBox(box); + }; + loadModel(); - }, [asset.assetId]); + }, []); + + useFrame(() => { + const assetPosition = new THREE.Vector3(...asset.position); + if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) { + setIsRendered(true); + } else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) { + setIsRendered(false); + } + }) + + const handleAssetDouble = (asset: Asset) => { + if (asset) { + if (activeTool === "cursor" && boundingBox && groupRef.current) { + const size = boundingBox.getSize(new THREE.Vector3()); + const center = boundingBox.getCenter(new THREE.Vector3()); + + const front = new THREE.Vector3(0, 0, 1); + groupRef.current.localToWorld(front); + front.sub(groupRef.current.position).normalize(); + + const distance = Math.max(size.x, size.y, size.z) * 2; + const newPosition = center.clone().addScaledVector(front, distance); + + (controls as CameraControls).setPosition( + newPosition.x, + newPosition.y, + newPosition.z, + true + ); + (controls as CameraControls).setTarget(center.x, center.y, center.z, true); + (controls as CameraControls).fitToBox(groupRef.current!, true, { + cover: true, + paddingTop: 5, + paddingLeft: 5, + paddingBottom: 5, + paddingRight: 5, + }); + setSelectedFloorItem(groupRef.current); + + } + } + }; return ( - <> - {gltfScene && - + { + e.stopPropagation(); + handleAssetDouble(asset); + }} + > + {gltfScene && ( + isRendered ? ( - - } - + ) : ( + + ) + )} + ); } diff --git a/app/src/modules/builder/assetGroup/models/models.tsx b/app/src/modules/builder/assetGroup/models/models.tsx index 7378812..4553531 100644 --- a/app/src/modules/builder/assetGroup/models/models.tsx +++ b/app/src/modules/builder/assetGroup/models/models.tsx @@ -1,16 +1,31 @@ -import React from 'react' import { useAssetsStore } from '../../../../store/builder/useAssetStore'; import Model from './model/model'; +import { useThree } from '@react-three/fiber'; +import { CameraControls } from '@react-three/drei'; +import { Vector3 } from 'three'; +import { useSelectedFloorItem } from '../../../../store/builder/store'; function Models() { + const { controls } = useThree(); const { assets } = useAssetsStore(); + const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); return ( - <> + { + e.stopPropagation(); + if (selectedFloorItem) { + const target = (controls as CameraControls).getTarget(new Vector3()); + (controls as CameraControls).setTarget(target.x, 0, target.z, true); + setSelectedFloorItem(null); + } + }} + > {assets.map((asset) => )} - + ) } diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index 18d407b..3189968 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -243,7 +243,7 @@ export default function Builder() { /> - + /> */} - {/* */} + diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 16f992b..763faa3 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -49,10 +49,10 @@ const SelectionControls: React.FC = () => { const helper = new SelectionHelper(gl); - if (!itemsGroup) { - echo.warn("itemsGroup not found in the scene."); - return; - } + // if (!itemsGroup) { + // echo.warn("itemsGroup not found in the scene."); + // return; + // } const onPointerDown = (event: PointerEvent) => { if (event.button === 2) { @@ -169,7 +169,7 @@ const SelectionControls: React.FC = () => { selectedObjects.map((object) => { let currentObject: THREE.Object3D | null = object; while (currentObject) { - if (currentObject.userData.modelId) { + if (currentObject.userData.modelUuid) { Objects.add(currentObject); break; } diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 426e199..7c5db64 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -1,4 +1,3 @@ -import * as THREE from "three"; import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing"; import { BlendFunction } from "postprocessing"; import { @@ -6,15 +5,14 @@ import { useSelectedWallItem, useSelectedFloorItem, } from "../../../store/builder/store"; -import * as Types from "../../../types/world/worldTypes"; import * as CONSTANTS from "../../../types/world/worldConstants"; -import { useEffect } from "react"; import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; +import { useEffect } from "react"; export default function PostProcessing() { - const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); - const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); - const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { deletableFloorItem } = useDeletableFloorItem(); + const { selectedWallItem } = useSelectedWallItem(); + const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventSphere } = useSelectedEventSphere(); function flattenChildren(children: any[]) { @@ -28,6 +26,10 @@ export default function PostProcessing() { return allChildren; } + useEffect(()=>{ + console.log('selectedFloorItem: ', selectedFloorItem); + },[selectedFloorItem]) + return ( <> -- 2.49.1 From b086ee8f75324deb4b8aac5f67b7ae889ba63ad9 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 26 May 2025 18:03:27 +0530 Subject: [PATCH 02/34] Refactor asset management and selection controls - Removed the FloorItemsGroup component to streamline asset handling. - Updated socket response handling by removing TempLoader integration. - Enhanced CopyPasteControls and DuplicationControls to utilize the new asset management structure. - Integrated asset addition and updates in move, rotate, and selection controls. - Improved performance by skipping items without valid modelfileID in the GLTF loader worker. - Cleaned up unused variables and imports across various control components. - Added logging for selectedFloorItem and deletableFloorItem for debugging purposes. --- .../IntialLoad/loadInitialFloorItems.ts | 343 -------------- .../builder/assetGroup/assetsGroup.tsx | 54 ++- .../models/model/assetBoundingBox.tsx | 2 +- .../builder/assetGroup/models/model/model.tsx | 78 ++- app/src/modules/builder/builder.tsx | 17 +- .../geomentries/assets/addAssetModel.ts | 122 ++--- .../geomentries/assets/assetManager.ts | 153 ------ .../geomentries/assets/assetVisibility.ts | 25 - .../assets/deletableHoveredFloorItems.ts | 43 -- .../geomentries/assets/deleteFloorItems.ts | 88 ---- .../builder/geomentries/assets/tempLoader.ts | 29 -- .../builder/groups/floorItemsGroup.tsx | 445 ------------------ .../socket/socketResponses.dev.tsx | 9 - .../selectionControls/copyPasteControls.tsx | 64 ++- .../selectionControls/duplicationControls.tsx | 68 ++- .../selectionControls/moveControls.tsx | 67 ++- .../selectionControls/rotateControls.tsx | 85 ++-- .../selectionControls/selectionControls.tsx | 34 +- .../scene/postProcessing/postProcessing.tsx | 6 +- .../webWorkers/assetManagerWorker.js | 51 -- .../webWorkers/gltfLoaderWorker.js | 3 + 21 files changed, 370 insertions(+), 1416 deletions(-) delete mode 100644 app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts delete mode 100644 app/src/modules/builder/geomentries/assets/assetManager.ts delete mode 100644 app/src/modules/builder/geomentries/assets/assetVisibility.ts delete mode 100644 app/src/modules/builder/geomentries/assets/deletableHoveredFloorItems.ts delete mode 100644 app/src/modules/builder/geomentries/assets/deleteFloorItems.ts delete mode 100644 app/src/modules/builder/geomentries/assets/tempLoader.ts delete mode 100644 app/src/modules/builder/groups/floorItemsGroup.tsx delete mode 100644 app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts deleted file mode 100644 index 096665a..0000000 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ /dev/null @@ -1,343 +0,0 @@ -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 * 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, - addEvent: (event: EventsSchema) => void, - renderDistance: number -): 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) < renderDistance) { - await new Promise(async (resolve) => { - - // Check Three.js Cache - const cachedModel = THREE.Cache.get(item.modelfileID!); - if (cachedModel) { - processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent); - modelsLoaded++; - checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); - return; - } - - // Check IndexedDB - const indexedDBModel = await retrieveGLTF(item.modelfileID!); - if (indexedDBModel) { - 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, addEvent); - modelsLoaded++; - checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); - }, - undefined, - (error) => { - echo.error(`[IndexedDB] Error loading ${item.modelName}:`); - URL.revokeObjectURL(blobUrl); - resolve(); - } - ); - return; - } - - // Fetch from Backend - 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, addEvent); - modelsLoaded++; - checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); - }, - undefined, - (error) => { - echo.error(`[Backend] Error loading ${item.modelName}:`); - resolve(); - } - ); - }); - } else { - // - 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, - addEvent: (event: EventsSchema) => void, -) { - const model = gltf.clone(); - model.uuid = item.modelUuid; - model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid, eventData: item.eventData }; - 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); - - if (item.eventData) { - setFloorItems((prevItems) => [ - ...(prevItems || []), - { - modelUuid: item.modelUuid, - modelName: item.modelName, - position: item.position, - rotation: item.rotation, - modelfileID: item.modelfileID, - isLocked: item.isLocked, - isVisible: item.isVisible, - eventData: item.eventData, - }, - ]); - - if (item.eventData.type === "Vehicle") { - const vehicleEvent: VehicleEventSchema = { - modelUuid: item.modelUuid, - modelName: item.modelName, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "vehicle", - speed: 1, - point: { - uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), - position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], - rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "travel", - unLoadDuration: 5, - loadCapacity: 1, - steeringAngle: 0, - pickUpPoint: null, - unLoadPoint: null, - triggers: [] - } - } - }; - addEvent(vehicleEvent); - } else if (item.eventData.type === "Conveyor") { - const ConveyorEvent: ConveyorEventSchema = { - modelUuid: item.modelUuid, - modelName: item.modelName, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "transfer", - speed: 1, - points: item.eventData.points?.map((point: any, index: number) => ({ - uuid: point.uuid || THREE.MathUtils.generateUUID(), - position: [point.position[0], point.position[1], point.position[2]], - rotation: [point.rotation[0], point.rotation[1], point.rotation[2]], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action 1`, - actionType: 'default', - material: 'Default material', - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: [] - } - })) || [], - }; - addEvent(ConveyorEvent); - } else if (item.eventData.type === "StaticMachine") { - const machineEvent: MachineEventSchema = { - modelUuid: item.modelUuid, - modelName: item.modelName, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "machine", - point: { - uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), - position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], - rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "process", - processTime: 10, - swapMaterial: "material-id", - triggers: [] - } - } - }; - addEvent(machineEvent); - } else if (item.eventData.type === "ArmBot") { - const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: item.modelUuid, - modelName: item.modelName, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "roboticArm", - speed: 1, - point: { - uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), - position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], - rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], - actions: [ - { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "pickAndPlace", - process: { - startPoint: null, - endPoint: null - }, - triggers: [] - } - ] - } - }; - addEvent(roboticArmEvent); - } else if (item.eventData.type === 'Storage') { - const storageEvent: StorageEventSchema = { - modelUuid: item.modelUuid, - modelName: item.modelName, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", - type: "storageUnit", - point: { - uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), - position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], - rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "store", - storageCapacity: 10, - triggers: [] - } - } - }; - addEvent(storageEvent); - } - } else { - 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) { - echo.success("Models Loaded!"); - dracoLoader.dispose(); - } - resolve(); -} - -export default loadInitialFloorItems; \ No newline at end of file diff --git a/app/src/modules/builder/assetGroup/assetsGroup.tsx b/app/src/modules/builder/assetGroup/assetsGroup.tsx index 5fabe2d..5fe75a4 100644 --- a/app/src/modules/builder/assetGroup/assetsGroup.tsx +++ b/app/src/modules/builder/assetGroup/assetsGroup.tsx @@ -1,13 +1,17 @@ import * as THREE from "three" import { useEffect } from 'react' import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; -import { useLoadingProgress } from '../../../store/builder/store'; +import { useLoadingProgress, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store'; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; -import { FloorItems } from "../../../types/world/worldTypes"; +import { FloorItems, RefGroup, RefMesh } from "../../../types/world/worldTypes"; import { useAssetsStore } from "../../../store/builder/useAssetStore"; import { useEventsStore } from "../../../store/simulation/useEventsStore"; import Models from "./models/models"; +import useModuleStore from "../../../store/useModuleStore"; +import { useThree } from "@react-three/fiber"; +import { CameraControls } from "@react-three/drei"; +import addAssetModel from "../geomentries/assets/addAssetModel"; const gltfLoaderWorker = new Worker( new URL( @@ -16,10 +20,15 @@ const gltfLoaderWorker = new Worker( ) ); -function AssetsGroup() { +function AssetsGroup({ floorGroup, plane }: { floorGroup: RefGroup, plane: RefMesh }) { + const { activeModule } = useModuleStore(); + const { socket } = useSocketStore(); + const { controls, gl, pointer, camera, raycaster } = useThree(); const { setLoadingProgress } = useLoadingProgress(); - const { setAssets } = useAssetsStore(); + const { setAssets, addAsset } = useAssetsStore(); const { addEvent } = useEventsStore(); + const { setSelectedFloorItem } = useSelectedFloorItem(); + const { selectedItem, setSelectedItem } = useSelectedItem(); const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); @@ -243,6 +252,43 @@ function AssetsGroup() { }; }, []); + useEffect(() => { + const canvasElement = gl.domElement; + + const onDrop = (event: any) => { + if (!event.dataTransfer?.files[0]) return; + + if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') { + + pointer.x = (event.clientX / window.innerWidth) * 2 - 1; + pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; + + addAssetModel(raycaster, camera, pointer, floorGroup, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane); + } + }; + + const onDragOver = (event: any) => { + event.preventDefault(); + }; + + + if (activeModule === "builder") { + canvasElement.addEventListener("drop", onDrop); + canvasElement.addEventListener("dragover", onDragOver); + } else { + if ((controls as CameraControls)) { + const target = (controls as CameraControls).getTarget(new THREE.Vector3()); + (controls as CameraControls).setTarget(target.x, 0, target.z, true); + setSelectedFloorItem(null); + } + } + + return () => { + canvasElement.removeEventListener("drop", onDrop); + canvasElement.removeEventListener("dragover", onDragOver); + }; + }, [selectedItem, camera, pointer, activeModule, controls]); + return ( <> diff --git a/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx b/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx index c1d4881..18648dc 100644 --- a/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx +++ b/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx @@ -10,7 +10,7 @@ export const AssetBoundingBox = ({ asset, boundingBox }: { asset: Asset, boundin const edges = new EdgesGeometry(boxGeometry); return ( - + diff --git a/app/src/modules/builder/assetGroup/models/model/model.tsx b/app/src/modules/builder/assetGroup/models/model/model.tsx index e58ef9f..07e027c 100644 --- a/app/src/modules/builder/assetGroup/models/model/model.tsx +++ b/app/src/modules/builder/assetGroup/models/model/model.tsx @@ -7,12 +7,18 @@ import { useFrame, useThree } from '@react-three/fiber'; import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem } from '../../../../../store/builder/store'; import { AssetBoundingBox } from './assetBoundingBox'; import { CameraControls } from '@react-three/drei'; +import { useAssetsStore } from '../../../../../store/builder/useAssetStore'; +import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../../store/simulation/useProductStore"; +import { useSocketStore } from '../../../../../store/builder/store'; function Model({ asset }: { asset: Asset }) { const { camera, controls } = useThree(); const { activeTool } = useActiveTool(); + const { removeAsset } = useAssetsStore(); + const { socket } = useSocketStore(); const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); - const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { setSelectedFloorItem } = useSelectedFloorItem(); const { renderDistance } = useRenderDistance(); const [isRendered, setIsRendered] = useState(false); const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -93,7 +99,7 @@ function Model({ asset }: { asset: Asset }) { } }) - const handleAssetDouble = (asset: Asset) => { + const handleDblClick = (asset: Asset) => { if (asset) { if (activeTool === "cursor" && boundingBox && groupRef.current) { const size = boundingBox.getSize(new THREE.Vector3()); @@ -126,6 +132,60 @@ function Model({ asset }: { asset: Asset }) { } }; + const handleClick = (asset: Asset) => { + if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) { + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + + //REST + + // const response = await deleteFloorItem(organization, asset.modelUuid, asset.modelName); + + //SOCKET + + const data = { + organization: organization, + modelUuid: asset.modelUuid, + modelName: asset.modelName, + socketId: socket.id + } + + const response = socket.emit('v2:model-asset:delete', data) + + useEventsStore.getState().removeEvent(asset.modelUuid); + useProductStore.getState().deleteEvent(asset.modelUuid); + + if (response) { + + const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); + const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== asset.modelUuid); + localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); + + removeAsset(asset.modelUuid); + + echo.success("Model Removed!"); + } + + } + } + + const handlePointerOver = (asset: Asset) => { + if (activeTool === "delete") { + if (deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) { + return; + } else { + setDeletableFloorItem(groupRef.current); + } + } + } + + const handlePointerOut = (asset: Asset) => { + if (activeTool === "delete" && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) { + setDeletableFloorItem(null); + } + } + return ( { + e.stopPropagation(); + handleDblClick(asset); + }} onClick={(e) => { e.stopPropagation(); - handleAssetDouble(asset); + handleClick(asset); + }} + onPointerOver={(e) => { + e.stopPropagation(); + handlePointerOver(asset); + }} + onPointerOut={(e) => { + e.stopPropagation(); + handlePointerOut(asset); }} > {gltfScene && ( diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index 3189968..dcd2659 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -33,7 +33,6 @@ 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"; @@ -87,7 +86,6 @@ export default function Builder() { 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. @@ -96,7 +94,6 @@ export default function Builder() { 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... @@ -243,15 +240,6 @@ export default function Builder() { /> - {/* */} - + diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 692664e..7847651 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -1,15 +1,11 @@ import * as THREE from 'three'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; -import gsap from 'gsap'; -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 { 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 { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator'; async function addAssetModel( @@ -17,14 +13,11 @@ async function addAssetModel( camera: THREE.Camera, pointer: THREE.Vector2, floorGroup: Types.RefGroup, - setFloorItems: Types.setFloorItemSetState, - itemsGroup: Types.RefGroup, - isTempLoader: Types.RefBoolean, - tempLoader: Types.RefMesh, socket: Socket, selectedItem: any, setSelectedItem: any, addEvent: (event: EventsSchema) => void, + addAsset: (asset: Asset) => void, plane: Types.RefMesh, ): Promise { @@ -33,7 +26,6 @@ async function addAssetModel( let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; try { - isTempLoader.current = true; const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); @@ -61,46 +53,32 @@ async function addAssetModel( if (intersectPoint.y < 0) { intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z); } - // console.log('selectedItem: ', selectedItem); const cachedModel = THREE.Cache.get(selectedItem.id); if (cachedModel) { - // console.log(`[Cache] Fetching ${selectedItem.name}`); - handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket); + handleModelLoad(cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket); return; } else { const cachedModelBlob = await retrieveGLTF(selectedItem.id); - if (cachedModelBlob) { - // console.log(`Added ${selectedItem.name} from indexDB`); - const blobUrl = URL.createObjectURL(cachedModelBlob); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(selectedItem.id, gltf); - handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket); - }, - () => { - TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); - }); + handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket); + }); } else { - // console.log(`Added ${selectedItem.name} from Backend`); - loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => { 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, addEvent, socket); - }, - () => { - TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); - }); + await handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket); + }) } } } } catch (error) { echo.error("Failed to add asset"); - console.error('Error fetching asset model:', error); } finally { setSelectedItem({}); } @@ -110,11 +88,8 @@ async function handleModelLoad( gltf: any, intersectPoint: THREE.Vector3, selectedItem: any, - itemsGroup: Types.RefGroup, - tempLoader: Types.RefMesh, - isTempLoader: Types.RefBoolean, - setFloorItems: Types.setFloorItemSetState, addEvent: (event: EventsSchema) => void, + addAsset: (asset: Asset) => void, socket: Socket ) { const model = gltf.scene.clone(); @@ -129,22 +104,16 @@ async function handleModelLoad( } }); - 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 = { + const newFloorItem: Asset = { modelUuid: model.uuid, modelName: selectedItem.name, - modelfileID: selectedItem.id, + assetId: selectedItem.id, position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], - rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + rotation: [0, 0, 0], isLocked: false, - isVisible: true + isVisible: true, + isCollidable: false, + opacity: 1, }; const email = localStorage.getItem("email"); @@ -158,7 +127,7 @@ async function handleModelLoad( // newFloorItem.modelName, // newFloorItem.modelfileID, // newFloorItem.position, - // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + // { x: 0, y: 0, z: 0 }, // false, // true, // ); @@ -183,7 +152,7 @@ async function handleModelLoad( modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, - rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + rotation: newFloorItem.rotation, state: "idle", type: 'transfer', speed: 1, @@ -252,7 +221,7 @@ async function handleModelLoad( modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, - rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + rotation: newFloorItem.rotation, state: "idle", type: "vehicle", speed: 1, @@ -285,7 +254,7 @@ async function handleModelLoad( modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, - rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + rotation: newFloorItem.rotation, state: "idle", type: "roboticArm", speed: 1, @@ -319,7 +288,7 @@ async function handleModelLoad( modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, - rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + rotation: newFloorItem.rotation, state: "idle", type: "machine", point: { @@ -347,7 +316,7 @@ async function handleModelLoad( modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, - rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + rotation: newFloorItem.rotation, state: "idle", type: "storageUnit", point: { @@ -375,7 +344,7 @@ async function handleModelLoad( organization, modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, - modelfileID: newFloorItem.modelfileID, + modelfileID: newFloorItem.assetId, position: newFloorItem.position, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, isLocked: false, @@ -384,27 +353,30 @@ async function handleModelLoad( eventData: eventData }; - model.userData.eventData = eventData; - - newFloorItem.eventData = eventData; - - setFloorItems((prevItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - socket.emit("v2:model-asset:add", completeData); - 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: () => { echo.success("Model Added!"); } }); + const asset: Asset = { + modelUuid: completeData.modelUuid, + modelName: completeData.modelName, + assetId: completeData.modelfileID, + position: completeData.position, + rotation: [completeData.rotation.x, completeData.rotation.y, completeData.rotation.z] as [number, number, number], + isLocked: completeData.isLocked, + isCollidable: false, + isVisible: completeData.isVisible, + opacity: 1, + eventData: completeData.eventData + } + + addAsset(asset); + } else { const data = { organization, modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, - modelfileID: newFloorItem.modelfileID, + modelfileID: newFloorItem.assetId, position: newFloorItem.position, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, isLocked: false, @@ -412,16 +384,22 @@ async function handleModelLoad( socketId: socket.id }; - setFloorItems((prevItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - socket.emit("v2:model-asset:add", data); - gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); - gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { echo.success("Model Added!"); } }); + const asset = { + modelUuid: data.modelUuid, + modelName: data.modelName, + assetId: data.modelfileID, + position: data.position, + rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [number, number, number], + isLocked: data.isLocked, + isCollidable: false, + isVisible: data.isVisible, + opacity: 1 + } + + addAsset(asset); + } } diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts deleted file mode 100644 index 5d2f90f..0000000 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ /dev/null @@ -1,153 +0,0 @@ -import * as THREE from "three"; -import gsap from "gsap"; -import * as Types from "../../../../types/world/worldTypes"; -import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; -import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils"; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import { toast } from 'react-toastify'; - -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; -let currentTaskId = 0; // Track the active task -let activePromises = new Map(); // Map to track task progress - -export default async function assetManager( - data: any, - itemsGroup: Types.RefGroup, - loader: GLTFLoader, -) { - const taskId = ++currentTaskId; // Increment taskId for each call - activePromises.set(taskId, true); // Mark task as active - - // - - if (data.toRemove.length > 0) { - data.toRemove.forEach((uuid: string) => { - const item = itemsGroup.current.getObjectByProperty("uuid", uuid); - if (item) { - // Traverse and dispose of resources - // item.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(); - // } - // } - // }); - - // Remove the object from the scene - itemsGroup.current.remove(item); - } - }); - } - - if (data.toAdd.length > 0) { - await initializeDB(); - - for (const item of data.toAdd) { - if (!activePromises.get(taskId)) return; // Stop processing if task is canceled - - await new Promise(async (resolve) => { - const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; - - // Check Three.js Cache - const cachedModel = THREE.Cache.get(item.modelfileID!); - if (cachedModel) { - // - processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve); - return; - } - - // Check IndexedDB - const indexedDBModel = await retrieveGLTF(item.modelfileID!); - if (indexedDBModel) { - // - const blobUrl = URL.createObjectURL(indexedDBModel); - loader.load( - blobUrl, - (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(item.modelfileID!, gltf); // Add to cache - processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve); - }, - undefined, - (error) => { - echo.error(`[IndexedDB] Error loading ${item.modelName}:`); - resolve(); - } - ); - return; - } - - // Fetch from Backend - // - loader.load( - modelUrl, - async (gltf) => { - const modelBlob = await fetch(modelUrl).then((res) => res.blob()); - await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB - THREE.Cache.add(item.modelfileID!, gltf); // Add to cache - processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve); - }, - undefined, - (error) => { - echo.error(`[Backend] Error loading ${item.modelName}:`); - resolve(); - } - ); - }); - } - - function processLoadedModel( - gltf: any, - item: Types.FloorItemType, - itemsGroup: Types.RefGroup, - resolve: () => void - ) { - if (!activePromises.get(taskId)) return; // Stop processing if task is canceled - - const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modelUuid); - if (existingModel) { - // - resolve(); - return; - } - - const model = gltf; - model.uuid = item.modelUuid; - model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid, eventData: item.eventData }; - model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - 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); - - 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: 0.5, ease: "power2.out", onStart: resolve, }); - } - } - - activePromises.delete(taskId); // Mark task as complete -} - -// Cancel ongoing task when new call arrives -export function cancelOngoingTasks() { - activePromises.clear(); // Clear all ongoing tasks -} diff --git a/app/src/modules/builder/geomentries/assets/assetVisibility.ts b/app/src/modules/builder/geomentries/assets/assetVisibility.ts deleted file mode 100644 index c2503c3..0000000 --- a/app/src/modules/builder/geomentries/assets/assetVisibility.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as Types from "../../../../types/world/worldTypes"; - -let lastUpdateTime = 0; - -export default function assetVisibility( - itemsGroup: Types.RefGroup, - cameraPosition: Types.Vector3, - renderDistance: Types.Number, - throttleTime = 100 -): void { - const now = performance.now(); - if (now - lastUpdateTime < throttleTime) return; - lastUpdateTime = now; - - if (!itemsGroup?.current || !cameraPosition) return; - - itemsGroup.current.children.forEach((child) => { - const Distance = cameraPosition.distanceTo(child.position); - if (Distance <= renderDistance) { - child.visible = true; - } else { - child.visible = false; - } - }); -} diff --git a/app/src/modules/builder/geomentries/assets/deletableHoveredFloorItems.ts b/app/src/modules/builder/geomentries/assets/deletableHoveredFloorItems.ts deleted file mode 100644 index 2913b1a..0000000 --- a/app/src/modules/builder/geomentries/assets/deletableHoveredFloorItems.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function DeletableHoveredFloorItems( - state: Types.ThreeState, - itemsGroup: Types.RefGroup, - hoveredDeletableFloorItem: Types.RefMesh, - setDeletableFloorItem: any -): void { - - ////////// Altering the color of the hovered GLTF item during the Deletion time ////////// - - state.raycaster.setFromCamera(state.pointer, state.camera); - const intersects = state.raycaster.intersectObjects(itemsGroup.current.children, true); - - if (intersects.length > 0) { - if (intersects[0].object.name === "Pole") { - return; - } - if (hoveredDeletableFloorItem.current) { - hoveredDeletableFloorItem.current = undefined; - setDeletableFloorItem(null); - } - let currentObject = intersects[0].object; - - while (currentObject) { - if (currentObject.name === "Scene") { - hoveredDeletableFloorItem.current = currentObject as THREE.Mesh; - setDeletableFloorItem(currentObject); - break; - } - currentObject = currentObject.parent as THREE.Object3D; - } - } else { - if (hoveredDeletableFloorItem.current) { - hoveredDeletableFloorItem.current = undefined; - setDeletableFloorItem(null); - } - } -} - -export default DeletableHoveredFloorItems; diff --git a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts deleted file mode 100644 index 5b234b4..0000000 --- a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { toast } from 'react-toastify'; -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; -// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; -import { Socket } from 'socket.io-client'; -import { getFloorAssets } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; -import { useEventsStore } from "../../../../store/simulation/useEventsStore"; -import { useProductStore } from "../../../../store/simulation/useProductStore"; - -async function DeleteFloorItems( - itemsGroup: Types.RefGroup, - hoveredDeletableFloorItem: Types.RefMesh, - setFloorItems: Types.setFloorItemSetState, - socket: Socket -): Promise { - - ////////// Deleting the hovered Floor GLTF from the scene (itemsGroup.current) and from the floorItems and also update it in the localstorage ////////// - - if (hoveredDeletableFloorItem.current) { - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - const items = await getFloorAssets(organization); - const removedItem = items.find( - (item: { modelUuid: string }) => item.modelUuid === hoveredDeletableFloorItem.current?.uuid - ); - - if (!removedItem) { - return - } - - //REST - - // const response = await deleteFloorItem(organization, removedItem.modelUuid, removedItem.modelName); - - //SOCKET - - const data = { - organization: organization, - modelUuid: removedItem.modelUuid, - modelName: removedItem.modelName, - socketId: socket.id - } - - const response = socket.emit('v2:model-asset:delete', data) - - useEventsStore.getState().removeEvent(removedItem.modelUuid); - useProductStore.getState().deleteEvent(removedItem.modelUuid); - - if (response) { - const updatedItems = items.filter( - (item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid - ); - - const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); - const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid); - localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); - - if (hoveredDeletableFloorItem.current) { - // Traverse and dispose of resources - hoveredDeletableFloorItem.current.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(); - } - } - }); - - // Remove the object from the scene - itemsGroup.current.remove(hoveredDeletableFloorItem.current); - } - setFloorItems(updatedItems); - - echo.success("Model Removed!"); - } - } -} - -export default DeleteFloorItems; diff --git a/app/src/modules/builder/geomentries/assets/tempLoader.ts b/app/src/modules/builder/geomentries/assets/tempLoader.ts deleted file mode 100644 index 73d2f9e..0000000 --- a/app/src/modules/builder/geomentries/assets/tempLoader.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function TempLoader( - intersectPoint: Types.Vector3, - isTempLoader: Types.RefBoolean, - tempLoader: Types.RefMesh, - itemsGroup: Types.RefGroup -): void { - - ////////// Temporary Loader that indicates the gltf is being loaded ////////// - - ////////// Bug: Can't Load More than one TempLoader if done, it won't leave the scene ////////// - - if (tempLoader.current) { - itemsGroup.current.remove(tempLoader.current); - } - if (isTempLoader.current) { - const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); - const cubeMaterial = new THREE.MeshBasicMaterial({ color: "white" }); - tempLoader.current = new THREE.Mesh(cubeGeometry, cubeMaterial); - tempLoader.current.position.set(intersectPoint.x, 0.5 + intersectPoint.y, intersectPoint.z); - itemsGroup.current.add(tempLoader.current); - isTempLoader.current = false; - } -} - -export default TempLoader; diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx deleted file mode 100644 index 58f8f05..0000000 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ /dev/null @@ -1,445 +0,0 @@ -import { useFrame, useThree } from "@react-three/fiber"; -import { - useActiveTool, - useCamMode, - useDeletableFloorItem, - useDeleteTool, - useFloorItems, - useLoadingProgress, - useRenderDistance, - useSelectedFloorItem, - useSelectedItem, - useSocketStore, - useToggleView, -} from "../../../store/builder/store"; -import { useEffect } from "react"; -import * as THREE from "three"; -import * as Types from "../../../types/world/worldTypes"; -import assetManager, { - cancelOngoingTasks, -} from "../geomentries/assets/assetManager"; -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 "../IntialLoad/loadInitialFloorItems"; -import addAssetModel from "../geomentries/assets/addAssetModel"; -import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; -import useModuleStore from "../../../store/useModuleStore"; -import { useEventsStore } from "../../../store/simulation/useEventsStore"; -import { findEnvironment } from "../../../services/factoryBuilder/environment/findEnvironment"; - -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 - ) -); - -const FloorItemsGroup = ({ - itemsGroup, - hoveredDeletableFloorItem, - AttachedObject, - floorGroup, - tempLoader, - isTempLoader, - plane, -}: any) => { - const state: Types.ThreeState = useThree(); - const { raycaster, controls }: any = state; - const { renderDistance } = useRenderDistance(); - const { toggleView } = useToggleView(); - const { floorItems, setFloorItems } = useFloorItems(); - const { camMode } = useCamMode(); - const { deleteTool } = useDeleteTool(); - const { setDeletableFloorItem } = useDeletableFloorItem(); - const { setSelectedFloorItem } = useSelectedFloorItem(); - const { activeTool } = useActiveTool(); - const { selectedItem, setSelectedItem } = useSelectedItem(); - 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); - - useEffect(() => { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; - - findEnvironment( - organization, - localStorage.getItem("userId")! - ).then((evnironMentData) => { - - let totalAssets = 0; - let loadedAssets = 0; - - const updateLoadingProgress = (progress: number) => { - if (progress < 100) { - setLoadingProgress(progress); - } else if (progress === 100) { - setTimeout(() => { - setLoadingProgress(100); - setTimeout(() => { - setLoadingProgress(0); - }, 1500); - }, 1000); - } - }; - - getFloorAssets(organization).then((data) => { - if (data.length > 0) { - const uniqueItems = (data as Types.FloorItems).filter( - (item, index, self) => - index === self.findIndex((t) => t.modelfileID === item.modelfileID) - ); - totalAssets = uniqueItems.length; - if (totalAssets === 0) { - updateLoadingProgress(100); - return; - } - gltfLoaderWorker.postMessage({ floorItems: uniqueItems }); - } else { - gltfLoaderWorker.postMessage({ floorItems: [] }); - loadInitialFloorItems( - itemsGroup, - setFloorItems, - addEvent, - evnironMentData.renderDistance - ); - updateLoadingProgress(100); - } - }); - - gltfLoaderWorker.onmessage = async (event) => { - if (event.data.message === "gltfLoaded" && event.data.modelBlob) { - const blobUrl = URL.createObjectURL(event.data.modelBlob); - - loader.load(blobUrl, (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(event.data.modelID, gltf); - - loadedAssets++; - const progress = Math.round((loadedAssets / totalAssets) * 100); - updateLoadingProgress(progress); - - if (loadedAssets === totalAssets) { - loadInitialFloorItems( - itemsGroup, - setFloorItems, - addEvent, - evnironMentData.renderDistance - ); - updateLoadingProgress(100); - } - }); - } - }; - }) - }, []); - - useEffect(() => { - assetManagerWorker.onmessage = async (event) => { - cancelOngoingTasks(); // Cancel the ongoing process - await assetManager(event.data, itemsGroup, loader); - }; - }, [assetManagerWorker]); - - useEffect(() => { - if (toggleView) return; - - const uuids: string[] = []; - itemsGroup.current?.children.forEach((child: any) => { - uuids.push(child.uuid); - }); - const cameraPosition = state.camera.position; - - assetManagerWorker.postMessage({ - floorItems, - cameraPosition, - uuids, - renderDistance, - }); - }, [camMode, renderDistance]); - - useEffect(() => { - const controls: any = state.controls; - const camera: any = state.camera; - - if (controls) { - let intervalId: NodeJS.Timeout | null = null; - - const handleChange = () => { - if (toggleView) return; - - const uuids: string[] = []; - itemsGroup.current?.children.forEach((child: any) => { - uuids.push(child.uuid); - }); - const cameraPosition = camera.position; - - assetManagerWorker.postMessage({ - floorItems, - cameraPosition, - uuids, - renderDistance, - }); - }; - - const startInterval = () => { - intervalId ??= setInterval(handleChange, 50); - }; - - const stopInterval = () => { - handleChange(); - if (intervalId) { - clearInterval(intervalId); - intervalId = null; - } - }; - - controls.addEventListener("rest", handleChange); - controls.addEventListener("rest", stopInterval); - controls.addEventListener("control", startInterval); - controls.addEventListener("controlend", stopInterval); - - return () => { - controls.removeEventListener("rest", handleChange); - controls.removeEventListener("rest", stopInterval); - controls.removeEventListener("control", startInterval); - controls.removeEventListener("controlend", stopInterval); - if (intervalId) { - clearInterval(intervalId); - } - }; - } - }, [state.controls, floorItems, toggleView, renderDistance]); - - 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 = async (evt: any) => { - if (controls) { - (controls as any).enabled = true; - } - if (evt.button === 0) { - isLeftMouseDown = false; - if (drag) return; - - if (deleteTool) { - DeleteFloorItems( - itemsGroup, - hoveredDeletableFloorItem, - setFloorItems, - socket - ); - } - - if (activeTool === "cursor") { - if (!itemsGroup.current) return; - let intersects = raycaster.intersectObjects( - itemsGroup.current.children, - true - ); - if ( - intersects.length > 0 && - intersects[0]?.object?.parent?.parent?.position && - intersects[0]?.object?.parent?.parent?.scale && - intersects[0]?.object?.parent?.parent?.rotation - ) { - // let currentObject = intersects[0].object; - // while (currentObject) { - // if (currentObject.name === "Scene") { - // break; - // } - // currentObject = currentObject.parent as THREE.Object3D; - // } - // if (currentObject) { - // AttachedObject.current = currentObject as any; - // setSelectedFloorItem(AttachedObject.current!); - // } - } else { - const target = controls.getTarget(new THREE.Vector3()); - await controls.setTarget(target.x, 0, target.z, true); - setSelectedFloorItem(null); - } - } - } - }; - - const onDblClick = async (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = false; - if (drag) return; - - - if (activeTool === "cursor") { - if (!itemsGroup.current) return; - let intersects = raycaster.intersectObjects( - itemsGroup.current.children, - true - ); - if ( - intersects.length > 0 && - intersects[0]?.object?.parent?.parent?.position && - intersects[0]?.object?.parent?.parent?.scale && - intersects[0]?.object?.parent?.parent?.rotation - ) { - let currentObject = intersects[0].object; - - while (currentObject) { - if (currentObject.name === "Scene") { - break; - } - currentObject = currentObject.parent as THREE.Object3D; - } - if (currentObject) { - AttachedObject.current = currentObject as any; - // controls.fitToSphere(AttachedObject.current!, true); - - const bbox = new THREE.Box3().setFromObject( - AttachedObject.current - ); - const size = bbox.getSize(new THREE.Vector3()); - const center = bbox.getCenter(new THREE.Vector3()); - - const front = new THREE.Vector3(0, 0, 1); - AttachedObject.current.localToWorld(front); - front.sub(AttachedObject.current.position).normalize(); - - const distance = Math.max(size.x, size.y, size.z) * 2; - const newPosition = center - .clone() - .addScaledVector(front, distance); - - controls.setPosition( - newPosition.x, - newPosition.y, - newPosition.z, - true - ); - controls.setTarget(center.x, center.y, center.z, true); - controls.fitToBox(AttachedObject.current!, true, { - cover: true, - paddingTop: 5, - paddingLeft: 5, - paddingBottom: 5, - paddingRight: 5, - }); - - setSelectedFloorItem(AttachedObject.current!); - } - } else { - const target = controls.getTarget(new THREE.Vector3()); - await controls.setTarget(target.x, 0, target.z, true); - setSelectedFloorItem(null); - } - } - } - }; - - const onDrop = (event: any) => { - if (!event.dataTransfer?.files[0]) return; - - if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') { - - state.pointer.x = (event.clientX / window.innerWidth) * 2 - 1; - state.pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; - - addAssetModel( - raycaster, - state.camera, - state.pointer, - floorGroup, - setFloorItems, - itemsGroup, - isTempLoader, - tempLoader, - socket, - selectedItem, - setSelectedItem, - addEvent, - plane - ); - } - }; - - const onDragOver = (event: any) => { - event.preventDefault(); - }; - - if (activeModule === "builder") { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("dblclick", onDblClick); - canvasElement.addEventListener("drop", onDrop); - canvasElement.addEventListener("dragover", onDragOver); - } else { - if (controls) { - const target = controls.getTarget(new THREE.Vector3()); - controls.setTarget(target.x, 0, target.z, true); - setSelectedFloorItem(null); - } - } - - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("dblclick", onDblClick); - canvasElement.removeEventListener("drop", onDrop); - canvasElement.removeEventListener("dragover", onDragOver); - }; - }, [deleteTool, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule,]); - - useFrame(() => { - if (controls) - if (deleteTool && activeModule === "builder") { - // assetVisibility(itemsGroup, state.camera.position, renderDistance); - DeletableHoveredFloorItems( - state, - itemsGroup, - hoveredDeletableFloorItem, - setDeletableFloorItem - ); - } else if (!deleteTool) { - if (hoveredDeletableFloorItem.current) { - hoveredDeletableFloorItem.current = undefined; - setDeletableFloorItem(null); - } - } - }); - - return ; -}; - -export default FloorItemsGroup; diff --git a/app/src/modules/collaboration/socket/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx index 441bae4..6e0051c 100644 --- a/app/src/modules/collaboration/socket/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx @@ -19,7 +19,6 @@ import { 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"; @@ -286,14 +285,6 @@ export default function SocketResponses({ }); THREE.Cache.add(data.data.modelName, gltf); - }, - () => { - TempLoader( - new THREE.Vector3(...data.data.position), - isTempLoader, - tempLoader, - itemsGroup - ); } ); } diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx index dd52900..6c7a91c 100644 --- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx @@ -6,8 +6,21 @@ import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useAssetsStore } from "../../../../store/builder/useAssetStore"; -const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, selectionGroup, setDuplicatedObjects, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { +const CopyPasteControls = ({ + 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(); @@ -15,6 +28,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const { addEvent } = useEventsStore(); + const { addAsset } = useAssetsStore(); useEffect(() => { if (!camera || !scene || toggleView) return; @@ -132,16 +146,15 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas 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) { + if (obj) { + const worldPosition = new THREE.Vector3(); + obj.getWorldPosition(worldPosition); + obj.position.copy(worldPosition); const newFloorItem: Types.FloorItemType = { - modelUuid: obj.uuid, - modelName: obj.userData.name, - modelfileID: obj.userData.modelId, + modelUuid: THREE.MathUtils.generateUUID(), + modelName: obj.userData.modelName, + modelfileID: obj.userData.assetId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, isLocked: false, @@ -362,7 +375,20 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas eventData: JSON.parse(JSON.stringify(eventData)) }; - itemsGroupRef.current.add(obj); + const asset: Asset = { + modelUuid: data.modelUuid, + modelName: data.modelName, + assetId: data.modelfileID, + position: data.position, + rotation: [data.rotation.x, data.rotation.y, data.rotation.z], + isLocked: data.isLocked, + isCollidable: false, + isVisible: data.isVisible, + opacity: 1, + eventData: data.eventData + } + + addAsset(asset); } else { setFloorItems((prevItems: Types.FloorItems) => { @@ -403,13 +429,19 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas socket.emit("v2:model-asset:add", data); - obj.userData = { - name: newFloorItem.modelName, - modelId: newFloorItem.modelfileID, - modelUuid: newFloorItem.modelUuid, - }; + const asset: Asset = { + modelUuid: data.modelUuid, + modelName: data.modelName, + assetId: data.modelfileID, + position: data.position, + rotation: [data.rotation.x, data.rotation.y, data.rotation.z], + isLocked: data.isLocked, + isCollidable: false, + isVisible: data.isVisible, + opacity: 1, + } - itemsGroupRef.current.add(obj); + addAsset(asset); } } }); diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx index 2dd9e37..93c99fc 100644 --- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx @@ -4,11 +4,21 @@ import { useFrame, useThree } from "@react-three/fiber"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; // 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"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useAssetsStore } from "../../../../store/builder/useAssetStore"; -const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { +const DuplicationControls = ({ + 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(); @@ -16,6 +26,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const { addEvent } = useEventsStore(); + const { addAsset } = useAssetsStore(); useEffect(() => { if (!camera || !scene || toggleView) return; @@ -110,16 +121,15 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb 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) { + if (obj) { + const worldPosition = new THREE.Vector3(); + obj.getWorldPosition(worldPosition); + obj.position.copy(worldPosition); const newFloorItem: Types.FloorItemType = { - modelUuid: obj.uuid, - modelName: obj.userData.name, - modelfileID: obj.userData.modelId, + modelUuid: THREE.MathUtils.generateUUID(), + modelName: obj.userData.modelName, + modelfileID: obj.userData.assetId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, isLocked: false, @@ -332,14 +342,20 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb socket.emit("v2:model-asset:add", data); - obj.userData = { - name: newFloorItem.modelName, - modelId: newFloorItem.modelfileID, - modelUuid: newFloorItem.modelUuid, - eventData: JSON.parse(JSON.stringify(eventData)) - }; + const asset: Asset = { + modelUuid: data.modelUuid, + modelName: data.modelName, + assetId: data.modelfileID, + position: data.position, + rotation: [data.rotation.x, data.rotation.y, data.rotation.z], + isLocked: data.isLocked, + isCollidable: false, + isVisible: data.isVisible, + opacity: 1, + eventData: data.eventData + } - itemsGroupRef.current.add(obj); + addAsset(asset); } else { setFloorItems((prevItems: Types.FloorItems) => { @@ -380,13 +396,19 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb socket.emit("v2:model-asset:add", data); - obj.userData = { - name: newFloorItem.modelName, - modelId: newFloorItem.modelfileID, - modelUuid: newFloorItem.modelUuid, - }; + const asset: Asset = { + modelUuid: data.modelUuid, + modelName: data.modelName, + assetId: data.modelfileID, + position: data.position, + rotation: [data.rotation.x, data.rotation.y, data.rotation.z], + isLocked: data.isLocked, + isCollidable: false, + isVisible: data.isVisible, + opacity: 1, + } - itemsGroupRef.current.add(obj); + addAsset(asset); } } }); diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index a41755c..de50c84 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -16,11 +16,11 @@ import { useSelectedProduct } from "../../../../store/simulation/useSimulationSt import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { snapControls } from "../../../../utils/handleSnap"; import DistanceFindingControls from "./distanceFindingControls"; +import { useAssetsStore } from "../../../../store/builder/useAssetStore"; function MoveControls({ movedObjects, setMovedObjects, - itemsGroupRef, pastedObjects, setpastedObjects, duplicatedObjects, @@ -36,12 +36,12 @@ function MoveControls({ const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const { selectedProduct } = useSelectedProduct(); - const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); - const itemsData = useRef([]); const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">(""); const email = localStorage.getItem("email"); const organization = email!.split("@")[1].split(".")[0]; + const { updateAsset } = useAssetsStore(); + const AssetGroup = useRef(undefined); const updateBackend = ( productName: string, @@ -58,11 +58,19 @@ function MoveControls({ }; useEffect(() => { - if (!camera || !scene || toggleView || !itemsGroupRef.current) return; + if (!camera || !scene || toggleView) return; const canvasElement = gl.domElement; canvasElement.tabIndex = 0; + const itemsGroup: any = scene.getObjectByName("Asset Group"); + AssetGroup.current = itemsGroup; + + if (!AssetGroup.current) { + console.error("Asset Group not found in the scene."); + return; + } + let isMoving = false; const onPointerDown = () => { @@ -91,15 +99,12 @@ function MoveControls({ clearSelection(); movedObjects.forEach((asset: any) => { - if (itemsGroupRef.current) { - itemsGroupRef.current.attach(asset); + if (AssetGroup.current) { + AssetGroup.current.attach(asset); } }); - setFloorItems([...floorItems, ...itemsData.current]); - setMovedObjects([]); - itemsData.current = []; } setKeyEvent(""); }; @@ -119,9 +124,6 @@ function MoveControls({ if (keyCombination === "G") { if (selectedAssets.length > 0) { moveAssets(); - itemsData.current = floorItems.filter((item: { modelUuid: string }) => - selectedAssets.some((asset: any) => asset.uuid === item.modelUuid) - ); } } @@ -130,15 +132,12 @@ function MoveControls({ clearSelection(); movedObjects.forEach((asset: any) => { - if (itemsGroupRef.current) { - itemsGroupRef.current.attach(asset); + if (AssetGroup.current) { + AssetGroup.current.attach(asset); } }); - setFloorItems([...floorItems, ...itemsData.current]); - setMovedObjects([]); - itemsData.current = []; } }; @@ -157,7 +156,7 @@ function MoveControls({ canvasElement.removeEventListener("keydown", onKeyDown); canvasElement?.removeEventListener("keyup", onKeyUp); }; - }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent,]); + }, [camera, controls, scene, toggleView, selectedAssets, socket, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent,]); let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25; @@ -219,11 +218,6 @@ function MoveControls({ }); 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); @@ -234,17 +228,17 @@ function MoveControls({ if (movedObjects.length === 0) return; movedObjects.forEach(async (obj: THREE.Object3D) => { - const worldPosition = new THREE.Vector3(); - obj.getWorldPosition(worldPosition); + if (obj && AssetGroup.current) { + const worldPosition = new THREE.Vector3(); + obj.getWorldPosition(worldPosition); - selectionGroup.current.remove(obj); - obj.position.copy(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, + modelUuid: obj.userData.modelUuid, + modelName: obj.userData.modelName, + modelfileID: obj.userData.assetId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, @@ -287,10 +281,9 @@ function MoveControls({ } } - setFloorItems((prevItems: Types.FloorItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; + updateAsset(obj.userData.modelUuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }); //REST @@ -322,12 +315,12 @@ function MoveControls({ socket.emit("v2:model-asset:add", data); - itemsGroupRef.current.add(obj); + AssetGroup.current.add(obj); } }); + echo.success("Object moved!"); - itemsData.current = []; clearSelection(); }; diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 65536d0..b8b9095 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -8,20 +8,32 @@ import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useAssetsStore } from "../../../../store/builder/useAssetStore"; + +function RotateControls({ + rotatedObjects, + setRotatedObjects, + movedObjects, + setMovedObjects, + pastedObjects, + setpastedObjects, + duplicatedObjects, + setDuplicatedObjects, + selectionGroup +}: any) { -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 { selectedProduct } = useSelectedProduct(); - const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); - const itemsData = useRef([]); const email = localStorage.getItem('email') const organization = (email?.split("@")[1])?.split(".")[0] ?? null; + const { updateAsset } = useAssetsStore(); + const AssetGroup = useRef(undefined); const updateBackend = ( productName: string, @@ -40,11 +52,19 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo const prevPointerPosition = useRef(null); useEffect(() => { - if (!camera || !scene || toggleView || !itemsGroupRef.current) return; + if (!camera || !scene || toggleView) return; const canvasElement = gl.domElement; canvasElement.tabIndex = 0; + const itemsGroup: any = scene.getObjectByName("Asset Group"); + AssetGroup.current = itemsGroup; + + if (!AssetGroup.current) { + console.error("Asset Group not found in the scene."); + return; + } + let isMoving = false; const onPointerDown = () => { @@ -65,15 +85,12 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo clearSelection(); rotatedObjects.forEach((asset: any) => { - if (itemsGroupRef.current) { - itemsGroupRef.current.attach(asset); + if (AssetGroup.current) { + AssetGroup.current.attach(asset); } }); - setFloorItems([...floorItems, ...itemsData.current]); - setRotatedObjects([]); - itemsData.current = []; } }; @@ -82,7 +99,6 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo 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") { @@ -90,15 +106,13 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo clearSelection(); rotatedObjects.forEach((asset: any) => { - if (itemsGroupRef.current) { - itemsGroupRef.current.attach(asset); + if (AssetGroup.current) { + AssetGroup.current.attach(asset); } }); - setFloorItems([...floorItems, ...itemsData.current]); setRotatedObjects([]); - itemsData.current = []; } }; @@ -115,7 +129,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo canvasElement.removeEventListener("pointerup", onPointerUp); canvasElement.removeEventListener("keydown", onKeyDown); }; - }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, rotatedObjects, movedObjects]); + }, [camera, controls, scene, toggleView, selectedAssets, socket, pastedObjects, duplicatedObjects, rotatedObjects, movedObjects]); useFrame(() => { if (rotatedObjects.length > 0) { @@ -146,9 +160,6 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo }); 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(); @@ -173,26 +184,24 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo if (rotatedObjects.length === 0) return; rotatedObjects.forEach(async (obj: THREE.Object3D) => { - const worldPosition = new THREE.Vector3(); - const worldQuaternion = new THREE.Quaternion(); + if (obj && AssetGroup.current) { + const worldPosition = new THREE.Vector3(); + const worldQuaternion = new THREE.Quaternion(); - obj.getWorldPosition(worldPosition); - obj.getWorldQuaternion(worldQuaternion); + obj.getWorldPosition(worldPosition); + obj.getWorldQuaternion(worldQuaternion); - selectionGroup.current.remove(obj); + selectionGroup.current.remove(obj); - obj.position.copy(worldPosition); - obj.quaternion.copy(worldQuaternion); - - - if (itemsGroupRef.current) { + obj.position.copy(worldPosition); + obj.quaternion.copy(worldQuaternion); const newFloorItem: Types.FloorItemType = { - modelUuid: obj.uuid, - modelName: obj.userData.name, - modelfileID: obj.userData.modelId, + modelUuid: obj.userData.modelUuid, + modelName: obj.userData.modelName, + modelfileID: obj.userData.assetId, position: [worldPosition.x, worldPosition.y, worldPosition.z], - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true }; @@ -221,15 +230,14 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo event ); } - + newFloorItem.eventData = eventData; } } - setFloorItems((prevItems: Types.FloorItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; + updateAsset(obj.userData.modelUuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }); //REST @@ -261,12 +269,11 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo socket.emit("v2:model-asset:add", data); - itemsGroupRef.current.add(obj); + AssetGroup.current.add(obj); } }); echo.success("Object rotated!"); - itemsData.current = []; clearSelection(); } diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 763faa3..691bb7c 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -15,10 +15,10 @@ import RotateControls from "./rotateControls"; import useModuleStore from "../../../../store/useModuleStore"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useAssetsStore } from "../../../../store/builder/useAssetStore"; 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(); @@ -28,9 +28,9 @@ const SelectionControls: React.FC = () => { const [pastedObjects, setpastedObjects] = useState([]); const [duplicatedObjects, setDuplicatedObjects] = useState([]); const boundingBoxRef = useRef(); - const { floorItems, setFloorItems } = useFloorItems(); const { activeModule } = useModuleStore(); const { socket } = useSocketStore(); + const { removeAsset } = useAssetsStore(); const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]); useEffect(() => { @@ -39,9 +39,6 @@ const SelectionControls: React.FC = () => { 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; @@ -49,11 +46,6 @@ const SelectionControls: React.FC = () => { const helper = new SelectionHelper(gl); - // if (!itemsGroup) { - // echo.warn("itemsGroup not found in the scene."); - // return; - // } - const onPointerDown = (event: PointerEvent) => { if (event.button === 2) { isRightClick = true; @@ -145,7 +137,7 @@ const SelectionControls: React.FC = () => { helper.enabled = false; helper.dispose(); }; - }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects, activeModule,]); + }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, rotatedObjects, activeModule,]); useEffect(() => { if (activeModule !== "builder") { @@ -213,14 +205,14 @@ const SelectionControls: React.FC = () => { selectedAssets.forEach((selectedMesh: THREE.Object3D) => { //REST - // const response = await deleteFloorItem(organization, selectedMesh.uuid, selectedMesh.userData.name); + // const response = await deleteFloorItem(organization, selectedMesh.userData.modelUuid, selectedMesh.userData.modelName); //SOCKET const data = { organization: organization, - modelUuid: selectedMesh.uuid, - modelName: selectedMesh.userData.name, + modelUuid: selectedMesh.userData.modelUuid, + modelName: selectedMesh.userData.modelName, socketId: socket.id, }; @@ -244,11 +236,11 @@ const SelectionControls: React.FC = () => { } }); - itemsGroupRef.current?.remove(selectedMesh); }); - const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid)); - setFloorItems(updatedItems); + selectedUUIDs.forEach((uuid: string) => { + removeAsset(uuid); + }); } echo.success("Selected models removed!"); clearSelection(); @@ -262,13 +254,13 @@ const SelectionControls: React.FC = () => { - + - + - + - + ); }; diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 7c5db64..9a449d6 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -27,9 +27,13 @@ export default function PostProcessing() { } useEffect(()=>{ - console.log('selectedFloorItem: ', selectedFloorItem); + // console.log('selectedFloorItem: ', selectedFloorItem); },[selectedFloorItem]) + useEffect(()=>{ + // console.log('selectedFloorItem: ', deletableFloorItem); + },[deletableFloorItem]) + return ( <> diff --git a/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js b/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js deleted file mode 100644 index 50dac3f..0000000 --- a/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js +++ /dev/null @@ -1,51 +0,0 @@ -import * as THREE from 'three'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; -import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; - -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); - -onmessage = (event) => { - const { floorItems, cameraPosition, uuids, renderDistance } = event.data; - if (!floorItems) return - - const toAdd = []; - const toRemove = []; - - const cameraPos = new THREE.Vector3(cameraPosition.x, cameraPosition.y, cameraPosition.z); - - // Check for items to be added - floorItems.forEach((item) => { - const itemPosition = new THREE.Vector3(...item.position); - const distance = cameraPos.distanceTo(itemPosition); - - if (distance <= renderDistance && !uuids.includes(item.modelUuid)) { - toAdd.push(item); - } - }); - - // Sort the toAdd array based on distance (closest first) - toAdd.sort((a, b) => { - const aDistance = cameraPos.distanceTo(new THREE.Vector3(...a.position)); - const bDistance = cameraPos.distanceTo(new THREE.Vector3(...b.position)); - return aDistance - bDistance; - }); - - // Check for items to be removed - uuids.forEach((uuid) => { - const floorItem = floorItems.find((item) => item.modelUuid === uuid); - if (floorItem) { - const itemPosition = new THREE.Vector3(...floorItem.position); - const distance = cameraPos.distanceTo(itemPosition); - - if (distance > renderDistance) { - toRemove.push(uuid); - } - } - }); - - // Send the result back to the main thread - postMessage({ toAdd, toRemove }); -}; diff --git a/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js b/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js index 9e7397d..f98ad9b 100644 --- a/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js +++ b/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js @@ -17,6 +17,9 @@ onmessage = async (event) => { ); for (const item of uniqueItems) { + if(item.modelfileID === null || item.modelfileID === undefined) { + continue; // Skip items without a valid modelfileID + } const modelID = item.modelfileID; const indexedDBModel = await retrieveGLTF(modelID); -- 2.49.1 From f6f0478e9aab473d8be275dbceecf9864ddaa029 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 27 May 2025 09:16:33 +0530 Subject: [PATCH 03/34] refactor: reorganize asset management functions and remove unused components --- .../builder/assetGroup/assetsGroup.tsx | 2 +- .../functions}/addAssetModel.ts | 812 +++++++++--------- .../model => functions}/assetBoundingBox.tsx | 4 +- .../builder/assetGroup/models/model/model.tsx | 6 +- .../selectionControls/boundingBoxHelper.tsx | 4 +- 5 files changed, 414 insertions(+), 414 deletions(-) rename app/src/modules/builder/{geomentries/assets => assetGroup/functions}/addAssetModel.ts (97%) rename app/src/modules/builder/assetGroup/{models/model => functions}/assetBoundingBox.tsx (74%) diff --git a/app/src/modules/builder/assetGroup/assetsGroup.tsx b/app/src/modules/builder/assetGroup/assetsGroup.tsx index 5fe75a4..5b6008d 100644 --- a/app/src/modules/builder/assetGroup/assetsGroup.tsx +++ b/app/src/modules/builder/assetGroup/assetsGroup.tsx @@ -11,7 +11,7 @@ import Models from "./models/models"; import useModuleStore from "../../../store/useModuleStore"; import { useThree } from "@react-three/fiber"; import { CameraControls } from "@react-three/drei"; -import addAssetModel from "../geomentries/assets/addAssetModel"; +import addAssetModel from "./functions/addAssetModel"; const gltfLoaderWorker = new Worker( new URL( diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/assetGroup/functions/addAssetModel.ts similarity index 97% rename from app/src/modules/builder/geomentries/assets/addAssetModel.ts rename to app/src/modules/builder/assetGroup/functions/addAssetModel.ts index 7847651..5949cf2 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/assetGroup/functions/addAssetModel.ts @@ -1,406 +1,406 @@ -import * as THREE from 'three'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; -import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; -import * as Types from "../../../../types/world/worldTypes"; -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 PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator'; - -async function addAssetModel( - raycaster: THREE.Raycaster, - camera: THREE.Camera, - pointer: THREE.Vector2, - floorGroup: Types.RefGroup, - socket: Socket, - selectedItem: any, - setSelectedItem: any, - addEvent: (event: EventsSchema) => void, - addAsset: (asset: Asset) => void, - plane: Types.RefMesh, -): Promise { - - ////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage ////////// - - let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - - try { - 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); - - raycaster.setFromCamera(pointer, camera); - const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true); - const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor")); - - const planeIntersections = raycaster.intersectObject(plane.current!, true); - const intersectedPlane = planeIntersections[0]; - - let intersectPoint: THREE.Vector3 | null = null; - - if (intersectedFloor && intersectedPlane) { - intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z)); - } else if (intersectedFloor) { - intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z); - } else if (intersectedPlane) { - intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z); - } - - if (intersectPoint) { - if (intersectPoint.y < 0) { - intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z); - } - const cachedModel = THREE.Cache.get(selectedItem.id); - if (cachedModel) { - handleModelLoad(cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket); - return; - } else { - const cachedModelBlob = await retrieveGLTF(selectedItem.id); - if (cachedModelBlob) { - const blobUrl = URL.createObjectURL(cachedModelBlob); - loader.load(blobUrl, (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(selectedItem.id, gltf); - handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket); - }); - } else { - loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => { - 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, addEvent, addAsset, socket); - }) - } - } - } - } catch (error) { - echo.error("Failed to add asset"); - } finally { - setSelectedItem({}); - } -} - -async function handleModelLoad( - gltf: any, - intersectPoint: THREE.Vector3, - selectedItem: any, - addEvent: (event: EventsSchema) => void, - addAsset: (asset: Asset) => void, - socket: Socket -) { - const model = gltf.scene.clone(); - model.userData = { name: selectedItem.name, modelId: selectedItem.id, modelUuid: model.uuid }; - model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z); - model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - - model.traverse((child: any) => { - if (child) { - child.castShadow = true; - child.receiveShadow = true; - } - }); - - const newFloorItem: Asset = { - modelUuid: model.uuid, - modelName: selectedItem.name, - assetId: selectedItem.id, - position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], - rotation: [0, 0, 0], - isLocked: false, - isVisible: true, - isCollidable: false, - opacity: 1, - }; - - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : ""; - - // API - - // await setFloorItemApi( - // organization, - // newFloorItem.modelUuid, - // newFloorItem.modelName, - // newFloorItem.modelfileID, - // newFloorItem.position, - // { x: 0, y: 0, z: 0 }, - // false, - // true, - // ); - - // SOCKET - - if (selectedItem.type) { - const data = PointsCalculator( - selectedItem.type, - gltf.scene.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const eventData: any = { - type: selectedItem.type, - }; - - if (selectedItem.type === "Conveyor") { - const ConveyorEvent: ConveyorEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - state: "idle", - type: 'transfer', - speed: 1, - points: data.points.map((point: THREE.Vector3, index: number) => { - const triggers: TriggerSchema[] = []; - - if (data.points && index < data.points.length - 1) { - triggers.push({ - triggerUuid: THREE.MathUtils.generateUUID(), - triggerName: `Trigger 1`, - triggerType: "onComplete", - delay: 0, - triggeredAsset: { - triggeredModel: { - modelName: newFloorItem.modelName, - modelUuid: newFloorItem.modelUuid - }, - triggeredPoint: { - pointName: `Point`, - pointUuid: "" - }, - triggeredAction: { - actionName: `Action 1`, - actionUuid: "" - } - } - }); - } - - return { - uuid: THREE.MathUtils.generateUUID(), - position: [point.x, point.y, point.z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action 1`, - actionType: 'default', - material: 'Default Material', - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: triggers - } - }; - }) - }; - - for (let i = 0; i < ConveyorEvent.points.length - 1; i++) { - const currentPoint = ConveyorEvent.points[i]; - const nextPoint = ConveyorEvent.points[i + 1]; - - if (currentPoint.action.triggers.length > 0) { - currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid; - currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid; - } - } - addEvent(ConveyorEvent); - eventData.points = ConveyorEvent.points.map(point => ({ - uuid: point.uuid, - position: point.position, - rotation: point.rotation - })); - - } else if (selectedItem.type === "Vehicle") { - const vehicleEvent: VehicleEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - 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: "Action 1", - actionType: "travel", - unLoadDuration: 5, - loadCapacity: 1, - steeringAngle: 0, - pickUpPoint: null, - unLoadPoint: null, - triggers: [] - } - } - }; - addEvent(vehicleEvent); - eventData.point = { - uuid: vehicleEvent.point.uuid, - position: vehicleEvent.point.position, - rotation: vehicleEvent.point.rotation - }; - - } else if (selectedItem.type === "ArmBot") { - const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - 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: "Action 1", - actionType: "pickAndPlace", - process: { - startPoint: null, - endPoint: null - }, - triggers: [] - } - ] - } - }; - addEvent(roboticArmEvent); - eventData.point = { - uuid: roboticArmEvent.point.uuid, - position: roboticArmEvent.point.position, - rotation: roboticArmEvent.point.rotation - }; - - } else if (selectedItem.type === "StaticMachine") { - const machineEvent: MachineEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - 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: "Action 1", - actionType: "process", - processTime: 10, - swapMaterial: "Default Material", - triggers: [] - } - } - }; - addEvent(machineEvent); - eventData.point = { - uuid: machineEvent.point.uuid, - position: machineEvent.point.position, - rotation: machineEvent.point.rotation - }; - } else if (selectedItem.type === "Storage") { - const storageEvent: StorageEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - state: "idle", - type: "storageUnit", - 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: "Action 1", - actionType: "store", - storageCapacity: 10, - triggers: [] - } - } - } - addEvent(storageEvent); - eventData.point = { - uuid: storageEvent.point.uuid, - position: storageEvent.point.position, - rotation: storageEvent.point.rotation - }; - } - - const completeData = { - organization, - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - modelfileID: newFloorItem.assetId, - position: newFloorItem.position, - rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, - isLocked: false, - isVisible: true, - socketId: socket.id, - eventData: eventData - }; - - socket.emit("v2:model-asset:add", completeData); - - const asset: Asset = { - modelUuid: completeData.modelUuid, - modelName: completeData.modelName, - assetId: completeData.modelfileID, - position: completeData.position, - rotation: [completeData.rotation.x, completeData.rotation.y, completeData.rotation.z] as [number, number, number], - isLocked: completeData.isLocked, - isCollidable: false, - isVisible: completeData.isVisible, - opacity: 1, - eventData: completeData.eventData - } - - addAsset(asset); - - } else { - - const data = { - organization, - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - modelfileID: newFloorItem.assetId, - position: newFloorItem.position, - rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, - isLocked: false, - isVisible: true, - socketId: socket.id - }; - - socket.emit("v2:model-asset:add", data); - - const asset = { - modelUuid: data.modelUuid, - modelName: data.modelName, - assetId: data.modelfileID, - position: data.position, - rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [number, number, number], - isLocked: data.isLocked, - isCollidable: false, - isVisible: data.isVisible, - opacity: 1 - } - - addAsset(asset); - - } -} - -export default addAssetModel; +import * as THREE from 'three'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; +import * as Types from "../../../../types/world/worldTypes"; +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 PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator'; + +async function addAssetModel( + raycaster: THREE.Raycaster, + camera: THREE.Camera, + pointer: THREE.Vector2, + floorGroup: Types.RefGroup, + socket: Socket, + selectedItem: any, + setSelectedItem: any, + addEvent: (event: EventsSchema) => void, + addAsset: (asset: Asset) => void, + plane: Types.RefMesh, +): Promise { + + ////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage ////////// + + let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; + + try { + 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); + + raycaster.setFromCamera(pointer, camera); + const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true); + const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor")); + + const planeIntersections = raycaster.intersectObject(plane.current!, true); + const intersectedPlane = planeIntersections[0]; + + let intersectPoint: THREE.Vector3 | null = null; + + if (intersectedFloor && intersectedPlane) { + intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z)); + } else if (intersectedFloor) { + intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z); + } else if (intersectedPlane) { + intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z); + } + + if (intersectPoint) { + if (intersectPoint.y < 0) { + intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z); + } + const cachedModel = THREE.Cache.get(selectedItem.id); + if (cachedModel) { + handleModelLoad(cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket); + return; + } else { + const cachedModelBlob = await retrieveGLTF(selectedItem.id); + if (cachedModelBlob) { + const blobUrl = URL.createObjectURL(cachedModelBlob); + loader.load(blobUrl, (gltf) => { + URL.revokeObjectURL(blobUrl); + THREE.Cache.remove(blobUrl); + THREE.Cache.add(selectedItem.id, gltf); + handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket); + }); + } else { + loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => { + 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, addEvent, addAsset, socket); + }) + } + } + } + } catch (error) { + echo.error("Failed to add asset"); + } finally { + setSelectedItem({}); + } +} + +async function handleModelLoad( + gltf: any, + intersectPoint: THREE.Vector3, + selectedItem: any, + addEvent: (event: EventsSchema) => void, + addAsset: (asset: Asset) => void, + socket: Socket +) { + const model = gltf.scene.clone(); + model.userData = { name: selectedItem.name, modelId: selectedItem.id, modelUuid: model.uuid }; + model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z); + model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); + + model.traverse((child: any) => { + if (child) { + child.castShadow = true; + child.receiveShadow = true; + } + }); + + const newFloorItem: Asset = { + modelUuid: model.uuid, + modelName: selectedItem.name, + assetId: selectedItem.id, + position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], + rotation: [0, 0, 0], + isLocked: false, + isVisible: true, + isCollidable: false, + opacity: 1, + }; + + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : ""; + + // API + + // await setFloorItemApi( + // organization, + // newFloorItem.modelUuid, + // newFloorItem.modelName, + // newFloorItem.modelfileID, + // newFloorItem.position, + // { x: 0, y: 0, z: 0 }, + // false, + // true, + // ); + + // SOCKET + + if (selectedItem.type) { + const data = PointsCalculator( + selectedItem.type, + gltf.scene.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + const eventData: any = { + type: selectedItem.type, + }; + + if (selectedItem.type === "Conveyor") { + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + state: "idle", + type: 'transfer', + speed: 1, + points: data.points.map((point: THREE.Vector3, index: number) => { + const triggers: TriggerSchema[] = []; + + if (data.points && index < data.points.length - 1) { + triggers.push({ + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `Trigger 1`, + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: newFloorItem.modelName, + modelUuid: newFloorItem.modelUuid + }, + triggeredPoint: { + pointName: `Point`, + pointUuid: "" + }, + triggeredAction: { + actionName: `Action 1`, + actionUuid: "" + } + } + }); + } + + return { + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action 1`, + actionType: 'default', + material: 'Default Material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: triggers + } + }; + }) + }; + + for (let i = 0; i < ConveyorEvent.points.length - 1; i++) { + const currentPoint = ConveyorEvent.points[i]; + const nextPoint = ConveyorEvent.points[i + 1]; + + if (currentPoint.action.triggers.length > 0) { + currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid; + currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid; + } + } + addEvent(ConveyorEvent); + eventData.points = ConveyorEvent.points.map(point => ({ + uuid: point.uuid, + position: point.position, + rotation: point.rotation + })); + + } else if (selectedItem.type === "Vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + 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: "Action 1", + actionType: "travel", + unLoadDuration: 5, + loadCapacity: 1, + steeringAngle: 0, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + eventData.point = { + uuid: vehicleEvent.point.uuid, + position: vehicleEvent.point.position, + rotation: vehicleEvent.point.rotation + }; + + } else if (selectedItem.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + 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: "Action 1", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + eventData.point = { + uuid: roboticArmEvent.point.uuid, + position: roboticArmEvent.point.position, + rotation: roboticArmEvent.point.rotation + }; + + } else if (selectedItem.type === "StaticMachine") { + const machineEvent: MachineEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + 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: "Action 1", + actionType: "process", + processTime: 10, + swapMaterial: "Default Material", + triggers: [] + } + } + }; + addEvent(machineEvent); + eventData.point = { + uuid: machineEvent.point.uuid, + position: machineEvent.point.position, + rotation: machineEvent.point.rotation + }; + } else if (selectedItem.type === "Storage") { + const storageEvent: StorageEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + state: "idle", + type: "storageUnit", + 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: "Action 1", + actionType: "store", + storageCapacity: 10, + triggers: [] + } + } + } + addEvent(storageEvent); + eventData.point = { + uuid: storageEvent.point.uuid, + position: storageEvent.point.position, + rotation: storageEvent.point.rotation + }; + } + + const completeData = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.assetId, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + eventData: eventData + }; + + socket.emit("v2:model-asset:add", completeData); + + const asset: Asset = { + modelUuid: completeData.modelUuid, + modelName: completeData.modelName, + assetId: completeData.modelfileID, + position: completeData.position, + rotation: [completeData.rotation.x, completeData.rotation.y, completeData.rotation.z] as [number, number, number], + isLocked: completeData.isLocked, + isCollidable: false, + isVisible: completeData.isVisible, + opacity: 1, + eventData: completeData.eventData + } + + addAsset(asset); + + } else { + + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.assetId, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id + }; + + socket.emit("v2:model-asset:add", data); + + const asset = { + modelUuid: data.modelUuid, + modelName: data.modelName, + assetId: data.modelfileID, + position: data.position, + rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [number, number, number], + isLocked: data.isLocked, + isCollidable: false, + isVisible: data.isVisible, + opacity: 1 + } + + addAsset(asset); + + } +} + +export default addAssetModel; diff --git a/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx b/app/src/modules/builder/assetGroup/functions/assetBoundingBox.tsx similarity index 74% rename from app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx rename to app/src/modules/builder/assetGroup/functions/assetBoundingBox.tsx index 18648dc..d74f37d 100644 --- a/app/src/modules/builder/assetGroup/models/model/assetBoundingBox.tsx +++ b/app/src/modules/builder/assetGroup/functions/assetBoundingBox.tsx @@ -1,6 +1,6 @@ import { Box3, BoxGeometry, EdgesGeometry, Vector3 } from "three"; -export const AssetBoundingBox = ({ asset, boundingBox }: { asset: Asset, boundingBox: Box3 | null }) => { +export const AssetBoundingBox = ({ boundingBox }: { boundingBox: Box3 | null }) => { if (!boundingBox) return null; const size = boundingBox.getSize(new Vector3()); @@ -13,7 +13,7 @@ export const AssetBoundingBox = ({ asset, boundingBox }: { asset: Asset, boundin - + ); diff --git a/app/src/modules/builder/assetGroup/models/model/model.tsx b/app/src/modules/builder/assetGroup/models/model/model.tsx index 07e027c..719af1d 100644 --- a/app/src/modules/builder/assetGroup/models/model/model.tsx +++ b/app/src/modules/builder/assetGroup/models/model/model.tsx @@ -5,8 +5,8 @@ import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; import { useFrame, useThree } from '@react-three/fiber'; import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem } from '../../../../../store/builder/store'; -import { AssetBoundingBox } from './assetBoundingBox'; -import { CameraControls } from '@react-three/drei'; +import { AssetBoundingBox } from '../../functions/assetBoundingBox'; +import { CameraControls, Detailed } from '@react-three/drei'; import { useAssetsStore } from '../../../../../store/builder/useAssetStore'; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; @@ -216,7 +216,7 @@ function Model({ asset }: { asset: Asset }) { isRendered ? ( ) : ( - + ) )} diff --git a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx index 5802705..e549b1d 100644 --- a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx +++ b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx @@ -45,12 +45,12 @@ const BoundingBox = ({ boundingBoxRef }: any) => { }, [selectedAssets]); const savedTheme: string | null = localStorage.getItem("theme") || "light"; - + return ( <> {points.length > 0 && ( <> - + -- 2.49.1 From 25439fdd8ce12d8ccc0819c0381aa8a5a7e04bb8 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 27 May 2025 11:26:55 +0530 Subject: [PATCH 04/34] Refactor asset management and collaboration features - Removed use of floor items from various components and replaced with asset management. - Integrated asset selection and clearing logic in Models component. - Updated SocketResponses to handle asset creation, updates, and deletions through collaboration. - Simplified copy, paste, and duplication controls by removing floor item dependencies. - Enhanced TransformControl to manage asset properties and synchronize with the backend. - Deleted unused AddOrRemoveEventsInProducts component to streamline event handling. - Updated Project component to initialize asset state instead of floor items. - Added setName method to asset store for updating asset names. --- .../sidebarRight/simulation/Simulations.tsx | 7 +- app/src/components/ui/list/DropDownList.tsx | 13 +- app/src/components/ui/list/List.tsx | 13 +- .../assetGroup/functions/addAssetModel.ts | 4 +- .../builder/assetGroup/models/model/model.tsx | 70 ++++- .../builder/assetGroup/models/models.tsx | 5 + .../socket/socketResponses.dev.tsx | 289 +++--------------- .../selectionControls/copyPasteControls.tsx | 27 +- .../selectionControls/duplicationControls.tsx | 27 +- .../selectionControls/moveControls.tsx | 1 - .../selectionControls/rotateControls.tsx | 2 +- .../selectionControls/selectionControls.tsx | 2 +- .../transformControls/transformControls.tsx | 152 ++++----- app/src/modules/scene/environment/shadow.tsx | 4 +- .../functions/handleAddEventToProduct.ts | 2 +- .../events/addOrRemoveEventsInProducts.tsx | 135 -------- .../modules/simulation/products/products.tsx | 3 - app/src/pages/Project.tsx | 8 +- app/src/store/builder/store.ts | 9 - app/src/store/builder/useAssetStore.ts | 10 + 20 files changed, 226 insertions(+), 557 deletions(-) delete mode 100644 app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 316269c..492a91a 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -28,7 +28,7 @@ import { useSaveVersion, } from "../../../../store/builder/store"; import CompareLayOut from "../../../ui/compareVersion/CompareLayOut"; -import {useToggleStore} from "../../../../store/useUIToggleStore"; +import { useToggleStore } from "../../../../store/useUIToggleStore"; interface Event { modelName: string; @@ -179,11 +179,10 @@ const Simulations: React.FC = () => { {products.map((product, index) => (
{/* eslint-disable-next-line */}
= ({ }; const [zoneDataList, setZoneDataList] = useState([]); - const { floorItems } = useFloorItems(); + const { assets } = useAssetsStore(); const isPointInsidePolygon = ( point: [number, number], @@ -80,7 +81,7 @@ const DropDownList: React.FC = ({ p[2], ]); - const assetsInZone = floorItems + const assetsInZone = assets .filter((item: any) => { const [x, , z] = item.position; return isPointInsidePolygon([x, z], polygon2D as [number, number][]); @@ -98,9 +99,9 @@ const DropDownList: React.FC = ({ assets: assetsInZone, }; }); - + setZoneDataList(updatedZoneList); - }, [zones, floorItems]); + }, [zones, assets]); return (
@@ -143,7 +144,7 @@ const DropDownList: React.FC = ({ value="Buildings" showKebabMenu={false} showAddIcon={false} - // items={zoneDataList} + // items={zoneDataList} /> = ({ items = [], remove }) => { const [expandedZones, setExpandedZones] = useState>( {} ); - const { setFloorItems } = useFloorItems(); + const { setName } = useAssetsStore(); useEffect(() => { useSelectedZoneStore.getState().setSelectedZone({ @@ -148,13 +148,8 @@ const List: React.FC = ({ items = [], remove }) => { newName ); // console.log("response: ", response); - setFloorItems((prevFloorItems: any[]) => - prevFloorItems.map((floorItems) => - floorItems.modelUuid === zoneAssetId.id - ? { ...floorItems, modelName: response.modelName } - : floorItems - ) - ); + + setName(zoneAssetId.id, response.modelName); } } const checkZoneNameDuplicate = (name: string) => { diff --git a/app/src/modules/builder/assetGroup/functions/addAssetModel.ts b/app/src/modules/builder/assetGroup/functions/addAssetModel.ts index 5949cf2..d0b6461 100644 --- a/app/src/modules/builder/assetGroup/functions/addAssetModel.ts +++ b/app/src/modules/builder/assetGroup/functions/addAssetModel.ts @@ -94,8 +94,8 @@ async function handleModelLoad( ) { const model = gltf.scene.clone(); model.userData = { name: selectedItem.name, modelId: selectedItem.id, modelUuid: model.uuid }; - model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z); - model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); + model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z); + model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap); model.traverse((child: any) => { if (child) { diff --git a/app/src/modules/builder/assetGroup/models/model/model.tsx b/app/src/modules/builder/assetGroup/models/model/model.tsx index 719af1d..fe1649b 100644 --- a/app/src/modules/builder/assetGroup/models/model/model.tsx +++ b/app/src/modules/builder/assetGroup/models/model/model.tsx @@ -3,19 +3,30 @@ import { useEffect, useRef, useState } from 'react'; import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; -import { useFrame, useThree } from '@react-three/fiber'; +import { ThreeEvent, useFrame, useThree } from '@react-three/fiber'; import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem } from '../../../../../store/builder/store'; import { AssetBoundingBox } from '../../functions/assetBoundingBox'; -import { CameraControls, Detailed } from '@react-three/drei'; +import { CameraControls } from '@react-three/drei'; import { useAssetsStore } from '../../../../../store/builder/useAssetStore'; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useSocketStore } from '../../../../../store/builder/store'; +import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore'; +import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore'; +import { useSelectedAsset, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; function Model({ asset }: { asset: Asset }) { - const { camera, controls } = useThree(); + const { camera, controls, gl } = useThree(); const { activeTool } = useActiveTool(); + const { subModule } = useSubModuleStore(); + const { activeModule } = useModuleStore(); const { removeAsset } = useAssetsStore(); + const { setTop } = useTopData(); + const { setLeft } = useLeftData(); + const { getIsEventInProduct } = useProductStore(); + const { getEventByModelUuid } = useEventsStore(); + const { selectedProduct } = useSelectedProduct(); + const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); const { socket } = useSocketStore(); const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); const { setSelectedFloorItem } = useSelectedFloorItem(); @@ -101,7 +112,7 @@ function Model({ asset }: { asset: Asset }) { const handleDblClick = (asset: Asset) => { if (asset) { - if (activeTool === "cursor" && boundingBox && groupRef.current) { + if (activeTool === "cursor" && boundingBox && groupRef.current && activeModule === 'builder') { const size = boundingBox.getSize(new THREE.Vector3()); const center = boundingBox.getCenter(new THREE.Vector3()); @@ -127,7 +138,6 @@ function Model({ asset }: { asset: Asset }) { paddingRight: 5, }); setSelectedFloorItem(groupRef.current); - } } }; @@ -137,7 +147,6 @@ function Model({ asset }: { asset: Asset }) { const email = localStorage.getItem('email') const organization = (email!.split("@")[1]).split(".")[0]; - //REST // const response = await deleteFloorItem(organization, asset.modelUuid, asset.modelName); @@ -158,10 +167,6 @@ function Model({ asset }: { asset: Asset }) { if (response) { - const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); - const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== asset.modelUuid); - localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); - removeAsset(asset.modelUuid); echo.success("Model Removed!"); @@ -186,6 +191,45 @@ function Model({ asset }: { asset: Asset }) { } } + const handleContextMenu = (asset: Asset, evt: ThreeEvent) => { + if (activeTool === "cursor" && subModule === 'simulations') { + if (asset.modelUuid) { + const canvasElement = gl.domElement; + const isInProduct = getIsEventInProduct(selectedProduct.productId, asset.modelUuid); + if (isInProduct) { + const event = getEventByModelUuid(asset.modelUuid); + if (event) { + setSelectedAsset(event); + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset(); + } + } else { + const event = getEventByModelUuid(asset.modelUuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } + } else { + clearSelectedAsset() + } + } else { + clearSelectedAsset() + } + } + return ( { e.stopPropagation(); - handleDblClick(asset); }} onClick={(e) => { e.stopPropagation(); + handleDblClick(asset); handleClick(asset); }} onPointerOver={(e) => { @@ -211,6 +255,10 @@ function Model({ asset }: { asset: Asset }) { e.stopPropagation(); handlePointerOut(asset); }} + onContextMenu={(e) => { + e.stopPropagation(); + handleContextMenu(asset, e); + }} > {gltfScene && ( isRendered ? ( diff --git a/app/src/modules/builder/assetGroup/models/models.tsx b/app/src/modules/builder/assetGroup/models/models.tsx index 4553531..e67a649 100644 --- a/app/src/modules/builder/assetGroup/models/models.tsx +++ b/app/src/modules/builder/assetGroup/models/models.tsx @@ -4,11 +4,13 @@ import { useThree } from '@react-three/fiber'; import { CameraControls } from '@react-three/drei'; import { Vector3 } from 'three'; import { useSelectedFloorItem } from '../../../../store/builder/store'; +import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore'; function Models() { const { controls } = useThree(); const { assets } = useAssetsStore(); const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); return ( {assets.map((asset) => diff --git a/app/src/modules/collaboration/socket/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx index 6e0051c..b36aa34 100644 --- a/app/src/modules/collaboration/socket/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx @@ -7,7 +7,6 @@ import { useSocketStore, useActiveLayer, useWallItems, - useFloorItems, useLayers, useUpdateScene, useWalls, @@ -32,6 +31,9 @@ import RemoveConnectedLines from "../../builder/geomentries/lines/removeConnecte import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility"; import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils"; import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; +import { useAssetsStore } from "../../../store/builder/useAssetStore"; +import { useEventsStore } from "../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../store/simulation/useProductStore"; export default function SocketResponses({ floorPlanGroup, @@ -53,13 +55,13 @@ export default function SocketResponses({ const { activeLayer, setActiveLayer } = useActiveLayer(); const { wallItems, setWallItems } = useWallItems(); const { setLayers } = useLayers(); - const { setFloorItems } = useFloorItems(); const { setUpdateScene } = useUpdateScene(); const { setWalls } = useWalls(); const { setDeletedLines } = useDeletedLines(); const { setNewLines } = useNewLines(); const { zones, setZones } = useZones(); const { zonePoints, setZonePoints } = useZonePoints(); + const { addAsset, updateAsset, removeAsset } = useAssetsStore(); useEffect(() => { const email = localStorage.getItem("email"); @@ -95,235 +97,54 @@ export default function SocketResponses({ if (organization !== data.organization) { return; } + console.log('data.data: ', data); 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: () => { - echo.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); - } + const asset: Asset = { + modelUuid: data.data.modelUuid, + modelName: data.data.modelName, + assetId: data.data.modelfileID, + position: data.data.position, + rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z], + isLocked: data.data.isLocked, + isCollidable: false, + isVisible: data.data.isVisible, + opacity: 1, } - if (url) { - loadModel(url); - } + addAsset(asset); + + echo.success("Added model through collaboration"); } catch (error) { - echo.error("Failed to update responce"); - 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: () => { - echo.success("Model Added!"); - }, - }); - - THREE.Cache.add(data.data.modelName, gltf); - } - ); + echo.error("Failed to create model through collaboration"); } } 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 - ); - } - }); + try { - setFloorItems((prevItems: Types.FloorItems) => { - if (!prevItems) { - return; + const asset: Asset = { + modelUuid: data.data.modelUuid, + modelName: data.data.modelName, + assetId: data.data.modelfileID, + position: data.data.position, + rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z], + isLocked: data.data.isLocked, + isCollidable: false, + isVisible: data.data.isVisible, + opacity: 1, } - 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; + + updateAsset(asset.modelUuid, { + position: asset.position, + rotation: asset.rotation, }); - return updatedItems; - }); + + echo.success("Updated model through collaboration"); + } catch (error) { + echo.error("Failed to update model through collaboration"); + } + } else { + echo.error("Failed executing action from collaboration"); } }); @@ -335,28 +156,18 @@ export default function SocketResponses({ return; } if (data.message === "Model deleted successfully") { - const deletedUUID = data.data.modelUuid; - let items = JSON.parse(localStorage.getItem("FloorItems")!); + try { + const deletedUUID = data.data.modelUuid; - const updatedItems = items.filter( - (item: { modelUuid: string }) => item.modelUuid !== deletedUUID - ); + useEventsStore.getState().removeEvent(deletedUUID); + useProductStore.getState().deleteEvent(deletedUUID); - const storedItems = JSON.parse( - localStorage.getItem("FloorItems") || "[]" - ); - const updatedStoredItems = storedItems.filter( - (item: { modelUuid: string }) => item.modelUuid !== deletedUUID - ); - localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); + removeAsset(deletedUUID); - itemsGroup.current.children.forEach((item: any) => { - if (item.uuid === deletedUUID) { - itemsGroup.current.remove(item); - } - }); - setFloorItems(updatedItems); - echo.success("Model Removed!"); + echo.success("Model Removed successfully through collaboration"); + } catch (error) { + echo.error("Failed to remove model through collaboration"); + } } }); diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx index 6c7a91c..f006870 100644 --- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; +import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; @@ -25,10 +25,9 @@ const CopyPasteControls = ({ 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(); const { addEvent } = useEventsStore(); - const { addAsset } = useAssetsStore(); + const { assets, addAsset } = useAssetsStore(); useEffect(() => { if (!camera || !scene || toggleView) return; @@ -77,7 +76,7 @@ const CopyPasteControls = ({ canvasElement.removeEventListener("keydown", onKeyDown); }; - }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, floorItems, rotatedObjects]); + }, [assets, camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, rotatedObjects]); useFrame(() => { if (pastedObjects.length > 0) { @@ -145,6 +144,9 @@ const CopyPasteControls = ({ const addPastedObjects = () => { if (pastedObjects.length === 0) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : "default"; + pastedObjects.forEach(async (obj: THREE.Object3D) => { if (obj) { const worldPosition = new THREE.Vector3(); @@ -329,15 +331,6 @@ const CopyPasteControls = ({ newFloorItem.eventData = eventData; - 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( @@ -391,14 +384,6 @@ const CopyPasteControls = ({ addAsset(asset); } else { - 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 diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx index 93c99fc..1d011ef 100644 --- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; +import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; @@ -23,10 +23,9 @@ const DuplicationControls = ({ 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(); const { addEvent } = useEventsStore(); - const { addAsset } = useAssetsStore(); + const { assets, addAsset } = useAssetsStore(); useEffect(() => { if (!camera || !scene || toggleView) return; @@ -72,7 +71,7 @@ const DuplicationControls = ({ canvasElement.removeEventListener("keydown", onKeyDown); }; - }, [camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects]); + }, [assets, camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, rotatedObjects]); useFrame(() => { if (duplicatedObjects.length > 0) { @@ -120,6 +119,9 @@ const DuplicationControls = ({ const addDuplicatedAssets = () => { if (duplicatedObjects.length === 0) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : "default"; + duplicatedObjects.forEach(async (obj: THREE.Object3D) => { if (obj) { const worldPosition = new THREE.Vector3(); @@ -303,15 +305,6 @@ const DuplicationControls = ({ newFloorItem.eventData = eventData; - 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( @@ -358,14 +351,6 @@ const DuplicationControls = ({ addAsset(asset); } else { - 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 diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index de50c84..d28e852 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -2,7 +2,6 @@ import * as THREE from "three"; import { useEffect, useMemo, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { - useFloorItems, useSelectedAssets, useSocketStore, useToggleView, diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index b8b9095..83a1eb4 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; import { useEffect, useMemo, useRef } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; +import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 691bb7c..2dcd775 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox"; import { SelectionHelper } from "./selectionHelper"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView, } from "../../../../store/builder/store"; +import { useSelectedAssets, useSocketStore, useToggleView, } from "../../../../store/builder/store"; import BoundingBox from "./boundingBoxHelper"; // import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; diff --git a/app/src/modules/scene/controls/transformControls/transformControls.tsx b/app/src/modules/scene/controls/transformControls/transformControls.tsx index d1167f4..66e965f 100644 --- a/app/src/modules/scene/controls/transformControls/transformControls.tsx +++ b/app/src/modules/scene/controls/transformControls/transformControls.tsx @@ -1,6 +1,6 @@ import { TransformControls } from "@react-three/drei"; import * as THREE from "three"; -import { useSelectedFloorItem, useObjectPosition, useObjectRotation, useFloorItems, useActiveTool, useSocketStore } from "../../../../store/builder/store"; +import { useSelectedFloorItem, useObjectPosition, useObjectRotation, useActiveTool, useSocketStore } from "../../../../store/builder/store"; import { useThree } from "@react-three/fiber"; import * as Types from '../../../../types/world/worldTypes'; @@ -11,6 +11,7 @@ import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; +import { useAssetsStore } from "../../../../store/builder/useAssetStore"; export default function TransformControl() { const state = useThree(); @@ -18,10 +19,10 @@ export default function TransformControl() { const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); const { setObjectPosition } = useObjectPosition(); const { setObjectRotation } = useObjectRotation(); - const { setFloorItems } = useFloorItems(); const { activeTool } = useActiveTool(); const { socket } = useSocketStore(); const { selectedProduct } = useSelectedProduct(); + const { updateAsset, getAssetById } = useAssetsStore(); const email = localStorage.getItem('email') const organization = (email!.split("@")[1]).split(".")[0]; @@ -60,97 +61,76 @@ export default function TransformControl() { 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, + const asset = getAssetById(selectedFloorItem?.uuid); + if (asset) { + if (asset.eventData) { + const eventData = useEventsStore.getState().getEventByModelUuid(asset.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(selectedProduct.productId, asset.modelUuid); + + if (eventData) { + useEventsStore.getState().updateEvent(asset.modelUuid, { position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number], - rotation: { x: selectedFloorItem.rotation.x, y: selectedFloorItem.rotation.y, z: selectedFloorItem.rotation.z }, - }; - return updatedItem; + rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z] as [number, number, number], + }); } - return item; - }); - if (updatedItem && selectedFloorItem) { - if (updatedItem.eventData) { - const eventData = useEventsStore.getState().getEventByModelUuid(updatedItem.modelUuid); - const productData = useProductStore.getState().getEventByModelUuid(selectedProduct.productId, updatedItem.modelUuid); - if (eventData) { - useEventsStore.getState().updateEvent(updatedItem.modelUuid, { - position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z], - rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z], - }); - } + if (productData) { + const event = useProductStore + .getState() + .updateEvent( + selectedProduct.productId, + asset.modelUuid, + { + position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number], + rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z] as [number, number, number], + } + ); - if (productData) { - const event = useProductStore - .getState() - .updateEvent( - selectedProduct.productId, - updatedItem.modelUuid, - { - position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z], - rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z], - } - ); - - if (event) { - updateBackend( - selectedProduct.productName, - selectedProduct.productId, - organization, - event - ); - } - - updatedItem.eventData = eventData; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); } } - - setFloorItems((prevItems: Types.FloorItems) => { - const updatedItems = [...(prevItems || []), updatedItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - - // REST - - // setFloorItemApi( - // organization, - // updatedItem.modelUuid, - // updatedItem.modelName, - // updatedItem.modelfileid, - // [selectedFloorItem.position.x, 0, 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, - modelfileID: updatedItem.modelfileID, - position: [selectedFloorItem.position.x, 0, 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; - }); + + updateAsset(asset.modelUuid, { + position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z], + rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z] as [number, number, number], + }); + + //REST + + // await setFloorItemApi( + // organization, + // asset.modelUuid, + // asset.modelName, + // [selectedFloorItem.position.x, 0, selectedFloorItem.position.z, + // { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z }, + // asset.assetId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modelUuid: asset.modelUuid, + modelName: asset.modelName, + modelfileID: asset.assetId, + position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number], + 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); + } } useEffect(() => { diff --git a/app/src/modules/scene/environment/shadow.tsx b/app/src/modules/scene/environment/shadow.tsx index 59b348b..d8c8002 100644 --- a/app/src/modules/scene/environment/shadow.tsx +++ b/app/src/modules/scene/environment/shadow.tsx @@ -6,7 +6,6 @@ import { useElevation, useShadows, useSunPosition, - useFloorItems, useWallItems, useTileDistance, } from "../../../store/builder/store"; @@ -26,14 +25,13 @@ export default function Shadows() { const { controls, gl } = useThree(); const { elevation, setElevation } = useElevation(); const { azimuth, setAzimuth } = useAzimuth(); - const { floorItems } = useFloorItems(); const { wallItems } = useWallItems(); const { planeValue } = useTileDistance(); useEffect(() => { gl.shadowMap.enabled = true; gl.shadowMap.type = THREE.PCFShadowMap; - }, [gl, floorItems, wallItems]); + }, [gl, wallItems]); useEffect(() => { if (lightRef.current && targetRef.current) { diff --git a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts index 86fd13f..236905b 100644 --- a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts +++ b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts @@ -28,7 +28,7 @@ export const handleAddEventToProduct = ({ organization: organization, eventDatas: event }).then((data) => { - // console.log(data); + console.log(data); }) if (clearSelectedAsset) { diff --git a/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx b/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx deleted file mode 100644 index 715aa37..0000000 --- a/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { useThree } from '@react-three/fiber' -import { useEffect } from 'react' -import { Object3D } from 'three'; -import { useSubModuleStore } from '../../../../store/useModuleStore'; -import { useLeftData, useTopData } from '../../../../store/visualization/useZone3DWidgetStore'; -import { useEventsStore } from '../../../../store/simulation/useEventsStore'; -import { useProductStore } from '../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; -import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore'; - -function AddOrRemoveEventsInProducts() { - const { gl, raycaster, scene } = useThree(); - const { subModule } = useSubModuleStore(); - const { setTop } = useTopData(); - const { setLeft } = useLeftData(); - const { getIsEventInProduct } = useProductStore(); - const { getEventByModelUuid } = useEventsStore(); - const { selectedProduct } = useSelectedProduct(); - const { selectedAsset, setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); - - useEffect(() => { - - const canvasElement = gl.domElement; - - let drag = false; - let isRightMouseDown = false; - - const onMouseDown = (evt: MouseEvent) => { - if (selectedAsset) { - clearSelectedAsset(); - } - if (evt.button === 2) { - isRightMouseDown = true; - drag = false; - } - }; - - const onMouseUp = (evt: MouseEvent) => { - if (evt.button === 2) { - isRightMouseDown = false; - } - } - - const onMouseMove = () => { - if (isRightMouseDown) { - drag = true; - } - }; - - const handleRightClick = (evt: MouseEvent) => { - if (drag) return; - evt.preventDefault(); - const canvasElement = gl.domElement; - if (!canvasElement) return; - - 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") && - !(intersect.object?.parent?.name.includes('zones')) && - !(intersect.object?.parent?.name.includes('Zone')) - ); - if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { - let currentObject = intersects[0].object; - - while (currentObject) { - if (currentObject.name === "Scene") { - break; - } - currentObject = currentObject.parent as Object3D; - } - if (currentObject) { - const isInProduct = getIsEventInProduct(selectedProduct.productId, currentObject.uuid); - - if (isInProduct) { - const event = getEventByModelUuid(currentObject.uuid); - if (event) { - setSelectedAsset(event) - const canvasRect = canvasElement.getBoundingClientRect(); - const relativeX = evt.clientX - canvasRect.left; - const relativeY = evt.clientY - canvasRect.top; - - setTop(relativeY); - setLeft(relativeX); - } else { - clearSelectedAsset() - } - } else { - const event = getEventByModelUuid(currentObject.uuid); - if (event) { - setSelectedAsset(event) - const canvasRect = canvasElement.getBoundingClientRect(); - const relativeX = evt.clientX - canvasRect.left; - const relativeY = evt.clientY - canvasRect.top; - - setTop(relativeY); - setLeft(relativeX); - } else { - clearSelectedAsset() - } - } - - } - } else { - clearSelectedAsset() - } - - }; - - if (subModule === 'simulations') { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener('contextmenu', handleRightClick); - } - - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener('contextmenu', handleRightClick); - }; - - }, [gl, subModule, selectedProduct, selectedAsset]); - - return ( - <> - ) -} - -export default AddOrRemoveEventsInProducts \ No newline at end of file diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index f0fd1f4..1ea1b21 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -2,7 +2,6 @@ import * as THREE from 'three'; import { useEffect } from 'react'; import { useProductStore } from '../../../store/simulation/useProductStore'; import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; -import AddOrRemoveEventsInProducts from './events/addOrRemoveEventsInProducts'; import { upsertProductOrEventApi } from '../../../services/simulation/products/UpsertProductOrEventApi'; import { getAllProductsApi } from '../../../services/simulation/products/getallProductsApi'; import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; @@ -127,8 +126,6 @@ function Products() { return ( <> - - ) } diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 6e49734..dc6adc3 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -7,7 +7,6 @@ import RealTimeVisulization from "../modules/visualization/RealTimeVisulization" import Tools from "../components/ui/Tools"; import { useSocketStore, - useFloorItems, useOrganization, useUserName, useWallItems, @@ -34,10 +33,11 @@ import Footer from "../components/footer/Footer"; import SelectFloorPlan from "../components/temporary/SelectFloorPlan"; import ControlsPlayer from "../components/layout/controls/ControlsPlayer"; import CompareLayOut from "../components/ui/compareVersion/CompareLayOut"; -import {useToggleStore} from "../store/useUIToggleStore"; +import { useToggleStore } from "../store/useUIToggleStore"; import RegularDropDown from "../components/ui/inputs/RegularDropDown"; import VersionSaved from "../components/layout/sidebarRight/versionHisory/VersionSaved"; import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; +import { useAssetsStore } from "../store/builder/useAssetStore"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -46,9 +46,9 @@ const Project: React.FC = () => { const { activeModule, setActiveModule } = useModuleStore(); const { loadingProgress } = useLoadingProgress(); + const { setAssets } = useAssetsStore(); const { setUserName } = useUserName(); const { setOrganization } = useOrganization(); - const { setFloorItems } = useFloorItems(); const { setWallItems } = useWallItems(); const { setZones } = useZones(); const { isVersionSaved } = useSaveVersion(); @@ -61,7 +61,7 @@ const Project: React.FC = () => { }, [isVersionSaved]); useEffect(() => { - setFloorItems([]); + setAssets([]); setWallItems([]); setZones([]); setActiveModule("builder"); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index f05a1b2..70e8a63 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -155,15 +155,6 @@ export const useDeletePointOrLine = create((set: any) => ({ setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), })); -export const useFloorItems = create((set: any) => ({ - floorItems: null, - setFloorItems: (callback: any) => - set((state: any) => ({ - floorItems: - typeof callback === "function" ? callback(state.floorItems) : callback, - })), -})); - export const useWallItems = create((set: any) => ({ wallItems: [], setWallItems: (callback: any) => diff --git a/app/src/store/builder/useAssetStore.ts b/app/src/store/builder/useAssetStore.ts index 326a877..ffa1d35 100644 --- a/app/src/store/builder/useAssetStore.ts +++ b/app/src/store/builder/useAssetStore.ts @@ -11,6 +11,7 @@ interface AssetsStore { setAssets: (assets: Assets) => void; // Asset properties + setName: (modelUuid: string, newName: string) => void; setPosition: (modelUuid: string, position: [number, number, number]) => void; setRotation: (modelUuid: string, rotation: [number, number, number]) => void; setLock: (modelUuid: string, isLocked: boolean) => void; @@ -70,6 +71,15 @@ export const useAssetsStore = create()( }, // Asset properties + setName: (modelUuid, newName) => { + set((state) => { + const asset = state.assets.find(a => a.modelUuid === modelUuid); + if (asset) { + asset.modelName = newName; + } + }); + }, + setPosition: (modelUuid, position) => { set((state) => { const asset = state.assets.find(a => a.modelUuid === modelUuid); -- 2.49.1 From 42a3d7285e73df1c2cdfe4fbe7f8c5dd335370a9 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 27 May 2025 11:31:03 +0530 Subject: [PATCH 05/34] Refactor asset management: - Removed obsolete Models component and integrated its functionality into AssetsGroup. - Updated import paths for AssetsGroup and related components. - Implemented new asset loading and event handling logic in AssetsGroup. - Added asset bounding box visualization. - Enhanced model loading with caching and error handling. - Improved asset interaction features including selection and deletion. --- app/src/modules/builder/{assetGroup => asset}/assetsGroup.tsx | 0 .../builder/{assetGroup => asset}/functions/addAssetModel.ts | 0 .../{assetGroup => asset}/functions/assetBoundingBox.tsx | 0 .../builder/{assetGroup => asset}/models/model/model.tsx | 0 app/src/modules/builder/{assetGroup => asset}/models/models.tsx | 0 app/src/modules/builder/builder.tsx | 2 +- 6 files changed, 1 insertion(+), 1 deletion(-) rename app/src/modules/builder/{assetGroup => asset}/assetsGroup.tsx (100%) rename app/src/modules/builder/{assetGroup => asset}/functions/addAssetModel.ts (100%) rename app/src/modules/builder/{assetGroup => asset}/functions/assetBoundingBox.tsx (100%) rename app/src/modules/builder/{assetGroup => asset}/models/model/model.tsx (100%) rename app/src/modules/builder/{assetGroup => asset}/models/models.tsx (100%) diff --git a/app/src/modules/builder/assetGroup/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx similarity index 100% rename from app/src/modules/builder/assetGroup/assetsGroup.tsx rename to app/src/modules/builder/asset/assetsGroup.tsx diff --git a/app/src/modules/builder/assetGroup/functions/addAssetModel.ts b/app/src/modules/builder/asset/functions/addAssetModel.ts similarity index 100% rename from app/src/modules/builder/assetGroup/functions/addAssetModel.ts rename to app/src/modules/builder/asset/functions/addAssetModel.ts diff --git a/app/src/modules/builder/assetGroup/functions/assetBoundingBox.tsx b/app/src/modules/builder/asset/functions/assetBoundingBox.tsx similarity index 100% rename from app/src/modules/builder/assetGroup/functions/assetBoundingBox.tsx rename to app/src/modules/builder/asset/functions/assetBoundingBox.tsx diff --git a/app/src/modules/builder/assetGroup/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx similarity index 100% rename from app/src/modules/builder/assetGroup/models/model/model.tsx rename to app/src/modules/builder/asset/models/model/model.tsx diff --git a/app/src/modules/builder/assetGroup/models/models.tsx b/app/src/modules/builder/asset/models/models.tsx similarity index 100% rename from app/src/modules/builder/assetGroup/models/models.tsx rename to app/src/modules/builder/asset/models/models.tsx diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index dcd2659..c69252b 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -46,7 +46,7 @@ import MeasurementTool from "../scene/tools/measurementTool"; import NavMesh from "../simulation/vehicle/navMesh/navMesh"; import CalculateAreaGroup from "./groups/calculateAreaGroup"; import LayoutImage from "./layout/layoutImage"; -import AssetsGroup from "./assetGroup/assetsGroup"; +import AssetsGroup from "./asset/assetsGroup"; import { Bvh } from "@react-three/drei"; export default function Builder() { -- 2.49.1 From 99ef074765c573a89dce55c0636fc578ff7b03a2 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 27 May 2025 16:09:36 +0530 Subject: [PATCH 06/34] feat: add AisleProperties component with texture and type selection --- app/src/assets/image/aisleTypes/Arc.png | Bin 0 -> 1184 bytes app/src/assets/image/aisleTypes/Arrow.png | Bin 0 -> 646 bytes app/src/assets/image/aisleTypes/Arrows.png | Bin 0 -> 551 bytes app/src/assets/image/aisleTypes/Circle.png | Bin 0 -> 1857 bytes app/src/assets/image/aisleTypes/Dashed.png | Bin 0 -> 494 bytes .../assets/image/aisleTypes/Directional.png | Bin 0 -> 1044 bytes app/src/assets/image/aisleTypes/Dotted.png | Bin 0 -> 550 bytes app/src/assets/image/aisleTypes/Solid.png | Bin 0 -> 229 bytes .../layout/sidebarRight/SideBarRight.tsx | 266 +++++++++--------- .../properties/AisleProperties.tsx | 191 +++++++++++++ app/src/styles/layout/sidebar.scss | 135 ++++++--- 11 files changed, 425 insertions(+), 167 deletions(-) create mode 100644 app/src/assets/image/aisleTypes/Arc.png create mode 100644 app/src/assets/image/aisleTypes/Arrow.png create mode 100644 app/src/assets/image/aisleTypes/Arrows.png create mode 100644 app/src/assets/image/aisleTypes/Circle.png create mode 100644 app/src/assets/image/aisleTypes/Dashed.png create mode 100644 app/src/assets/image/aisleTypes/Directional.png create mode 100644 app/src/assets/image/aisleTypes/Dotted.png create mode 100644 app/src/assets/image/aisleTypes/Solid.png create mode 100644 app/src/components/layout/sidebarRight/properties/AisleProperties.tsx diff --git a/app/src/assets/image/aisleTypes/Arc.png b/app/src/assets/image/aisleTypes/Arc.png new file mode 100644 index 0000000000000000000000000000000000000000..74e72867b970a842e7a7c999b98fccc92514c82e GIT binary patch literal 1184 zcmV;R1Yi4!P)eqSObnWD-6AC2ZxPZe%04ft7&ZnvSe_#hoO|;6hgf6}N`r0}x?} zXec2O;wwW?LnNZ--*yrt(B5`Bofi8`PHtzWo#gy`9{1jsC?X;vA|fJU4-V16Kw^{G zVrHjF8AOf$dV|M)p$MB$s{&{v+s%UoA`I1Z;V`7xb-!Is2NWH{~^zeG^j z#yVS0$wR&8$PMFDDc$jz*`IK9gbe5B$piclp_}{t@Wj9c$GMNZe)#;WZhV~Nui|9f zaZky%2qRqly52mJ9fv>eeDBa&R-I3iO%W2D|E&`P=XoKMCwvidzJK&H!ahk^c0Nru zM9>T1?Q6wc0Lz6hLg@F8e&W#ohMdRbX`Fl_8zM|Q6#(t+M(+yxIttzca#`iw;`KZs z;Zy*=^H}f0={sapeBbdh65_nRS7)DH5;_^--!r(%ZEqcuo9p!N#Ku>=ii9|K0To?9 z1nuJ%-MqhoG)VBrd*pNY@5YNrh_L`~McW_*sPE8_|8X+%Kj(<|uDy}jCI@>;Ln{Et zR0Ne5LA>8rV0&Uv1pt|(LmQ{T*!x$NwkHNz0N_>xnQi*RRHbZ}2IvCy9U6*YoB}8S zaGMS)R)ivT0JA_AAUz2RByJ)><}_Fm=>}K>uxWgFkphgHNEq&GKWi%h>VPRg9R(bx zk)UuCOp6r5%MFVtgl**GLdY#nBSA$J*nu=)0TL7f0f3W8&})HR6d(<*G%jjnq=7~u zz)2*icqC>Ax&f1*kO%-oBLN#FOFS=-tO_D_h3Y$&H41n)*o|l;H1nfyNu(u`u_YEN zL`7)DdjM9T7Vy5HMj0F7udB(St`t5`Z8U$?+K}m-*mceLFB&z zi(Mqd?4rO-g(QU-I}xhw9-?wv#1Pt402xODo*t3$Vnk@M6M+{^M=ehNGYT}y@xzl$u@XVz&LCM$lF%6_q;rFvScxEuY@yKs7Xgt#R;+*D#t`aM02w`j yGSlHei-7Gk`rm0|`y*f~MMOkIL_|a!ME(M2^oF;*SE*nC0000!U8pjw!xMO6IqaA+XfpZD6STFgcOvE znI~?}duH42=n(Fk+`;j@_lviD}>OcNl^m|VdTg9JsiyH;7tevEi)RYIz}^0 ztlQvJ2xf(_exDIC9P;-P(8vagFd+nH+dKej{~*m0Ik!4sT4$#wM%4a6CPomKT=AHy gkst_yAP6q-3*?J}V--lCBme*a07*qoM6N<$g4(1Dp#T5? literal 0 HcmV?d00001 diff --git a/app/src/assets/image/aisleTypes/Arrows.png b/app/src/assets/image/aisleTypes/Arrows.png new file mode 100644 index 0000000000000000000000000000000000000000..c025010e605903e269d7702d18603ddcf6b0510b GIT binary patch literal 551 zcmeAS@N?(olHy`uVBq!ia0vp^jv&mz1|<8wpL7LMoCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qc2d~#(wTUiL5}mJ)SO(Ar*{oXV`l%1&E+W)ShUb}w$xS~F0HrU&$aBCvaEW} zo$t)?Pxe+T)zrQ(tYL8K=r(v*m^5jZ3TuCoN7wIY<*z3)97GcjC9|j=eY^GHujgk| zZ0n5{dTA^U>`6ai!kyvvmSd*=qQD7ZRSV~rDA`T0@oJA&OJDvgU}YWa`uzKgjBHxn zN~TXRI@EY~^Ik)i_J9Ar9J-^h?$i2{egp{QW%7X9zmlr<#C;Rzi(9%CKv!^9;@?BI!q>C{!g%orm`QnB}^AFW67#2gWOdr>mdKI;Vst0B&5|`~Uy| literal 0 HcmV?d00001 diff --git a/app/src/assets/image/aisleTypes/Circle.png b/app/src/assets/image/aisleTypes/Circle.png new file mode 100644 index 0000000000000000000000000000000000000000..8be99299d6c9bb742190f2b7bfafdffa51e528db GIT binary patch literal 1857 zcmV-H2fp};P)ulBJNe$L_bdMh zQDFYuRr?~?;oW>60%}cL136Fd%Hf~s$g$rMJup2=5~5TQYyo)gCo%v1z=a<I|qz4+PTX3sD23DI+J{E$EW)$%+1vX`8s zCr4`J#P^T$oX_*IkYU!a?~(ps*ORrdv{s&Cft_VgOVHT!e|u_7linGaJ{%UCy-AM4 zvZ#DCavZSk<$z&%k3V}J=YVNpk|OFJ$YIvYG;tDb&zy$<289^M#c?|LP8*#A)*6Sp z8ieMLG7sSCI0YccbV&DgC(<%U2m!Eod5-FAx?jNRp*=H`UO}7J7f5fF&@i)2UML7umVjs z4G^M)4~SZT0>gZ_O*mgS;6OQTFBEaUsEUx;+vTph$mbCP`>C?@A3Ay=FY^y#+NMYW z6%mqbUYe{RLLR`3Qg}{K73!afTi-0wtj3=kC^F&32p55(rt{=b(L?RSPov*?pBiul-MNZ=7iHZnzQ^XDS(s)3YW>IypGf|}EZU_-{@6kQ4_hBENJUArW^%DHcbF$&tc!N{ButJi4b4ej;cnZ`}~h(2912 zJ+Q?26oIBLv(xLxej>EAG~Vv|0h}UL&ljv`4xMT@>TCV;K|c|s8KQ{K7HteHaZ`#A ztv=1`$3Y9I|0S^q-HOdtGTFBFa^rs*8^9w5(0f2^}6h^BEP#I44U) zMB}rEs!N}&xq=oyDfAjuL@=>3>;|{p@sK8G9ikd&JW`@iDq`BS3p|s2P!S<3s>LEO zCAirF0fwkLpyQR0b-aWK(|!k0vIO=ErmRv!2WQ9jO$Vs*PEzABBy0R)Du{gzzV(f2 zvUC!CMAtLnQ2FNb4fet;RhDrUKxze(Gj?iVkOHcUFStl7x+G-1h0XyB&DLSnKQ0r4 zopR>XSc~h2s3RWP{f)&>A0h=*EdjEQ%B%r=`ff9_$P7gdl zO!Hfot{)R;7S?Kx_lB z$f;gKS@;Q4gaTw8HGn64Pb%!VV$@I>U2km+`z1MolpyUGJ=f2``W z$lZxy-8q?;Kn_c~qc2d~#(wTUiL5}mW=|K#kP61P*E#(T8wfZA`X9;Mk-~NSf!~}K z;{y*W4$4_a3+l4{Rp047$7Altij_dqpbl`w)a1u>Ta=}EbY+Y79+Z&<866t(k+%F&sX2m=9$>y%I6g{ z$8v>G%-k8O9#@y@f1keONXpG6Z=}^YXD)L*vpC;t zT3P+-i);5^f8Wt|5PDbcpEmt^n03%E8RTkGMO&X3QM6rR=uru5#KX?lOjO?#(vOYe8Td+s?cL<)sMp-_ZPFDWR?ZGak> zl-Ayq=f?$VV6w07>-l6yGlUqR1|-$r*P8$P`b_>&`gFs(!E^ycK#RK@nn*lwf!^QO z;$9dZIf;if#gs!Np6tiDZk<=Z;9}R%ds^MtJI7BKDQ1XvLTY$OD-r<2*$twdP|^hs zadm@8CzN%8LtNb;(g_t^;4nC9(9-hnSh+!z6MS9ZFg|hu53zECC=t^3<-Np zGHM5)CE54nfV-oCNfWhYD7jU4H2?zVfVt+?3OucOkUJBc`~=nVr-%yyUX1P zZaF$2Qk;AS=EsQH?|* z!qn_{p2QBlefI~Gf{k;$g>>&0Dm`w?+yXo%!`*vS!xr!oN?>%rq%Vwp!aiQ)F7`53 z5fjnLIweYCtncyaub~9Txa-{BkU&Cn!p!_OjZJRke*E0O#NFpX$6@tvJ>0~&3|Xr$ z92p`c5^aSiz|!(Bx|~_VisMKNw2E-ejoV+G)rW8fNkWDQnw=N8z|Lf?zOMiXe25vG z3qZ6CNm_j`p=<|F##j-{G3$sK5Da_Ypb!Yf2|<8c21i#7vL+umW{5yW?NC%a*`jDZ z<8WG>rH};xQk>u|qk-M8B!WSf10q3^6RO`1Q4&fi9d|-;LeSG8Dnbd2aVNA-YYXFd zLPUZL5la3LbC54v!$Ji{QX-g$7NP8S32{ClloLq22t_Hg`$Dk#Argd(P%dQ-P(MV5 z+71+=6XJ{n5lX+MIvrw;Xc3Y=zaqslFp38Me3h@zrb(etC=?1sz3?Bvwn`6qF8)dY O0000``W z$lZxy-8q?;Kn_c~qc2d~#(wTUiL5}m-JULvAr*{oZ|wCtoFKyX;QF*x8dDWIt}MO3 zK*7&Re?eTswsm^{bn>bg`M6|dVq)g(%6NaEiaFQa(cHXsS@$D(5pJ%3M?W7G3fTCz zB@cjR6BCxt~9wrbaxq*dpN{H?WLf21T! z;Onv3#WmkdbZ4__T#OO!k?aoD?^BC1J1Jl=&vN?ta^=~k8XXS)*W_N7&8ZNX`DMai zD}L2k&IKtSU#|!}C$V4N%cMPEeeB+nD=*^ge*X?pRkx3wdb#*MSZ(S> z?dPA&b!Qj-j6NY*%y5)l{cUuLYhHcX!Qy@TlfLoXys`V3-@|)T&x&fq@g>@rNw3t6 z{4?$HN=6moz28nOj;Pzvtns**K~JRg^6tZmQ|57ZbVMbt5E5c;)8Yx0SY;5BxZ+Xr z3Z^zKyEd(a6+#IsE~Oj@P)#@x(Au#}zFVdQ&MBb@0N!TdX8-^I literal 0 HcmV?d00001 diff --git a/app/src/assets/image/aisleTypes/Solid.png b/app/src/assets/image/aisleTypes/Solid.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfb8dfa537c96cdeb65fedb23ab09d04bdfa24e GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^jv&mz1|<8wpL7LMjKx9jP7LeL$-D$|=6kw0hEy=V zz5bB1K|z4+Li8e4nKgz*j_zDK+)@XWPRuK?XRWRak8N>nU|?io;Sf-8z+ils<^5zWV94fk3A+c)I$ztaD0e0sw3jMKJ&X literal 0 HcmV?d00001 diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 582b085..10de581 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -67,142 +67,142 @@ const SideBarRight: React.FC = () => { }`} >
- {toggleUIRight && !isVersionSaved && ( -
- {activeModule !== "simulation" && ( - + {toggleUIRight && ( + <> + {!isVersionSaved && ( +
+ {activeModule !== "simulation" && ( + + )} + {activeModule === "simulation" && ( + <> + + + + + )} +
)} - {activeModule === "simulation" && ( - <> - - - - + + {viewVersionHistory && ( +
+
+ +
+
)} -
+ + {/* process builder */} + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && ( +
+
+ +
+
+ )} + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + selectedFloorItem && ( +
+
+ +
+
+ )} + + {!viewVersionHistory && + subModule === "zoneProperties" && + (activeModule === "builder" || activeModule === "simulation") && ( +
+
+ +
+
+ )} + {/* simulation */} + {!isVersionSaved && + !viewVersionHistory && + activeModule === "simulation" && ( + <> + {subModule === "simulations" && ( +
+
+ +
+
+ )} + {subModule === "mechanics" && ( +
+
+ +
+
+ )} + {subModule === "analysis" && ( +
+
+ +
+
+ )} + + )} + {/* realtime visualization */} + {activeModule === "visualization" && } + )} - - {toggleUIRight && viewVersionHistory && ( -
-
- -
-
- )} - - {/* process builder */} - {toggleUIRight && - !viewVersionHistory && - subModule === "properties" && - activeModule !== "visualization" && - !selectedFloorItem && ( -
-
- -
-
- )} - {toggleUIRight && - !viewVersionHistory && - subModule === "properties" && - activeModule !== "visualization" && - selectedFloorItem && ( -
-
- -
-
- )} - - {toggleUIRight && - !viewVersionHistory && - subModule === "zoneProperties" && - (activeModule === "builder" || activeModule === "simulation") && ( -
-
- -
-
- )} - {/* simulation */} - {toggleUIRight && - !isVersionSaved && - !viewVersionHistory && - activeModule === "simulation" && ( - <> - {subModule === "simulations" && ( -
-
- -
-
- )} - {subModule === "mechanics" && ( -
-
- -
-
- )} - {subModule === "analysis" && ( -
-
- -
-
- )} - - )} - {/* realtime visualization */} - {toggleUIRight && activeModule === "visualization" && }
); }; diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx new file mode 100644 index 0000000..eaab9f6 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx @@ -0,0 +1,191 @@ +import React, { useState } from "react"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; +import { ArrowIcon } from "../../../icons/ExportCommonIcons"; + +// image imports +import Arc from "../../../../assets/image/aisleTypes/Arc.png"; +import Arrow from "../../../../assets/image/aisleTypes/Arrow.png"; +import Arrows from "../../../../assets/image/aisleTypes/Arrows.png"; +import Circle from "../../../../assets/image/aisleTypes/Circle.png"; +import Dashed from "../../../../assets/image/aisleTypes/Dashed.png"; +import Directional from "../../../../assets/image/aisleTypes/Directional.png"; +import Dotted from "../../../../assets/image/aisleTypes/Dotted.png"; +import Solid from "../../../../assets/image/aisleTypes/Solid.png"; + +interface TextureItem { + color: string; + id: string; + brief: string; + texture: string; +} + +const AisleProperties: React.FC = () => { + const [collapsePresets, setCollapsePresets] = useState(false); + const [collapseTexture, setCollapseTexture] = useState(true); + const [selectedTexture, setSelectedTexture] = useState( + "yellow1" + ); + const [selectedType, setSelectedType] = useState("Solid"); + + const aisleTextureList: TextureItem[] = [ + { color: "gray", id: "gray", brief: "basic", texture: "" }, + { + color: "yellow", + id: "yellow1", + brief: "pedestrian walkways", + texture: "", + }, + { color: "green", id: "green1", brief: "pedestrian walkways", texture: "" }, + { color: "orange", id: "orange", brief: "material flow", texture: "" }, + { color: "blue", id: "blue", brief: "vehicle paths", texture: "" }, + { color: "purple", id: "purple", brief: "material flow", texture: "" }, + { color: "red", id: "red", brief: "safety zone", texture: "" }, + { + color: "bright green", + id: "bright-green", + brief: "safety zone", + texture: "", + }, + { + color: "yellow-black", + id: "yellow-black", + brief: "utility aisles", + texture: "", + }, + { + color: "white-black", + id: "white-black", + brief: "utility aisles", + texture: "", + }, + ]; + + const aisleTypes = [ + { + name: "Solid", + id: "1", + thumbnail: Solid, + }, + { + name: "Dotted", + id: "2", + thumbnail: Dotted, + }, + { + name: "Dashed", + id: "3", + thumbnail: Dashed, + }, + { + name: "Arrow", + id: "4", + thumbnail: Arrow, + }, + { + name: "Contiuous Arrows", + id: "5", + thumbnail: Arrows, + }, + { + name: "Directional", + id: "6", + thumbnail: Directional, + }, + { + name: "Arc", + id: "7", + thumbnail: Arc, + }, + { + name: "Circle", + id: "8", + thumbnail: Circle, + }, + ]; + + return ( +
+
Properties
+
+ {}} + /> +
+ + {/* Presets */} +
+ + {!collapsePresets && ( +
+ {aisleTypes.map((val) => ( +
+ +
+ ))} +
+ )} +
+ + {/* Texture */} +
+ + + {collapseTexture && ( +
+ {aisleTextureList.map((val) => ( + + ))} +
+ )} +
+
+ ); +}; + +export default AisleProperties; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 3a2dd11..543150f 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -486,9 +486,6 @@ .add-icon { transform: scale(1.1); - - - } .kebab-icon { @@ -539,7 +536,7 @@ gap: 4px; .saved-history-count { - font-size: var(--font-size-tiny) + font-size: var(--font-size-tiny); } } } @@ -556,7 +553,6 @@ gap: 12px; .version-name { - background: var(--background-color); border: 1px solid var(--border-color); color: var(--text-color); @@ -588,7 +584,6 @@ display: flex; flex-direction: column; gap: 6px; - } .saved-by { @@ -597,7 +592,6 @@ gap: 6px; .user-profile { - background: var(--background-color-accent); color: var(--text-button-color); width: 20px; @@ -612,7 +606,6 @@ .user-name { text-transform: capitalize; - } } @@ -625,8 +618,6 @@ } } } - - } .no-event-selected { @@ -665,7 +656,7 @@ path { stroke: var(--text-button-color); - strokeWidth: 1.3; + stroke-width: 1.3; } } } @@ -686,7 +677,6 @@ max-height: 60vh; .sidebar-right-content-container { - .dataSideBar { .inputs-wrapper { display: flex; @@ -936,7 +926,7 @@ path { stroke: var(--accent-color); - strokeWidth: 1.5px; + stroke-width: 1.5px; } &:hover { @@ -1271,15 +1261,105 @@ } } + .aisle-properties-container { + max-height: 65vh; + overflow: auto; + .aisle-texture-container { + max-height: 40vh; + overflow: auto; + .aisle-list { + width: calc(100% - 8px); + text-align: start; + padding: 4px 6px; + display: flex; + align-items: center; + gap: 6px; + border-radius: #{$border-radius-large}; + margin: 2px 6px; + .texture-display { + height: 34px; + width: 34px; + background: #7e7e7e86; + border-radius: #{$border-radius-large}; + margin-right: 4px; + overflow: hidden; + } + .aisle-color { + text-transform: capitalize; + } + .aisle-brief { + font-size: var(--font-size-small); + color: var(--input-text-color); + } + &.selected { + background: var(--background-color-accent); + color: var(--text-button-color); + &:hover { + background: var(--background-color-accent); + } + } + &:hover { + background: var(--background-color-secondary); + } + } + } + .value-field-container { + margin: 0; + } + .presets-list-container { + display: flex; + flex-wrap: wrap; + gap: 6px; + padding: 6px; + padding-left: 7px; + .preset-list { + background: #444; + height: 90px; + width: 90px; + border-radius: #{$border-radius-large}; + overflow: hidden; + .thumbnail { + height: 100%; + width: 100%; + border-radius: #{$border-radius-large}; + outline-offset: -1px; + img { + height: 100%; + width: 100%; + object-fit: cover; + transition: all 0.2s; + } + &.selected { + outline: 2px solid var(--border-color-accent); + outline-offset: -2px; + &:hover { + outline: 2px solid var(--border-color-accent); + img { + transform: scale(1); + } + } + } + &:hover { + outline: 1px solid var(--border-color); + img { + transform: scale(1.1); + } + } + } + } + } + } + .global-properties-container, .analysis-main-container, .asset-properties-container, - .zone-properties-container { + .zone-properties-container, + .aisle-properties-container { .header { @include flex-space-between; padding: 10px 12px; color: var(--text-color); - + width: 100%; .input-value { color: inherit; } @@ -1661,9 +1741,11 @@ width: 100%; height: 100%; font-size: var(--font-size-regular); - background: linear-gradient(0deg, - rgba(37, 24, 51, 0) 0%, - rgba(52, 41, 61, 0.5) 100%); + background: linear-gradient( + 0deg, + rgba(37, 24, 51, 0) 0%, + rgba(52, 41, 61, 0.5) 100% + ); pointer-events: none; backdrop-filter: blur(8px); opacity: 0; @@ -1740,9 +1822,6 @@ } } - - - .versionSaved { min-width: 449px; position: fixed; @@ -1798,7 +1877,6 @@ } button { - font-size: var(--font-size-small); display: flex; justify-content: center; @@ -1810,10 +1888,7 @@ cursor: pointer; } } - - } - } .dismissing { @@ -1821,8 +1896,6 @@ } .edit-version-popup-wrapper { - - height: 100vh; width: 100vw; background: var(--background-color-secondary); @@ -1835,8 +1908,6 @@ border-radius: #{$border-radius-large}; backdrop-filter: blur(15px); outline: 1px solid var(--border-color); - padding: 6px; - display: flex; flex-direction: column; gap: 30px; @@ -1854,7 +1925,6 @@ .version-name, .version-description { - background: var(--background-color); backdrop-filter: blur(20px); border-radius: 20px; @@ -1870,7 +1940,6 @@ right: 8px; font-size: var(--font-size-tiny); color: var(--text-disabled); - } input { @@ -1883,7 +1952,6 @@ .version-description { textarea { - padding: 4px 8px; width: 100%; min-height: 101px; @@ -1900,7 +1968,6 @@ gap: 20px; .save { - display: flex; justify-content: center; align-items: center; @@ -1912,4 +1979,4 @@ } } } -} \ No newline at end of file +} -- 2.49.1 From bb46eeb3cc1c05aea14474f2004100e08038123c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 27 May 2025 18:11:26 +0530 Subject: [PATCH 07/34] feat: implement aisle management features with creator and instances --- .../aisle/Instances/aisleInstances.tsx | 24 +++ .../Instances/instance/aisleInstance.tsx | 19 ++ .../instance/aisleTypes/dashedAisle.tsx | 71 +++++++ .../instance/aisleTypes/solidAisle.tsx | 53 +++++ .../aisle/aisleCreator/aisleCreator.tsx | 196 ++++++++++++++++++ .../aisle/aisleCreator/referenceAisle.tsx | 193 +++++++++++++++++ app/src/modules/builder/aisle/aislesGroup.tsx | 21 ++ .../builder/asset/models/model/model.tsx | 41 ++-- app/src/modules/builder/builder.tsx | 7 +- .../functions/handleAddEventToProduct.ts | 2 +- app/src/store/builder/useAisleStore.ts | 86 ++++++++ app/src/types/builderTypes.d.ts | 25 ++- app/src/types/world/worldConstants.ts | 4 +- 13 files changed, 720 insertions(+), 22 deletions(-) create mode 100644 app/src/modules/builder/aisle/Instances/aisleInstances.tsx create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx create mode 100644 app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx create mode 100644 app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx create mode 100644 app/src/modules/builder/aisle/aislesGroup.tsx create mode 100644 app/src/store/builder/useAisleStore.ts diff --git a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx new file mode 100644 index 0000000..1ec9308 --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx @@ -0,0 +1,24 @@ +import { useEffect } from 'react'; +import { useAisleStore } from '../../../../store/builder/useAisleStore'; +import AisleInstance from './instance/aisleInstance'; + +function AisleInstances() { + const { aisles } = useAisleStore(); + + useEffect(() => { + console.log('aisles: ', aisles); + }, [aisles]); + + return ( + + <> + + {aisles.map((aisle) => + + )} + + + ) +} + +export default AisleInstances \ No newline at end of file diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx new file mode 100644 index 0000000..beada6f --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx @@ -0,0 +1,19 @@ +import DashedAisle from './aisleTypes/dashedAisle'; +import SolidAisle from './aisleTypes/solidAisle'; + +function AisleInstance({ aisle }: { readonly aisle: Aisle }) { + + return ( + <> + {aisle.type.aisleType === 'solid-aisle' && ( + + )} + + {aisle.type.aisleType === 'dashed-aisle' && ( + + )} + + ); +} + +export default AisleInstance; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx new file mode 100644 index 0000000..5774fcd --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx @@ -0,0 +1,71 @@ +import * as THREE from 'three'; +import { useMemo } from 'react'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../../types/world/worldConstants'; + +function DashedAisle({ aisle }: { readonly aisle: Aisle }) { + const shapes = useMemo(() => { + if (aisle.points.length < 2) return []; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.width || 0.1; + const dashLength = 0.5; + const gapLength = 0.3; + + const direction = new THREE.Vector3().subVectors(end, start).normalize(); + const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + + const totalLength = new THREE.Vector3().subVectors(end, start).length(); + const segmentCount = Math.floor(totalLength / (dashLength + gapLength)); + + const shapes = []; + const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); + + for (let i = 0; i < segmentCount; i++) { + const segmentStart = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * (dashLength + gapLength)); + const segmentEnd = new THREE.Vector3().copy(segmentStart).addScaledVector(directionNormalized, dashLength); + + const leftStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, width / 2); + const rightStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, -width / 2); + const leftEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, width / 2); + const rightEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, -width / 2); + + const shape = new THREE.Shape(); + shape.moveTo(leftStart.x, leftStart.z); + shape.lineTo(leftEnd.x, leftEnd.z); + shape.lineTo(rightEnd.x, rightEnd.z); + shape.lineTo(rightStart.x, rightStart.z); + shape.closePath(); + + shapes.push(shape); + } + + return shapes; + }, [aisle]); + + if (shapes.length === 0) return null; + + return ( + + {shapes.map((shape, index) => ( + + + + ))} + + ); +} + +export default DashedAisle; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx new file mode 100644 index 0000000..c2bfdab --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx @@ -0,0 +1,53 @@ +import * as THREE from 'three'; +import { useMemo } from 'react'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../../types/world/worldConstants'; + +function SolidAisle({ aisle }: { readonly aisle: Aisle }) { + const shape = useMemo(() => { + if (aisle.points.length < 2) return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.width || 0.1; + + const direction = new THREE.Vector3().subVectors(end, start).normalize(); + const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + + const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, width / 2); + const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -width / 2); + const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, width / 2); + const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -width / 2); + + const shape = new THREE.Shape(); + shape.moveTo(leftStart.x, leftStart.z); + shape.lineTo(leftEnd.x, leftEnd.z); + shape.lineTo(rightEnd.x, rightEnd.z); + shape.lineTo(rightStart.x, rightStart.z); + shape.closePath(); + + return shape; + }, [aisle]); + + if (!shape) return null; + + return ( + + + + + + ); +} + +export default SolidAisle; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx new file mode 100644 index 0000000..593c437 --- /dev/null +++ b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx @@ -0,0 +1,196 @@ +import * as THREE from 'three' +import { useEffect, useMemo, useState } from 'react' +import { useThree } from '@react-three/fiber'; +import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; +import { useAisleStore } from '../../../../store/builder/useAisleStore'; +import * as Constants from '../../../../types/world/worldConstants'; +import ReferenceAisle from './referenceAisle'; + +function AisleCreator() { + const { scene, camera, raycaster, gl, pointer } = useThree(); + const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); + const { toggleView } = useToggleView(); + const { toolMode } = useToolMode(); + const { activeLayer } = useActiveLayer(); + const { socket } = useSocketStore(); + const { aisles, addAisle } = useAisleStore(); + + const [tempPoints, setTempPoints] = useState([]); + const [isCreating, setIsCreating] = useState(false); + const [aisleType, setAisleType] = useState<'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'>('dashed-aisle'); + + useEffect(() => { + if (tempPoints.length > 0) { + setTempPoints([]); + setIsCreating(false); + } + }, [aisleType]); + + const allPoints = useMemo(() => { + const points: Point[] = []; + const seenUuids = new Set(); + + // Add points from existing aisles + aisles.forEach(aisle => { + aisle.points.forEach(point => { + if (!seenUuids.has(point.uuid)) { + seenUuids.add(point.uuid); + points.push(point); + } + }); + }); + + // Add temporary points + tempPoints.forEach(point => { + if (!seenUuids.has(point.uuid)) { + seenUuids.add(point.uuid); + points.push(point); + } + }); + + return points; + }, [aisles, tempPoints]); + + + 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 onMouseClick = () => { + if (drag || !toggleView) return; + + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + + if (!point) return; + + if (['solid-aisle', 'dashed-aisle', 'stripped-aisle', 'dotted-aisle', 'arrows-aisle'].includes(aisleType)) { + const newPoint: Point = { + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + layer: activeLayer + }; + + if (tempPoints.length === 0) { + setTempPoints([newPoint]); + setIsCreating(true); + } else { + const aisle: Aisle = { + uuid: THREE.MathUtils.generateUUID(), + points: [tempPoints[0], newPoint], + type: { + typeName: 'Aisle', + material: 'default', + aisleType: aisleType, + color: Constants.aisleConfig.defaultColor, + width: Constants.aisleConfig.width + } + }; + + addAisle(aisle); + + setTempPoints([newPoint]); + } + } else if (['arc-aisle', 'circle-aisle', 'arrow-aisle', 'junction-aisle'].includes(aisleType)) { + const newPoint: Point = { + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + layer: activeLayer + }; + + if (tempPoints.length === 0) { + setTempPoints([newPoint]); + setIsCreating(true); + } else { + const aisle: Aisle = { + uuid: THREE.MathUtils.generateUUID(), + points: [tempPoints[0], newPoint], + type: { + typeName: 'Aisle', + material: 'default', + aisleType: aisleType, + color: Constants.aisleConfig.defaultColor, + width: Constants.aisleConfig.width + } + }; + + addAisle(aisle); + + setTempPoints([]); + setIsCreating(false); + } + } + }; + + const onContext = (event: any) => { + event.preventDefault(); + if (isCreating) { + setTempPoints([]); + setIsCreating(false); + } + }; + + if (toolMode === "Aisle" && toggleView) { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener("click", onMouseClick); + canvasElement.addEventListener("contextmenu", onContext); + } else { + setTempPoints([]); + setIsCreating(false); + } + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("click", onMouseClick); + canvasElement.removeEventListener("contextmenu", onContext); + }; + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addAisle, aisleType]); + + return ( + <> + + {allPoints.map((point) => ( + + + + + ))} + + + + + ); +} + +export default AisleCreator; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx new file mode 100644 index 0000000..437337a --- /dev/null +++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx @@ -0,0 +1,193 @@ +import { useEffect, useMemo, useRef, useState } from 'react'; +import * as THREE from 'three'; +import { useFrame, useThree } from '@react-three/fiber'; +import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store'; +import * as Constants from '../../../../types/world/worldConstants'; +import { Extrude } from '@react-three/drei'; + +interface ReferenceAisleProps { + tempPoints: Point[]; + aisleType: 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'; +} + +function ReferenceAisle({ tempPoints, aisleType }: Readonly) { + const { pointer, raycaster, camera } = useThree(); + const { toolMode } = useToolMode(); + const { toggleView } = useToggleView(); + const { activeLayer } = useActiveLayer(); + const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); + + const [tempAisle, setTempAisle] = useState(null); + const mousePosRef = useRef(new THREE.Vector3()); + + useFrame(() => { + if (toolMode === "Aisle" && toggleView && tempPoints.length === 1) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + raycaster.ray.intersectPlane(plane, intersectionPoint); + + if (intersectionPoint) { + mousePosRef.current.copy(intersectionPoint); + + setTempAisle({ + uuid: 'temp-aisle', + points: [ + tempPoints[0], + { + uuid: 'temp-point', + position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z], + layer: activeLayer + } + ], + type: { + typeName: 'Aisle', + material: 'default', + aisleType: aisleType, + color: Constants.aisleConfig.defaultColor, + width: Constants.aisleConfig.width + } + }); + } + } else if (tempAisle !== null) { + setTempAisle(null); + } + }); + + useEffect(() => { + setTempAisle(null); + }, [toolMode, toggleView, tempPoints.length, aisleType]); + + if (!tempAisle) return null; + + const renderAisle = () => { + switch (aisleType) { + case 'solid-aisle': + return ; + case 'dashed-aisle': + return ; + default: + return null; + } + }; + + return ( + + {renderAisle()} + + ); +} + +export default ReferenceAisle; + + +function SolidAisle({ aisle }: { readonly aisle: Aisle }) { + const shape = useMemo(() => { + if (aisle.points.length < 2) return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.width || 0.1; + + const direction = new THREE.Vector3().subVectors(end, start).normalize(); + const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + + const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, width / 2); + const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -width / 2); + const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, width / 2); + const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -width / 2); + + const shape = new THREE.Shape(); + shape.moveTo(leftStart.x, leftStart.z); + shape.lineTo(leftEnd.x, leftEnd.z); + shape.lineTo(rightEnd.x, rightEnd.z); + shape.lineTo(rightStart.x, rightStart.z); + shape.closePath(); + + return shape; + }, [aisle]); + + if (!shape) return null; + + return ( + + + + + + ); +} + +function DashedAisle({ aisle }: { readonly aisle: Aisle }) { + const shapes = useMemo(() => { + if (aisle.points.length < 2) return []; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.width || 0.1; + const dashLength = 0.5; + const gapLength = 0.3; + + const direction = new THREE.Vector3().subVectors(end, start).normalize(); + const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + + const totalLength = new THREE.Vector3().subVectors(end, start).length(); + const segmentCount = Math.floor(totalLength / (dashLength + gapLength)); + + const shapes = []; + const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); + + for (let i = 0; i < segmentCount; i++) { + const segmentStart = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * (dashLength + gapLength)); + const segmentEnd = new THREE.Vector3().copy(segmentStart).addScaledVector(directionNormalized, dashLength); + + const leftStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, width / 2); + const rightStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, -width / 2); + const leftEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, width / 2); + const rightEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, -width / 2); + + const shape = new THREE.Shape(); + shape.moveTo(leftStart.x, leftStart.z); + shape.lineTo(leftEnd.x, leftEnd.z); + shape.lineTo(rightEnd.x, rightEnd.z); + shape.lineTo(rightStart.x, rightStart.z); + shape.closePath(); + + shapes.push(shape); + } + + return shapes; + }, [aisle]); + + if (shapes.length === 0) return null; + + return ( + + {shapes.map((shape, index) => ( + + + + ))} + + ); +} diff --git a/app/src/modules/builder/aisle/aislesGroup.tsx b/app/src/modules/builder/aisle/aislesGroup.tsx new file mode 100644 index 0000000..6639672 --- /dev/null +++ b/app/src/modules/builder/aisle/aislesGroup.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import AisleCreator from './aisleCreator/aisleCreator' +import AisleInstances from './Instances/aisleInstances' + +function AislesGroup() { + + return ( + + <> + + + + + + + + + ) +} + +export default AislesGroup \ No newline at end of file diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index fe1649b..d7af8d4 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -4,18 +4,17 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; import { ThreeEvent, useFrame, useThree } from '@react-three/fiber'; -import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem } from '../../../../../store/builder/store'; +import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore } from '../../../../../store/builder/store'; import { AssetBoundingBox } from '../../functions/assetBoundingBox'; import { CameraControls } from '@react-three/drei'; import { useAssetsStore } from '../../../../../store/builder/useAssetStore'; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSocketStore } from '../../../../../store/builder/store'; import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore'; import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore'; import { useSelectedAsset, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; -function Model({ asset }: { asset: Asset }) { +function Model({ asset }: { readonly asset: Asset }) { const { camera, controls, gl } = useThree(); const { activeTool } = useActiveTool(); const { subModule } = useSubModuleStore(); @@ -46,7 +45,8 @@ function Model({ asset }: { asset: Asset }) { const loadModel = async () => { try { // Check Cache - const cachedModel = THREE.Cache.get(asset.assetId!); + const assetId = asset.assetId; + const cachedModel = THREE.Cache.get(assetId); if (cachedModel) { setGltfScene(cachedModel); calculateBoundingBox(cachedModel.scene); @@ -54,13 +54,13 @@ function Model({ asset }: { asset: Asset }) { } // Check IndexedDB - const indexedDBModel = await retrieveGLTF(asset.assetId!); + const indexedDBModel = await retrieveGLTF(assetId); if (indexedDBModel) { const blobUrl = URL.createObjectURL(indexedDBModel); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); - THREE.Cache.add(asset.assetId!, gltf); + THREE.Cache.add(assetId, gltf); setGltfScene(gltf); calculateBoundingBox(gltf.scene); }, @@ -74,14 +74,22 @@ function Model({ asset }: { asset: Asset }) { } // Fetch from Backend - const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${asset.assetId!}`; - loader.load(modelUrl, async (gltf) => { - const modelBlob = await fetch(modelUrl).then((res) => res.blob()); - await storeGLTF(asset.assetId!, modelBlob); - THREE.Cache.add(asset.assetId!, gltf); - setGltfScene(gltf); - calculateBoundingBox(gltf.scene); - }, + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${assetId}`; + const handleBackendLoad = async (gltf: GLTF) => { + try { + const response = await fetch(modelUrl); + const modelBlob = await response.blob(); + await storeGLTF(assetId, modelBlob); + THREE.Cache.add(assetId, gltf); + setGltfScene(gltf); + calculateBoundingBox(gltf.scene); + } catch (error) { + console.error(`[Backend] Error storing/loading ${asset.modelName}:`, error); + } + }; + loader.load( + modelUrl, + handleBackendLoad, undefined, (error) => { echo.error(`[Backend] Error loading ${asset.modelName}:`); @@ -130,7 +138,7 @@ function Model({ asset }: { asset: Asset }) { true ); (controls as CameraControls).setTarget(center.x, center.y, center.z, true); - (controls as CameraControls).fitToBox(groupRef.current!, true, { + (controls as CameraControls).fitToBox(groupRef.current, true, { cover: true, paddingTop: 5, paddingLeft: 5, @@ -191,6 +199,8 @@ function Model({ asset }: { asset: Asset }) { } } + + const handleContextMenu = (asset: Asset, evt: ThreeEvent) => { if (activeTool === "cursor" && subModule === 'simulations') { if (asset.modelUuid) { @@ -215,7 +225,6 @@ function Model({ asset }: { asset: Asset }) { const canvasRect = canvasElement.getBoundingClientRect(); const relativeX = evt.clientX - canvasRect.left; const relativeY = evt.clientY - canvasRect.top; - setTop(relativeY); setLeft(relativeX); } else { diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index c69252b..3263b90 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -48,6 +48,7 @@ import CalculateAreaGroup from "./groups/calculateAreaGroup"; import LayoutImage from "./layout/layoutImage"; import AssetsGroup from "./asset/assetsGroup"; import { Bvh } from "@react-three/drei"; +import AislesGroup from "./aisle/aislesGroup"; export default function Builder() { const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. @@ -274,7 +275,7 @@ export default function Builder() { - + /> */} + + diff --git a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts index 236905b..86fd13f 100644 --- a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts +++ b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts @@ -28,7 +28,7 @@ export const handleAddEventToProduct = ({ organization: organization, eventDatas: event }).then((data) => { - console.log(data); + // console.log(data); }) if (clearSelectedAsset) { diff --git a/app/src/store/builder/useAisleStore.ts b/app/src/store/builder/useAisleStore.ts new file mode 100644 index 0000000..22bdbd3 --- /dev/null +++ b/app/src/store/builder/useAisleStore.ts @@ -0,0 +1,86 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface AisleStore { + aisles: Aisles; + setAisles: (aisles: Aisles) => void; + addAisle: (aisle: Aisle) => void; + updateAisle: (uuid: string, updated: Partial) => void; + removeAisle: (uuid: string) => void; + setPosition: (pointUuid: string, position: [number, number, number]) => void; + setLayer: (pointUuid: string, layer: number) => void; + setMaterial: (aisleUuid: string, material: string) => void; + setColor: (aisleUuid: string, color: string) => void; + setWidth: (aisleUuid: string, width: number) => void; + getAisleById: (uuid: string) => Aisle | undefined; +} + +export const useAisleStore = create()( + immer((set, get) => ({ + aisles: [], + + setAisles: (aisles) => set((state) => { + state.aisles = aisles; + }), + + addAisle: (aisle) => set((state) => { + state.aisles.push(aisle); + }), + + updateAisle: (uuid, updated) => set((state) => { + const aisle = state.aisles.find((a) => a.uuid === uuid); + if (aisle) { + Object.assign(aisle, updated); + } + }), + + removeAisle: (uuid) => set((state) => { + state.aisles = state.aisles.filter((a) => a.uuid !== uuid); + }), + + setPosition: (pointUuid: string, position: [number, number, number]) => set((state) => { + for (const aisle of state.aisles) { + const point = aisle.points.find(p => p.uuid === pointUuid); + if (point) { + point.position = position; + break; + } + } + }), + + setLayer: (pointUuid: string, layer: number) => set((state) => { + for (const aisle of state.aisles) { + const point = aisle.points.find(p => p.uuid === pointUuid); + if (point) { + point.layer = layer; + break; + } + } + }), + + setMaterial: (aisleUuid: string, material: string) => set((state) => { + const aisle = state.aisles.find(a => a.uuid === aisleUuid); + if (aisle) { + aisle.type.material = material; + } + }), + + setColor: (aisleUuid: string, color: string) => set((state) => { + const aisle = state.aisles.find(a => a.uuid === aisleUuid); + if (aisle) { + aisle.type.color = color; + } + }), + + setWidth: (aisleUuid: string, width: number) => set((state) => { + const aisle = state.aisles.find(a => a.uuid === aisleUuid); + if (aisle) { + aisle.type.width = width; + } + }), + + getAisleById: (uuid) => { + return get().aisles.find((a) => a.uuid === uuid); + }, + })) +); diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index adfdc78..b2409a0 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -28,4 +28,27 @@ interface Asset { } }; -type Assets = Asset[]; \ No newline at end of file +type Assets = Asset[]; + + +interface Point { + uuid: string; + position: [number, number, number]; + layer: number; +} + +interface AisleType { + typeName: 'Aisle'; + material: string; + aisleType: 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle'| 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'; + color: string; + width: number; +} + +interface Aisle { + uuid: string; + points: [Point, Point]; + type: AisleType; +} + +type Aisles = Aisle[]; \ No newline at end of file diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index 5193ee1..c2cb62d 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -158,7 +158,7 @@ export type RoofConfig = { export type AisleConfig = { width: number; height: number; - defaultColor: number; + defaultColor: string; }; export type ZoneConfig = { @@ -345,7 +345,7 @@ export const roofConfig: RoofConfig = { export const aisleConfig: AisleConfig = { width: 0.1, // Width of the aisles height: 0.01, // Height of the aisles - defaultColor: 0xE2AC09, // Default color of the aisles + defaultColor: '#E2AC09', // Default color of the aisles }; export const zoneConfig: ZoneConfig = { -- 2.49.1 From d3048d7ef18823b4e4ad6634fb215a629fa2d79c Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Tue, 27 May 2025 18:16:11 +0530 Subject: [PATCH 08/34] feat: add ComparisonResult and EnergyUsage components with performance metrics and energy usage charts --- app/public/index.html | 47 +-- .../components/icons/ExportCommonIcons.tsx | 56 +++ .../visualization/design/Design.tsx | 25 +- .../components/ui/compareVersion/Compare.tsx | 1 + .../ui/compareVersion/CompareLayOut.tsx | 2 +- .../ui/compareVersion/ComparisonResult.tsx | 74 ++++ .../result-card/EnergyUsage.tsx | 104 +++++ .../result-card/PerformanceResult.tsx | 63 +++ .../widgets/3d/cards/ProductionCapacity.tsx | 8 +- app/src/pages/Project.tsx | 2 + app/src/styles/layout/compareLayout.scss | 383 +++++++++++++++++- app/src/styles/layout/compareLayoutPopUp.scss | 2 + app/src/styles/layout/sidebar.scss | 3 +- app/src/styles/pages/realTimeViz.scss | 7 +- 14 files changed, 733 insertions(+), 44 deletions(-) create mode 100644 app/src/components/ui/compareVersion/ComparisonResult.tsx create mode 100644 app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx create mode 100644 app/src/components/ui/compareVersion/result-card/PerformanceResult.tsx diff --git a/app/public/index.html b/app/public/index.html index d05ca9d..22359c2 100644 --- a/app/public/index.html +++ b/app/public/index.html @@ -1,24 +1,19 @@ - - - - - - - - - - - Dwinzo (beta) - - - -
-
- - - + + + \ No newline at end of file diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index b259666..039a0a9 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -1279,3 +1279,59 @@ export const FinishEditIcon = () => { ); }; + +export const PerformanceIcon = () => { + return ( + + + + + + + + + + ); +}; + +export const GreenTickIcon = () => { + return ( + + + + + ); +}; diff --git a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx index a70c887..0f0e0da 100644 --- a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx +++ b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx @@ -115,16 +115,21 @@ const Design = () => {
- + {selectedChartId ? ( + + ) : ( + "No Preview" + )}
diff --git a/app/src/components/ui/compareVersion/Compare.tsx b/app/src/components/ui/compareVersion/Compare.tsx index f3d0b0b..93127b5 100644 --- a/app/src/components/ui/compareVersion/Compare.tsx +++ b/app/src/components/ui/compareVersion/Compare.tsx @@ -70,6 +70,7 @@ const ComparePopUp: React.FC = ({ onClose }) => { Save this version and proceed.
+
); }; diff --git a/app/src/components/ui/compareVersion/CompareLayOut.tsx b/app/src/components/ui/compareVersion/CompareLayOut.tsx index 193dfb2..b857c13 100644 --- a/app/src/components/ui/compareVersion/CompareLayOut.tsx +++ b/app/src/components/ui/compareVersion/CompareLayOut.tsx @@ -20,7 +20,7 @@ interface CompareLayoutProps { const CompareLayOut: React.FC = ({ dummyLayouts }) => { const { products } = useProductStore(); - console.log('products: ', products); + console.log("products: ", products); const [width, setWidth] = useState("50vw"); const [isResizing, setIsResizing] = useState(false); const [showLayoutDropdown, setShowLayoutDropdown] = useState(false); diff --git a/app/src/components/ui/compareVersion/ComparisonResult.tsx b/app/src/components/ui/compareVersion/ComparisonResult.tsx new file mode 100644 index 0000000..619738f --- /dev/null +++ b/app/src/components/ui/compareVersion/ComparisonResult.tsx @@ -0,0 +1,74 @@ +import React from "react"; +import PerformanceResult from "./result-card/PerformanceResult"; +import EnergyUsage from "./result-card/EnergyUsage"; + +const ComparisonResult = () => { + return ( +
+
Performance Comparison
+
+ +
+

Throughput (units/hr)

+
+
+
Layout 1
+
500/ hr
+
+
+
Layout 2
+
550/ hr
+
+
+
+
+
+
+
Cycle Time
+
+
+
Layout 1
+
120 Sec
+
+ ↑19.6% +
+
+
+
Layout 2
+
110 Sec
+
+ ↑19.6%1.6% +
+
+
+
+
+
+
Overall Downtime
+
+
+
Total down time
+
(Simulation 1)
+
+
+
17
+
mins
+
+
+
+ +
+
Overall Scrap Rate
+
+
Layout 1
+
Total scrap produced by
+
2.7 ton
+
+
+ +
+
+ ); +}; + +export default ComparisonResult; diff --git a/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx b/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx new file mode 100644 index 0000000..37f7478 --- /dev/null +++ b/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import { Line } from "react-chartjs-2"; +import { + Chart as ChartJS, + LineElement, + PointElement, + CategoryScale, + LinearScale, + Tooltip, + Legend, +} from "chart.js"; + +ChartJS.register( + LineElement, + PointElement, + CategoryScale, + LinearScale, + Tooltip, + Legend +); + +const EnergyUsage = () => { + const data = { + labels: ["Mon", "Tue", "Wed", "Thu", "Fri"], + datasets: [ + { + label: "Simulation 1", + data: [400, 600, 450, 1000, 1000], + borderColor: "#6a0dad", + fill: false, + tension: 0.5, // More curved line + pointRadius: 0, // Remove point indicators + }, + { + label: "Simulation 2", + data: [300, 500, 700, 950, 1100], + borderColor: "#b19cd9", + fill: false, + tension: 0.5, + pointRadius: 0, + }, + ], + }; + + const options = { + responsive: true, + plugins: { + legend: { + display: false, // Hide legend + }, + tooltip: { + enabled: false, // Hide tooltips + }, + }, + scales: { + x: { + display: false, // Hide x-axis + grid: { + display: false, + }, + }, + y: { + display: false, // Hide y-axis + grid: { + display: false, + }, + }, + }, + }; + + return ( +
+
+

Energy Usage

+

+ 2500 kWh +

+
+ +
+
+
+
+
Simulation 1
+
98%
+
+
+
+
+
+
Simulation 2
+
97%
+
+
+
+ +
+ +
+
+ ); +}; + +export default EnergyUsage; diff --git a/app/src/components/ui/compareVersion/result-card/PerformanceResult.tsx b/app/src/components/ui/compareVersion/result-card/PerformanceResult.tsx new file mode 100644 index 0000000..f21d573 --- /dev/null +++ b/app/src/components/ui/compareVersion/result-card/PerformanceResult.tsx @@ -0,0 +1,63 @@ +import React from "react"; +import { + GreenTickIcon, + PerformanceIcon, + TickIcon, +} from "../../../icons/ExportCommonIcons"; + +const PerformanceResult = () => { + return ( +
+
+
+ +
+
Performance result
+
+ +
+
+
+
+ Success rate{" "} + + + +
+
98%
+
+
Environmental impact
+
+ +
+
+
Waste generation
+
+
I
+
0.5%
+
+
+ +
+
Risk 
management
+
+
I
+
0.1%
+
+
+ +
+
+
I
+
0.5%
+
+
+
+
+ +
Simulation 1
+
+ ); +}; + +export default PerformanceResult; diff --git a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx index 324f53c..8e3d817 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx @@ -195,10 +195,9 @@ const ProductionCapacity: React.FC = ({ } }, [chartMeasurements, chartDuration, widgetName]); - useEffect(() => { }, [rotation]); + useEffect(() => {}, [rotation]); return ( - = ({ }} >
setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} style={{ diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 2ab193e..a5f1c73 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -40,6 +40,7 @@ import VersionSaved from "../components/layout/sidebarRight/versionHisory/Versio import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import { useProductStore } from "../store/simulation/useProductStore"; import ThreadChat from "../components/ui/collaboration/ThreadChat"; +import ComparisonResult from "../components/ui/compareVersion/ComparisonResult"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -180,6 +181,7 @@ const Project: React.FC = () => { />
+ {true && } )} diff --git a/app/src/styles/layout/compareLayout.scss b/app/src/styles/layout/compareLayout.scss index bee1ab8..f897f07 100644 --- a/app/src/styles/layout/compareLayout.scss +++ b/app/src/styles/layout/compareLayout.scss @@ -189,8 +189,242 @@ } } } + + + } +.compare-result-container { + display: flex; + flex-direction: column; + gap: 6px; + position: fixed; + bottom: 40px; + width: 100%; + min-height: 200px; + z-index: 10; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + padding: 18px 8px; + + .header { + width: fit-content; + background-color: var(--background-color-solid); + color: var(--background-color-accent); + padding: 6px 10px; + border-radius: 6px; + } + + .compare-result-wrapper { + display: flex; + gap: 12px; + + .comparisionCard { + position: relative; + flex: 1; + width: auto; + max-height: 200px; + background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: 12px; + padding: 8px 12px; + overflow: hidden; + } + + .performanceResult-wrapper { + min-width: 328px; + flex: 0; + position: relative; + padding-right: 65px; + + .header { + + display: flex; + gap: 12px; + align-items: center; + } + + .metrics-container { + display: flex; + gap: 12px; + height: 100%; + + .metrics-left { + display: flex; + flex-direction: column; + justify-content: space-around; + height: 100%; + + .metric { + .metric-label { + display: flex; + align-items: center; + gap: 6px; + + span { + display: flex; + } + } + + .metric-value { + padding-top: 6px; + font-size: var(--font-size-xlarge); + color: var(--background-color-accent); + font-weight: 600; + } + } + + .label { + padding-bottom: 68px; + } + } + + .metrics-right { + height: fit-content; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(2, 1fr); + + gap: 2px; + overflow: visible; + + margin: auto 0; + + .metric-wrapper { + position: relative; + width: 64px; + height: 50px; + overflow: visible; // allow content like labels to overflow + + &:nth-child(1) { + &::after { + + content: ""; + position: absolute; + + top: -100%; + left: 50%; + width: 100%; // Required for visible shape + height: 40px; + background-color: #B7B7C6; + + // Custom polygon shape (adjust if needed) + clip-path: polygon(96% 52%, 96% 54%, 45% 53%, 3% 100%, 0 100%, 42% 52%); + + + z-index: 0; // Behind any inner content + } + } + + // Optional: content above the shape + >* { + position: relative; + z-index: 1; + } + } + + + .metric-label { + position: absolute; + top: 0px; + left: 0%; + white-space: nowrap; + + transform: translate(-50%, -50%); + + font-size: 10px; + z-index: 1; + } + + .metric-wrapper { + + &:nth-child(1) { + .metric-label { + top: -57%; + left: 220%; + } + } + + &:nth-child(2) { + .metric-label { + white-space: normal; + width: 50px; + // top: -50%; + left: 230%; + } + } + } + + .metric { + width: 100%; + height: 100%; + position: relative; + display: flex; + justify-content: center; + align-items: center; + + &::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + background: var(--background-color, wheat); + clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); + filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); + // backdrop-filter: blur(20px); + // filter: drop-shadow(30px 10px 4px #4444dd); + z-index: 0; + } + + // Content stays above the shape + >* { + position: relative; + z-index: 1; + } + } + + + .metric-wrapper:nth-child(2) { + grid-column-start: 1; + grid-row-start: 2; + } + + .metric-wrapper:nth-child(3) { + grid-row: span 2 / span 2; + grid-column-start: 2; + grid-row-start: 1; + margin-top: 40%; + left: -16px; + position: relative; + } + } + + + } + + .simulation-tag { + + background: var(--background-color-button); + + color: var(--icon-default-color-active); + position: absolute; + bottom: 0; + right: 0; + padding: 10px 5px; + border-radius: 12px 0 0 0; + } + } + + } +} + + + + @keyframes slideInFromRight { from { transform: translateX(100%); @@ -210,4 +444,151 @@ // transition: padding 0.3s ease; // } -// } \ No newline at end of file +// } + +.energy-usage { + position: relative; + + .energy-usage-wrapper { + h4 { + font-weight: 600; + } + + .value { + padding-top: 25px; + font-size: var(--font-size-xxxlarge); + color: var(--background-color-accent); + } + } + + .simulation-details { + position: absolute; + bottom: 12px; + right: 12px; + + .simulation-wrapper { + display: flex; + align-items: center; + gap: 6px; + + .icon { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: var(--background-color-accent); + } + } + } + + .chart { + width: 90%; + position: absolute; + top: 10px; + left: 0; + } +} + +.throughPutCard-container { + + .layers-wrapper { + padding: 20px 10px; + height: 100%; + width: 100%; + display: flex; + justify-content: space-between; + + .layer-wrapper { + display: flex; + flex-direction: column; + + &:last-child { + justify-content: end; + } + } + } + + .chart { + height: 90%; + position: absolute; + bottom: 0; + left: 0; + } +} + +.cycle-time-container { + .cycle-main { + display: flex; + justify-content: space-between; + height: 100%; + + .layers-wrapper { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + + .layers { + display: flex; + flex-direction: column; + gap: 4px; + + .layer-name { + color: var(--background-color-accent); + } + + .layer-time { + font-size: var(--font-size-large); + } + + .layer-profit { + color: #14CA44; + text-align: end; + + span { + color: #14CA44; + } + } + } + } + } +} + +.overallDowntime-container { + .totalDownTime { + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + border-radius: 12px; + width: fit-content; + display: flex; + justify-content: space-between; + align-items: center; + gap: 20px; + padding: 8px 10px; + margin: 44px 0; + + .totalDownTime-right { + display: flex; + flex-direction: column; + gap: 6px; + } + + .totalDownTime-left { + display: flex; + gap: 6px; + + .value { + font-size: var(--font-size-xlarge); + color: var(--background-color-button); + } + } + } +} + +.overallScrapRate { + .overallScrapRate-value { + display: flex; + flex-direction: column; + gap: 6px; + margin: 40px 0; + } +} \ No newline at end of file diff --git a/app/src/styles/layout/compareLayoutPopUp.scss b/app/src/styles/layout/compareLayoutPopUp.scss index 5182cb6..48820a1 100644 --- a/app/src/styles/layout/compareLayoutPopUp.scss +++ b/app/src/styles/layout/compareLayoutPopUp.scss @@ -202,6 +202,8 @@ gap: 6px; } } + + } diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 9d114e0..7c07772 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -221,7 +221,7 @@ padding: 13px 5px; background: var(--background-color-secondary); border-radius: #{$border-radius-medium}; - + box-shadow:var(--box-shadow-light); display: flex; justify-content: space-between; @@ -922,6 +922,7 @@ .display-element { width: 100%; height: 150px; + @include flex-center; background: var(--background-color); backdrop-filter: blur(20px); border-radius: 5px; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 53e3193..e8628ec 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -69,7 +69,7 @@ pointer-events: all; transition: all 0.3s linear; - &.bottom{ + &.bottom { bottom: var(--bottomWidth); } @@ -121,7 +121,8 @@ .zone-container.visualization-playing { bottom: 74px; - &.bottom{ + + &.bottom { bottom: var(--bottomWidth); } } @@ -612,7 +613,9 @@ top: 18px; right: 5px; transform: translate(0px, 0); + overflow: hidden; background: var(--background-color); + backdrop-filter: blur(20px); z-index: 10; display: flex; -- 2.49.1 From 3f3e6d4f149c11744ddfaa762ce1c65822f2d828 Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Wed, 28 May 2025 09:54:16 +0530 Subject: [PATCH 09/34] feat: enhance ComparisonResult component with chart integration and layout adjustments --- .../ui/compareVersion/ComparisonResult.tsx | 80 ++++++++++++++++--- app/src/styles/layout/compareLayout.scss | 78 ++++++++++++------ 2 files changed, 120 insertions(+), 38 deletions(-) diff --git a/app/src/components/ui/compareVersion/ComparisonResult.tsx b/app/src/components/ui/compareVersion/ComparisonResult.tsx index 619738f..031fc1a 100644 --- a/app/src/components/ui/compareVersion/ComparisonResult.tsx +++ b/app/src/components/ui/compareVersion/ComparisonResult.tsx @@ -1,8 +1,52 @@ -import React from "react"; +import React, { useMemo } from "react"; import PerformanceResult from "./result-card/PerformanceResult"; import EnergyUsage from "./result-card/EnergyUsage"; +import { Bar } from "react-chartjs-2"; const ComparisonResult = () => { + const defaultData = { + labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], + datasets: [ + { + label: "Dataset", + data: [12, 19, 3, 5, 2, 3], + backgroundColor: ["#6f42c1"], + borderColor: "#b392f0", + borderWidth: 1, + }, + ], + }; + + // Memoize Chart Options + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + }, + legend: { + display: false, + }, + }, + scales: { + x: { + display: false, // Hide x-axis + grid: { + display: false, + }, + }, + y: { + display: false, // Hide y-axis + grid: { + display: false, + }, + }, + }, + }), + [] + ); return (
Performance Comparison
@@ -45,24 +89,34 @@ const ComparisonResult = () => {
Overall Downtime
-
-
-
Total down time
-
(Simulation 1)
-
-
-
17
-
mins
+
+
+
+
Total down time
+
(Simulation 1)
+
+
+
17
+
mins
+
+
Overall Scrap Rate
-
-
Layout 1
-
Total scrap produced by
-
2.7 ton
+
+
+
Layout 1
+
+ Total scrap produced by +
+
2.7 ton
+
+
+ +
diff --git a/app/src/styles/layout/compareLayout.scss b/app/src/styles/layout/compareLayout.scss index f897f07..eabc4e7 100644 --- a/app/src/styles/layout/compareLayout.scss +++ b/app/src/styles/layout/compareLayout.scss @@ -554,41 +554,69 @@ } .overallDowntime-container { - .totalDownTime { - background: var(--background-color-secondary); - backdrop-filter: blur(20px); - border-radius: 12px; - width: fit-content; + .totalDownTime-wrapper { display: flex; - justify-content: space-between; - align-items: center; - gap: 20px; - padding: 8px 10px; - margin: 44px 0; - .totalDownTime-right { + .totalDownTime { + width: 70%; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + border-radius: 12px; + display: flex; - flex-direction: column; - gap: 6px; + justify-content: space-between; + align-items: center; + gap: 20px; + padding: 8px 10px; + margin: 44px 0; + + .totalDownTime-right { + display: flex; + flex-direction: column; + gap: 6px; + } + + .totalDownTime-left { + display: flex; + align-items: center; + gap: 6px; + + .value { + font-size: var(--font-size-xlarge); + color: var(--background-color-button); + } + } } - .totalDownTime-left { - display: flex; - gap: 6px; - - .value { - font-size: var(--font-size-xlarge); - color: var(--background-color-button); - } + .chart { + width: 30%; + position: relative; } } } .overallScrapRate { - .overallScrapRate-value { + .overallScrapRate-wrapper { display: flex; - flex-direction: column; - gap: 6px; - margin: 40px 0; + + .overallScrapRate-value { + width: 50%; + display: flex; + flex-direction: column; + gap: 6px; + margin: 40px 0; + + .overallScrapRate-key { + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .chart { + width: 50%; + position: relative; + } } } \ No newline at end of file -- 2.49.1 From cb414f282409247c8ede9db2ded511dbcbda1e68 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 28 May 2025 10:44:19 +0530 Subject: [PATCH 10/34] feat: enhance aisle management with new properties and types --- .../layout/sidebarRight/SideBarRight.tsx | 33 +++-- .../properties/AisleProperties.tsx | 140 ++++++++++-------- .../Instances/instance/aisleInstance.tsx | 5 + .../instance/aisleTypes/dashedAisle.tsx | 4 +- .../instance/aisleTypes/dottedAisle.tsx | 58 ++++++++ .../instance/aisleTypes/solidAisle.tsx | 4 +- .../aisle/aisleCreator/aisleCreator.tsx | 55 ++----- .../aisle/aisleCreator/referenceAisle.tsx | 76 ++++++++-- app/src/store/builder/useAisleStore.ts | 16 +- app/src/store/builder/useBuilderStore.ts | 42 ++++++ app/src/types/builderTypes.d.ts | 11 +- 11 files changed, 296 insertions(+), 148 deletions(-) create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx create mode 100644 app/src/store/builder/useBuilderStore.ts diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 10de581..44199bc 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -16,6 +16,7 @@ import Simulations from "./simulation/Simulations"; import useVersionHistoryStore, { useSaveVersion, useSelectedFloorItem, + useToolMode, } from "../../../store/builder/store"; import { useSelectedEventData, @@ -26,10 +27,12 @@ import AsstePropertiies from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; import EventProperties from "./properties/eventProperties/EventProperties"; import VersionHistory from "./versionHisory/VersionHistory"; +import AisleProperties from "./properties/AisleProperties"; const SideBarRight: React.FC = () => { const { activeModule } = useModuleStore(); const { toggleUIRight } = useToggleStore(); + const { toolMode } = useToolMode(); const { subModule, setSubModule } = useSubModuleStore(); const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventData } = useSelectedEventData(); @@ -62,9 +65,8 @@ const SideBarRight: React.FC = () => { return (
{toggleUIRight && ( @@ -74,9 +76,8 @@ const SideBarRight: React.FC = () => { {activeModule !== "simulation" && (
-
+
+
+
+
+
+
diff --git a/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx b/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx index 37f7478..93e80ec 100644 --- a/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx +++ b/app/src/components/ui/compareVersion/result-card/EnergyUsage.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useMemo } from "react"; import { Line } from "react-chartjs-2"; import { Chart as ChartJS, @@ -42,31 +42,35 @@ const EnergyUsage = () => { ], }; - const options = { - responsive: true, - plugins: { - legend: { - display: false, // Hide legend - }, - tooltip: { - enabled: false, // Hide tooltips - }, - }, - scales: { - x: { - display: false, // Hide x-axis - grid: { + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + }, + legend: { display: false, }, }, - y: { - display: false, // Hide y-axis - grid: { - display: false, + scales: { + x: { + display: false, // Hide x-axis + grid: { + display: false, + }, + }, + y: { + display: false, // Hide y-axis + grid: { + display: false, + }, }, }, - }, - }; + }), + [] + ); return (
diff --git a/app/src/styles/layout/compareLayout.scss b/app/src/styles/layout/compareLayout.scss index eabc4e7..b78772c 100644 --- a/app/src/styles/layout/compareLayout.scss +++ b/app/src/styles/layout/compareLayout.scss @@ -481,10 +481,13 @@ } .chart { + height: 100%; width: 90%; position: absolute; top: 10px; left: 0; + margin-bottom: 20px; + padding: 20px; } } @@ -556,6 +559,9 @@ .overallDowntime-container { .totalDownTime-wrapper { display: flex; + height: auto; + width: 100%; + justify-content: space-between; .totalDownTime { width: 70%; @@ -589,8 +595,33 @@ } .chart { + height: auto; width: 30%; + width: 20px; position: relative; + perspective: 800px; + /* Enables 3D viewing */ + + + .vertical-chart { + height: 100%; + display: flex; + flex-direction: column-reverse; + gap: 6px; + + .layout2 { + transform-style: preserve-3d; + transform: rotateX(15deg); + /* 3D tilt */ + height: 20%; + background-color: #F3A60D; + } + + .layout1 { + height: 80%; + background-color: #6F42C1; + } + } } } } -- 2.49.1 From 0b9e894341bb2e6c29e38e417178a654bee0e40c Mon Sep 17 00:00:00 2001 From: Vishnu Date: Wed, 28 May 2025 11:02:12 +0530 Subject: [PATCH 12/34] feat: refactor compareLayout styles for improved layout and responsiveness --- .../ui/compareVersion/CompareLayOut.tsx | 22 +- app/src/styles/layout/compareLayout.scss | 1073 ++++++++--------- 2 files changed, 521 insertions(+), 574 deletions(-) diff --git a/app/src/components/ui/compareVersion/CompareLayOut.tsx b/app/src/components/ui/compareVersion/CompareLayOut.tsx index b857c13..00480bc 100644 --- a/app/src/components/ui/compareVersion/CompareLayOut.tsx +++ b/app/src/components/ui/compareVersion/CompareLayOut.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from "react"; +import React, { useState, useRef, useEffect, Suspense } from "react"; import { CompareLayoutIcon, LayoutIcon, @@ -9,6 +9,7 @@ import Search from "../inputs/Search"; import OuterClick from "../../../utils/outerClick"; import RegularDropDown from "../inputs/RegularDropDown"; import { useProductStore } from "../../../store/simulation/useProductStore"; +import Scene from "../../../modules/scene/scene"; interface Layout { id: number; @@ -90,6 +91,7 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => { window.removeEventListener("mouseup", handleMouseUp); document.body.classList.remove("resizing-active"); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isResizing]); // Maintain proportional width on window resize @@ -120,10 +122,22 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => { ref={wrapperRef} style={{ width }} > +
-
- -
+ {selectedLayout && ( +
+ {/* + + */} +
+ )} {width !== "0px" && !selectedLayout && ( // Show only if no layout selected diff --git a/app/src/styles/layout/compareLayout.scss b/app/src/styles/layout/compareLayout.scss index b78772c..e17f227 100644 --- a/app/src/styles/layout/compareLayout.scss +++ b/app/src/styles/layout/compareLayout.scss @@ -2,652 +2,585 @@ @use "../abstracts/mixins" as *; .initial-selectLayout-wrapper { - position: fixed; - top: 100px; - left: 40px; - z-index: 10; + position: fixed; + top: 100px; + left: 40px; + z-index: 10; - .regularDropdown-container { - background: var(--background-color); - } + .regularDropdown-container { + background: var(--background-color); + } } .compareLayOut-wrapper { - position: fixed; - top: 0; - right: 0; - z-index: 2; - height: 100vh; + position: fixed; + top: 0; + right: 0; + z-index: 2; + height: 100vh; + background: var(--background-color); + backdrop-filter: blur(20px); + display: flex; + justify-content: center; + align-items: center; + animation: slideInFromRight 0.4s ease-out forwards; + user-select: none; + + .selectLayout-wrapper { + position: absolute; + top: 100px; + right: 40px; + + .regularDropdown-container { + background: var(--background-color); + } + } + + .resizer { + width: 32px; + height: 32px; + @include flex-center; + padding: 6px; + position: absolute; + top: 50%; + left: 0; + transform: translate(-50%, -50%); background: var(--background-color); backdrop-filter: blur(20px); + box-shadow: $box-shadow-heavy; + border-radius: 50%; + cursor: ew-resize; + transition: transform 0.1s ease; + z-index: 10; + } + + .chooseLayout-container { + width: 100%; + height: 100%; display: flex; justify-content: center; align-items: center; - animation: slideInFromRight 0.4s ease-out forwards; - user-select: none; + position: relative; + overflow: hidden; - - .selectLayout-wrapper { - - position: absolute; - top: 100px; - right: 40px; - - .regularDropdown-container { - background: var(--background-color); - } + .compare-layout-canvas-container { + position: absolute; + height: 100vh; + width: 100vw; + top: 0; + right: 0; } - .chooseLayout-container { + .chooseLayout-wrapper { + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 20px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + max-width: 80%; + text-align: center; + position: relative; + + .icon { width: 100%; - height: 100%; + margin-bottom: 15px; + text-align: center; + + svg { + width: 100%; + } + } + + .value { + margin-bottom: 15px; + font-size: var(--font-size-small); + font-weight: 500; + color: var(--text-primary); + } + + button { + display: block; + margin: 0 auto; + padding: 8px 16px; + background: var(--background-color-button); + color: var(--icon-default-color-active); + border: none; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + transform: translateY(-1px); + } + } + + .displayLayouts-container { + max-width: 170px; + height: auto; + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 6px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + position: absolute; + right: 0; + top: 100%; + transform: translate(50%, -10px); display: flex; - justify-content: center; - align-items: center; - position: relative; - - .resizer { - width: 32px; - height: 32px; - @include flex-center; - padding: 6px; - position: absolute; - top: 50%; - left: 0; - transform: translate(-50%, -50%); - background: var(--background-color); - backdrop-filter: blur(20px); - box-shadow: $box-shadow-heavy; - border-radius: 50%; - cursor: ew-resize; - transition: transform 0.1s ease; - z-index: 10; - - + flex-direction: column; + gap: 6px; + .header { + text-align: left; + padding-top: 6px; + padding-left: 6px; } - .chooseLayout-wrapper { - background: var(--background-color); - backdrop-filter: blur(20px); - padding: 20px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - max-width: 80%; - text-align: center; - position: relative; + .search-wrapper { + padding: 6px 0; - .icon { - width: 100%; - margin-bottom: 15px; - text-align: center; - - svg { - - width: 100%; - } - - } - - .value { - margin-bottom: 15px; - font-size: var(--font-size-small); - font-weight: 500; - color: var(--text-primary); - } - - button { - display: block; - margin: 0 auto; - padding: 8px 16px; - background: var(--background-color-button); - color: var(--icon-default-color-active); - border: none; - border-radius: 4px; - cursor: pointer; - transition: all 0.2s ease; - - &:hover { - - transform: translateY(-1px); - } - - - - } - - .displayLayouts-container { - max-width: 170px; - height: auto; - background: var(--background-color); - backdrop-filter: blur(20px); - padding: 6px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - position: absolute; - right: 0; - top: 100%; - transform: translate(50%, -10px); - display: flex; - flex-direction: column; - gap: 6px; - - .header { - text-align: left; - padding-top: 6px; - padding-left: 6px; - } - - .search-wrapper { - padding: 6px 0; - - .search-container { - padding: 0; - border-radius: 6px; - } - } - - .layouts-container { - .layout { - - padding: 6px 0; - } - - .layout-wrapper { - display: flex; - align-items: center; - gap: 6px; - cursor: pointer; - padding: 0 10px; - background: none; - width: 100%; - - &:hover { - background-color: var(--highlight-text-color) !important; - border-radius: 4px; - - .layout { - color: var(--text-button-color) !important; - - } - - svg { - - path { - - fill: var(--text-button-color) !important; - } - } - - .layout { - - color: var(--background-color-accent); - } - } - } - } - } + .search-container { + padding: 0; + border-radius: 6px; + } } + + .layouts-container { + .layout { + padding: 6px 0; + } + + .layout-wrapper { + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; + padding: 0 10px; + background: none; + width: 100%; + + &:hover { + background-color: var(--highlight-text-color) !important; + border-radius: 4px; + + .layout { + color: var(--text-button-color) !important; + } + + svg { + path { + fill: var(--text-button-color) !important; + } + } + } + } + } + } } - - - + } } .compare-result-container { - display: flex; - flex-direction: column; - gap: 6px; - position: fixed; - bottom: 40px; - width: 100%; - min-height: 200px; - z-index: 10; - background: var(--background-color-secondary); - backdrop-filter: blur(20px); - padding: 18px 8px; + display: flex; + flex-direction: column; + gap: 6px; + position: fixed; + bottom: 40px; + width: 100%; + min-height: 200px; + z-index: 10; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + padding: 18px 8px; - .header { - width: fit-content; - background-color: var(--background-color-solid); - color: var(--background-color-accent); - padding: 6px 10px; - border-radius: 6px; + .header { + width: fit-content; + background-color: var(--background-color-solid); + color: var(--background-color-accent); + padding: 6px 10px; + border-radius: 6px; + } + + .compare-result-wrapper { + display: flex; + gap: 12px; + + .comparisionCard { + position: relative; + flex: 1; + width: auto; + max-height: 200px; + background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: 12px; + padding: 8px 12px; + overflow: hidden; } - .compare-result-wrapper { + .performanceResult-wrapper { + min-width: 328px; + flex: 0; + position: relative; + padding-right: 65px; + + .header { display: flex; gap: 12px; + align-items: center; + } - .comparisionCard { - position: relative; - flex: 1; - width: auto; - max-height: 200px; - background: var(--background-color); - outline: 1px solid var(--border-color); - outline-offset: -1px; - border-radius: 12px; - padding: 8px 12px; - overflow: hidden; + .metrics-container { + display: flex; + gap: 12px; + height: 100%; + + .metrics-left { + display: flex; + flex-direction: column; + justify-content: space-around; + height: 100%; + + .metric { + .metric-label { + display: flex; + align-items: center; + gap: 6px; + + span { + display: flex; + } + } + .metric-value { + padding-top: 6px; + font-size: var(--font-size-xlarge); + color: var(--background-color-accent); + font-weight: 600; + } + } + + .label { + padding-bottom: 68px; + } } - .performanceResult-wrapper { - min-width: 328px; - flex: 0; + .metrics-right { + height: fit-content; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(2, 1fr); + + gap: 2px; + overflow: visible; + + margin: auto 0; + + .metric-wrapper { position: relative; - padding-right: 65px; + width: 64px; + height: 50px; + overflow: visible; // allow content like labels to overflow - .header { - - display: flex; - gap: 12px; - align-items: center; - } - - .metrics-container { - display: flex; - gap: 12px; - height: 100%; - - .metrics-left { - display: flex; - flex-direction: column; - justify-content: space-around; - height: 100%; - - .metric { - .metric-label { - display: flex; - align-items: center; - gap: 6px; - - span { - display: flex; - } - } - - .metric-value { - padding-top: 6px; - font-size: var(--font-size-xlarge); - color: var(--background-color-accent); - font-weight: 600; - } - } - - .label { - padding-bottom: 68px; - } - } - - .metrics-right { - height: fit-content; - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-template-rows: repeat(2, 1fr); - - gap: 2px; - overflow: visible; - - margin: auto 0; - - .metric-wrapper { - position: relative; - width: 64px; - height: 50px; - overflow: visible; // allow content like labels to overflow - - &:nth-child(1) { - &::after { - - content: ""; - position: absolute; - - top: -100%; - left: 50%; - width: 100%; // Required for visible shape - height: 40px; - background-color: #B7B7C6; - - // Custom polygon shape (adjust if needed) - clip-path: polygon(96% 52%, 96% 54%, 45% 53%, 3% 100%, 0 100%, 42% 52%); - - - z-index: 0; // Behind any inner content - } - } - - // Optional: content above the shape - >* { - position: relative; - z-index: 1; - } - } - - - .metric-label { - position: absolute; - top: 0px; - left: 0%; - white-space: nowrap; - - transform: translate(-50%, -50%); - - font-size: 10px; - z-index: 1; - } - - .metric-wrapper { - - &:nth-child(1) { - .metric-label { - top: -57%; - left: 220%; - } - } - - &:nth-child(2) { - .metric-label { - white-space: normal; - width: 50px; - // top: -50%; - left: 230%; - } - } - } - - .metric { - width: 100%; - height: 100%; - position: relative; - display: flex; - justify-content: center; - align-items: center; - - &::after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - - background: var(--background-color, wheat); - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); - // backdrop-filter: blur(20px); - // filter: drop-shadow(30px 10px 4px #4444dd); - z-index: 0; - } - - // Content stays above the shape - >* { - position: relative; - z-index: 1; - } - } - - - .metric-wrapper:nth-child(2) { - grid-column-start: 1; - grid-row-start: 2; - } - - .metric-wrapper:nth-child(3) { - grid-row: span 2 / span 2; - grid-column-start: 2; - grid-row-start: 1; - margin-top: 40%; - left: -16px; - position: relative; - } - } - - - } - - .simulation-tag { - - background: var(--background-color-button); - - color: var(--icon-default-color-active); + &:nth-child(1) { + .metric-label { + top: -57%; + left: 220%; + } + &::after { + content: ""; position: absolute; - bottom: 0; - right: 0; - padding: 10px 5px; - border-radius: 12px 0 0 0; + + top: -100%; + left: 50%; + width: 100%; // Required for visible shape + height: 40px; + background-color: #b7b7c6; + + // Custom polygon shape (adjust if needed) + clip-path: polygon( + 96% 52%, + 96% 54%, + 45% 53%, + 3% 100%, + 0 100%, + 42% 52% + ); + + z-index: 0; // Behind any inner content + } } + + // Optional: content above the shape + > * { + position: relative; + z-index: 1; + } + + &:nth-child(2) { + grid-column-start: 1; + grid-row-start: 2; + .metric-label { + white-space: normal; + width: 50px; + left: 230%; + } + } + &:nth-child(3) { + grid-row: span 2 / span 2; + grid-column-start: 2; + grid-row-start: 1; + margin-top: 40%; + left: -16px; + position: relative; + } + } + + .metric-label { + position: absolute; + top: 0px; + left: 0%; + white-space: nowrap; + + transform: translate(-50%, -50%); + + font-size: 10px; + z-index: 1; + } + + .metric { + width: 100%; + height: 100%; + position: relative; + display: flex; + justify-content: center; + align-items: center; + + &::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + background: var(--background-color, wheat); + clip-path: polygon( + 25% 0%, + 75% 0%, + 100% 50%, + 75% 100%, + 25% 100%, + 0% 50% + ); + filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); + + z-index: 0; + } + + // Content stays above the shape + > * { + position: relative; + z-index: 1; + } + } } + } + .simulation-tag { + background: var(--background-color-button); + + color: var(--icon-default-color-active); + position: absolute; + bottom: 0; + right: 0; + padding: 10px 5px; + border-radius: 12px 0 0 0; + } } + } } - - - @keyframes slideInFromRight { - from { - transform: translateX(100%); - opacity: 0; - } + from { + transform: translateX(100%); + opacity: 0; + } - to { - transform: translateX(0); - opacity: 1; - } + to { + transform: translateX(0); + opacity: 1; + } } - -// body.compare-layout-open { -// main { -// padding-right: 10px; - -// transition: padding 0.3s ease; -// } -// } - .energy-usage { - position: relative; + position: relative; - .energy-usage-wrapper { - h4 { - font-weight: 600; - } - - .value { - padding-top: 25px; - font-size: var(--font-size-xxxlarge); - color: var(--background-color-accent); - } + .energy-usage-wrapper { + h4 { + font-weight: 600; } - .simulation-details { - position: absolute; - bottom: 12px; - right: 12px; - - .simulation-wrapper { - display: flex; - align-items: center; - gap: 6px; - - .icon { - width: 20px; - height: 20px; - border-radius: 50%; - background-color: var(--background-color-accent); - } - } + .value { + padding-top: 25px; + font-size: var(--font-size-xxxlarge); + color: var(--background-color-accent); } + } - .chart { - height: 100%; - width: 90%; - position: absolute; - top: 10px; - left: 0; - margin-bottom: 20px; - padding: 20px; + .simulation-details { + position: absolute; + bottom: 12px; + right: 12px; + + .simulation-wrapper { + display: flex; + align-items: center; + gap: 6px; + + .icon { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: var(--background-color-accent); + } } + } + + .chart { + width: 90%; + position: absolute; + top: 10px; + left: 0; + } } .throughPutCard-container { + .layers-wrapper { + padding: 20px 10px; + height: 100%; + width: 100%; + display: flex; + justify-content: space-between; - .layers-wrapper { - padding: 20px 10px; - height: 100%; - width: 100%; - display: flex; - justify-content: space-between; + .layer-wrapper { + display: flex; + flex-direction: column; - .layer-wrapper { - display: flex; - flex-direction: column; - - &:last-child { - justify-content: end; - } - } + &:last-child { + justify-content: end; + } } + } - .chart { - height: 90%; - position: absolute; - bottom: 0; - left: 0; - } + .chart { + height: 90%; + position: absolute; + bottom: 0; + left: 0; + } } .cycle-time-container { - .cycle-main { + .cycle-main { + display: flex; + justify-content: space-between; + height: 100%; + + .layers-wrapper { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + + .layers { display: flex; - justify-content: space-between; - height: 100%; + flex-direction: column; + gap: 4px; - .layers-wrapper { - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - - .layers { - display: flex; - flex-direction: column; - gap: 4px; - - .layer-name { - color: var(--background-color-accent); - } - - .layer-time { - font-size: var(--font-size-large); - } - - .layer-profit { - color: #14CA44; - text-align: end; - - span { - color: #14CA44; - } - } - } + .layer-name { + color: var(--background-color-accent); } + + .layer-time { + font-size: var(--font-size-large); + } + + .layer-profit { + color: #14ca44; + text-align: end; + + span { + color: #14ca44; + } + } + } } + } } .overallDowntime-container { - .totalDownTime-wrapper { + .totalDownTime-wrapper { + display: flex; + + .totalDownTime { + width: 70%; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + border-radius: 12px; + + display: flex; + justify-content: space-between; + align-items: center; + gap: 20px; + padding: 8px 10px; + margin: 44px 0; + + .totalDownTime-right { display: flex; - height: auto; - width: 100%; - justify-content: space-between; + flex-direction: column; + gap: 6px; + } - .totalDownTime { - width: 70%; - background: var(--background-color-secondary); - backdrop-filter: blur(20px); - border-radius: 12px; + .totalDownTime-left { + display: flex; + align-items: center; + gap: 6px; - display: flex; - justify-content: space-between; - align-items: center; - gap: 20px; - padding: 8px 10px; - margin: 44px 0; - - .totalDownTime-right { - display: flex; - flex-direction: column; - gap: 6px; - } - - .totalDownTime-left { - display: flex; - align-items: center; - gap: 6px; - - .value { - font-size: var(--font-size-xlarge); - color: var(--background-color-button); - } - } - } - - .chart { - height: auto; - width: 30%; - width: 20px; - position: relative; - perspective: 800px; - /* Enables 3D viewing */ - - - .vertical-chart { - height: 100%; - display: flex; - flex-direction: column-reverse; - gap: 6px; - - .layout2 { - transform-style: preserve-3d; - transform: rotateX(15deg); - /* 3D tilt */ - height: 20%; - background-color: #F3A60D; - } - - .layout1 { - height: 80%; - background-color: #6F42C1; - } - } + .value { + font-size: var(--font-size-xlarge); + color: var(--background-color-button); } + } } + + .chart { + width: 30%; + position: relative; + } + } } .overallScrapRate { - .overallScrapRate-wrapper { - display: flex; + .overallScrapRate-wrapper { + display: flex; - .overallScrapRate-value { - width: 50%; - display: flex; - flex-direction: column; - gap: 6px; - margin: 40px 0; + .overallScrapRate-value { + width: 50%; + display: flex; + flex-direction: column; + gap: 6px; + margin: 40px 0; - .overallScrapRate-key { - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } - - .chart { - width: 50%; - position: relative; - } + .overallScrapRate-key { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } -} \ No newline at end of file + + .chart { + width: 50%; + position: relative; + } + } +} -- 2.49.1 From 5c37d407332cdc056bf1a657faea99f69d6e6dba Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 28 May 2025 15:26:08 +0530 Subject: [PATCH 13/34] Refactor material store usage to integrate with scene context - Removed direct usage of useMaterialStore in various components and replaced it with useSceneContext to access materialStore. - Introduced SceneProvider to encapsulate materialStore creation and provide it through context. - Updated components such as CompareLayOut, Scene, and various action handlers to utilize the new context structure. - Cleaned up imports and removed unnecessary console logs. - Adjusted Project component to conditionally render ComparisonResult based on a boolean flag. --- .../ui/compareVersion/CompareLayOut.tsx | 7 +- app/src/modules/scene/scene.tsx | 39 +- app/src/modules/scene/sceneContext.tsx | 29 ++ .../actionHandler/useDefaultHandler.ts | 5 +- .../conveyor/actionHandler/useDelayHandler.ts | 5 +- .../actionHandler/useDespawnHandler.ts | 5 +- .../conveyor/actionHandler/useSpawnHandler.ts | 5 +- .../conveyor/actionHandler/useSwapHandler.ts | 5 +- .../actionHandler/useProcessHandler.ts | 5 +- .../actionHandler/usePickAndPlaceHandler.ts | 5 +- .../actionHandler/useRetrieveHandler.ts | 5 +- .../actionHandler/useStoreHandler.ts | 5 +- .../vehicle/actionHandler/useTravelHandler.ts | 5 +- .../analysis/throughPut/throughPutData.tsx | 9 +- .../conveyorInstance/conveyorInstance.tsx | 5 +- .../materialCollitionDetector.tsx | 6 +- .../materials/instances/materialInstances.tsx | 5 +- .../simulation/materials/materials.tsx | 5 +- .../armInstance/roboticArmInstance.tsx | 7 +- .../triggerHandler/useTriggerHandler.ts | 5 +- .../instances/instance/vehicleInstance.tsx | 5 +- app/src/pages/Project.tsx | 2 +- app/src/store/simulation/useMaterialStore.ts | 405 +++++++++--------- 23 files changed, 315 insertions(+), 264 deletions(-) create mode 100644 app/src/modules/scene/sceneContext.tsx diff --git a/app/src/components/ui/compareVersion/CompareLayOut.tsx b/app/src/components/ui/compareVersion/CompareLayOut.tsx index 00480bc..ec47167 100644 --- a/app/src/components/ui/compareVersion/CompareLayOut.tsx +++ b/app/src/components/ui/compareVersion/CompareLayOut.tsx @@ -21,7 +21,6 @@ interface CompareLayoutProps { const CompareLayOut: React.FC = ({ dummyLayouts }) => { const { products } = useProductStore(); - console.log("products: ", products); const [width, setWidth] = useState("50vw"); const [isResizing, setIsResizing] = useState(false); const [showLayoutDropdown, setShowLayoutDropdown] = useState(false); @@ -133,9 +132,9 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => {
{selectedLayout && (
- {/* + - */} +
)} @@ -156,7 +155,7 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => { {showLayoutDropdown && (
Layouts
- {}} /> + { }} />
{products.map((layout) => (
- {true && } + {false && } )} diff --git a/app/src/store/simulation/useMaterialStore.ts b/app/src/store/simulation/useMaterialStore.ts index 31f5726..123ebb0 100644 --- a/app/src/store/simulation/useMaterialStore.ts +++ b/app/src/store/simulation/useMaterialStore.ts @@ -54,226 +54,231 @@ type MaterialsStore = { getMaterialHistory: () => MaterialHistorySchema; }; -export const useMaterialStore = create()( - immer((set, get) => ({ - materials: [], - materialHistory: [], +export const createMaterialStore = () => { + return create()( + immer((set, get) => ({ + materials: [], + materialHistory: [], - addMaterial: (material) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - state.materials.push(material); - }); - return updatedMaterial; - }, + addMaterial: (material) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + state.materials.push(material); + }); + return updatedMaterial; + }, - removeMaterial: (materialId) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - state.materials = state.materials.filter(m => m.materialId !== materialId); - updatedMaterial = JSON.parse(JSON.stringify(material)); + removeMaterial: (materialId) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + state.materials = state.materials.filter(m => m.materialId !== materialId); + updatedMaterial = JSON.parse(JSON.stringify(material)); - state.materialHistory.push({ - material, - removedAt: new Date().toISOString() - }); - } - }); - return updatedMaterial; - }, + state.materialHistory.push({ + material, + removedAt: new Date().toISOString() + }); + } + }); + return updatedMaterial; + }, - clearMaterials: () => { - set((state) => { - state.materials = []; - }); - }, + clearMaterials: () => { + set((state) => { + state.materials = []; + }); + }, - updateMaterial: (materialId, updates) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - Object.assign(material, updates); - updatedMaterial = JSON.parse(JSON.stringify(material)); - } - }); - return updatedMaterial; - }, + updateMaterial: (materialId, updates) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + Object.assign(material, updates); + updatedMaterial = JSON.parse(JSON.stringify(material)); + } + }); + return updatedMaterial; + }, - setPreviousLocation: (materialId, location) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.previous = location; - updatedMaterial = JSON.parse(JSON.stringify(material)); - } - }); - return updatedMaterial; - }, + setPreviousLocation: (materialId, location) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.previous = location; + updatedMaterial = JSON.parse(JSON.stringify(material)); + } + }); + return updatedMaterial; + }, - setCurrentLocation: (materialId, location) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.current = location; - updatedMaterial = JSON.parse(JSON.stringify(material)); - } - }); - return updatedMaterial; - }, + setCurrentLocation: (materialId, location) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.current = location; + updatedMaterial = JSON.parse(JSON.stringify(material)); + } + }); + return updatedMaterial; + }, - setNextLocation: (materialId, location) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.next = location; - updatedMaterial = JSON.parse(JSON.stringify(material)); - } - }); - return updatedMaterial; - }, + setNextLocation: (materialId, location) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.next = location; + updatedMaterial = JSON.parse(JSON.stringify(material)); + } + }); + return updatedMaterial; + }, - setMaterial: (materialId, materialType) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.materialType = materialType; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setMaterial: (materialId, materialType) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.materialType = materialType; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setStartTime: (materialId, startTime) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.startTime = startTime - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setStartTime: (materialId, startTime) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.startTime = startTime + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setEndTime: (materialId, endTime) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.endTime = endTime; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setEndTime: (materialId, endTime) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.endTime = endTime; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setCost: (materialId, cost) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.cost = cost; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setCost: (materialId, cost) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.cost = cost; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setWeight: (materialId, weight) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.weight = weight; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setWeight: (materialId, weight) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.weight = weight; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setIsActive: (materialId, isActive) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.isActive = isActive; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setIsActive: (materialId, isActive) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.isActive = isActive; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setIsVisible: (materialId, isVisible) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.isVisible = isVisible; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setIsVisible: (materialId, isVisible) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.isVisible = isVisible; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setIsPaused: (materialId, isPaused) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.isPaused = isPaused; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setIsPaused: (materialId, isPaused) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.isPaused = isPaused; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - setIsRendered: (materialId, isRendered) => { - let updatedMaterial: MaterialSchema | undefined; - set((state) => { - const material = state.materials.find(m => m.materialId === materialId); - if (material) { - material.isRendered = isRendered; - updatedMaterial = JSON.parse(JSON.stringify(material)); - }; - }); - return updatedMaterial; - }, + setIsRendered: (materialId, isRendered) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + material.isRendered = isRendered; + updatedMaterial = JSON.parse(JSON.stringify(material)); + }; + }); + return updatedMaterial; + }, - getMaterialById: (materialId) => { - return get().materials.find(m => m.materialId === materialId); - }, + getMaterialById: (materialId) => { + return get().materials.find(m => m.materialId === materialId); + }, - getMaterialsByCurrentModelUuid: (currentModelUuid) => { - return get().materials.filter(m => m.current?.modelUuid === currentModelUuid); - }, + getMaterialsByCurrentModelUuid: (currentModelUuid) => { + return get().materials.filter(m => m.current?.modelUuid === currentModelUuid); + }, - getMaterialByCurrentPointUuid: (currentPointlUuid) => { - return get().materials.find(m => m.current?.pointUuid === currentPointlUuid); - }, + getMaterialByCurrentPointUuid: (currentPointlUuid) => { + return get().materials.find(m => m.current?.pointUuid === currentPointlUuid); + }, - getMaterialsByPoint: (pointUuid) => { - return get().materials.filter(m => - m.current?.pointUuid === pointUuid || - m.next?.pointUuid === pointUuid - ); - }, + getMaterialsByPoint: (pointUuid) => { + return get().materials.filter(m => + m.current?.pointUuid === pointUuid || + m.next?.pointUuid === pointUuid + ); + }, - getMaterialsByModel: (modelUuid) => { - return get().materials.filter(m => - m.current?.modelUuid === modelUuid || - m.next?.modelUuid === modelUuid - ); - }, + getMaterialsByModel: (modelUuid) => { + return get().materials.filter(m => + m.current?.modelUuid === modelUuid || + m.next?.modelUuid === modelUuid + ); + }, - getMaterialHistory: () => { - return get().materialHistory; - }, - })) -); \ No newline at end of file + getMaterialHistory: () => { + return get().materialHistory; + }, + })) + ) +} + + +export type MaterialStoreType = ReturnType; \ No newline at end of file -- 2.49.1 From 5e58606f8fbced4c6596d5119cda5c5416e70796 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 28 May 2025 16:24:08 +0530 Subject: [PATCH 14/34] Refactor store creation for Conveyor, Machine, Storage Unit, and Vehicle - Changed the store creation functions to `createConveyorStore`, `createMachineStore`, `createStorageUnitStore`, and `createVehicleStore` for better clarity and consistency. - Updated the internal state management methods to maintain functionality while improving readability. - Ensured that all stores now return their respective types for better type safety. --- .../mechanics/storageMechanics.tsx | 5 +- .../mechanics/vehicleMechanics.tsx | 34 +- .../aisle/Instances/aisleInstances.tsx | 2 +- app/src/modules/builder/aisle/aislesGroup.tsx | 1 - app/src/modules/scene/sceneContext.tsx | 28 +- .../conveyor/actionHandler/useSpawnHandler.ts | 5 +- .../actionHandler/useProcessHandler.ts | 5 +- .../actionHandler/usePickAndPlaceHandler.ts | 5 +- .../actionHandler/useRetrieveHandler.ts | 11 +- .../actionHandler/useStoreHandler.ts | 5 +- .../vehicle/actionHandler/useTravelHandler.ts | 5 +- .../analysis/throughPut/throughPutData.tsx | 17 +- .../eventManager/useConveyorEventManager.ts | 5 +- .../conveyorInstance/conveyorInstance.tsx | 5 +- .../conveyor/instances/conveyorInstances.tsx | 5 +- .../eventManager/useMachineEventManager.ts | 5 +- .../instances/animator/machineAnimator.tsx | 6 +- .../machineInstance/machineInstance.tsx | 7 +- .../machine/instances/machineInstances.tsx | 5 +- .../instances/animator/materialAnimator.tsx | 5 +- .../modules/simulation/products/products.tsx | 19 +- .../eventManager/useArmBotEventManager.ts | 5 +- .../instances/animator/roboticArmAnimator.tsx | 2 +- .../armInstance/roboticArmInstance.tsx | 15 +- .../instances/roboticArmInstances.tsx | 5 +- .../simulation/roboticArm/roboticArm.tsx | 5 +- .../checkActiveRoboticArmsInSubsequence.ts | 5 +- .../simulation/spatialUI/arm/armBotUI.tsx | 5 +- .../spatialUI/vehicle/vehicleUI.tsx | 5 +- .../instances/storageUnitInstances.tsx | 7 +- .../triggerHandler/useTriggerHandler.ts | 17 +- .../eventManager/useVehicleEventManager.ts | 5 +- .../instances/animator/vehicleAnimator.tsx | 7 +- .../instances/instance/vehicleInstance.tsx | 16 +- .../vehicle/instances/vehicleInstances.tsx | 5 +- .../modules/simulation/vehicle/vehicles.tsx | 5 +- app/src/store/simulation/useArmBotStore.ts | 310 +++++++------- app/src/store/simulation/useConveyorStore.ts | 192 ++++----- app/src/store/simulation/useMachineStore.ts | 254 ++++++------ .../store/simulation/useStorageUnitStore.ts | 310 +++++++------- app/src/store/simulation/useVehicleStore.ts | 380 +++++++++--------- 41 files changed, 884 insertions(+), 856 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 202daa7..4ea5687 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -6,18 +6,19 @@ import StorageAction from "../actions/StorageAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; -import { useStorageUnitStore } from "../../../../../../store/simulation/useStorageUnitStore"; import { useSelectedAction, useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import * as THREE from 'three'; +import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; function StorageMechanics() { + const { storageUnitStore } = useSceneContext(); const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); const { getPointByUuid, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); - const { setCurrentMaterials, clearCurrentMaterials, updateCurrentLoad, getStorageUnitById } = useStorageUnitStore(); + const { setCurrentMaterials, clearCurrentMaterials, updateCurrentLoad, getStorageUnitById } = storageUnitStore(); const email = localStorage.getItem('email') const organization = (email!.split("@")[1]).split(".")[0]; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 2894e33..8e61dcf 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -13,21 +13,17 @@ import { useProductStore } from "../../../../../../store/simulation/useProductSt import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; -import { useVehicleStore } from "../../../../../../store/simulation/useVehicleStore"; +import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; function VehicleMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "travel">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState< - VehiclePointSchema | undefined - >(); + const { vehicleStore } = useSceneContext(); + const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = - useProductStore(); + const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); - const { getVehicleById } = useVehicleStore(); + const { getVehicleById } = vehicleStore(); const email = localStorage.getItem("email"); const organization = email!.split("@")[1].split(".")[0]; @@ -255,7 +251,7 @@ function VehicleMechanics() { defaultValue={"0.5"} max={10} activeOption="m/s" - onClick={() => {}} + onClick={() => { }} onChange={handleSpeedChange} />
@@ -294,14 +290,14 @@ function VehicleMechanics() { onChange: handleUnloadDurationChange, }} clearPoints={handleClearPoints} - // pickPoint={{ - // value: currentPickPoint, - // onChange: handlePickPointChange, - // }} - // unloadPoint={{ - // value: currentUnloadPoint, - // onChange: handleUnloadPointChange, - // }} + // pickPoint={{ + // value: currentPickPoint, + // onChange: handlePickPointChange, + // }} + // unloadPoint={{ + // value: currentUnloadPoint, + // onChange: handleUnloadPointChange, + // }} /> )}
diff --git a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx index 1ec9308..efcbf58 100644 --- a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx +++ b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx @@ -6,7 +6,7 @@ function AisleInstances() { const { aisles } = useAisleStore(); useEffect(() => { - console.log('aisles: ', aisles); + // console.log('aisles: ', aisles); }, [aisles]); return ( diff --git a/app/src/modules/builder/aisle/aislesGroup.tsx b/app/src/modules/builder/aisle/aislesGroup.tsx index 6639672..f163bed 100644 --- a/app/src/modules/builder/aisle/aislesGroup.tsx +++ b/app/src/modules/builder/aisle/aislesGroup.tsx @@ -1,4 +1,3 @@ -import React from 'react' import AisleCreator from './aisleCreator/aisleCreator' import AisleInstances from './Instances/aisleInstances' diff --git a/app/src/modules/scene/sceneContext.tsx b/app/src/modules/scene/sceneContext.tsx index fe8f244..1eea293 100644 --- a/app/src/modules/scene/sceneContext.tsx +++ b/app/src/modules/scene/sceneContext.tsx @@ -1,16 +1,40 @@ import { createContext, useContext, useMemo } from 'react'; import { createMaterialStore, MaterialStoreType } from '../../store/simulation/useMaterialStore'; +import { createArmBotStore, ArmBotStoreType } from '../../store/simulation/useArmBotStore'; +import { createMachineStore, MachineStoreType } from '../../store/simulation/useMachineStore'; +import { createConveyorStore, ConveyorStoreType } from '../../store/simulation/useConveyorStore'; +import { createVehicleStore, VehicleStoreType } from '../../store/simulation/useVehicleStore'; +import { createStorageUnitStore, StorageUnitStoreType } from '../../store/simulation/useStorageUnitStore'; type SceneContextValue = { materialStore: MaterialStoreType; - // Add other stores here if needed + armBotStore: ArmBotStoreType; + machineStore: MachineStoreType; + conveyorStore: ConveyorStoreType; + vehicleStore: VehicleStoreType; + storageUnitStore: StorageUnitStoreType; }; const SceneContext = createContext(null); export function SceneProvider({ children }: { readonly children: React.ReactNode }) { const materialStore = useMemo(() => createMaterialStore(), []); - const contextValue = useMemo(() => ({ materialStore }), [materialStore]); + const armBotStore = useMemo(() => createArmBotStore(), []); + const machineStore = useMemo(() => createMachineStore(), []); + const conveyorStore = useMemo(() => createConveyorStore(), []); + const vehicleStore = useMemo(() => createVehicleStore(), []); + const storageUnitStore = useMemo(() => createStorageUnitStore(), []); + + const contextValue = useMemo(() => ( + { + materialStore, + armBotStore, + machineStore, + conveyorStore, + vehicleStore, + storageUnitStore + } + ), [materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]); return ( diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts index 3b186c0..a2efcfb 100644 --- a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts +++ b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts @@ -4,7 +4,6 @@ import { useFrame } from "@react-three/fiber"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { usePlayButtonStore, useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore"; -import { useConveyorStore } from "../../../../../store/simulation/useConveyorStore"; import { useSceneContext } from "../../../../scene/sceneContext"; interface SpawnInstance { @@ -23,9 +22,9 @@ interface SpawnInstance { } export function useSpawnHandler() { - const { materialStore } = useSceneContext(); + const { materialStore, conveyorStore } = useSceneContext(); const { addMaterial } = materialStore(); - const { getConveyorById } = useConveyorStore(); + const { getConveyorById } = conveyorStore(); const { getModelUuidByActionUuid, getPointUuidByActionUuid } = useProductStore(); const { isPlaying } = usePlayButtonStore(); const { isPaused } = usePauseButtonStore(); diff --git a/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts index 9f536d5..c7dc10b 100644 --- a/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts +++ b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts @@ -1,13 +1,12 @@ import { useCallback } from "react"; -import { useMachineStore } from "../../../../../store/simulation/useMachineStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; export function useProcessHandler() { - const { materialStore } = useSceneContext(); + const { materialStore, machineStore } = useSceneContext(); const { getMaterialById, setMaterial } = materialStore(); - const { addCurrentAction } = useMachineStore(); + const { addCurrentAction } = machineStore(); const { getModelUuidByActionUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); diff --git a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts index ec0cabd..9f53c80 100644 --- a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts +++ b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts @@ -1,13 +1,12 @@ import { useCallback } from "react"; -import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; export function usePickAndPlaceHandler() { - const { materialStore } = useSceneContext(); + const { materialStore, armBotStore } = useSceneContext(); const { getMaterialById } = materialStore(); - const { addCurrentAction } = useArmBotStore(); + const { addCurrentAction } = armBotStore(); const { getModelUuidByActionUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts index c0981b6..3f4f9a8 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts @@ -2,20 +2,17 @@ import { useCallback, useState, useEffect, useRef } from "react"; import { useFrame } from "@react-three/fiber"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; -import { useStorageUnitStore } from "../../../../../store/simulation/useStorageUnitStore"; -import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore"; -import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore"; import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore"; import { useSceneContext } from "../../../../scene/sceneContext"; export function useRetrieveHandler() { - const { materialStore } = useSceneContext(); + const { materialStore, armBotStore, vehicleStore, storageUnitStore } = useSceneContext(); const { addMaterial } = materialStore(); const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = useProductStore(); - const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = useStorageUnitStore(); - const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = useVehicleStore(); + const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore(); + const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore(); const { selectedProduct } = useSelectedProduct(); - const { getArmBotById, addCurrentAction } = useArmBotStore(); + const { getArmBotById, addCurrentAction } = armBotStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); const { isPaused } = usePauseButtonStore(); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts index d9d356f..61e1f94 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts @@ -1,13 +1,12 @@ import { useCallback } from "react"; -import { useStorageUnitStore } from "../../../../../store/simulation/useStorageUnitStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; export function useStoreHandler() { - const { materialStore } = useSceneContext(); + const { materialStore, storageUnitStore } = useSceneContext(); const { getMaterialById, removeMaterial, setEndTime } = materialStore(); - const { addCurrentMaterial, updateCurrentLoad } = useStorageUnitStore(); + const { addCurrentMaterial, updateCurrentLoad } = storageUnitStore(); const { getModelUuidByActionUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); diff --git a/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts index bb96cb8..69c18b5 100644 --- a/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts +++ b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts @@ -1,15 +1,14 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; -import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore"; import { useSceneContext } from "../../../../scene/sceneContext"; export function useTravelHandler() { - const { materialStore } = useSceneContext(); + const { materialStore, vehicleStore } = useSceneContext(); const { getMaterialById } = materialStore(); const { getModelUuidByActionUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - const { incrementVehicleLoad, addCurrentMaterial } = useVehicleStore(); + const { incrementVehicleLoad, addCurrentMaterial } = vehicleStore(); const travelLogStatus = (materialUuid: string, status: string) => { echo.info(`${materialUuid}, ${status}`); diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index 84b4c35..6fde8db 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -2,24 +2,19 @@ import { useEffect } from 'react'; import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useProductStore } from '../../../../store/simulation/useProductStore'; import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; -import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; import { useMachineCount, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store'; -import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; -import { useMachineStore } from '../../../../store/simulation/useMachineStore'; -import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; -import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; import { useSceneContext } from '../../../scene/sceneContext'; export default function ThroughPutData() { + const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); const { selectedProduct } = useSelectedProduct(); const { products, getProductById } = useProductStore(); - const { armBots } = useArmBotStore(); - const { vehicles } = useVehicleStore(); - const { machines } = useMachineStore(); - const { conveyors } = useConveyorStore(); - const { storageUnits } = useStorageUnitStore(); - const { materialStore } = useSceneContext(); + const { armBots } = armBotStore(); + const { vehicles } = vehicleStore(); + const { machines } = machineStore(); + const { conveyors } = conveyorStore(); + const { storageUnits } = storageUnitStore(); const { materialHistory } = materialStore(); const { machineCount, setMachineCount } = useMachineCount(); const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); diff --git a/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts b/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts index 4870613..34407c9 100644 --- a/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts +++ b/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; import { useFrame } from '@react-three/fiber'; -import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore'; +import { useSceneContext } from '../../../scene/sceneContext'; type ConveyorCallback = { conveyorId: string; @@ -9,7 +9,8 @@ type ConveyorCallback = { }; export function useConveyorEventManager() { - const { getConveyorById } = useConveyorStore(); + const { conveyorStore } = useSceneContext(); + const { getConveyorById } = conveyorStore(); const callbacksRef = useRef([]); const isMonitoringRef = useRef(false); const { isPlaying } = usePlayButtonStore(); diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx index fb17b36..69061d6 100644 --- a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx @@ -1,5 +1,4 @@ import { useEffect } from 'react' -import { useConveyorStore } from '../../../../../store/simulation/useConveyorStore'; import { useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; @@ -9,10 +8,10 @@ import { useSceneContext } from '../../../../scene/sceneContext'; function ConveyorInstance({ conveyor }: { conveyor: ConveyorStatus }) { const { getProductById } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - const { materialStore } = useSceneContext(); + const { materialStore, conveyorStore } = useSceneContext(); const { getMaterialsByCurrentModelUuid, materials } = materialStore(); const { isReset } = useResetButtonStore(); - const { setConveyorPaused } = useConveyorStore(); + const { setConveyorPaused } = conveyorStore(); useEffect(() => { const product = getProductById(selectedProduct.productId); diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx index 4bc4252..75557ed 100644 --- a/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx @@ -1,10 +1,11 @@ import React from 'react' import ConveyorInstance from './conveyorInstance/conveyorInstance' -import { useConveyorStore } from '../../../../store/simulation/useConveyorStore' +import { useSceneContext } from '../../../scene/sceneContext'; function ConveyorInstances() { - const { conveyors } = useConveyorStore(); + const { conveyorStore } = useSceneContext(); + const { conveyors } = conveyorStore(); return ( <> diff --git a/app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts b/app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts index 35c6418..66dda67 100644 --- a/app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts +++ b/app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; import { useFrame } from '@react-three/fiber'; -import { useMachineStore } from '../../../../store/simulation/useMachineStore'; import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore'; +import { useSceneContext } from '../../../scene/sceneContext'; type MachineCallback = { machineId: string; @@ -9,7 +9,8 @@ type MachineCallback = { }; export function useMachineEventManager() { - const { getMachineById } = useMachineStore(); + const { machineStore } = useSceneContext(); + const { getMachineById } = machineStore(); const callbacksRef = useRef([]); const isMonitoringRef = useRef(false); const { isPlaying } = usePlayButtonStore(); diff --git a/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx b/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx index 8f1505f..d510784 100644 --- a/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx +++ b/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx @@ -1,7 +1,6 @@ import { useEffect, useRef } from 'react'; -import { useMachineStore } from '../../../../../store/simulation/useMachineStore'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; - +import { useSceneContext } from '../../../../scene/sceneContext'; interface MachineAnimatorProps { currentPhase: string; @@ -19,7 +18,8 @@ const MachineAnimator = ({ currentPhase, handleCallBack, processingTime, machine const animationFrameId = useRef(null); const pauseTimeRef = useRef(null); const { isPaused } = usePauseButtonStore(); - const { removeCurrentAction } = useMachineStore(); + const { machineStore } = useSceneContext(); + const { removeCurrentAction } = machineStore(); const { isReset } = useResetButtonStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx index ae8c97f..da8ea2f 100644 --- a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -1,12 +1,12 @@ import { useEffect, useRef, useState } from 'react' -import { useMachineStore } from '../../../../../store/simulation/useMachineStore'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import MachineAnimator from '../animator/machineAnimator'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; +import { useSceneContext } from '../../../../scene/sceneContext'; -function MachineInstance({ machineDetail }: { machineDetail: MachineStatus }) { +function MachineInstance({ machineDetail }: { readonly machineDetail: MachineStatus }) { const [currentPhase, setCurrentPhase] = useState('idle'); let isIncrememtable = useRef(true); const idleTimeRef = useRef(0); @@ -16,7 +16,8 @@ function MachineInstance({ machineDetail }: { machineDetail: MachineStatus }) { const isSpeedRef = useRef(0); const isPausedRef = useRef(false); const { isPlaying } = usePlayButtonStore(); - const { machines, setMachineState, setMachineActive, incrementIdleTime, incrementActiveTime, resetTime } = useMachineStore(); + const { machineStore } = useSceneContext(); + const { machines, setMachineState, setMachineActive, incrementIdleTime, incrementActiveTime, resetTime } = machineStore(); const { selectedProduct } = useSelectedProduct(); const { getActionByUuid } = useProductStore(); const { triggerPointActions } = useTriggerHandler(); diff --git a/app/src/modules/simulation/machine/instances/machineInstances.tsx b/app/src/modules/simulation/machine/instances/machineInstances.tsx index e228b01..eac048f 100644 --- a/app/src/modules/simulation/machine/instances/machineInstances.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstances.tsx @@ -1,10 +1,11 @@ import React from "react"; import MachineInstance from "./machineInstance/machineInstance"; -import { useMachineStore } from "../../../../store/simulation/useMachineStore"; import MachineContentUi from "../../ui3d/MachineContentUi"; +import { useSceneContext } from "../../../scene/sceneContext"; function MachineInstances() { - const { machines } = useMachineStore(); + const { machineStore } = useSceneContext(); + const { machines } = machineStore(); return ( <> {machines.map((machine: MachineStatus) => ( diff --git a/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx index 4afe359..5cf20c7 100644 --- a/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx +++ b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from 'react'; import * as THREE from 'three'; import { useFrame, useThree } from '@react-three/fiber'; import { usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useConveyorStore } from '../../../../../store/simulation/useConveyorStore'; +import { useSceneContext } from '../../../../scene/sceneContext'; interface MaterialAnimatorProps { matRef: React.RefObject; @@ -20,7 +20,8 @@ function MaterialAnimator({ const { scene } = useThree(); const [targetPosition, setTargetPosition] = useState(null); const [isAnimating, setIsAnimating] = useState(false); - const { getConveyorById } = useConveyorStore(); + const { conveyorStore } = useSceneContext(); + const { getConveyorById } = conveyorStore(); const animationState = useRef({ startTime: 0, startPosition: new THREE.Vector3(), diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 1ea1b21..49310e2 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -4,21 +4,18 @@ import { useProductStore } from '../../../store/simulation/useProductStore'; import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; import { upsertProductOrEventApi } from '../../../services/simulation/products/UpsertProductOrEventApi'; import { getAllProductsApi } from '../../../services/simulation/products/getallProductsApi'; -import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; -import { useArmBotStore } from '../../../store/simulation/useArmBotStore'; -import { useConveyorStore } from '../../../store/simulation/useConveyorStore'; -import { useMachineStore } from '../../../store/simulation/useMachineStore'; -import { useStorageUnitStore } from '../../../store/simulation/useStorageUnitStore'; import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore'; +import { useSceneContext } from '../../scene/sceneContext'; function Products() { + const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); const { products, getProductById, addProduct, setProducts } = useProductStore(); const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - const { addVehicle, clearvehicles } = useVehicleStore(); - const { addArmBot, clearArmBots } = useArmBotStore(); - const { addMachine, clearMachines } = useMachineStore(); - const { addConveyor, clearConveyors } = useConveyorStore(); - const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = useStorageUnitStore(); + const { addVehicle, clearvehicles } = vehicleStore(); + const { addArmBot, clearArmBots } = armBotStore(); + const { addMachine, clearMachines } = machineStore(); + const { addConveyor, clearConveyors } = conveyorStore(); + const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore(); const { isReset } = useResetButtonStore(); const { isPlaying } = usePlayButtonStore(); @@ -105,7 +102,7 @@ function Products() { addStorageUnit(selectedProduct.productId, event); if (event.point.action.actionType === 'retrieve') { - const storageAction = event.point.action as StorageAction; + const storageAction = event.point.action; const materials = Array.from({ length: storageAction.storageCapacity }, () => ({ materialType: storageAction.materialType || 'Default material', materialId: THREE.MathUtils.generateUUID() diff --git a/app/src/modules/simulation/roboticArm/eventManager/useArmBotEventManager.ts b/app/src/modules/simulation/roboticArm/eventManager/useArmBotEventManager.ts index 59004fa..3f07ea9 100644 --- a/app/src/modules/simulation/roboticArm/eventManager/useArmBotEventManager.ts +++ b/app/src/modules/simulation/roboticArm/eventManager/useArmBotEventManager.ts @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; import { useFrame } from '@react-three/fiber'; -import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore'; +import { useSceneContext } from '../../../scene/sceneContext'; type ArmBotCallback = { armBotId: string; @@ -9,7 +9,8 @@ type ArmBotCallback = { }; export function useArmBotEventManager() { - const { getArmBotById } = useArmBotStore(); + const {armBotStore} = useSceneContext(); + const { getArmBotById } = armBotStore(); const callbacksRef = useRef([]); const isMonitoringRef = useRef(false); const { isPlaying } = usePlayButtonStore(); diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 52213fe..1ad53de 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useFrame, useThree } from '@react-three/fiber'; import * as THREE from 'three'; import { Line, Text } from '@react-three/drei'; diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index ab34ec3..e0c26bc 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import * as THREE from "three"; import { useThree } from "@react-three/fiber"; import IKInstance from '../ikInstance/ikInstance'; @@ -6,15 +6,12 @@ import RoboticArmAnimator from '../animator/roboticArmAnimator'; import MaterialAnimator from '../animator/materialAnimator'; import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb"; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useSceneContext } from '../../../../scene/sceneContext'; -function RoboticArmInstance({ armBot }: {readonly armBot: ArmBotStatus }) { +function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) { const [currentPhase, setCurrentPhase] = useState<(string)>("init"); const [path, setPath] = useState<[number, number, number][]>([]); @@ -28,10 +25,10 @@ function RoboticArmInstance({ armBot }: {readonly armBot: ArmBotStatus }) { const isSpeedRef = useRef(null); let startTime: number; - const { setArmBotActive, setArmBotState, removeCurrentAction, incrementActiveTime, incrementIdleTime } = useArmBotStore(); - const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore(); - const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore(); - const { materialStore } = useSceneContext(); + const { materialStore, armBotStore, vehicleStore, storageUnitStore } = useSceneContext(); + const { setArmBotActive, setArmBotState, removeCurrentAction, incrementActiveTime, incrementIdleTime } = armBotStore(); + const { decrementVehicleLoad, removeLastMaterial } = vehicleStore(); + const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = storageUnitStore(); const { getMaterialById, setIsVisible, setIsPaused } = materialStore(); const { selectedProduct } = useSelectedProduct(); const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore(); diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index f57fbcd..b1295a3 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -1,10 +1,11 @@ +import { useSceneContext } from "../../../scene/sceneContext"; import RoboticArmInstance from "./armInstance/roboticArmInstance"; -import { useArmBotStore } from "../../../../store/simulation/useArmBotStore"; // import RoboticArmContentUi from "../../ui3d/RoboticArmContentUi"; import React from "react"; function RoboticArmInstances() { - const { armBots } = useArmBotStore(); + const {armBotStore} = useSceneContext(); + const { armBots } = armBotStore(); return ( <> diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index ffdb312..1946fce 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,12 +1,13 @@ import { useEffect, useState } from "react"; -import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import RoboticArmInstances from "./instances/roboticArmInstances"; import ArmBotUI from "../spatialUI/arm/armBotUI"; +import { useSceneContext } from "../../scene/sceneContext"; function RoboticArm() { - const { getArmBotById } = useArmBotStore(); + const {armBotStore} = useSceneContext(); + const { getArmBotById } = armBotStore(); const { selectedEventSphere } = useSelectedEventSphere(); const { isPlaying } = usePlayButtonStore(); const [isArmBotSelected, setIsArmBotSelected] = useState(false); diff --git a/app/src/modules/simulation/simulator/functions/checkActiveRoboticArmsInSubsequence.ts b/app/src/modules/simulation/simulator/functions/checkActiveRoboticArmsInSubsequence.ts index 797f836..bfa8bfa 100644 --- a/app/src/modules/simulation/simulator/functions/checkActiveRoboticArmsInSubsequence.ts +++ b/app/src/modules/simulation/simulator/functions/checkActiveRoboticArmsInSubsequence.ts @@ -1,5 +1,5 @@ +import { useSceneContext } from "../../../scene/sceneContext"; import { extractTriggersFromPoint } from "./extractTriggersFromPoint"; -import { useArmBotStore } from "../../../../store/simulation/useArmBotStore"; export function getRoboticArmSequencesInProduct( product: { @@ -80,7 +80,8 @@ export function findRoboticArmSubsequence( // React component/hook that uses the pure functions export function useCheckActiveRoboticArmsInSubsequence() { - const { getArmBotById } = useArmBotStore(); + const {armBotStore} = useSceneContext(); + const { getArmBotById } = armBotStore(); return function (product: { productName: string; diff --git a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx index 0775157..7a835f7 100644 --- a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx +++ b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx @@ -3,7 +3,6 @@ import { useSelectedAction, useSelectedEventSphere, useSelectedProduct } from '. import { useGLTF } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; import { useProductStore } from '../../../../store/simulation/useProductStore'; -import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; import PickDropPoints from './PickDropPoints'; import useDraggableGLTF from './useDraggableGLTF'; import * as THREE from 'three'; @@ -11,6 +10,7 @@ import * as THREE from 'three'; import armPick from "../../../../assets/gltf-glb/ui/arm_ui_pick.glb"; import armDrop from "../../../../assets/gltf-glb/ui/arm_ui_drop.glb"; import { upsertProductOrEventApi } from '../../../../services/simulation/products/UpsertProductOrEventApi'; +import { useSceneContext } from '../../../scene/sceneContext'; type Positions = { pick: [number, number, number]; @@ -24,7 +24,8 @@ const ArmBotUI = () => { const { selectedProduct } = useSelectedProduct(); const { scene } = useThree(); const { selectedAction } = useSelectedAction(); - const { armBots } = useArmBotStore(); + const { armBotStore } = useSceneContext(); + const { armBots } = armBotStore(); const armUiPick = useGLTF(armPick) as any; const armUiDrop = useGLTF(armDrop) as any; diff --git a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx index db55344..c60e7e9 100644 --- a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx @@ -8,13 +8,13 @@ import { useSelectedProduct, useIsRotating, } from "../../../../store/simulation/useSimulationStore"; -import { useVehicleStore } from "../../../../store/simulation/useVehicleStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { DoubleSide, Group, Plane, Vector3 } from "three"; import startPoint from "../../../../assets/gltf-glb/ui/arrow_green.glb"; import startEnd from "../../../../assets/gltf-glb/ui/arrow_red.glb"; +import { useSceneContext } from "../../../scene/sceneContext"; const VehicleUI = () => { const { scene: startScene } = useGLTF(startPoint) as any; @@ -24,7 +24,8 @@ const VehicleUI = () => { const prevMousePos = useRef({ x: 0, y: 0 }); const { selectedEventSphere } = useSelectedEventSphere(); const { selectedProduct } = useSelectedProduct(); - const { vehicles, getVehicleById } = useVehicleStore(); + const { vehicleStore } = useSceneContext(); + const { vehicles, getVehicleById } = vehicleStore(); const { updateEvent } = useProductStore(); const [startPosition, setStartPosition] = useState<[number, number, number]>([ 0, 1, 0, diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx index 29b6ea0..72ad0e9 100644 --- a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx +++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx @@ -1,17 +1,18 @@ import React from 'react' import StorageUnitInstance from './storageUnitInstance/storageUnitInstance' -import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore' import StorageContentUi from '../../ui3d/StorageContentUi'; +import { useSceneContext } from '../../../scene/sceneContext'; function StorageUnitInstances() { - const { storageUnits } = useStorageUnitStore(); + const { storageUnitStore } = useSceneContext(); + const { storageUnits } = storageUnitStore(); return ( <> {storageUnits.map((storageUnit: StorageUnitStatus) => ( - + ))} diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index c01fa0e..8ef5d1a 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -2,31 +2,26 @@ import { useCallback } from 'react'; import { useActionHandler } from '../../actions/useActionHandler'; import { useProductStore } from '../../../../store/simulation/useProductStore'; import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; -import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; -import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; -import { useMachineStore } from '../../../../store/simulation/useMachineStore'; -import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; import { useArmBotEventManager } from '../../roboticArm/eventManager/useArmBotEventManager'; -import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; import { useConveyorEventManager } from '../../conveyor/eventManager/useConveyorEventManager'; import { useVehicleEventManager } from '../../vehicle/eventManager/useVehicleEventManager'; import { useMachineEventManager } from '../../machine/eventManager/useMachineEventManager'; import { useSceneContext } from '../../../scene/sceneContext'; export function useTriggerHandler() { + const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); const { handleAction } = useActionHandler(); const { selectedProduct } = useSelectedProduct(); const { getEventByTriggerUuid, getEventByModelUuid, getActionByUuid, getModelUuidByActionUuid } = useProductStore(); - const { getArmBotById } = useArmBotStore(); - const { getConveyorById } = useConveyorStore(); + const { getArmBotById } = armBotStore(); + const { getConveyorById } = conveyorStore(); const { addArmBotToMonitor } = useArmBotEventManager(); const { addConveyorToMonitor } = useConveyorEventManager(); const { addVehicleToMonitor } = useVehicleEventManager(); const { addMachineToMonitor } = useMachineEventManager(); - const { getVehicleById } = useVehicleStore(); - const { getMachineById } = useMachineStore(); - const { getStorageUnitById } = useStorageUnitStore(); - const { materialStore } = useSceneContext(); + const { getVehicleById } = vehicleStore(); + const { getMachineById } = machineStore(); + const { getStorageUnitById } = storageUnitStore(); const { getMaterialById, setCurrentLocation, setNextLocation, setPreviousLocation, setIsPaused, setIsVisible, setEndTime } = materialStore(); const handleTrigger = (trigger: TriggerSchema, action: Action, materialId?: string) => { diff --git a/app/src/modules/simulation/vehicle/eventManager/useVehicleEventManager.ts b/app/src/modules/simulation/vehicle/eventManager/useVehicleEventManager.ts index 7b2bb08..625beff 100644 --- a/app/src/modules/simulation/vehicle/eventManager/useVehicleEventManager.ts +++ b/app/src/modules/simulation/vehicle/eventManager/useVehicleEventManager.ts @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; import { useFrame } from '@react-three/fiber'; -import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore'; +import { useSceneContext } from '../../../scene/sceneContext'; type VehicleCallback = { vehicleId: string; @@ -9,7 +9,8 @@ type VehicleCallback = { }; export function useVehicleEventManager() { - const { getVehicleById } = useVehicleStore(); + const { vehicleStore } = useSceneContext(); + const { getVehicleById } = vehicleStore(); const callbacksRef = useRef([]); const isMonitoringRef = useRef(false); const { isPlaying } = usePlayButtonStore(); diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 9d51a8d..64501c1 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -3,7 +3,7 @@ import { useFrame, useThree } from '@react-three/fiber'; import * as THREE from 'three'; import { Line } from '@react-three/drei'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; +import { useSceneContext } from '../../../../scene/sceneContext'; interface VehicleAnimatorProps { path: [number, number, number][]; @@ -15,8 +15,9 @@ interface VehicleAnimatorProps { agvDetail: VehicleStatus; } -function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset, startUnloadingProcess }: VehicleAnimatorProps) { - const { getVehicleById } = useVehicleStore(); +function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset, startUnloadingProcess }: Readonly) { + const { vehicleStore } = useSceneContext(); + const { getVehicleById } = vehicleStore(); const { isPaused } = usePauseButtonStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 81a2981..b9339cc 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,13 +1,9 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import VehicleAnimator from '../animator/vehicleAnimator'; import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/builder/store'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; -import { useConveyorStore } from '../../../../../store/simulation/useConveyorStore'; -import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; @@ -17,15 +13,15 @@ import { useSceneContext } from '../../../../scene/sceneContext'; function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) { const { navMesh } = useNavMesh(); const { isPlaying } = usePlayButtonStore(); - const { materialStore } = useSceneContext(); + const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); const { removeMaterial, setEndTime } = materialStore(); - const { getStorageUnitById } = useStorageUnitStore(); - const { getArmBotById } = useArmBotStore(); - const { getConveyorById } = useConveyorStore(); + const { getStorageUnitById } = storageUnitStore(); + const { getArmBotById } = armBotStore(); + const { getConveyorById } = conveyorStore(); const { triggerPointActions } = useTriggerHandler(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = useVehicleStore(); + const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = vehicleStore(); const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 1c7cd51..708a4e1 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,10 +1,11 @@ import React from "react"; import VehicleInstance from "./instance/vehicleInstance"; -import { useVehicleStore } from "../../../../store/simulation/useVehicleStore"; import VehicleContentUi from "../../ui3d/VehicleContentUi"; +import { useSceneContext } from "../../../scene/sceneContext"; function VehicleInstances() { - const { vehicles } = useVehicleStore(); + const { vehicleStore } = useSceneContext(); + const { vehicles } = vehicleStore(); return ( <> diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index b9293cd..9e594a5 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -1,12 +1,13 @@ import { useEffect, useState } from "react"; -import { useVehicleStore } from "../../../store/simulation/useVehicleStore"; import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import VehicleInstances from "./instances/vehicleInstances"; import VehicleUI from "../spatialUI/vehicle/vehicleUI"; +import { useSceneContext } from "../../scene/sceneContext"; function Vehicles() { - const { getVehicleById } = useVehicleStore(); + const { vehicleStore } = useSceneContext(); + const { getVehicleById } = vehicleStore(); const { selectedEventSphere } = useSelectedEventSphere(); const { isPlaying } = usePlayButtonStore(); const [isVehicleSelected, setIsVehicleSelected] = useState(false); diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index 7c4d38b..e05ee2b 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -34,173 +34,177 @@ interface ArmBotStore { getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[]; } -export const useArmBotStore = create()( - immer((set, get) => ({ - armBots: [], +export const createArmBotStore = () => { + return create()( + immer((set, get) => ({ + armBots: [], - addArmBot: (productId, event) => { - set((state) => { - const exists = state.armBots.some(a => a.modelUuid === event.modelUuid); - if (!exists) { - 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); - } - }); - }, - - clearArmBots: () => { - set((state) => { - state.armBots = []; - }); - }, - - addCurrentAction: (modelUuid, actionUuid, materialType, materialId) => { - 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, - materialType: materialType, - materialId: materialId - }; + addArmBot: (productId, event) => { + set((state) => { + const exists = state.armBots.some(a => a.modelUuid === event.modelUuid); + if (!exists) { + state.armBots.push({ + ...event, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + state: 'idle', + }); } - } - }); - }, + }); + }, - removeCurrentAction: (modelUuid) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.currentAction = undefined; - } - }); - }, + removeArmBot: (modelUuid) => { + set((state) => { + state.armBots = state.armBots.filter(a => a.modelUuid !== modelUuid); + }); + }, - 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); - } - }); - }, - - updateStartPoint: (modelUuid, actionUuid, startPoint) => { - 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) { - action.process.startPoint = startPoint; + updateArmBot: (modelUuid, updates) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + Object.assign(armBot, updates); } - } - }); - }, + }); + }, - updateEndPoint: (modelUuid, actionUuid, endPoint) => { - 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) { - action.process.endPoint = endPoint; + clearArmBots: () => { + set((state) => { + state.armBots = []; + }); + }, + + addCurrentAction: (modelUuid, actionUuid, materialType, materialId) => { + 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, + materialType: materialType, + materialId: materialId + }; + } } - } - }); - }, + }); + }, - setArmBotActive: (modelUuid, isActive) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.isActive = isActive; - } - }); - }, + removeCurrentAction: (modelUuid) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.currentAction = undefined; + } + }); + }, - setArmBotState: (modelUuid, newState) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.state = newState; - } - }); - }, + addAction: (modelUuid, action) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.point.actions.push(action); + } + }); + }, - incrementActiveTime: (modelUuid, incrementBy) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.activeTime += incrementBy; - } - }); - }, + 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); + } + }); + }, - incrementIdleTime: (modelUuid, incrementBy) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.idleTime += incrementBy; - } - }); - }, + updateStartPoint: (modelUuid, actionUuid, startPoint) => { + 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) { + action.process.startPoint = startPoint; + } + } + }); + }, - getArmBotById: (modelUuid) => { - return get().armBots.find(a => a.modelUuid === modelUuid); - }, + updateEndPoint: (modelUuid, actionUuid, endPoint) => { + 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) { + action.process.endPoint = endPoint; + } + } + }); + }, - getArmBotsByProduct: (productId) => { - return get().armBots.filter(a => a.productId === productId); - }, + setArmBotActive: (modelUuid, isActive) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.isActive = isActive; + } + }); + }, - getArmBotsByState: (state) => { - return get().armBots.filter(a => a.state === state); - }, + setArmBotState: (modelUuid, newState) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.state = newState; + } + }); + }, - getActiveArmBots: () => { - return get().armBots.filter(a => a.isActive); - }, + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.activeTime += incrementBy; + } + }); + }, - getIdleArmBots: () => { - return get().armBots.filter(a => !a.isActive && a.state === 'idle'); - }, + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.idleTime += incrementBy; + } + }); + }, - getArmBotsByCurrentAction: (actionUuid) => { - return get().armBots.filter(a => a.currentAction?.actionUuid === actionUuid); - } - })) -); + 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); + } + })) + ) +} + +export type ArmBotStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/simulation/useConveyorStore.ts b/app/src/store/simulation/useConveyorStore.ts index 6d920eb..40dfab4 100644 --- a/app/src/store/simulation/useConveyorStore.ts +++ b/app/src/store/simulation/useConveyorStore.ts @@ -26,111 +26,115 @@ interface ConveyorStore { getIdleConveyors: () => ConveyorStatus[]; } -export const useConveyorStore = create()( - immer((set, get) => ({ - conveyors: [], +export const createConveyorStore = () => { + return create()( + immer((set, get) => ({ + conveyors: [], - addConveyor: (productId, event) => { - set((state) => { - const exists = state.conveyors.some(c => c.modelUuid === event.modelUuid); - if (!exists) { - state.conveyors.push({ - ...event, - productId, - isActive: false, - isPaused: false, - idleTime: 0, - activeTime: 0, - state: 'idle', - }); - } - }); - }, + addConveyor: (productId, event) => { + set((state) => { + const exists = state.conveyors.some(c => c.modelUuid === event.modelUuid); + if (!exists) { + state.conveyors.push({ + ...event, + productId, + isActive: false, + isPaused: false, + idleTime: 0, + activeTime: 0, + state: 'idle', + }); + } + }); + }, - removeConveyor: (modelUuid) => { - set((state) => { - state.conveyors = state.conveyors.filter(c => c.modelUuid !== modelUuid); - }); - }, + 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); - } - }); - }, + updateConveyor: (modelUuid, updates) => { + set((state) => { + const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid); + if (conveyor) { + Object.assign(conveyor, updates); + } + }); + }, - clearConveyors: () => { - set((state) => { - state.conveyors = []; - }); - }, + clearConveyors: () => { + set((state) => { + state.conveyors = []; + }); + }, - setConveyorActive: (modelUuid, isActive) => { - set((state) => { - const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid); - if (conveyor) { - conveyor.isActive = isActive; - } - }); - }, + 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; - } - }); - }, + setConveyorState: (modelUuid, newState) => { + set((state) => { + const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid); + if (conveyor) { + conveyor.state = newState; + } + }); + }, - setConveyorPaused: (modelUuid, isPaused) => { - set((state) => { - const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid); - if (conveyor) { - conveyor.isPaused = isPaused; - } - }); - }, + setConveyorPaused: (modelUuid, isPaused) => { + set((state) => { + const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid); + if (conveyor) { + conveyor.isPaused = isPaused; + } + }); + }, - incrementActiveTime: (modelUuid, incrementBy) => { - set((state) => { - const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid); - if (conveyor) { - conveyor.activeTime += incrementBy; - } - }); - }, + 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; - } - }); - }, + 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); - }, + getConveyorById: (modelUuid) => { + return get().conveyors.find(c => c.modelUuid === modelUuid); + }, - getConveyorsByProduct: (productId) => { - return get().conveyors.filter(c => c.productId === productId); - }, + getConveyorsByProduct: (productId) => { + return get().conveyors.filter(c => c.productId === productId); + }, - getConveyorsByState: (state) => { - return get().conveyors.filter(c => c.state === state); - }, + getConveyorsByState: (state) => { + return get().conveyors.filter(c => c.state === state); + }, - getActiveConveyors: () => { - return get().conveyors.filter(c => c.isActive); - }, + getActiveConveyors: () => { + return get().conveyors.filter(c => c.isActive); + }, - getIdleConveyors: () => { - return get().conveyors.filter(c => !c.isActive && c.state === 'idle'); - }, - })) -); + getIdleConveyors: () => { + return get().conveyors.filter(c => !c.isActive && c.state === 'idle'); + }, + })) + ) +} + +export type ConveyorStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/simulation/useMachineStore.ts b/app/src/store/simulation/useMachineStore.ts index df480e0..8fb5b06 100644 --- a/app/src/store/simulation/useMachineStore.ts +++ b/app/src/store/simulation/useMachineStore.ts @@ -37,140 +37,144 @@ interface MachineStore { getIdleMachines: () => MachineStatus[]; } -export const useMachineStore = create()( - immer((set, get) => ({ - machines: [], +export const createMachineStore = () => { + return create()( + immer((set, get) => ({ + machines: [], - addMachine: (productId, machine) => { - set((state) => { - const exists = state.machines.some( - (m) => m.modelUuid === machine.modelUuid - ); - if (!exists) { - 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); - } - }); - }, - - clearMachines: () => { - set((state) => { - state.machines = []; - }); - }, - - addCurrentAction: (modelUuid, actionUuid, materialType, materialId) => { - set((state) => { - const armBot = state.machines.find((a) => a.modelUuid === modelUuid); - if (armBot) { - const action = armBot.point.action; - if (action) { - armBot.currentAction = { - actionUuid: actionUuid, - actionName: action.actionName, - materialType: materialType, - materialId: materialId, - }; + addMachine: (productId, machine) => { + set((state) => { + const exists = state.machines.some( + (m) => m.modelUuid === machine.modelUuid + ); + if (!exists) { + state.machines.push({ + ...machine, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + state: "idle", + }); } - } - }); - }, + }); + }, - removeCurrentAction: (modelUuid) => { - set((state) => { - const armBot = state.machines.find((a) => a.modelUuid === modelUuid); - if (armBot) { - armBot.currentAction = undefined; - } - }); - }, + removeMachine: (modelUuid) => { + set((state) => { + state.machines = state.machines.filter( + (m) => m.modelUuid !== modelUuid + ); + }); + }, - setMachineActive: (modelUuid, isActive) => { - set((state) => { - const machine = state.machines.find((m) => m.modelUuid === modelUuid); - if (machine) { - machine.isActive = isActive; - } - }); - }, + updateMachine: (modelUuid, updates) => { + set((state) => { + const machine = state.machines.find((m) => m.modelUuid === modelUuid); + if (machine) { + Object.assign(machine, updates); + } + }); + }, - setMachineState: (modelUuid, newState) => { - set((state) => { - const machine = state.machines.find((m) => m.modelUuid === modelUuid); - if (machine) { - machine.state = newState; - } - }); - }, + clearMachines: () => { + set((state) => { + state.machines = []; + }); + }, - incrementActiveTime: (modelUuid, incrementBy) => { - set((state) => { - const machine = state.machines.find((m) => m.modelUuid === modelUuid); - if (machine) { - machine.activeTime += incrementBy; - } - }); - }, + addCurrentAction: (modelUuid, actionUuid, materialType, materialId) => { + set((state) => { + const armBot = state.machines.find((a) => a.modelUuid === modelUuid); + if (armBot) { + const action = armBot.point.action; + if (action) { + armBot.currentAction = { + actionUuid: actionUuid, + actionName: action.actionName, + materialType: materialType, + materialId: materialId, + }; + } + } + }); + }, - incrementIdleTime: (modelUuid, incrementBy) => { - set((state) => { - const machine = state.machines.find((m) => m.modelUuid === modelUuid); - if (machine) { - machine.idleTime += incrementBy; - } - }); - }, - resetTime: (modelUuid) => { - set((state) => { - const machine = state.machines.find((m) => m.modelUuid === modelUuid); - if (machine) { - machine.activeTime = 0; - machine.idleTime = 0; - } - }); - }, + removeCurrentAction: (modelUuid) => { + set((state) => { + const armBot = state.machines.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.currentAction = undefined; + } + }); + }, - getMachineById: (modelUuid) => { - return get().machines.find((m) => m.modelUuid === modelUuid); - }, + setMachineActive: (modelUuid, isActive) => { + set((state) => { + const machine = state.machines.find((m) => m.modelUuid === modelUuid); + if (machine) { + machine.isActive = isActive; + } + }); + }, - getMachinesByProduct: (productId) => { - return get().machines.filter((m) => m.productId === productId); - }, + setMachineState: (modelUuid, newState) => { + set((state) => { + const machine = state.machines.find((m) => m.modelUuid === modelUuid); + if (machine) { + machine.state = newState; + } + }); + }, - getMachinesBystate: (state) => { - return get().machines.filter((m) => m.state === state); - }, + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const machine = state.machines.find((m) => m.modelUuid === modelUuid); + if (machine) { + machine.activeTime += incrementBy; + } + }); + }, - getActiveMachines: () => { - return get().machines.filter((m) => m.isActive); - }, + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const machine = state.machines.find((m) => m.modelUuid === modelUuid); + if (machine) { + machine.idleTime += incrementBy; + } + }); + }, + resetTime: (modelUuid) => { + set((state) => { + const machine = state.machines.find((m) => m.modelUuid === modelUuid); + if (machine) { + machine.activeTime = 0; + machine.idleTime = 0; + } + }); + }, - getIdleMachines: () => { - return get().machines.filter((m) => !m.isActive && m.state === "idle"); - }, - })) -); + 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"); + }, + })) + ) +} + +export type MachineStoreType = ReturnType; diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts index 171f674..a71af3b 100644 --- a/app/src/store/simulation/useStorageUnitStore.ts +++ b/app/src/store/simulation/useStorageUnitStore.ts @@ -35,181 +35,185 @@ interface StorageUnitStore { getEmptyStorageUnits: () => StorageUnitStatus[]; } -export const useStorageUnitStore = create()( - immer((set, get) => ({ - storageUnits: [], +export const createStorageUnitStore = () => { + return create()( + immer((set, get) => ({ + storageUnits: [], - addStorageUnit: (productId, storageUnit) => { - set((state) => { - const exists = state.storageUnits.some(s => s.modelUuid === storageUnit.modelUuid); - if (!exists) { - state.storageUnits.push({ - ...storageUnit, - productId, - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - currentMaterials: [], - state: 'idle' - }); - } - }); - }, + addStorageUnit: (productId, storageUnit) => { + set((state) => { + const exists = state.storageUnits.some(s => s.modelUuid === storageUnit.modelUuid); + if (!exists) { + state.storageUnits.push({ + ...storageUnit, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + currentLoad: 0, + currentMaterials: [], + state: 'idle' + }); + } + }); + }, - removeStorageUnit: (modelUuid) => { - set((state) => { - state.storageUnits = state.storageUnits.filter(s => s.modelUuid !== modelUuid); - }); - }, + 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); - } - }); - }, + updateStorageUnit: (modelUuid, updates) => { + set((state) => { + const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); + if (unit) { + Object.assign(unit, updates); + } + }); + }, - clearStorageUnits: () => { - set(() => ({ - storageUnits: [], - })); - }, + clearStorageUnits: () => { + set(() => ({ + storageUnits: [], + })); + }, - setStorageUnitActive: (modelUuid, isActive) => { - set((state) => { - const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); - if (unit) { - unit.isActive = isActive; - } - }); - }, + 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; - } - }); - }, + setStorageUnitState: (modelUuid, newState) => { + set((state) => { + const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); + if (unit) { + unit.state = newState; + } + }); + }, - updateCurrentLoad: (modelUuid, incrementBy) => { - set((state) => { - const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); - if (unit) { - unit.currentLoad += incrementBy; - } - }); - }, + updateCurrentLoad: (modelUuid, incrementBy) => { + set((state) => { + const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); + if (unit) { + unit.currentLoad += incrementBy; + } + }); + }, - incrementActiveTime: (modelUuid, incrementBy) => { - set((state) => { - const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); - if (unit) { - unit.activeTime += incrementBy; - } - }); - }, + 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; - } - }); - }, + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); + if (unit) { + unit.idleTime += incrementBy; + } + }); + }, - addCurrentMaterial: (modelUuid, materialType, materialId) => { - set((state) => { - const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); - if (storage) { - storage.currentMaterials.push({ materialType, materialId }); - } - }); - }, + addCurrentMaterial: (modelUuid, materialType, materialId) => { + set((state) => { + const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); + if (storage) { + storage.currentMaterials.push({ materialType, materialId }); + } + }); + }, - setCurrentMaterials: (modelUuid, materials) => { - set((state) => { - const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); - if (storage) { - storage.currentMaterials = materials; - } - }); - }, + setCurrentMaterials: (modelUuid, materials) => { + set((state) => { + const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); + if (storage) { + storage.currentMaterials = materials; + } + }); + }, - getLastMaterial: (modelUuid) => { - let removedMaterial: { materialId: string; materialType: string; } | undefined; - set((state) => { - const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); - if (storage) { - if (storage.currentMaterials.length > 0) { - const material = storage.currentMaterials[storage.currentMaterials.length - 1]; - if (material) { - removedMaterial = { materialId: material.materialId, materialType: material.materialType }; + getLastMaterial: (modelUuid) => { + let removedMaterial: { materialId: string; materialType: string; } | undefined; + set((state) => { + const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); + if (storage) { + if (storage.currentMaterials.length > 0) { + const material = storage.currentMaterials[storage.currentMaterials.length - 1]; + if (material) { + removedMaterial = { materialId: material.materialId, materialType: material.materialType }; + } } } - } - }); - return removedMaterial; - }, + }); + return removedMaterial; + }, - removeLastMaterial: (modelUuid) => { - let removedMaterial: { materialId: string; materialType: string; } | undefined; - set((state) => { - const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); - if (storage) { - if (storage.currentMaterials.length > 0) { - const material = storage.currentMaterials.pop(); - if (material) { - removedMaterial = { materialId: material.materialId, materialType: material.materialType }; + removeLastMaterial: (modelUuid) => { + let removedMaterial: { materialId: string; materialType: string; } | undefined; + set((state) => { + const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); + if (storage) { + if (storage.currentMaterials.length > 0) { + const material = storage.currentMaterials.pop(); + if (material) { + removedMaterial = { materialId: material.materialId, materialType: material.materialType }; + } } } - } - }); - return removedMaterial; - }, + }); + return removedMaterial; + }, - clearCurrentMaterials: (modelUuid) => { - set((state) => { - const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); - if (storage) { - storage.currentMaterials = []; - } - }); - }, + clearCurrentMaterials: (modelUuid) => { + set((state) => { + const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); + if (storage) { + storage.currentMaterials = []; + } + }); + }, - getStorageUnitById: (modelUuid) => { - return get().storageUnits.find(s => s.modelUuid === modelUuid); - }, + getStorageUnitById: (modelUuid) => { + return get().storageUnits.find(s => s.modelUuid === modelUuid); + }, - getStorageUnitsByProduct: (productId) => { - return get().storageUnits.filter(s => s.productId === productId); - }, + getStorageUnitsByProduct: (productId) => { + return get().storageUnits.filter(s => s.productId === productId); + }, - getStorageUnitsBystate: (state) => { - return get().storageUnits.filter(s => s.state === state); - }, + getStorageUnitsBystate: (state) => { + return get().storageUnits.filter(s => s.state === state); + }, - getActiveStorageUnits: () => { - return get().storageUnits.filter(s => s.isActive); - }, + getActiveStorageUnits: () => { + return get().storageUnits.filter(s => s.isActive); + }, - getIdleStorageUnits: () => { - return get().storageUnits.filter(s => !s.isActive && s.state === 'idle'); - }, + getIdleStorageUnits: () => { + return get().storageUnits.filter(s => !s.isActive && s.state === 'idle'); + }, - getFullStorageUnits: () => { - return get().storageUnits.filter( - s => s.currentLoad >= s.point.action.storageCapacity - ); - }, + getFullStorageUnits: () => { + return get().storageUnits.filter( + s => s.currentLoad >= s.point.action.storageCapacity + ); + }, - getEmptyStorageUnits: () => { - return get().storageUnits.filter(s => s.currentLoad === 0); - }, - })) -); + getEmptyStorageUnits: () => { + return get().storageUnits.filter(s => s.currentLoad === 0); + }, + })) + ) +} + +export type StorageUnitStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index d1ce04f..c41bb7c 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -37,217 +37,221 @@ interface VehiclesStore { getActiveVehicles: () => VehicleStatus[]; } -export const useVehicleStore = create()( - immer((set, get) => ({ - vehicles: [], +export const createVehicleStore = () => { + return create()( + immer((set, get) => ({ + vehicles: [], - addVehicle: (productId, event) => { - set((state) => { - const exists = state.vehicles.some((v) => v.modelUuid === event.modelUuid); - if (!exists) { - state.vehicles.push({ - ...event, - productId, - isActive: false, - isPicking: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - currentMaterials: [], - distanceTraveled: 0, - state: 'idle' - }); - } - }); - }, + addVehicle: (productId, event) => { + set((state) => { + const exists = state.vehicles.some((v) => v.modelUuid === event.modelUuid); + if (!exists) { + state.vehicles.push({ + ...event, + productId, + isActive: false, + isPicking: false, + idleTime: 0, + activeTime: 0, + currentLoad: 0, + currentMaterials: [], + distanceTraveled: 0, + state: 'idle' + }); + } + }); + }, - removeVehicle: (modelUuid) => { - set((state) => { - state.vehicles = state.vehicles.filter( - (v) => v.modelUuid !== modelUuid - ); - }); - }, + 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); - } - }); - }, + updateVehicle: (modelUuid, updates) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + Object.assign(vehicle, updates); + } + }); + }, - clearvehicles: () => { - set((state) => { - state.vehicles = []; - }); - }, + clearvehicles: () => { + set((state) => { + state.vehicles = []; + }); + }, - setVehicleActive: (modelUuid, isActive) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.isActive = isActive; - } - }); - }, + setVehicleActive: (modelUuid, isActive) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.isActive = isActive; + } + }); + }, - setVehiclePicking: (modelUuid, isPicking) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.isPicking = isPicking; - } - }); - }, + setVehiclePicking: (modelUuid, isPicking) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.isPicking = isPicking; + } + }); + }, - updateSteeringAngle: (modelUuid, steeringAngle) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.point.action.steeringAngle = steeringAngle; - } - }); - }, + updateSteeringAngle: (modelUuid, steeringAngle) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.point.action.steeringAngle = steeringAngle; + } + }); + }, - incrementVehicleLoad: (modelUuid, incrementBy) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.currentLoad += incrementBy; - } - }); - }, + 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; - } - }); - }, + decrementVehicleLoad: (modelUuid, decrementBy) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.currentLoad -= decrementBy; + } + }); + }, - setVehicleLoad: (modelUuid, load) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.currentLoad = load; - } - }); - }, + setVehicleLoad: (modelUuid, load) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.currentLoad = load; + } + }); + }, - setVehicleState: (modelUuid, newState) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.state = newState; - } - }); - }, + setVehicleState: (modelUuid, newState) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.state = newState; + } + }); + }, - addCurrentMaterial: (modelUuid, materialType, materialId) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.currentMaterials.push({ materialType, materialId }); - } - }); - }, + addCurrentMaterial: (modelUuid, materialType, materialId) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.currentMaterials.push({ materialType, materialId }); + } + }); + }, - setCurrentMaterials: (modelUuid, materials) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.currentMaterials = materials; - } - }); - }, + setCurrentMaterials: (modelUuid, materials) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.currentMaterials = materials; + } + }); + }, - removeLastMaterial: (modelUuid) => { - let removedMaterial: { materialId: string; materialType: string; } | undefined; - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - if (vehicle.currentMaterials.length > 0) { - const material = vehicle.currentMaterials.pop(); - if (material) { - removedMaterial = { materialId: material.materialId, materialType: material.materialType }; + removeLastMaterial: (modelUuid) => { + let removedMaterial: { materialId: string; materialType: string; } | undefined; + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + if (vehicle.currentMaterials.length > 0) { + const material = vehicle.currentMaterials.pop(); + if (material) { + removedMaterial = { materialId: material.materialId, materialType: material.materialType }; + } } } - } - }); - return removedMaterial; - }, + }); + return removedMaterial; + }, - getLastMaterial: (modelUuid) => { - let removedMaterial: { materialId: string; materialType: string; } | undefined; - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - if (vehicle.currentMaterials.length > 0) { - removedMaterial = { - materialId: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialId, - materialType: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialType - }; + getLastMaterial: (modelUuid) => { + let removedMaterial: { materialId: string; materialType: string; } | undefined; + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + if (vehicle.currentMaterials.length > 0) { + removedMaterial = { + materialId: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialId, + materialType: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialType + }; + } } - } - }); - return removedMaterial; - }, + }); + return removedMaterial; + }, - clearCurrentMaterials: (modelUuid) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.currentMaterials = []; - } - }); - }, + clearCurrentMaterials: (modelUuid) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.currentMaterials = []; + } + }); + }, - incrementActiveTime: (modelUuid, incrementBy) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.activeTime += incrementBy; - } - }); - }, + 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; - } - }); - }, + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.idleTime += incrementBy; + } + }); + }, - resetTime: (modelUuid) => { - set((state) => { - const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); - if (vehicle) { - vehicle.activeTime = 0; - vehicle.idleTime = 0; - } - }); - }, + resetTime: (modelUuid) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.activeTime = 0; + vehicle.idleTime = 0; + } + }); + }, - getVehicleById: (modelUuid) => { - return get().vehicles.find((v) => v.modelUuid === modelUuid); - }, + getVehicleById: (modelUuid) => { + return get().vehicles.find((v) => v.modelUuid === modelUuid); + }, - getVehiclesByProduct: (productId) => { - return get().vehicles.filter((v) => v.productId === productId); - }, + getVehiclesByProduct: (productId) => { + return get().vehicles.filter((v) => v.productId === productId); + }, - getVehiclesByState: (state) => { - return get().vehicles.filter((v) => v.state === state); - }, + getVehiclesByState: (state) => { + return get().vehicles.filter((v) => v.state === state); + }, - getActiveVehicles: () => { - return get().vehicles.filter((v) => v.isActive); - }, - })) -); + getActiveVehicles: () => { + return get().vehicles.filter((v) => v.isActive); + }, + })) + ) +} + +export type VehicleStoreType = ReturnType; \ No newline at end of file -- 2.49.1 From d3ea36d1bacf15f5930f6638dce4281b54426cf6 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 12:00:16 +0530 Subject: [PATCH 15/34] feat: Refactor product selection and comparison functionality - Created a new store for selected products using Zustand and immer for state management. - Introduced `useMainProduct` and `useComparisonProduct` hooks to manage main and comparison products. - Implemented `ComparisonScene` and `ComparisonSceneProvider` components to handle product comparisons. - Updated `MainScene` to allow selection of main products with a dropdown. - Enhanced styles for comparison layout and product selection UI. - Established a context for product management to streamline state access across components. --- .../layout/scenes/ComparisonScene.tsx | 48 + .../layout/scenes/ComparisonSceneProvider.tsx | 12 + .../components/layout/scenes/MainScene.tsx | 113 ++ .../layout/scenes/MainSceneProvider.tsx | 12 + .../eventProperties/EventProperties.tsx | 5 +- .../components/ActionsList.tsx | 10 +- .../mechanics/conveyorMechanics.tsx | 6 +- .../mechanics/machineMechanics.tsx | 6 +- .../mechanics/roboticArmMechanics.tsx | 9 +- .../mechanics/storageMechanics.tsx | 6 +- .../mechanics/vehicleMechanics.tsx | 5 +- .../eventProperties/trigger/Trigger.tsx | 26 +- .../sidebarRight/simulation/Simulations.tsx | 9 +- .../ui/compareVersion/CompareLayOut.tsx | 40 +- app/src/modules/builder/asset/assetsGroup.tsx | 4 +- .../builder/asset/models/model/model.tsx | 10 +- .../selectionControls/moveControls.tsx | 5 +- .../selectionControls/rotateControls.tsx | 9 +- .../transformControls/transformControls.tsx | 5 +- app/src/modules/scene/scene.tsx | 8 +- app/src/modules/scene/sceneContext.tsx | 16 +- .../conveyor/actionHandler/useSpawnHandler.ts | 5 +- .../actionHandler/useProcessHandler.ts | 5 +- .../actionHandler/usePickAndPlaceHandler.ts | 5 +- .../actionHandler/useRetrieveHandler.ts | 5 +- .../actionHandler/useStoreHandler.ts | 5 +- .../vehicle/actionHandler/useTravelHandler.ts | 5 +- .../simulation/analysis/ROI/roiData.tsx | 5 +- .../analysis/throughPut/throughPutData.tsx | 5 +- .../conveyorInstance/conveyorInstance.tsx | 7 +- .../events/points/creator/pointsCreator.tsx | 5 +- .../triggerConnections/triggerConnector.tsx | 5 +- .../machineInstance/machineInstance.tsx | 5 +- .../instances/instance/materialInstance.tsx | 9 +- .../simulation/products/productContext.tsx | 37 + .../modules/simulation/products/products.tsx | 34 +- .../armInstance/roboticArmInstance.tsx | 5 +- .../simulation/simulator/simulator.tsx | 5 +- .../simulation/spatialUI/arm/armBotUI.tsx | 6 +- .../spatialUI/arm/useDraggableGLTF.ts | 12 +- .../spatialUI/vehicle/vehicleUI.tsx | 7 +- .../triggerHandler/useTriggerHandler.ts | 5 +- .../instances/instance/vehicleInstance.tsx | 5 +- app/src/pages/Project.tsx | 126 +- .../store/simulation/useSimulationStore.ts | 82 +- app/src/styles/layout/compareLayout.scss | 1013 +++++++++-------- 46 files changed, 996 insertions(+), 776 deletions(-) create mode 100644 app/src/components/layout/scenes/ComparisonScene.tsx create mode 100644 app/src/components/layout/scenes/ComparisonSceneProvider.tsx create mode 100644 app/src/components/layout/scenes/MainScene.tsx create mode 100644 app/src/components/layout/scenes/MainSceneProvider.tsx create mode 100644 app/src/modules/simulation/products/productContext.tsx diff --git a/app/src/components/layout/scenes/ComparisonScene.tsx b/app/src/components/layout/scenes/ComparisonScene.tsx new file mode 100644 index 0000000..d823d5b --- /dev/null +++ b/app/src/components/layout/scenes/ComparisonScene.tsx @@ -0,0 +1,48 @@ +import { useProductContext } from '../../../modules/simulation/products/productContext' +import RegularDropDown from '../../ui/inputs/RegularDropDown'; +import { useProductStore } from '../../../store/simulation/useProductStore'; +import { useSaveVersion } from '../../../store/builder/store'; +import useModuleStore from '../../../store/useModuleStore'; +import CompareLayOut from '../../ui/compareVersion/CompareLayOut'; +import ComparisonResult from '../../ui/compareVersion/ComparisonResult'; +import { useComparisonProduct } from '../../../store/simulation/useSimulationStore'; +import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; + +function ComparisonScene() { + const { isPlaying } = usePlayButtonStore(); + const { products } = useProductStore(); + const { isVersionSaved } = useSaveVersion(); + const { activeModule } = useModuleStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); + const { comparisonProduct, setComparisonProduct } = useComparisonProduct(); + + const handleSelectLayout = (option: string) => { + const product = products.find((product) => product.productName === option); + if (product) { + setComparisonProduct(product.productId, product.productName); + } + }; + return ( + <> + {isVersionSaved && activeModule === "simulation" && selectedProduct && ( + <> + {comparisonProduct && !isPlaying && +
+ l.productName)} // Pass layout names as options + onSelect={handleSelectLayout} + search={false} + /> +
+ } + + {false && } + + )} + + ) +} + +export default ComparisonScene; diff --git a/app/src/components/layout/scenes/ComparisonSceneProvider.tsx b/app/src/components/layout/scenes/ComparisonSceneProvider.tsx new file mode 100644 index 0000000..e47805c --- /dev/null +++ b/app/src/components/layout/scenes/ComparisonSceneProvider.tsx @@ -0,0 +1,12 @@ +import { ProductProvider } from '../../../modules/simulation/products/productContext' +import ComparisonScene from './ComparisonScene'; + +function ComparisonSceneProvider() { + return ( + + + + ) +} + +export default ComparisonSceneProvider \ No newline at end of file diff --git a/app/src/components/layout/scenes/MainScene.tsx b/app/src/components/layout/scenes/MainScene.tsx new file mode 100644 index 0000000..3101be5 --- /dev/null +++ b/app/src/components/layout/scenes/MainScene.tsx @@ -0,0 +1,113 @@ +import React from 'react' +import { useLoadingProgress, useSaveVersion, useSocketStore, useWidgetSubOption } from '../../../store/builder/store'; +import useModuleStore, { useThreeDStore } from '../../../store/useModuleStore'; +import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; +import { useSelectedZoneStore } from '../../../store/visualization/useZoneStore'; +import { useFloatingWidget } from '../../../store/visualization/useDroppedObjectsStore'; +import { useSelectedUserStore } from '../../../store/collaboration/useCollabStore'; +import KeyPressListener from '../../../utils/shortcutkeys/handleShortcutKeys'; +import LoadingPage from '../../templates/LoadingPage'; +import ModuleToggle from '../../ui/ModuleToggle'; +import SideBarLeft from '../sidebarLeft/SideBarLeft'; +import SideBarRight from '../sidebarRight/SideBarRight'; +import RealTimeVisulization from '../../../modules/visualization/RealTimeVisulization'; +import MarketPlace from '../../../modules/market/MarketPlace'; +import Tools from '../../ui/Tools'; +import SimulationPlayer from '../../ui/simulation/simulationPlayer'; +import ControlsPlayer from '../controls/ControlsPlayer'; +import SelectFloorPlan from '../../temporary/SelectFloorPlan'; +import { createHandleDrop } from '../../../modules/visualization/functions/handleUiDrop'; +import Scene from '../../../modules/scene/scene'; +import { useMainProduct } from '../../../store/simulation/useSimulationStore'; +import { useProductContext } from '../../../modules/simulation/products/productContext'; +import { useProductStore } from '../../../store/simulation/useProductStore'; +import RegularDropDown from '../../ui/inputs/RegularDropDown'; + +function MainScene() { + const { products } = useProductStore(); + const { setMainProduct } = useMainProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); + const { isVersionSaved } = useSaveVersion(); + const { activeModule } = useModuleStore(); + const { selectedUser } = useSelectedUserStore(); + const { loadingProgress } = useLoadingProgress(); + const { toggleThreeD } = useThreeDStore(); + const { isPlaying } = usePlayButtonStore(); + const { widgetSubOption } = useWidgetSubOption(); + const { visualizationSocket } = useSocketStore(); + const { selectedZone } = useSelectedZoneStore(); + const { setFloatingWidget } = useFloatingWidget(); + + const handleSelectLayout = (option: string) => { + const product = products.find((product) => product.productName === option); + if (product) { + setMainProduct(product.productId, product.productName); + } + }; + + return ( + <> + {!selectedUser && ( + <> + + {loadingProgress > 0 && } + {!isPlaying && ( + <> + {toggleThreeD && } + + + + )} + + {activeModule === "market" && } + {activeModule !== "market" && !isPlaying && !isVersionSaved && ( + + )} + {isPlaying && activeModule === "simulation" && } + {isPlaying && activeModule !== "simulation" && } + + {/* remove this later */} + {activeModule === "builder" && !toggleThreeD && } + + )} +
+ createHandleDrop({ + widgetSubOption, + visualizationSocket, + selectedZone, + setFloatingWidget, + event, + }) + } + onDragOver={(event) => event.preventDefault()} + > + +
+ + {selectedProduct && isVersionSaved && !isPlaying && ( +
+ l.productName)} // Pass layout names as options + onSelect={handleSelectLayout} + search={false} + /> +
+ )} + + ) +} + +export default MainScene \ No newline at end of file diff --git a/app/src/components/layout/scenes/MainSceneProvider.tsx b/app/src/components/layout/scenes/MainSceneProvider.tsx new file mode 100644 index 0000000..17971fa --- /dev/null +++ b/app/src/components/layout/scenes/MainSceneProvider.tsx @@ -0,0 +1,12 @@ +import { ProductProvider } from '../../../modules/simulation/products/productContext' +import MainScene from './MainScene' + +function MainSceneProvider() { + return ( + + + + ) +} + +export default MainSceneProvider \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index b9550ae..c47a169 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react"; import { useSelectedEventData, useSelectedEventSphere, - useSelectedProduct, } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -13,11 +12,13 @@ import StorageMechanics from "./mechanics/storageMechanics"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; +import { useProductContext } from "../../../../../modules/simulation/products/productContext"; const EventProperties: React.FC = () => { const { selectedEventData } = useSelectedEventData(); const { getEventByModelUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const [currentEventData, setCurrentEventData] = useState( null ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx index 632805b..52cd9db 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx @@ -8,10 +8,10 @@ import RenameInput from "../../../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../../../functions/handleResizePannel"; import { useSelectedAction, - useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; interface ActionsListProps { selectedPointData: any; @@ -33,7 +33,8 @@ const ActionsList: React.FC = ({ // store const { renameAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { selectedAction, setSelectedAction } = useSelectedAction(); const handleRenameAction = (newName: string) => { @@ -87,11 +88,10 @@ const ActionsList: React.FC = ({ selectedPointData?.actions?.map((action: any) => (
@@ -286,7 +287,7 @@ function RoboticArmMechanics() { {}} + onSelect={() => { }} disabled={true} /> diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 4ea5687..1c27ad1 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -6,9 +6,10 @@ import StorageAction from "../actions/StorageAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; -import { useSelectedAction, useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore"; import * as THREE from 'three'; import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; function StorageMechanics() { const { storageUnitStore } = useSceneContext(); @@ -16,7 +17,8 @@ function StorageMechanics() { const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); const { setCurrentMaterials, clearCurrentMaterials, updateCurrentLoad, getStorageUnitById } = storageUnitStore(); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 8e61dcf..786f38e 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -7,13 +7,13 @@ import { useSelectedAction, useSelectedEventData, useSelectedEventSphere, - useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; function VehicleMechanics() { const { vehicleStore } = useSceneContext(); @@ -21,7 +21,8 @@ function VehicleMechanics() { const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); const { getVehicleById } = vehicleStore(); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index fb0b97a..d94b553 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -11,9 +11,9 @@ import { handleResize } from "../../../../../../functions/handleResizePannel"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useSelectedAction, - useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; type TriggerProps = { selectedPointData?: PointsScheme | undefined; @@ -22,7 +22,8 @@ type TriggerProps = { const Trigger = ({ selectedPointData, type }: TriggerProps) => { const [currentAction, setCurrentAction] = useState(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { getActionByUuid, getEventByModelUuid, @@ -60,10 +61,10 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { ) { actionUuid = ( selectedPointData as - | ConveyorPointSchema - | VehiclePointSchema - | MachinePointSchema - | StoragePointSchema + | ConveyorPointSchema + | VehiclePointSchema + | MachinePointSchema + | StoragePointSchema ).action?.actionUuid; } else if ( type === "RoboticArm" && @@ -153,10 +154,10 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { return [ ( model as - | VehicleEventSchema - | RoboticArmEventSchema - | MachineEventSchema - | StorageEventSchema + | VehicleEventSchema + | RoboticArmEventSchema + | MachineEventSchema + | StorageEventSchema ).point, ]; } @@ -416,11 +417,10 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { {triggers.map((trigger) => (
setSelectedTrigger(trigger)} >
- {selectedLayout && ( + {comparisonProduct && (
- +
)} {width !== "0px" && - !selectedLayout && ( // Show only if no layout selected + !comparisonProduct && ( // Show only if no layout selected
@@ -177,16 +173,6 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => { )} {/* Always show after layout is selected */} - {width !== "0px" && selectedLayout && ( -
- l.productName)} // Pass layout names as options - onSelect={handleSelectLayout} - search={false} - /> -
- )}
); diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 5b6008d..e407d3c 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -12,6 +12,7 @@ import useModuleStore from "../../../store/useModuleStore"; import { useThree } from "@react-three/fiber"; import { CameraControls } from "@react-three/drei"; import addAssetModel from "./functions/addAssetModel"; +import { useSceneContext } from "../../scene/sceneContext"; const gltfLoaderWorker = new Worker( new URL( @@ -20,8 +21,9 @@ const gltfLoaderWorker = new Worker( ) ); -function AssetsGroup({ floorGroup, plane }: { floorGroup: RefGroup, plane: RefMesh }) { +function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) { const { activeModule } = useModuleStore(); + const { layout } = useSceneContext(); const { socket } = useSocketStore(); const { controls, gl, pointer, camera, raycaster } = useThree(); const { setLoadingProgress } = useLoadingProgress(); diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index d7af8d4..39fb4be 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -12,7 +12,8 @@ import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore'; import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore'; -import { useSelectedAsset, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; +import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore'; +import { useProductContext } from '../../../../simulation/products/productContext'; function Model({ asset }: { readonly asset: Asset }) { const { camera, controls, gl } = useThree(); @@ -24,7 +25,8 @@ function Model({ asset }: { readonly asset: Asset }) { const { setLeft } = useLeftData(); const { getIsEventInProduct } = useProductStore(); const { getEventByModelUuid } = useEventsStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); const { socket } = useSocketStore(); const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); @@ -199,7 +201,7 @@ function Model({ asset }: { readonly asset: Asset }) { } } - + const handleContextMenu = (asset: Asset, evt: ThreeEvent) => { if (activeTool === "cursor" && subModule === 'simulations') { @@ -250,10 +252,10 @@ function Model({ asset }: { readonly asset: Asset }) { userData={asset} onDoubleClick={(e) => { e.stopPropagation(); + handleDblClick(asset); }} onClick={(e) => { e.stopPropagation(); - handleDblClick(asset); handleClick(asset); }} onPointerOver={(e) => { diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index d28e852..3a68e96 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -11,11 +11,11 @@ import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { snapControls } from "../../../../utils/handleSnap"; import DistanceFindingControls from "./distanceFindingControls"; import { useAssetsStore } from "../../../../store/builder/useAssetStore"; +import { useProductContext } from "../../../simulation/products/productContext"; function MoveControls({ movedObjects, @@ -34,7 +34,8 @@ function MoveControls({ const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { socket } = useSocketStore(); const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">(""); const email = localStorage.getItem("email"); diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 83a1eb4..0418d46 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -6,9 +6,9 @@ import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../st import * as Types from "../../../../types/world/worldTypes"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { useAssetsStore } from "../../../../store/builder/useAssetStore"; +import { useProductContext } from "../../../simulation/products/productContext"; function RotateControls({ rotatedObjects, @@ -27,7 +27,8 @@ function RotateControls({ const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { socket } = useSocketStore(); const email = localStorage.getItem('email') @@ -208,7 +209,7 @@ function RotateControls({ if (obj.userData.eventData) { const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid); - const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(selectedProductStore.getState().selectedProduct.productId, obj.userData.modelUuid); if (eventData) { useEventsStore.getState().updateEvent(obj.userData.modelUuid, { @@ -217,7 +218,7 @@ function RotateControls({ }) } if (productData) { - const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { + const event = useProductStore.getState().updateEvent(selectedProductStore.getState().selectedProduct.productId, obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) diff --git a/app/src/modules/scene/controls/transformControls/transformControls.tsx b/app/src/modules/scene/controls/transformControls/transformControls.tsx index 66e965f..3c66589 100644 --- a/app/src/modules/scene/controls/transformControls/transformControls.tsx +++ b/app/src/modules/scene/controls/transformControls/transformControls.tsx @@ -8,10 +8,10 @@ import { useEffect, useState } from "react"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; import { useAssetsStore } from "../../../../store/builder/useAssetStore"; +import { useProductContext } from "../../../simulation/products/productContext"; export default function TransformControl() { const state = useThree(); @@ -21,7 +21,8 @@ export default function TransformControl() { const { setObjectRotation } = useObjectRotation(); const { activeTool } = useActiveTool(); const { socket } = useSocketStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { updateAsset, getAssetById } = useAssetsStore(); const email = localStorage.getItem('email') diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index 00c5bbc..7777a30 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -1,5 +1,6 @@ import { useMemo } from "react"; import { Canvas } from "@react-three/fiber"; +import { Color } from "three"; import { KeyboardControls } from "@react-three/drei"; import { SceneProvider } from "./sceneContext"; @@ -9,7 +10,7 @@ import Setup from "./setup/setup"; import Simulation from "../simulation/simulation"; import Collaboration from "../collaboration/collaboration"; -export default function Scene() { +export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Comparison Layout' }) { const map = useMemo(() => [ { name: "forward", keys: ["ArrowUp", "w", "W"] }, { name: "backward", keys: ["ArrowDown", "s", "S"] }, @@ -18,7 +19,7 @@ export default function Scene() { ], []); return ( - + { e.preventDefault(); }} + onCreated={(e) => { + e.scene.background = new Color(0x19191d); + }} > diff --git a/app/src/modules/scene/sceneContext.tsx b/app/src/modules/scene/sceneContext.tsx index 1eea293..0145b45 100644 --- a/app/src/modules/scene/sceneContext.tsx +++ b/app/src/modules/scene/sceneContext.tsx @@ -13,11 +13,18 @@ type SceneContextValue = { conveyorStore: ConveyorStoreType; vehicleStore: VehicleStoreType; storageUnitStore: StorageUnitStoreType; + layout: 'Main Layout' | 'Comparison Layout'; }; const SceneContext = createContext(null); -export function SceneProvider({ children }: { readonly children: React.ReactNode }) { +export function SceneProvider({ + children, + layout +}: { + readonly children: React.ReactNode; + readonly layout: 'Main Layout' | 'Comparison Layout'; +}) { const materialStore = useMemo(() => createMaterialStore(), []); const armBotStore = useMemo(() => createArmBotStore(), []); const machineStore = useMemo(() => createMachineStore(), []); @@ -32,9 +39,10 @@ export function SceneProvider({ children }: { readonly children: React.ReactNode machineStore, conveyorStore, vehicleStore, - storageUnitStore + storageUnitStore, + layout } - ), [materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]); + ), [materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout]); return ( @@ -50,4 +58,4 @@ export function useSceneContext() { throw new Error('useSceneContext must be used within a SceneProvider'); } return context; -} +} \ No newline at end of file diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts index a2efcfb..d546b12 100644 --- a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts +++ b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts @@ -2,9 +2,9 @@ import { useCallback, useEffect, useState } from "react"; import * as THREE from 'three'; import { useFrame } from "@react-three/fiber"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { usePlayButtonStore, useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; interface SpawnInstance { lastSpawnTime: number | null; @@ -30,7 +30,8 @@ export function useSpawnHandler() { const { isPaused } = usePauseButtonStore(); const { speed } = useAnimationPlaySpeed(); const { isReset } = useResetButtonStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const [activeSpawns, setActiveSpawns] = useState>(new Map()); diff --git a/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts index c7dc10b..378975a 100644 --- a/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts +++ b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts @@ -1,14 +1,15 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useProcessHandler() { const { materialStore, machineStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { getMaterialById, setMaterial } = materialStore(); const { addCurrentAction } = machineStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const processLogStatus = (materialUuid: string, status: string) => { echo.log(`${materialUuid}, ${status}`); diff --git a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts index 9f53c80..cfa62f9 100644 --- a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts +++ b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts @@ -1,14 +1,15 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function usePickAndPlaceHandler() { const { materialStore, armBotStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { getMaterialById } = materialStore(); const { addCurrentAction } = armBotStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const pickAndPlaceLogStatus = (materialUuid: string, status: string) => { echo.warn(`${materialUuid}, ${status}`); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts index 3f4f9a8..5d4ea93 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts @@ -1,17 +1,18 @@ import { useCallback, useState, useEffect, useRef } from "react"; import { useFrame } from "@react-three/fiber"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useRetrieveHandler() { const { materialStore, armBotStore, vehicleStore, storageUnitStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { addMaterial } = materialStore(); const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = useProductStore(); const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore(); const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getArmBotById, addCurrentAction } = armBotStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts index 61e1f94..2656457 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts @@ -1,14 +1,15 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useStoreHandler() { const { materialStore, storageUnitStore } = useSceneContext(); const { getMaterialById, removeMaterial, setEndTime } = materialStore(); const { addCurrentMaterial, updateCurrentLoad } = storageUnitStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const storeLogStatus = (materialUuid: string, status: string) => { echo.info(`${materialUuid}, ${status}`); diff --git a/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts index 69c18b5..fe3dd4a 100644 --- a/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts +++ b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts @@ -1,13 +1,14 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useTravelHandler() { const { materialStore, vehicleStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { getMaterialById } = materialStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { incrementVehicleLoad, addCurrentMaterial } = vehicleStore(); const travelLogStatus = (materialUuid: string, status: string) => { diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx index f1ddda5..4d6444d 100644 --- a/app/src/modules/simulation/analysis/ROI/roiData.tsx +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -1,12 +1,13 @@ import React, { useEffect, useState } from 'react' import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; +import { useProductContext } from '../../products/productContext'; export default function ROIData() { + const { selectedProductStore } = useProductContext(); const { inputValues } = useInputValues(); const { productionCapacityData } = useProductionCapacityData() - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { isPlaying } = usePlayButtonStore(); const { setRoiSummaryData } = useROISummaryData(); useEffect(() => { diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index 6fde8db..6b9062f 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -1,14 +1,15 @@ import { useEffect } from 'react'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useProductStore } from '../../../../store/simulation/useProductStore'; import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; import { useMachineCount, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; import { useSceneContext } from '../../../scene/sceneContext'; +import { useProductContext } from '../../products/productContext'; export default function ThroughPutData() { const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { products, getProductById } = useProductStore(); const { armBots } = armBotStore(); const { vehicles } = vehicleStore(); diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx index 69061d6..67db5b9 100644 --- a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx @@ -1,13 +1,14 @@ import { useEffect } from 'react' import { useResetButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; // import { findConveyorSubsequence } from '../../../simulator/functions/getConveyorSequencesInProduct'; -function ConveyorInstance({ conveyor }: { conveyor: ConveyorStatus }) { +function ConveyorInstance({ conveyor }: { readonly conveyor: ConveyorStatus }) { const { getProductById } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { materialStore, conveyorStore } = useSceneContext(); const { getMaterialsByCurrentModelUuid, materials } = materialStore(); const { isReset } = useResetButtonStore(); diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index c1b7d23..89513ec 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -2,7 +2,6 @@ import { useEffect, useRef, useState } from "react"; import * as THREE from "three"; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore"; import { TransformControls } from "@react-three/drei"; import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; @@ -10,13 +9,15 @@ import { useSelectedEventSphere, useSelectedEventData, } from "../../../../../st import { useThree } from "@react-three/fiber"; import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore"; import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useProductContext } from "../../../products/productContext"; function PointsCreator() { const { gl, raycaster, scene, pointer, camera } = useThree(); const { subModule } = useSubModuleStore(); + const { selectedProductStore } = useProductContext(); const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getEventByModelUuid: getEventByModelUuidFromProduct2, getPointByUuid: getPointByUuidFromProduct } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); diff --git a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx index 2a420ae..d082419 100644 --- a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx +++ b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx @@ -5,13 +5,13 @@ import { useSubModuleStore } from "../../../../store/useModuleStore"; import { useSelectedAction, useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { handleAddEventToProduct } from "../points/functions/handleAddEventToProduct"; import { QuadraticBezierLine } from "@react-three/drei"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { useDeleteTool } from "../../../../store/builder/store"; import { usePlayButtonStore } from "../../../../store/usePlayButtonStore"; import { ArrowOnQuadraticBezier, Arrows } from "../arrows/arrows"; +import { useProductContext } from "../../products/productContext"; interface ConnectionLine { id: string; @@ -23,9 +23,10 @@ interface ConnectionLine { function TriggerConnector() { const { gl, raycaster, scene, pointer, camera } = useThree(); const { subModule } = useSubModuleStore(); + const { selectedProductStore } = useProductContext(); const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, removeTrigger, addEvent, getEventByModelUuid, getPointUuidByActionUuid, getProductById } = useProductStore(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const [hoveredLineKey, setHoveredLineKey] = useState(null); const groupRefs = useRef>({}); const [helperlineColor, setHelperLineColor] = useState("red"); diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx index da8ea2f..2356e76 100644 --- a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -2,9 +2,9 @@ import { useEffect, useRef, useState } from 'react' import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import MachineAnimator from '../animator/machineAnimator'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; function MachineInstance({ machineDetail }: { readonly machineDetail: MachineStatus }) { const [currentPhase, setCurrentPhase] = useState('idle'); @@ -17,8 +17,9 @@ function MachineInstance({ machineDetail }: { readonly machineDetail: MachineSta const isPausedRef = useRef(false); const { isPlaying } = usePlayButtonStore(); const { machineStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { machines, setMachineState, setMachineActive, incrementIdleTime, incrementActiveTime, resetTime } = machineStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getActionByUuid } = useProductStore(); const { triggerPointActions } = useTriggerHandler(); const { speed } = useAnimationPlaySpeed(); diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx index fce425a..9826ad9 100644 --- a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx +++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx @@ -1,18 +1,19 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react' +import { useMemo, useRef } from 'react' import * as THREE from 'three'; import MaterialAnimator from '../animator/materialAnimator'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { MaterialModel } from '../material/materialModel'; import { useThree } from '@react-three/fiber'; import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; +import { useProductContext } from '../../../products/productContext'; -function MaterialInstance({ material }: { material: MaterialSchema }) { +function MaterialInstance({ material }: { readonly material: MaterialSchema }) { const matRef: any = useRef(); const { scene } = useThree(); + const { selectedProductStore } = useProductContext(); const { getModelUuidByPointUuid, getPointByUuid, getEventByModelUuid, getActionByUuid, getTriggerByUuid, getActionByPointUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { speed } = useAnimationPlaySpeed(); const { triggerPointActions } = useTriggerHandler(); diff --git a/app/src/modules/simulation/products/productContext.tsx b/app/src/modules/simulation/products/productContext.tsx new file mode 100644 index 0000000..ba95435 --- /dev/null +++ b/app/src/modules/simulation/products/productContext.tsx @@ -0,0 +1,37 @@ +import { createContext, useContext, useMemo } from 'react'; +import { createSelectedProductStore, SelectedProductType } from '../../../store/simulation/useSimulationStore'; + +type ProductContextValue = { + selectedProductStore: SelectedProductType, +}; + +const ProductContext = createContext(null); + +export function ProductProvider({ + children, +}: { + readonly children: React.ReactNode; +}) { + const selectedProductStore = useMemo(() => createSelectedProductStore(), []); + + const contextValue = useMemo(() => ( + { + selectedProductStore + } + ), [selectedProductStore]); + + return ( + + {children} + + ); +} + +// Base hook to get the context +export function useProductContext() { + const context = useContext(ProductContext); + if (!context) { + throw new Error('useProductContext must be used within a ProductProvider'); + } + return context; +} \ No newline at end of file diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 49310e2..1b08013 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -1,16 +1,18 @@ import * as THREE from 'three'; import { useEffect } from 'react'; import { useProductStore } from '../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; import { upsertProductOrEventApi } from '../../../services/simulation/products/UpsertProductOrEventApi'; import { getAllProductsApi } from '../../../services/simulation/products/getallProductsApi'; import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore'; import { useSceneContext } from '../../scene/sceneContext'; +import { useProductContext } from './productContext'; +import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore'; function Products() { - const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); + const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout } = useSceneContext(); const { products, getProductById, addProduct, setProducts } = useProductStore(); - const { selectedProduct, setSelectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct, setSelectedProduct } = selectedProductStore(); const { addVehicle, clearvehicles } = vehicleStore(); const { addArmBot, clearArmBots } = armBotStore(); const { addMachine, clearMachines } = machineStore(); @@ -18,6 +20,24 @@ function Products() { const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore(); const { isReset } = useResetButtonStore(); const { isPlaying } = usePlayButtonStore(); + const { mainProduct } = useMainProduct(); + const { comparisonProduct } = useComparisonProduct(); + + useEffect(() => { + if (layout === 'Main Layout' && mainProduct) { + setSelectedProduct(mainProduct.productId, mainProduct.productName); + } + }, [mainProduct]) + + useEffect(() => { + if (layout === 'Comparison Layout' && comparisonProduct) { + setSelectedProduct(comparisonProduct.productId, comparisonProduct.productName); + } + }, [comparisonProduct]) + + useEffect(() => { + console.log(selectedProduct); + }, [selectedProduct]) useEffect(() => { const email = localStorage.getItem('email') @@ -28,10 +48,14 @@ function Products() { const name = 'Product 1'; addProduct(name, id); upsertProductOrEventApi({ productName: name, productId: id, organization: organization }) - setSelectedProduct(id, name); + if (layout === 'Main Layout') { + setSelectedProduct(id, name); + } } else { setProducts(data); - setSelectedProduct(data[0].productId, data[0].productName); + if (layout === 'Main Layout') { + setSelectedProduct(data[0].productId, data[0].productName); + } } }) }, []) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index e0c26bc..40cd0f1 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -7,9 +7,9 @@ import MaterialAnimator from '../animator/materialAnimator'; import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb"; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) { @@ -25,12 +25,13 @@ function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) { const isSpeedRef = useRef(null); let startTime: number; + const { selectedProductStore } = useProductContext(); const { materialStore, armBotStore, vehicleStore, storageUnitStore } = useSceneContext(); const { setArmBotActive, setArmBotState, removeCurrentAction, incrementActiveTime, incrementIdleTime } = armBotStore(); const { decrementVehicleLoad, removeLastMaterial } = vehicleStore(); const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = storageUnitStore(); const { getMaterialById, setIsVisible, setIsPaused } = materialStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore(); const { triggerPointActions } = useTriggerHandler(); const { isPlaying } = usePlayButtonStore(); diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx index aa0b9f6..ecd50b2 100644 --- a/app/src/modules/simulation/simulator/simulator.tsx +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -3,12 +3,13 @@ import { useProductStore } from '../../../store/simulation/useProductStore'; import { useActionHandler } from '../actions/useActionHandler'; import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore'; import { determineExecutionOrder } from './functions/determineExecutionOrder'; -import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; +import { useProductContext } from '../products/productContext'; function Simulator() { + const { selectedProductStore } = useProductContext(); const { products, getProductById } = useProductStore(); const { handleAction } = useActionHandler(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { isPlaying } = usePlayButtonStore(); const { isReset } = useResetButtonStore(); diff --git a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx index 7a835f7..5624582 100644 --- a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx +++ b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { useSelectedAction, useSelectedEventSphere, useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { useSelectedAction, useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore'; import { useGLTF } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; import { useProductStore } from '../../../../store/simulation/useProductStore'; @@ -11,6 +11,7 @@ import armPick from "../../../../assets/gltf-glb/ui/arm_ui_pick.glb"; import armDrop from "../../../../assets/gltf-glb/ui/arm_ui_drop.glb"; import { upsertProductOrEventApi } from '../../../../services/simulation/products/UpsertProductOrEventApi'; import { useSceneContext } from '../../../scene/sceneContext'; +import { useProductContext } from '../../products/productContext'; type Positions = { pick: [number, number, number]; @@ -21,7 +22,8 @@ type Positions = { const ArmBotUI = () => { const { getEventByModelUuid, updateAction, getActionByUuid } = useProductStore(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { scene } = useThree(); const { selectedAction } = useSelectedAction(); const { armBotStore } = useSceneContext(); diff --git a/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts b/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts index e1f7fbf..8794ffd 100644 --- a/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts +++ b/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts @@ -4,21 +4,19 @@ import { ThreeEvent, useThree } from "@react-three/fiber"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useSelectedEventData, - useSelectedProduct, } from "../../../../store/simulation/useSimulationStore"; +import { useProductContext } from "../../products/productContext"; type OnUpdateCallback = (object: THREE.Object3D) => void; export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { - const { getEventByModelUuid, updateAction, getActionByUuid } = - useProductStore(); + const { getEventByModelUuid } = useProductStore(); const { selectedEventData } = useSelectedEventData(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { camera, gl, controls } = useThree(); const activeObjRef = useRef(null); - const planeRef = useRef( - new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) - ); + const planeRef = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); const offsetRef = useRef(new THREE.Vector3()); const initialPositionRef = useRef(new THREE.Vector3()); diff --git a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx index c60e7e9..8765d14 100644 --- a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx @@ -5,7 +5,6 @@ import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedEventSphere, useIsDragging, - useSelectedProduct, useIsRotating, } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; @@ -15,6 +14,7 @@ import { DoubleSide, Group, Plane, Vector3 } from "three"; import startPoint from "../../../../assets/gltf-glb/ui/arrow_green.glb"; import startEnd from "../../../../assets/gltf-glb/ui/arrow_red.glb"; import { useSceneContext } from "../../../scene/sceneContext"; +import { useProductContext } from "../../products/productContext"; const VehicleUI = () => { const { scene: startScene } = useGLTF(startPoint) as any; @@ -23,8 +23,9 @@ const VehicleUI = () => { const endMarker = useRef(null); const prevMousePos = useRef({ x: 0, y: 0 }); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedProduct } = useSelectedProduct(); - const { vehicleStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); + const { vehicleStore } = useSceneContext(); + const { selectedProduct } = selectedProductStore(); const { vehicles, getVehicleById } = vehicleStore(); const { updateEvent } = useProductStore(); const [startPosition, setStartPosition] = useState<[number, number, number]>([ diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index 8ef5d1a..e349880 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -1,17 +1,18 @@ import { useCallback } from 'react'; import { useActionHandler } from '../../actions/useActionHandler'; import { useProductStore } from '../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useArmBotEventManager } from '../../roboticArm/eventManager/useArmBotEventManager'; import { useConveyorEventManager } from '../../conveyor/eventManager/useConveyorEventManager'; import { useVehicleEventManager } from '../../vehicle/eventManager/useVehicleEventManager'; import { useMachineEventManager } from '../../machine/eventManager/useMachineEventManager'; import { useSceneContext } from '../../../scene/sceneContext'; +import { useProductContext } from '../../products/productContext'; export function useTriggerHandler() { const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { handleAction } = useActionHandler(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getEventByTriggerUuid, getEventByModelUuid, getActionByUuid, getModelUuidByActionUuid } = useProductStore(); const { getArmBotById } = armBotStore(); const { getConveyorById } = conveyorStore(); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index b9339cc..38d38a8 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -5,10 +5,10 @@ import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/builder/store'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import MaterialAnimator from '../animator/materialAnimator'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) { const { navMesh } = useNavMesh(); @@ -20,7 +20,8 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) const { getConveyorById } = conveyorStore(); const { triggerPointActions } = useTriggerHandler(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = vehicleStore(); const [currentPhase, setCurrentPhase] = useState('stationed'); diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 2863e40..cca83af 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -1,61 +1,39 @@ -import React, { useEffect, useState } from "react"; -import ModuleToggle from "../components/ui/ModuleToggle"; -import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft"; -import SideBarRight from "../components/layout/sidebarRight/SideBarRight"; -import useModuleStore, { useThreeDStore } from "../store/useModuleStore"; -import RealTimeVisulization from "../modules/visualization/RealTimeVisulization"; -import Tools from "../components/ui/Tools"; +import React, { useEffect } from "react"; +import useModuleStore from "../store/useModuleStore"; import { useSocketStore, useOrganization, useUserName, useWallItems, useZones, - useLoadingProgress, - useWidgetSubOption, useSaveVersion, } from "../store/builder/store"; import { useNavigate } from "react-router-dom"; -import { usePlayButtonStore } from "../store/usePlayButtonStore"; -import MarketPlace from "../modules/market/MarketPlace"; -import LoadingPage from "../components/templates/LoadingPage"; -import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys"; import { useSelectedUserStore } from "../store/collaboration/useCollabStore"; import FollowPerson from "../components/templates/FollowPerson"; -import Scene from "../modules/scene/scene"; -import { createHandleDrop } from "../modules/visualization/functions/handleUiDrop"; -import { useSelectedZoneStore } from "../store/visualization/useZoneStore"; -import { useFloatingWidget } from "../store/visualization/useDroppedObjectsStore"; import { useLogger } from "../components/ui/log/LoggerContext"; import RenderOverlay from "../components/templates/Overlay"; import LogList from "../components/ui/log/LogList"; import Footer from "../components/footer/Footer"; -import SelectFloorPlan from "../components/temporary/SelectFloorPlan"; -import ControlsPlayer from "../components/layout/controls/ControlsPlayer"; -import CompareLayOut from "../components/ui/compareVersion/CompareLayOut"; import { useToggleStore } from "../store/useUIToggleStore"; -import RegularDropDown from "../components/ui/inputs/RegularDropDown"; import VersionSaved from "../components/layout/sidebarRight/versionHisory/VersionSaved"; -import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import { useAssetsStore } from "../store/builder/useAssetStore"; -import { useProductStore } from "../store/simulation/useProductStore"; -import ThreadChat from "../components/ui/collaboration/ThreadChat"; -import ComparisonResult from "../components/ui/compareVersion/ComparisonResult"; +import ComparisonSceneProvider from "../components/layout/scenes/ComparisonSceneProvider"; +import MainSceneProvider from "../components/layout/scenes/MainSceneProvider"; const Project: React.FC = () => { let navigate = useNavigate(); const echo = useLogger(); const { setToggleUI } = useToggleStore(); - const { activeModule, setActiveModule } = useModuleStore(); - const { loadingProgress } = useLoadingProgress(); const { setAssets } = useAssetsStore(); const { setUserName } = useUserName(); const { setOrganization } = useOrganization(); const { setWallItems } = useWallItems(); const { setZones } = useZones(); const { isVersionSaved } = useSaveVersion(); - const { products } = useProductStore(); + const { selectedUser } = useSelectedUserStore(); + const { isLogListVisible } = useLogger(); useEffect(() => { if (!isVersionSaved) { @@ -85,84 +63,10 @@ const Project: React.FC = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - // global store - const { toggleThreeD } = useThreeDStore(); - - // simulation store - const { isPlaying } = usePlayButtonStore(); - - // collaboration store - const { selectedUser } = useSelectedUserStore(); - const { isLogListVisible } = useLogger(); - - // real-time visualization store - const { widgetSubOption } = useWidgetSubOption(); - const { visualizationSocket } = useSocketStore(); - const { selectedZone } = useSelectedZoneStore(); - const { setFloatingWidget } = useFloatingWidget(); - - const [selectedLayout, setSelectedLayout] = useState(null); // Track selected layout - - const dummyLayouts = [ - { id: 1, name: "Layout 1" }, - { id: 2, name: "Layout 2" }, - { id: 3, name: "Layout 3" }, - { id: 4, name: "Layout 4" }, - ]; - - const handleSelectLayout = (option: string) => { - setSelectedLayout(option); // Set selected layout - console.log("Selected layout:", option); - }; return (
- {!selectedUser && ( - <> - - {loadingProgress > 0 && } - {!isPlaying && ( - <> - {toggleThreeD && } - - - - )} - - {activeModule === "market" && } - {activeModule !== "market" && !isPlaying && !isVersionSaved && ( - - )} - {isPlaying && activeModule === "simulation" && } - {isPlaying && activeModule !== "simulation" && } - - {/* remove this later */} - {activeModule === "builder" && !toggleThreeD && } - - )} -
- createHandleDrop({ - widgetSubOption, - visualizationSocket, - selectedZone, - setFloatingWidget, - event, - }) - } - onDragOver={(event) => event.preventDefault()} - > - -
+ + {selectedUser && } {isLogListVisible && ( @@ -170,20 +74,6 @@ const Project: React.FC = () => { )} {activeModule !== "market" && !selectedUser &&
} - {isVersionSaved && activeModule === "simulation" && ( - <> -
- l.productName)} // Pass layout names as options - onSelect={handleSelectLayout} - search={false} - /> -
- - {false && } - - )}
); diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts index b3d3c78..9d9df4b 100644 --- a/app/src/store/simulation/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -74,23 +74,27 @@ interface SelectedProductState { clearSelectedProduct: () => void; } -export const useSelectedProduct = create()( - immer((set) => ({ - selectedProduct: { productId: '', productName: '' }, - setSelectedProduct: (productId, productName) => { - set((state) => { - state.selectedProduct.productId = productId; - state.selectedProduct.productName = productName; - }); - }, - clearSelectedProduct: () => { - set((state) => { - state.selectedProduct.productId = ''; - state.selectedProduct.productName = ''; - }); - }, - })) -); +export const createSelectedProductStore = () => { + return create()( + immer((set) => ({ + selectedProduct: { productId: '', productName: '' }, + setSelectedProduct: (productId, productName) => { + set((state) => { + state.selectedProduct.productId = productId; + state.selectedProduct.productName = productName; + }); + }, + clearSelectedProduct: () => { + set((state) => { + state.selectedProduct.productId = ''; + state.selectedProduct.productName = ''; + }); + }, + })) + ) +} + +export type SelectedProductType = ReturnType; interface SelectedActionState { selectedAction: { actionId: string | null; actionName: string | null }; @@ -146,4 +150,48 @@ export const useIsRotating = create()( }); }, })) +); + +interface MainProductState { + mainProduct: { productId: string; productName: string } | null; + setMainProduct: (productId: string, productName: string) => void; + clearMainProduct: () => void; +} + +export const useMainProduct = create()( + immer((set) => ({ + mainProduct: null, + setMainProduct: (productId: string, productName: string) => { + set((state) => { + state.mainProduct = { productId, productName }; + }); + }, + clearMainProduct: () => { + set((state) => { + state.mainProduct = null; + }); + }, + })) +); + +interface ComparisonProductState { + comparisonProduct: { productId: string; productName: string } | null; + setComparisonProduct: (productId: string, productName: string) => void; + clearComparisonProduct: () => void; +} + +export const useComparisonProduct = create()( + immer((set) => ({ + comparisonProduct: null, + setComparisonProduct: (productId: string, productName: string) => { + set((state) => { + state.comparisonProduct = { productId, productName }; + }); + }, + clearComparisonProduct: () => { + set((state) => { + state.comparisonProduct = null; + }); + }, + })) ); \ No newline at end of file diff --git a/app/src/styles/layout/compareLayout.scss b/app/src/styles/layout/compareLayout.scss index e17f227..e7d54c6 100644 --- a/app/src/styles/layout/compareLayout.scss +++ b/app/src/styles/layout/compareLayout.scss @@ -2,585 +2,588 @@ @use "../abstracts/mixins" as *; .initial-selectLayout-wrapper { - position: fixed; - top: 100px; - left: 40px; - z-index: 10; + position: fixed; + top: 100px; + right: 40px; + z-index: 10; - .regularDropdown-container { - background: var(--background-color); - } + .regularDropdown-container { + background: var(--background-color); + } +} + +.selectLayout-wrapper { + position: fixed; + left: 40px; + top: 100px; + z-index: 10; + + .regularDropdown-container { + background: var(--background-color); + } } .compareLayOut-wrapper { - position: fixed; - top: 0; - right: 0; - z-index: 2; - height: 100vh; - background: var(--background-color); - backdrop-filter: blur(20px); - display: flex; - justify-content: center; - align-items: center; - animation: slideInFromRight 0.4s ease-out forwards; - user-select: none; - - .selectLayout-wrapper { - position: absolute; - top: 100px; - right: 40px; - - .regularDropdown-container { - background: var(--background-color); - } - } - - .resizer { - width: 32px; - height: 32px; - @include flex-center; - padding: 6px; - position: absolute; - top: 50%; - left: 0; - transform: translate(-50%, -50%); + position: fixed; + top: 0; + right: 0; + z-index: 2; + height: 100vh; background: var(--background-color); backdrop-filter: blur(20px); - box-shadow: $box-shadow-heavy; - border-radius: 50%; - cursor: ew-resize; - transition: transform 0.1s ease; - z-index: 10; - } - - .chooseLayout-container { - width: 100%; - height: 100%; display: flex; justify-content: center; align-items: center; - position: relative; - overflow: hidden; + animation: slideInFromRight 0.4s ease-out forwards; + user-select: none; - .compare-layout-canvas-container { - position: absolute; - height: 100vh; - width: 100vw; - top: 0; - right: 0; - } - - .chooseLayout-wrapper { - background: var(--background-color); - backdrop-filter: blur(20px); - padding: 20px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - max-width: 80%; - text-align: center; - position: relative; - - .icon { - width: 100%; - margin-bottom: 15px; - text-align: center; - - svg { - width: 100%; - } - } - - .value { - margin-bottom: 15px; - font-size: var(--font-size-small); - font-weight: 500; - color: var(--text-primary); - } - - button { - display: block; - margin: 0 auto; - padding: 8px 16px; - background: var(--background-color-button); - color: var(--icon-default-color-active); - border: none; - border-radius: 4px; - cursor: pointer; - transition: all 0.2s ease; - - &:hover { - transform: translateY(-1px); - } - } - - .displayLayouts-container { - max-width: 170px; - height: auto; + .resizer { + width: 32px; + height: 32px; + @include flex-center; + padding: 6px; + position: absolute; + top: 50%; + left: 0; + transform: translate(-50%, -50%); background: var(--background-color); backdrop-filter: blur(20px); - padding: 6px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - position: absolute; - right: 0; - top: 100%; - transform: translate(50%, -10px); - display: flex; - flex-direction: column; - gap: 6px; - - .header { - text-align: left; - padding-top: 6px; - padding-left: 6px; - } - - .search-wrapper { - padding: 6px 0; - - .search-container { - padding: 0; - border-radius: 6px; - } - } - - .layouts-container { - .layout { - padding: 6px 0; - } - - .layout-wrapper { - display: flex; - align-items: center; - gap: 6px; - cursor: pointer; - padding: 0 10px; - background: none; - width: 100%; - - &:hover { - background-color: var(--highlight-text-color) !important; - border-radius: 4px; - - .layout { - color: var(--text-button-color) !important; - } - - svg { - path { - fill: var(--text-button-color) !important; - } - } - } - } - } - } + box-shadow: $box-shadow-heavy; + border-radius: 50%; + cursor: ew-resize; + transition: transform 0.1s ease; + z-index: 10; + } + + .chooseLayout-container { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + position: relative; + overflow: hidden; + + .compare-layout-canvas-container { + position: absolute; + height: 100vh; + width: 100vw; + top: 0; + right: 0; + } + + .chooseLayout-wrapper { + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 20px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + max-width: 80%; + text-align: center; + position: relative; + + .icon { + width: 100%; + margin-bottom: 15px; + text-align: center; + + svg { + width: 100%; + } + } + + .value { + margin-bottom: 15px; + font-size: var(--font-size-small); + font-weight: 500; + color: var(--text-primary); + } + + button { + display: block; + margin: 0 auto; + padding: 8px 16px; + background: var(--background-color-button); + color: var(--icon-default-color-active); + border: none; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + transform: translateY(-1px); + } + } + + .displayLayouts-container { + max-width: 170px; + height: auto; + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 6px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + position: absolute; + right: 0; + top: 100%; + transform: translate(50%, -10px); + display: flex; + flex-direction: column; + gap: 6px; + + .header { + text-align: left; + padding-top: 6px; + padding-left: 6px; + } + + .search-wrapper { + padding: 6px 0; + + .search-container { + padding: 0; + border-radius: 6px; + } + } + + .layouts-container { + .layout { + padding: 6px 0; + } + + .layout-wrapper { + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; + padding: 0 10px; + background: none; + width: 100%; + + &:hover { + background-color: var( + --highlight-text-color + ) !important; + border-radius: 4px; + + .layout { + color: var(--text-button-color) !important; + } + + svg { + path { + fill: var(--text-button-color) !important; + } + } + } + } + } + } + } } - } } .compare-result-container { - display: flex; - flex-direction: column; - gap: 6px; - position: fixed; - bottom: 40px; - width: 100%; - min-height: 200px; - z-index: 10; - background: var(--background-color-secondary); - backdrop-filter: blur(20px); - padding: 18px 8px; - - .header { - width: fit-content; - background-color: var(--background-color-solid); - color: var(--background-color-accent); - padding: 6px 10px; - border-radius: 6px; - } - - .compare-result-wrapper { display: flex; - gap: 12px; + flex-direction: column; + gap: 6px; + position: fixed; + bottom: 40px; + width: 100%; + min-height: 200px; + z-index: 10; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + padding: 18px 8px; - .comparisionCard { - position: relative; - flex: 1; - width: auto; - max-height: 200px; - background: var(--background-color); - outline: 1px solid var(--border-color); - outline-offset: -1px; - border-radius: 12px; - padding: 8px 12px; - overflow: hidden; + .header { + width: fit-content; + background-color: var(--background-color-solid); + color: var(--background-color-accent); + padding: 6px 10px; + border-radius: 6px; } - .performanceResult-wrapper { - min-width: 328px; - flex: 0; - position: relative; - padding-right: 65px; - - .header { + .compare-result-wrapper { display: flex; gap: 12px; - align-items: center; - } - .metrics-container { - display: flex; - gap: 12px; - height: 100%; + .comparisionCard { + position: relative; + flex: 1; + width: auto; + max-height: 200px; + background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: 12px; + padding: 8px 12px; + overflow: hidden; + } - .metrics-left { - display: flex; - flex-direction: column; - justify-content: space-around; - height: 100%; + .performanceResult-wrapper { + min-width: 328px; + flex: 0; + position: relative; + padding-right: 65px; - .metric { - .metric-label { - display: flex; - align-items: center; - gap: 6px; - - span { + .header { display: flex; - } + gap: 12px; + align-items: center; } - .metric-value { - padding-top: 6px; - font-size: var(--font-size-xlarge); - color: var(--background-color-accent); - font-weight: 600; + + .metrics-container { + display: flex; + gap: 12px; + height: 100%; + + .metrics-left { + display: flex; + flex-direction: column; + justify-content: space-around; + height: 100%; + + .metric { + .metric-label { + display: flex; + align-items: center; + gap: 6px; + + span { + display: flex; + } + } + .metric-value { + padding-top: 6px; + font-size: var(--font-size-xlarge); + color: var(--background-color-accent); + font-weight: 600; + } + } + + .label { + padding-bottom: 68px; + } + } + + .metrics-right { + height: fit-content; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(2, 1fr); + + gap: 2px; + overflow: visible; + + margin: auto 0; + + .metric-wrapper { + position: relative; + width: 64px; + height: 50px; + overflow: visible; // allow content like labels to overflow + + &:nth-child(1) { + .metric-label { + top: -57%; + left: 220%; + } + &::after { + content: ""; + position: absolute; + + top: -100%; + left: 50%; + width: 100%; // Required for visible shape + height: 40px; + background-color: #b7b7c6; + + // Custom polygon shape (adjust if needed) + clip-path: polygon( + 96% 52%, + 96% 54%, + 45% 53%, + 3% 100%, + 0 100%, + 42% 52% + ); + + z-index: 0; // Behind any inner content + } + } + + // Optional: content above the shape + > * { + position: relative; + z-index: 1; + } + + &:nth-child(2) { + grid-column-start: 1; + grid-row-start: 2; + .metric-label { + white-space: normal; + width: 50px; + left: 230%; + } + } + &:nth-child(3) { + grid-row: span 2 / span 2; + grid-column-start: 2; + grid-row-start: 1; + margin-top: 40%; + left: -16px; + position: relative; + } + } + + .metric-label { + position: absolute; + top: 0px; + left: 0%; + white-space: nowrap; + + transform: translate(-50%, -50%); + + font-size: 10px; + z-index: 1; + } + + .metric { + width: 100%; + height: 100%; + position: relative; + display: flex; + justify-content: center; + align-items: center; + + &::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + background: var(--background-color, wheat); + clip-path: polygon( + 25% 0%, + 75% 0%, + 100% 50%, + 75% 100%, + 25% 100%, + 0% 50% + ); + filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); + + z-index: 0; + } + + // Content stays above the shape + > * { + position: relative; + z-index: 1; + } + } + } } - } - .label { - padding-bottom: 68px; - } - } + .simulation-tag { + background: var(--background-color-button); - .metrics-right { - height: fit-content; - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-template-rows: repeat(2, 1fr); - - gap: 2px; - overflow: visible; - - margin: auto 0; - - .metric-wrapper { - position: relative; - width: 64px; - height: 50px; - overflow: visible; // allow content like labels to overflow - - &:nth-child(1) { - .metric-label { - top: -57%; - left: 220%; - } - &::after { - content: ""; + color: var(--icon-default-color-active); position: absolute; - - top: -100%; - left: 50%; - width: 100%; // Required for visible shape - height: 40px; - background-color: #b7b7c6; - - // Custom polygon shape (adjust if needed) - clip-path: polygon( - 96% 52%, - 96% 54%, - 45% 53%, - 3% 100%, - 0 100%, - 42% 52% - ); - - z-index: 0; // Behind any inner content - } + bottom: 0; + right: 0; + padding: 10px 5px; + border-radius: 12px 0 0 0; } - - // Optional: content above the shape - > * { - position: relative; - z-index: 1; - } - - &:nth-child(2) { - grid-column-start: 1; - grid-row-start: 2; - .metric-label { - white-space: normal; - width: 50px; - left: 230%; - } - } - &:nth-child(3) { - grid-row: span 2 / span 2; - grid-column-start: 2; - grid-row-start: 1; - margin-top: 40%; - left: -16px; - position: relative; - } - } - - .metric-label { - position: absolute; - top: 0px; - left: 0%; - white-space: nowrap; - - transform: translate(-50%, -50%); - - font-size: 10px; - z-index: 1; - } - - .metric { - width: 100%; - height: 100%; - position: relative; - display: flex; - justify-content: center; - align-items: center; - - &::after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - - background: var(--background-color, wheat); - clip-path: polygon( - 25% 0%, - 75% 0%, - 100% 50%, - 75% 100%, - 25% 100%, - 0% 50% - ); - filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); - - z-index: 0; - } - - // Content stays above the shape - > * { - position: relative; - z-index: 1; - } - } } - } - - .simulation-tag { - background: var(--background-color-button); - - color: var(--icon-default-color-active); - position: absolute; - bottom: 0; - right: 0; - padding: 10px 5px; - border-radius: 12px 0 0 0; - } } - } } @keyframes slideInFromRight { - from { - transform: translateX(100%); - opacity: 0; - } + from { + transform: translateX(100%); + opacity: 0; + } - to { - transform: translateX(0); - opacity: 1; - } + to { + transform: translateX(0); + opacity: 1; + } } .energy-usage { - position: relative; + position: relative; - .energy-usage-wrapper { - h4 { - font-weight: 600; + .energy-usage-wrapper { + h4 { + font-weight: 600; + } + + .value { + padding-top: 25px; + font-size: var(--font-size-xxxlarge); + color: var(--background-color-accent); + } } - .value { - padding-top: 25px; - font-size: var(--font-size-xxxlarge); - color: var(--background-color-accent); + .simulation-details { + position: absolute; + bottom: 12px; + right: 12px; + + .simulation-wrapper { + display: flex; + align-items: center; + gap: 6px; + + .icon { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: var(--background-color-accent); + } + } } - } - .simulation-details { - position: absolute; - bottom: 12px; - right: 12px; - - .simulation-wrapper { - display: flex; - align-items: center; - gap: 6px; - - .icon { - width: 20px; - height: 20px; - border-radius: 50%; - background-color: var(--background-color-accent); - } + .chart { + width: 90%; + position: absolute; + top: 10px; + left: 0; } - } - - .chart { - width: 90%; - position: absolute; - top: 10px; - left: 0; - } } .throughPutCard-container { - .layers-wrapper { - padding: 20px 10px; - height: 100%; - width: 100%; - display: flex; - justify-content: space-between; + .layers-wrapper { + padding: 20px 10px; + height: 100%; + width: 100%; + display: flex; + justify-content: space-between; - .layer-wrapper { - display: flex; - flex-direction: column; + .layer-wrapper { + display: flex; + flex-direction: column; - &:last-child { - justify-content: end; - } + &:last-child { + justify-content: end; + } + } } - } - .chart { - height: 90%; - position: absolute; - bottom: 0; - left: 0; - } + .chart { + height: 90%; + position: absolute; + bottom: 0; + left: 0; + } } .cycle-time-container { - .cycle-main { - display: flex; - justify-content: space-between; - height: 100%; - - .layers-wrapper { - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - - .layers { + .cycle-main { display: flex; - flex-direction: column; - gap: 4px; + justify-content: space-between; + height: 100%; - .layer-name { - color: var(--background-color-accent); + .layers-wrapper { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + + .layers { + display: flex; + flex-direction: column; + gap: 4px; + + .layer-name { + color: var(--background-color-accent); + } + + .layer-time { + font-size: var(--font-size-large); + } + + .layer-profit { + color: #14ca44; + text-align: end; + + span { + color: #14ca44; + } + } + } } - - .layer-time { - font-size: var(--font-size-large); - } - - .layer-profit { - color: #14ca44; - text-align: end; - - span { - color: #14ca44; - } - } - } } - } } .overallDowntime-container { - .totalDownTime-wrapper { - display: flex; - - .totalDownTime { - width: 70%; - background: var(--background-color-secondary); - backdrop-filter: blur(20px); - border-radius: 12px; - - display: flex; - justify-content: space-between; - align-items: center; - gap: 20px; - padding: 8px 10px; - margin: 44px 0; - - .totalDownTime-right { + .totalDownTime-wrapper { display: flex; - flex-direction: column; - gap: 6px; - } - .totalDownTime-left { - display: flex; - align-items: center; - gap: 6px; + .totalDownTime { + width: 70%; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + border-radius: 12px; - .value { - font-size: var(--font-size-xlarge); - color: var(--background-color-button); + display: flex; + justify-content: space-between; + align-items: center; + gap: 20px; + padding: 8px 10px; + margin: 44px 0; + + .totalDownTime-right { + display: flex; + flex-direction: column; + gap: 6px; + } + + .totalDownTime-left { + display: flex; + align-items: center; + gap: 6px; + + .value { + font-size: var(--font-size-xlarge); + color: var(--background-color-button); + } + } } - } - } - .chart { - width: 30%; - position: relative; + .chart { + width: 30%; + position: relative; + } } - } } .overallScrapRate { - .overallScrapRate-wrapper { - display: flex; + .overallScrapRate-wrapper { + display: flex; - .overallScrapRate-value { - width: 50%; - display: flex; - flex-direction: column; - gap: 6px; - margin: 40px 0; + .overallScrapRate-value { + width: 50%; + display: flex; + flex-direction: column; + gap: 6px; + margin: 40px 0; - .overallScrapRate-key { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } + .overallScrapRate-key { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .chart { + width: 50%; + position: relative; + } } - - .chart { - width: 50%; - position: relative; - } - } } -- 2.49.1 From e26de7e651bed8e1a6ad456b1a8c97242ef2a08b Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 12:08:15 +0530 Subject: [PATCH 16/34] refactor: Update selectedObjects iteration method in SelectionControls --- .../selectionControls/boundingBoxHelper.tsx | 120 ++++++++++++------ .../selectionControls/selectionControls.tsx | 2 +- 2 files changed, 79 insertions(+), 43 deletions(-) diff --git a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx index e549b1d..d1d3cfd 100644 --- a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx +++ b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx @@ -3,60 +3,96 @@ import { useMemo } from "react"; import * as THREE from "three"; import { useSelectedAssets } from "../../../../store/builder/store"; -const BoundingBox = ({ boundingBoxRef }: any) => { +interface BoundingBoxProps { + boundingBoxRef?: any; + isPerAsset?: boolean; +} + +const getBoxLines = (min: THREE.Vector3, max: THREE.Vector3) => [ + [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], +]; + +const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => { const { selectedAssets } = useSelectedAssets(); + const savedTheme: string = localStorage.getItem("theme") || "light"; - const { points, boxProps } = useMemo(() => { - if (selectedAssets.length === 0) return { points: [], boxProps: {} }; + const boxes = useMemo(() => { + if (selectedAssets.length === 0) return []; - const box = new THREE.Box3(); - selectedAssets.forEach((obj: any) => box.expandByObject(obj.clone())); + if (isPerAsset) { + return selectedAssets.map((obj: any) => { + const box = new THREE.Box3().setFromObject(obj.clone()); + const size = new THREE.Vector3(); + const center = new THREE.Vector3(); + box.getSize(size); + box.getCenter(center); - 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 halfSize = size.clone().multiplyScalar(0.5); - const min = center.clone().sub(halfSize); - const max = center.clone().add(halfSize); + return { + points: getBoxLines(min, max), + position: center.toArray(), + size: size.toArray(), + }; + }); + } else { + const box = new THREE.Box3(); + selectedAssets.forEach((obj: any) => box.expandByObject(obj.clone())); + const size = new THREE.Vector3(); + const center = new THREE.Vector3(); + box.getSize(size); + box.getCenter(center); - 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], + const halfSize = size.clone().multiplyScalar(0.5); + const min = center.clone().sub(halfSize); + const max = center.clone().add(halfSize); - [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: getBoxLines(min, max), + position: center.toArray(), + size: size.toArray(), + }, + ]; + } + }, [selectedAssets, isPerAsset]); return ( <> - {points.length > 0 && ( - <> - - - + {boxes.map((box: any, index: number) => ( + + + + - - )} + + ))} ); }; diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 2dcd775..477fc98 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -158,7 +158,7 @@ const SelectionControls: React.FC = () => { let selectedObjects = selectionBox.select(); let Objects = new Set(); - selectedObjects.map((object) => { + selectedObjects.forEach((object) => { let currentObject: THREE.Object3D | null = object; while (currentObject) { if (currentObject.userData.modelUuid) { -- 2.49.1 From e72854d51404ff87baf8ffc985ce31f9d5a9fc9d Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 12:55:17 +0530 Subject: [PATCH 17/34] refactor: Update asset properties and selection controls for improved functionality using shift click functionality --- .../properties/AssetProperties.tsx | 2 +- .../builder/asset/models/model/model.tsx | 2 - .../selectionControls/boundingBoxHelper.tsx | 4 +- .../selectionControls/selectionControls.tsx | 64 ++++++++++++++++++- .../modules/scene/tools/measurementTool.tsx | 2 +- .../modules/simulation/products/products.tsx | 4 -- 6 files changed, 66 insertions(+), 12 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx index 85a7539..4223129 100644 --- a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx @@ -48,7 +48,7 @@ const AssetProperties: React.FC = () => { return (
{/* Name */} -
{selectedFloorItem.userData.name}
+
{selectedFloorItem.userData.modelName}
{objectPosition.x && objectPosition.z && ) => { if (activeTool === "cursor" && subModule === 'simulations') { if (asset.modelUuid) { diff --git a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx index d1d3cfd..32fcce7 100644 --- a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx +++ b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx @@ -75,8 +75,9 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => return ( <> {boxes.map((box: any, index: number) => ( - + segments /> { - const { camera, controls, gl, scene, pointer } = useThree(); + const { camera, controls, gl, scene, raycaster, pointer } = useThree(); const selectionGroup = useRef() as Types.RefGroup; const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); @@ -39,10 +39,13 @@ const SelectionControls: React.FC = () => { const canvasElement = gl.domElement; canvasElement.tabIndex = 0; + let isDragging = false; + let isLeftMouseDown = false; let isSelecting = false; let isRightClick = false; let rightClickMoved = false; let isCtrlSelecting = false; + let isShiftSelecting = false; const helper = new SelectionHelper(gl); @@ -53,6 +56,9 @@ const SelectionControls: React.FC = () => { } else if (event.button === 0) { isSelecting = false; isCtrlSelecting = event.ctrlKey; + isShiftSelecting = event.shiftKey; + isLeftMouseDown = true; + isDragging = false; if (event.ctrlKey && duplicatedObjects.length === 0) { if (controls) (controls as any).enabled = false; selectionBox.startPoint.set(pointer.x, pointer.y, 0); @@ -64,6 +70,9 @@ const SelectionControls: React.FC = () => { if (isRightClick) { rightClickMoved = true; } + if (isLeftMouseDown) { + isDragging = true; + } isSelecting = true; if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting) { selectionBox.endPoint.set(pointer.x, pointer.y, 0); @@ -71,7 +80,7 @@ const SelectionControls: React.FC = () => { }; const onPointerUp = (event: PointerEvent) => { - if (event.button === 2) { + if (event.button === 2 && !event.ctrlKey && !event.shiftKey) { isRightClick = false; if (!rightClickMoved) { clearSelection(); @@ -85,10 +94,59 @@ const SelectionControls: React.FC = () => { 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)) { + } else if (!isSelecting && selectedAssets.length > 0 && ((!event.ctrlKey && !event.shiftKey && pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) || event.button !== 0)) { clearSelection(); helper.enabled = true; isCtrlSelecting = false; + } else if (controls) { + (controls as any).enabled = true; + } + + if (!isDragging && isLeftMouseDown && isShiftSelecting && event.shiftKey) { + isShiftSelecting = false; + isLeftMouseDown = false; + isDragging = false; + + 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.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && + intersect.object.type !== "GridHelper" + ); + if (intersects.length > 0) { + const intersect = intersects[0]; + const intersectObject = intersect.object; + + let currentObject: THREE.Object3D | null = intersectObject; + while (currentObject) { + if (currentObject.userData.modelUuid) { + break; + } + currentObject = currentObject.parent || null; + } + + if (currentObject) { + const updatedSelections = new Set(selectedAssets); + + if (updatedSelections.has(currentObject)) { + updatedSelections.delete(currentObject); + } else { + updatedSelections.add(currentObject); + } + + const selected = Array.from(updatedSelections); + + setSelectedAssets(selected); + } + } } }; diff --git a/app/src/modules/scene/tools/measurementTool.tsx b/app/src/modules/scene/tools/measurementTool.tsx index a70dd8a..f9d6ae7 100644 --- a/app/src/modules/scene/tools/measurementTool.tsx +++ b/app/src/modules/scene/tools/measurementTool.tsx @@ -51,7 +51,7 @@ const MeasurementTool = () => { !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && - !(intersect.object.type === "GridHelper") + intersect.object.type !== "GridHelper" ); if (intersects.length > 0) { diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 1b08013..7e019a5 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -35,10 +35,6 @@ function Products() { } }, [comparisonProduct]) - useEffect(() => { - console.log(selectedProduct); - }, [selectedProduct]) - useEffect(() => { const email = localStorage.getItem('email') const organization = (email!.split("@")[1]).split(".")[0]; -- 2.49.1 From 24810d0eeb2362d9a63afdf0992e5a77c1b77993 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 13:06:02 +0530 Subject: [PATCH 18/34] refactor: Enhance intersection filtering by adding zonePlane and selection group exclusions --- app/src/modules/builder/groups/zoneGroup.tsx | 3 +- .../collaboration/comments/commentsGroup.tsx | 18 +++++++--- .../selectionControls/selectionControls.tsx | 2 ++ .../modules/scene/tools/measurementTool.tsx | 14 +++++++- .../triggerConnections/triggerConnector.tsx | 12 +++++-- .../widgets/3d/Dropped3dWidget.tsx | 36 ++++++++++++------- 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 5b567af..21ba6cc 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -553,7 +553,7 @@ const ZoneGroup: React.FC = () => { const midpoint = new THREE.Vector3( (point1.x + point2.x) / 2, CONSTANTS.zoneConfig.height / 2 + - (zone.layer - 1) * CONSTANTS.zoneConfig.height, + (zone.layer - 1) * CONSTANTS.zoneConfig.height, (point1.z + point2.z) / 2 ); @@ -564,6 +564,7 @@ const ZoneGroup: React.FC = () => { return ( !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && - !intersect.object.name.includes("commentHolder") && !intersect.object.name.includes("agv-collider") && - !(intersect.object.type === "GridHelper") + !intersect.object.name.includes("zonePlane") && + !intersect.object.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && + intersect.object.type !== "GridHelper" ); if (intersects.length > 0) { @@ -67,9 +72,14 @@ function CommentsGroup() { (intersect) => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && - !intersect.object.name.includes("commentHolder") && !intersect.object.name.includes("agv-collider") && - !(intersect.object.type === "GridHelper") + !intersect.object.name.includes("zonePlane") && + !intersect.object.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && + intersect.object.type !== "GridHelper" ); if (intersects.length > 0) { const position = new Vector3(intersects[0].point.x, Math.max(intersects[0].point.y, 0), intersects[0].point.z); diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index db072d2..02faf56 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -114,6 +114,7 @@ const SelectionControls: React.FC = () => { !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("zonePlane") && !intersect.object.name.includes("SelectionGroup") && !intersect.object.name.includes("selectionAssetGroup") && !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && @@ -124,6 +125,7 @@ const SelectionControls: React.FC = () => { if (intersects.length > 0) { const intersect = intersects[0]; const intersectObject = intersect.object; + console.log('intersectObject: ', intersectObject); let currentObject: THREE.Object3D | null = intersectObject; while (currentObject) { diff --git a/app/src/modules/scene/tools/measurementTool.tsx b/app/src/modules/scene/tools/measurementTool.tsx index f9d6ae7..1da41b3 100644 --- a/app/src/modules/scene/tools/measurementTool.tsx +++ b/app/src/modules/scene/tools/measurementTool.tsx @@ -51,6 +51,12 @@ const MeasurementTool = () => { !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("zonePlane") && + !intersect.object.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && intersect.object.type !== "GridHelper" ); @@ -106,7 +112,13 @@ const MeasurementTool = () => { !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && - !(intersect.object.type === "GridHelper") + !intersect.object.name.includes("zonePlane") && + !intersect.object.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && + intersect.object.type !== "GridHelper" ); if (intersects.length > 0) { diff --git a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx index d082419..09048b4 100644 --- a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx +++ b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx @@ -368,12 +368,18 @@ function TriggerConnector() { 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.name.includes("agv-collider") && + !intersect.object.name.includes("zonePlane") && + !intersect.object.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && + intersect.object.type !== "GridHelper" && !intersect.object.name.includes("ArrowWithTube") && !intersect.object.parent?.name.includes("Zone") && - !(intersect.object.type === "GridHelper") && - !(intersect.object.type === "Line2") + intersect.object.type !== "Line2" ); let point: THREE.Vector3 | null = null; diff --git a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx index ccb88c4..601309a 100644 --- a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx +++ b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx @@ -138,9 +138,15 @@ export default function Dropped3dWidgets() { .filter( (intersect) => !intersect.object.name.includes("Roof") && - !intersect.object.name.includes("agv-collider") && !intersect.object.name.includes("MeasurementReference") && - !(intersect.object.type === "GridHelper") + !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("zonePlane") && + !intersect.object.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && + intersect.object.type !== "GridHelper" ); if (intersects.length > 0) { @@ -174,9 +180,15 @@ export default function Dropped3dWidgets() { .filter( (intersect) => !intersect.object.name.includes("Roof") && - !intersect.object.name.includes("agv-collider") && !intersect.object.name.includes("MeasurementReference") && - !(intersect.object.type === "GridHelper") + !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("zonePlane") && + !intersect.object.name.includes("SelectionGroup") && + !intersect.object.name.includes("selectionAssetGroup") && + !intersect.object.name.includes("SelectionGroupBoundingBoxLine") && + !intersect.object.name.includes("SelectionGroupBoundingBox") && + !intersect.object.name.includes("SelectionGroupBoundingLine") && + intersect.object.type !== "GridHelper" ); // Update widget's position in memory if (intersects.length > 0) { @@ -412,7 +424,7 @@ export default function Dropped3dWidgets() { } } }; - + const handleMouseMove = (event: MouseEvent) => { if (!rightClickSelected || !rightSelect) return; @@ -477,9 +489,9 @@ export default function Dropped3dWidgets() { // // planeIntersect.current // // ); // // console.log('intersect: ', intersect); - + // let intersect = event.clientY - + // if (intersect && typeof intersectcontextmenu === "number") { // console.log('intersect: ', intersect); // const diff = intersect - intersectcontextmenu; @@ -504,21 +516,21 @@ export default function Dropped3dWidgets() { lastClientY.current = event.clientY; return; } - + const diff = lastClientY.current - event.clientY; // dragging up = increase Y const scaleFactor = 0.05; // tune this based on your scene scale - + const unclampedY = selectedWidget.position[1] + diff * scaleFactor; const newY = Math.max(0, unclampedY); - + lastClientY.current = event.clientY; - + const newPosition: [number, number, number] = [ selectedWidget.position[0], newY, selectedWidget.position[2], ]; - + updateWidgetPosition(selectedZoneId, rightClickSelected, newPosition); } -- 2.49.1 From 40d7cbbcc4fbff38489c38cb763c2dc5ab72b18c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 13:07:16 +0530 Subject: [PATCH 19/34] refactor: Remove debug log for intersected object in selection controls --- .../scene/controls/selectionControls/selectionControls.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 02faf56..0c158a9 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -125,7 +125,6 @@ const SelectionControls: React.FC = () => { if (intersects.length > 0) { const intersect = intersects[0]; const intersectObject = intersect.object; - console.log('intersectObject: ', intersectObject); let currentObject: THREE.Object3D | null = intersectObject; while (currentObject) { -- 2.49.1 From 95a98e131f7696d4312fc38a2def16b646863737 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 13:43:36 +0530 Subject: [PATCH 20/34] refactor: Remove unused imports and simplify JSX structure in AssetsGroup and Model components --- app/src/modules/builder/asset/assetsGroup.tsx | 6 +---- .../builder/asset/models/model/model.tsx | 27 ++++++++++++------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index e407d3c..04fd32b 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -12,7 +12,6 @@ import useModuleStore from "../../../store/useModuleStore"; import { useThree } from "@react-three/fiber"; import { CameraControls } from "@react-three/drei"; import addAssetModel from "./functions/addAssetModel"; -import { useSceneContext } from "../../scene/sceneContext"; const gltfLoaderWorker = new Worker( new URL( @@ -23,7 +22,6 @@ const gltfLoaderWorker = new Worker( function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) { const { activeModule } = useModuleStore(); - const { layout } = useSceneContext(); const { socket } = useSocketStore(); const { controls, gl, pointer, camera, raycaster } = useThree(); const { setLoadingProgress } = useLoadingProgress(); @@ -292,9 +290,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea }, [selectedItem, camera, pointer, activeModule, controls]); return ( - <> - - + ) } diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index 14fe258..bbe857d 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -4,7 +4,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; import { ThreeEvent, useFrame, useThree } from '@react-three/fiber'; -import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore } from '../../../../../store/builder/store'; +import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView } from '../../../../../store/builder/store'; import { AssetBoundingBox } from '../../functions/assetBoundingBox'; import { CameraControls } from '@react-three/drei'; import { useAssetsStore } from '../../../../../store/builder/useAssetStore'; @@ -18,6 +18,7 @@ import { useProductContext } from '../../../../simulation/products/productContex function Model({ asset }: { readonly asset: Asset }) { const { camera, controls, gl } = useThree(); const { activeTool } = useActiveTool(); + const { toggleView } = useToggleView(); const { subModule } = useSubModuleStore(); const { activeModule } = useModuleStore(); const { removeAsset } = useAssetsStore(); @@ -249,20 +250,28 @@ function Model({ asset }: { readonly asset: Asset }) { visible={asset.isVisible} userData={asset} onDoubleClick={(e) => { - e.stopPropagation(); - handleDblClick(asset); + if (!toggleView) { + e.stopPropagation(); + handleDblClick(asset); + } }} onClick={(e) => { - e.stopPropagation(); - handleClick(asset); + if (!toggleView) { + e.stopPropagation(); + handleClick(asset); + } }} onPointerOver={(e) => { - e.stopPropagation(); - handlePointerOver(asset); + if (!toggleView) { + e.stopPropagation(); + handlePointerOver(asset); + } }} onPointerOut={(e) => { - e.stopPropagation(); - handlePointerOut(asset); + if (!toggleView) { + e.stopPropagation(); + handlePointerOut(asset); + } }} onContextMenu={(e) => { e.stopPropagation(); -- 2.49.1 From 879c47875362b97f0f5328930c196e02f2149a8c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 13:58:32 +0530 Subject: [PATCH 21/34] refactor: Add name to wall mesh for better identification in PolygonGenerator --- .../modules/simulation/vehicle/navMesh/polygonGenerator.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx index a1bbfb0..54f669b 100644 --- a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx +++ b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx @@ -44,7 +44,7 @@ export default function PolygonGenerator({ }); const polygons = turf.polygonize(turf.featureCollection(validLineFeatures)); - + renderWallGeometry(wallPoints); if (polygons.features.length > 0) { @@ -115,6 +115,7 @@ export default function PolygonGenerator({ const quaternion = new THREE.Quaternion(); quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction); wallMesh.quaternion.copy(quaternion); + wallMesh.name = "agv-collider"; groupRef.current?.add(wallMesh); } -- 2.49.1 From d30ae344264117d8feffa89de0b3931a668d1810 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 14:39:19 +0530 Subject: [PATCH 22/34] refactor: Add ArrowsAisle component and update aisle properties for improved functionality --- .../properties/AisleProperties.tsx | 2 +- .../Instances/instance/aisleInstance.tsx | 5 ++ .../instance/aisleTypes/arrowsAisle.tsx | 74 ++++++++++++++++++ .../instance/aisleTypes/dashedAisle.tsx | 2 +- .../instance/aisleTypes/dottedAisle.tsx | 4 +- .../aisle/aisleCreator/referenceAisle.tsx | 78 ++++++++++++++++++- app/src/modules/builder/groups/zoneGroup.tsx | 3 +- app/src/store/builder/useBuilderStore.ts | 2 +- 8 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx index db58c7a..c277812 100644 --- a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx @@ -26,13 +26,13 @@ const AisleProperties: React.FC = () => { const { aisleType, aisleWidth, aisleColor, setAisleType, setAisleColor, setAisleWidth } = useBuilderStore(); const aisleTextureList: TextureItem[] = [ - { color: "gray", id: "gray", brief: "basic", texture: "" }, { color: "yellow", id: "yellow1", brief: "pedestrian walkways", texture: "", }, + { color: "gray", id: "gray", brief: "basic", texture: "" }, { color: "green", id: "green1", brief: "pedestrian walkways", texture: "" }, { color: "orange", id: "orange", brief: "material flow", texture: "" }, { color: "blue", id: "blue", brief: "vehicle paths", texture: "" }, diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx index 8ab9c5f..9afd3d6 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx @@ -1,3 +1,4 @@ +import ArrowsAisle from './aisleTypes/arrowsAisle'; import DashedAisle from './aisleTypes/dashedAisle'; import DottedAisle from './aisleTypes/dottedAisle'; import SolidAisle from './aisleTypes/solidAisle'; @@ -17,6 +18,10 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) { {aisle.type.aisleType === 'dotted-aisle' && ( )} + + {aisle.type.aisleType === 'arrows-aisle' && ( + + )} ); } diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx new file mode 100644 index 0000000..a71f836 --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx @@ -0,0 +1,74 @@ +import * as THREE from 'three'; +import { useMemo } from 'react'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../../types/world/worldConstants'; + +function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) { + const arrows = useMemo(() => { + if (aisle.points.length < 2) return []; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + const arrowLength = 0.6; + const spacing = 0.6; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const count = Math.floor((length + spacing) / (arrowLength + spacing)); + + const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = []; + + for (let i = 0; i < count; i++) { + const initialOffset = 0.6; + const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing)); + + const shape = new THREE.Shape(); + const w = width * 0.8; + const h = arrowLength; + + shape.moveTo(0, 0); + shape.lineTo(w, h * 0.6); + shape.lineTo(w * 0.4, h * 0.6); + shape.lineTo(w * 0.4, h); + shape.lineTo(-w * 0.4, h); + shape.lineTo(-w * 0.4, h * 0.6); + shape.lineTo(-w, h * 0.6); + shape.lineTo(0, 0); + + const angle = Math.atan2(direction.x, direction.z) + Math.PI; + + arrowShapes.push({ shape, position: center, rotationY: angle }); + } + + return arrowShapes; + }, [aisle]); + + if (arrows.length === 0) return null; + + return ( + + {arrows.map(({ shape, position, rotationY }, index) => ( + + + + + + ))} + + ); +} + +export default ArrowsAisle; diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx index 7103479..1f0c0d5 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx @@ -17,7 +17,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) { const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); const totalLength = new THREE.Vector3().subVectors(end, start).length(); - const segmentCount = Math.floor(totalLength / (dashLength + gapLength)); + const segmentCount = Math.floor((totalLength + gapLength) / (dashLength + gapLength)); const shapes = []; const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx index 09a3c65..5cdc1d5 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx @@ -11,10 +11,10 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) { const end = new THREE.Vector3(...aisle.points[1].position); const width = aisle.type.aisleWidth || 0.1; const dotSpacing = 0.5; - const dotRadius = width * 0.4; + const dotRadius = width * 0.6; const totalLength = new THREE.Vector3().subVectors(end, start).length(); - const dotCount = Math.floor(totalLength / dotSpacing); + const dotCount = Math.floor((totalLength + (dotSpacing / 2)) / dotSpacing); const shapes = []; const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx index 74d5e1f..e804d35 100644 --- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx @@ -68,6 +68,8 @@ function ReferenceAisle({ tempPoints, aisleType, aisleWidth, aisleColor }: Reado return ; case 'dotted-aisle': return ; + case 'arrows-aisle': + return default: return null; } @@ -143,7 +145,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) { const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); const totalLength = new THREE.Vector3().subVectors(end, start).length(); - const segmentCount = Math.floor(totalLength / (dashLength + gapLength)); + const segmentCount = Math.floor((totalLength + gapLength) / (dashLength + gapLength)); const shapes = []; const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); @@ -202,10 +204,10 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) { const end = new THREE.Vector3(...aisle.points[1].position); const width = aisle.type.aisleWidth || 0.1; const dotSpacing = 0.5; - const dotRadius = width * 0.4; + const dotRadius = width * 0.6; const totalLength = new THREE.Vector3().subVectors(end, start).length(); - const dotCount = Math.floor(totalLength / dotSpacing); + const dotCount = Math.floor((totalLength + (dotSpacing / 2)) / dotSpacing); const shapes = []; const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); @@ -244,4 +246,72 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) { ))} ); -} \ No newline at end of file +} + +function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) { + const arrows = useMemo(() => { + if (aisle.points.length < 2) return []; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + const arrowLength = 0.6; + const spacing = 0.6; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const count = Math.floor((length + spacing) / (arrowLength + spacing)); + + const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = []; + + for (let i = 0; i < count; i++) { + const initialOffset = 0.6; + const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing)); + + const shape = new THREE.Shape(); + const w = width * 0.8; + const h = arrowLength; + + shape.moveTo(0, 0); + shape.lineTo(w, h * 0.6); + shape.lineTo(w * 0.4, h * 0.6); + shape.lineTo(w * 0.4, h); + shape.lineTo(-w * 0.4, h); + shape.lineTo(-w * 0.4, h * 0.6); + shape.lineTo(-w, h * 0.6); + shape.lineTo(0, 0); + + const angle = Math.atan2(direction.x, direction.z) + Math.PI; + + arrowShapes.push({ shape, position: center, rotationY: angle }); + } + + return arrowShapes; + }, [aisle]); + + if (arrows.length === 0) return null; + + return ( + + {arrows.map(({ shape, position, rotationY }, index) => ( + + + + + + ))} + + ); +} diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 21ba6cc..5b567af 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -553,7 +553,7 @@ const ZoneGroup: React.FC = () => { const midpoint = new THREE.Vector3( (point1.x + point2.x) / 2, CONSTANTS.zoneConfig.height / 2 + - (zone.layer - 1) * CONSTANTS.zoneConfig.height, + (zone.layer - 1) * CONSTANTS.zoneConfig.height, (point1.z + point2.z) / 2 ); @@ -564,7 +564,6 @@ const ZoneGroup: React.FC = () => { return ( ()( immer((set) => ({ aisleType: 'solid-aisle', aisleWidth: 0.1, - aisleColor: 'gray', + aisleColor: 'yellow', setAisleType: (type) => { set((state) => { state.aisleType = type; -- 2.49.1 From 9875239d5437443192aa18aaa16546254d157162 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 16:37:25 +0530 Subject: [PATCH 23/34] Refactor aisle properties and types in builder store - Updated AisleProperties component to include new properties for dashed, dotted, and arrows aisles. - Added new handlers for dash length, gap length, dot radius, and aisle length changes. - Enhanced aisle type management in AisleCreator to handle new aisle types and their properties. - Introduced type-specific setters in useAisleStore for better aisle property management. - Updated builderTypes to define specific interfaces for each aisle type. - Improved rendering logic for advanced properties based on selected aisle type. --- .../properties/AisleProperties.tsx | 241 +++++++++++------- .../instance/aisleTypes/arrowsAisle.tsx | 8 +- .../instance/aisleTypes/dashedAisle.tsx | 6 +- .../instance/aisleTypes/dottedAisle.tsx | 6 +- .../instance/aisleTypes/solidAisle.tsx | 2 +- .../aisle/aisleCreator/aisleCreator.tsx | 123 ++++++++- .../aisle/aisleCreator/referenceAisle.tsx | 130 +++++++--- .../simulation/events/arrows/arrows.tsx | 2 +- app/src/store/builder/useAisleStore.ts | 102 +++++++- app/src/store/builder/useBuilderStore.ts | 81 ++++++ app/src/types/builderTypes.d.ts | 67 ++++- 11 files changed, 609 insertions(+), 159 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx index c277812..f354844 100644 --- a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx @@ -23,39 +23,20 @@ interface TextureItem { const AisleProperties: React.FC = () => { const [collapsePresets, setCollapsePresets] = useState(false); const [collapseTexture, setCollapseTexture] = useState(true); - const { aisleType, aisleWidth, aisleColor, setAisleType, setAisleColor, setAisleWidth } = useBuilderStore(); + + const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength } = useBuilderStore(); const aisleTextureList: TextureItem[] = [ - { - color: "yellow", - id: "yellow1", - brief: "pedestrian walkways", - texture: "", - }, + { color: "yellow", id: "yellow1", brief: "pedestrian walkways", texture: "" }, { color: "gray", id: "gray", brief: "basic", texture: "" }, { color: "green", id: "green1", brief: "pedestrian walkways", texture: "" }, { color: "orange", id: "orange", brief: "material flow", texture: "" }, { color: "blue", id: "blue", brief: "vehicle paths", texture: "" }, { color: "purple", id: "purple", brief: "material flow", texture: "" }, { color: "red", id: "red", brief: "safety zone", texture: "" }, - { - color: "bright green", - id: "bright-green", - brief: "safety zone", - texture: "", - }, - { - color: "yellow-black", - id: "yellow-black", - brief: "utility aisles", - texture: "", - }, - { - color: "white-black", - id: "white-black", - brief: "utility aisles", - texture: "", - }, + { color: "bright green", id: "bright-green", brief: "safety zone", texture: "" }, + { color: "yellow-black", id: "yellow-black", brief: "utility aisles", texture: "" }, + { color: "white-black", id: "white-black", brief: "utility aisles", texture: "" }, ]; const aisleTypes: { @@ -64,77 +45,148 @@ const AisleProperties: React.FC = () => { id: string; thumbnail: string; }[] = [ - { - name: "Solid", - type: "solid-aisle", - id: "1", - thumbnail: Solid, - }, - { - name: "Dotted", - type: "dotted-aisle", - id: "2", - thumbnail: Dotted, - }, - { - name: "Dashed", - type: "dashed-aisle", - id: "3", - thumbnail: Dashed, - }, - { - name: "Arrow", - type: "arrow-aisle", - id: "4", - thumbnail: Arrow, - }, - { - name: "Contiuous Arrows", - type: "arrows-aisle", - id: "5", - thumbnail: Arrows, - }, - { - name: "Directional", - type: "junction-aisle", - id: "6", - thumbnail: Directional, - }, - { - name: "Arc", - type: "arc-aisle", - id: "7", - thumbnail: Arc, - }, - { - name: "Circle", - type: "circle-aisle", - id: "8", - thumbnail: Circle, - }, + { name: "Solid", type: "solid-aisle", id: "1", thumbnail: Solid }, + { name: "Dotted", type: "dotted-aisle", id: "2", thumbnail: Dotted }, + { name: "Dashed", type: "dashed-aisle", id: "3", thumbnail: Dashed }, + { name: "Arrow", type: "arrow-aisle", id: "4", thumbnail: Arrow }, + { name: "Continuous Arrows", type: "arrows-aisle", id: "5", thumbnail: Arrows }, + { name: "Directional", type: "junction-aisle", id: "6", thumbnail: Directional }, + { name: "Arc", type: "arc-aisle", id: "7", thumbnail: Arc }, + { name: "Circle", type: "circle-aisle", id: "8", thumbnail: Circle }, ]; const handleAisleWidthChange = (value: string) => { const width = parseFloat(value); - if (isNaN(width)) { - return; + if (!isNaN(width)) { + setAisleWidth(width); } - setAisleWidth(width); - } + }; + + const handleDashLengthChange = (value: string) => { + const length = parseFloat(value); + if (!isNaN(length)) { + setDashLength(length); + } + }; + + const handleGapLengthChange = (value: string) => { + const length = parseFloat(value); + if (!isNaN(length)) { + setGapLength(length); + } + }; + + const handleDotRadiusChange = (value: string) => { + const radius = parseFloat(value); + if (!isNaN(radius)) { + setDotRadius(radius); + } + }; + + const handleAisleLengthChange = (value: string) => { + const length = parseFloat(value); + if (!isNaN(length)) { + setAisleLength(length); + } + }; + + const renderAdvancedProperties = () => { + switch (aisleType) { + case 'dashed-aisle': + return ( + <> + {aisleType && + <> + + + + } + + ); + case 'dotted-aisle': + return ( + <> + {aisleType && + <> + + + } + + ); + case 'arrows-aisle': + return ( + <> + {aisleType && + <> + + + } + + ); + default: + return null; + } + }; return (
Properties
+ + {/* Basic Properties */}
- + {aisleType !== 'dotted-aisle' && + + } + {renderAdvancedProperties()}
{/* Presets */} @@ -154,12 +206,9 @@ const AisleProperties: React.FC = () => { {aisleTypes.map((val) => (
@@ -177,10 +226,7 @@ const AisleProperties: React.FC = () => { aria-expanded={!collapseTexture} >
Aisle Texture
-
+
@@ -191,8 +237,7 @@ const AisleProperties: React.FC = () => {