diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 277637a..b13944c 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -72,9 +72,8 @@ const SideBarRight: React.FC = () => {
{/* {activeModule === "builder" && ( */}
setSubModule("properties")} > @@ -83,25 +82,22 @@ const SideBarRight: React.FC = () => { {activeModule === "simulation" && ( <>
setSubModule("mechanics")} >
setSubModule("simulations")} >
setSubModule("analysis")} > diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 2a12734..cbb19fa 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -1,147 +1,172 @@ -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef } from "react"; import { - AddIcon, - ArrowIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + ArrowIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { generateUUID } from "three/src/math/MathUtils"; -interface Path { - pathName: string; // Represents the name of the path - Children: string[]; // Represents the list of child points +interface Event { + pathName: string; } -interface DropListProps { - val: Path; // Use the Path interface for the val prop +interface ListProps { + val: Event; } -const DropList: React.FC = ({ val }) => { - const [openDrop, setOpenDrop] = useState(false); - return ( -
-
{ - setOpenDrop(!openDrop); - }} - > - {val.pathName} -
- -
-
- {val.Children && openDrop && ( -
- {val.Children.map((child, index) => ( -
- {child} +const List: React.FC = ({ val }) => { + return ( +
+
+ {val.pathName}
- ))}
- )} -
- ); + ); }; const Simulations: React.FC = () => { - const productsContainerRef = useRef(null); - const [productsList, setProductsList] = useState([]); - const [selectedItem, setSelectedItem] = useState(); + const productsContainerRef = useRef(null); + const { products, addProduct, removeProduct, renameProduct } = useProductStore(); + const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - const handleAddAction = () => { - setProductsList([...productsList, `Product ${productsList.length + 1}`]); - }; + useEffect(() => { + if (products.length > 0 && selectedProduct.productId === '' && selectedProduct.productName === '') { + setSelectedProduct(products[0].productId, products[0].productName); + } + }, [products, selectedProduct]); - const handleRemoveAction = (index: number) => { - setProductsList(productsList.filter((_, i) => i !== index)); - if (selectedItem === productsList[index]) { - setSelectedItem(""); - } - }; + const handleAddProduct = () => { + addProduct(`Product ${products.length + 1}`, generateUUID()); + }; - const Value = [ - { pathName: "Path 1", Children: ["Point 1", "Point 2"] }, - { pathName: "Path 2", Children: ["Point 1", "Point 2"] }, - { pathName: "Path 3", Children: ["Point 1", "Point 2"] }, - ]; + const handleRemoveProduct = (productId: string) => { + const currentIndex = products.findIndex(p => p.productId === productId); + const isSelected = selectedProduct.productId === productId; - return ( -
-
Simulations
-
-
-
-
Products
-
- Add -
-
-
-
- {productsList.map((action, index) => ( -
-
setSelectedItem(action)} - > - - -
-
handleRemoveAction(index)} - > - -
+ const updatedProducts = products.filter(p => p.productId !== productId); + + if (isSelected) { + if (updatedProducts.length > 0) { + let newSelectedIndex = currentIndex; + if (currentIndex >= updatedProducts.length) { + newSelectedIndex = updatedProducts.length - 1; + } + setSelectedProduct( + updatedProducts[newSelectedIndex].productId, + updatedProducts[newSelectedIndex].productName + ); + } else { + setSelectedProduct('', ''); + } + } + + removeProduct(productId); + }; + + const handleRenameProduct = (productId: string, newName: string) => { + renameProduct(productId, newName); + if (selectedProduct.productId === productId) { + setSelectedProduct(productId, newName); + } + }; + + const selectedProductData = products.find( + (product) => product.productId === selectedProduct.productId + ); + + const events: Event[] = selectedProductData?.eventsData.map((event, index) => ({ + pathName: `${event.modelName} - ${event.type} #${index + 1}`, + })) || []; + + return ( +
+
Simulations
+
+
+
+
Products
+
+ Add +
+
+
+
+ {products.map((product, index) => ( +
+
setSelectedProduct(product.productId, product.productName)} + > + + handleRenameProduct(product.productId, newName)} + /> +
+ {products.length > 1 && ( +
handleRemoveProduct(product.productId)} + > + +
+ )} +
+ ))} +
+
handleResize(e, productsContainerRef)} + > + +
+
+
+ +
+
+
Events
+
+ +
+
+ {events.map((event, index) => ( + + ))} +
+ +
+
+ Need to Compare Layout? +
+
+ Click 'Compare' to review and analyze the layout differences between them. +
+
+ +
- ))}
-
handleResize(e, productsContainerRef)} - > - -
-
-
-
-
Operations
-
- -
-
- {Value.map((val, index) => ( - - ))} -
-
-
- Need to Compare Layout? -
-
- Click 'Compare' to review and analyze the layout - differences between them. -
-
- -
-
-
-
- ); + ); }; export default Simulations; diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index e88dc3c..2378bf3 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -8,10 +8,12 @@ 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'; +import PointsCalculator from '../../simulation/events/points/functions/pointsCalculator'; async function loadInitialFloorItems( itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, + addEvent: (event: EventsSchema) => void, ): Promise { if (!itemsGroup.current) return; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -70,7 +72,7 @@ async function loadInitialFloorItems( const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { // console.log(`[Cache] Fetching ${item.modelname}`); - processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems); + processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); return; @@ -85,7 +87,7 @@ async function loadInitialFloorItems( URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); }, @@ -106,7 +108,7 @@ async function loadInitialFloorItems( const modelBlob = await fetch(modelUrl).then((res) => res.blob()); await storeGLTF(item.modelfileID!, modelBlob); THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); }, @@ -148,8 +150,9 @@ function processLoadedModel( item: Types.FloorItemType, itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, + addEvent: (event: EventsSchema) => void, ) { - const model = gltf; + 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 }; @@ -182,6 +185,243 @@ function processLoadedModel( }, ]); + if (item.modelfileID === "a1ee92554935007b10b3eb05") { + const data = PointsCalculator( + 'Vehicle', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + 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: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Vehicle Action", + actionType: "travel", + material: null, + unLoadDuration: 5, + loadCapacity: 10, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { + const data = PointsCalculator( + 'Conveyor', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + 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: data.points.map((point: THREE.Vector3, index: number) => ({ + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index}`, + actionType: 'default', + material: 'inherit', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) + }; + addEvent(ConveyorEvent); + } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { + // const data = PointsCalculator( + // 'Conveyor', + // gltf.clone(), + // new THREE.Vector3(...model.rotation) + // ); + + // if (!data || !data.points) return; + + // const points: ConveyorPointSchema[] = data.points.map((point: THREE.Vector3, index: number) => { + // const actionUuid = THREE.MathUtils.generateUUID(); + // return { + // uuid: THREE.MathUtils.generateUUID(), + // position: [point.x, point.y, point.z], + // rotation: [0, 0, 0], + // action: { + // actionUuid, + // actionName: `Action ${index}`, + // actionType: 'default', + // material: 'inherit', + // delay: 0, + // spawnInterval: 5, + // spawnCount: 1, + // triggers: [] + // } + // }; + // }); + + // points.forEach((point, index) => { + // if (index < points.length - 1) { + // const nextPoint = points[index + 1]; + // point.action.triggers.push({ + // triggerUuid: THREE.MathUtils.generateUUID(), + // triggerName: `Trigger 1`, + // triggerType: "onComplete", + // delay: 0, + // triggeredAsset: { + // triggeredModel: { + // modelName: item.modelname, + // modelUuid: item.modeluuid + // }, + // triggeredPoint: { + // pointName: `Point ${index + 1}`, + // pointUuid: nextPoint.uuid + // }, + // triggeredAction: { + // actionName: nextPoint.action.actionName, + // actionUuid: nextPoint.action.actionUuid + // } + // } + // }); + // } + // }); + + // 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 + // }; + // addEvent(ConveyorEvent); + } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { + const data = PointsCalculator( + 'Conveyor', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + 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: data.points.map((point: THREE.Vector3, index: number) => ({ + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index}`, + actionType: 'default', + material: 'inherit', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) + }; + addEvent(ConveyorEvent); + } else if (item.modelfileID === "29dee78715ad5b853f5c346d") { + const data = PointsCalculator( + 'StaticMachine', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + 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: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Process Action", + actionType: "process", + processTime: 10, + swapMaterial: "material-id", + triggers: [] + } + } + }; + addEvent(machineEvent); + } else if (item.modelfileID === "52e6681fbb743a890d96c914") { + const data = PointsCalculator( + 'ArmBot', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + 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: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Pick and Place", + actionType: "pickAndPlace", + process: { + startPoint: [0, 0, 0], + endPoint: [0, 0, 0] + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + } + 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' }); } diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 193dd41..670c7b5 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -10,7 +10,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils'; 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/pointsCalculator'; +import PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator'; async function addAssetModel( raycaster: THREE.Raycaster, @@ -266,7 +266,7 @@ async function handleModelLoad( } }; addEvent(roboticArmEvent); - } else if (selectedItem.type === "Machine") { + } else if (selectedItem.type === "StaticMachine") { const machineEvent: MachineEventSchema = { modelUuid: newFloorItem.modeluuid, modelName: newFloorItem.modelname, diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 2a3c2cc..241f628 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -75,7 +75,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject gltfLoaderWorker.postMessage({ floorItems: data }); } else { gltfLoaderWorker.postMessage({ floorItems: [] }); - loadInitialFloorItems(itemsGroup, setFloorItems); + loadInitialFloorItems(itemsGroup, setFloorItems, addEvent); updateLoadingProgress(100); } }); @@ -94,7 +94,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject updateLoadingProgress(progress); if (loadedAssets === totalAssets) { - loadInitialFloorItems(itemsGroup, setFloorItems); + loadInitialFloorItems(itemsGroup, setFloorItems, addEvent); updateLoadingProgress(100); } }); diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index d3245fb..dd5607a 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -2,90 +2,107 @@ import * as THREE from "three"; import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing"; import { BlendFunction } from "postprocessing"; import { - useDeletableFloorItem, - useSelectedWallItem, - useSelectedFloorItem, + useDeletableFloorItem, + useSelectedWallItem, + useSelectedFloorItem, } from "../../../store/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"; export default function PostProcessing() { - const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); - const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); - const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); + const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); + const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { selectedEventSphere } = useSelectedEventSphere(); - function flattenChildren(children: any[]) { - const allChildren: any[] = []; - children.forEach((child) => { - allChildren.push(child); - if (child.children && child.children.length > 0) { - allChildren.push(...flattenChildren(child.children)); - } - }); - return allChildren; - } + function flattenChildren(children: any[]) { + const allChildren: any[] = []; + children.forEach((child) => { + allChildren.push(child); + if (child.children && child.children.length > 0) { + allChildren.push(...flattenChildren(child.children)); + } + }); + return allChildren; + } - return ( - <> - - - {deletableFloorItem && ( - - )} - {selectedWallItem && ( - child.name !== "CSG_REF" - )} - selectionLayer={10} - width={3000} - blendFunction={BlendFunction.ALPHA} - edgeStrength={5} - resolutionScale={2} - pulseSpeed={0} - visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} - hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} - blur={true} - xRay={true} - /> - )} - {selectedFloorItem && ( - - )} - - - ); + return ( + <> + + + {deletableFloorItem && ( + + )} + {selectedWallItem && ( + child.name !== "CSG_REF" + )} + selectionLayer={10} + width={3000} + blendFunction={BlendFunction.ALPHA} + edgeStrength={5} + resolutionScale={2} + pulseSpeed={0} + visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} + hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} + blur={true} + xRay={true} + /> + )} + {selectedFloorItem && ( + + )} + {selectedEventSphere && ( + + )} + + + ); } diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 335f1f5..8baacd9 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -4,20 +4,20 @@ import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; import useModuleStore from '../../../../../store/useModuleStore'; import { TransformControls } from '@react-three/drei'; import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; +import { useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore'; function PointsCreator() { const { events, updatePoint, getPointByUuid } = useEventsStore(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); - const [selectedPoint, setSelectedPoint] = useState(null); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); useEffect(() => { - setTransformMode(null); const handleKeyDown = (e: KeyboardEvent) => { const keyCombination = detectModifierKeys(e); - if (!selectedPoint) return; + if (!selectedEventSphere) return; if (keyCombination === "G") { setTransformMode((prev) => (prev === "translate" ? null : "translate")); } @@ -28,13 +28,13 @@ function PointsCreator() { window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); - }, [selectedPoint]); + }, [selectedEventSphere]); - const updatePointToState = (selectedPoint: THREE.Mesh) => { - let point = JSON.parse(JSON.stringify(getPointByUuid(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid))); + const updatePointToState = (selectedEventSphere: THREE.Mesh) => { + let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); if (point) { - point.position = [selectedPoint.position.x, selectedPoint.position.y, selectedPoint.position.z]; - updatePoint(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid, point) + point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z]; + updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point) } } @@ -53,10 +53,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[point.uuid]); + setSelectedEventSphere(sphereRefs.current[point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} key={`${i}-${j}`} position={new THREE.Vector3(...point.position)} @@ -76,10 +77,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere(sphereRefs.current[event.point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} @@ -97,10 +99,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere(sphereRefs.current[event.point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} @@ -118,10 +121,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere(sphereRefs.current[event.point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} @@ -136,8 +140,8 @@ function PointsCreator() { } })} - {(selectedPoint && transformMode) && - { updatePointToState(selectedPoint) }} /> + {(selectedEventSphere && transformMode) && + { updatePointToState(selectedEventSphere) }} /> } } diff --git a/app/src/modules/simulation/events/points/pointsCalculator.ts b/app/src/modules/simulation/events/points/functions/pointsCalculator.ts similarity index 96% rename from app/src/modules/simulation/events/points/pointsCalculator.ts rename to app/src/modules/simulation/events/points/functions/pointsCalculator.ts index 86d368e..ccc2dbb 100644 --- a/app/src/modules/simulation/events/points/pointsCalculator.ts +++ b/app/src/modules/simulation/events/points/functions/pointsCalculator.ts @@ -1,5 +1,5 @@ import * as THREE from 'three'; -import { Group } from '../../../../types/world/worldTypes'; +import { Group } from '../../../../../types/world/worldTypes'; function PointsCalculator( type: string, diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx new file mode 100644 index 0000000..edb825f --- /dev/null +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function MachineInstance() { + return ( + <> + + ) +} + +export default MachineInstance \ No newline at end of file diff --git a/app/src/modules/simulation/machine/instances/machineInstances.tsx b/app/src/modules/simulation/machine/instances/machineInstances.tsx new file mode 100644 index 0000000..b0c2c9f --- /dev/null +++ b/app/src/modules/simulation/machine/instances/machineInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import MachineInstance from './machineInstance/machineInstance' + +function MachineInstances() { + return ( + <> + + + + + ) +} + +export default MachineInstances \ No newline at end of file diff --git a/app/src/modules/simulation/machine/machine.tsx b/app/src/modules/simulation/machine/machine.tsx new file mode 100644 index 0000000..32c3b8e --- /dev/null +++ b/app/src/modules/simulation/machine/machine.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import MachineInstances from './instances/machineInstances' + +function Machine() { + return ( + <> + + + + + ) +} + +export default Machine \ No newline at end of file diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx new file mode 100644 index 0000000..2e9a16e --- /dev/null +++ b/app/src/modules/simulation/products/products.tsx @@ -0,0 +1,20 @@ +import React, { useEffect } from 'react' +import { useProductStore } from '../../../store/simulation/useProductStore' +import * as THREE from 'three'; + +function Products() { + const { products, addProduct } = useProductStore(); + + useEffect(() => { + if (products.length === 0) { + addProduct('Product 1', THREE.MathUtils.generateUUID()); + } + }, [products]) + + return ( + <> + + ) +} + +export default Products \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 1270d93..02a1690 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,6 +1,5 @@ import React from 'react' import RoboticArmInstances from './instances/roboticArmInstances'; -import IkInstances from './instances/ikInstances'; function RoboticArm() { return ( diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index b7bf36d..f02b066 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -5,13 +5,18 @@ import Vehicles from './vehicle/vehicles'; import Points from './events/points/points'; import Conveyor from './conveyor/conveyor'; import RoboticArm from './roboticArm/roboticArm'; +import Materials from './materials/materials'; +import Machine from './machine/machine'; +import StorageUnit from './storageUnit/storageUnit'; +import Simulator from './simulator/simulator'; +import Products from './products/products'; function Simulation() { const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - // console.log('events: ', events); + console.log('events: ', events); }, [events]) useEffect(() => { @@ -23,11 +28,21 @@ function Simulation() { + + + + + + - + + + + + ) diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx new file mode 100644 index 0000000..8cc22d6 --- /dev/null +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +function Simulator() { + return ( + <> + + + ) +} + +export default Simulator \ No newline at end of file diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx new file mode 100644 index 0000000..29d404e --- /dev/null +++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function storageUnitInstance() { + return ( + <> + + ) +} + +export default storageUnitInstance \ No newline at end of file diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx new file mode 100644 index 0000000..d79b5d8 --- /dev/null +++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import StorageUnitInstance from './storageUnitInstance/storageUnitInstance' + +function StorageUnitInstances() { + return ( + <> + + + + + ) +} + +export default StorageUnitInstances \ No newline at end of file diff --git a/app/src/modules/simulation/storageUnit/storageUnit.tsx b/app/src/modules/simulation/storageUnit/storageUnit.tsx new file mode 100644 index 0000000..eee0875 --- /dev/null +++ b/app/src/modules/simulation/storageUnit/storageUnit.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import StorageUnitInstances from './instances/storageUnitInstances' + +function StorageUnit() { + return ( + <> + + + + + ) +} + +export default StorageUnit \ No newline at end of file diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index 493a068..d907f21 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -17,6 +17,9 @@ interface ArmBotStore { addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void; removeAction: (modelUuid: string, actionUuid: string) => void; + updateStartPoint: (modelUuid: string, actionUuid: string, startPoint: [number, number, number] | null) => void; + updateEndPoint: (modelUuid: string, actionUuid: string, endPoint: [number, number, number] | null) => void; + setArmBotActive: (modelUuid: string, isActive: boolean) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void; @@ -106,6 +109,30 @@ export const useArmBotStore = create()( }); }, + 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; + } + } + }); + }, + + 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; + } + } + }); + }, + setArmBotActive: (modelUuid, isActive) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); diff --git a/app/src/store/simulation/useMaterialStore.ts b/app/src/store/simulation/useMaterialStore.ts new file mode 100644 index 0000000..56a35a7 --- /dev/null +++ b/app/src/store/simulation/useMaterialStore.ts @@ -0,0 +1,76 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +type MaterialsStore = { + materials: MaterialsSchema; + + addMaterial: (material: MaterialSchema) => void; + removeMaterial: (materialId: string) => void; + updateMaterial: (materialId: string, updates: Partial) => void; + + setStartTime: (materialId: string, startTime: string) => void; + setEndTime: (materialId: string, endTime: string) => void; + setCost: (materialId: string, cost: number) => void; + setWeight: (materialId: string, weight: number) => void; + + getMaterialById: (materialId: string) => MaterialSchema | undefined; +}; + +export const useMaterialStore = create()( + immer((set, get) => ({ + materials: [], + + addMaterial: (material) => { + set((state) => { + state.materials.push(material); + }); + }, + + removeMaterial: (materialId) => { + set((state) => { + state.materials = state.materials.filter(m => m.materialId !== materialId); + }); + }, + + updateMaterial: (materialId, updates) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + Object.assign(material, updates); + } + }); + }, + + setStartTime: (materialId, startTime) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.startTime = startTime; + }); + }, + + setEndTime: (materialId, endTime) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.endTime = endTime; + }); + }, + + setCost: (materialId, cost) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.cost = cost; + }); + }, + + setWeight: (materialId, weight) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.weight = weight; + }); + }, + + getMaterialById: (materialId) => { + return get().materials.find(m => m.materialId === materialId); + }, + })) +); diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 41a13f6..81feb7f 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -48,6 +48,11 @@ type ProductsStore = { updates: Partial ) => void; + // Renaming functions + renameProduct: (productId: string, newName: string) => void; + renameAction: (actionUuid: string, newName: string) => void; + renameTrigger: (triggerUuid: string, newName: string) => void; + // Helper functions getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; }; @@ -331,6 +336,84 @@ export const useProductStore = create()( }); }, + // Renaming functions + renameProduct: (productId, newName) => { + set((state) => { + const product = state.products.find(p => p.productId === productId); + if (product) { + product.productName = newName; + } + }); + }, + + renameAction: (actionUuid, newName) => { + set((state) => { + for (const product of state.products) { + for (const event of product.eventsData) { + if ('points' in event) { + for (const point of (event as ConveyorEventSchema).points) { + if (point.action && point.action.actionUuid === actionUuid) { + point.action.actionName = newName; + return; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && point.action.actionUuid === actionUuid) { + point.action.actionName = newName; + return; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) { + action.actionName = newName; + return; + } + } + } + } + } + }); + }, + + renameTrigger: (triggerUuid, newName) => { + set((state) => { + for (const product of state.products) { + for (const event of product.eventsData) { + if ('points' in event) { + for (const point of (event as ConveyorEventSchema).points) { + if (point.action && 'triggers' in point.action) { + const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); + if (trigger) { + trigger.triggerName = newName; + return; + } + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && 'triggers' in point.action) { + const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) { + trigger.triggerName = newName; + return; + } + } else if ('actions' in point) { + for (const action of point.actions) { + if ('triggers' in action) { + const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) { + trigger.triggerName = newName; + return; + } + } + } + } + } + } + } + }); + }, + // Helper functions getProductById: (productId) => { return get().products.find(p => p.productId === productId); diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts new file mode 100644 index 0000000..9c0fc00 --- /dev/null +++ b/app/src/store/simulation/useSimulationStore.ts @@ -0,0 +1,49 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; +import * as THREE from 'three'; + +interface SelectedEventSphereState { + selectedEventSphere: THREE.Mesh | null; + setSelectedEventSphere: (mesh: THREE.Mesh | null) => void; + clearSelectedEventSphere: () => void; +} + +export const useSelectedEventSphere = create()( + immer((set) => ({ + selectedEventSphere: null, + setSelectedEventSphere: (mesh) => { + set((state) => { + state.selectedEventSphere = mesh; + }); + }, + clearSelectedEventSphere: () => { + set((state) => { + state.selectedEventSphere = null; + }); + }, + })) +); + +interface SelectedProductState { + selectedProduct: { productId: string; productName: string }; + setSelectedProduct: (productId: string, productName: string) => void; + 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 = ''; + }); + }, + })) +); \ No newline at end of file diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index f6b0a0c..1b99456 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -168,4 +168,17 @@ interface StorageUnitStatus extends StorageEventSchema { idleTime: number; activeTime: number; currentLoad: number; -} \ No newline at end of file +} + +interface MaterialSchema { + materialId: string; + materialName: string; + materialType: string; + isActive: boolean; + startTime?: string; + endTime?: string; + cost?: number; + weight?: number; +} + +type MaterialsSchema = MaterialSchema[]; \ No newline at end of file