diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index cfc5dcd..d924d9d 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -18,20 +18,20 @@ import Window from "../../assets/gltf-glb/window.glb"; ////////// Zustand State Imports ////////// import { - useToggleView, - useDeletePointOrLine, - useMovePoint, - useActiveLayer, - useSocketStore, - useWallVisibility, - useRoofVisibility, - useShadows, - useUpdateScene, - useWalls, - useToolMode, - useRefTextUpdate, - useRenderDistance, - useLimitDistance, + useToggleView, + useDeletePointOrLine, + useMovePoint, + useActiveLayer, + useSocketStore, + useWallVisibility, + useRoofVisibility, + useShadows, + useUpdateScene, + useWalls, + useToolMode, + useRefTextUpdate, + useRenderDistance, + useLimitDistance, } from "../../store/store"; ////////// 3D Function Imports ////////// @@ -40,7 +40,7 @@ import loadWalls from "./geomentries/walls/loadWalls"; import * as Types from "../../types/world/worldTypes"; -import SocketResponses from "../collaboration/socketResponses.dev"; +import SocketResponses from "../collaboration/socket/socketResponses.dev"; import FloorItemsGroup from "./groups/floorItemsGroup"; import FloorPlanGroup from "./groups/floorPlanGroup"; import FloorGroup from "./groups/floorGroup"; @@ -57,317 +57,296 @@ import useModuleStore from "../../store/useModuleStore"; import MeasurementTool from "../scene/tools/measurementTool"; export default function Builder() { - const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. - const csg = useRef(); // Reference for CSG object, used for 3D modeling. - const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. - const scene = useRef() as Types.RefScene; // Reference to the scene. - const camera = useRef() as Types.RefCamera; // Reference to the camera object. - const controls = useRef(); // Reference to the controls object. - const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. - const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. + const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. + const csg = useRef(); // Reference for CSG object, used for 3D modeling. + const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. + const scene = useRef() as Types.RefScene; // Reference to the scene. + const camera = useRef() as Types.RefCamera; // Reference to the camera object. + const controls = useRef(); // Reference to the controls object. + const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. + const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. - // Assigning the scene and camera from the Three.js state to the references. + // Assigning the scene and camera from the Three.js state to the references. - scene.current = state.scene; - camera.current = state.camera; - controls.current = state.controls; - raycaster.current = state.raycaster; + scene.current = state.scene; + camera.current = state.camera; + controls.current = state.controls; + raycaster.current = state.raycaster; - const plane = useRef(null); // Reference for a plane object for raycaster reference. - const grid = useRef() as any; // Reference for a grid object for raycaster reference. - const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. - const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). - const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... - const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. - const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. - const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). - const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. - const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. - const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. - const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. - const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. - const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. - const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. - const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. - const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. - const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. - const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). - const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. - const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. - const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. - const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. - const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. - const floorGroupAisle = useRef() as Types.RefGroup; - const zoneGroup = useRef() as Types.RefGroup; - const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. - const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. - const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. - const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. - const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. - const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. - const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... + const plane = useRef(null); // Reference for a plane object for raycaster reference. + const grid = useRef() as any; // Reference for a grid object for raycaster reference. + const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. + const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). + const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... + const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. + const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. + const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). + const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. + const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. + const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. + const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. + const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. + const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. + const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. + const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. + const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. + const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. + const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). + const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. + const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. + const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. + const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. + const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. + const floorGroupAisle = useRef() as Types.RefGroup; + const zoneGroup = useRef() as Types.RefGroup; + const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. + const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. + const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. + const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. + const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. + const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. + const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... - const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. + const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. - const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item. - const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. - const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D. - const { toolMode, setToolMode } = useToolMode(); - const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not. - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { socket } = useSocketStore(); - const { roofVisibility, setRoofVisibility } = useRoofVisibility(); - const { wallVisibility, setWallVisibility } = useWallVisibility(); - const { shadows, setShadows } = useShadows(); - const { renderDistance, setRenderDistance } = useRenderDistance(); - const { limitDistance, setLimitDistance } = useLimitDistance(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { walls, setWalls } = useWalls(); - const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); - const { activeModule } = useModuleStore(); + const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item. + const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. + const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D. + const { toolMode, setToolMode } = useToolMode(); + const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not. + const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); + const { socket } = useSocketStore(); + const { roofVisibility, setRoofVisibility } = useRoofVisibility(); + const { wallVisibility, setWallVisibility } = useWallVisibility(); + const { shadows, setShadows } = useShadows(); + const { renderDistance, setRenderDistance } = useRenderDistance(); + const { limitDistance, setLimitDistance } = useLimitDistance(); + const { updateScene, setUpdateScene } = useUpdateScene(); + const { walls, setWalls } = useWalls(); + const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); + const { activeModule } = useModuleStore(); - // const loader = new GLTFLoader(); - // const dracoLoader = new DRACOLoader(); + // 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); + // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); + // loader.setDRACOLoader(dracoLoader); - ////////// Assest Configuration Values ////////// + ////////// Assest Configuration Values ////////// - const AssetConfigurations: Types.AssetConfigurations = { - arch: { - modelUrl: arch, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - door: { - modelUrl: door, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - window: { - modelUrl: Window, - scale: [0.75, 0.75, 0.75], - csgscale: [5, 3, 0.5], - csgposition: [0, 1.5, 0], - positionY: (intersectionPoint) => intersectionPoint.point.y, - type: "Free-Move", - }, - }; + const AssetConfigurations: Types.AssetConfigurations = { + arch: { + modelUrl: arch, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + positionY: () => 0, + type: "Fixed-Move", + }, + door: { + modelUrl: door, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + positionY: () => 0, + type: "Fixed-Move", + }, + window: { + modelUrl: Window, + scale: [0.75, 0.75, 0.75], + csgscale: [5, 3, 0.5], + csgposition: [0, 1.5, 0], + positionY: (intersectionPoint) => intersectionPoint.point.y, + type: "Free-Move", + }, + }; - ////////// All Toggle's ////////// + ////////// All Toggle's ////////// - useEffect(() => { - setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); - if (dragPointControls.current) { - dragPointControls.current.enabled = false; - } - if (toggleView) { - Layer2DVisibility( - activeLayer, - floorPlanGroup, - floorPlanGroupLine, - floorPlanGroupPoint, - currentLayerPoint, - dragPointControls - ); - } else { - setToolMode(null); - setDeletePointOrLine(false); - setMovePoint(false); - loadWalls(lines, setWalls); - setUpdateScene(true); - line.current = []; - } - }, [toggleView]); + useEffect(() => { + setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); + if (dragPointControls.current) { + dragPointControls.current.enabled = false; + } + if (toggleView) { + Layer2DVisibility( + activeLayer, + floorPlanGroup, + floorPlanGroupLine, + floorPlanGroupPoint, + currentLayerPoint, + dragPointControls + ); + } else { + setToolMode(null); + setDeletePointOrLine(false); + setMovePoint(false); + loadWalls(lines, setWalls); + setUpdateScene(true); + line.current = []; + } + }, [toggleView]); - useEffect(() => { - THREE.Cache.clear(); - THREE.Cache.enabled = true; - }, []); + useEffect(() => { + THREE.Cache.clear(); + THREE.Cache.enabled = true; + }, []); - useEffect(() => { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; + useEffect(() => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - async function fetchVisibility() { - const visibility = await findEnvironment( - organization, - localStorage.getItem("userId")! - ); - if (visibility) { - setRoofVisibility(visibility.roofVisibility); - setWallVisibility(visibility.wallVisibility); - setShadows(visibility.shadowVisibility); - setRenderDistance(visibility.renderDistance); - setLimitDistance(visibility.limitDistance); - } - } - fetchVisibility(); - }, []); + async function fetchVisibility() { + const visibility = await findEnvironment( + organization, + localStorage.getItem("userId")! + ); + if (visibility) { + setRoofVisibility(visibility.roofVisibility); + setWallVisibility(visibility.wallVisibility); + setShadows(visibility.shadowVisibility); + setRenderDistance(visibility.renderDistance); + setLimitDistance(visibility.limitDistance); + } + } + fetchVisibility(); + }, []); - ////////// UseFrame is Here ////////// + ////////// UseFrame is Here ////////// - useFrame(() => { - if (toolMode) { - Draw( - state, - plane, - cursorPosition, - floorPlanGroupPoint, - floorPlanGroupLine, - snappedPoint, - isSnapped, - isSnappedUUID, - line, - lines, - ispreSnapped, - floorPlanGroup, - ReferenceLineMesh, - LineCreated, - setRefTextUpdate, - Tube, - anglesnappedPoint, - isAngleSnapped, - toolMode - ); - } - }); + useFrame(() => { + if (toolMode) { + Draw( + state, + plane, + cursorPosition, + floorPlanGroupPoint, + floorPlanGroupLine, + snappedPoint, + isSnapped, + isSnappedUUID, + line, + lines, + ispreSnapped, + floorPlanGroup, + ReferenceLineMesh, + LineCreated, + setRefTextUpdate, + Tube, + anglesnappedPoint, + isAngleSnapped, + toolMode + ); + } + }); - ////////// Return ////////// + ////////// Return ////////// - return ( - <> - + return ( + <> + - + - + - + - + - + - + - + - {/* */} + - + - + - - - {/* */} - - ); + + ); } diff --git a/app/src/modules/builder/groups/zoneGroup1.tsx b/app/src/modules/builder/groups/zoneGroup1.tsx deleted file mode 100644 index 80be9a3..0000000 --- a/app/src/modules/builder/groups/zoneGroup1.tsx +++ /dev/null @@ -1,245 +0,0 @@ -import { useEffect } from "react"; -import * as THREE from 'three'; -import * as Types from '../../../types/world/worldTypes'; -import * as CONSTANTS from "../../../types/world/worldConstants"; -import { useActiveLayer, useSocketStore, useDeleteTool, useDeletePointOrLine, useMovePoint, useToggleView, useUpdateScene, useNewLines, useToolMode } from "../../../store/store"; -import { useThree } from "@react-three/fiber"; -import arrayLineToObject from "../geomentries/lines/lineConvertions/arrayLineToObject"; -import addPointToScene from "../geomentries/points/addPointToScene"; -import addLineToScene from "../geomentries/lines/addLineToScene"; -import removeSoloPoint from "../geomentries/points/removeSoloPoint"; -import removeReferenceLine from "../geomentries/lines/removeReferenceLine"; -import getClosestIntersection from "../geomentries/lines/getClosestIntersection"; -import loadZones from "../geomentries/zones/loadZones"; - -const ZoneGroup = ({ zoneGroup, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => { - const { toggleView, setToggleView } = useToggleView(); - const { deleteTool, setDeleteTool } = useDeleteTool(); - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { toolMode, setToolMode } = useToolMode(); - const { movePoint, setMovePoint } = useMovePoint(); - const { socket } = useSocketStore(); - const { activeLayer } = useActiveLayer(); - const { gl, raycaster, camera, pointer } = useThree(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { newLines, setNewLines } = useNewLines(); - - useEffect(() => { - if (updateScene) { - loadZones(lines, zoneGroup); - setUpdateScene(false); - } - }, [updateScene]) - - useEffect(() => { - if (toolMode === "Zone") { - setDeletePointOrLine(false); - setMovePoint(false); - setDeleteTool(false); - } else { - removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint); - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - }, [toolMode]) - - useEffect(() => { - - const canvasElement = gl.domElement; - - let drag = false; - let isLeftMouseDown = false; - - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - } - }; - - const onMouseUp = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = false; - } - } - - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - }; - - const onContextMenu = (e: any) => { - e.preventDefault(); - if (toolMode === "Zone") { - removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint); - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - }; - - const onMouseClick = (evt: any) => { - if (!plane.current || drag) return; - const intersects = raycaster.intersectObject(plane.current, true); - let intersectionPoint = intersects[0].point; - const points = floorPlanGroupPoint.current?.children ?? []; - const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible); - let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true); - - if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) { - const lineType = intersectsLines[0].object.userData.linePoints[0][3]; - if (lineType === CONSTANTS.lineConfig.zoneName) { - // console.log("intersected a zone line"); - - const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(300); - let intersection = getClosestIntersection(ThroughPoint, intersectionPoint); - if (!intersection) return; - const point = addPointToScene(intersection, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName); - (line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.zoneName,]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - lines.current.push(line.current as Types.Line); - - const data = arrayLineToObject(line.current as Types.Line); - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization: organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id - } - - socket.emit('v1:Line:create', input); - - setNewLines([line.current]); - - addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - } - } else if (intersectsPoint && intersects && intersects.length > 0) { - if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.zoneName) { - // console.log("intersected a zone point"); - - intersectionPoint = intersectsPoint.object.position; - (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.zoneName]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - lines.current.push(line.current as Types.Line); - - const data = arrayLineToObject(line.current as Types.Line); - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization: organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id - } - - socket.emit('v1:Line:create', input); - - setNewLines([line.current]); - - addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - ispreSnapped.current = false; - isSnapped.current = false; - } - } - } else if (intersects && intersects.length > 0) { - // console.log("intersected a empty area"); - - let uuid: string = ""; - if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) { - intersectionPoint = anglesnappedPoint.current; - const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName); - uuid = point.uuid; - } else if (isSnapped.current && snappedPoint.current && line.current.length > 0) { - intersectionPoint = snappedPoint.current; - uuid = isSnappedUUID.current!; - } else if (ispreSnapped.current && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - uuid = isSnappedUUID.current!; - } else { - const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName); - uuid = point.uuid; - } - - (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.zoneName]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - lines.current.push(line.current as Types.Line); - - const data = arrayLineToObject(line.current as Types.Line); - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization: organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id - } - - socket.emit('v1:Line:create', input); - - setNewLines([line.current]); - - addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - ispreSnapped.current = false; - isSnapped.current = false; - } - } - } - - if (toolMode === 'Zone') { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("click", onMouseClick); - canvasElement.addEventListener("contextmenu", onContextMenu); - } - - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("click", onMouseClick); - canvasElement.removeEventListener("contextmenu", onContextMenu); - }; - }, [toolMode]) - - return ( - - - ) -} - -export default ZoneGroup; \ No newline at end of file diff --git a/app/src/modules/collaboration/camera/collabCams.tsx b/app/src/modules/collaboration/camera/collabCams.tsx index 63ab2a1..1347a2a 100644 --- a/app/src/modules/collaboration/camera/collabCams.tsx +++ b/app/src/modules/collaboration/camera/collabCams.tsx @@ -2,7 +2,7 @@ import * as THREE from "three"; import { useEffect, useRef, useState } from "react"; import { useFrame } from "@react-three/fiber"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; -import camModel from "../../assets/gltf-glb/camera face 2.gltf"; +import camModel from "../../../assets/gltf-glb/camera face 2.gltf"; import getActiveUsersData from "../../../services/factoryBuilder/collab/getActiveUsers"; import { useActiveUsers, useSocketStore } from "../../../store/store"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx similarity index 94% rename from app/src/modules/collaboration/socketResponses.dev.tsx rename to app/src/modules/collaboration/socket/socketResponses.dev.tsx index 6e578a1..3d9cddf 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx @@ -1,827 +1,827 @@ -import { useEffect } from "react"; -import * as THREE from 'three'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; -import gsap from 'gsap'; -import { toast } from 'react-toastify'; -import { useSocketStore, useActiveLayer, useWallItems, useFloorItems, useLayers, useUpdateScene, useWalls, useDeletedLines, useNewLines, useZonePoints, useZones } from "../../store/store"; - -import * as Types from "../../types/world/worldTypes"; -import * as CONSTANTS from '../../types/world/worldConstants'; -import TempLoader from "../builder/geomentries/assets/tempLoader"; - -// import { setFloorItemApi } from "../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; -import objectLineToArray from "../builder/geomentries/lines/lineConvertions/objectLineToArray"; -import addLineToScene from "../builder/geomentries/lines/addLineToScene"; -import updateLinesPositions from "../builder/geomentries/lines/updateLinesPositions"; -import updateLines from "../builder/geomentries/lines/updateLines"; -import updateDistanceText from "../builder/geomentries/lines/updateDistanceText"; -import updateFloorLines from "../builder/geomentries/floors/updateFloorLines"; -import loadWalls from "../builder/geomentries/walls/loadWalls"; -import RemoveConnectedLines from "../builder/geomentries/lines/removeConnectedLines"; -import Layer2DVisibility from "../builder/geomentries/layers/layer2DVisibility"; -import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; -import { retrieveGLTF, storeGLTF } from "../../utils/indexDB/idbUtils"; -import { getZonesApi } from "../../services/factoryBuilder/zones/getZonesApi"; - - -export default function SocketResponses({ - floorPlanGroup, - lines, - floorGroup, - floorGroupAisle, - scene, - onlyFloorlines, - AssetConfigurations, - itemsGroup, - isTempLoader, - tempLoader, - currentLayerPoint, - floorPlanGroupPoint, - floorPlanGroupLine, - zoneGroup, - dragPointControls -}: any) { - - const { socket } = useSocketStore(); - const { activeLayer, setActiveLayer } = useActiveLayer(); - const { wallItems, setWallItems } = useWallItems(); - const { layers, setLayers } = useLayers(); - const { floorItems, setFloorItems } = useFloorItems(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { walls, setWalls } = useWalls(); - const { deletedLines, setDeletedLines } = useDeletedLines(); - const { newLines, setNewLines } = useNewLines(); - const { zones, setZones } = useZones(); - const { zonePoints, setZonePoints } = useZonePoints(); - - useEffect(() => { - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - if (!socket) return - - socket.on('cameraCreateResponse', (data: any) => { - // console.log('data: ', data); - }) - - socket.on('userConnectRespones', (data: any) => { - // console.log('data: ', data); - }) - - socket.on('userDisConnectRespones', (data: any) => { - // console.log('data: ', data); - }) - - socket.on('cameraUpdateResponse', (data: any) => { - // console.log('data: ', data); - }) - - socket.on('EnvironmentUpdateResponse', (data: any) => { - // console.log('data: ', data); - }) - - socket.on('model-asset:response:updates', async (data: any) => { - // console.log('data: ', data); - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "Model created successfully") { - const loader = new GLTFLoader(); - const dracoLoader = new DRACOLoader(); - - dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); - loader.setDRACOLoader(dracoLoader); - let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - - try { - isTempLoader.current = true; - const cachedModel = THREE.Cache.get(data.data.modelname); - let url; - if (cachedModel) { - // console.log(`Getting ${data.data.modelname} from cache`); - const model = cachedModel.scene.clone(); - model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; - model.position.set(...data.data.position as [number, number, number]); - model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); - model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - - model.traverse((child: any) => { - if (child.isMesh) { - // Clone the material to ensure changes are independent - // child.material = child.material.clone(); - - child.castShadow = true; - child.receiveShadow = true; - } - }); - - itemsGroup.current.add(model); - - if (tempLoader.current) { - tempLoader.current.material.dispose(); - tempLoader.current.geometry.dispose(); - itemsGroup.current.remove(tempLoader.current); - tempLoader.current = undefined; - } - - const newFloorItem: Types.FloorItemType = { - modeluuid: data.data.modeluuid, - modelname: data.data.modelname, - modelfileID: data.data.modelfileID, - position: [...data.data.position as [number, number, number]], - rotation: { - x: model.rotation.x, - y: model.rotation.y, - z: model.rotation.z, - }, - isLocked: data.data.isLocked, - isVisible: data.data.isVisible, - }; - - setFloorItems((prevItems: any) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - - gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' }); - gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); - - } else { - const indexedDBModel = await retrieveGLTF(data.data.modelname); - if (indexedDBModel) { - // console.log(`Getting ${data.data.modelname} from IndexedDB`); - url = URL.createObjectURL(indexedDBModel); - } else { - // console.log(`Getting ${data.data.modelname} from Backend`); - url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`; - const modelBlob = await fetch(url).then((res) => res.blob()); - await storeGLTF(data.data.modelfileID, modelBlob); - } - } - - if (url) { - loadModel(url); - } - - } catch (error) { - console.error('Error fetching asset model:', error); - } - - function loadModel(url: string) { - loader.load(url, (gltf) => { - URL.revokeObjectURL(url); - THREE.Cache.remove(url); - const model = gltf.scene; - model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; - model.position.set(...data.data.position as [number, number, number]); - model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); - model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - - model.traverse((child: any) => { - if (child.isMesh) { - // Clone the material to ensure changes are independent - // child.material = child.material.clone(); - - child.castShadow = true; - child.receiveShadow = true; - } - }); - - itemsGroup.current.add(model); - - if (tempLoader.current) { - tempLoader.current.material.dispose(); - tempLoader.current.geometry.dispose(); - itemsGroup.current.remove(tempLoader.current); - tempLoader.current = undefined; - } - - const newFloorItem: Types.FloorItemType = { - modeluuid: data.data.modeluuid, - modelname: data.data.modelname, - modelfileID: data.data.modelfileID, - position: [...data.data.position as [number, number, number]], - rotation: { - x: model.rotation.x, - y: model.rotation.y, - z: model.rotation.z, - }, - isLocked: data.data.isLocked, - isVisible: data.data.isVisible, - }; - - setFloorItems((prevItems: any) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - - gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' }); - gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); - - THREE.Cache.add(data.data.modelname, gltf); - }, () => { - TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup); - }); - } - - } else if (data.message === "Model updated successfully") { - itemsGroup.current?.children.forEach((item: THREE.Group) => { - if (item.uuid === data.data.modeluuid) { - item.position.set(...data.data.position as [number, number, number]); - item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); - } - }) - - setFloorItems((prevItems: Types.FloorItems) => { - if (!prevItems) { - return - } - let updatedItem: any = null; - const updatedItems = prevItems.map((item) => { - if (item.modeluuid === data.data.modeluuid) { - updatedItem = { - ...item, - position: [...data.data.position] as [number, number, number], - rotation: { x: data.data.rotation.x, y: data.data.rotation.y, z: data.data.rotation.z, }, - }; - return updatedItem; - } - return item; - }); - return updatedItems; - }) - } - }) - - socket.on('model-asset:response:updates', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "Model deleted successfully") { - const deletedUUID = data.data.modeluuid; - let items = JSON.parse(localStorage.getItem("FloorItems")!); - - const updatedItems = items.filter( - (item: { modeluuid: string }) => item.modeluuid !== deletedUUID - ); - - const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); - const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== deletedUUID); - localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); - - itemsGroup.current.children.forEach((item: any) => { - if (item.uuid === deletedUUID) { - itemsGroup.current.remove(item); - } - }) - setFloorItems(updatedItems); - toast.success("Model Removed!"); - } - }) - - socket.on('Line:response:update', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "line updated") { - const DraggedUUID = data.data.uuid; - const DraggedPosition = new THREE.Vector3(data.data.position.x, data.data.position.y, data.data.position.z); - - const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', DraggedUUID); - point.position.set(DraggedPosition.x, DraggedPosition.y, DraggedPosition.z); - const affectedLines = updateLinesPositions({ uuid: DraggedUUID, position: DraggedPosition }, lines); - - updateLines(floorPlanGroupLine, affectedLines); - updateDistanceText(scene, floorPlanGroupLine, affectedLines); - updateFloorLines(onlyFloorlines, { uuid: DraggedUUID, position: DraggedPosition }); - - loadWalls(lines, setWalls); - setUpdateScene(true); - - } - }) - - socket.on('Line:response:delete', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "line deleted") { - const line = objectLineToArray(data.data); - const linePoints = line; - const connectedpoints = [linePoints[0][1], linePoints[1][1]]; - - - onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) => - floorline.filter((line: any) => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1]) - ).filter((floorline: any) => floorline.length > 0); - - const removedLine = lines.current.find((item: any) => (item[0][1] === linePoints[0][1] && item[1][1] === linePoints[1][1] || (item[0][1] === linePoints[1][1] && item[1][1] === linePoints[0][1]))); - lines.current = lines.current.filter((item: any) => item !== removedLine); - - floorPlanGroupLine.current.children.forEach((line: any) => { - const linePoints = line.userData.linePoints as [number, string, number][]; - const uuid1 = linePoints[0][1]; - const uuid2 = linePoints[1][1]; - - if ((uuid1 === connectedpoints[0] && uuid2 === connectedpoints[1] || (uuid1 === connectedpoints[1] && uuid2 === connectedpoints[0]))) { - line.material.dispose(); - line.geometry.dispose(); - floorPlanGroupLine.current.remove(line); - setDeletedLines([line.userData.linePoints]) - } - }); - - connectedpoints.forEach((pointUUID) => { - let isConnected = false; - floorPlanGroupLine.current.children.forEach((line: any) => { - const linePoints = line.userData.linePoints; - const uuid1 = linePoints[0][1]; - const uuid2 = linePoints[1][1]; - if (uuid1 === pointUUID || uuid2 === pointUUID) { - isConnected = true; - } - }); - - if (!isConnected) { - floorPlanGroupPoint.current.children.forEach((point: any) => { - if (point.uuid === pointUUID) { - point.material.dispose(); - point.geometry.dispose(); - floorPlanGroupPoint.current.remove(point); - } - }); - } - }); - - loadWalls(lines, setWalls); - setUpdateScene(true); - - toast.success("Line Removed!"); - } - }) - - socket.on('Line:response:delete:point', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "point deleted") { - const point = floorPlanGroupPoint.current?.getObjectByProperty('uuid', data.data); - point.material.dispose(); - point.geometry.dispose(); - floorPlanGroupPoint.current.remove(point); - - onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) => - floorline.filter((line: any) => line[0][1] !== data.data && line[1][1] !== data.data) - ).filter((floorline: any) => floorline.length > 0); - - RemoveConnectedLines(data.data, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines); - - loadWalls(lines, setWalls); - setUpdateScene(true); - - toast.success("Point Removed!"); - } - }) - - socket.on('Line:response:delete:layer', async (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "layer deleted") { - setActiveLayer(1) - const removedLayer = data.data; - const removedLines: Types.Lines = lines.current.filter((line: any) => line[0][2] === removedLayer); - - ////////// Remove Points and lines from the removed layer ////////// - - removedLines.forEach(async (line) => { - line.forEach(async (removedPoint) => { - const removableLines: THREE.Mesh[] = []; - const connectedpoints: string[] = []; - - floorPlanGroupLine.current.children.forEach((line: any) => { - const linePoints = line.userData.linePoints as [number, string, number][]; - const uuid1 = linePoints[0][1]; - const uuid2 = linePoints[1][1]; - - if (uuid1 === removedPoint[1] || uuid2 === removedPoint[1]) { - connectedpoints.push(uuid1 === removedPoint[1] ? uuid2 : uuid1); - removableLines.push(line as THREE.Mesh); - } - }); - - if (removableLines.length > 0) { - removableLines.forEach((line: any) => { - lines.current = lines.current.filter((item: any) => JSON.stringify(item) !== JSON.stringify(line.userData.linePoints)); - line.material.dispose(); - line.geometry.dispose(); - floorPlanGroupLine.current.remove(line); - }); - } - - const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', removedPoint[1]); - if (point) { - point.material.dispose(); - point.geometry.dispose(); - floorPlanGroupPoint.current.remove(point) - } - }); - }); - - ////////// Update the remaining lines layer values in the userData and in lines.current ////////// - - let remaining = lines.current.filter((line: any) => line[0][2] !== removedLayer); - let updatedLines: Types.Lines = []; - remaining.forEach((line: any) => { - let newLines = JSON.parse(JSON.stringify(line)); - if (newLines[0][2] > removedLayer) { - newLines[0][2] -= 1; - newLines[1][2] -= 1; - } - - const matchingLine = floorPlanGroupLine.current.children.find((l: any) => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]); - if (matchingLine) { - const updatedUserData = JSON.parse(JSON.stringify(matchingLine.userData)); - updatedUserData.linePoints[0][2] = newLines[0][2]; - updatedUserData.linePoints[1][2] = newLines[1][2]; - matchingLine.userData = updatedUserData; - } - updatedLines.push(newLines); - }); - - lines.current = updatedLines; - localStorage.setItem("Lines", JSON.stringify(lines.current)); - - ////////// Also remove OnlyFloorLines and update it in localstorage ////////// - - onlyFloorlines.current = onlyFloorlines.current.filter((floor: any) => { - return floor[0][0][2] !== removedLayer; - }); - const meshToRemove = floorGroup.current?.children.find((mesh: any) => - mesh.name === `Only_Floor_Line_${removedLayer}` - ); - if (meshToRemove) { - meshToRemove.geometry.dispose(); - meshToRemove.material.dispose(); - floorGroup.current?.remove(meshToRemove); - } - - const zonesData = await getZonesApi(organization); - const highestLayer = Math.max( - 1, - lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), - zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) - ); - - setLayers(highestLayer); - - loadWalls(lines, setWalls); - setUpdateScene(true); - - toast.success("Layer Removed!"); - } - }) - }, [socket]) - - useEffect(() => { - if (!socket) return - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - socket.on('wallItemsDeleteResponse', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "wallitem deleted") { - const deletedUUID = data.data.modeluuid; - let WallItemsRef = wallItems; - const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID); - - setWallItems([]); - setTimeout(async () => { - WallItemsRef = Items; - setWallItems(WallItemsRef); - const WallItemsForStorage = WallItemsRef.map((item: any) => { - const { model, ...rest } = item; - return { - ...rest, - modeluuid: model?.uuid, - }; - }); - - localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); - toast.success("Model Removed!"); - }, 50); - } - }) - - socket.on('wallItemsUpdateResponse', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "wallIitem created") { - const loader = new GLTFLoader(); - loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => { - const model = gltf.scene; - model.uuid = data.data.modeluuid; - model.children[0].children.forEach((child) => { - if (child.name !== "CSG_REF") { - child.castShadow = true; - child.receiveShadow = true; - } - }); - - const newWallItem = { - type: data.data.type, - model: model, - modelname: data.data.modelname, - scale: data.data.scale, - csgscale: data.data.csgscale, - csgposition: data.data.csgposition, - position: data.data.position, - quaternion: data.data.quaternion - }; - - setWallItems((prevItems: any) => { - const updatedItems = [...prevItems, newWallItem]; - - const WallItemsForStorage = updatedItems.map(item => { - const { model, ...rest } = item; - return { - ...rest, - modeluuid: model?.uuid, - }; - }); - - localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); - toast.success("Model Added!"); - - return updatedItems; - }); - }); - } else if (data.message === "wallIitem updated") { - const updatedUUID = data.data.modeluuid; - - setWallItems((prevItems: any) => { - const updatedItems = prevItems.map((item: any) => { - if (item.model.uuid === updatedUUID) { - return { - ...item, - position: data.data.position, - quaternion: data.data.quaternion, - scale: data.data.scale, - csgscale: data.data.csgscale, - csgposition: data.data.csgposition, - }; - } - return item; - }); - - const WallItemsForStorage = updatedItems.map((item: any) => { - const { model, ...rest } = item; - return { - ...rest, - modeluuid: model?.uuid, - }; - }); - - localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); - toast.success("Model Updated!"); - - return updatedItems; - }); - - } - - }) - - return () => { - socket.off('wallItemsDeleteResponse'); - socket.off('wallItemsUpdateResponse'); - }; - }, [wallItems]) - - function getPointColor(lineType: string | undefined): string { - switch (lineType) { - case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor; - case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor; - case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor; - default: return CONSTANTS.pointConfig.defaultOuterColor; - } - } - - function getLineColor(lineType: string | undefined): string { - switch (lineType) { - case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor; - case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor; - case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor; - default: return CONSTANTS.lineConfig.defaultColor; - } - } - - useEffect(() => { - if (!socket) return - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - socket.on('Line:response:create', async (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "line create") { - const line: Types.Line = objectLineToArray(data.data); - const type = line[0][3]; - const pointColour = getPointColor(type); - const lineColour = getLineColor(type); - setNewLines([line]) - - line.forEach((line) => { - const existingPoint = floorPlanGroupPoint.current?.getObjectByProperty('uuid', line[1]); - if (existingPoint) { - return; - } - const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale); - const material = new THREE.ShaderMaterial({ - uniforms: { - uColor: { value: new THREE.Color(pointColour) }, // Blue color for the border - uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square - }, - vertexShader: ` - varying vec2 vUv; - - void main() { - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - } - `, - fragmentShader: ` - varying vec2 vUv; - uniform vec3 uColor; - uniform vec3 uInnerColor; - - void main() { - // Define the size of the white square as a proportion of the face - float borderThickness = 0.2; // Adjust this value for border thickness - if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness && - vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) { - gl_FragColor = vec4(uInnerColor, 1.0); // White inner square - } else { - gl_FragColor = vec4(uColor, 1.0); // Blue border - } - } - `, - }); - const point = new THREE.Mesh(geometry, material); - point.name = "point"; - point.uuid = line[1]; - point.userData = { type: type, color: pointColour }; - point.position.set(line[0].x, line[0].y, line[0].z); - currentLayerPoint.current.push(point); - - floorPlanGroupPoint.current?.add(point); - }) - if (dragPointControls.current) { - dragPointControls.current!.objects = currentLayerPoint.current; - } - addLineToScene( - new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), - new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), - lineColour, - line, - floorPlanGroupLine - ) - lines.current.push(line); - - const zonesData = await getZonesApi(organization); - const highestLayer = Math.max( - 1, - lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), - zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) - ); - - setLayers(highestLayer); - - Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls) - - loadWalls(lines, setWalls); - setUpdateScene(true); - } - }) - - return () => { - socket.off('Line:response:create'); - }; - }, [socket, activeLayer]) - - useEffect(() => { - if (!socket) return - const email = localStorage.getItem('email'); - const organization = (email!.split("@")[1]).split(".")[0]; - - socket.on('zone:response:updates', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - - if (data.message === "zone created") { - const pointsArray: [number, number, number][] = data.data.points; - const vector3Array = pointsArray.map(([x, y, z]) => new THREE.Vector3(x, y, z)); - const newZones = [...zones, data.data]; - setZones(newZones); - const updatedZonePoints = [...zonePoints, ...vector3Array]; - setZonePoints(updatedZonePoints); - - const highestLayer = Math.max( - 1, - lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), - newZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) - ); - - setLayers(highestLayer); - setUpdateScene(true); - } - - if (data.message === "zone updated") { - const updatedZones = zones.map((zone: any) => - zone.zoneId === data.data.zoneId ? data.data : zone - ); - setZones(updatedZones); - setUpdateScene(true); - } - - - }) - - socket.on('zone:response:delete', (data: any) => { - if (socket.id === data.socketId) { - return - } - if (organization !== data.organization) { - return - } - if (data.message === "zone deleted") { - const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId); - setZones(updatedZones); - - const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === data.data.zoneId); - if (zoneIndex !== -1) { - const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); - setZonePoints(updatedzonePoints); - } - - const highestLayer = Math.max( - 1, - lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), - updatedZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) - ); - - setLayers(highestLayer); - setUpdateScene(true); - } - }) - - return () => { - socket.off('zone:response:updates'); - socket.off('zone:response:delete'); - }; - }, [socket, zones, zonePoints]) - - return ( - <> - ) +import { useEffect } from "react"; +import * as THREE from 'three'; +import gsap from 'gsap'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; +import { toast } from 'react-toastify'; +import { useSocketStore, useActiveLayer, useWallItems, useFloorItems, useLayers, useUpdateScene, useWalls, useDeletedLines, useNewLines, useZonePoints, useZones } from "../../../store/store"; + +import * as Types from "../../../types/world/worldTypes"; +import * as CONSTANTS from '../../../types/world/worldConstants'; +import TempLoader from "../../builder/geomentries/assets/tempLoader"; + +// import { setFloorItemApi } from "../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; +import objectLineToArray from "../../builder/geomentries/lines/lineConvertions/objectLineToArray"; +import addLineToScene from "../../builder/geomentries/lines/addLineToScene"; +import updateLinesPositions from "../../builder/geomentries/lines/updateLinesPositions"; +import updateLines from "../../builder/geomentries/lines/updateLines"; +import updateDistanceText from "../../builder/geomentries/lines/updateDistanceText"; +import updateFloorLines from "../../builder/geomentries/floors/updateFloorLines"; +import loadWalls from "../../builder/geomentries/walls/loadWalls"; +import RemoveConnectedLines from "../../builder/geomentries/lines/removeConnectedLines"; +import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility"; +import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils"; +import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; + + +export default function SocketResponses({ + floorPlanGroup, + lines, + floorGroup, + floorGroupAisle, + scene, + onlyFloorlines, + AssetConfigurations, + itemsGroup, + isTempLoader, + tempLoader, + currentLayerPoint, + floorPlanGroupPoint, + floorPlanGroupLine, + zoneGroup, + dragPointControls +}: any) { + + const { socket } = useSocketStore(); + const { activeLayer, setActiveLayer } = useActiveLayer(); + const { wallItems, setWallItems } = useWallItems(); + const { layers, setLayers } = useLayers(); + const { floorItems, setFloorItems } = useFloorItems(); + const { updateScene, setUpdateScene } = useUpdateScene(); + const { walls, setWalls } = useWalls(); + const { deletedLines, setDeletedLines } = useDeletedLines(); + const { newLines, setNewLines } = useNewLines(); + const { zones, setZones } = useZones(); + const { zonePoints, setZonePoints } = useZonePoints(); + + useEffect(() => { + + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + if (!socket) return + + socket.on('cameraCreateResponse', (data: any) => { + // console.log('data: ', data); + }) + + socket.on('userConnectRespones', (data: any) => { + // console.log('data: ', data); + }) + + socket.on('userDisConnectRespones', (data: any) => { + // console.log('data: ', data); + }) + + socket.on('cameraUpdateResponse', (data: any) => { + // console.log('data: ', data); + }) + + socket.on('EnvironmentUpdateResponse', (data: any) => { + // console.log('data: ', data); + }) + + socket.on('model-asset:response:updates', async (data: any) => { + // console.log('data: ', data); + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "Model created successfully") { + const loader = new GLTFLoader(); + const dracoLoader = new DRACOLoader(); + + dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); + loader.setDRACOLoader(dracoLoader); + let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; + + try { + isTempLoader.current = true; + const cachedModel = THREE.Cache.get(data.data.modelname); + let url; + if (cachedModel) { + // console.log(`Getting ${data.data.modelname} from cache`); + const model = cachedModel.scene.clone(); + model.uuid = data.data.modeluuid; + model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; + model.position.set(...data.data.position as [number, number, number]); + model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); + model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); + + model.traverse((child: any) => { + if (child.isMesh) { + // Clone the material to ensure changes are independent + // child.material = child.material.clone(); + + child.castShadow = true; + child.receiveShadow = true; + } + }); + + itemsGroup.current.add(model); + + if (tempLoader.current) { + tempLoader.current.material.dispose(); + tempLoader.current.geometry.dispose(); + itemsGroup.current.remove(tempLoader.current); + tempLoader.current = undefined; + } + + const newFloorItem: Types.FloorItemType = { + modeluuid: data.data.modeluuid, + modelname: data.data.modelname, + modelfileID: data.data.modelfileID, + position: [...data.data.position as [number, number, number]], + rotation: { + x: model.rotation.x, + y: model.rotation.y, + z: model.rotation.z, + }, + isLocked: data.data.isLocked, + isVisible: data.data.isVisible, + }; + + setFloorItems((prevItems: any) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' }); + gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); + + } else { + const indexedDBModel = await retrieveGLTF(data.data.modelname); + if (indexedDBModel) { + // console.log(`Getting ${data.data.modelname} from IndexedDB`); + url = URL.createObjectURL(indexedDBModel); + } else { + // console.log(`Getting ${data.data.modelname} from Backend`); + url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`; + const modelBlob = await fetch(url).then((res) => res.blob()); + await storeGLTF(data.data.modelfileID, modelBlob); + } + } + + if (url) { + loadModel(url); + } + + } catch (error) { + console.error('Error fetching asset model:', error); + } + + function loadModel(url: string) { + loader.load(url, (gltf) => { + URL.revokeObjectURL(url); + THREE.Cache.remove(url); + const model = gltf.scene; + model.uuid = data.data.modeluuid; + model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; + model.position.set(...data.data.position as [number, number, number]); + model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); + model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); + + model.traverse((child: any) => { + if (child.isMesh) { + // Clone the material to ensure changes are independent + // child.material = child.material.clone(); + + child.castShadow = true; + child.receiveShadow = true; + } + }); + + itemsGroup.current.add(model); + + if (tempLoader.current) { + tempLoader.current.material.dispose(); + tempLoader.current.geometry.dispose(); + itemsGroup.current.remove(tempLoader.current); + tempLoader.current = undefined; + } + + const newFloorItem: Types.FloorItemType = { + modeluuid: data.data.modeluuid, + modelname: data.data.modelname, + modelfileID: data.data.modelfileID, + position: [...data.data.position as [number, number, number]], + rotation: { + x: model.rotation.x, + y: model.rotation.y, + z: model.rotation.z, + }, + isLocked: data.data.isLocked, + isVisible: data.data.isVisible, + }; + + setFloorItems((prevItems: any) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' }); + gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); + + THREE.Cache.add(data.data.modelname, gltf); + }, () => { + TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup); + }); + } + + } else if (data.message === "Model updated successfully") { + itemsGroup.current?.children.forEach((item: THREE.Group) => { + if (item.uuid === data.data.modeluuid) { + item.position.set(...data.data.position as [number, number, number]); + item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); + } + }) + + setFloorItems((prevItems: Types.FloorItems) => { + if (!prevItems) { + return + } + let updatedItem: any = null; + const updatedItems = prevItems.map((item) => { + if (item.modeluuid === data.data.modeluuid) { + updatedItem = { + ...item, + position: [...data.data.position] as [number, number, number], + rotation: { x: data.data.rotation.x, y: data.data.rotation.y, z: data.data.rotation.z, }, + }; + return updatedItem; + } + return item; + }); + return updatedItems; + }) + } + }) + + socket.on('model-asset:response:updates', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "Model deleted successfully") { + const deletedUUID = data.data.modeluuid; + let items = JSON.parse(localStorage.getItem("FloorItems")!); + + const updatedItems = items.filter( + (item: { modeluuid: string }) => item.modeluuid !== deletedUUID + ); + + const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); + const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== deletedUUID); + localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); + + itemsGroup.current.children.forEach((item: any) => { + if (item.uuid === deletedUUID) { + itemsGroup.current.remove(item); + } + }) + setFloorItems(updatedItems); + toast.success("Model Removed!"); + } + }) + + socket.on('Line:response:update', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "line updated") { + const DraggedUUID = data.data.uuid; + const DraggedPosition = new THREE.Vector3(data.data.position.x, data.data.position.y, data.data.position.z); + + const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', DraggedUUID); + point.position.set(DraggedPosition.x, DraggedPosition.y, DraggedPosition.z); + const affectedLines = updateLinesPositions({ uuid: DraggedUUID, position: DraggedPosition }, lines); + + updateLines(floorPlanGroupLine, affectedLines); + updateDistanceText(scene, floorPlanGroupLine, affectedLines); + updateFloorLines(onlyFloorlines, { uuid: DraggedUUID, position: DraggedPosition }); + + loadWalls(lines, setWalls); + setUpdateScene(true); + + } + }) + + socket.on('Line:response:delete', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "line deleted") { + const line = objectLineToArray(data.data); + const linePoints = line; + const connectedpoints = [linePoints[0][1], linePoints[1][1]]; + + + onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) => + floorline.filter((line: any) => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1]) + ).filter((floorline: any) => floorline.length > 0); + + const removedLine = lines.current.find((item: any) => (item[0][1] === linePoints[0][1] && item[1][1] === linePoints[1][1] || (item[0][1] === linePoints[1][1] && item[1][1] === linePoints[0][1]))); + lines.current = lines.current.filter((item: any) => item !== removedLine); + + floorPlanGroupLine.current.children.forEach((line: any) => { + const linePoints = line.userData.linePoints as [number, string, number][]; + const uuid1 = linePoints[0][1]; + const uuid2 = linePoints[1][1]; + + if ((uuid1 === connectedpoints[0] && uuid2 === connectedpoints[1] || (uuid1 === connectedpoints[1] && uuid2 === connectedpoints[0]))) { + line.material.dispose(); + line.geometry.dispose(); + floorPlanGroupLine.current.remove(line); + setDeletedLines([line.userData.linePoints]) + } + }); + + connectedpoints.forEach((pointUUID) => { + let isConnected = false; + floorPlanGroupLine.current.children.forEach((line: any) => { + const linePoints = line.userData.linePoints; + const uuid1 = linePoints[0][1]; + const uuid2 = linePoints[1][1]; + if (uuid1 === pointUUID || uuid2 === pointUUID) { + isConnected = true; + } + }); + + if (!isConnected) { + floorPlanGroupPoint.current.children.forEach((point: any) => { + if (point.uuid === pointUUID) { + point.material.dispose(); + point.geometry.dispose(); + floorPlanGroupPoint.current.remove(point); + } + }); + } + }); + + loadWalls(lines, setWalls); + setUpdateScene(true); + + toast.success("Line Removed!"); + } + }) + + socket.on('Line:response:delete:point', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "point deleted") { + const point = floorPlanGroupPoint.current?.getObjectByProperty('uuid', data.data); + point.material.dispose(); + point.geometry.dispose(); + floorPlanGroupPoint.current.remove(point); + + onlyFloorlines.current = onlyFloorlines.current.map((floorline: any) => + floorline.filter((line: any) => line[0][1] !== data.data && line[1][1] !== data.data) + ).filter((floorline: any) => floorline.length > 0); + + RemoveConnectedLines(data.data, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines); + + loadWalls(lines, setWalls); + setUpdateScene(true); + + toast.success("Point Removed!"); + } + }) + + socket.on('Line:response:delete:layer', async (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "layer deleted") { + setActiveLayer(1) + const removedLayer = data.data; + const removedLines: Types.Lines = lines.current.filter((line: any) => line[0][2] === removedLayer); + + ////////// Remove Points and lines from the removed layer ////////// + + removedLines.forEach(async (line) => { + line.forEach(async (removedPoint) => { + const removableLines: THREE.Mesh[] = []; + const connectedpoints: string[] = []; + + floorPlanGroupLine.current.children.forEach((line: any) => { + const linePoints = line.userData.linePoints as [number, string, number][]; + const uuid1 = linePoints[0][1]; + const uuid2 = linePoints[1][1]; + + if (uuid1 === removedPoint[1] || uuid2 === removedPoint[1]) { + connectedpoints.push(uuid1 === removedPoint[1] ? uuid2 : uuid1); + removableLines.push(line as THREE.Mesh); + } + }); + + if (removableLines.length > 0) { + removableLines.forEach((line: any) => { + lines.current = lines.current.filter((item: any) => JSON.stringify(item) !== JSON.stringify(line.userData.linePoints)); + line.material.dispose(); + line.geometry.dispose(); + floorPlanGroupLine.current.remove(line); + }); + } + + const point = floorPlanGroupPoint.current.getObjectByProperty('uuid', removedPoint[1]); + if (point) { + point.material.dispose(); + point.geometry.dispose(); + floorPlanGroupPoint.current.remove(point) + } + }); + }); + + ////////// Update the remaining lines layer values in the userData and in lines.current ////////// + + let remaining = lines.current.filter((line: any) => line[0][2] !== removedLayer); + let updatedLines: Types.Lines = []; + remaining.forEach((line: any) => { + let newLines = JSON.parse(JSON.stringify(line)); + if (newLines[0][2] > removedLayer) { + newLines[0][2] -= 1; + newLines[1][2] -= 1; + } + + const matchingLine = floorPlanGroupLine.current.children.find((l: any) => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]); + if (matchingLine) { + const updatedUserData = JSON.parse(JSON.stringify(matchingLine.userData)); + updatedUserData.linePoints[0][2] = newLines[0][2]; + updatedUserData.linePoints[1][2] = newLines[1][2]; + matchingLine.userData = updatedUserData; + } + updatedLines.push(newLines); + }); + + lines.current = updatedLines; + localStorage.setItem("Lines", JSON.stringify(lines.current)); + + ////////// Also remove OnlyFloorLines and update it in localstorage ////////// + + onlyFloorlines.current = onlyFloorlines.current.filter((floor: any) => { + return floor[0][0][2] !== removedLayer; + }); + const meshToRemove = floorGroup.current?.children.find((mesh: any) => + mesh.name === `Only_Floor_Line_${removedLayer}` + ); + if (meshToRemove) { + meshToRemove.geometry.dispose(); + meshToRemove.material.dispose(); + floorGroup.current?.remove(meshToRemove); + } + + const zonesData = await getZonesApi(organization); + const highestLayer = Math.max( + 1, + lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), + zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) + ); + + setLayers(highestLayer); + + loadWalls(lines, setWalls); + setUpdateScene(true); + + toast.success("Layer Removed!"); + } + }) + }, [socket]) + + useEffect(() => { + if (!socket) return + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + socket.on('wallItemsDeleteResponse', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "wallitem deleted") { + const deletedUUID = data.data.modeluuid; + let WallItemsRef = wallItems; + const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID); + + setWallItems([]); + setTimeout(async () => { + WallItemsRef = Items; + setWallItems(WallItemsRef); + const WallItemsForStorage = WallItemsRef.map((item: any) => { + const { model, ...rest } = item; + return { + ...rest, + modeluuid: model?.uuid, + }; + }); + + localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); + toast.success("Model Removed!"); + }, 50); + } + }) + + socket.on('wallItemsUpdateResponse', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "wallIitem created") { + const loader = new GLTFLoader(); + loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => { + const model = gltf.scene; + model.uuid = data.data.modeluuid; + model.children[0].children.forEach((child) => { + if (child.name !== "CSG_REF") { + child.castShadow = true; + child.receiveShadow = true; + } + }); + + const newWallItem = { + type: data.data.type, + model: model, + modelname: data.data.modelname, + scale: data.data.scale, + csgscale: data.data.csgscale, + csgposition: data.data.csgposition, + position: data.data.position, + quaternion: data.data.quaternion + }; + + setWallItems((prevItems: any) => { + const updatedItems = [...prevItems, newWallItem]; + + const WallItemsForStorage = updatedItems.map(item => { + const { model, ...rest } = item; + return { + ...rest, + modeluuid: model?.uuid, + }; + }); + + localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); + toast.success("Model Added!"); + + return updatedItems; + }); + }); + } else if (data.message === "wallIitem updated") { + const updatedUUID = data.data.modeluuid; + + setWallItems((prevItems: any) => { + const updatedItems = prevItems.map((item: any) => { + if (item.model.uuid === updatedUUID) { + return { + ...item, + position: data.data.position, + quaternion: data.data.quaternion, + scale: data.data.scale, + csgscale: data.data.csgscale, + csgposition: data.data.csgposition, + }; + } + return item; + }); + + const WallItemsForStorage = updatedItems.map((item: any) => { + const { model, ...rest } = item; + return { + ...rest, + modeluuid: model?.uuid, + }; + }); + + localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); + toast.success("Model Updated!"); + + return updatedItems; + }); + + } + + }) + + return () => { + socket.off('wallItemsDeleteResponse'); + socket.off('wallItemsUpdateResponse'); + }; + }, [wallItems]) + + function getPointColor(lineType: string | undefined): string { + switch (lineType) { + case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor; + case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor; + case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor; + default: return CONSTANTS.pointConfig.defaultOuterColor; + } + } + + function getLineColor(lineType: string | undefined): string { + switch (lineType) { + case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor; + case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor; + case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor; + default: return CONSTANTS.lineConfig.defaultColor; + } + } + + useEffect(() => { + if (!socket) return + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + socket.on('Line:response:create', async (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "line create") { + const line: Types.Line = objectLineToArray(data.data); + const type = line[0][3]; + const pointColour = getPointColor(type); + const lineColour = getLineColor(type); + setNewLines([line]) + + line.forEach((line) => { + const existingPoint = floorPlanGroupPoint.current?.getObjectByProperty('uuid', line[1]); + if (existingPoint) { + return; + } + const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale); + const material = new THREE.ShaderMaterial({ + uniforms: { + uColor: { value: new THREE.Color(pointColour) }, // Blue color for the border + uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square + }, + vertexShader: ` + varying vec2 vUv; + + void main() { + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + } + `, + fragmentShader: ` + varying vec2 vUv; + uniform vec3 uColor; + uniform vec3 uInnerColor; + + void main() { + // Define the size of the white square as a proportion of the face + float borderThickness = 0.2; // Adjust this value for border thickness + if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness && + vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) { + gl_FragColor = vec4(uInnerColor, 1.0); // White inner square + } else { + gl_FragColor = vec4(uColor, 1.0); // Blue border + } + } + `, + }); + const point = new THREE.Mesh(geometry, material); + point.name = "point"; + point.uuid = line[1]; + point.userData = { type: type, color: pointColour }; + point.position.set(line[0].x, line[0].y, line[0].z); + currentLayerPoint.current.push(point); + + floorPlanGroupPoint.current?.add(point); + }) + if (dragPointControls.current) { + dragPointControls.current!.objects = currentLayerPoint.current; + } + addLineToScene( + new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), + new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), + lineColour, + line, + floorPlanGroupLine + ) + lines.current.push(line); + + const zonesData = await getZonesApi(organization); + const highestLayer = Math.max( + 1, + lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), + zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) + ); + + setLayers(highestLayer); + + Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls) + + loadWalls(lines, setWalls); + setUpdateScene(true); + } + }) + + return () => { + socket.off('Line:response:create'); + }; + }, [socket, activeLayer]) + + useEffect(() => { + if (!socket) return + const email = localStorage.getItem('email'); + const organization = (email!.split("@")[1]).split(".")[0]; + + socket.on('zone:response:updates', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + + if (data.message === "zone created") { + const pointsArray: [number, number, number][] = data.data.points; + const vector3Array = pointsArray.map(([x, y, z]) => new THREE.Vector3(x, y, z)); + const newZones = [...zones, data.data]; + setZones(newZones); + const updatedZonePoints = [...zonePoints, ...vector3Array]; + setZonePoints(updatedZonePoints); + + const highestLayer = Math.max( + 1, + lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), + newZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) + ); + + setLayers(highestLayer); + setUpdateScene(true); + } + + if (data.message === "zone updated") { + const updatedZones = zones.map((zone: any) => + zone.zoneId === data.data.zoneId ? data.data : zone + ); + setZones(updatedZones); + setUpdateScene(true); + } + + + }) + + socket.on('zone:response:delete', (data: any) => { + if (socket.id === data.socketId) { + return + } + if (organization !== data.organization) { + return + } + if (data.message === "zone deleted") { + const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId); + setZones(updatedZones); + + const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === data.data.zoneId); + if (zoneIndex !== -1) { + const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); + setZonePoints(updatedzonePoints); + } + + const highestLayer = Math.max( + 1, + lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0), + updatedZones.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0) + ); + + setLayers(highestLayer); + setUpdateScene(true); + } + }) + + return () => { + socket.off('zone:response:updates'); + socket.off('zone:response:delete'); + }; + }, [socket, zones, zonePoints]) + + return ( + <> + ) } \ No newline at end of file diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index 41ededb..6564032 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -6,6 +6,7 @@ import Builder from "../builder/builder"; import Visualization from "../visualization/visualization"; import Setup from "./setup/setup"; import Simulation from "../simulation/simulation"; +import Collaboration from "../collaboration/collaboration"; export default function Scene() { const map = useMemo(() => [ @@ -21,6 +22,8 @@ export default function Scene() { + + diff --git a/app/src/modules/simulation/actions/temp.md b/app/src/modules/simulation/actions/temp.md new file mode 100644 index 0000000..e69de29 diff --git a/app/src/modules/simulation/events/points/temp.md b/app/src/modules/simulation/events/points/temp.md new file mode 100644 index 0000000..e69de29 diff --git a/app/src/modules/simulation/events/temp.md b/app/src/modules/simulation/events/temp.md new file mode 100644 index 0000000..e69de29 diff --git a/app/src/modules/simulation/products/temp.md b/app/src/modules/simulation/products/temp.md new file mode 100644 index 0000000..e69de29 diff --git a/app/src/modules/simulation/triggers/temp.md b/app/src/modules/simulation/triggers/temp.md new file mode 100644 index 0000000..e69de29 diff --git a/app/src/modules/visualization/mqttTemp/drieHtmlTemp.tsx b/app/src/modules/visualization/mqttTemp/drieHtmlTemp.tsx index 8604bcc..3e0adba 100644 --- a/app/src/modules/visualization/mqttTemp/drieHtmlTemp.tsx +++ b/app/src/modules/visualization/mqttTemp/drieHtmlTemp.tsx @@ -6,11 +6,11 @@ import UI from "./ui"; import { useEffect } from "react"; import { useThree } from "@react-three/fiber"; -export default function DrieHtmlTemp({ itemsGroup }: { itemsGroup: Types.RefGroup }) { +export default function DrieHtmlTemp() { const { drieTemp, setDrieTemp } = useDrieTemp(); const { drieUIValue, setDrieUIValue } = useDrieUIValue(); const state = useThree(); - const { camera, raycaster } = state; + const { camera, raycaster, scene } = state; useEffect(() => { const canvasElement = state.gl.domElement; @@ -34,8 +34,8 @@ export default function DrieHtmlTemp({ itemsGroup }: { itemsGroup: Types.RefGrou if (evt.button === 0) { isLeftMouseDown = false; if (drag) return; - if (!itemsGroup.current) return - let intersects = raycaster.intersectObjects(itemsGroup.current.children, true); + if (!scene) return + let intersects = raycaster.intersectObjects(scene.children, true); if (intersects.length > 0) { let currentObject = intersects[0].object; diff --git a/app/src/modules/visualization/visualization.tsx b/app/src/modules/visualization/visualization.tsx index 36c5537..e5b1692 100644 --- a/app/src/modules/visualization/visualization.tsx +++ b/app/src/modules/visualization/visualization.tsx @@ -2,7 +2,8 @@ import React from 'react' import Dropped3dWidgets from './widgets/3d/Dropped3dWidget' import ZoneCentreTarget from './zone/zoneCameraTarget' import ZoneAssets from './zone/zoneAssets' -// import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents' +import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents' +import DrieHtmlTemp from './mqttTemp/drieHtmlTemp' const Visualization = () => { return ( @@ -10,11 +11,14 @@ const Visualization = () => { - {/* + - */} + + + {/* */} + ) } diff --git a/app/src/store/useEventsStore.ts b/app/src/store/useEventsStore.ts new file mode 100644 index 0000000..2fc0317 --- /dev/null +++ b/app/src/store/useEventsStore.ts @@ -0,0 +1,349 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; +import { useProductStore } from './useSimulationStore'; + +type EventsStore = { + events: EventsSchema[]; + + // Sync with product store + syncFromProducts: (products: productsSchema) => void; + + // Event-level actions + addEvent: (event: EventsSchema) => void; + removeEvent: (modelUuid: string) => void; + updateEvent: (modelUuid: string, updates: Partial) => void; + + // Point-level actions + addPoint: (modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; + removePoint: (modelUuid: string, pointUuid: string) => void; + updatePoint: ( + modelUuid: string, + pointUuid: string, + updates: Partial + ) => void; + + // Action-level actions + addAction: ( + modelUuid: string, + pointUuid: string, + action: TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] + ) => void; + removeAction: (actionUuid: string) => void; + updateAction: ( + actionUuid: string, + updates: Partial + ) => void; + + // Trigger-level actions + addTrigger: (actionUuid: string, trigger: TriggerSchema) => void; + removeTrigger: (triggerUuid: string) => void; + updateTrigger: (triggerUuid: string, updates: Partial) => void; + + // Helper functions + getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined; + getPointByUuid: (modelUuid: string, pointUuid: string) => TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined; + getActionByUuid: (actionUuid: string) => (TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined; + getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined; +}; + +export const useEventsStore = create()( + immer((set, get) => ({ + events: [], + + // Sync events from products store + syncFromProducts: (products) => { + set((state) => { + state.events = products.flatMap(product => product.eventsData); + }); + }, + + // Event-level actions + addEvent: (event) => { + set((state) => { + state.events.push(event); + }); + }, + + removeEvent: (modelUuid) => { + set((state) => { + state.events = state.events.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid); + }); + }, + + updateEvent: (modelUuid, updates) => { + set((state) => { + const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + if (event) { + Object.assign(event, updates); + } + }); + }, + + // Point-level actions + addPoint: (modelUuid, point) => { + set((state) => { + const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + if (event && 'points' in event) { + (event as TransferEventSchema).points.push(point as TransferPointSchema); + } else if (event && 'point' in event) { + (event as VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent).point = point as any; + } + }); + }, + + removePoint: (modelUuid, pointUuid) => { + set((state) => { + const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + if (event && 'points' in event) { + (event as TransferEventSchema).points = (event as TransferEventSchema).points.filter(p => p.uuid !== pointUuid); + } + // For single-point events, you might want to handle differently + }); + }, + + updatePoint: (modelUuid, pointUuid, updates) => { + set((state) => { + const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + if (event && 'points' in event) { + const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + if (point) { + Object.assign(point, updates); + } + } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { + Object.assign((event as any).point, updates); + } + }); + }, + + // Action-level actions + addAction: (modelUuid, pointUuid, action) => { + set((state) => { + const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + if (event && 'points' in event) { + const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + if (point) { + point.action = action as any; + } + } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { + if ('action' in (event as any).point) { + (event as any).point.action = action; + } else if ('actions' in (event as any).point) { + (event as any).point.actions.push(action); + } + } + }); + }, + + removeAction: (actionUuid) => { + set((state) => { + for (const event of state.events) { + if ('points' in event) { + for (const point of (event as TransferEventSchema).points) { + if (point.action && point.action.actionUuid === actionUuid) { + // Handle removal for single action points + } + } + } else if ('point' in event) { + const point = (event as any).point; + if (event.type === "roboticArm") { + if ('actions' in point) { + point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid); + } + } else if ('action' in point && point.action?.actionUuid === actionUuid) { + // Handle single action + } + } + } + }); + }, + + updateAction: (actionUuid, updates) => { + set((state) => { + for (const event of state.events) { + if ('points' in event) { + for (const point of (event as TransferEventSchema).points) { + if (point.action && point.action.actionUuid === actionUuid) { + Object.assign(point.action, updates); + return; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && point.action.actionUuid === actionUuid) { + Object.assign(point.action, updates); + return; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) { + Object.assign(action, updates); + return; + } + } + } + } + }); + }, + + // Trigger-level actions + addTrigger: (actionUuid, trigger) => { + set((state) => { + for (const event of state.events) { + if ('points' in event) { + for (const point of (event as TransferEventSchema).points) { + if (point.action && point.action.actionUuid === actionUuid) { + point.action.triggers.push(trigger); + return; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && point.action.actionUuid === actionUuid) { + point.action.triggers.push(trigger); + return; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) { + action.triggers.push(trigger); + return; + } + } + } + } + }); + }, + + removeTrigger: (triggerUuid) => { + set((state) => { + for (const event of state.events) { + if ('points' in event) { + for (const point of (event as TransferEventSchema).points) { + if (point.action && 'triggers' in point.action) { + point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid); + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && 'triggers' in point.action) { + point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid); + } else if ('actions' in point) { + for (const action of point.actions) { + if ('triggers' in action) { + action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid); + } + } + } + } + } + }); + }, + + updateTrigger: (triggerUuid, updates) => { + set((state) => { + for (const event of state.events) { + if ('points' in event) { + for (const point of (event as TransferEventSchema).points) { + if (point.action && 'triggers' in point.action) { + const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); + if (trigger) { + Object.assign(trigger, updates); + return; + } + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && 'triggers' in point.action) { + const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) { + Object.assign(trigger, updates); + return; + } + } else if ('actions' in point) { + for (const action of point.actions) { + if ('triggers' in action) { + const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) { + Object.assign(trigger, updates); + return; + } + } + } + } + } + } + }); + }, + + // Helper functions + getEventByModelUuid: (modelUuid) => { + return get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + }, + + getPointByUuid: (modelUuid, pointUuid) => { + const event = get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + if (event && 'points' in event) { + return (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { + return (event as any).point; + } + return undefined; + }, + + getActionByUuid: (actionUuid) => { + const state = get(); + for (const event of state.events) { + if ('points' in event) { + for (const point of (event as TransferEventSchema).points) { + if (point.action && point.action.actionUuid === actionUuid) { + return point.action; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && point.action.actionUuid === actionUuid) { + return point.action; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) return action; + } + } + } + return undefined; + }, + + getTriggerByUuid: (triggerUuid) => { + const state = get(); + for (const event of state.events) { + if ('points' in event) { + for (const point of (event as TransferEventSchema).points) { + if (point.action && 'triggers' in point.action) { + const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); + if (trigger) return trigger; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && 'triggers' in point.action) { + const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) return trigger; + } else if ('actions' in point) { + for (const action of point.actions) { + if ('triggers' in action) { + const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) return trigger; + } + } + } + } + } + return undefined; + } + })) +); + +// Set up automatic syncing between stores +useProductStore.subscribe( + (state) => { + useEventsStore.getState().syncFromProducts(state.products); + } +); \ No newline at end of file diff --git a/app/src/store/useSimulationStore.ts b/app/src/store/useSimulationStore.ts index c1d76cd..f0c3a56 100644 --- a/app/src/store/useSimulationStore.ts +++ b/app/src/store/useSimulationStore.ts @@ -1,134 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface AssetEventSchema { - modelUuid: string; - modelName: string; - position: [number, number, number]; - rotation: [number, number, number]; - state: "idle" | "running" | "stopped" | "disabled" | "error"; -} - -interface TriggerSchema { - triggerUuid: string; - triggerName: string; - triggerType: "onComplete" | "onStart" | "onStop" | "delay" | "onError"; - delay: number; - triggeredAsset: { - triggeredModel: { modelName: string, modelUuid: string }; - triggeredAction: { actionName: string, actionUuid: string }; - } | null; -} - -interface TransferPointSchema { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { - actionUuid: string; - actionName: string; - actionType: "default" | "spawn" | "swap" | "despawn"; - material: string | "inherit"; - delay: number | "inherit"; - spawnInterval: number | "inherit"; - spawnCount: number | "inherit"; - triggers: TriggerSchema[]; - }[]; -} - -interface VehiclePointSchema { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { - actionUuid: string; - actionName: string; - actionType: "travel"; - material: string; - unLoadDuration: number; - loadCapacity: number; - pickUpPoint: { x: number; y: number, z: number } | {}; - unLoadPoint: { x: number; y: number, z: number } | {}; - triggers: TriggerSchema[]; - }[]; -} - -interface RoboticArmPointSchema { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { - actionUuid: string; - actionName: string; - actionType: "pickAndPlace"; - process: { startPoint: string; endPoint: string }; - triggers: TriggerSchema[]; - }[]; -} - -interface MachinePointSchema { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { - actionUuid: string; - actionName: string; - actionType: "process"; - processTime: number; - swapMaterial: string; - triggers: TriggerSchema[]; - }[]; -} - -interface StoragePointSchema { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { - actionUuid: string; - actionName: string; - actionType: "storage"; - materials: { materialName: string; materialId: string; quantity: number }[]; - storageCapacity: number; - }[]; -} - -interface TransferEventSchema extends AssetEventSchema { - type: "transfer"; - speed: number; - points: TransferPointSchema[]; -} - -interface VehicleSchemaEvent extends AssetEventSchema { - type: "vehicle"; - speed: number; - point: VehiclePointSchema; -} - -interface RoboticArmSchemaEvent extends AssetEventSchema { - type: "roboticArm"; - speed: number; - point: RoboticArmPointSchema; -} - -interface MachineSchemaEvent extends AssetEventSchema { - type: "machine"; - point: MachinePointSchema; -} - -interface StorageSchemaEvent extends AssetEventSchema { - type: "storageUnit"; - point: StoragePointSchema; -} - -type EventsSchema = TransferEventSchema | VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent | []; - -type productsSchema = { - productName: string; - productId: string; - eventsData: EventsSchema[]; -}[] - type Store = { products: productsSchema; @@ -138,14 +10,14 @@ type Store = { updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void; // Event-level actions - addEventToProduct: (productId: string, event: EventsSchema) => void; - removeEventFromProduct: (productId: string, modelUuid: string) => void; - updateEventInProduct: (productId: string, modelUuid: string, updates: Partial) => void; + addEvent: (productId: string, event: EventsSchema) => void; + removeEvent: (productId: string, modelUuid: string) => void; + updateEvent: (productId: string, modelUuid: string, updates: Partial) => void; // Point-level actions - addPointToEvent: (productId: string, modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; - removePointFromEvent: (productId: string, modelUuid: string, pointUuid: string) => void; - updatePointInEvent: ( + addPoint: (productId: string, modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; + removePoint: (productId: string, modelUuid: string, pointUuid: string) => void; + updatePoint: ( productId: string, modelUuid: string, pointUuid: string, @@ -157,12 +29,12 @@ type Store = { productId: string, modelUuid: string, pointUuid: string, - action: TransferPointSchema['actions'][0] | VehiclePointSchema['actions'][0] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['actions'][0] | StoragePointSchema['actions'][0] + action: TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] ) => void; removeAction: (actionUuid: string) => void; updateAction: ( actionUuid: string, - updates: Partial + updates: Partial ) => void; // Trigger-level actions @@ -178,16 +50,11 @@ type Store = { // Helper functions getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; - getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | undefined; - getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined; - getActionByUuid: (actionUuid: string) => (TransferPointSchema['actions'][0] | VehiclePointSchema['actions'][0] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['actions'][0] | StoragePointSchema['actions'][0]) | undefined; - getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined; }; export const useProductStore = create()( immer((set, get) => ({ products: [], - activeProductId: null, // Product-level actions addProduct: (productName, productId) => { @@ -217,7 +84,7 @@ export const useProductStore = create()( }, // Event-level actions - addEventToProduct: (productId, event) => { + addEvent: (productId, event) => { set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -226,7 +93,7 @@ export const useProductStore = create()( }); }, - removeEventFromProduct: (productId, modelUuid) => { + removeEvent: (productId, modelUuid) => { set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -235,7 +102,7 @@ export const useProductStore = create()( }); }, - updateEventInProduct: (productId, modelUuid, updates) => { + updateEvent: (productId, modelUuid, updates) => { set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -248,7 +115,7 @@ export const useProductStore = create()( }, // Point-level actions - addPointToEvent: (productId, modelUuid, point) => { + addPoint: (productId, modelUuid, point) => { set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -262,7 +129,7 @@ export const useProductStore = create()( }); }, - removePointFromEvent: (productId, modelUuid, pointUuid) => { + removePoint: (productId, modelUuid, pointUuid) => { set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -271,13 +138,12 @@ export const useProductStore = create()( (event as TransferEventSchema).points = (event as TransferEventSchema).points.filter(p => p.uuid !== pointUuid); } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { // For events with single point, we can't remove it, only reset to empty - // You might want to handle this differently } } }); }, - updatePointInEvent: (productId, modelUuid, pointUuid, updates) => { + updatePoint: (productId, modelUuid, pointUuid, updates) => { set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -303,25 +169,37 @@ export const useProductStore = create()( if (event && 'points' in event) { const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); if (point) { - point.actions.push(action as any); + point.action = action as any; } } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { - (event as any).point.actions.push(action); + if ('action' in (event as any).point) { + (event as any).point.action = action; + } else if ('actions' in (event as any).point) { + (event as any).point.actions.push(action); + } } } }); }, - removeAction: (actionUuid) => { + removeAction: (actionUuid: string) => { set((state) => { for (const product of state.products) { for (const event of product.eventsData) { if ('points' in event) { + // Handle TransferEventSchema for (const point of (event as TransferEventSchema).points) { - point.actions = point.actions.filter(a => a.actionUuid !== actionUuid); } } else if ('point' in event) { - (event as any).point.actions = (event as any).point.actions.filter((a: any) => a.actionUuid !== actionUuid); + const point = (event as any).point; + if (event.type === "roboticArm") { + // Handle RoboticArmSchemaEvent + if ('actions' in point) { + point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid); + } + } else if ('action' in point && point.action?.actionUuid === actionUuid) { + // For other schemas with a single 'action' + } } } } @@ -334,17 +212,22 @@ export const useProductStore = create()( for (const event of product.eventsData) { if ('points' in event) { for (const point of (event as TransferEventSchema).points) { - const action = point.actions.find(a => a.actionUuid === actionUuid); - if (action) { - Object.assign(action, updates); + if (point.action && point.action.actionUuid === actionUuid) { + Object.assign(point.action, updates); return; } } } else if ('point' in event) { - const action = (event as any).point.actions.find((a: any) => a.actionUuid === actionUuid); - if (action) { - Object.assign(action, updates); + const point = (event as any).point; + if ('action' in point && point.action.actionUuid === actionUuid) { + Object.assign(point.action, updates); return; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) { + Object.assign(action, updates); + return; + } } } } @@ -359,17 +242,22 @@ export const useProductStore = create()( for (const event of product.eventsData) { if ('points' in event) { for (const point of (event as TransferEventSchema).points) { - const action = point.actions.find(a => a.actionUuid === actionUuid); - if (action && 'triggers' in action) { - action.triggers.push(trigger); + if (point.action && point.action.actionUuid === actionUuid) { + point.action.triggers.push(trigger); return; } } } else if ('point' in event) { - const action = (event as any).point.actions.find((a: any) => a.actionUuid === actionUuid); - if (action && 'triggers' in action) { - action.triggers.push(trigger); + const point = (event as any).point; + if ('action' in point && point.action.actionUuid === actionUuid) { + point.action.triggers.push(trigger); return; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) { + action.triggers.push(trigger); + return; + } } } } @@ -383,16 +271,19 @@ export const useProductStore = create()( for (const event of product.eventsData) { if ('points' in event) { for (const point of (event as TransferEventSchema).points) { - for (const action of point.actions) { - if ('triggers' in action) { - action.triggers = action.triggers.filter(t => t.triggerUuid !== triggerUuid); - } + if (point.action && 'triggers' in point.action) { + point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid); } } } else if ('point' in event) { - for (const action of (event as any).point.actions) { - if ('triggers' in action) { - action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid); + const point = (event as any).point; + if ('action' in point && 'triggers' in point.action) { + point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid); + } else if ('actions' in point) { + for (const action of point.actions) { + if ('triggers' in action) { + action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid); + } } } } @@ -407,23 +298,30 @@ export const useProductStore = create()( for (const event of product.eventsData) { if ('points' in event) { for (const point of (event as TransferEventSchema).points) { - for (const action of point.actions) { - if ('triggers' in action) { - const trigger = action.triggers.find(t => t.triggerUuid === triggerUuid); - if (trigger) { - Object.assign(trigger, updates); - return; - } + if (point.action && 'triggers' in point.action) { + const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); + if (trigger) { + Object.assign(trigger, updates); + return; } } } } else if ('point' in event) { - for (const action of (event as any).point.actions) { - if ('triggers' in action) { - const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); - if (trigger) { - Object.assign(trigger, updates); - return; + const point = (event as any).point; + if ('action' in point && 'triggers' in point.action) { + const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) { + Object.assign(trigger, updates); + return; + } + } else if ('actions' in point) { + for (const action of point.actions) { + if ('triggers' in action) { + const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); + if (trigger) { + Object.assign(trigger, updates); + return; + } } } } @@ -436,71 +334,6 @@ export const useProductStore = create()( // Helper functions getProductById: (productId) => { return get().products.find(p => p.productId === productId); - }, - - getEventByModelUuid: (productId, modelUuid) => { - const product = get().products.find(p => p.productId === productId); - if (product) { - return product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); - } - return undefined; - }, - - getPointByUuid: (productId, modelUuid, pointUuid) => { - const product = get().products.find(p => p.productId === productId); - if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); - if (event && 'points' in event) { - return (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); - } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { - return (event as any).point; - } - } - return undefined; - }, - - getActionByUuid: (actionUuid) => { - const state = get(); - for (const product of state.products) { - for (const event of product.eventsData) { - if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { - const action = point.actions.find(a => a.actionUuid === actionUuid); - if (action) return action; - } - } else if ('point' in event) { - const action = (event as any).point.actions.find((a: any) => a.actionUuid === actionUuid); - if (action) return action; - } - } - } - return undefined; - }, - - getTriggerByUuid: (triggerUuid) => { - const state = get(); - for (const product of state.products) { - for (const event of product.eventsData) { - if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { - for (const action of point.actions) { - if ('triggers' in action) { - const trigger = action.triggers.find(t => t.triggerUuid === triggerUuid); - if (trigger) return trigger; - } - } - } - } else if ('point' in event) { - for (const action of (event as any).point.actions) { - if ('triggers' in action) { - const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); - if (trigger) return trigger; - } - } - } - } - } - return undefined; } })) ); \ No newline at end of file diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 0e30be4..07298ca 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -1,99 +1,3 @@ - -interface PathConnection { - fromModelUUID: string; - fromUUID: string; - toConnections: { - toModelUUID: string; - toUUID: string; - }[]; -} - -interface ConnectionStore { - connections: PathConnection[]; - setConnections: (connections: PathConnection[]) => void; - addConnection: (newConnection: PathConnection) => void; - removeConnection: (fromUUID: string, toUUID: string) => void; -} - -interface ConveyorEventsSchema { - modeluuid: string; - modelName: string; - type: "Conveyor"; - points: { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean; }[] | []; - triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number; }[] | []; - connections: { - source: { modelUUID: string; pointUUID: string }; - targets: { modelUUID: string; pointUUID: string }[]; - }; - }[]; - position: [number, number, number]; - rotation: [number, number, number]; - speed: number | string; -} - -interface VehicleEventsSchema { - modeluuid: string; - modelName: string; - type: "Vehicle"; - points: { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { uuid: string; name: string; type: string; start: { x: number; y: number } | {}; hitCount: number; end: { x: number; y: number } | {}; buffer: number; }; - connections: { - source: { modelUUID: string; pointUUID: string }; - targets: { modelUUID: string; pointUUID: string }[]; - }; - speed: number; - isPlaying: boolean; - }; - - position: [number, number, number]; - rotation: [number, number, number]; -} - -interface StaticMachineEventsSchema { - modeluuid: string; - modelName: string; - type: "StaticMachine"; - points: { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { uuid: string; name: string; buffer: number; material: string; }; - triggers: { uuid: string; name: string; type: string }; - connections: { - source: { modelUUID: string; pointUUID: string }; - targets: { modelUUID: string; pointUUID: string }[]; - }; - }; - position: [number, number, number]; - rotation: [number, number, number]; -} - -interface ArmBotEventsSchema { - modeluuid: string; - modelName: string; - type: "ArmBot"; - points: { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; }; - triggers: { uuid: string; name: string; type: string }; - connections: { - source: { modelUUID: string; pointUUID: string }; - targets: { modelUUID: string; pointUUID: string }[]; - }; - }; - position: [number, number, number]; - rotation: [number, number, number]; -} - interface AssetEventSchema { modelUuid: string; modelName: string; @@ -117,7 +21,7 @@ interface TransferPointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; - actions: { + action: { actionUuid: string; actionName: string; actionType: "default" | "spawn" | "swap" | "despawn"; @@ -125,15 +29,15 @@ interface TransferPointSchema { delay: number | "inherit"; spawnInterval: number | "inherit"; spawnCount: number | "inherit"; - triggers: TriggerSchema[] | []; - }[]; + triggers: TriggerSchema[]; + }; } interface VehiclePointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; - actions: { + action: { actionUuid: string; actionName: string; actionType: "travel"; @@ -142,8 +46,8 @@ interface VehiclePointSchema { loadCapacity: number; pickUpPoint: { x: number; y: number, z: number } | {}; unLoadPoint: { x: number; y: number, z: number } | {}; - triggers: TriggerSchema[] | []; - }[]; + triggers: TriggerSchema[]; + }; } interface RoboticArmPointSchema { @@ -155,7 +59,7 @@ interface RoboticArmPointSchema { actionName: string; actionType: "pickAndPlace"; process: { startPoint: string; endPoint: string }; - triggers: TriggerSchema[] | []; + triggers: TriggerSchema[]; }[]; } @@ -163,27 +67,27 @@ interface MachinePointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; - actions: { + action: { actionUuid: string; actionName: string; actionType: "process"; processTime: number; swapMaterial: string; - triggers: TriggerSchema[] | []; - }[]; + triggers: TriggerSchema[]; + }; } interface StoragePointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; - actions: { + action: { actionUuid: string; actionName: string; actionType: "storage"; materials: { materialName: string; materialId: string; quantity: number }[]; storageCapacity: number; - }[]; + }; } interface TransferEventSchema extends AssetEventSchema { @@ -220,4 +124,4 @@ type productsSchema = { productName: string; productId: string; eventsData: EventsSchema[]; -}[] | [] \ No newline at end of file +}[] \ No newline at end of file