From 1e880067802e79ec370f9e75d9360f27287f0452 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 26 Jun 2025 17:47:32 +0530 Subject: [PATCH 01/18] Refactor aisle API services: remove createAisleApi, update deleteAisleApi to include versionId, and modify wall asset APIs for consistency in endpoint naming. Enhance floor and wall store functionality with new setters and methods for managing floors and walls, including decal handling. Introduce FloorInstance and FloorInstances components for rendering floor data, and implement FloorCreator for interactive floor creation. Add reference floor visualization with snapping capabilities. Update wall API services for improved error handling and response management. --- .../properties/SelectedWallProperties.tsx | 69 +++++- .../aisle/aisleCreator/aisleCreator.tsx | 24 ++- app/src/modules/builder/builder.tsx | 17 +- .../Instances/Instance/floorInstance.tsx | 10 + .../floor/Instances/floorInstances.tsx | 121 +++++++++++ .../floor/floorCreator/floorCreator.tsx | 175 ++++++++++++++++ .../floor/floorCreator/referenceFloor.tsx | 164 +++++++++++++++ app/src/modules/builder/floor/floorGroup.tsx | 31 +++ .../modules/builder/groups/floorPlanGroup.tsx | 4 +- app/src/modules/builder/line/line.tsx | 82 +++++++- .../point/helpers/usePointSnapping.tsx | 94 ++++++++- app/src/modules/builder/point/point.tsx | 79 ++++++- .../point/reference/referencePoint.tsx | 6 + .../builder/wall/Instances/wallInstances.tsx | 4 +- .../wall/wallCreator/referenceWall.tsx | 75 ++++--- .../builder/wall/wallCreator/wallCreator.tsx | 151 +++++++++++++- app/src/modules/builder/wall/wallGroup.tsx | 29 ++- .../factoryBuilder/aisle/deleteAisleApi.ts | 2 +- .../{createAisleApi.ts => upsertAisleApi.ts} | 2 +- .../assest/wallAsset/deleteWallItemApi.ts | 2 +- .../assest/wallAsset/getWallItemsApi.ts | 2 +- .../assest/wallAsset/setWallItemApi.ts | 2 +- .../factoryBuilder/wall/deleteWallApi.ts | 39 ++++ .../factoryBuilder/wall/getWallsApi.ts | 37 ++++ .../factoryBuilder/wall/upsertWallApi.ts | 39 ++++ app/src/store/builder/useBuilderStore.ts | 54 +++++ app/src/store/builder/useFloorStore.ts | 197 +++++++++++++++++- app/src/store/builder/useWallStore.ts | 53 +++-- 28 files changed, 1442 insertions(+), 122 deletions(-) create mode 100644 app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx create mode 100644 app/src/modules/builder/floor/Instances/floorInstances.tsx create mode 100644 app/src/modules/builder/floor/floorCreator/floorCreator.tsx create mode 100644 app/src/modules/builder/floor/floorCreator/referenceFloor.tsx create mode 100644 app/src/modules/builder/floor/floorGroup.tsx rename app/src/services/factoryBuilder/aisle/{createAisleApi.ts => upsertAisleApi.ts} (97%) create mode 100644 app/src/services/factoryBuilder/wall/deleteWallApi.ts create mode 100644 app/src/services/factoryBuilder/wall/getWallsApi.ts create mode 100644 app/src/services/factoryBuilder/wall/upsertWallApi.ts diff --git a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx index b647145..b5099d5 100644 --- a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx @@ -6,10 +6,20 @@ import wallTexture1 from '../../../../assets/textures/floor/factory wall texture import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; import { useSceneContext } from "../../../../modules/scene/sceneContext"; +import { useVersionContext } from "../../../../modules/builder/version/versionContext"; +import { useParams } from "react-router-dom"; +import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi"; +import { getUserData } from "../../../../functions/getUserData"; +import { useSocketStore } from "../../../../store/builder/store"; const SelectedWallProperties = () => { const { selectedWall } = useBuilderStore(); const { wallStore } = useSceneContext(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { socket } = useSocketStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); const { getWallById, updateWall } = wallStore(); const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1"); @@ -24,14 +34,50 @@ const SelectedWallProperties = () => { const handleHeightChange = (val: string) => { const height = parseFloat(val); if (!isNaN(height) && wall) { - updateWall(wall.wallUuid, { wallHeight: height }); + const updatedWall = updateWall(wall.wallUuid, { wallHeight: height }); + if (updatedWall && projectId) { + + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall); + + // SOCKET + + const data = { + wallData: updatedWall, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + } } }; const handleThicknessChange = (val: string) => { const thickness = parseFloat(val); if (!isNaN(thickness) && wall) { - updateWall(wall.wallUuid, { wallThickness: thickness }); + const updatedWall = updateWall(wall.wallUuid, { wallThickness: thickness }); + if (updatedWall && projectId) { + + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall); + + // SOCKET + + const data = { + wallData: updatedWall, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + } } }; @@ -39,8 +85,25 @@ const SelectedWallProperties = () => { if (!wall) return; const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId }) + const updatedWall = updateWall(wall.wallUuid, updated); + if (updatedWall && projectId) { - updateWall(wall.wallUuid, updated); + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall); + + // SOCKET + + const data = { + wallData: updatedWall, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + } }; if (!wall) return null; diff --git a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx index e0805e9..31ed1f6 100644 --- a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx @@ -2,13 +2,13 @@ import * as THREE from 'three' import { useEffect, useMemo, useRef, useState } from 'react' import { useThree } from '@react-three/fiber'; import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; -import ReferenceAisle from './referenceAisle'; import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; -import ReferencePoint from '../../point/reference/referencePoint'; -import { createAisleApi } from '../../../../services/factoryBuilder/aisle/createAisleApi'; +import { upsertAisleApi } from '../../../../services/factoryBuilder/aisle/upsertAisleApi'; import { useParams } from 'react-router-dom'; import { useVersionContext } from '../../version/versionContext'; import { useSceneContext } from '../../../scene/sceneContext'; +import ReferenceAisle from './referenceAisle'; +import ReferencePoint from '../../point/reference/referencePoint'; function AisleCreator() { const { scene, camera, raycaster, gl, pointer } = useThree(); @@ -74,6 +74,8 @@ function AisleCreator() { newPoint.layer = snappedPoint.layer; } + if (snappedPoint && snappedPoint.pointUuid === tempPoints[0]?.pointUuid) { return } + if (snappedPosition && !snappedPoint) { newPoint.position = snappedPosition; } @@ -104,7 +106,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } @@ -127,7 +129,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } @@ -149,7 +151,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } @@ -170,7 +172,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } @@ -193,7 +195,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } @@ -215,7 +217,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } @@ -236,7 +238,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } @@ -258,7 +260,7 @@ function AisleCreator() { }; addAisle(aisle); if (projectId) { - createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '') } setTempPoints([newPoint]); } diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index b977781..9ad8bd2 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -33,7 +33,7 @@ import * as Types from "../../types/world/worldTypes"; import SocketResponses from "../collaboration/socket/socketResponses.dev"; import FloorPlanGroup from "./groups/floorPlanGroup"; -import FloorGroup from "./groups/floorGroup"; +// import FloorGroup from "./groups/floorGroup"; import Draw from "./functions/draw"; import WallsAndWallItems from "./groups/wallsAndWallItems"; import Ground from "../scene/environment/ground"; @@ -52,6 +52,7 @@ import AislesGroup from "./aisle/aislesGroup"; import WallGroup from "./wall/wallGroup"; import { useBuilderStore } from "../../store/builder/useBuilderStore"; import { getUserData } from "../../functions/getUserData"; +import FloorGroup from "./floor/floorGroup"; export default function Builder() { const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. @@ -185,7 +186,7 @@ export default function Builder() { - + {/* */} - + /> */} - + /> */} - {/* */} + + + ); } diff --git a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx new file mode 100644 index 0000000..1b6dcb7 --- /dev/null +++ b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function FloorInstance({ floor }: { floor: Floor }) { + return ( + <> + + ) +} + +export default FloorInstance \ No newline at end of file diff --git a/app/src/modules/builder/floor/Instances/floorInstances.tsx b/app/src/modules/builder/floor/Instances/floorInstances.tsx new file mode 100644 index 0000000..75fd359 --- /dev/null +++ b/app/src/modules/builder/floor/Instances/floorInstances.tsx @@ -0,0 +1,121 @@ +import React, { useEffect, useMemo } from 'react'; +import { Vector3 } from 'three'; +import { Html } from '@react-three/drei'; +import { useSceneContext } from '../../../scene/sceneContext'; +import { useToggleView } from '../../../../store/builder/store'; +import Line from '../../line/line'; +import Point from '../../point/point'; +import FloorInstance from './Instance/floorInstance'; + +function FloorInstances() { + const { floorStore } = useSceneContext(); + const { floors } = floorStore(); + const { toggleView } = useToggleView(); + + useEffect(() => { + // console.log('floors: ', floors); + }, [floors]) + + const allPoints = useMemo(() => { + const points: Point[] = []; + const seenUuids = new Set(); + + floors.forEach(floor => { + floor.points.forEach(point => { + if (!seenUuids.has(point.pointUuid)) { + seenUuids.add(point.pointUuid); + points.push(point); + } + }); + }); + + return points; + }, [floors]); + + const allLines = useMemo(() => { + const lines: { start: Point; end: Point; key: string }[] = []; + + floors.forEach((floor) => { + const points = floor.points; + if (points.length < 2) return; + + for (let i = 0; i < points.length; i++) { + const current = points[i]; + const next = points[(i + 1) % points.length]; + if (current.pointUuid !== next.pointUuid) { + lines.push({ + start: current, + end: next, + key: `${current.pointUuid}-${next.pointUuid}` + }); + } + } + }); + + return lines; + }, [floors]); + + return ( + <> + + {!toggleView && floors.length > 1 && ( + + {floors.map((floor) => ( + + ))} + + )} + + {toggleView && ( + <> + + {allPoints.map((point) => ( + + ))} + + + + + {allLines.map(({ start, end, key }) => ( + + ))} + + {allLines.map((line) => { + const { start, end, key } = line; + const textPosition = new Vector3().addVectors(new Vector3(...start.position), new Vector3(...end.position)).divideScalar(2); + const distance = new Vector3(...start.position).distanceTo(new Vector3(...end.position)); + + return ( + + {toggleView && + +
+ {distance.toFixed(2)} m +
+ + } +
+ ) + })} + +
+ + + )} + + ) +} + +export default FloorInstances; \ No newline at end of file diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx new file mode 100644 index 0000000..db031d5 --- /dev/null +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -0,0 +1,175 @@ +import * as THREE from 'three' +import { useEffect, useMemo, useRef, useState } from 'react' +import { useThree } from '@react-three/fiber'; +import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; +import { useSceneContext } from '../../../scene/sceneContext'; +import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; +import ReferencePoint from '../../point/reference/referencePoint'; +import ReferenceFloor from './referenceFloor'; + +function FloorCreator() { + const { scene, camera, raycaster, gl, pointer } = useThree(); + const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); + const { toggleView } = useToggleView(); + const { toolMode } = useToolMode(); + const { activeLayer } = useActiveLayer(); + const { socket } = useSocketStore(); + const { floorStore } = useSceneContext(); + const { addFloor, removeDecal, getFloorPointById, getFloorByPoints } = floorStore(); + const drag = useRef(false); + const isLeftMouseDown = useRef(false); + + const [tempPoints, setTempPoints] = useState([]); + const [isCreating, setIsCreating] = useState(false); + const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint } = useBuilderStore(); + + useEffect(() => { + const canvasElement = gl.domElement; + + const onMouseDown = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown.current = true; + drag.current = false; + } + }; + + const onMouseUp = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown.current = false; + } + }; + + const onMouseMove = () => { + if (isLeftMouseDown) { + drag.current = true; + } + }; + + const onMouseClick = () => { + if (drag.current || !toggleView) return; + + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + let position = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (!position) return; + + const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Point'); + + const floorIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Line'); + + if (floorIntersect && !pointIntersects) { + + } + + const newPoint: Point = { + pointUuid: THREE.MathUtils.generateUUID(), + pointType: 'Floor', + position: [position.x, position.y, position.z], + layer: activeLayer + }; + + if (snappedPosition && snappedPoint) { + newPoint.pointUuid = snappedPoint.pointUuid; + newPoint.position = snappedPosition; + newPoint.layer = snappedPoint.layer; + } + + if (snappedPoint && snappedPoint.pointUuid === tempPoints[tempPoints.length - 1]?.pointUuid) { return } + + if (snappedPosition && !snappedPoint) { + newPoint.position = snappedPosition; + } + + if (pointIntersects && !snappedPoint) { + if (tempPoints.length > 2 && isCreating && pointIntersects.object.userData.pointUuid === tempPoints[0].pointUuid) { + if (tempPoints.length >= 3) { + const floor: Floor = { + floorUuid: THREE.MathUtils.generateUUID(), + points: tempPoints, + topMaterial, + sideMaterial, + floorDepth, + isBeveled, + bevelStrength, + decals: [], + }; + + addFloor(floor); + } + setTempPoints([]); + setIsCreating(false); + } + } + + setTempPoints(prev => [...prev, newPoint]); + setIsCreating(true); + + }; + + const onContext = (event: any) => { + event.preventDefault(); + if (isCreating) { + if (tempPoints.length >= 3) { + const floor: Floor = { + floorUuid: THREE.MathUtils.generateUUID(), + points: tempPoints, + topMaterial, + sideMaterial, + floorDepth, + isBeveled, + bevelStrength, + decals: [], + }; + + addFloor(floor); + } + setTempPoints([]); + setIsCreating(false); + } + }; + + if (toolMode === "Floor" && toggleView) { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener("click", onMouseClick); + canvasElement.addEventListener("contextmenu", onContext); + } else { + setTempPoints([]); + setIsCreating(false); + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("click", onMouseClick); + canvasElement.removeEventListener("contextmenu", onContext); + } + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("click", onMouseClick); + canvasElement.removeEventListener("contextmenu", onContext); + }; + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, removeDecal, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]); + + return ( + <> + {toggleView && + <> + + {tempPoints.map((point) => ( + + ))} + + + {tempPoints.length > 0 && + + } + + } + + ) +} + +export default FloorCreator \ No newline at end of file diff --git a/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx new file mode 100644 index 0000000..6e40a1c --- /dev/null +++ b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx @@ -0,0 +1,164 @@ +import { useEffect, useRef, useState, useMemo } from 'react'; +import * as THREE from 'three'; +import { useFrame, useThree } from '@react-three/fiber'; +import { Extrude, Html } from '@react-three/drei'; +import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; +import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store'; +import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping'; +import { usePointSnapping } from '../../point/helpers/usePointSnapping'; +import ReferenceLine from '../../line/reference/referenceLine'; + +interface ReferenceFloorProps { + tempPoints: Point[]; +} + +function ReferenceFloor({ tempPoints }: Readonly) { + const { floorDepth, isBeveled, bevelStrength, setSnappedPosition, setSnappedPoint } = useBuilderStore(); + const { pointer, raycaster, camera } = useThree(); + const { toolMode } = useToolMode(); + const { toggleView } = useToggleView(); + const { activeLayer } = useActiveLayer(); + const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); + const finalPosition = useRef<[number, number, number] | null>(null); + + const [tempFloor, setTempFloor] = useState(null); + const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position); + + const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[tempPoints.length - 1]?.position || null); + const { snapFloorPoint } = usePointSnapping({ uuid: 'temp-floor', pointType: 'Floor', position: directionalSnap.position || [0, 0, 0], }); + + useFrame(() => { + if (toolMode === 'Floor' && toggleView && tempPoints.length > 0) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + raycaster.ray.intersectPlane(plane, intersectionPoint); + + setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); + + if (!intersectionPoint) return; + const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.slice(0, -2)); + + if (snapped.isSnapped && snapped.snappedPoint) { + finalPosition.current = snapped.position; + setSnappedPosition(snapped.position); + setSnappedPoint(snapped.snappedPoint); + } else if (directionalSnap.isSnapped) { + finalPosition.current = directionalSnap.position; + setSnappedPosition(directionalSnap.position); + setSnappedPoint(null); + } else { + finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]; + setSnappedPosition(null); + setSnappedPoint(null); + } + + if (!finalPosition.current) return; + + const floorPoints: Point[] = [ + ...tempPoints, + { + pointUuid: 'temp-point', + pointType: 'Floor', + position: finalPosition.current, + layer: activeLayer, + }, + ]; + + setTempFloor({ + floorUuid: 'temp-floor', + points: floorPoints, + topMaterial: 'default', + sideMaterial: 'default', + floorDepth, + bevelStrength, + isBeveled, + decals: [], + }); + + } else if (tempFloor !== null) { + setTempFloor(null); + } + }); + + useEffect(() => { + setTempFloor(null); + }, [toolMode, toggleView, tempPoints.length, floorDepth, bevelStrength, isBeveled]); + + const allLines = useMemo(() => { + if (!tempFloor || tempFloor.points.length < 2) return []; + + const lines: [Point, Point][] = []; + const pts = tempFloor.points; + + for (let i = 0; i < pts.length - 1; i++) { + lines.push([pts[i], pts[i + 1]]); + } + + return lines; + }, [tempFloor]); + + if (!tempFloor) return null; + + return ( + + {allLines.map(([p1, p2], idx) => { + const v1 = new THREE.Vector3(...p1.position); + const v2 = new THREE.Vector3(...p2.position); + const mid = new THREE.Vector3().addVectors(v1, v2).multiplyScalar(0.5); + const dist = v1.distanceTo(v2); + + return ( + + + {toggleView && ( + +
{dist.toFixed(2)} m
+ + )} +
+ ); + })} + + {tempPoints.length >= 3 && ( + + )} +
+ ); +} + +export default ReferenceFloor; + + +function Floor({ floor }: { floor: Point[] }) { + const savedTheme: string | null = localStorage.getItem('theme'); + + const shape = useMemo(() => { + const shape = new THREE.Shape(); + const points = floor.map(p => new THREE.Vector2(p.position[0], p.position[2])); + if (points.length < 3) return null; + shape.moveTo(points[0].x, points[0].y); + points.forEach((pt) => { shape.lineTo(pt.x, pt.y); }); + return shape; + }, [floor]); + + if (!shape) return null; + + return ( + + + + + + ); +} diff --git a/app/src/modules/builder/floor/floorGroup.tsx b/app/src/modules/builder/floor/floorGroup.tsx new file mode 100644 index 0000000..fdcf37c --- /dev/null +++ b/app/src/modules/builder/floor/floorGroup.tsx @@ -0,0 +1,31 @@ +import { useEffect } from 'react'; +import { useToggleView } from '../../../store/builder/store' +import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import FloorCreator from './floorCreator/floorCreator'; +import FloorInstances from './Instances/floorInstances'; +import useModuleStore from '../../../store/useModuleStore'; + +function FloorGroup() { + const { togglView } = useToggleView(); + const { setSelectedFloor, setSelectedDecal } = useBuilderStore(); + const { activeModule } = useModuleStore(); + + useEffect(() => { + if (togglView || activeModule !== 'builder') { + setSelectedFloor(null); + setSelectedDecal(null); + } + }, [togglView, activeModule]) + + return ( + <> + + + + + + + ) +} + +export default FloorGroup \ No newline at end of file diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx index 8f1c2f2..a9a845e 100644 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ b/app/src/modules/builder/groups/floorPlanGroup.tsx @@ -148,11 +148,11 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin } if (toolMode === "Wall") { - drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); + // drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); } if (toolMode === "Floor") { - drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); + // drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); } } diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index 19f0810..42aa5c2 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -2,10 +2,15 @@ import * as THREE from 'three'; import { useThree } from '@react-three/fiber'; import { useEffect, useMemo, useState } from "react"; import { DragControls, Tube } from '@react-three/drei'; -import { useToolMode } from '../../../store/builder/store'; +import { useSocketStore, useToolMode } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useSceneContext } from '../../scene/sceneContext'; import * as Constants from '../../../types/world/worldConstants'; +import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; +import { useVersionContext } from '../version/versionContext'; +import { useParams } from 'react-router-dom'; +import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; +import { getUserData } from '../../../functions/getUserData'; interface LineProps { points: [Point, Point]; @@ -16,9 +21,15 @@ function Line({ points }: Readonly) { const { raycaster, camera, pointer, gl } = useThree(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const [isDeletable, setIsDeletable] = useState(false); + const { socket } = useSocketStore(); const { toolMode } = useToolMode(); - const { wallStore } = useSceneContext(); - const { removeWallByPoints, setPosition } = wallStore(); + const { wallStore, floorStore } = useSceneContext(); + const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore(); + const { removeFloorByPoints, setPosition: setFloorPosition } = floorStore(); + const { userId, organization } = getUserData(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { projectId } = useParams(); const [dragOffset, setDragOffset] = useState(null); const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore(); @@ -79,7 +90,29 @@ function Line({ points }: Readonly) { const handlePointClick = (points: [Point, Point]) => { if (toolMode === '2D-Delete') { if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') { - removeWallByPoints(points); + const removedWall = removeWallByPoints(points); + if (removedWall && projectId) { + + // API + + // deleteWallApi(projectId, selectedVersion?.versionId || '', removedWall.wallUuid); + + // SOCKET + + const data = { + wallUuid: removedWall.wallUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:delete', data); + } + setHoveredLine(null); + } + if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { + removeFloorByPoints(points); setHoveredLine(null); } gl.domElement.style.cursor = 'default'; @@ -105,8 +138,14 @@ function Line({ points }: Readonly) { const newStart = new THREE.Vector3().addVectors(start, delta); const newEnd = new THREE.Vector3().addVectors(end, delta); - setPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]); - setPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]); + if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') { + setWallPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]); + setWallPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]); + } + if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { + setFloorPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]); + setFloorPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]); + } } } }; @@ -127,11 +166,38 @@ function Line({ points }: Readonly) { }; const handleDragEnd = (points: [Point, Point]) => { + if (toolMode !== 'move' || !dragOffset) return; gl.domElement.style.cursor = 'default'; setDragOffset(null); - if (toolMode !== 'move') return; if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') { - // console.log('Wall after drag: ', points); + const updatedWalls1 = getWallsByPointId(points[0].pointUuid); + const updatedWalls2 = getWallsByPointId(points[1].pointUuid); + const updatedWalls = [...updatedWalls1, ...updatedWalls2].filter((wall, index, self) => index === self.findIndex((w) => w.wallUuid === wall.wallUuid)); + + if (updatedWalls.length > 0 && projectId) { + updatedWalls.forEach(updatedWall => { + + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall).catch((error) => { + // console.error('Error updating wall:', error); + // }); + + // SOCKET + + const data = { + wallData: updatedWall, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + }) + } + } else if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { + // Handle floor update logic here if needed } } diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx index c7d31cc..3d0f7e1 100644 --- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx +++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx @@ -11,9 +11,10 @@ const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping i const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => { - const { aisleStore, wallStore } = useSceneContext(); + const { aisleStore, wallStore, floorStore } = useSceneContext(); const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore(); const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore(); + const { floors, getConnectedPoints: getConnectedFloorPoints } = floorStore(); // Wall Snapping @@ -24,10 +25,13 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string ); }, [walls, currentPoint]); - const snapWallPoint = useCallback((position: [number, number, number]) => { + const snapWallPoint = useCallback((position: [number, number, number], tempPoints?: Point) => { if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null }; const otherPoints = getAllOtherWallPoints(); + if (tempPoints) { + otherPoints.push(tempPoints); + } const currentVec = new THREE.Vector3(...position); for (const point of otherPoints) { const pointVec = new THREE.Vector3(...point.position); @@ -187,10 +191,96 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string }; }, [currentPoint, getConnectedAislePoints]); + // Floor Snapping + + const getAllOtherFloorPoints = useCallback(() => { + if (!currentPoint) return []; + + return floors.flatMap(floor => + floor.points.filter(point => point.pointUuid !== currentPoint.uuid) + ); + }, [floors, currentPoint]); + + const snapFloorPoint = useCallback((position: [number, number, number], tempPoints: Point[] | []) => { + if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null }; + + const otherPoints = [...getAllOtherFloorPoints(), ...tempPoints]; + const currentVec = new THREE.Vector3(...position); + + for (const point of otherPoints) { + const pointVec = new THREE.Vector3(...point.position); + const distance = currentVec.distanceTo(pointVec); + + if (distance <= POINT_SNAP_THRESHOLD && currentPoint.pointType === 'Floor') { + return { position: point.position, isSnapped: true, snappedPoint: point }; + } + } + + return { position: position, isSnapped: false, snappedPoint: null }; + }, [currentPoint, getAllOtherFloorPoints]); + + const snapFloorAngle = useCallback((newPosition: [number, number, number]): { + position: [number, number, number], + isSnapped: boolean, + snapSources: THREE.Vector3[] + } => { + if (!currentPoint || !CAN_ANGLE_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] }; + + const connectedPoints = getConnectedFloorPoints(currentPoint.uuid); + if (connectedPoints.length === 0) { + return { position: newPosition, isSnapped: false, snapSources: [] }; + } + + const newPos = new THREE.Vector3(...newPosition); + let closestX: { pos: THREE.Vector3, dist: number } | null = null; + let closestZ: { pos: THREE.Vector3, dist: number } | null = null; + + for (const connectedPoint of connectedPoints) { + const cPos = new THREE.Vector3(...connectedPoint.position); + const xDist = Math.abs(newPos.x - cPos.x); + const zDist = Math.abs(newPos.z - cPos.z); + + if (xDist < ANGLE_SNAP_DISTANCE_THRESHOLD) { + if (!closestX || xDist < closestX.dist) { + closestX = { pos: cPos, dist: xDist }; + } + } + + if (zDist < ANGLE_SNAP_DISTANCE_THRESHOLD) { + if (!closestZ || zDist < closestZ.dist) { + closestZ = { pos: cPos, dist: zDist }; + } + } + } + + const snappedPos = newPos.clone(); + const snapSources: THREE.Vector3[] = []; + + if (closestX) { + snappedPos.x = closestX.pos.x; + snapSources.push(closestX.pos.clone()); + } + + if (closestZ) { + snappedPos.z = closestZ.pos.z; + snapSources.push(closestZ.pos.clone()); + } + + const isSnapped = snapSources.length > 0; + + return { + position: [snappedPos.x, snappedPos.y, snappedPos.z], + isSnapped, + snapSources + }; + }, [currentPoint, getConnectedFloorPoints]); + return { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, + snapFloorPoint, + snapFloorAngle, }; }; \ No newline at end of file diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index a671806..c3b94d3 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -1,29 +1,36 @@ import * as THREE from 'three'; import * as Constants from '../../../types/world/worldConstants'; import { useRef, useState, useEffect, useMemo } from 'react'; -import { useToolMode } from '../../../store/builder/store'; +import { useSocketStore, useToolMode } from '../../../store/builder/store'; import { DragControls } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { usePointSnapping } from './helpers/usePointSnapping'; -import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; import { useParams } from 'react-router-dom'; -import { createAisleApi } from '../../../services/factoryBuilder/aisle/createAisleApi'; import { useVersionContext } from '../version/versionContext'; import { useSceneContext } from '../../scene/sceneContext'; +import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAisleApi'; +import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; +import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; +import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; +import { getUserData } from '../../../functions/getUserData'; + function Point({ point }: { readonly point: Point }) { const materialRef = useRef(null); const { raycaster, camera, pointer, gl } = useThree(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const [isHovered, setIsHovered] = useState(false); const [dragOffset, setDragOffset] = useState(null); + const { socket } = useSocketStore(); const { toolMode } = useToolMode(); - const { aisleStore, wallStore } = useSceneContext(); + const { aisleStore, wallStore, floorStore } = useSceneContext(); const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); - const { setPosition: setWallPosition, removePoint: removeWallPoint } = wallStore(); + const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore(); + const { setPosition: setFloorPosition, removePoint: removeFloorPoint } = floorStore(); const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); + const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { projectId } = useParams(); @@ -113,6 +120,10 @@ function Point({ point }: { readonly point: Point }) { const wallSnapped = snapWallAngle(newPosition); const finalSnapped = snapWallPoint(wallSnapped.position); setWallPosition(point.pointUuid, finalSnapped.position); + } else if (point.pointType === 'Floor') { + const floorSnapped = snapWallAngle(newPosition); + const finalSnapped = snapWallPoint(floorSnapped.position); + setFloorPosition(point.pointUuid, finalSnapped.position); } } } @@ -138,11 +149,34 @@ function Point({ point }: { readonly point: Point }) { const updatedAisles = getAislesByPointId(point.pointUuid); if (updatedAisles.length > 0 && projectId) { updatedAisles.forEach((updatedAisle) => { - createAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '') + upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '') }) } } else if (point.pointType === 'Wall') { + const updatedWalls = getWallsByPointId(point.pointUuid); + if (updatedWalls && updatedWalls.length > 0 && projectId) { + updatedWalls.forEach((updatedWall) => { + + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall); + + // SOCKET + + const data = { + wallData: updatedWall, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + }); + } // console.log('Wall after drag: ', point); + } else if (point.pointType === 'Floor') { + // console.log('Floor after drag: ', point); } } @@ -152,16 +186,43 @@ function Point({ point }: { readonly point: Point }) { const removedAisles = removeAislePoint(point.pointUuid); if (removedAisles.length > 0) { removedAisles.forEach(aisle => { - if (projectId) + if (projectId) { deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '') + } }); setHoveredPoint(null); } } if (point.pointType === 'Wall') { - const removedAisles = removeWallPoint(point.pointUuid); - if (removedAisles.length > 0) { + const removedWalls = removeWallPoint(point.pointUuid); + if (removedWalls.length > 0) { setHoveredPoint(null); + removedWalls.forEach(wall => { + if (projectId) { + + // API + + // deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid); + + // SOCKET + + const data = { + wallUuid: wall.wallUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:delete', data); + } + }); + } + } + if (point.pointType === 'Floor') { + const removedFloors = removeFloorPoint(point.pointUuid); + setHoveredPoint(null); + if (removedFloors.length > 0) { } } gl.domElement.style.cursor = 'default'; diff --git a/app/src/modules/builder/point/reference/referencePoint.tsx b/app/src/modules/builder/point/reference/referencePoint.tsx index 44d399f..3be6f95 100644 --- a/app/src/modules/builder/point/reference/referencePoint.tsx +++ b/app/src/modules/builder/point/reference/referencePoint.tsx @@ -21,9 +21,15 @@ function ReferencePoint({ point }: { readonly point: Point }) { return null; } + const pointName = point.pointType === 'Wall' ? 'Wall-Point' : + point.pointType === 'Floor' ? 'Floor-Point' : + point.pointType === 'Aisle' ? 'Aisle-Point' : + point.pointType === 'Zone' ? 'Zone-Point' : 'Point'; + return ( (); - walls.forEach(aisle => { - aisle.points.forEach(point => { + walls.forEach(wall => { + wall.points.forEach(point => { if (!seenUuids.has(point.pointUuid)) { seenUuids.add(point.pointUuid); points.push(point); diff --git a/app/src/modules/builder/wall/wallCreator/referenceWall.tsx b/app/src/modules/builder/wall/wallCreator/referenceWall.tsx index f932f46..278fe67 100644 --- a/app/src/modules/builder/wall/wallCreator/referenceWall.tsx +++ b/app/src/modules/builder/wall/wallCreator/referenceWall.tsx @@ -36,46 +36,45 @@ function ReferenceWall({ tempPoints }: Readonly) { setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); - if (intersectionPoint) { - const snapped = snapWallPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); - - if (snapped.isSnapped && snapped.snappedPoint) { - finalPosition.current = snapped.position; - setSnappedPosition(snapped.position); - setSnappedPoint(snapped.snappedPoint); - } else if (directionalSnap.isSnapped) { - finalPosition.current = directionalSnap.position; - setSnappedPosition(directionalSnap.position); - setSnappedPoint(null); - } else { - finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]; - setSnappedPosition(null); - setSnappedPoint(null); - } - - if (!finalPosition.current) return; - - const wallPoints: [Point, Point] = [ - tempPoints[0], - { - pointUuid: 'temp-point', - pointType: 'Wall', - position: finalPosition.current, - layer: activeLayer, - } - ]; - - setTempWall({ - wallUuid: 'temp-wall', - points: wallPoints, - outsideMaterial: 'default', - insideMaterial: 'default', - wallThickness: wallThickness, - wallHeight: wallHeight, - decals: [] - }) + if (!intersectionPoint) return; + const snapped = snapWallPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints[0]); + if (snapped.isSnapped && snapped.snappedPoint) { + finalPosition.current = snapped.position; + setSnappedPosition(snapped.position); + setSnappedPoint(snapped.snappedPoint); + } else if (directionalSnap.isSnapped) { + finalPosition.current = directionalSnap.position; + setSnappedPosition(directionalSnap.position); + setSnappedPoint(null); + } else { + finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]; + setSnappedPosition(null); + setSnappedPoint(null); } + + if (!finalPosition.current) return; + + const wallPoints: [Point, Point] = [ + tempPoints[0], + { + pointUuid: 'temp-point', + pointType: 'Wall', + position: finalPosition.current, + layer: activeLayer, + } + ]; + + setTempWall({ + wallUuid: 'temp-wall', + points: wallPoints, + outsideMaterial: 'default', + insideMaterial: 'default', + wallThickness: wallThickness, + wallHeight: wallHeight, + decals: [] + }) + } else if (tempWall !== null) { setTempWall(null); } diff --git a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx index a136a41..c3a6c66 100644 --- a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx +++ b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx @@ -5,9 +5,15 @@ import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../. import * as Constants from '../../../../types/world/worldConstants'; import { useSceneContext } from '../../../scene/sceneContext'; import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; +import { useParams } from 'react-router-dom'; +import { useVersionContext } from '../../version/versionContext'; +import { getUserData } from '../../../../functions/getUserData'; +import getClosestIntersection from '../../geomentries/lines/getClosestIntersection'; import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceWall from './referenceWall'; -import getClosestIntersection from '../../geomentries/lines/getClosestIntersection'; + +import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi'; +import { deleteWallApi } from '../../../../services/factoryBuilder/wall/deleteWallApi'; function WallCreator() { const { scene, camera, raycaster, gl, pointer } = useThree(); @@ -20,10 +26,14 @@ function WallCreator() { const { addWall, getWallPointById, removeWall, getWallByPoints } = wallStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); - const { wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint } = useBuilderStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); const [tempPoints, setTempPoints] = useState([]); const [isCreating, setIsCreating] = useState(false); + const { wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore(); useEffect(() => { const canvasElement = gl.domElement; @@ -58,6 +68,7 @@ function WallCreator() { const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Wall-Point'); const wallIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Wall-Line'); + if (wallIntersect && !pointIntersects) { const wall = getWallByPoints(wallIntersect.object.userData.points); if (wall) { @@ -80,6 +91,25 @@ function WallCreator() { const closestPoint = new THREE.Vector3().lerpVectors(point1Vec, point2Vec, t); removeWall(wall.wallUuid); + if (projectId) { + + // API + + // deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid); + + // SOCKET + + const data = { + wallUuid: wall.wallUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:delete', data); + + } const point1: Point = { pointUuid: wall.points[0].pointUuid, @@ -114,6 +144,24 @@ function WallCreator() { } addWall(wall2); + // API + + // if (projectId) { + // upsertWallApi(projectId, selectedVersion?.versionId || '', wall2); + // } + + // SOCKET + + const data = { + wallData: wall2, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + const wall3: Wall = { wallUuid: THREE.MathUtils.generateUUID(), points: [point2, newPoint], @@ -125,6 +173,24 @@ function WallCreator() { } addWall(wall3); + // API + + // if (projectId) { + // upsertWallApi(projectId, selectedVersion?.versionId || '', wall3); + // } + + // SOCKET + + const data2 = { + wallData: wall3, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data2); + setTempPoints([newPoint]); setIsCreating(true); } else { @@ -139,6 +205,24 @@ function WallCreator() { }; addWall(wall1); + // API + + // if (projectId) { + // upsertWallApi(projectId, selectedVersion?.versionId || '', wall1); + // } + + // SOCKET + + const data = { + wallData: wall1, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + const wall2: Wall = { wallUuid: THREE.MathUtils.generateUUID(), points: [point1, newPoint], @@ -150,6 +234,24 @@ function WallCreator() { } addWall(wall2); + // API + + // if (projectId) { + // upsertWallApi(projectId, selectedVersion?.versionId || '', wall2); + // } + + // SOCKET + + const data1 = { + wallData: wall2, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data1); + const wall3: Wall = { wallUuid: THREE.MathUtils.generateUUID(), points: [point2, newPoint], @@ -161,6 +263,24 @@ function WallCreator() { } addWall(wall3); + // API + + // if (projectId) { + // upsertWallApi(projectId, selectedVersion?.versionId || '', wall3); + // } + + // SOCKET + + const data3 = { + wallData: wall3, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data3); + setTempPoints([newPoint]); } @@ -181,6 +301,8 @@ function WallCreator() { newPoint.layer = snappedPoint.layer; } + if (snappedPoint && snappedPoint.pointUuid === tempPoints[0]?.pointUuid) { return } + if (snappedPosition && !snappedPoint) { newPoint.position = snappedPosition; } @@ -208,6 +330,25 @@ function WallCreator() { decals: [] }; addWall(wall); + + // API + + // if (projectId) { + // upsertWallApi(projectId, selectedVersion?.versionId || '', wall); + // } + + // SOCKET + + const data = { + wallData: wall, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + setTempPoints([newPoint]); } @@ -222,6 +363,10 @@ function WallCreator() { }; if (toolMode === "Wall" && toggleView) { + if (tempPoints.length === 0) { + setSnappedPosition(null); + setSnappedPoint(null); + } canvasElement.addEventListener("mousedown", onMouseDown); canvasElement.addEventListener("mouseup", onMouseUp); canvasElement.addEventListener("mousemove", onMouseMove); @@ -244,7 +389,7 @@ function WallCreator() { canvasElement.removeEventListener("click", onMouseClick); canvasElement.removeEventListener("contextmenu", onContext); }; - }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addWall, getWallPointById, wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint]); + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addWall, getWallPointById, wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint, selectedVersion?.versionId]); return ( <> diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index aae36b9..0722d56 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -1,14 +1,23 @@ import { useEffect } from 'react'; -import { useToggleView } from '../../../store/builder/store' +import { useToggleView } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; -import WallCreator from './wallCreator/wallCreator' -import WallInstances from './Instances/wallInstances' +import WallCreator from './wallCreator/wallCreator'; +import WallInstances from './Instances/wallInstances'; import useModuleStore from '../../../store/useModuleStore'; +import { useVersionContext } from '../version/versionContext'; +import { useParams } from 'react-router-dom'; +import { useSceneContext } from '../../scene/sceneContext'; +import { getWallsApi } from '../../../services/factoryBuilder/wall/getWallsApi'; function WallGroup() { const { togglView } = useToggleView(); const { setSelectedWall, setSelectedDecal } = useBuilderStore(); const { activeModule } = useModuleStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { wallStore } = useSceneContext(); + const { setWalls } = wallStore(); + const { projectId } = useParams(); useEffect(() => { if (togglView || activeModule !== 'builder') { @@ -17,6 +26,20 @@ function WallGroup() { } }, [togglView, activeModule]) + useEffect(() => { + if (projectId && selectedVersion) { + getWallsApi(projectId, selectedVersion?.versionId || '').then((walls) => { + if (walls && walls.length > 0) { + setWalls(walls); + } else { + setWalls([]); + } + }).catch((err) => { + console.log(err); + }) + } + }, [projectId, selectedVersion?.versionId]) + return ( <> diff --git a/app/src/services/factoryBuilder/aisle/deleteAisleApi.ts b/app/src/services/factoryBuilder/aisle/deleteAisleApi.ts index 5ef96a3..28fde46 100644 --- a/app/src/services/factoryBuilder/aisle/deleteAisleApi.ts +++ b/app/src/services/factoryBuilder/aisle/deleteAisleApi.ts @@ -10,7 +10,7 @@ export const deleteAisleApi = async (aisleUuid: string, projectId: string, versi token: localStorage.getItem("token") || "", // Coerce null to empty string refresh_token: localStorage.getItem("refreshToken") || "", }, - body: JSON.stringify({ aisleUuid, projectId }), + body: JSON.stringify({ aisleUuid, projectId, versionId }), }); const newAccessToken = response.headers.get("x-access-token"); if (newAccessToken) { diff --git a/app/src/services/factoryBuilder/aisle/createAisleApi.ts b/app/src/services/factoryBuilder/aisle/upsertAisleApi.ts similarity index 97% rename from app/src/services/factoryBuilder/aisle/createAisleApi.ts rename to app/src/services/factoryBuilder/aisle/upsertAisleApi.ts index 27ae378..b980c61 100644 --- a/app/src/services/factoryBuilder/aisle/createAisleApi.ts +++ b/app/src/services/factoryBuilder/aisle/upsertAisleApi.ts @@ -1,6 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const createAisleApi = async ( +export const upsertAisleApi = async ( aisleUuid: string, points: any, type: Object, diff --git a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts index 84dee42..a959ebe 100644 --- a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts +++ b/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts @@ -7,7 +7,7 @@ export const deleteWallItem = async ( ) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/deleteWallItem`, + `${url_Backend_dwinzo}/api/V1/wallItems/delete`, { method: "DELETE", headers: { diff --git a/app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts index 55a09f0..ca72867 100644 --- a/app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts +++ b/app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts @@ -3,7 +3,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const getWallItems = async (organization: string, projectId?: string, versionId?: string) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/V1/walls/${projectId}/${versionId}`, + `${url_Backend_dwinzo}/api/V1/wallItems/${projectId}/${versionId}`, { method: "GET", headers: { diff --git a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts index b7a0dbd..4a7aab4 100644 --- a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts +++ b/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts @@ -12,7 +12,7 @@ export const setWallItem = async ( scale: Object ) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/setWallItems`, { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/wallItems`, { method: "POST", headers: { Authorization: "Bearer ", diff --git a/app/src/services/factoryBuilder/wall/deleteWallApi.ts b/app/src/services/factoryBuilder/wall/deleteWallApi.ts new file mode 100644 index 0000000..8a91d11 --- /dev/null +++ b/app/src/services/factoryBuilder/wall/deleteWallApi.ts @@ -0,0 +1,39 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteWallApi = async ( + projectId: string, + versionId: string, + wallUuid: string +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/deleteWall`, { + method: "PATCH", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, wallUuid }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to delete wall:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to delete wall"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/wall/getWallsApi.ts b/app/src/services/factoryBuilder/wall/getWallsApi.ts new file mode 100644 index 0000000..88bf3e7 --- /dev/null +++ b/app/src/services/factoryBuilder/wall/getWallsApi.ts @@ -0,0 +1,37 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getWallsApi = async ( + projectId: string, + versionId: string, +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/Walls/${projectId}/${versionId}`, { + method: "GET", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to get wall:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to get wall"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/wall/upsertWallApi.ts b/app/src/services/factoryBuilder/wall/upsertWallApi.ts new file mode 100644 index 0000000..023da68 --- /dev/null +++ b/app/src/services/factoryBuilder/wall/upsertWallApi.ts @@ -0,0 +1,39 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const upsertWallApi = async ( + projectId: string, + versionId: string, + wallData: Wall +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertWall`, { + method: "POST", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, wallData }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to upsert wall:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to upsert wall"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index 7803df9..18facd9 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -16,6 +16,14 @@ interface BuilderState { outsideMaterial: string; insideMaterial: string; + // Floor Settings + selectedFloor: Object3D | null; + floorDepth: number; + isBeveled: boolean; + bevelStrength: number; + sideMaterial: string; + topMaterial: string; + // Decal Settings selectedDecal: Object3D | null; @@ -44,6 +52,13 @@ interface BuilderState { setWallHeight: (height: number) => void; setWallMaterial: (material: string, side: 'inside' | 'outside') => void; + // Setters - Floor + setSelectedFloor: (floor: Object3D | null) => void; + setFloorDepth: (depth: number) => void; + setBeveled: (isBeveled: boolean) => void; + setBevelStrength: (strength: number) => void; + setFloorMaterial: (material: string, side: 'side' | 'top') => void; + // Setters - Decal setSelectedDecal: (decal: Object3D | null) => void; @@ -81,6 +96,13 @@ export const useBuilderStore = create()( outsideMaterial: 'Default Material', insideMaterial: 'Material 1', + selectedFloor: null, + floorDepth: 0.3, + isBeveled: false, + bevelStrength: 0.05, + sideMaterial: 'Default Side', + topMaterial: 'Default Top', + selectedDecal: null, selectedAisle: null, @@ -147,6 +169,38 @@ export const useBuilderStore = create()( }); }, + // === Setters: Floor === + setSelectedFloor: (floor: Object3D | null) => { + set((state) => { + state.selectedFloor = floor; + }); + }, + + setFloorDepth: (depth: number) => { + set((state) => { + state.floorDepth = depth; + }); + }, + + setBeveled: (isBeveled: boolean) => { + set((state) => { + state.isBeveled = isBeveled; + }); + }, + + setBevelStrength: (strength: number) => { + set((state) => { + state.bevelStrength = strength; + }); + }, + + setFloorMaterial: (material: string, side: 'side' | 'top') => { + set((state) => { + if (side === 'side') state.sideMaterial = material; + else state.topMaterial = material; + }); + }, + // === Setters: Decal === setSelectedDecal: (decal: Object3D | null) => { diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index 4c89333..f1c9bfa 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -7,14 +7,29 @@ interface FloorStore { addFloor: (floor: Floor) => void; updateFloor: (uuid: string, updated: Partial) => void; removeFloor: (uuid: string) => void; - removePointFromFloors: (pointUuid: string) => void; + removePoint: (pointUuid: string) => Floor[]; + removeFloorByPoints: (Points: [Point, Point]) => Floor[]; clearFloors: () => void; + setPosition: ( + pointUuid: string, + position: [number, number, number] + ) => Floor | undefined; setIsBeveled: (uuid: string, isBeveled: boolean) => void; setBevelStrength: (uuid: string, strength: number) => void; setDepth: (uuid: string, depth: number) => void; setMaterial: (uuid: string, sideMaterial: string, topMaterial: string) => void; + addDecal: (floors: string, decal: Decal) => void; + updateDecal: (decalUuid: string, decal: Decal) => void; + removeDecal: (decalUuid: string) => void; + updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void; + updateDecalRotation: (decalUuid: string, rotation: number) => void; + updateDecalScale: (decalUuid: string, scale: number) => void; getFloorById: (uuid: string) => Floor | undefined; + getFloorsByPointId: (uuid: string) => Floor | undefined; + getFloorByPoints: (points: Point[]) => Floor | undefined; + getFloorPointById: (uuid: string) => Point | undefined; + getConnectedPoints: (uuid: string) => Point[]; } export const createFloorStore = () => { @@ -41,16 +56,98 @@ export const createFloorStore = () => { state.floors = state.floors.filter(f => f.floorUuid !== uuid); }), - removePointFromFloors: (pointUuid) => set(state => { - for (const floor of state.floors) { - floor.points = floor.points.filter(p => p.pointUuid !== pointUuid); - } - }), + removePoint: (pointUuid) => { + const removedFloors: Floor[] = []; + + set(state => { + const updatedFloors: Floor[] = []; + + for (const floor of state.floors) { + const hasPoint = floor.points.some(p => p.pointUuid === pointUuid); + if (!hasPoint) { + updatedFloors.push(floor); + continue; + } + + const remainingPoints = floor.points.filter(p => p.pointUuid !== pointUuid); + if (remainingPoints.length > 2) { + floor.points = remainingPoints; + updatedFloors.push(floor); + } else { + removedFloors.push(floor); + } + } + + state.floors = updatedFloors; + }); + + return removedFloors; + }, + removeFloorByPoints: ([pointA, pointB]) => { + const removedFloors: Floor[] = []; + + set(state => { + const updatedFloors: Floor[] = []; + + for (const floor of state.floors) { + const indices = floor.points + .map((p, i) => ({ uuid: p.pointUuid, index: i })); + + const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; + const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; + + if (idxA === -1 || idxB === -1) { + updatedFloors.push(floor); + continue; + } + + const areAdjacent = + Math.abs(idxA - idxB) === 1 || + (idxA === 0 && idxB === floor.points.length - 1) || + (idxB === 0 && idxA === floor.points.length - 1); + + if (!areAdjacent) { + updatedFloors.push(floor); + continue; + } + + const remainingPoints = floor.points.filter( + p => p.pointUuid !== pointA.pointUuid && p.pointUuid !== pointB.pointUuid + ); + + if (remainingPoints.length > 2) { + floor.points = remainingPoints; + updatedFloors.push(floor); + } else { + removedFloors.push(floor); + } + } + + state.floors = updatedFloors; + }); + + return removedFloors; + }, clearFloors: () => set(state => { state.floors = []; }), + setPosition: (pointUuid, position) => { + let updatedFloor: Floor | undefined; + set((state) => { + for (const floor of state.floors) { + const point = floor.points.find((p) => p.pointUuid === pointUuid); + if (point) { + point.position = position; + updatedFloor = JSON.parse(JSON.stringify(floor)); + break; + } + } + }); + return updatedFloor; + }, + setIsBeveled: (uuid, isBeveled) => set(state => { const floor = state.floors.find(f => f.floorUuid === uuid); if (floor) { @@ -80,9 +177,97 @@ export const createFloorStore = () => { } }), + addDecal: (floorUuid, decal) => set(state => { + const floor = state.floors.find(f => f.floorUuid === floorUuid); + if (floor) { + floor.decals.push(decal); + } + }), + + updateDecal: (decalUuid, updatedDecal) => set(state => { + for (const floor of state.floors) { + const index = floor.decals.findIndex(d => d.decalUuid === decalUuid); + if (index !== -1) { + floor.decals[index] = updatedDecal; + break; + } + } + }), + + removeDecal: (decalUuid) => set(state => { + for (const floor of state.floors) { + floor.decals = floor.decals.filter(d => d.decalUuid !== decalUuid); + } + }), + + updateDecalPosition: (decalUuid, position) => set(state => { + for (const floor of state.floors) { + const decal = floor.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalPosition = position; + break; + } + } + }), + + updateDecalRotation: (decalUuid, rotation) => set(state => { + for (const floor of state.floors) { + const decal = floor.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalRotation = rotation; + break; + } + } + }), + + updateDecalScale: (decalUuid, scale) => set(state => { + for (const floor of state.floors) { + const decal = floor.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalScale = scale; + break; + } + } + }), + + getFloorById: (uuid) => { return get().floors.find(f => f.floorUuid === uuid); }, + + getFloorsByPointId: (pointUuid) => { + return get().floors.find(floor => + floor.points.some(p => p.pointUuid === pointUuid) + ); + }, + + getFloorByPoints: (points) => { + return get().floors.find(floor => { + const floorPointIds = new Set(floor.points.map(p => p.pointUuid)); + const givenPointIds = new Set(points.map(p => p.pointUuid)); + return floorPointIds.size === givenPointIds.size && + [...floorPointIds].every(id => givenPointIds.has(id)); + }); + }, + + getFloorPointById: (pointUuid) => { + for (const floor of get().floors) { + const point = floor.points.find(p => p.pointUuid === pointUuid); + if (point) return point; + } + return undefined; + }, + + getConnectedPoints: (pointUuid) => { + const connected: Point[] = []; + for (const floor of get().floors) { + if (floor.points.some(p => p.pointUuid === pointUuid)) { + connected.push(...floor.points.filter(p => p.pointUuid !== pointUuid)); + } + } + return connected; + } + })) ); }; diff --git a/app/src/store/builder/useWallStore.ts b/app/src/store/builder/useWallStore.ts index 3547330..11f7130 100644 --- a/app/src/store/builder/useWallStore.ts +++ b/app/src/store/builder/useWallStore.ts @@ -5,7 +5,7 @@ interface WallStore { walls: Wall[]; setWalls: (walls: Wall[]) => void; addWall: (wall: Wall) => void; - updateWall: (uuid: string, updated: Partial) => void; + updateWall: (uuid: string, updated: Partial) => Wall | undefined; removeWall: (uuid: string) => void; clearWalls: () => void; removeWallByPoints: (Points: [Point, Point]) => Wall | undefined; @@ -17,11 +17,11 @@ interface WallStore { updateDecalScale: (decalUuid: string, scale: number) => void; removePoint: (pointUuid: string) => Wall[]; - setPosition: (pointUuid: string, position: [number, number, number]) => void; + setPosition: (pointUuid: string, position: [number, number, number]) => Wall[] | []; setLayer: (pointUuid: string, layer: number) => void; getWallById: (uuid: string) => Wall | undefined; - getWallByPointId: (uuid: string) => Wall | undefined; + getWallsByPointId: (uuid: string) => Wall[] | []; getWallByPoints: (points: Point[]) => Wall | undefined; getWallPointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; @@ -40,12 +40,17 @@ export const createWallStore = () => { state.walls.push(wall); }), - updateWall: (uuid, updated) => set((state) => { - const wall = state.walls.find(w => w.wallUuid === uuid); - if (wall) { - Object.assign(wall, updated); - } - }), + updateWall: (uuid, updated) => { + let updatedWall: Wall | undefined; + set((state) => { + const wall = state.walls.find(w => w.wallUuid === uuid); + if (wall) { + Object.assign(wall, updated); + updatedWall = JSON.parse(JSON.stringify(wall)); + } + }); + return updatedWall; + }, removeWall: (uuid) => set((state) => { state.walls = state.walls.filter(w => w.wallUuid !== uuid); @@ -144,14 +149,19 @@ export const createWallStore = () => { return removedWalls; }, - setPosition: (pointUuid, position) => set((state) => { - for (const wall of state.walls) { - const point = wall.points.find(p => p.pointUuid === pointUuid); - if (point) { - point.position = position; + setPosition: (pointUuid, position) => { + let updatedWalls: Wall[] = []; + set((state) => { + for (const wall of state.walls) { + const point = wall.points.find(p => p.pointUuid === pointUuid); + if (point) { + point.position = position; + updatedWalls.push(wall); + } } - } - }), + }); + return updatedWalls; + }, setLayer: (pointUuid, layer) => set((state) => { for (const wall of state.walls) { @@ -166,13 +176,10 @@ export const createWallStore = () => { return get().walls.find(w => w.wallUuid === uuid); }, - getWallByPointId: (uuid) => { - for (const wall of get().walls) { - if (wall.points.some(p => p.pointUuid === uuid)) { - return wall; - } - } - return undefined; + getWallsByPointId: (uuid) => { + return get().walls.filter((a) => { + return a.points.some((p) => p.pointUuid === uuid); + }) }, getWallByPoints: (point) => { From 5003dc3504ab8bfaac90312bd1d8202f69336ebd Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 26 Jun 2025 18:23:01 +0530 Subject: [PATCH 02/18] Refactor floor management APIs: implement getFloorsApi, deleteFloorApi, and upsertFloorApi for enhanced floor data handling. Update FloorCreator for improved point snapping and floor creation logic. Modify ReferencePoint to include UUID and user data. Adjust usePointSnapping to handle temporary points more effectively. --- .../floor/floorCreator/floorCreator.tsx | 44 ++++++++++--------- .../point/helpers/usePointSnapping.tsx | 7 ++- app/src/modules/builder/point/point.tsx | 10 ++--- .../point/reference/referencePoint.tsx | 2 + .../factoryBuilder/floor/deleteFloorApi.ts | 39 ++++++++++++++++ .../factoryBuilder/floor/getFloorsApi.ts | 37 ++++++++++++++++ .../factoryBuilder/floor/upsertFloorApi.ts | 39 ++++++++++++++++ .../factoryBuilder/wall/getWallsApi.ts | 4 +- app/src/store/builder/useFloorStore.ts | 8 ++-- 9 files changed, 157 insertions(+), 33 deletions(-) create mode 100644 app/src/services/factoryBuilder/floor/deleteFloorApi.ts create mode 100644 app/src/services/factoryBuilder/floor/getFloorsApi.ts create mode 100644 app/src/services/factoryBuilder/floor/upsertFloorApi.ts diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx index db031d5..2d09ff9 100644 --- a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -18,7 +18,7 @@ function FloorCreator() { const { addFloor, removeDecal, getFloorPointById, getFloorByPoints } = floorStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); - + const [tempPoints, setTempPoints] = useState([]); const [isCreating, setIsCreating] = useState(false); const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint } = useBuilderStore(); @@ -80,30 +80,34 @@ function FloorCreator() { newPoint.position = snappedPosition; } - if (pointIntersects && !snappedPoint) { - if (tempPoints.length > 2 && isCreating && pointIntersects.object.userData.pointUuid === tempPoints[0].pointUuid) { - if (tempPoints.length >= 3) { - const floor: Floor = { - floorUuid: THREE.MathUtils.generateUUID(), - points: tempPoints, - topMaterial, - sideMaterial, - floorDepth, - isBeveled, - bevelStrength, - decals: [], - }; + if (pointIntersects) { + if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) { + const floor: Floor = { + floorUuid: THREE.MathUtils.generateUUID(), + points: tempPoints, + topMaterial, + sideMaterial, + floorDepth, + isBeveled, + bevelStrength, + decals: [], + }; - addFloor(floor); - } + addFloor(floor); + setTempPoints([]); + setIsCreating(false); + } else if (tempPoints.length === 0) { + tempPoints.push(pointIntersects.object.userData as Point); + setIsCreating(true); + } else { setTempPoints([]); setIsCreating(false); } + } else { + setTempPoints(prev => [...prev, newPoint]); + setIsCreating(true); } - setTempPoints(prev => [...prev, newPoint]); - setIsCreating(true); - }; const onContext = (event: any) => { @@ -157,7 +161,7 @@ function FloorCreator() { <> {toggleView && <> - + {tempPoints.map((point) => ( ))} diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx index 3d0f7e1..0d8f378 100644 --- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx +++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx @@ -201,10 +201,13 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string ); }, [floors, currentPoint]); - const snapFloorPoint = useCallback((position: [number, number, number], tempPoints: Point[] | []) => { + const snapFloorPoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => { if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null }; - const otherPoints = [...getAllOtherFloorPoints(), ...tempPoints]; + const otherPoints = getAllOtherFloorPoints(); + if (tempPoints) { + otherPoints.concat(tempPoints); + } const currentVec = new THREE.Vector3(...position); for (const point of otherPoints) { diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index c3b94d3..504617d 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -12,8 +12,8 @@ import { useSceneContext } from '../../scene/sceneContext'; import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAisleApi'; import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; -import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; -import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; +// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; +// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; import { getUserData } from '../../../functions/getUserData'; function Point({ point }: { readonly point: Point }) { @@ -28,7 +28,7 @@ function Point({ point }: { readonly point: Point }) { const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore(); const { setPosition: setFloorPosition, removePoint: removeFloorPoint } = floorStore(); - const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); + const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); @@ -121,8 +121,8 @@ function Point({ point }: { readonly point: Point }) { const finalSnapped = snapWallPoint(wallSnapped.position); setWallPosition(point.pointUuid, finalSnapped.position); } else if (point.pointType === 'Floor') { - const floorSnapped = snapWallAngle(newPosition); - const finalSnapped = snapWallPoint(floorSnapped.position); + const floorSnapped = snapFloorAngle(newPosition); + const finalSnapped = snapFloorPoint(floorSnapped.position); setFloorPosition(point.pointUuid, finalSnapped.position); } } diff --git a/app/src/modules/builder/point/reference/referencePoint.tsx b/app/src/modules/builder/point/reference/referencePoint.tsx index 3be6f95..2f2cccd 100644 --- a/app/src/modules/builder/point/reference/referencePoint.tsx +++ b/app/src/modules/builder/point/reference/referencePoint.tsx @@ -30,6 +30,8 @@ function ReferencePoint({ point }: { readonly point: Point }) { { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/deleteFloor`, { + method: "PATCH", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, floorUuid }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to delete floor:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to delete floor"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/floor/getFloorsApi.ts b/app/src/services/factoryBuilder/floor/getFloorsApi.ts new file mode 100644 index 0000000..2659e61 --- /dev/null +++ b/app/src/services/factoryBuilder/floor/getFloorsApi.ts @@ -0,0 +1,37 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getFloorsApi = async ( + projectId: string, + versionId: string, +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/floors/${projectId}/${versionId}`, { + method: "GET", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to get floors:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to get floors"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/floor/upsertFloorApi.ts b/app/src/services/factoryBuilder/floor/upsertFloorApi.ts new file mode 100644 index 0000000..a00d8f7 --- /dev/null +++ b/app/src/services/factoryBuilder/floor/upsertFloorApi.ts @@ -0,0 +1,39 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const upsertFloorApi = async ( + projectId: string, + versionId: string, + floorData: Wall +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertFloor`, { + method: "POST", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, floorData }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to upsert floor:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to upsert floor"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/wall/getWallsApi.ts b/app/src/services/factoryBuilder/wall/getWallsApi.ts index 88bf3e7..b3f94b0 100644 --- a/app/src/services/factoryBuilder/wall/getWallsApi.ts +++ b/app/src/services/factoryBuilder/wall/getWallsApi.ts @@ -21,13 +21,13 @@ export const getWallsApi = async ( } if (!response.ok) { - console.error("Failed to get wall:", response.statusText); + console.error("Failed to get walls:", response.statusText); } const result = await response.json(); return result; } catch (error) { - echo.error("Failed to get wall"); + echo.error("Failed to get walls"); if (error instanceof Error) { console.log(error.message); } else { diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index f1c9bfa..c3ddf7d 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -13,7 +13,7 @@ interface FloorStore { setPosition: ( pointUuid: string, position: [number, number, number] - ) => Floor | undefined; + ) => Floor[] | []; setIsBeveled: (uuid: string, isBeveled: boolean) => void; setBevelStrength: (uuid: string, strength: number) => void; setDepth: (uuid: string, depth: number) => void; @@ -83,6 +83,7 @@ export const createFloorStore = () => { return removedFloors; }, + removeFloorByPoints: ([pointA, pointB]) => { const removedFloors: Floor[] = []; @@ -134,14 +135,13 @@ export const createFloorStore = () => { }), setPosition: (pointUuid, position) => { - let updatedFloor: Floor | undefined; + let updatedFloor: Floor[] = []; set((state) => { for (const floor of state.floors) { const point = floor.points.find((p) => p.pointUuid === pointUuid); if (point) { point.position = position; - updatedFloor = JSON.parse(JSON.stringify(floor)); - break; + updatedFloor.push(JSON.parse(JSON.stringify(floor))); } } }); From 04c302ea4c600069b4bcd940ab86945dd624e866 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 10:48:48 +0530 Subject: [PATCH 03/18] Refactor floor management components and APIs: enhance FloorInstance for shape creation, update FloorInstances to handle floor rendering and UUID tracking, and improve FloorCreator with project and version context. Modify floor store methods for better floor management and integrate API calls for floor upsert and deletion. Adjust wall and point components to support new floor functionalities. --- .../Instances/Instance/floorInstance.tsx | 31 ++++++- .../floor/Instances/floorInstances.tsx | 9 +- .../floor/floorCreator/floorCreator.tsx | 57 +++++++++++-- app/src/modules/builder/floor/floorGroup.tsx | 26 +++++- app/src/modules/builder/line/line.tsx | 83 +++++++++++++++++-- app/src/modules/builder/point/point.tsx | 72 +++++++++++++++- app/src/modules/builder/wall/wallGroup.tsx | 9 +- .../factoryBuilder/floor/upsertFloorApi.ts | 2 +- app/src/store/builder/useBuilderStore.ts | 2 +- app/src/store/builder/useFloorStore.ts | 49 ++++++----- 10 files changed, 287 insertions(+), 53 deletions(-) diff --git a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx index 1b6dcb7..6c9016e 100644 --- a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx +++ b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx @@ -1,10 +1,33 @@ -import React from 'react' +import { useMemo } from 'react' +import { Shape, Vector2, DoubleSide } from 'three'; +import { useLoader } from '@react-three/fiber'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../types/world/worldConstants'; function FloorInstance({ floor }: { floor: Floor }) { + + const shape = useMemo(() => { + const shape = new Shape(); + const points = floor.points.map(p => new Vector2(p.position[0], p.position[2])); + if (points.length < 3) return null; + shape.moveTo(points[0].x, points[0].y); + points.forEach((pt) => { shape.lineTo(pt.x, pt.y); }); + return shape; + }, [floor]); + + if (!shape) return null; + return ( - <> - - ) + + + + + + ); } export default FloorInstance \ No newline at end of file diff --git a/app/src/modules/builder/floor/Instances/floorInstances.tsx b/app/src/modules/builder/floor/Instances/floorInstances.tsx index 75fd359..a5969eb 100644 --- a/app/src/modules/builder/floor/Instances/floorInstances.tsx +++ b/app/src/modules/builder/floor/Instances/floorInstances.tsx @@ -34,6 +34,7 @@ function FloorInstances() { const allLines = useMemo(() => { const lines: { start: Point; end: Point; key: string }[] = []; + const seenUuids = new Set(); floors.forEach((floor) => { const points = floor.points; @@ -42,11 +43,13 @@ function FloorInstances() { for (let i = 0; i < points.length; i++) { const current = points[i]; const next = points[(i + 1) % points.length]; - if (current.pointUuid !== next.pointUuid) { + const lineKey = `${current.pointUuid}-${next.pointUuid}`; + if (current.pointUuid !== next.pointUuid && !seenUuids.has(lineKey)) { + seenUuids.add(lineKey); lines.push({ start: current, end: next, - key: `${current.pointUuid}-${next.pointUuid}` + key: lineKey }); } } @@ -58,7 +61,7 @@ function FloorInstances() { return ( <> - {!toggleView && floors.length > 1 && ( + {!toggleView && floors.length > 0 && ( {floors.map((floor) => ( diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx index 2d09ff9..aaeb0f3 100644 --- a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -4,9 +4,14 @@ import { useThree } from '@react-three/fiber'; import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; import { useSceneContext } from '../../../scene/sceneContext'; import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; +import { useParams } from 'react-router-dom'; +import { useVersionContext } from '../../version/versionContext'; +import { getUserData } from '../../../../functions/getUserData'; import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceFloor from './referenceFloor'; +// import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi'; + function FloorCreator() { const { scene, camera, raycaster, gl, pointer } = useThree(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); @@ -15,9 +20,13 @@ function FloorCreator() { const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); const { floorStore } = useSceneContext(); - const { addFloor, removeDecal, getFloorPointById, getFloorByPoints } = floorStore(); + const { addFloor, getFloorPointById, getFloorByPoints } = floorStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); const [tempPoints, setTempPoints] = useState([]); const [isCreating, setIsCreating] = useState(false); @@ -94,14 +103,33 @@ function FloorCreator() { }; addFloor(floor); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + + } setTempPoints([]); setIsCreating(false); - } else if (tempPoints.length === 0) { + } else if (tempPoints.length === 0 || (tempPoints.length > 1 && pointIntersects.object.uuid !== tempPoints[tempPoints.length - 2].pointUuid)) { tempPoints.push(pointIntersects.object.userData as Point); setIsCreating(true); } else { - setTempPoints([]); - setIsCreating(false); + tempPoints.push(pointIntersects.object.userData as Point); + setIsCreating(true); } } else { setTempPoints(prev => [...prev, newPoint]); @@ -126,6 +154,25 @@ function FloorCreator() { }; addFloor(floor); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + + } } setTempPoints([]); setIsCreating(false); @@ -155,7 +202,7 @@ function FloorCreator() { canvasElement.removeEventListener("click", onMouseClick); canvasElement.removeEventListener("contextmenu", onContext); }; - }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, removeDecal, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]); + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]); return ( <> diff --git a/app/src/modules/builder/floor/floorGroup.tsx b/app/src/modules/builder/floor/floorGroup.tsx index fdcf37c..53a81f4 100644 --- a/app/src/modules/builder/floor/floorGroup.tsx +++ b/app/src/modules/builder/floor/floorGroup.tsx @@ -1,14 +1,23 @@ import { useEffect } from 'react'; import { useToggleView } from '../../../store/builder/store' import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import { useVersionContext } from '../version/versionContext'; +import { useSceneContext } from '../../scene/sceneContext'; +import { useParams } from 'react-router-dom'; +import useModuleStore from '../../../store/useModuleStore'; import FloorCreator from './floorCreator/floorCreator'; import FloorInstances from './Instances/floorInstances'; -import useModuleStore from '../../../store/useModuleStore'; +import { getFloorsApi } from '../../../services/factoryBuilder/floor/getFloorsApi'; function FloorGroup() { const { togglView } = useToggleView(); const { setSelectedFloor, setSelectedDecal } = useBuilderStore(); const { activeModule } = useModuleStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { floorStore } = useSceneContext(); + const { setFloors } = floorStore(); + const { projectId } = useParams(); useEffect(() => { if (togglView || activeModule !== 'builder') { @@ -17,6 +26,21 @@ function FloorGroup() { } }, [togglView, activeModule]) + useEffect(() => { + if (projectId && selectedVersion) { + getFloorsApi(projectId, selectedVersion?.versionId || '').then((floors) => { + console.log('floors: ', floors); + if (floors && floors.length > 0) { + setFloors(floors); + } else { + setFloors([]); + } + }).catch((err) => { + console.log(err); + }) + } + }, [projectId, selectedVersion?.versionId]) + return ( <> diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index 42aa5c2..f75be5d 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -6,12 +6,15 @@ import { useSocketStore, useToolMode } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useSceneContext } from '../../scene/sceneContext'; import * as Constants from '../../../types/world/worldConstants'; -import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; import { useVersionContext } from '../version/versionContext'; import { useParams } from 'react-router-dom'; -import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; import { getUserData } from '../../../functions/getUserData'; +// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; +// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; +import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; +import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; + interface LineProps { points: [Point, Point]; } @@ -25,7 +28,7 @@ function Line({ points }: Readonly) { const { toolMode } = useToolMode(); const { wallStore, floorStore } = useSceneContext(); const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore(); - const { removeFloorByPoints, setPosition: setFloorPosition } = floorStore(); + const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId } = floorStore(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); @@ -112,7 +115,52 @@ function Line({ points }: Readonly) { setHoveredLine(null); } if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { - removeFloorByPoints(points); + const { removedFloors, updatedFloors } = removeFloorByPoints(points); + if (removedFloors.length > 0) { + removedFloors.forEach(floor => { + if (projectId) { + + // API + + // deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid); + + // SOCKET + + const data = { + floorUuid: floor.floorUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:delete', data); + } + }); + } + if (updatedFloors.length > 0) { + updatedFloors.forEach(floor => { + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }); + } + setHoveredLine(null); } gl.domElement.style.cursor = 'default'; @@ -197,7 +245,32 @@ function Line({ points }: Readonly) { }) } } else if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { - // Handle floor update logic here if needed + const updatedFloors1 = getFloorsByPointId(points[0].pointUuid); + const updatedFloors2 = getFloorsByPointId(points[1].pointUuid); + const updatedFloors = [...updatedFloors1, ...updatedFloors2].filter((floor, index, self) => index === self.findIndex((f) => f.floorUuid === floor.floorUuid)); + + if (updatedFloors.length > 0 && projectId) { + updatedFloors.forEach(updatedFloor => { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor).catch((error) => { + // console.error('Error updating floor:', error); + // }); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + }) + } } } diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index 504617d..fe2dd6e 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -14,7 +14,10 @@ import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAis import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; // import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; // import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; +import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; + import { getUserData } from '../../../functions/getUserData'; +import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; function Point({ point }: { readonly point: Point }) { const materialRef = useRef(null); @@ -27,7 +30,7 @@ function Point({ point }: { readonly point: Point }) { const { aisleStore, wallStore, floorStore } = useSceneContext(); const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore(); - const { setPosition: setFloorPosition, removePoint: removeFloorPoint } = floorStore(); + const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore(); const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { userId, organization } = getUserData(); @@ -174,9 +177,28 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Wall:add', data); }); } - // console.log('Wall after drag: ', point); } else if (point.pointType === 'Floor') { - // console.log('Floor after drag: ', point); + const updatedFloors = getFloorsByPointId(point.pointUuid); + if (updatedFloors && updatedFloors.length > 0 && projectId) { + updatedFloors.forEach((updatedFloor) => { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + }); + } } } @@ -220,9 +242,51 @@ function Point({ point }: { readonly point: Point }) { } } if (point.pointType === 'Floor') { - const removedFloors = removeFloorPoint(point.pointUuid); + const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid); setHoveredPoint(null); if (removedFloors.length > 0) { + removedFloors.forEach(floor => { + if (projectId) { + + // API + + // deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid); + + // SOCKET + + const data = { + floorUuid: floor.floorUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:delete', data); + } + }); + } + if (updatedFloors.length > 0) { + updatedFloors.forEach(floor => { + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }); } } gl.domElement.style.cursor = 'default'; diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index 0722d56..bd8bad1 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -1,12 +1,13 @@ import { useEffect } from 'react'; import { useToggleView } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import { useVersionContext } from '../version/versionContext'; +import { useSceneContext } from '../../scene/sceneContext'; +import { useParams } from 'react-router-dom'; +import useModuleStore from '../../../store/useModuleStore'; import WallCreator from './wallCreator/wallCreator'; import WallInstances from './Instances/wallInstances'; -import useModuleStore from '../../../store/useModuleStore'; -import { useVersionContext } from '../version/versionContext'; -import { useParams } from 'react-router-dom'; -import { useSceneContext } from '../../scene/sceneContext'; + import { getWallsApi } from '../../../services/factoryBuilder/wall/getWallsApi'; function WallGroup() { diff --git a/app/src/services/factoryBuilder/floor/upsertFloorApi.ts b/app/src/services/factoryBuilder/floor/upsertFloorApi.ts index a00d8f7..45590c1 100644 --- a/app/src/services/factoryBuilder/floor/upsertFloorApi.ts +++ b/app/src/services/factoryBuilder/floor/upsertFloorApi.ts @@ -3,7 +3,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const upsertFloorApi = async ( projectId: string, versionId: string, - floorData: Wall + floorData: Floor ) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertFloor`, { diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index 18facd9..e35db75 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -97,7 +97,7 @@ export const useBuilderStore = create()( insideMaterial: 'Material 1', selectedFloor: null, - floorDepth: 0.3, + floorDepth: 0.1, isBeveled: false, bevelStrength: 0.05, sideMaterial: 'Default Side', diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index c3ddf7d..7d425eb 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -7,8 +7,8 @@ interface FloorStore { addFloor: (floor: Floor) => void; updateFloor: (uuid: string, updated: Partial) => void; removeFloor: (uuid: string) => void; - removePoint: (pointUuid: string) => Floor[]; - removeFloorByPoints: (Points: [Point, Point]) => Floor[]; + removePoint: (pointUuid: string) => { removedFloors: Floor[], updatedFloors: Floor[] }; + removeFloorByPoints: (Points: [Point, Point]) => { removedFloors: Floor[], updatedFloors: Floor[] }; clearFloors: () => void; setPosition: ( pointUuid: string, @@ -26,7 +26,7 @@ interface FloorStore { updateDecalScale: (decalUuid: string, scale: number) => void; getFloorById: (uuid: string) => Floor | undefined; - getFloorsByPointId: (uuid: string) => Floor | undefined; + getFloorsByPointId: (uuid: string) => Floor[] | []; getFloorByPoints: (points: Point[]) => Floor | undefined; getFloorPointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; @@ -58,47 +58,46 @@ export const createFloorStore = () => { removePoint: (pointUuid) => { const removedFloors: Floor[] = []; + const updatedFloors: Floor[] = []; set(state => { - const updatedFloors: Floor[] = []; - for (const floor of state.floors) { - const hasPoint = floor.points.some(p => p.pointUuid === pointUuid); - if (!hasPoint) { - updatedFloors.push(floor); + const pointIndex = floor.points.findIndex(p => p.pointUuid === pointUuid); + if (pointIndex === -1) { + updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } const remainingPoints = floor.points.filter(p => p.pointUuid !== pointUuid); - if (remainingPoints.length > 2) { - floor.points = remainingPoints; - updatedFloors.push(floor); - } else { - removedFloors.push(floor); + + if (remainingPoints.length <= 2) { + removedFloors.push(JSON.parse(JSON.stringify(floor))); + continue; } + floor.points = remainingPoints; + updatedFloors.push(JSON.parse(JSON.stringify(floor))); } state.floors = updatedFloors; }); - return removedFloors; + return { removedFloors, updatedFloors }; }, removeFloorByPoints: ([pointA, pointB]) => { const removedFloors: Floor[] = []; + const updatedFloors: Floor[] = []; set(state => { - const updatedFloors: Floor[] = []; for (const floor of state.floors) { - const indices = floor.points - .map((p, i) => ({ uuid: p.pointUuid, index: i })); + const indices = floor.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; if (idxA === -1 || idxB === -1) { - updatedFloors.push(floor); + updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } @@ -108,7 +107,7 @@ export const createFloorStore = () => { (idxB === 0 && idxA === floor.points.length - 1); if (!areAdjacent) { - updatedFloors.push(floor); + updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } @@ -118,16 +117,16 @@ export const createFloorStore = () => { if (remainingPoints.length > 2) { floor.points = remainingPoints; - updatedFloors.push(floor); + updatedFloors.push(JSON.parse(JSON.stringify(floor))); } else { - removedFloors.push(floor); + removedFloors.push(JSON.parse(JSON.stringify(floor))); } } state.floors = updatedFloors; }); - return removedFloors; + return { removedFloors, updatedFloors }; }, clearFloors: () => set(state => { @@ -236,9 +235,9 @@ export const createFloorStore = () => { }, getFloorsByPointId: (pointUuid) => { - return get().floors.find(floor => - floor.points.some(p => p.pointUuid === pointUuid) - ); + return get().floors.filter(floor => { + return floor.points.some(p => p.pointUuid === pointUuid); + }); }, getFloorByPoints: (points) => { From 64f0cdb1480e5f5f071bde6d89879f18ec032321 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 11:56:54 +0530 Subject: [PATCH 04/18] Refactor builder store and related components: update DecalInstance to manage selectedFloor state, enhance FloorInstance with improved material handling and texture application, and modify FloorGroup to remove unnecessary console log. Update Wall component for better shadow handling and adjust useBuilderStore to change default material values. --- .../modules/builder/Decal/decalInstance.tsx | 3 +- .../Instances/Instance/floorInstance.tsx | 90 ++++++++++++++++--- app/src/modules/builder/floor/floorGroup.tsx | 1 - .../builder/wall/Instances/instance/wall.tsx | 12 +-- .../scene/postProcessing/postProcessing.tsx | 21 ++++- app/src/store/builder/useBuilderStore.ts | 4 +- 6 files changed, 111 insertions(+), 20 deletions(-) diff --git a/app/src/modules/builder/Decal/decalInstance.tsx b/app/src/modules/builder/Decal/decalInstance.tsx index 6ed0490..71dcd83 100644 --- a/app/src/modules/builder/Decal/decalInstance.tsx +++ b/app/src/modules/builder/Decal/decalInstance.tsx @@ -8,7 +8,7 @@ import defaultMaterial from '../../../assets/textures/floor/wall-tex.png'; import useModuleStore from '../../../store/useModuleStore'; function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) { - const { setSelectedWall, selectedDecal, setSelectedDecal } = useBuilderStore(); + const { setSelectedWall, setSelectedFloor, selectedDecal, setSelectedDecal } = useBuilderStore(); const { togglView } = useToggleView(); const { activeModule } = useModuleStore(); const material = useLoader(THREE.TextureLoader, defaultMaterial); @@ -26,6 +26,7 @@ function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: De if (e.object.userData.decalUuid) { setSelectedDecal(e.object); setSelectedWall(null); + setSelectedFloor(null); } } }} diff --git a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx index 6c9016e..ce82298 100644 --- a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx +++ b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx @@ -1,33 +1,103 @@ -import { useMemo } from 'react' -import { Shape, Vector2, DoubleSide } from 'three'; +import { useMemo } from 'react'; +import { Shape, Vector2, DoubleSide, TextureLoader, RepeatWrapping, SRGBColorSpace } from 'three'; import { useLoader } from '@react-three/fiber'; import { Extrude } from '@react-three/drei'; +import useModuleStore from '../../../../../store/useModuleStore'; +import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; +import { useToggleView } from '../../../../../store/builder/store'; import * as Constants from '../../../../../types/world/worldConstants'; +import texturePath from "../../../../../assets/textures/floor/white.png"; +import texturePathDark from "../../../../../assets/textures/floor/black.png"; +import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg'; + function FloorInstance({ floor }: { floor: Floor }) { + const { togglView } = useToggleView(); + const { activeModule } = useModuleStore(); + const { selectedFloor, setSelectedFloor, setSelectedDecal } = useBuilderStore(); + const savedTheme = localStorage.getItem('theme'); + + const materials: Record = { + "Default Material": savedTheme === "dark" ? texturePathDark : texturePath, + "Material 1": savedTheme === "dark" ? material1 : material1, + }; const shape = useMemo(() => { const shape = new Shape(); const points = floor.points.map(p => new Vector2(p.position[0], p.position[2])); if (points.length < 3) return null; shape.moveTo(points[0].x, points[0].y); - points.forEach((pt) => { shape.lineTo(pt.x, pt.y); }); + for (let i = 1; i < points.length; i++) { + shape.lineTo(points[i].x, points[i].y); + } return shape; }, [floor]); + const textureScale = Constants.floorConfig.textureScale; + + const [topTexture, sideTexture] = useLoader( + TextureLoader, + [ + materials[floor.topMaterial] || materials['Default Material'], + materials[floor.sideMaterial] || materials['Default Material'] + ] + ); + + if (!materials[floor.topMaterial] || !materials[floor.sideMaterial]) return null; + + [topTexture, sideTexture].forEach(tex => { + tex.wrapS = tex.wrapT = RepeatWrapping; + tex.repeat.set(textureScale, textureScale); + tex.colorSpace = SRGBColorSpace; + }); + if (!shape) return null; return ( - + { + if (!togglView && activeModule === 'builder') { + if (e.object.userData.floorUuid) { + setSelectedFloor(e.object); + setSelectedDecal(null); + } + } + }} + onPointerMissed={() => { + if (selectedFloor && selectedFloor.userData.floorUuid === floor.floorUuid) { + setSelectedFloor(null); + } + }} + > - + + - + ); } -export default FloorInstance \ No newline at end of file +export default FloorInstance; \ No newline at end of file diff --git a/app/src/modules/builder/floor/floorGroup.tsx b/app/src/modules/builder/floor/floorGroup.tsx index 53a81f4..e0da8e5 100644 --- a/app/src/modules/builder/floor/floorGroup.tsx +++ b/app/src/modules/builder/floor/floorGroup.tsx @@ -29,7 +29,6 @@ function FloorGroup() { useEffect(() => { if (projectId && selectedVersion) { getFloorsApi(projectId, selectedVersion?.versionId || '').then((floors) => { - console.log('floors: ', floors); if (floors && floors.length > 0) { setFloors(floors); } else { diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 037816b..a07e8f9 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -1,20 +1,21 @@ import * as THREE from 'three'; import { Base } from '@react-three/csg'; import { useMemo, useRef, useState } from 'react'; -import { Decal, MeshDiscardMaterial } from '@react-three/drei'; +import { MeshDiscardMaterial } from '@react-three/drei'; import { useFrame, useThree } from '@react-three/fiber'; - -import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png'; -import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg'; - import useModuleStore from '../../../../../store/useModuleStore'; import { useSceneContext } from '../../../../scene/sceneContext'; import { useWallClassification } from './helpers/useWallClassification'; import { useToggleView, useWallVisibility } from '../../../../../store/builder/store'; import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; import * as Constants from '../../../../../types/world/worldConstants'; + import DecalInstance from '../../../Decal/decalInstance'; +import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png'; +import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg'; + + function Wall({ wall }: { readonly wall: Wall }) { const { wallStore } = useSceneContext(); const { walls, addDecal } = wallStore(); @@ -116,6 +117,7 @@ function Wall({ wall }: { readonly wall: Wall }) { { + // console.log('selectedFloor: ', selectedFloor); + }, [selectedFloor]) + return ( )} + {selectedFloor && ( + + )} {selectedDecal && ( ()( floorDepth: 0.1, isBeveled: false, bevelStrength: 0.05, - sideMaterial: 'Default Side', - topMaterial: 'Default Top', + sideMaterial: 'Material 1', + topMaterial: 'Default Material', selectedDecal: null, From c73bdf455615a74303bb129f48850d5f0ed2909b Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 15:44:31 +0530 Subject: [PATCH 05/18] completed floor --- .../layout/sidebarRight/SideBarRight.tsx | 425 +++++---- .../properties/FloorProperties.tsx | 171 ++++ .../properties/SelectedFloorProperties.tsx | 250 +++++ .../properties/SelectedWallProperties.tsx | 32 +- .../properties/WallProperties.tsx | 271 +++--- .../instance/aisleTypes/arcAisle.tsx | 2 +- .../instance/aisleTypes/arrowAisle.tsx | 2 +- .../instance/aisleTypes/arrowsAisle.tsx | 2 +- .../instance/aisleTypes/circleAisle.tsx | 2 +- .../instance/aisleTypes/dashedAisle.tsx | 2 +- .../instance/aisleTypes/dottedAisle.tsx | 2 +- .../instance/aisleTypes/junctionAisle.tsx | 2 +- .../instance/aisleTypes/solidAisle.tsx | 2 +- app/src/modules/builder/asset/assetsGroup.tsx | 4 +- .../builder/asset/functions/addAssetModel.ts | 875 +++++++++--------- .../Instances/Instance/floorInstance.tsx | 12 +- .../builder/wall/Instances/instance/wall.tsx | 2 +- .../builder/wall/Instances/wallInstances.tsx | 7 +- .../builder/wall/wallCreator/wallCreator.tsx | 4 +- .../distanceFindingControls.tsx | 487 ++++------ app/src/store/builder/useBuilderStore.ts | 6 +- app/src/store/builder/useFloorStore.ts | 19 +- 22 files changed, 1422 insertions(+), 1159 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/FloorProperties.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index d6413bc..1fa90d3 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -1,27 +1,28 @@ import React, { useEffect } from "react"; import Header from "./Header"; import useModuleStore, { - useSubModuleStore, + useSubModuleStore, } from "../../../store/useModuleStore"; import { - AnalysisIcon, - MechanicsIcon, - PropertiesIcon, - SimulationIcon, + AnalysisIcon, + MechanicsIcon, + PropertiesIcon, + SimulationIcon, } from "../../icons/SimulationIcons"; import { useToggleStore } from "../../../store/useUIToggleStore"; import Visualization from "./visualization/Visualization"; import Analysis from "./analysis/Analysis"; import Simulations from "./simulation/Simulations"; import useVersionHistoryVisibleStore, { - useSaveVersion, - useSelectedFloorItem, - useToolMode, + useSaveVersion, + useSelectedFloorItem, + useToolMode, } from "../../../store/builder/store"; import { - useSelectedEventData, - useSelectedEventSphere, + useSelectedEventData, + useSelectedEventSphere, } from "../../../store/simulation/useSimulationStore"; +import { useBuilderStore } from "../../../store/builder/useBuilderStore"; import GlobalProperties from "./properties/GlobalProperties"; import AssetProperties from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; @@ -29,207 +30,227 @@ import EventProperties from "./properties/eventProperties/EventProperties"; import VersionHistory from "./versionHisory/VersionHistory"; import AisleProperties from "./properties/AisleProperties"; import WallProperties from "./properties/WallProperties"; -import { useBuilderStore } from "../../../store/builder/useBuilderStore"; +import FloorProperties from "./properties/FloorProperties"; import SelectedWallProperties from "./properties/SelectedWallProperties"; +import SelectedFloorProperties from "./properties/SelectedFloorProperties"; const SideBarRight: React.FC = () => { - const { activeModule } = useModuleStore(); - const { toggleUIRight } = useToggleStore(); - const { toolMode } = useToolMode(); - const { subModule, setSubModule } = useSubModuleStore(); - const { selectedFloorItem } = useSelectedFloorItem(); - const { selectedWall } = useBuilderStore(); - const { selectedEventData } = useSelectedEventData(); - const { selectedEventSphere } = useSelectedEventSphere(); - const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore(); - const { isVersionSaved } = useSaveVersion(); + const { activeModule } = useModuleStore(); + const { toggleUIRight } = useToggleStore(); + const { toolMode } = useToolMode(); + const { subModule, setSubModule } = useSubModuleStore(); + const { selectedFloorItem } = useSelectedFloorItem(); + const { selectedWall, selectedFloor, selectedAisle } = useBuilderStore(); + const { selectedEventData } = useSelectedEventData(); + const { selectedEventSphere } = useSelectedEventSphere(); + const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore(); + const { isVersionSaved } = useSaveVersion(); - // Reset activeList whenever activeModule changes - useEffect(() => { - if (activeModule !== "simulation") setSubModule("properties"); - if (activeModule === "simulation") setSubModule("simulations"); - }, [activeModule, setSubModule]); + // Reset activeList whenever activeModule changes + useEffect(() => { + if (activeModule !== "simulation") setSubModule("properties"); + if (activeModule === "simulation") setSubModule("simulations"); + }, [activeModule, setSubModule]); - useEffect(() => { - if ( - activeModule !== "mechanics" && - selectedEventData && - selectedEventSphere - ) { - setSubModule("mechanics"); - } else if (!selectedEventData && !selectedEventSphere) { - if (activeModule === "simulation") { - setSubModule("simulations"); - } - } - if (activeModule !== "simulation") { - setSubModule("properties"); - } - }, [activeModule, selectedEventData, selectedEventSphere, setSubModule]); + useEffect(() => { + if ( + activeModule !== "mechanics" && + selectedEventData && + selectedEventSphere + ) { + setSubModule("mechanics"); + } else if (!selectedEventData && !selectedEventSphere) { + if (activeModule === "simulation") { + setSubModule("simulations"); + } + } + if (activeModule !== "simulation") { + setSubModule("properties"); + } + }, [activeModule, selectedEventData, selectedEventSphere, setSubModule]); - return ( -
-
- {toggleUIRight && ( - <> - {!isVersionSaved && ( -
- {activeModule !== "simulation" && ( - - )} - {activeModule === "simulation" && ( + return ( +
+
+ {toggleUIRight && ( <> - - - + {!isVersionSaved && ( +
+ {activeModule !== "simulation" && ( + + )} + {activeModule === "simulation" && ( + <> + + + + + )} +
+ )} + + {viewVersionHistory && ( +
+
+ +
+
+ )} + + {/* process builder */} + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && + !selectedFloor && + !selectedWall && ( +
+
+ {(() => { + if (toolMode === "Aisle") { + return ; + } else if (toolMode === "Wall") { + return ; + } else if (toolMode === "Floor") { + return ; + } else { + return ; + } + })()} +
+
+ )} + + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + selectedFloorItem && ( +
+
+ +
+
+ )} + + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && + !selectedFloor && + !selectedAisle && + selectedWall && ( +
+
+ +
+
+ )} + + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && + !selectedWall && + !selectedAisle && + selectedFloor && ( +
+
+ +
+
+ )} + + {!viewVersionHistory && + subModule === "zoneProperties" && + (activeModule === "builder" || activeModule === "simulation") && ( +
+
+ +
+
+ )} + + {/* simulation */} + {!isVersionSaved && + !viewVersionHistory && + activeModule === "simulation" && ( + <> + {subModule === "simulations" && ( +
+
+ +
+
+ )} + {subModule === "mechanics" && ( +
+
+ +
+
+ )} + {subModule === "analysis" && ( +
+
+ +
+
+ )} + + )} + {/* realtime visualization */} + {activeModule === "visualization" && } - )} -
- )} - - {viewVersionHistory && ( -
-
- -
-
- )} - - {/* process builder */} - {!viewVersionHistory && - subModule === "properties" && - activeModule !== "visualization" && - !selectedFloorItem && - !selectedWall && ( -
-
- {(() => { - if (toolMode === "Aisle") { - return ; - } else if (toolMode === "Wall") { - return ; - } else { - return ; - } - })()} -
-
)} - - {!viewVersionHistory && - subModule === "properties" && - activeModule !== "visualization" && - selectedFloorItem && ( -
-
- -
-
- )} - - {!viewVersionHistory && - subModule === "properties" && - activeModule !== "visualization" && - !selectedFloorItem && - selectedWall && ( -
-
- -
-
- )} - - {!viewVersionHistory && - subModule === "zoneProperties" && - (activeModule === "builder" || activeModule === "simulation") && ( -
-
- -
-
- )} - - {/* simulation */} - {!isVersionSaved && - !viewVersionHistory && - activeModule === "simulation" && ( - <> - {subModule === "simulations" && ( -
-
- -
-
- )} - {subModule === "mechanics" && ( -
-
- -
-
- )} - {subModule === "analysis" && ( -
-
- -
-
- )} - - )} - {/* realtime visualization */} - {activeModule === "visualization" && } - - )} -
- ); +
+ ); }; export default SideBarRight; diff --git a/app/src/components/layout/sidebarRight/properties/FloorProperties.tsx b/app/src/components/layout/sidebarRight/properties/FloorProperties.tsx new file mode 100644 index 0000000..41e8d41 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/FloorProperties.tsx @@ -0,0 +1,171 @@ +import { useEffect, useState } from "react"; +import InputToggle from "../../../ui/inputs/InputToggle"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; + +import defaultTexture from '../../../../assets/textures/floor/white.png'; +import flootTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg'; + +import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; + +type Material = { + texture: string; + textureId: string; + textureName: string; +}; + +const materials = [ + { texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" }, + { texture: flootTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" } +]; + +const FloorProperties = () => { + const { floorDepth, isBeveled, topMaterial, sideMaterial, bevelStrength, setFloorDepth, setIsBeveled, setBevelStrength, setFloorMaterial } = useBuilderStore(); + + const [activeSurface, setActiveSurface] = useState<"top" | "side">("top"); + + const [selectedMaterials, setSelectedMaterials] = useState<{ top: Material | null; side: Material | null; }>({ top: null, side: null, }); + + useEffect(() => { + setSelectedMaterials({ + top: materials.find((mat) => mat.textureId === topMaterial) || null, + side: materials.find((mat) => mat.textureId === sideMaterial) || null, + }); + }, []); + + const handleDepthChange = (val: string) => { + setFloorDepth(parseFloat(val)); + }; + + const handleIsBevelChange = (val: boolean) => { + setIsBeveled(val); + }; + + const handleBevelChange = (val: string) => { + setBevelStrength(parseFloat(val)); + }; + + const handleSelectMaterial = (material: Material) => { + setSelectedMaterials((prev) => ({ + ...prev, + [activeSurface]: material, + })); + setFloorMaterial(material.textureId, activeSurface); + }; + + return ( +
+
+
Floor
+
+ + handleIsBevelChange(!isBeveled)} + /> + +
+
+ +
+
+
Materials
+
+ +
+
+ + + +
+ +
+ {selectedMaterials[activeSurface] && ( + {selectedMaterials[activeSurface]!.textureName} + )} +
+
+ +
+ {materials.length === 0 ? ( +
No materials added yet.
+ ) : ( +
+ {materials.map((material, index) => { + const isSelected = selectedMaterials[activeSurface]?.texture === material.texture; + + return ( + + ); + })} +
+ )} +
+
+
+ ); +}; + +export default FloorProperties; diff --git a/app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx new file mode 100644 index 0000000..8df2a88 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx @@ -0,0 +1,250 @@ +import { useEffect, useState } from "react"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; +import InputToggle from "../../../ui/inputs/InputToggle"; + +import defaultTexture from '../../../../assets/textures/floor/white.png'; +import floorTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg'; + +import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; +import { useSceneContext } from "../../../../modules/scene/sceneContext"; +import { useVersionContext } from "../../../../modules/builder/version/versionContext"; +import { useParams } from "react-router-dom"; +import { getUserData } from "../../../../functions/getUserData"; +import { useSocketStore } from "../../../../store/builder/store"; + +// import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi"; + +const SelectedFloorProperties = () => { + const [depth, setDepth] = useState(""); + const [isBeveled, setIsBeveled] = useState(false); + const [bevelStrength, setBevelStrength] = useState(""); + const { selectedFloor } = useBuilderStore(); + const { floorStore } = useSceneContext(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { socket } = useSocketStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); + const { getFloorById, updateFloor } = floorStore(); + + const [activeSurface, setActiveSurface] = useState<"top" | "side">("top"); + + const materials = [ + { texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" }, + { texture: floorTexture1, textureId: "Material 1", textureName: "Grunge Concrete" } + ]; + + const floor = selectedFloor ? getFloorById(selectedFloor.userData.floorUuid) : null; + + useEffect(() => { + if (floor) { + setDepth(floor.floorDepth.toString()); + setIsBeveled(floor.isBeveled); + setBevelStrength(floor.bevelStrength.toString()); + } + }, [floor]); + + const handleDepthChange = (val: string) => { + setDepth(val); + const parsed = parseFloat(val); + if (!isNaN(parsed) && floor) { + const updatedFloor = updateFloor(floor.floorUuid, { floorDepth: parsed }); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + } + }; + + const handleBevelChange = (val: string) => { + setBevelStrength(val); + const parsed = parseFloat(val); + if (!isNaN(parsed) && floor) { + const updatedFloor = updateFloor(floor.floorUuid, { bevelStrength: parsed }); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + } + }; + + const handleIsBeveledToggle = () => { + setIsBeveled(!isBeveled); + if (!floor) return; + const updatedFloor = updateFloor(floor.floorUuid, { isBeveled: !floor.isBeveled }); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + + }; + + const handleSelectMaterial = (material: { textureId: string; textureName: string }) => { + if (!floor) return; + const key = activeSurface === "top" ? "topMaterial" : "sideMaterial"; + const updatedFloor = updateFloor(floor.floorUuid, { [key]: material.textureId }); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + + }; + + if (!floor) return null; + + const selectedMaterials = { + top: materials.find((m) => m.textureId === floor.topMaterial) ?? materials[0], + side: materials.find((m) => m.textureId === floor.sideMaterial) ?? materials[0], + }; + + return ( +
+
+
Floor
+
+ + + +
+
+ +
+
+
Materials
+
+ +
+
+ {(["top", "side"] as const).map((surface) => ( + + ))} +
+ +
+ {selectedMaterials[activeSurface].textureName} +
+
+ +
+
+ {materials.map((material, index) => { + const isSelected = selectedMaterials[activeSurface].textureId === material.textureId; + return ( + + ); + })} +
+
+
+
+ ); +}; + +export default SelectedFloorProperties; diff --git a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx index b5099d5..517927c 100644 --- a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; import defaultTexture from '../../../../assets/textures/floor/wall-tex.png'; @@ -8,11 +8,14 @@ import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; import { useSceneContext } from "../../../../modules/scene/sceneContext"; import { useVersionContext } from "../../../../modules/builder/version/versionContext"; import { useParams } from "react-router-dom"; -import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi"; import { getUserData } from "../../../../functions/getUserData"; import { useSocketStore } from "../../../../store/builder/store"; +// import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi"; + const SelectedWallProperties = () => { + const [height, setHeight] = useState(""); + const [thickness, setThickness] = useState(""); const { selectedWall } = useBuilderStore(); const { wallStore } = useSceneContext(); const { selectedVersionStore } = useVersionContext(); @@ -31,7 +34,15 @@ const SelectedWallProperties = () => { const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null; + useEffect(() => { + if (wall) { + setHeight(wall.wallHeight.toString()); + setThickness(wall.wallThickness.toString()); + } + }, [wall, selectedWall]); + const handleHeightChange = (val: string) => { + setHeight(val); const height = parseFloat(val); if (!isNaN(height) && wall) { const updatedWall = updateWall(wall.wallUuid, { wallHeight: height }); @@ -57,6 +68,7 @@ const SelectedWallProperties = () => { }; const handleThicknessChange = (val: string) => { + setThickness(val); const thickness = parseFloat(val); if (!isNaN(thickness) && wall) { const updatedWall = updateWall(wall.wallUuid, { wallThickness: thickness }); @@ -109,16 +121,8 @@ const SelectedWallProperties = () => { if (!wall) return null; const selectedMaterials = { - side1: { - texture: materials.find((material) => material.textureId === wall.insideMaterial)?.texture || 'Unknown', - textureId: materials.find((material) => material.textureId === wall.insideMaterial)?.textureId || 'Unknown', - textureName: materials.find((material) => material.textureId === wall.insideMaterial)?.textureName || 'Unknown' - }, - side2: { - texture: materials.find((material) => material.textureId === wall.outsideMaterial)?.texture || 'Unknown', - textureId: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureId || 'Unknown', - textureName: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureName || 'Unknown' - } + side1: materials.find((m) => m.textureId === wall.insideMaterial) ?? materials[0], + side2: materials.find((m) => m.textureId === wall.outsideMaterial) ?? materials[0] }; return ( @@ -128,12 +132,12 @@ const SelectedWallProperties = () => {
diff --git a/app/src/components/layout/sidebarRight/properties/WallProperties.tsx b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx index eb835f1..ae17c1f 100644 --- a/app/src/components/layout/sidebarRight/properties/WallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx @@ -10,163 +10,152 @@ import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; // Define Material type type Material = { - texture: string; - textureName: string; + texture: string; + textureId: string; + textureName: string; }; -// Default and initial materials -const defaultMaterial: Material = { - texture: defaultTexture, - textureName: "Default Material", -}; - -const initialMaterial: Material = { - texture: wallTexture1, - textureName: "Grunge Concrete Wall", -}; +const materials = [ + { texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" }, + { texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" } +]; const WallProperties = () => { - const { wallHeight, wallThickness, setWallHeight, setWallThickness } = useBuilderStore(); + const { wallHeight, wallThickness, insideMaterial, outsideMaterial, setWallHeight, setWallThickness } = useBuilderStore(); - const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1"); + const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1"); - const [materials, setMaterials] = useState([ - defaultMaterial, - initialMaterial, - ]); - - const [selectedMaterials, setSelectedMaterials] = useState<{ - side1: Material | null; - side2: Material | null; - }>({ - side1: null, - side2: null, - }); - - // Set default material initially for both sides - useEffect(() => { - setSelectedMaterials({ - side1: defaultMaterial, - side2: defaultMaterial, + const [selectedMaterials, setSelectedMaterials] = useState<{ + side1: Material | null; + side2: Material | null; + }>({ + side1: null, + side2: null, }); - }, []); - const handleHeightChange = (newValue: string) => { - setWallHeight(parseFloat(newValue)); - }; + useEffect(() => { + setSelectedMaterials({ + side1: materials.find((mat) => mat.textureId === outsideMaterial) || null, + side2: materials.find((mat) => mat.textureId === insideMaterial) || null, + }); + }, []); - const handleThicknessChange = (newValue: string) => { - setWallThickness(parseFloat(newValue)); - }; + const handleHeightChange = (newValue: string) => { + setWallHeight(parseFloat(newValue)); + }; - const handleSelectMaterial = (material: Material) => { - setSelectedMaterials((prev) => ({ - ...prev, - [activeSide]: material, - })); - }; + const handleThicknessChange = (newValue: string) => { + setWallThickness(parseFloat(newValue)); + }; - return ( -
-
-
Wall
-
- handleHeightChange(val)} - /> - handleThicknessChange(val)} - /> -
-
-
-
-
Materials
-
+ const handleSelectMaterial = (material: Material) => { + setSelectedMaterials((prev) => ({ + ...prev, + [activeSide]: material, + })); + }; -
-
- + return ( +
+
+
Wall
+
+ handleHeightChange(val)} + /> + handleThicknessChange(val)} + /> +
+
+
+
+
Materials
+
- -
+
+
+ -
- {selectedMaterials[activeSide] && ( - {selectedMaterials[activeSide]!.textureName} - )} -
-
- -
- {materials.length === 0 ? ( -
No materials added yet.
- ) : ( -
- {materials.map((material, index) => { - const isSelected = selectedMaterials[activeSide]?.texture === material.texture; - - return ( -
- - ); - })} -
- )} + +
+ {selectedMaterials[activeSide] && ( + {selectedMaterials[activeSide]!.textureName} + )} +
+
+ +
+ {materials.length === 0 ? ( +
No materials added yet.
+ ) : ( +
+ {materials.map((material, index) => { + const isSelected = selectedMaterials[activeSide]?.texture === material.texture; + + return ( + + ); + })} +
+ )} +
+
- - - ); + ); }; export default WallProperties; diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx index d4c27b6..bc09b68 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx @@ -78,7 +78,7 @@ function ArcAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx index 941fb7f..49bf666 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx @@ -65,7 +65,7 @@ function ArrowAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx index 5dc6ee7..8bc6fd5 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx @@ -68,7 +68,7 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx index 6d838de..af852e8 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx @@ -53,7 +53,7 @@ function CircleAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx index 0c3eb7f..bbdad90 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx @@ -66,7 +66,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx index f701fba..bf17d08 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx @@ -53,7 +53,7 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx index 23ea6e6..a3f8bdf 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx @@ -100,7 +100,7 @@ function JunctionAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx index ed78112..e9321b0 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx @@ -50,7 +50,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) { position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]} rotation={[Math.PI / 2, 0, 0]} userData={aisle} - onClick={handleClick} + onDoubleClick={handleClick} onPointerMissed={() => { setSelectedAisle(null); }} diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index b597ab3..2b923f8 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -26,7 +26,7 @@ const gltfLoaderWorker = new Worker( function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) { const { activeModule } = useModuleStore(); const { socket } = useSocketStore(); - const { controls, gl, pointer, camera, raycaster } = useThree(); + const { controls, gl, pointer, camera, raycaster, scene } = useThree(); const { setLoadingProgress } = useLoadingProgress(); const { assetStore, eventStore } = useSceneContext(); const { selectedVersionStore } = useVersionContext(); @@ -277,7 +277,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea pointer.x = (event.clientX / window.innerWidth) * 2 - 1; pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; - addAssetModel(raycaster, camera, pointer, floorGroup, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId); + addAssetModel(scene, raycaster, camera, pointer, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId); } }; diff --git a/app/src/modules/builder/asset/functions/addAssetModel.ts b/app/src/modules/builder/asset/functions/addAssetModel.ts index 2eaa744..3977fa7 100644 --- a/app/src/modules/builder/asset/functions/addAssetModel.ts +++ b/app/src/modules/builder/asset/functions/addAssetModel.ts @@ -10,489 +10,438 @@ import PointsCalculator from "../../../simulation/events/points/functions/points import { getUserData } from "../../../../functions/getUserData"; async function addAssetModel( - raycaster: THREE.Raycaster, - camera: THREE.Camera, - pointer: THREE.Vector2, - floorGroup: Types.RefGroup, - socket: Socket, - selectedItem: any, - setSelectedItem: any, - addEvent: (event: EventsSchema) => void, - addAsset: (asset: Asset) => void, - plane: Types.RefMesh, - selectedVersion?: Version | null, - projectId?: string, - userId?: string + scene: THREE.Scene, + raycaster: THREE.Raycaster, + camera: THREE.Camera, + pointer: THREE.Vector2, + socket: Socket, + selectedItem: any, + setSelectedItem: any, + addEvent: (event: EventsSchema) => void, + addAsset: (asset: Asset) => void, + plane: Types.RefMesh, + selectedVersion?: Version | null, + projectId?: string, + userId?: string ): Promise { - ////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage ////////// + ////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage ////////// - let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; + let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - try { - const loader = new GLTFLoader(); - const dracoLoader = new DRACOLoader(); + try { + const loader = new GLTFLoader(); + const dracoLoader = new DRACOLoader(); - dracoLoader.setDecoderPath( - "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/" - ); - loader.setDRACOLoader(dracoLoader); + dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"); + loader.setDRACOLoader(dracoLoader); - raycaster.setFromCamera(pointer, camera); - const floorIntersections = raycaster.intersectObjects( - floorGroup.current.children, - true - ); - const intersectedFloor = floorIntersections.find((intersect) => - intersect.object.name.includes("Floor") - ); + raycaster.setFromCamera(pointer, camera); + const wallFloorsGroup = scene.getObjectByName("Walls-Floors-Group") as Types.Group | null; + const floorsGroup = scene.getObjectByName("Floors-Group") as Types.Group | null; + const floorChildren = floorsGroup?.children ?? []; + const wallFloorChildren = wallFloorsGroup?.children ?? []; + const floorIntersections = raycaster.intersectObjects([...floorChildren, ...wallFloorChildren], true); + const intersectedFloor = floorIntersections.find((intersect) => intersect.object.name.includes("Floor")); - const planeIntersections = raycaster.intersectObject(plane.current!, true); - const intersectedPlane = planeIntersections[0]; + const planeIntersections = raycaster.intersectObject(plane.current!, true); + const intersectedPlane = planeIntersections[0]; - let intersectPoint: THREE.Vector3 | null = null; + let intersectPoint: THREE.Vector3 | null = null; - if (intersectedFloor && intersectedPlane) { - intersectPoint = - intersectedFloor.distance < intersectedPlane.distance - ? new THREE.Vector3( - intersectedFloor.point.x, - Math.round(intersectedFloor.point.y), - intersectedFloor.point.z - ) - : new THREE.Vector3( - intersectedPlane.point.x, - 0, - intersectedPlane.point.z - ); - } else if (intersectedFloor) { - intersectPoint = new THREE.Vector3( - intersectedFloor.point.x, - Math.round(intersectedFloor.point.y), - intersectedFloor.point.z - ); - } else if (intersectedPlane) { - intersectPoint = new THREE.Vector3( - intersectedPlane.point.x, - 0, - intersectedPlane.point.z - ); - } - - if (intersectPoint) { - if (intersectPoint.y < 0) { - intersectPoint = new THREE.Vector3( - intersectPoint.x, - 0, - intersectPoint.z - ); - } - const cachedModel = THREE.Cache.get(selectedItem.id); - if (cachedModel) { - handleModelLoad( - cachedModel, - intersectPoint!, - selectedItem, - addEvent, - addAsset, - socket, - selectedVersion?.versionId || '', - projectId, - userId - ); - return; - } else { - const cachedModelBlob = await retrieveGLTF(selectedItem.id); - if (cachedModelBlob) { - const blobUrl = URL.createObjectURL(cachedModelBlob); - loader.load(blobUrl, (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(selectedItem.id, gltf); - handleModelLoad( - gltf, - intersectPoint!, - selectedItem, - addEvent, - addAsset, - socket, - selectedVersion?.versionId || '', - projectId, - userId - ); - }); - } else { - loader.load( - `${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, - async (gltf) => { - const modelBlob = await fetch( - `${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}` - ).then((res) => res.blob()); - await storeGLTF(selectedItem.id, modelBlob); - THREE.Cache.add(selectedItem.id, gltf); - await handleModelLoad( - gltf, - intersectPoint!, - selectedItem, - addEvent, - addAsset, - socket, - selectedVersion?.versionId || '', - projectId, - userId - ); + if (intersectedFloor && intersectedPlane) { + // intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? + // new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z) + // : new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z); + if (intersectedFloor.distance < intersectedPlane.distance) { + if (intersectedFloor.object.userData.floorUuid) { + intersectPoint = new THREE.Vector3(intersectedFloor.point.x, intersectedFloor.object.userData.floorDepth, intersectedFloor.point.z); + } else { + intersectPoint = new THREE.Vector3(intersectedFloor.point.x, 0, intersectedFloor.point.z); + } + } else { + intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z); } - ); + } else if (intersectedFloor) { + intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z); + } else if (intersectedPlane) { + intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z); } - } + + if (intersectPoint) { + + if (intersectPoint.y < 0) { + intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z); + } + const cachedModel = THREE.Cache.get(selectedItem.id); + if (cachedModel) { + handleModelLoad(cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId); + return; + } else { + const cachedModelBlob = await retrieveGLTF(selectedItem.id); + if (cachedModelBlob) { + const blobUrl = URL.createObjectURL(cachedModelBlob); + loader.load(blobUrl, (gltf) => { + URL.revokeObjectURL(blobUrl); + THREE.Cache.remove(blobUrl); + THREE.Cache.add(selectedItem.id, gltf); + handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId); + }); + } else { + loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, + async (gltf) => { + const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob()); + await storeGLTF(selectedItem.id, modelBlob); + THREE.Cache.add(selectedItem.id, gltf); + await handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId); + } + ); + } + } + } + } catch (error) { + echo.error("Failed to add asset"); + } finally { + setSelectedItem({}); } - } catch (error) { - echo.error("Failed to add asset"); - } finally { - setSelectedItem({}); - } } async function handleModelLoad( - gltf: any, - intersectPoint: THREE.Vector3, - selectedItem: any, - addEvent: (event: EventsSchema) => void, - addAsset: (asset: Asset) => void, - socket: Socket, - versionId: string, - projectId?: string, - userId?: string + gltf: any, + intersectPoint: THREE.Vector3, + selectedItem: any, + addEvent: (event: EventsSchema) => void, + addAsset: (asset: Asset) => void, + socket: Socket, + versionId: string, + projectId?: string, + userId?: string ) { - const { organization } = getUserData(); - const model = gltf.scene.clone(); - model.userData = { - name: selectedItem.name, - modelId: selectedItem.id, - modelUuid: model.uuid, - }; - model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z); - model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap); - - model.traverse((child: any) => { - if (child) { - child.castShadow = true; - child.receiveShadow = true; - } - }); - - const newFloorItem: Asset = { - modelUuid: model.uuid, - modelName: selectedItem.name, - assetId: selectedItem.id, - position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], - rotation: [0, 0, 0], - isLocked: false, - isVisible: true, - isCollidable: false, - opacity: 1, - }; - - - // API - - // await setAssetsApi( - // organization, - // newFloorItem.modelUuid, - // newFloorItem.modelName, - // newFloorItem.assetId, - // newFloorItem.position, - // { x: 0, y: 0, z: 0 }, - // false, - // true, - // ); - - // SOCKET - - if (selectedItem.type) { - const data = PointsCalculator( - selectedItem.type, - gltf.scene.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const eventData: any = { - type: selectedItem.type, + const { organization } = getUserData(); + const model = gltf.scene.clone(); + model.userData = { + name: selectedItem.name, + modelId: selectedItem.id, + modelUuid: model.uuid, }; + model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z); + model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap); - if (selectedItem.type === "Conveyor") { - const ConveyorEvent: ConveyorEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - state: "idle", - type: "transfer", - speed: 1, - points: data.points.map((point: THREE.Vector3, index: number) => { - const triggers: TriggerSchema[] = []; - - if (data.points && index < data.points.length - 1) { - triggers.push({ - triggerUuid: THREE.MathUtils.generateUUID(), - triggerName: `Trigger 1`, - triggerType: "onComplete", - delay: 0, - triggeredAsset: { - triggeredModel: { - modelName: newFloorItem.modelName, - modelUuid: newFloorItem.modelUuid, - }, - triggeredPoint: { - pointName: `Point`, - pointUuid: "", - }, - triggeredAction: { - actionName: `Action 1`, - actionUuid: "", - }, - }, - }); - } - - return { - uuid: THREE.MathUtils.generateUUID(), - position: [point.x, point.y, point.z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action 1`, - actionType: "default", - material: "Default Material", - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: triggers, - }, - }; - }), - }; - - for (let i = 0; i < ConveyorEvent.points.length - 1; i++) { - const currentPoint = ConveyorEvent.points[i]; - const nextPoint = ConveyorEvent.points[i + 1]; - - if (currentPoint.action.triggers.length > 0) { - currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = - nextPoint.uuid; - currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = - nextPoint.action.actionUuid; + model.traverse((child: any) => { + if (child) { + child.castShadow = true; + child.receiveShadow = true; } - } - addEvent(ConveyorEvent); - eventData.points = ConveyorEvent.points.map((point) => ({ - uuid: point.uuid, - position: point.position, - rotation: point.rotation, - })); - } else if (selectedItem.type === "Vehicle") { - const vehicleEvent: VehicleEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - state: "idle", - type: "vehicle", - speed: 1, - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "travel", - unLoadDuration: 5, - loadCapacity: 1, - steeringAngle: 0, - pickUpPoint: null, - unLoadPoint: null, - triggers: [], - }, - }, - }; - addEvent(vehicleEvent); - eventData.point = { - uuid: vehicleEvent.point.uuid, - position: vehicleEvent.point.position, - rotation: vehicleEvent.point.rotation, - }; - } else if (selectedItem.type === "ArmBot") { - const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - state: "idle", - type: "roboticArm", - speed: 1, - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - actions: [ - { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "pickAndPlace", - process: { - startPoint: null, - endPoint: null, - }, - triggers: [], + }); + + const newFloorItem: Asset = { + modelUuid: model.uuid, + modelName: selectedItem.name, + assetId: selectedItem.id, + position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], + rotation: [0, 0, 0], + isLocked: false, + isVisible: true, + isCollidable: false, + opacity: 1, + }; + + + // API + + // await setAssetsApi( + // organization, + // newFloorItem.modelUuid, + // newFloorItem.modelName, + // newFloorItem.assetId, + // newFloorItem.position, + // { x: 0, y: 0, z: 0 }, + // false, + // true, + // ); + + // SOCKET + + if (selectedItem.type) { + const data = PointsCalculator( + selectedItem.type, + gltf.scene.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + const eventData: any = { type: selectedItem.type, }; + + if (selectedItem.type === "Conveyor") { + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + state: "idle", + type: "transfer", + speed: 1, + points: data.points.map((point: THREE.Vector3, index: number) => { + const triggers: TriggerSchema[] = []; + + if (data.points && index < data.points.length - 1) { + triggers.push({ + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `Trigger 1`, + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: newFloorItem.modelName, + modelUuid: newFloorItem.modelUuid, + }, + triggeredPoint: { + pointName: `Point`, + pointUuid: "", + }, + triggeredAction: { + actionName: `Action 1`, + actionUuid: "", + }, + }, + }); + } + + return { + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action 1`, + actionType: "default", + material: "Default Material", + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: triggers, + }, + }; + }), + }; + + for (let i = 0; i < ConveyorEvent.points.length - 1; i++) { + const currentPoint = ConveyorEvent.points[i]; + const nextPoint = ConveyorEvent.points[i + 1]; + + if (currentPoint.action.triggers.length > 0) { + currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid; + currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid; + } + } + addEvent(ConveyorEvent); + eventData.points = ConveyorEvent.points.map((point) => ({ + uuid: point.uuid, + position: point.position, + rotation: point.rotation, + })); + } else if (selectedItem.type === "Vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "travel", + unLoadDuration: 5, + loadCapacity: 1, + steeringAngle: 0, + pickUpPoint: null, + unLoadPoint: null, + triggers: [], + }, + }, + }; + addEvent(vehicleEvent); + eventData.point = { + uuid: vehicleEvent.point.uuid, + position: vehicleEvent.point.position, + rotation: vehicleEvent.point.rotation, + }; + } else if (selectedItem.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null, + }, + triggers: [], + }, + ], + }, + }; + addEvent(roboticArmEvent); + eventData.point = { + uuid: roboticArmEvent.point.uuid, + position: roboticArmEvent.point.position, + rotation: roboticArmEvent.point.rotation, + }; + } else if (selectedItem.type === "StaticMachine") { + const machineEvent: MachineEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + state: "idle", + type: "machine", + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "process", + processTime: 10, + swapMaterial: "Default Material", + triggers: [], + }, + }, + }; + addEvent(machineEvent); + eventData.point = { + uuid: machineEvent.point.uuid, + position: machineEvent.point.position, + rotation: machineEvent.point.rotation, + }; + } else if (selectedItem.type === "Storage") { + const storageEvent: StorageEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: newFloorItem.rotation, + state: "idle", + type: "storageUnit", + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "store", + storageCapacity: 10, + triggers: [], + }, + }, + }; + addEvent(storageEvent); + eventData.point = { + uuid: storageEvent.point.uuid, + position: storageEvent.point.position, + rotation: storageEvent.point.rotation, + }; + } + + const completeData = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + assetId: newFloorItem.assetId, + position: newFloorItem.position, + rotation: { + x: model.rotation.x, + y: model.rotation.y, + z: model.rotation.z, }, - ], - }, - }; - addEvent(roboticArmEvent); - eventData.point = { - uuid: roboticArmEvent.point.uuid, - position: roboticArmEvent.point.position, - rotation: roboticArmEvent.point.rotation, - }; - } else if (selectedItem.type === "StaticMachine") { - const machineEvent: MachineEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - state: "idle", - type: "machine", - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "process", - processTime: 10, - swapMaterial: "Default Material", - triggers: [], - }, - }, - }; - addEvent(machineEvent); - eventData.point = { - uuid: machineEvent.point.uuid, - position: machineEvent.point.position, - rotation: machineEvent.point.rotation, - }; - } else if (selectedItem.type === "Storage") { - const storageEvent: StorageEventSchema = { - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - position: newFloorItem.position, - rotation: newFloorItem.rotation, - state: "idle", - type: "storageUnit", - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "store", - storageCapacity: 10, - triggers: [], - }, - }, - }; - addEvent(storageEvent); - eventData.point = { - uuid: storageEvent.point.uuid, - position: storageEvent.point.position, - rotation: storageEvent.point.rotation, - }; + isLocked: false, + isVisible: true, + socketId: socket.id, + eventData: eventData, + versionId: versionId, + projectId: projectId, + userId: userId, + }; + + socket.emit("v1:model-asset:add", completeData); + + const asset: Asset = { + modelUuid: completeData.modelUuid, + modelName: completeData.modelName, + assetId: completeData.assetId, + position: completeData.position, + rotation: [ + completeData.rotation.x, + completeData.rotation.y, + completeData.rotation.z, + ] as [number, number, number], + isLocked: completeData.isLocked, + isCollidable: false, + isVisible: completeData.isVisible, + opacity: 1, + eventData: completeData.eventData, + }; + + addAsset(asset); + } else { + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + assetId: newFloorItem.assetId, + position: newFloorItem.position, + rotation: { + x: model.rotation.x, + y: model.rotation.y, + z: model.rotation.z, + }, + isLocked: false, + isVisible: true, + socketId: socket.id, + versionId: versionId, + projectId: projectId, + userId: userId, + }; + + socket.emit("v1:model-asset:add", data); + + const asset = { + modelUuid: data.modelUuid, + modelName: data.modelName, + assetId: data.assetId, + position: data.position, + rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [ + number, + number, + number + ], + isLocked: data.isLocked, + isCollidable: false, + isVisible: data.isVisible, + opacity: 1, + }; + + addAsset(asset); } - - const completeData = { - organization, - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - assetId: newFloorItem.assetId, - position: newFloorItem.position, - rotation: { - x: model.rotation.x, - y: model.rotation.y, - z: model.rotation.z, - }, - isLocked: false, - isVisible: true, - socketId: socket.id, - eventData: eventData, - versionId: versionId, - projectId: projectId, - userId: userId, - }; - - socket.emit("v1:model-asset:add", completeData); - - const asset: Asset = { - modelUuid: completeData.modelUuid, - modelName: completeData.modelName, - assetId: completeData.assetId, - position: completeData.position, - rotation: [ - completeData.rotation.x, - completeData.rotation.y, - completeData.rotation.z, - ] as [number, number, number], - isLocked: completeData.isLocked, - isCollidable: false, - isVisible: completeData.isVisible, - opacity: 1, - eventData: completeData.eventData, - }; - - addAsset(asset); - } else { - const data = { - organization, - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - assetId: newFloorItem.assetId, - position: newFloorItem.position, - rotation: { - x: model.rotation.x, - y: model.rotation.y, - z: model.rotation.z, - }, - isLocked: false, - isVisible: true, - socketId: socket.id, - versionId: versionId, - projectId: projectId, - userId: userId, - }; - - socket.emit("v1:model-asset:add", data); - - const asset = { - modelUuid: data.modelUuid, - modelName: data.modelName, - assetId: data.assetId, - position: data.position, - rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [ - number, - number, - number - ], - isLocked: data.isLocked, - isCollidable: false, - isVisible: data.isVisible, - opacity: 1, - }; - - addAsset(asset); - } } export default addAssetModel; diff --git a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx index ce82298..e5ed733 100644 --- a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx +++ b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx @@ -59,9 +59,9 @@ function FloorInstance({ floor }: { floor: Floor }) { receiveShadow name={`Floor-${floor.floorUuid}`} rotation={[Math.PI / 2, 0, 0]} - position={[0, floor.floorDepth, 0]} + position={[0, !floor.isBeveled ? floor.floorDepth : (floor.floorDepth - 0.1), 0]} userData={floor} - onClick={(e) => { + onDoubleClick={(e) => { if (!togglView && activeModule === 'builder') { if (e.object.userData.floorUuid) { setSelectedFloor(e.object); @@ -76,10 +76,14 @@ function FloorInstance({ floor }: { floor: Floor }) { }} > diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index a07e8f9..ff0e5ce 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -123,7 +123,7 @@ function Wall({ wall }: { readonly wall: Wall }) { rotation={[0, -angle, 0]} userData={wall} name={`WallReference_${wall.wallUuid}`} - onClick={(e) => { + onDoubleClick={(e) => { if (visible && !togglView && activeModule === 'builder') { if (e.object.userData.wallUuid) { setSelectedWall(e.object); diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx index 40c60cd..267c91f 100644 --- a/app/src/modules/builder/wall/Instances/wallInstances.tsx +++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx @@ -134,14 +134,15 @@ function Floor({ room }: { room: Point[] }) { if (!shape) return null; return ( - + - +
); } diff --git a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx index c3a6c66..b31ad82 100644 --- a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx +++ b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx @@ -12,8 +12,8 @@ import getClosestIntersection from '../../geomentries/lines/getClosestIntersecti import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceWall from './referenceWall'; -import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi'; -import { deleteWallApi } from '../../../../services/factoryBuilder/wall/deleteWallApi'; +// import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi'; +// import { deleteWallApi } from '../../../../services/factoryBuilder/wall/deleteWallApi'; function WallCreator() { const { scene, camera, raycaster, gl, pointer } = useThree(); diff --git a/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx b/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx index 4f2eb02..af654d6 100644 --- a/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx @@ -1,339 +1,208 @@ import React, { useRef, useState } from "react"; import { - Vector3, - Raycaster, - BufferGeometry, - LineBasicMaterial, - Line, - Mesh, - Group, + Vector3, + Raycaster, + BufferGeometry, + LineBasicMaterial, + Line, + Mesh, + Group, } from "three"; import { useThree, useFrame } from "@react-three/fiber"; import { Html } from "@react-three/drei"; interface DistanceFindingControlsProps { - boundingBoxRef: React.RefObject; - object: number; + boundingBoxRef: React.RefObject; + object: number; } +const material = new LineBasicMaterial({ color: "#d2baff" }); + +const DIRECTION_LABEL_MAP = { + textPosX: "textPosX", + textNegX: "textNegX", + textPosZ: "textPosZ", + textNegZ: "textNegZ", +} as const; + const DistanceFindingControls = ({ - boundingBoxRef, - object, + boundingBoxRef, + object, }: DistanceFindingControlsProps) => { - const { camera, scene } = useThree(); - const [labelValues, setLabelValues] = useState<{ - textPosX: any; - textNegX: any; - textPosZ: any; - textNegZ: any; - }>({ - textPosX: "", - textNegX: "", - textPosZ: "", - textNegZ: "", - }); + const { camera, scene } = useThree(); + const [labelValues, setLabelValues] = useState>({ + textPosX: "", + textNegX: "", + textPosZ: "", + textNegZ: "", + }); - // Refs for measurement lines - const line1 = useRef(null); - const line2 = useRef(null); - const line3 = useRef(null); - const line4 = useRef(null); - const line5 = useRef(null); - - // Refs for measurement text labels - const textPosX = useRef(null); - const textNegX = useRef(null); - const textPosZ = useRef(null); - const textNegZ = useRef(null); - const textPosY = useRef(null); - - // Store line geometries to avoid recreation - const lineGeometries = useRef({ - posX: new BufferGeometry(), - negX: new BufferGeometry(), - posZ: new BufferGeometry(), - negZ: new BufferGeometry(), - posY: new BufferGeometry(), - }); - - useFrame(() => { - if (!boundingBoxRef?.current) return; - - boundingBoxRef.current.geometry.computeBoundingBox(); - const bbox = boundingBoxRef.current.geometry.boundingBox; - - if (!bbox) return; - - const size = { - x: bbox.max.x - bbox.min.x, - y: bbox.max.y - bbox.min.y, - z: bbox.max.z - bbox.min.z, + const lineRefs = { + posX: useRef(null), + negX: useRef(null), + posZ: useRef(null), + negZ: useRef(null), + posY: useRef(null), }; - const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone(); + const textRefs = { + textPosX: useRef(null), + textNegX: useRef(null), + textPosZ: useRef(null), + textNegZ: useRef(null), + textPosY: useRef(null), + }; - if (!vec) return; - updateLine({ - line: line1.current, - geometry: lineGeometries.current.posX, - direction: new Vector3(1, 0, 0), // Positive X - angle: "pos", - mesh: textPosX, - vec, - size, + const lineGeometries = useRef({ + posX: new BufferGeometry(), + negX: new BufferGeometry(), + posZ: new BufferGeometry(), + negZ: new BufferGeometry(), + posY: new BufferGeometry(), }); - updateLine({ - line: line2.current, - geometry: lineGeometries.current.negX, - direction: new Vector3(-1, 0, 0), // Negative X - angle: "neg", - mesh: textNegX, - vec, - size, + + useFrame(() => { + const bboxMesh = boundingBoxRef?.current; + if (!bboxMesh) return; + + bboxMesh.geometry.computeBoundingBox(); + const bbox = bboxMesh.geometry.boundingBox; + if (!bbox) return; + + const size = { + x: bbox.max.x - bbox.min.x, + y: bbox.max.y - bbox.min.y, + z: bbox.max.z - bbox.min.z, + }; + + const center = bboxMesh.getWorldPosition(new Vector3()).clone(); + if (!center) return; + + updateLine("posX", new Vector3(1, 0, 0), "pos", size, center); + updateLine("negX", new Vector3(-1, 0, 0), "neg", size, center); + updateLine("posZ", new Vector3(0, 0, 1), "pos", size, center); + updateLine("negZ", new Vector3(0, 0, -1), "neg", size, center); + updateLine("posY", new Vector3(0, -1, 0), "posY", size, center); }); - updateLine({ - line: line3.current, - geometry: lineGeometries.current.posZ, - direction: new Vector3(0, 0, 1), // Positive Z - angle: "pos", - mesh: textPosZ, - vec, - size, - }); - updateLine({ - line: line4.current, - geometry: lineGeometries.current.negZ, - direction: new Vector3(0, 0, -1), // Negative Z - angle: "neg", - mesh: textNegZ, - vec, - size, - }); - updateLine({ - line: line5.current, - geometry: lineGeometries.current.posY, - direction: new Vector3(0, -1, 0), // Down (Y) - angle: "posY", - mesh: textPosY, - vec, - size, - }); - }); - const updateLine = ({ - line, - geometry, - direction, - angle, - mesh, - vec, - size, - }: { - line: Line | null; - geometry: BufferGeometry; - direction: Vector3; - angle: string; - mesh: React.RefObject; - vec: Vector3; - size: { x: number; y: number; z: number }; - }) => { - if (!line) return; + const updateLine = ( + key: keyof typeof lineRefs, + direction: Vector3, + angle: string, + size: { x: number; y: number; z: number }, + origin: Vector3 + ) => { + const line = lineRefs[key].current; + const geometry = lineGeometries.current[key]; + const mesh = textRefs[`text${key[0].toUpperCase() + key.slice(1)}` as keyof typeof textRefs]; - const points = []; + if (!line) return; - if (angle === "pos") { - points[0] = new Vector3(vec.x, vec.y, vec.z).add( - new Vector3((direction.x * size.x) / 2, 0, (direction.z * size.z) / 2) - ); - } else if (angle === "neg") { - points[0] = new Vector3(vec.x, vec.y, vec.z).sub( - new Vector3((-direction.x * size.x) / 2, 0, (-direction.z * size.z) / 2) - ); - } else if (angle === "posY") { - points[0] = new Vector3(vec.x, vec.y, vec.z).sub( - new Vector3(0, size.y / 2, 0) - ); - } + const points: Vector3[] = []; + const halfSize = new Vector3(size.x / 2, size.y / 2, size.z / 2); - const ray = new Raycaster(); - if (camera) ray.camera = camera; - ray.set(new Vector3(vec.x, vec.y, vec.z), direction); - ray.params.Line.threshold = 0.1; + if (angle === "pos") { + points[0] = origin.clone().add(direction.clone().multiply(halfSize)); + } else if (angle === "neg") { + points[0] = origin.clone().sub(direction.clone().multiply(halfSize)); + } else if (angle === "posY") { + points[0] = origin.clone().sub(new Vector3(0, size.y / 2, 0)); + } - // Find intersection points - const wallsGroup = scene.children.find((val) => - val?.name.includes("Walls") + const ray = new Raycaster(); + ray.camera = camera; + ray.set(origin, direction); + ray.params.Line.threshold = 0.1; + + const wallsGroup = scene.children.find((val) => + val?.name.includes("Walls") + ); + const intersects = wallsGroup + ? ray.intersectObjects([wallsGroup], true) + : []; + + const intersect = intersects.find((i) => + i.object.name.includes("Wall") + ); + + if (intersect) { + points[1] = angle !== "posY" ? intersect.point : new Vector3(origin.x, 0, origin.z); + } + + if (points[1]) { + geometry.dispose(); + geometry.setFromPoints(points); + line.geometry = geometry; + + const distance = points[0].distanceTo(points[1]).toFixed(2); + + if (mesh?.current) { + geometry.computeBoundingSphere(); + mesh.current.position.copy(geometry.boundingSphere!.center); + + const labelEl = document.getElementById(mesh.current.name); + if (labelEl) { + labelEl.innerText = `${distance}m`; + + if (DIRECTION_LABEL_MAP[labelEl.id as keyof typeof DIRECTION_LABEL_MAP]) { + setLabelValues((prev) => ({ + ...prev, + [labelEl.id]: distance, + })); + } + } + } + } else { + geometry.dispose(); + geometry.setFromPoints([new Vector3(), new Vector3()]); + line.geometry = geometry; + + const labelEl = document.getElementById(mesh?.current?.name ?? ""); + if (labelEl && DIRECTION_LABEL_MAP[labelEl.id as keyof typeof DIRECTION_LABEL_MAP]) { + labelEl.innerText = ""; + setLabelValues((prev) => ({ + ...prev, + [labelEl.id]: "", + })); + } + } + }; + + const renderLabel = (id: keyof typeof textRefs) => ( + + +
{labelValues[id]}
+ +
); - const intersects = wallsGroup - ? ray.intersectObjects([wallsGroup], true) - : []; - // Find intersection point - if (intersects[0]) { - for (const intersect of intersects) { - if (intersect.object.name.includes("Wall")) { - points[1] = - angle !== "posY" ? intersect.point : new Vector3(vec.x, 0, vec.z); // Floor - break; - } - } - } - if (points[1]) { - geometry.dispose(); - geometry.setFromPoints([points[0], points[1]]); - line.geometry = geometry; - - // Calculate the distance only once - const distance = points[0].distanceTo(points[1]).toFixed(2); - - // Update measurement text - if (mesh?.current) { - geometry.computeBoundingSphere(); - const center = geometry.boundingSphere?.center; - if (center) { - mesh.current.position.copy(center); - } - - const label = document.getElementById(mesh.current.name); - if (label) { - label.innerText = `${distance}m`; - - // Update specific label state based on the label ID - switch (label.id) { - case "textPosX": - setLabelValues((prevState) => ({ ...prevState, textPosX: distance })); - break; - case "textNegX": - setLabelValues((prevState) => ({ ...prevState, textNegX: distance })); - break; - case "textPosZ": - setLabelValues((prevState) => ({ ...prevState, textPosZ: distance })); - break; - case "textNegZ": - setLabelValues((prevState) => ({ ...prevState, textNegZ: distance })); - break; - default: - break; - } - } - } - } else { - // No intersection found - clear the line - geometry.dispose(); - geometry.setFromPoints([new Vector3(), new Vector3()]); - line.geometry = geometry; - - const label = document.getElementById(mesh?.current?.name ?? ""); - if (label) { - label.innerText = ""; - - // Clear the corresponding label value in the state - switch (label.id) { - case "textPosX": - setLabelValues((prevState) => ({ ...prevState, textPosX: "" })); - break; - case "textNegX": - setLabelValues((prevState) => ({ ...prevState, textNegX: "" })); - break; - case "textPosZ": - setLabelValues((prevState) => ({ ...prevState, textPosZ: "" })); - break; - case "textNegZ": - setLabelValues((prevState) => ({ ...prevState, textNegZ: "" })); - break; - default: - break; - } - } - } - - }; - - const Material = new LineBasicMaterial({ color: "#d2baff" }); - - return ( - <> - {/* Measurement text labels */} - {boundingBoxRef.current && object > 0 && ( + return ( <> - - -
{labelValues.textPosX}
- -
+ {boundingBoxRef.current && object > 0 && ( + + {renderLabel("textPosX")} + {renderLabel("textNegX")} + {renderLabel("textPosZ")} + {renderLabel("textNegZ")} - - -
{labelValues.textNegX}
- -
- - - -
{labelValues.textPosZ}
- -
- - - -
{labelValues.textNegZ}
- -
- - {/* Measurement lines */} - - - - + + + + +
+ )} - ) - } - - ); + ); }; export default DistanceFindingControls; diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index 8e240c1..e7a60ca 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -55,7 +55,7 @@ interface BuilderState { // Setters - Floor setSelectedFloor: (floor: Object3D | null) => void; setFloorDepth: (depth: number) => void; - setBeveled: (isBeveled: boolean) => void; + setIsBeveled: (isBeveled: boolean) => void; setBevelStrength: (strength: number) => void; setFloorMaterial: (material: string, side: 'side' | 'top') => void; @@ -99,7 +99,7 @@ export const useBuilderStore = create()( selectedFloor: null, floorDepth: 0.1, isBeveled: false, - bevelStrength: 0.05, + bevelStrength: 5, sideMaterial: 'Material 1', topMaterial: 'Default Material', @@ -182,7 +182,7 @@ export const useBuilderStore = create()( }); }, - setBeveled: (isBeveled: boolean) => { + setIsBeveled: (isBeveled: boolean) => { set((state) => { state.isBeveled = isBeveled; }); diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index 7d425eb..77dc152 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -5,7 +5,7 @@ interface FloorStore { floors: Floor[]; setFloors: (floors: Floor[]) => void; addFloor: (floor: Floor) => void; - updateFloor: (uuid: string, updated: Partial) => void; + updateFloor: (uuid: string, updated: Partial) => Floor | undefined; removeFloor: (uuid: string) => void; removePoint: (pointUuid: string) => { removedFloors: Floor[], updatedFloors: Floor[] }; removeFloorByPoints: (Points: [Point, Point]) => { removedFloors: Floor[], updatedFloors: Floor[] }; @@ -45,12 +45,17 @@ export const createFloorStore = () => { state.floors.push(floor); }), - updateFloor: (uuid, updated) => set(state => { - const floor = state.floors.find(f => f.floorUuid === uuid); - if (floor) { - Object.assign(floor, updated); - } - }), + updateFloor: (uuid, updated) => { + let updatedFloor: Floor | undefined; + set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + Object.assign(floor, updated); + updatedFloor = JSON.parse(JSON.stringify(floor)); + } + }); + return updatedFloor; + }, removeFloor: (uuid) => set(state => { state.floors = state.floors.filter(f => f.floorUuid !== uuid); From edf76fa1c9064df596faf307048f6116ef5ac235 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 15:46:06 +0530 Subject: [PATCH 06/18] Fix bounding box position calculations and update distance finding controls for accurate positioning based on geometry. Enhance move controls to correctly handle floor intersections and adjust object positioning accordingly. --- .../selectionControls/boundingBoxHelper.tsx | 4 ++-- .../distanceFindingControls.tsx | 10 +++++++++ .../selectionControls/moveControls.tsx | 21 ++++++++++++++++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx index 05b43c6..b30b03e 100644 --- a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx +++ b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx @@ -51,7 +51,7 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => return { points: getBoxLines(min, max), - position: [position.x, center.y, position.z], + position: [position.x, position.y, position.z], rotation: rotation.toArray(), size: size.toArray(), }; @@ -93,7 +93,7 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"} lineWidth={2.7} segments - position={[box.position[0], 0, box.position[2]]} + position={[box.position[0], box.position[1], box.position[2]]} quaternion={new THREE.Quaternion(...box.rotation)} /> 0 && ( {renderLabel("textPosX")} {renderLabel("textNegX")} diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index 70d32e9..e246081 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -165,10 +165,21 @@ function MoveControls({ if (movedObjects.length > 0) { const intersectionPoint = new THREE.Vector3(); raycaster.setFromCamera(pointer, camera); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + let point = raycaster.ray.intersectPlane(plane, intersectionPoint); + const floorsGroup = scene.getObjectByName("Floors-Group") as Types.Group | null; + const floorChildren = floorsGroup?.children ?? []; + const floorIntersections = raycaster.intersectObjects([...floorChildren], true); + const intersectedFloor = floorIntersections.find((intersect) => intersect.object.name.includes("Floor")); + + if (intersectedFloor && selectedAssets.length === 1) { + if (intersectedFloor.object.userData.floorUuid) { + point = new THREE.Vector3(intersectedFloor.point.x, intersectedFloor.object.userData.floorDepth, intersectedFloor.point.z); + } + } if (point) { let targetX = point.x; + let targetY = point.y; let targetZ = point.z; if (keyEvent === "Ctrl") { @@ -192,7 +203,7 @@ function MoveControls({ selectionGroup.current.position.lerp( new THREE.Vector3( targetX - (position.x - selectionGroup.current.position.x), - selectionGroup.current.position.y, + targetY - (position.y - selectionGroup.current.position.y), targetZ - (position.z - selectionGroup.current.position.z) ), moveSpeed @@ -230,9 +241,13 @@ function MoveControls({ movedObjects.forEach(async (obj: THREE.Object3D) => { if (obj && AssetGroup.current) { - const worldPosition = new THREE.Vector3(); + let worldPosition = new THREE.Vector3(); obj.getWorldPosition(worldPosition); + if (worldPosition.y < 0) { + worldPosition.y = 0; + } + selectionGroup.current.remove(obj); obj.position.copy(worldPosition); From 12f1dd17716fb4a07c1ea8dbff26837cb622165e Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 15:58:34 +0530 Subject: [PATCH 07/18] Refactor interaction handling: change click events to double-click for DecalInstance, FloorInstance, and Wall components. Prevent event propagation to ensure proper selection behavior. --- app/src/modules/builder/Decal/decalInstance.tsx | 3 ++- .../modules/builder/floor/Instances/Instance/floorInstance.tsx | 3 ++- app/src/modules/builder/wall/Instances/instance/wall.tsx | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/modules/builder/Decal/decalInstance.tsx b/app/src/modules/builder/Decal/decalInstance.tsx index 71dcd83..fa8be89 100644 --- a/app/src/modules/builder/Decal/decalInstance.tsx +++ b/app/src/modules/builder/Decal/decalInstance.tsx @@ -21,9 +21,10 @@ function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: De rotation={[0, 0, decal.decalRotation]} scale={[decal.decalScale, decal.decalScale, 0.01]} userData={decal} - onClick={(e) => { + onDoubleClick={(e) => { if (visible && !togglView && activeModule === 'builder') { if (e.object.userData.decalUuid) { + e.stopPropagation(); setSelectedDecal(e.object); setSelectedWall(null); setSelectedFloor(null); diff --git a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx index e5ed733..c6c8139 100644 --- a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx +++ b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx @@ -59,11 +59,12 @@ function FloorInstance({ floor }: { floor: Floor }) { receiveShadow name={`Floor-${floor.floorUuid}`} rotation={[Math.PI / 2, 0, 0]} - position={[0, !floor.isBeveled ? floor.floorDepth : (floor.floorDepth - 0.1), 0]} + position={[0, !floor.isBeveled ? (floor.floorDepth - 0.1) : (floor.floorDepth - 0.2), 0]} userData={floor} onDoubleClick={(e) => { if (!togglView && activeModule === 'builder') { if (e.object.userData.floorUuid) { + e.stopPropagation(); setSelectedFloor(e.object); setSelectedDecal(null); } diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index ff0e5ce..0498b5b 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -126,6 +126,7 @@ function Wall({ wall }: { readonly wall: Wall }) { onDoubleClick={(e) => { if (visible && !togglView && activeModule === 'builder') { if (e.object.userData.wallUuid) { + e.stopPropagation(); setSelectedWall(e.object); setSelectedDecal(null); From 540bb44e0cf6e40783213e25bbb55d4abceb24a5 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 16:01:58 +0530 Subject: [PATCH 08/18] Add floorName property to Floor interface and update related components for floor creation --- .../modules/builder/floor/floorCreator/floorCreator.tsx | 2 ++ .../modules/builder/floor/floorCreator/referenceFloor.tsx | 1 + app/src/store/builder/useFloorStore.ts | 8 ++++++++ app/src/store/builder/useZoneStore.ts | 8 ++++++++ app/src/types/builderTypes.d.ts | 1 + 5 files changed, 20 insertions(+) diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx index aaeb0f3..35ba59e 100644 --- a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -93,6 +93,7 @@ function FloorCreator() { if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) { const floor: Floor = { floorUuid: THREE.MathUtils.generateUUID(), + floorName: "Floor", points: tempPoints, topMaterial, sideMaterial, @@ -144,6 +145,7 @@ function FloorCreator() { if (tempPoints.length >= 3) { const floor: Floor = { floorUuid: THREE.MathUtils.generateUUID(), + floorName: "Floor", points: tempPoints, topMaterial, sideMaterial, diff --git a/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx index 6e40a1c..3c9d593 100644 --- a/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx +++ b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx @@ -66,6 +66,7 @@ function ReferenceFloor({ tempPoints }: Readonly) { setTempFloor({ floorUuid: 'temp-floor', + floorName: 'temp-floor', points: floorPoints, topMaterial: 'default', sideMaterial: 'default', diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index 77dc152..9f2d871 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -6,6 +6,7 @@ interface FloorStore { setFloors: (floors: Floor[]) => void; addFloor: (floor: Floor) => void; updateFloor: (uuid: string, updated: Partial) => Floor | undefined; + setFloorName: (uuid: string, name: string) => void; removeFloor: (uuid: string) => void; removePoint: (pointUuid: string) => { removedFloors: Floor[], updatedFloors: Floor[] }; removeFloorByPoints: (Points: [Point, Point]) => { removedFloors: Floor[], updatedFloors: Floor[] }; @@ -57,6 +58,13 @@ export const createFloorStore = () => { return updatedFloor; }, + setFloorName: (uuid, name) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.floorName = name; + } + }), + removeFloor: (uuid) => set(state => { state.floors = state.floors.filter(f => f.floorUuid !== uuid); }), diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts index ee3c736..3740c13 100644 --- a/app/src/store/builder/useZoneStore.ts +++ b/app/src/store/builder/useZoneStore.ts @@ -6,6 +6,7 @@ interface ZoneStore { setZones: (zones: Zone[]) => void; addZone: (zone: Zone) => void; updateZone: (uuid: string, updated: Partial) => void; + setZoneName: (uuid: string, name: string) => void; removeZone: (uuid: string) => void; removePointFromZones: (pointUuid: string) => void; clearZones: () => void; @@ -35,6 +36,13 @@ export const createZoneStore = () => { } }), + setZoneName: (uuid, name) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + zone.zoneName = name; + } + }), + removeZone: (uuid) => set(state => { state.zones = state.zones.filter(z => z.zoneUuid !== uuid); }), diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index bbc9b7b..c7eef96 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -113,6 +113,7 @@ type Walls = Wall[]; interface Floor { floorUuid: string; + floorName: string; points: Point[]; sideMaterial: string; topMaterial: string; From bfa4d7bbc69b440d7d5791ba0fc81781e4e8d4bc Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 16:10:53 +0530 Subject: [PATCH 09/18] Add Floor2DInstance component and integrate into FloorInstances for 2D floor rendering --- .../Instances/Instance/floor2DInstance.tsx | 51 +++++++++++++++++++ .../floor/Instances/floorInstances.tsx | 9 ++++ 2 files changed, 60 insertions(+) create mode 100644 app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx diff --git a/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx new file mode 100644 index 0000000..166b1de --- /dev/null +++ b/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx @@ -0,0 +1,51 @@ +import { useMemo } from 'react'; +import { DoubleSide, Shape, Vector2 } from 'three'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../types/world/worldConstants'; + +function Floor2DInstance({ floor }: { floor: Floor }) { + const savedTheme: string | null = localStorage.getItem("theme"); + + const shape = useMemo(() => { + const shape = new Shape(); + const points = floor.points.map(p => new Vector2(p.position[0], p.position[2])); + if (points.length < 3) return null; + shape.moveTo(points[0].x, points[0].y); + for (let i = 1; i < points.length; i++) { + shape.lineTo(points[i].x, points[i].y); + } + return shape; + }, [floor]); + + if (!shape) return null; + + return ( + + + + + + ); +} + +export default Floor2DInstance; \ No newline at end of file diff --git a/app/src/modules/builder/floor/Instances/floorInstances.tsx b/app/src/modules/builder/floor/Instances/floorInstances.tsx index a5969eb..a578800 100644 --- a/app/src/modules/builder/floor/Instances/floorInstances.tsx +++ b/app/src/modules/builder/floor/Instances/floorInstances.tsx @@ -6,6 +6,7 @@ import { useToggleView } from '../../../../store/builder/store'; import Line from '../../line/line'; import Point from '../../point/point'; import FloorInstance from './Instance/floorInstance'; +import Floor2DInstance from './Instance/floor2DInstance'; function FloorInstances() { const { floorStore } = useSceneContext(); @@ -69,6 +70,14 @@ function FloorInstances() { )} + {toggleView && floors.length > 0 && ( + + {floors.map((floor) => ( + + ))} + + )} + {toggleView && ( <> From 812a4f6aeff4a9ae05e11631fc69b4d2114c815a Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 16:54:38 +0530 Subject: [PATCH 10/18] Refactor wall creator and socket responses; update nav mesh components and remove unused pillar functions - Updated import path for getClosestIntersection in wallCreator.tsx - Cleaned up socketResponses.dev.tsx by removing unused imports and code, simplifying the component structure - Modified navMesh.tsx to remove lines prop and adjust NavMeshDetails accordingly - Refactored navMeshDetails.tsx to remove lines dependency in useEffect - Updated polygonGenerator.tsx to remove lines prop and commented out unused code - Added getClosestIntersection helper function for better modularity - Removed unused pillar-related functions and commented out code in addAndUpdateReferencePillar.ts, addPillar.ts, deletableHoveredPillar.ts, deletePillar.ts, and updateReferencePolesheight.ts --- .../modules/builder/Decal/decalInstance.tsx | 2 +- .../builder/IntialLoad/loadInitialLine.ts | 30 - .../builder/IntialLoad/loadInitialPoint.ts | 87 -- .../IntialLoad/loadInitialWallItems.ts | 190 ++-- app/src/modules/builder/asset/assetsGroup.tsx | 2 +- app/src/modules/builder/builder.tsx | 169 +--- app/src/modules/builder/dfx/LoadBlueprint.tsx | 82 +- .../dragControlDeclaration.ts | 100 -- .../eventFunctions/handleContextMenu.ts | 8 - .../builder/eventFunctions/handleMeshDown.ts | 61 -- .../eventFunctions/handleMeshMissed.ts | 34 - .../builder/functions/deletableLineOrPoint.ts | 87 -- app/src/modules/builder/functions/draw.ts | 93 -- .../geomentries/floors/addFloorToScene.ts | 62 -- .../geomentries/floors/drawOnlyFloor.ts | 275 ------ .../builder/geomentries/floors/loadFloor.ts | 50 - .../geomentries/floors/loadOnlyFloors.ts | 183 ---- .../geomentries/floors/updateFloorLines.ts | 24 - .../builder/geomentries/layers/deleteLayer.ts | 104 -- .../geomentries/layers/layer2DVisibility.ts | 35 - .../geomentries/lines/addLineToScene.ts | 24 - .../lines/createAndMoveReferenceLine.ts | 98 -- .../builder/geomentries/lines/deleteLine.ts | 92 -- .../lines/distanceText/distanceText.tsx | 226 ----- .../distanceText/referenceDistanceText.tsx | 71 -- .../builder/geomentries/lines/drawWall.ts | 218 ----- .../geomentries/lines/getRoomsFromLines.ts | 86 -- .../lineConvertions/arrayLineToObject.ts | 24 - .../lineConvertions/arrayLinesToObject.ts | 30 - .../lineConvertions/objectLineToArray.ts | 13 - .../lineConvertions/objectLinesToArray.ts | 20 - .../geomentries/lines/removeConnectedLines.ts | 66 -- .../geomentries/lines/removeReferenceLine.ts | 22 - .../builder/geomentries/lines/splitLine.ts | 153 --- .../geomentries/lines/updateDistanceText.ts | 42 - .../builder/geomentries/lines/updateLines.ts | 24 - .../geomentries/lines/updateLinesPositions.ts | 32 - .../lines/vectorizeLinesCurrent.ts | 18 - .../pillars/addAndUpdateReferencePillar.ts | 54 -- .../builder/geomentries/pillars/addPillar.ts | 24 - .../pillars/deletableHoveredPillar.ts | 34 - .../geomentries/pillars/deletePillar.ts | 21 - .../pillars/updateReferencePolesheight.ts | 40 - .../geomentries/points/addPointToScene.ts | 65 -- .../builder/geomentries/points/deletePoint.ts | 72 -- .../builder/geomentries/points/dragPoint.ts | 44 - .../geomentries/points/removeSoloPoint.ts | 37 - .../geomentries/roofs/addRoofToScene.ts | 32 - .../builder/geomentries/roofs/hideRoof.ts | 47 - .../builder/geomentries/walls/addWallItems.ts | 164 ---- .../geomentries/walls/deleteWallItems.ts | 62 -- .../builder/geomentries/walls/hideWalls.ts | 45 - .../builder/geomentries/walls/loadWalls.ts | 140 --- .../geomentries/zones/addZonesToScene.ts | 50 - .../builder/geomentries/zones/loadZones.ts | 19 - app/src/modules/builder/groups/floorGroup.tsx | 127 --- .../modules/builder/groups/floorPlanGroup.tsx | 191 ---- .../modules/builder/groups/wallItemsGroup.tsx | 516 +++++----- .../builder/groups/wallsAndWallItems.tsx | 142 +-- app/src/modules/builder/groups/wallsMesh.tsx | 150 +-- .../helpers}/getClosestIntersection.ts | 52 +- app/src/modules/builder/line/line.tsx | 4 +- .../pillars/addAndUpdateReferencePillar.ts | 54 ++ app/src/modules/builder/pillars/addPillar.ts | 24 + .../builder/pillars/deletableHoveredPillar.ts | 34 + .../modules/builder/pillars/deletePillar.ts | 21 + .../pillars/updateReferencePolesheight.ts | 40 + .../builder/wall/wallCreator/wallCreator.tsx | 2 +- .../socket/socketResponses.dev.tsx | 894 +----------------- .../simulation/vehicle/navMesh/navMesh.tsx | 10 +- .../vehicle/navMesh/navMeshDetails.tsx | 4 +- .../vehicle/navMesh/polygonGenerator.tsx | 17 +- 72 files changed, 752 insertions(+), 5417 deletions(-) delete mode 100644 app/src/modules/builder/IntialLoad/loadInitialLine.ts delete mode 100644 app/src/modules/builder/IntialLoad/loadInitialPoint.ts delete mode 100644 app/src/modules/builder/eventDeclaration/dragControlDeclaration.ts delete mode 100644 app/src/modules/builder/eventFunctions/handleContextMenu.ts delete mode 100644 app/src/modules/builder/eventFunctions/handleMeshDown.ts delete mode 100644 app/src/modules/builder/eventFunctions/handleMeshMissed.ts delete mode 100644 app/src/modules/builder/functions/deletableLineOrPoint.ts delete mode 100644 app/src/modules/builder/functions/draw.ts delete mode 100644 app/src/modules/builder/geomentries/floors/addFloorToScene.ts delete mode 100644 app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts delete mode 100644 app/src/modules/builder/geomentries/floors/loadFloor.ts delete mode 100644 app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts delete mode 100644 app/src/modules/builder/geomentries/floors/updateFloorLines.ts delete mode 100644 app/src/modules/builder/geomentries/layers/deleteLayer.ts delete mode 100644 app/src/modules/builder/geomentries/layers/layer2DVisibility.ts delete mode 100644 app/src/modules/builder/geomentries/lines/addLineToScene.ts delete mode 100644 app/src/modules/builder/geomentries/lines/createAndMoveReferenceLine.ts delete mode 100644 app/src/modules/builder/geomentries/lines/deleteLine.ts delete mode 100644 app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx delete mode 100644 app/src/modules/builder/geomentries/lines/distanceText/referenceDistanceText.tsx delete mode 100644 app/src/modules/builder/geomentries/lines/drawWall.ts delete mode 100644 app/src/modules/builder/geomentries/lines/getRoomsFromLines.ts delete mode 100644 app/src/modules/builder/geomentries/lines/lineConvertions/arrayLineToObject.ts delete mode 100644 app/src/modules/builder/geomentries/lines/lineConvertions/arrayLinesToObject.ts delete mode 100644 app/src/modules/builder/geomentries/lines/lineConvertions/objectLineToArray.ts delete mode 100644 app/src/modules/builder/geomentries/lines/lineConvertions/objectLinesToArray.ts delete mode 100644 app/src/modules/builder/geomentries/lines/removeConnectedLines.ts delete mode 100644 app/src/modules/builder/geomentries/lines/removeReferenceLine.ts delete mode 100644 app/src/modules/builder/geomentries/lines/splitLine.ts delete mode 100644 app/src/modules/builder/geomentries/lines/updateDistanceText.ts delete mode 100644 app/src/modules/builder/geomentries/lines/updateLines.ts delete mode 100644 app/src/modules/builder/geomentries/lines/updateLinesPositions.ts delete mode 100644 app/src/modules/builder/geomentries/lines/vectorizeLinesCurrent.ts delete mode 100644 app/src/modules/builder/geomentries/pillars/addAndUpdateReferencePillar.ts delete mode 100644 app/src/modules/builder/geomentries/pillars/addPillar.ts delete mode 100644 app/src/modules/builder/geomentries/pillars/deletableHoveredPillar.ts delete mode 100644 app/src/modules/builder/geomentries/pillars/deletePillar.ts delete mode 100644 app/src/modules/builder/geomentries/pillars/updateReferencePolesheight.ts delete mode 100644 app/src/modules/builder/geomentries/points/addPointToScene.ts delete mode 100644 app/src/modules/builder/geomentries/points/deletePoint.ts delete mode 100644 app/src/modules/builder/geomentries/points/dragPoint.ts delete mode 100644 app/src/modules/builder/geomentries/points/removeSoloPoint.ts delete mode 100644 app/src/modules/builder/geomentries/roofs/addRoofToScene.ts delete mode 100644 app/src/modules/builder/geomentries/roofs/hideRoof.ts delete mode 100644 app/src/modules/builder/geomentries/walls/addWallItems.ts delete mode 100644 app/src/modules/builder/geomentries/walls/deleteWallItems.ts delete mode 100644 app/src/modules/builder/geomentries/walls/hideWalls.ts delete mode 100644 app/src/modules/builder/geomentries/walls/loadWalls.ts delete mode 100644 app/src/modules/builder/geomentries/zones/addZonesToScene.ts delete mode 100644 app/src/modules/builder/geomentries/zones/loadZones.ts delete mode 100644 app/src/modules/builder/groups/floorGroup.tsx delete mode 100644 app/src/modules/builder/groups/floorPlanGroup.tsx rename app/src/modules/builder/{geomentries/lines => line/helpers}/getClosestIntersection.ts (96%) create mode 100644 app/src/modules/builder/pillars/addAndUpdateReferencePillar.ts create mode 100644 app/src/modules/builder/pillars/addPillar.ts create mode 100644 app/src/modules/builder/pillars/deletableHoveredPillar.ts create mode 100644 app/src/modules/builder/pillars/deletePillar.ts create mode 100644 app/src/modules/builder/pillars/updateReferencePolesheight.ts diff --git a/app/src/modules/builder/Decal/decalInstance.tsx b/app/src/modules/builder/Decal/decalInstance.tsx index fa8be89..dfdd622 100644 --- a/app/src/modules/builder/Decal/decalInstance.tsx +++ b/app/src/modules/builder/Decal/decalInstance.tsx @@ -21,7 +21,7 @@ function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: De rotation={[0, 0, decal.decalRotation]} scale={[decal.decalScale, decal.decalScale, 0.01]} userData={decal} - onDoubleClick={(e) => { + onClick={(e) => { if (visible && !togglView && activeModule === 'builder') { if (e.object.userData.decalUuid) { e.stopPropagation(); diff --git a/app/src/modules/builder/IntialLoad/loadInitialLine.ts b/app/src/modules/builder/IntialLoad/loadInitialLine.ts deleted file mode 100644 index f8c3132..0000000 --- a/app/src/modules/builder/IntialLoad/loadInitialLine.ts +++ /dev/null @@ -1,30 +0,0 @@ -import addLineToScene from '../../builder/geomentries/lines/addLineToScene'; -import * as CONSTANTS from '../../../types/world/worldConstants'; -import * as Types from "../../../types/world/worldTypes"; - -function loadInitialLine( - floorPlanGroupLine: Types.RefGroup, - lines: Types.RefLines -): void { - - if (!floorPlanGroupLine.current) return - - ////////// Load the Lines initially if there are any ////////// - - floorPlanGroupLine.current.children = []; - lines.current.forEach((line) => { - let colour; - if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName) { - colour = CONSTANTS.lineConfig.wallColor; - } else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName) { - colour = CONSTANTS.lineConfig.floorColor; - } else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName) { - colour = CONSTANTS.lineConfig.aisleColor; - } - if (colour) { - addLineToScene(line[0][0], line[1][0], colour, line, floorPlanGroupLine); - } - }); -} - -export default loadInitialLine; diff --git a/app/src/modules/builder/IntialLoad/loadInitialPoint.ts b/app/src/modules/builder/IntialLoad/loadInitialPoint.ts deleted file mode 100644 index 91db577..0000000 --- a/app/src/modules/builder/IntialLoad/loadInitialPoint.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as THREE from 'three'; - -import * as CONSTANTS from '../../../types/world/worldConstants'; -import * as Types from "../../../types/world/worldTypes"; - -////////// Load the Boxes initially if there are any ////////// - -function loadInitialPoint( - lines: Types.RefLines, - floorPlanGroupPoint: Types.RefGroup, - currentLayerPoint: Types.RefMeshArray, - dragPointControls: Types.RefDragControl -): void { - - if (!floorPlanGroupPoint.current) return - - floorPlanGroupPoint.current.children = []; - currentLayerPoint.current = []; - lines.current.forEach((line) => { - const colour = getPointColor(line[0][3]); - line.forEach((pointData) => { - const [point, id] = pointData; - - /////////// Check if a box with this id already exists ////////// - - const existingBox = floorPlanGroupPoint.current?.getObjectByProperty('uuid', id); - if (existingBox) { - return; - } - - const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale); - const material = new THREE.ShaderMaterial({ - uniforms: { - uOuterColor: { value: new THREE.Color(colour) }, // Blue color for the border - uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square - }, - vertexShader: ` - varying vec2 vUv; - - void main() { - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - } - `, - fragmentShader: ` - varying vec2 vUv; - uniform vec3 uOuterColor; - 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(uOuterColor, 1.0); // Blue border - } - } - `, - }); - const box = new THREE.Mesh(geometry, material); - box.name = "point"; - box.uuid = id; - box.userData = { type: line[0][3], color: colour }; - box.position.set(point.x, point.y, point.z); - currentLayerPoint.current.push(box); - - floorPlanGroupPoint.current?.add(box); - }); - }); - - function getPointColor(lineType: string | undefined): string { - switch (lineType) { - case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor; - case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor; - case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor; - default: return CONSTANTS.pointConfig.defaultOuterColor; - } - } - - if (dragPointControls.current) { - dragPointControls.current!.objects = currentLayerPoint.current; - } -} - -export default loadInitialPoint; diff --git a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts index ba82510..fd74916 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts @@ -1,110 +1,110 @@ -import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; -import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; -import * as THREE from "three"; -import * as Types from "../../../types/world/worldTypes"; -import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi"; -import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils"; -import { getUserData } from "../../../functions/getUserData"; +// import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; +// import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; +// import * as THREE from "three"; +// import * as Types from "../../../types/world/worldTypes"; +// import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi"; +// import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils"; +// import { getUserData } from "../../../functions/getUserData"; -async function loadInitialWallItems( - setWallItems: Types.setWallItemSetState, - projectId?: string, - versionId?: string -): Promise { - if (!projectId || !versionId) return; - try { - const { organization, email } = getUserData(); +// async function loadInitialWallItems( +// setWallItems: Types.setWallItemSetState, +// projectId?: string, +// versionId?: string +// ): Promise { +// if (!projectId || !versionId) return; +// try { +// const { organization, email } = getUserData(); - if (!email) { - console.error("No email found in localStorage"); - } +// if (!email) { +// console.error("No email found in localStorage"); +// } - const items = await getWallItems(organization, projectId, versionId); +// const items = await getWallItems(organization, projectId, versionId); - let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - if (!items || items.length === 0) { - localStorage.removeItem("WallItems"); - return; - } +// if (!items || items.length === 0) { +// localStorage.removeItem("WallItems"); +// return; +// } - localStorage.setItem("WallItems", JSON.stringify(items)); +// localStorage.setItem("WallItems", JSON.stringify(items)); - const loader = new GLTFLoader(); - const dracoLoader = new DRACOLoader(); - dracoLoader.setDecoderPath( - "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/" - ); - loader.setDRACOLoader(dracoLoader); +// 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); - const loadedWallItems = await Promise.all( - items.map(async (item: Types.WallItem) => { - // Check THREE.js cache first - const cachedModel = THREE.Cache.get(item.assetId!); - if (cachedModel) { - return processModel(cachedModel, item); - } +// const loadedWallItems = await Promise.all( +// items.map(async (item: Types.WallItem) => { +// // Check THREE.js cache first +// const cachedModel = THREE.Cache.get(item.assetId!); +// if (cachedModel) { +// return processModel(cachedModel, item); +// } - // Check IndexedDB cache - const cachedModelBlob = await retrieveGLTF(item.assetId!); - if (cachedModelBlob) { - const blobUrl = URL.createObjectURL(cachedModelBlob); - return new Promise((resolve) => { - loader.load(blobUrl, (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.add(item.assetId!, gltf); - resolve(processModel(gltf, item)); - }); - }); - } +// // Check IndexedDB cache +// const cachedModelBlob = await retrieveGLTF(item.assetId!); +// if (cachedModelBlob) { +// const blobUrl = URL.createObjectURL(cachedModelBlob); +// return new Promise((resolve) => { +// loader.load(blobUrl, (gltf) => { +// URL.revokeObjectURL(blobUrl); +// THREE.Cache.add(item.assetId!, gltf); +// resolve(processModel(gltf, item)); +// }); +// }); +// } - // Load from original URL if not cached - const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`; - return new Promise((resolve) => { - loader.load(modelUrl, async (gltf) => { - try { - // Cache the model - const modelBlob = await fetch(modelUrl).then((res) => res.blob()); - await storeGLTF(item.assetId!, modelBlob); - THREE.Cache.add(item.assetId!, gltf); - resolve(processModel(gltf, item)); - } catch (error) { - console.error("Failed to cache model:", error); - resolve(processModel(gltf, item)); - } - }); - }); - }) - ); +// // Load from original URL if not cached +// const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`; +// return new Promise((resolve) => { +// loader.load(modelUrl, async (gltf) => { +// try { +// // Cache the model +// const modelBlob = await fetch(modelUrl).then((res) => res.blob()); +// await storeGLTF(item.assetId!, modelBlob); +// THREE.Cache.add(item.assetId!, gltf); +// resolve(processModel(gltf, item)); +// } catch (error) { +// console.error("Failed to cache model:", error); +// resolve(processModel(gltf, item)); +// } +// }); +// }); +// }) +// ); - setWallItems(loadedWallItems); - } catch (error) { - console.error("Failed to load wall items:", error); - } -} +// setWallItems(loadedWallItems); +// } catch (error) { +// console.error("Failed to load wall items:", error); +// } +// } -function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem { - const model = gltf.scene.clone(); - model.uuid = item.modelUuid!; +// function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem { +// const model = gltf.scene.clone(); +// model.uuid = item.modelUuid!; - model.children[0]?.children?.forEach((child: THREE.Object3D) => { - if (child.name !== "CSG_REF") { - child.castShadow = true; - child.receiveShadow = true; - } - }); +// model.children[0]?.children?.forEach((child: THREE.Object3D) => { +// if (child.name !== "CSG_REF") { +// child.castShadow = true; +// child.receiveShadow = true; +// } +// }); - return { - type: item.type, - model: model, - modelName: item.modelName, - assetId: item.assetId, - scale: item.scale, - csgscale: item.csgscale, - csgposition: item.csgposition, - position: item.position, - quaternion: item.quaternion, - }; -} +// return { +// type: item.type, +// model: model, +// modelName: item.modelName, +// assetId: item.assetId, +// scale: item.scale, +// csgscale: item.csgscale, +// csgposition: item.csgposition, +// position: item.position, +// quaternion: item.quaternion, +// }; +// } -export default loadInitialWallItems; +// export default loadInitialWallItems; diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 2b923f8..72e8033 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -23,7 +23,7 @@ const gltfLoaderWorker = new Worker( ) ); -function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) { +function AssetsGroup({ plane }: { readonly plane: RefMesh }) { const { activeModule } = useModuleStore(); const { socket } = useSocketStore(); const { controls, gl, pointer, camera, raycaster, scene } = useThree(); diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index 9ad8bd2..66a3502 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -1,109 +1,62 @@ ////////// Three and React Three Fiber Imports ////////// import * as THREE from "three"; -import { useEffect, useRef, useState } from "react"; -import { useThree, useFrame } from "@react-three/fiber"; - -////////// Component Imports ////////// - -import DistanceText from "./geomentries/lines/distanceText/distanceText"; -import ReferenceDistanceText from "./geomentries/lines/distanceText/referenceDistanceText"; +import { useEffect, useRef } from "react"; +import { useThree } from "@react-three/fiber"; +import { Bvh } from "@react-three/drei"; ////////// Zustand State Imports ////////// import { useToggleView, - useActiveLayer, useWallVisibility, useRoofVisibility, useShadows, - useUpdateScene, - useWalls, useToolMode, - useRefTextUpdate, useRenderDistance, useLimitDistance, } from "../../store/builder/store"; ////////// 3D Function Imports ////////// -import loadWalls from "./geomentries/walls/loadWalls"; - import * as Types from "../../types/world/worldTypes"; import SocketResponses from "../collaboration/socket/socketResponses.dev"; -import FloorPlanGroup from "./groups/floorPlanGroup"; -// import FloorGroup from "./groups/floorGroup"; -import Draw from "./functions/draw"; -import WallsAndWallItems from "./groups/wallsAndWallItems"; import Ground from "../scene/environment/ground"; import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment"; -import Layer2DVisibility from "./geomentries/layers/layer2DVisibility"; import ZoneGroup from "./groups/zoneGroup"; import MeasurementTool from "../scene/tools/measurementTool"; import NavMesh from "../simulation/vehicle/navMesh/navMesh"; import CalculateAreaGroup from "./groups/calculateAreaGroup"; import LayoutImage from "./layout/layoutImage"; import AssetsGroup from "./asset/assetsGroup"; -import { Bvh } from "@react-three/drei"; import DxfFile from "./dfx/LoadBlueprint"; -import { useParams } from "react-router-dom"; import AislesGroup from "./aisle/aislesGroup"; import WallGroup from "./wall/wallGroup"; +import FloorGroup from "./floor/floorGroup"; +import { useParams } from "react-router-dom"; import { useBuilderStore } from "../../store/builder/useBuilderStore"; import { getUserData } from "../../functions/getUserData"; -import FloorGroup from "./floor/floorGroup"; 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 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. 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 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 floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. - 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 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 hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. - const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. - const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... - const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. - - const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item. - const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. const { toggleView } = useToggleView(); // State for toggling between 2D and 3D. - const { toolMode, setToolMode } = useToolMode(); + const { setToolMode } = useToolMode(); const { setRoofVisibility } = useRoofVisibility(); const { setWallVisibility } = useWallVisibility(); const { setShadows } = useShadows(); const { setRenderDistance } = useRenderDistance(); const { setLimitDistance } = useLimitDistance(); - const { setUpdateScene } = useUpdateScene(); - const { setWalls } = useWalls(); - const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); const { projectId } = useParams(); const { setHoveredPoint, setHoveredLine } = useBuilderStore(); const { userId, organization } = getUserData(); @@ -117,24 +70,11 @@ export default function Builder() { ////////// All Toggle's ////////// useEffect(() => { - setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); - if (toggleView) { - Layer2DVisibility( - activeLayer, - floorPlanGroup, - floorPlanGroupLine, - floorPlanGroupPoint, - currentLayerPoint, - dragPointControls - ); - } else { + if (!toggleView) { setHoveredLine(null); setHoveredPoint(null); state.gl.domElement.style.cursor = 'default'; setToolMode('cursor'); - loadWalls(lines, setWalls); - setUpdateScene(true); - line.current = []; } }, [toggleView]); @@ -153,60 +93,13 @@ export default function Builder() { fetchVisibility(); }, []); - ////////// UseFrame is Here ////////// - - useFrame(() => { - if (toolMode) { - Draw( - state, - plane, - cursorPosition, - floorPlanGroupPoint, - snappedPoint, - isSnapped, - isSnappedUUID, - line, - ispreSnapped, - floorPlanGroup, - ReferenceLineMesh, - LineCreated, - setRefTextUpdate, - Tube, - anglesnappedPoint, - isAngleSnapped, - toolMode - ); - } - }); - ////////// Return ////////// return ( <> - - {/* */} - - - - - - - + {/* - {/* */} - - - - + @@ -264,15 +123,9 @@ export default function Builder() { - + - + diff --git a/app/src/modules/builder/dfx/LoadBlueprint.tsx b/app/src/modules/builder/dfx/LoadBlueprint.tsx index 4e2425d..1a95268 100644 --- a/app/src/modules/builder/dfx/LoadBlueprint.tsx +++ b/app/src/modules/builder/dfx/LoadBlueprint.tsx @@ -1,40 +1,21 @@ import { useEffect, useRef } from 'react'; import { useDfxUpload, useSocketStore, useToggleView, useUpdateScene } from '../../../store/builder/store'; import { LineBasicMaterial, Line } from 'three'; -import loadInitialPoint from '../IntialLoad/loadInitialPoint'; -import loadInitialLine from '../IntialLoad/loadInitialLine'; import { TransformControls } from '@react-three/drei'; import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBlueprint'; import * as Types from '../../../types/world/worldTypes'; -import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject'; import { useParams } from 'react-router-dom'; import { getUserData } from '../../../functions/getUserData'; import { useVersionContext } from '../version/versionContext'; -// Interface defining the props for the DxfFile component -interface DxfFileProps { - lines: Types.RefLines; // Reference to lines in the DXF file - floorPlanGroupPoint: Types.RefGroup; // Reference to floor plan points group - dragPointControls: Types.RefDragControl; // Reference to drag controls - floorPlanGroupLine: Types.RefGroup; // Reference to floor plan lines group - currentLayerPoint: Types.RefMeshArray; // Reference to current layer points -} - /** * DxfFile component handles the rendering and manipulation of DXf file data in a 3D scene. * It processes the DXF data to create points and lines representing walls and allows * transformation controls for interactive editing. */ -const DxfFile = ({ - floorPlanGroupPoint, - currentLayerPoint, - dragPointControls, - floorPlanGroupLine, - lines, -}: DxfFileProps) => { +const DxfFile = () => { // State management hooks const { dfxuploaded, dfxWallGenerate, setObjValue, objValue } = useDfxUpload(); - const { setUpdateScene } = useUpdateScene(); const { toggleView } = useToggleView(); const { socket } = useSocketStore(); const { selectedVersionStore } = useVersionContext(); @@ -50,55 +31,34 @@ const DxfFile = ({ * Loads initial points and lines from the DXF data and updates the scene. */ useEffect(() => { - if ( - dfxWallGenerate && - dragPointControls && - floorPlanGroupPoint && - currentLayerPoint && - floorPlanGroupLine - ) { + if (dfxWallGenerate) { // Store generated lines in ref - lines.current.push(...dfxWallGenerate); - dfxWallGenerate.map((line: any) => { - const lineData = arrayLineToObject(line as Types.Line); + // lines.current.push(...dfxWallGenerate); + // dfxWallGenerate.map((line: any) => { + // const lineData = arrayLineToObject(line as Types.Line); - //REST + // //REST - // setLine(organization, lineData.layer!, lineData.line!, lineData.type!); + // // setLine(organization, lineData.layer!, lineData.line!, lineData.type!); - //SOCKET + // //SOCKET - const input = { - organization, - layer: lineData.layer, - line: lineData.line, - type: lineData.type, - socketId: socket.id, - versionId: selectedVersion?.versionId || '', - projectId, - userId - } + // const input = { + // organization, + // layer: lineData.layer, + // line: lineData.line, + // type: lineData.type, + // socketId: socket.id, + // versionId: selectedVersion?.versionId || '', + // projectId, + // userId + // } - console.log('input: ', input); - socket.emit('v1:Line:create', input); + // socket.emit('v1:Line:create', input); - }) - - // Load initial points and lines from DXF data - loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls); - loadInitialLine(floorPlanGroupLine, lines); - - // Trigger scene update - setUpdateScene(true); + // }) } - }, [ - lines, - floorPlanGroupLine, - floorPlanGroupPoint, - currentLayerPoint, - dragPointControls, - dfxWallGenerate, - ]); + }, [dfxWallGenerate]); /** * Handles transformation changes for individual lines. diff --git a/app/src/modules/builder/eventDeclaration/dragControlDeclaration.ts b/app/src/modules/builder/eventDeclaration/dragControlDeclaration.ts deleted file mode 100644 index 52a4e16..0000000 --- a/app/src/modules/builder/eventDeclaration/dragControlDeclaration.ts +++ /dev/null @@ -1,100 +0,0 @@ -import * as THREE from "three"; -import { DragControls } from "three/examples/jsm/controls/DragControls"; -import * as CONSTANTS from "../../../types/world/worldConstants"; -import DragPoint from "../geomentries/points/dragPoint"; - -import * as Types from "../../../types/world/worldTypes"; -// import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi'; -import { Socket } from "socket.io-client"; -import { getUserData } from "../../../functions/getUserData"; - -export default async function addDragControl( - dragPointControls: Types.RefDragControl, - currentLayerPoint: Types.RefMeshArray, - state: Types.ThreeState, - floorPlanGroupPoint: Types.RefGroup, - floorPlanGroupLine: Types.RefGroup, - lines: Types.RefLines, - onlyFloorlines: Types.RefOnlyFloorLines, - socket: Socket, - projectId?: string, - versionId?: string -) { - ////////// Dragging Point and also change the size to indicate during hover ////////// - - dragPointControls.current = new DragControls( - currentLayerPoint.current, - state.camera, - state.gl.domElement - ); - dragPointControls.current.enabled = false; - const { userId, organization, email } = getUserData(); - dragPointControls.current.addEventListener("drag", function (event) { - const object = event.object; - if (object.visible) { - (state.controls as any).enabled = false; - DragPoint( - event as any, - floorPlanGroupPoint, - floorPlanGroupLine, - state.scene, - lines, - onlyFloorlines - ); - } else { - (state.controls as any).enabled = true; - } - }); - - dragPointControls.current.addEventListener("dragstart", function (event) { }); - - dragPointControls.current.addEventListener("dragend", async function (event) { - if (!dragPointControls.current) return; - - //REST - - // await updatePoint( - // organization, - // { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z }, - // event.object.uuid, - // ) - - //SOCKET - - const data = { - organization, - position: { - x: event.object.position.x, - y: 0.01, - z: event.object.position.z, - }, - uuid: event.object.uuid, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - socket.emit("v1:Line:update", data); - - if (state.controls) { - (state.controls as any).enabled = true; - } - }); - - dragPointControls.current.addEventListener("hoveron", function (event: any) { - if ((event.object as Types.Mesh).name === "point") { - event.object.material.uniforms.uInnerColor.value.set( - event.object.userData.color - ); - } - }); - - dragPointControls.current.addEventListener("hoveroff", function (event: any) { - if ((event.object as Types.Mesh).name === "point") { - event.object.material.uniforms.uInnerColor.value.set( - new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) - ); - } - }); -} diff --git a/app/src/modules/builder/eventFunctions/handleContextMenu.ts b/app/src/modules/builder/eventFunctions/handleContextMenu.ts deleted file mode 100644 index 454f847..0000000 --- a/app/src/modules/builder/eventFunctions/handleContextMenu.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as Types from "../../../types/world/worldTypes"; - -export default function handleContextMenu( - menuVisible: Types.Boolean, - setMenuVisible: Types.BooleanState -): void { - // setMenuVisible(true) -} \ No newline at end of file diff --git a/app/src/modules/builder/eventFunctions/handleMeshDown.ts b/app/src/modules/builder/eventFunctions/handleMeshDown.ts deleted file mode 100644 index 9fb7839..0000000 --- a/app/src/modules/builder/eventFunctions/handleMeshDown.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../types/world/worldTypes"; - -function handleMeshDown( - event: Types.MeshEvent, - currentWallItem: Types.RefMesh, - setSelectedWallItem: Types.setSelectedWallItemSetState, - setSelectedItemsIndex: Types.setSelectedItemsIndexSetState, - wallItems: Types.wallItems, - toggleView: Types.Boolean -): void { - - ////////// To select which of the Wall item and CSG is selected to be dragged ////////// - - if (!toggleView) { - if (currentWallItem.current) { - currentWallItem.current.children.forEach((child) => { - if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") { - const material = (child as THREE.Mesh).material; - if (Array.isArray(material)) { - material.forEach(mat => { - if (mat instanceof THREE.MeshStandardMaterial) { - mat.emissive = new THREE.Color("black"); - } - }); - } else if (material instanceof THREE.MeshStandardMaterial) { - material.emissive = new THREE.Color("black"); - } - } - }); - currentWallItem.current = null; - setSelectedWallItem(null); - setSelectedItemsIndex(null); - } - - if (event.intersections.length > 0) { - if (event.object) { - const wallItemModel = event.object; - let currentObject = wallItemModel as THREE.Object3D; - while (currentObject) { - if (currentObject.name === "Scene") { - break; - } - currentObject = currentObject.parent as THREE.Object3D; - } - if (!currentObject) return; - const clickedIndex = wallItems.findIndex((item) => item.model?.uuid === currentObject.uuid); - if (clickedIndex !== -1) { - setSelectedItemsIndex(clickedIndex); - const wallItemModel = wallItems[clickedIndex]?.model; - if (wallItemModel) { - setSelectedWallItem(wallItemModel); - } - } - } - - } - } -} -export default handleMeshDown; diff --git a/app/src/modules/builder/eventFunctions/handleMeshMissed.ts b/app/src/modules/builder/eventFunctions/handleMeshMissed.ts deleted file mode 100644 index f374831..0000000 --- a/app/src/modules/builder/eventFunctions/handleMeshMissed.ts +++ /dev/null @@ -1,34 +0,0 @@ -import * as THREE from 'three'; -import * as Types from "../../../types/world/worldTypes"; - -function handleMeshMissed( - currentWallItem: Types.RefMesh, - setSelectedWallItem: Types.setSelectedWallItemSetState, - setSelectedItemsIndex: Types.setSelectedItemsIndexSetState -): void { - - ////////// If an item is selected and then clicked outside other than the selected object, this runs and removes the color of the selected object and sets setSelectedWallItem and setSelectedItemsIndex as null ////////// - - if (currentWallItem.current) { - currentWallItem.current.children.forEach((child) => { - if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") { - const material = (child as THREE.Mesh).material; - - if (Array.isArray(material)) { - material.forEach(mat => { - if (mat instanceof THREE.MeshStandardMaterial) { - mat.emissive = new THREE.Color("black"); - } - }); - } else if (material instanceof THREE.MeshStandardMaterial) { - material.emissive = new THREE.Color("black"); - } - } - }); - currentWallItem.current = null; - setSelectedWallItem(null); - setSelectedItemsIndex(null); - } -} - -export default handleMeshMissed; diff --git a/app/src/modules/builder/functions/deletableLineOrPoint.ts b/app/src/modules/builder/functions/deletableLineOrPoint.ts deleted file mode 100644 index cbca682..0000000 --- a/app/src/modules/builder/functions/deletableLineOrPoint.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as THREE from 'three'; -import * as CONSTANTS from '../../../types/world/worldConstants'; -import * as Types from "../../../types/world/worldTypes"; - -function DeletableLineorPoint( - state: Types.ThreeState, - plane: Types.RefMesh, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroupPoint: Types.RefGroup, - hoveredDeletableLine: Types.RefMesh, - hoveredDeletablePoint: Types.RefMesh -): void { - - ////////// Altering the color of the hovered line or point during the deletion time ////////// - - if (!plane.current) return; - let intersects = state.raycaster.intersectObject(plane.current, true); - - let visibleIntersectLines; - if (floorPlanGroupLine.current) { visibleIntersectLines = state.raycaster?.intersectObjects(floorPlanGroupLine.current.children, true); } - const visibleIntersectLine = visibleIntersectLines?.find(intersect => intersect.object.visible) as THREE.Line | undefined || null; - - let visibleIntersectPoints; - if (floorPlanGroupPoint.current) { - visibleIntersectPoints = state.raycaster?.intersectObjects(floorPlanGroupPoint.current.children, true); - } - const visibleIntersectPoint = visibleIntersectPoints?.find(intersect => intersect.object.visible) as THREE.Mesh | undefined; - - 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; - } - } - - if (intersects.length > 0) { - if (visibleIntersectPoint) { - if (hoveredDeletableLine.current) { - const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3]; - const color = getLineColor(lineType); - (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color); - hoveredDeletableLine.current = null; - } - - hoveredDeletablePoint.current = (visibleIntersectPoint as any).object; - (hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(new THREE.Color("red")); - (hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set(new THREE.Color("red")); - // (hoveredDeletablePoint.current as THREE.Mesh).scale.set(1.5, 1.5, 1.5); - } else if (hoveredDeletablePoint.current) { - (hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor); - (hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set((hoveredDeletablePoint.current as any).userData.color); - // hoveredDeletablePoint.current.scale.set(1, 1, 1); - hoveredDeletablePoint.current = null; - } - - if (visibleIntersectLine && !visibleIntersectPoint) { - if (hoveredDeletableLine.current) { - const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3]; - const color = getLineColor(lineType); - (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color); - hoveredDeletableLine.current = null; - } - - if (hoveredDeletablePoint.current) { - (hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor); - (hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set((hoveredDeletablePoint.current as any).userData.color); - // hoveredDeletablePoint.current.scale.set(1, 1, 1); - hoveredDeletablePoint.current = null; - } - - hoveredDeletableLine.current = (visibleIntersectLine as any).object; - if (hoveredDeletableLine.current) { - (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color("red"); - } - } else if (hoveredDeletableLine.current) { - const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3]; - const color = getLineColor(lineType); - (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color); - hoveredDeletableLine.current = null; - } - } - -} - -export default DeletableLineorPoint; diff --git a/app/src/modules/builder/functions/draw.ts b/app/src/modules/builder/functions/draw.ts deleted file mode 100644 index 425fbbb..0000000 --- a/app/src/modules/builder/functions/draw.ts +++ /dev/null @@ -1,93 +0,0 @@ -import * as Types from "../../../types/world/worldTypes"; -import * as CONSTANTS from '../../../types/world/worldConstants'; -import createAndMoveReferenceLine from "../geomentries/lines/createAndMoveReferenceLine"; - -async function Draw( - state: Types.ThreeState, - plane: Types.RefMesh, - cursorPosition: Types.Vector3, - floorPlanGroupPoint: Types.RefGroup, - snappedPoint: Types.RefVector3, - isSnapped: Types.RefBoolean, - isSnappedUUID: Types.RefString, - line: Types.RefLine, - ispreSnapped: Types.RefBoolean, - floorPlanGroup: Types.RefGroup, - ReferenceLineMesh: Types.RefMesh, - LineCreated: Types.RefBoolean, - setRefTextUpdate: any, - Tube: Types.RefTubeGeometry, - anglesnappedPoint: Types.RefVector3, - isAngleSnapped: Types.RefBoolean, - toolMode: Types.String, -): Promise { - - ////////// Snapping the cursor during the drawing time and also changing the color of the intersected lines ////////// - - if (!plane.current) return; - const intersects = state.raycaster.intersectObject(plane.current, true); - - if (intersects.length > 0 && (toolMode === "Wall" || toolMode === "Floor")) { - const intersectionPoint = intersects[0].point; - cursorPosition.copy(intersectionPoint); - const snapThreshold = 1; - - if (line.current.length === 0) { - for (const point of floorPlanGroupPoint.current.children) { - const pointType = point.userData.type; - - const canSnap = - ((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) || - ((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) - - if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold + 0.5 && point.visible) { - cursorPosition.copy(point.position); - snappedPoint.current = point.position; - ispreSnapped.current = true; - isSnapped.current = false; - isSnappedUUID.current = point.uuid; - break; - } else { - ispreSnapped.current = false; - } - } - } else if (line.current.length > 0 && line.current[0]) { - for (const point of floorPlanGroupPoint.current.children) { - const pointType = point.userData.type; - - let canSnap = - ((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) || - ((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) - - if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold && point.visible) { - cursorPosition.copy(point.position); - snappedPoint.current = point.position; - isSnapped.current = true; - ispreSnapped.current = false; - isSnappedUUID.current = point.uuid; - break; - } else { - isSnapped.current = false; - } - } - - createAndMoveReferenceLine( - line.current[0][0], - cursorPosition, - isSnapped, - ispreSnapped, - line, - setRefTextUpdate, - floorPlanGroup, - ReferenceLineMesh, - LineCreated, - Tube, - anglesnappedPoint, - isAngleSnapped - ); - } - } - -} - -export default Draw; \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/floors/addFloorToScene.ts b/app/src/modules/builder/geomentries/floors/addFloorToScene.ts deleted file mode 100644 index 71f2d24..0000000 --- a/app/src/modules/builder/geomentries/floors/addFloorToScene.ts +++ /dev/null @@ -1,62 +0,0 @@ -import * as THREE from 'three'; -import * as Types from "../../../../types/world/worldTypes"; -import * as CONSTANTS from "../../../../types/world/worldConstants"; - -import texturePath from "../../../../assets/textures/floor/white.png"; -import texturePathDark from "../../../../assets/textures/floor/black.png"; - -// Cache for materials -const materialCache = new Map(); - -export default function addFloorToScene( - shape: THREE.Shape, - layer: number, - floorGroup: Types.RefGroup, - userData: any, -) { - const savedTheme: string | null = localStorage.getItem('theme'); - - const textureLoader = new THREE.TextureLoader(); - - const textureScale = CONSTANTS.floorConfig.textureScale; - - const materialKey = `floorMaterial_${textureScale}`; - - let material: THREE.Material; - - if (materialCache.has(materialKey)) { - material = materialCache.get(materialKey) as THREE.Material; - } else { - const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath); - // const floorTexture = textureLoader.load(texturePath); - - floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping; - floorTexture.repeat.set(textureScale, textureScale); - floorTexture.colorSpace = THREE.SRGBColorSpace; - - material = new THREE.MeshStandardMaterial({ - map: floorTexture, - side: THREE.DoubleSide, - }); - - materialCache.set(materialKey, material); - } - - const extrudeSettings = { - depth: CONSTANTS.floorConfig.height, - bevelEnabled: false, - }; - - const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); - const mesh = new THREE.Mesh(geometry, material); - - mesh.receiveShadow = true; - mesh.position.y = (layer) * CONSTANTS.wallConfig.height; - mesh.rotateX(Math.PI / 2); - mesh.name = `Floor_Layer_${layer}`; - - // Store UUIDs for debugging or future processing - mesh.userData.uuids = userData; - - floorGroup.current.add(mesh); -} diff --git a/app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts b/app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts deleted file mode 100644 index 74b06ef..0000000 --- a/app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts +++ /dev/null @@ -1,275 +0,0 @@ -import * as THREE from "three"; - -import * as Types from "../../../../types/world/worldTypes"; -import * as CONSTANTS from "../../../../types/world/worldConstants"; - -import addPointToScene from "../points/addPointToScene"; -import addLineToScene from "../lines/addLineToScene"; -import splitLine from "../lines/splitLine"; -import removeReferenceLine from "../lines/removeReferenceLine"; -import getClosestIntersection from "../lines/getClosestIntersection"; -import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject"; -// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi'; -import { Socket } from "socket.io-client"; -import { getUserData } from "../../../../functions/getUserData"; - -async function drawOnlyFloor( - raycaster: THREE.Raycaster, - state: Types.ThreeState, - camera: THREE.Camera, - plane: Types.RefMesh, - floorPlanGroupPoint: Types.RefGroup, - snappedPoint: Types.RefVector3, - isSnapped: Types.RefBoolean, - isSnappedUUID: Types.RefString, - line: Types.RefLine, - ispreSnapped: Types.RefBoolean, - anglesnappedPoint: Types.RefVector3, - isAngleSnapped: Types.RefBoolean, - onlyFloorline: Types.RefOnlyFloorLine, - onlyFloorlines: Types.RefOnlyFloorLines, - lines: Types.RefLines, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroup: Types.RefGroup, - ReferenceLineMesh: Types.RefMesh, - LineCreated: Types.RefBoolean, - currentLayerPoint: Types.RefMeshArray, - dragPointControls: Types.RefDragControl, - setNewLines: any, - setDeletedLines: any, - activeLayer: Types.Number, - socket: Socket, - projectId?: string, - versionId?: string, -): Promise { - ////////// Creating lines Based on the positions clicked ////////// - - if (!plane.current) return; - const { userId, organization, email } = getUserData(); - const intersects = raycaster.intersectObject(plane.current, true); - const intersectsLines = raycaster.intersectObjects( - floorPlanGroupLine.current.children, - true - ); - const intersectsPoint = raycaster.intersectObjects( - floorPlanGroupPoint.current.children, - true - ); - const VisibleintersectsPoint = intersectsPoint.find( - (intersect) => intersect.object.visible - ); - const visibleIntersect = intersectsLines.find( - (intersect) => - intersect.object.visible && - intersect.object.name !== CONSTANTS.lineConfig.referenceName - ); - if ( - (intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && - intersectsLines.length > 0 && - !isSnapped.current && - !ispreSnapped.current - ) { - ////////// Clicked on a preexisting Line ////////// - - if ( - visibleIntersect && - (intersectsLines[0].object.userData.linePoints[0][3] === - CONSTANTS.lineConfig.floorName || - intersectsLines[0].object.userData.linePoints[0][3] === - CONSTANTS.lineConfig.wallName) - ) { - let pointColor, lineColor; - if ( - intersectsLines[0].object.userData.linePoints[0][3] === - CONSTANTS.lineConfig.wallName - ) { - pointColor = CONSTANTS.pointConfig.wallOuterColor; - lineColor = CONSTANTS.lineConfig.wallColor; - } else { - pointColor = CONSTANTS.pointConfig.floorOuterColor; - lineColor = CONSTANTS.lineConfig.floorColor; - } - let IntersectsPoint = new THREE.Vector3( - intersects[0].point.x, - 0.01, - intersects[0].point.z - ); - if ( - isAngleSnapped.current && - line.current.length > 0 && - anglesnappedPoint.current - ) { - IntersectsPoint = anglesnappedPoint.current; - } - if (visibleIntersect.object instanceof THREE.Mesh) { - const ThroughPoint = - visibleIntersect.object.geometry.parameters.path.getPoints( - CONSTANTS.lineConfig.lineIntersectionPoints - ); - let intersectionPoint = getClosestIntersection( - ThroughPoint, - IntersectsPoint - ); - - if (intersectionPoint) { - const newLines = splitLine( - visibleIntersect, - intersectionPoint, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - lines, - setDeletedLines, - floorPlanGroupLine, - socket, - pointColor, - lineColor, - intersectsLines[0].object.userData.linePoints[0][3], - projectId - ); - setNewLines([newLines[0], newLines[1]]); - - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.floorName, - ]); - - 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); - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - projectId, - versionId, - userId, - }; - - console.log('input: ', input); - socket.emit("v1:Line:create", input); - - setNewLines([newLines[0], newLines[1], line.current]); - onlyFloorline.current.push(line.current as Types.Line); - onlyFloorlines.current.push(onlyFloorline.current); - onlyFloorline.current = []; - - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.floorColor, - line.current, - floorPlanGroupLine - ); - - removeReferenceLine( - floorPlanGroup, - ReferenceLineMesh, - LineCreated, - line - ); - } - return; - } - } - } - } - if (intersects.length > 0 && intersectsLines.length === 0) { - ////////// Clicked on an empty place or a point ////////// - - let intersectionPoint = intersects[0].point; - - if ( - isAngleSnapped.current && - line.current.length > 0 && - anglesnappedPoint.current - ) { - intersectionPoint = anglesnappedPoint.current; - } - if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } - if (ispreSnapped.current && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } - - if (!isSnapped.current && !ispreSnapped.current) { - addPointToScene( - intersectionPoint, - CONSTANTS.pointConfig.floorOuterColor, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - CONSTANTS.lineConfig.floorName - ); - } else { - ispreSnapped.current = false; - isSnapped.current = false; - } - - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.floorName, - ]); - - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - onlyFloorline.current.push(line.current as Types.Line); - lines.current.push(line.current as Types.Line); - const data = arrayLineToObject(line.current as Types.Line); - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - console.log('input: ', input); - socket.emit("v1:Line:create", input); - - setNewLines([line.current]); - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.floorColor, - line.current, - floorPlanGroupLine - ); - const lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - if (isSnapped.current) { - ////////// Add this to stop the drawing mode after snapping ////////// - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - onlyFloorlines.current.push(onlyFloorline.current); - onlyFloorline.current = []; - } - } -} - -export default drawOnlyFloor; diff --git a/app/src/modules/builder/geomentries/floors/loadFloor.ts b/app/src/modules/builder/geomentries/floors/loadFloor.ts deleted file mode 100644 index d4f2fc1..0000000 --- a/app/src/modules/builder/geomentries/floors/loadFloor.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as THREE from 'three'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import addRoofToScene from '../roofs/addRoofToScene'; - -import * as Types from "../../../../types/world/worldTypes"; -import loadOnlyFloors from './loadOnlyFloors'; -import addFloorToScene from './addFloorToScene'; -import getRoomsFromLines from '../lines/getRoomsFromLines'; - -async function loadFloor( - lines: Types.RefLines, - floorGroup: Types.RefGroup, -): Promise { - - if (!floorGroup.current) return; - - floorGroup.current.children = []; - - if (lines.current.length > 2) { - const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => { - const layer = pair[0][2]; - if (!acc[layer]) acc[layer] = []; - acc[layer].push(pair); - return acc; - }, {}); - - for (const layer in linesByLayer) { - // Only Floor Polygons - loadOnlyFloors(floorGroup, linesByLayer, layer); - - const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] }); - - rooms.forEach(({ coordinates: room, layer }) => { - const userData = room.map(point => point.uuid); - const shape = new THREE.Shape(); - shape.moveTo(room[0].position.x, room[0].position.z); - room.forEach(point => shape.lineTo(point.position.x, point.position.z)); - shape.closePath(); - - // Floor Polygons - addFloorToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, floorGroup, userData); - - // Roof Polygons - addRoofToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, userData, floorGroup); - }); - } - } -} - -export default loadFloor; diff --git a/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts b/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts deleted file mode 100644 index 3da7b46..0000000 --- a/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts +++ /dev/null @@ -1,183 +0,0 @@ -import * as THREE from 'three'; -import * as turf from '@turf/turf'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import * as Types from "../../../../types/world/worldTypes"; - -function loadOnlyFloors( - floorGroup: Types.RefGroup, - linesByLayer: any, - layer: any, -): void { - - ////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well ////////// - - let floorsInLayer = linesByLayer[layer]; - floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName); - const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) => - pair.map((point) => ({ - position: [point[0].x, point[0].z], - uuid: point[1] - })) - ); - const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position))); - - function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) { - const floorpolygons = []; - const connectedLines = []; - const unprocessedLines = [...FloorLineFeatures]; // Copy the features - - while (unprocessedLines.length > 0) { - const currentLine = unprocessedLines.pop(); - const coordinates = currentLine.geometry.coordinates; - - // Check if the line is closed (forms a polygon) - if ( - coordinates[0][0] === coordinates[coordinates.length - 1][0] && - coordinates[0][1] === coordinates[coordinates.length - 1][1] - ) { - floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon - continue; - } - - // Check if the line connects to another line - let connected = false; - for (let i = unprocessedLines.length - 1; i >= 0; i--) { - const otherCoordinates = unprocessedLines[i].geometry.coordinates; - - // Check if lines share a start or end point - if ( - coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] && - coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1] - ) { - // Merge lines - const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)]; - unprocessedLines[i] = turf.lineString(mergedCoordinates); - connected = true; - break; - } else if ( - coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] && - coordinates[coordinates.length - 1][1] === otherCoordinates[0][1] - ) { - // Merge lines - const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)]; - unprocessedLines[i] = turf.lineString(mergedCoordinates); - connected = true; - break; - } - } - - if (!connected) { - connectedLines.push(currentLine); // Add unconnected line as-is - } - } - - return { floorpolygons, connectedLines }; - } - - const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures); - - function convertConnectedLinesToPolygons(connectedLines: any) { - return connectedLines.map((line: any) => { - const coordinates = line.geometry.coordinates; - - // If the line has more than two points, close the polygon - if (coordinates.length > 2) { - const firstPoint = coordinates[0]; - const lastPoint = coordinates[coordinates.length - 1]; - - // Check if already closed; if not, close it - if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) { - coordinates.push(firstPoint); - } - - // Convert the closed line into a polygon - return turf.polygon([coordinates]); - } - - // If not enough points for a polygon, return the line unchanged - return line; - }); - } - - const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines); - - if (convertedConnectedPolygons.length > 0) { - const validPolygons = convertedConnectedPolygons.filter( - (polygon: any) => polygon.geometry?.type === "Polygon" - ); - - if (validPolygons.length > 0) { - floorpolygons.push(...validPolygons); - } - } - - function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) { - return floorpolygons.map((polygon: any) => { - const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon) - - // Map each coordinate back to its original structure - const mappedPoints = coordinates.map((coord: [number, number]) => { - const [x, z] = coord; - - // Find the original point matching this coordinate - const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z); - - if (!originalPoint) { - console.error(`Original point for coordinate [${x}, ${z}] not found.`); - } - - return originalPoint; - }); - - // Create pairs of consecutive points - const pairs: typeof originalLines = []; - for (let i = 0; i < mappedPoints.length - 1; i++) { - pairs.push([mappedPoints[i], mappedPoints[i + 1]]); - } - - return pairs; - }); - } - - const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer); - - convertedFloorPolygons.forEach((floor) => { - const points: THREE.Vector3[] = []; - - floor.forEach((lineSegment) => { - const startPoint = lineSegment[0][0]; - points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z)); - }); - - const lastLine = floor[floor.length - 1]; - const endPoint = lastLine[1][0]; - points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z)); - - const shape = new THREE.Shape(); - shape.moveTo(points[0].x, points[0].z); - - points.forEach(point => shape.lineTo(point.x, point.z)); - shape.closePath(); - - const extrudeSettings = { - depth: CONSTANTS.floorConfig.height, - bevelEnabled: false - }; - - const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); - const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide }); - const mesh = new THREE.Mesh(geometry, material); - - mesh.castShadow = true; - mesh.receiveShadow = true; - - mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height; - mesh.rotateX(Math.PI / 2); - mesh.name = `Only_Floor_Line_${floor[0][0][2]}`; - - mesh.userData = floor; - floorGroup?.current?.add(mesh); - }); -} - -export default loadOnlyFloors; diff --git a/app/src/modules/builder/geomentries/floors/updateFloorLines.ts b/app/src/modules/builder/geomentries/floors/updateFloorLines.ts deleted file mode 100644 index 4198a00..0000000 --- a/app/src/modules/builder/geomentries/floors/updateFloorLines.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as Types from "../../../../types/world/worldTypes"; - -function updateFloorLines( - onlyFloorlines: Types.RefOnlyFloorLines, - DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 } -): void { - - ////////// Update onlyFloorlines.current if it contains the dragged point ////////// - - onlyFloorlines.current.forEach((floorline) => { - floorline.forEach((line) => { - line.forEach((point) => { - const [position, uuid] = point; - if (uuid === DragedPoint.uuid) { - position.x = DragedPoint.position.x; - position.y = 0.01; - position.z = DragedPoint.position.z; - } - }); - }); - }); -} - -export default updateFloorLines; diff --git a/app/src/modules/builder/geomentries/layers/deleteLayer.ts b/app/src/modules/builder/geomentries/layers/deleteLayer.ts deleted file mode 100644 index 318cc61..0000000 --- a/app/src/modules/builder/geomentries/layers/deleteLayer.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { toast } from "react-toastify"; -import RemoveConnectedLines from "../lines/removeConnectedLines"; - -import * as Types from "../../../../types/world/worldTypes"; -import { Socket } from "socket.io-client"; -import { getUserData } from "../../../../functions/getUserData"; -// import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi'; - -async function DeleteLayer( - removedLayer: Types.Number, - lines: Types.RefLines, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroupPoint: Types.RefGroup, - onlyFloorlines: Types.RefOnlyFloorLines, - floorGroup: Types.RefGroup, - setDeletedLines: any, - setRemovedLayer: Types.setRemoveLayerSetState, - socket: Socket, - projectId?: string, - versionId?: string, -): Promise { - ////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer ////////// - - const removedLines: Types.Lines = lines.current.filter( - (line) => line[0][2] === removedLayer - ); - const { userId, organization } = getUserData(); - - //REST - - // await deleteLayer(organization, removedLayer); - - //SOCKET - - const data = { - organization, - layer: removedLayer, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - socket.emit("v1:Line:delete:layer", data); - - ////////// Remove Points and lines from the removed layer ////////// - - removedLines.forEach((line) => { - line.forEach((removedPoint) => { - RemoveConnectedLines( - removedPoint[1], - floorPlanGroupLine, - floorPlanGroupPoint, - setDeletedLines, - lines - ); - }); - }); - - ////////// Update the remaining lines layer values in the userData and in lines.current ////////// - - let remaining = lines.current.filter((line) => line[0][2] !== removedLayer); - let updatedLines: Types.Lines = []; - remaining.forEach((line) => { - let newLines: Types.Line = [...line]; - if (newLines[0][2] > removedLayer) { - newLines[0][2] -= 1; - newLines[1][2] -= 1; - } - - const matchingLine = floorPlanGroupLine.current.children.find( - (l) => - l.userData.linePoints[0][1] === line[0][1] && - l.userData.linePoints[1][1] === line[1][1] - ); - if (matchingLine) { - const updatedUserData = matchingLine.userData; - updatedUserData.linePoints[0][2] = newLines[0][2]; - updatedUserData.linePoints[1][2] = newLines[1][2]; - } - 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) => { - return floor[0][0][2] !== removedLayer; - }); - const meshToRemove: any = floorGroup.current?.children.find( - (mesh) => mesh.name === `Only_Floor_Line_${removedLayer}` - ); - if (meshToRemove) { - (meshToRemove.material).dispose(); - (meshToRemove.geometry).dispose(); - floorGroup.current?.remove(meshToRemove); - } - - echo.success("Layer Removed!"); - setRemovedLayer(null); -} -export default DeleteLayer; diff --git a/app/src/modules/builder/geomentries/layers/layer2DVisibility.ts b/app/src/modules/builder/geomentries/layers/layer2DVisibility.ts deleted file mode 100644 index f1828de..0000000 --- a/app/src/modules/builder/geomentries/layers/layer2DVisibility.ts +++ /dev/null @@ -1,35 +0,0 @@ -import * as Types from "../../../../types/world/worldTypes"; - -function Layer2DVisibility( - activeLayer: Types.Number, - floorPlanGroup: Types.RefGroup, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroupPoint: Types.RefGroup, - currentLayerPoint: Types.RefMeshArray, - dragPointControls: Types.RefDragControl -): void { - - if (floorPlanGroup.current && dragPointControls.current) { - currentLayerPoint.current = []; - floorPlanGroupLine.current.children.forEach((line) => { - const linePoints = line.userData.linePoints; - - const point1 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[0][1]) as Types.Mesh; - const point2 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[1][1]) as Types.Mesh; - - if (linePoints[0][2] !== activeLayer && linePoints[1][2] !== activeLayer) { - point1.visible = false; - point2.visible = false; - line.visible = false; - } else { - point1.visible = true; - point2.visible = true; - line.visible = true; - currentLayerPoint.current.push(point1, point2); - } - }); - dragPointControls.current!.objects = currentLayerPoint.current; - } -} - -export default Layer2DVisibility; diff --git a/app/src/modules/builder/geomentries/lines/addLineToScene.ts b/app/src/modules/builder/geomentries/lines/addLineToScene.ts deleted file mode 100644 index 9e30e1d..0000000 --- a/app/src/modules/builder/geomentries/lines/addLineToScene.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as THREE from "three"; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import * as Types from "../../../../types/world/worldTypes"; - -function addLineToScene( - start: Types.Vector3, - end: Types.Vector3, - colour: Types.Color, - userData: Types.UserData, - floorPlanGroupLine: Types.RefGroup -): void { - - ////////// A function that creates and adds lines based on the start, end, and colour from the params, Also adds the userData in the mesh userData ////////// - - const path = new THREE.CatmullRomCurve3([start, end]); - const geometry = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); - const material = new THREE.MeshBasicMaterial({ color: colour }); - const mesh = new THREE.Mesh(geometry, material); - floorPlanGroupLine.current.add(mesh); - - mesh.userData.linePoints = userData; -} - -export default addLineToScene; diff --git a/app/src/modules/builder/geomentries/lines/createAndMoveReferenceLine.ts b/app/src/modules/builder/geomentries/lines/createAndMoveReferenceLine.ts deleted file mode 100644 index e5b6fbe..0000000 --- a/app/src/modules/builder/geomentries/lines/createAndMoveReferenceLine.ts +++ /dev/null @@ -1,98 +0,0 @@ -import * as THREE from "three"; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import * as Types from "../../../../types/world/worldTypes"; - -function createAndMoveReferenceLine( - point: Types.Vector3, - cursorPosition: Types.Vector3, - isSnapped: Types.RefBoolean, - ispreSnapped: Types.RefBoolean, - line: Types.RefLine, - setRefTextUpdate: Types.NumberIncrementState, - floorPlanGroup: Types.RefGroup, - ReferenceLineMesh: Types.RefMesh, - LineCreated: Types.RefBoolean, - Tube: Types.RefTubeGeometry, - anglesnappedPoint: Types.RefVector3, - isAngleSnapped: Types.RefBoolean -): void { - - ////////// Creating new and maintaining the old reference line and also snap the reference line based on its angle ////////// - - const startPoint = point; - - const dx = cursorPosition.x - startPoint.x; - const dz = cursorPosition.z - startPoint.z; - let angle = Math.atan2(dz, dx); - - angle = (angle * 180) / Math.PI; - angle = (angle + 360) % 360; - - const snapAngles = [0, 90, 180, 270, 360]; - const snapThreshold = 2.5; - - const closestSnapAngle = snapAngles.reduce((prev, curr) => - Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev - ); - - if (!isSnapped.current && !ispreSnapped.current && line.current.length > 0) { - if (Math.abs(closestSnapAngle - angle) <= snapThreshold) { - const snappedAngleRad = (closestSnapAngle * Math.PI) / 180; - const distance = Math.sqrt(dx * dx + dz * dz); - const snappedX = startPoint.x + distance * Math.cos(snappedAngleRad); - const snappedZ = startPoint.z + distance * Math.sin(snappedAngleRad); - - if ( - cursorPosition.distanceTo( - new THREE.Vector3(snappedX, 0.01, snappedZ) - ) < 2 - ) { - cursorPosition.set(snappedX, 0.01, snappedZ); - isAngleSnapped.current = true; - anglesnappedPoint.current = new THREE.Vector3( - snappedX, - 0.01, - snappedZ - ); - } else { - isAngleSnapped.current = false; - anglesnappedPoint.current = null; - } - } else { - isAngleSnapped.current = false; - anglesnappedPoint.current = null; - } - } else { - isAngleSnapped.current = false; - anglesnappedPoint.current = null; - } - - if (!LineCreated.current) { - setRefTextUpdate((prevUpdate) => prevUpdate - 1); - const path = new THREE.LineCurve3(startPoint, cursorPosition); - Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); - const material = new THREE.MeshBasicMaterial({ color: CONSTANTS.lineConfig.helperColor }); - ReferenceLineMesh.current = new THREE.Mesh(Tube.current, material); - ReferenceLineMesh.current.name = CONSTANTS.lineConfig.referenceName; - ReferenceLineMesh.current.userData = { - linePoints: { startPoint, cursorPosition }, - }; - floorPlanGroup.current?.add(ReferenceLineMesh.current); - LineCreated.current = true; - } else { - if (ReferenceLineMesh.current) { - const path = new THREE.LineCurve3(startPoint, new THREE.Vector3(cursorPosition.x, 0.01, cursorPosition.z)); - Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); - - if (ReferenceLineMesh.current) { - ReferenceLineMesh.current.userData = { - linePoints: { startPoint, cursorPosition }, - }; - ReferenceLineMesh.current.geometry.dispose(); - ReferenceLineMesh.current.geometry = Tube.current; - } - } - } -} - -export default createAndMoveReferenceLine; diff --git a/app/src/modules/builder/geomentries/lines/deleteLine.ts b/app/src/modules/builder/geomentries/lines/deleteLine.ts deleted file mode 100644 index 4b5158f..0000000 --- a/app/src/modules/builder/geomentries/lines/deleteLine.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Socket } from "socket.io-client"; -// import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi"; -import * as Types from "../../../../types/world/worldTypes"; - -import { toast } from "react-toastify"; -import { getUserData } from "../../../../functions/getUserData"; - -function deleteLine( - hoveredDeletableLine: Types.RefMesh, - onlyFloorlines: Types.RefOnlyFloorLines, - lines: Types.RefLines, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroupPoint: Types.RefGroup, - setDeletedLines: any, - socket: Socket, - projectId?: string, - versionId?: string, -): void { - const { userId, organization, email } = getUserData(); - ////////// Deleting a line and the points if they are not connected to any other line ////////// - - if (!hoveredDeletableLine.current) { - return; - } - - const linePoints = hoveredDeletableLine.current.userData.linePoints; - const connectedpoints = [linePoints[0][1], linePoints[1][1]]; - - //REST - - // deleteLineApi( - // organization, - // [ - // { "uuid": linePoints[0][1] }, - // { "uuid": linePoints[1][1] } - // ] - // ) - - //SOCKET - - const data = { - organization, - line: [{ uuid: linePoints[0][1] }, { uuid: linePoints[1][1] }], - socketId: socket.id, - versionId, - projectId, - userId, - }; - - socket.emit("v1:Line:delete", data); - - onlyFloorlines.current = onlyFloorlines.current - .map((floorline) => - floorline.filter( - (line) => - line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1] - ) - ) - .filter((floorline) => floorline.length > 0); - - lines.current = lines.current.filter((item) => item !== linePoints); - (hoveredDeletableLine.current.material).dispose(); - (hoveredDeletableLine.current.geometry).dispose(); - floorPlanGroupLine.current.remove(hoveredDeletableLine.current); - setDeletedLines([linePoints]); - - connectedpoints.forEach((pointUUID) => { - let isConnected = false; - floorPlanGroupLine.current.children.forEach((line) => { - 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); - } - }); - } - }); - - echo.success("Line Removed!"); -} - -export default deleteLine; diff --git a/app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx b/app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx deleted file mode 100644 index cdb586e..0000000 --- a/app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import { useEffect, useState } from "react"; -import { getLines } from "../../../../../services/factoryBuilder/lines/getLinesApi"; -import * as THREE from "three"; -import { - useActiveLayer, - useDeletedLines, - useNewLines, - useRoomsState, - useToggleView, -} from "../../../../../store/builder/store"; -import objectLinesToArray from "../lineConvertions/objectLinesToArray"; -import { Html } from "@react-three/drei"; -import { Vector2 } from "three"; -import * as Types from "../../../../../types/world/worldTypes"; -import getRoomsFromLines from "../getRoomsFromLines"; -import * as turf from '@turf/turf'; -import { useParams } from "react-router-dom"; -import { getUserData } from "../../../../../functions/getUserData"; -import { useVersionContext } from "../../../version/versionContext"; - -const DistanceText = () => { - const [lines, setLines] = useState< - { - distance: string; - position: THREE.Vector3; - userData: Types.Line; - layer: string; - }[] - >([]); - const { activeLayer } = useActiveLayer(); - const { toggleView } = useToggleView(); - const { newLines, setNewLines } = useNewLines(); - const { deletedLines, setDeletedLines } = useDeletedLines(); - const [linesState, setLinesState] = useState([]); - const { roomsState, setRoomsState } = useRoomsState(); - const { selectedVersionStore } = useVersionContext(); - const { selectedVersion } = selectedVersionStore(); - const { projectId } = useParams(); - const { organization, email } = getUserData(); - - useEffect(() => { - - if (linesState.length === 0) return; - const getLines = async () => { - const points3D = linesState.map(line => { - const startPoint = line[0][0]; // First point of each wall line - return [startPoint.x, 0, startPoint.z]; - }); - - // Ensure the polygon is closed - if ( - points3D[0][0] !== points3D[points3D.length - 1][0] || - points3D[0][1] !== points3D[points3D.length - 1][1] - ) { - points3D.push(points3D[0]); - } - - // Convert to 2D for turf (x, z) - const coords2D = points3D.map(p => [p[0], p[1]]); - - const projected = points3D.map((p: any) => new Vector2(p[0], p[1])); - - // Shoelace formula for 2D polygon - let area = 0; - const n = projected.length; - for (let i = 0; i < n - 1; i++) { - const curr = projected[i]; - const next = projected[i + 1]; - area += curr.x * next.y - next.x * curr.y; - - } - - // return Math.abs(area) / 2; - - // Build polygon and compute area - // const polygon = turf.polygon([coords2D]); - // const area = turf.area(polygon); - // const area = computeAreaFrom3DPoints(coords2D) - - // - if (lines.length > 2) { - const linesByLayer = linesState.reduce((acc: { [key: number]: any[] }, pair) => { - const layer = pair[0][2]; - if (!acc[layer]) acc[layer] = []; - acc[layer].push(pair); - return acc; - }, {}); - - - for (const layer in linesByLayer) { - const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] }); - setRoomsState(rooms) - } - } - } - getLines(); - }, [linesState, roomsState]) - - - useEffect(() => { - if (!email || !selectedVersion) return; - - getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => { - data = objectLinesToArray(data); - setLinesState(data); - - const lines = data - .filter((line: Types.Line) => line[0][2] === activeLayer) - .map((line: Types.Line) => { - const point1 = new THREE.Vector3( - line[0][0].x, - line[0][0].y, - line[0][0].z - ); - const point2 = new THREE.Vector3( - line[1][0].x, - line[1][0].y, - line[1][0].z - ); - const distance = point1.distanceTo(point2); - const midpoint = new THREE.Vector3() - .addVectors(point1, point2) - .divideScalar(2); - return { - distance: distance.toFixed(1), - position: midpoint, - userData: line, - layer: activeLayer, - }; - }); - setLines(lines); - }); - }, [activeLayer, selectedVersion?.versionId]); - - useEffect(() => { - if (newLines.length > 0) { - if (newLines[0][0][2] !== activeLayer) return; - const newLinesData = newLines.map((line: Types.Line) => { - const point1 = new THREE.Vector3( - line[0][0].x, - line[0][0].y, - line[0][0].z - ); - const point2 = new THREE.Vector3( - line[1][0].x, - line[1][0].y, - line[1][0].z - ); - const distance = point1.distanceTo(point2); - const midpoint = new THREE.Vector3() - .addVectors(point1, point2) - .divideScalar(2); - - return { - distance: distance.toFixed(1), - position: midpoint, - userData: line, - layer: activeLayer, - }; - }); - setLines((prevLines) => [...prevLines, ...newLinesData]); - setLinesState((prevLines) => [...prevLines, ...newLines]); - setNewLines([]); - } - }, [newLines, activeLayer]); - - useEffect(() => { - if ((deletedLines as Types.Lines).length > 0) { - setLines((prevLines) => - prevLines.filter( - (line) => - !deletedLines.some( - (deletedLine: any) => - deletedLine[0][1] === line.userData[0][1] && - deletedLine[1][1] === line.userData[1][1] - ) - ) - ); - - setLinesState(prev => - prev.filter(line => - !(deletedLines as Types.Lines).some( - deleted => - line[0][1] === deleted[0][1] && line[1][1] === deleted[1][1] - ) - ) - ); - - setDeletedLines([]); - setRoomsState([]) - } - }, [deletedLines]); - - return ( - <> - {toggleView && ( - - {lines.map((text) => ( - -
- {text.distance} m -
- - ))} -
- )} - - ); -}; - -export default DistanceText; diff --git a/app/src/modules/builder/geomentries/lines/distanceText/referenceDistanceText.tsx b/app/src/modules/builder/geomentries/lines/distanceText/referenceDistanceText.tsx deleted file mode 100644 index ce9864d..0000000 --- a/app/src/modules/builder/geomentries/lines/distanceText/referenceDistanceText.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import * as THREE from "three"; -import { Html } from "@react-three/drei"; -import { useState, useEffect } from "react"; -import { useActiveLayer } from "../../../../../store/builder/store"; - -const ReferenceDistanceText = ({ line }: { line: any }) => { - interface TextState { - distance: string; - position: THREE.Vector3; - userData: any; - layer: any; - } - - const [text, setTexts] = useState(null); - const { activeLayer } = useActiveLayer(); - - useEffect(() => { - if (line) { - if (line.parent === null) { - setTexts(null); - return; - } - const distance = line.userData.linePoints.cursorPosition.distanceTo( - line.userData.linePoints.startPoint - ); - const midpoint = new THREE.Vector3() - .addVectors( - line.userData.linePoints.cursorPosition, - line.userData.linePoints.startPoint - ) - .divideScalar(2); - const newTexts = { - distance: distance.toFixed(1), - position: midpoint, - userData: line, - layer: activeLayer, - }; - setTexts(newTexts); - } - }); - - return ( - - - {text !== null && ( - -
- {text.distance} m -
- - )} -
-
- ); -}; - -export default ReferenceDistanceText; diff --git a/app/src/modules/builder/geomentries/lines/drawWall.ts b/app/src/modules/builder/geomentries/lines/drawWall.ts deleted file mode 100644 index 80333ed..0000000 --- a/app/src/modules/builder/geomentries/lines/drawWall.ts +++ /dev/null @@ -1,218 +0,0 @@ -import * as THREE from "three"; -import * as CONSTANTS from "../../../../types/world/worldConstants"; - -import addPointToScene from "../points/addPointToScene"; -import addLineToScene from "./addLineToScene"; -import splitLine from "./splitLine"; -import removeReferenceLine from "./removeReferenceLine"; -import getClosestIntersection from "./getClosestIntersection"; - -import * as Types from "../../../../types/world/worldTypes"; -import arrayLineToObject from "./lineConvertions/arrayLineToObject"; -// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi'; -import { Socket } from "socket.io-client"; -import { getUserData } from "../../../../functions/getUserData"; - -async function drawWall( - raycaster: THREE.Raycaster, - plane: Types.RefMesh, - floorPlanGroupPoint: Types.RefGroup, - snappedPoint: Types.RefVector3, - isSnapped: Types.RefBoolean, - isSnappedUUID: Types.RefString, - line: Types.RefLine, - ispreSnapped: Types.RefBoolean, - anglesnappedPoint: Types.RefVector3, - isAngleSnapped: Types.RefBoolean, - lines: Types.RefLines, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroup: Types.RefGroup, - ReferenceLineMesh: Types.RefMesh, - LineCreated: Types.RefBoolean, - currentLayerPoint: Types.RefMeshArray, - dragPointControls: Types.RefDragControl, - setNewLines: any, - setDeletedLines: any, - activeLayer: Types.Number, - socket: Socket, - projectId?: string, - versionId?: string, -): Promise { - const { userId, organization } = getUserData(); - ////////// Creating lines Based on the positions clicked ////////// - - ////////// Allows the user lines that represents walls and roof, floor if forms a polygon ////////// - - if (!plane.current) return; - let intersects = raycaster.intersectObject(plane.current, true); - - let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true); - let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true); - - const VisibleintersectsPoint = intersectsPoint.find((intersect) => intersect.object.visible); - const visibleIntersect = intersectsLines.find( - (intersect) => - intersect.object.visible && - intersect.object.name !== CONSTANTS.lineConfig.referenceName && - intersect.object.userData.linePoints[0][3] === - CONSTANTS.lineConfig.wallName - ); - - if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) { - ////////// Clicked on a preexisting Line ////////// - - if (visibleIntersect && intersects) { - let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z); - - if (isAngleSnapped.current && anglesnappedPoint.current) { - IntersectsPoint = anglesnappedPoint.current; - } - if (visibleIntersect.object instanceof THREE.Mesh) { - const ThroughPoint = visibleIntersect.object.geometry.parameters.path.getPoints(CONSTANTS.lineConfig.lineIntersectionPoints); - let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint); - - if (intersectionPoint) { - const newLines = splitLine( - visibleIntersect, - intersectionPoint, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - lines, - setDeletedLines, - floorPlanGroupLine, - socket, - CONSTANTS.pointConfig.wallOuterColor, - CONSTANTS.lineConfig.wallColor, - CONSTANTS.lineConfig.wallName, - projectId, - versionId - ); - setNewLines([newLines[0], newLines[1]]); - - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.wallName, - ]); - - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - const data = arrayLineToObject(line.current as Types.Line); - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - socket.emit("v1:Line:create", input); - - setNewLines([newLines[0], newLines[1], line.current]); - lines.current.push(line.current as Types.Line); - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.wallColor, - line.current, - floorPlanGroupLine - ); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - return; - } - } - } - } - - if (intersects && intersects.length > 0) { - ////////// Clicked on a emply place or a point ////////// - - let intersectionPoint = intersects[0].point; - - if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) { - intersectionPoint = anglesnappedPoint.current; - } - if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } - if (ispreSnapped.current && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } - - if (!isSnapped.current && !ispreSnapped.current) { - addPointToScene( - intersectionPoint, - CONSTANTS.pointConfig.wallOuterColor, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - CONSTANTS.lineConfig.wallName - ); - } else { - ispreSnapped.current = false; - isSnapped.current = false; - } - - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.wallName, - ]); - - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - const data = arrayLineToObject(line.current as Types.Line); - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - socket.emit("v1:Line:create", input); - - setNewLines([line.current]); - lines.current.push(line.current as Types.Line); - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.wallColor, - line.current, - floorPlanGroupLine - ); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - if (isSnapped.current) { - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - } -} - -export default drawWall; diff --git a/app/src/modules/builder/geomentries/lines/getRoomsFromLines.ts b/app/src/modules/builder/geomentries/lines/getRoomsFromLines.ts deleted file mode 100644 index 08304ea..0000000 --- a/app/src/modules/builder/geomentries/lines/getRoomsFromLines.ts +++ /dev/null @@ -1,86 +0,0 @@ -import * as THREE from 'three'; -import * as turf from '@turf/turf'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import * as Types from "../../../../types/world/worldTypes"; - -async function getRoomsFromLines(lines: Types.RefLines) { - const rooms: Types.Rooms = []; - - if (lines.current.length > 2) { - const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => { - const layer = pair[0][2]; - if (!acc[layer]) acc[layer] = []; - acc[layer].push(pair); - return acc; - }, {}); - - ////////// Use turf.polygonize to create polygons from the line points ////////// - - for (const layer in linesByLayer) { - - let linesInLayer = linesByLayer[layer]; - linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName); - const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) => - pair.map((point) => ({ - position: [point[0].x, point[0].z], - uuid: point[1] - })) - ); - const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position))); - const polygons = turf.polygonize(turf.featureCollection(lineFeatures)); - - let union: any[] = []; - - polygons.features.forEach((feature) => { - union.push(feature); - }); - - if (union.length > 1) { - const unionResult = turf.union(turf.featureCollection(union)); - if (unionResult?.geometry.type === "MultiPolygon") { - unionResult?.geometry.coordinates.forEach((poly) => { - const Coordinates = poly[0].map(([x, z]) => { - const matchingPoint = result.flat().find(r => - r.position[0].toFixed(10) === x.toFixed(10) && - r.position[1].toFixed(10) === z.toFixed(10) - ); - return { - position: new THREE.Vector3(x, 0, z), - uuid: matchingPoint ? matchingPoint.uuid : '' - }; - }); - rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) }); - }); - } else if (unionResult?.geometry.type === "Polygon") { - const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => { - const matchingPoint = result.flat().find(r => - r.position[0].toFixed(10) === x.toFixed(10) && - r.position[1].toFixed(10) === z.toFixed(10) - ); - return { - position: new THREE.Vector3(x, 0, z), - uuid: matchingPoint ? matchingPoint.uuid : '' - }; - }); - rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) }); - } - } else if (union.length === 1) { - const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => { - const matchingPoint = result.flat().find(r => - r.position[0].toFixed(10) === x.toFixed(10) && - r.position[1].toFixed(10) === z.toFixed(10) - ); - return { - position: new THREE.Vector3(x, 0, z), - uuid: matchingPoint ? matchingPoint.uuid : '' - }; - }); - rooms.push({ coordinates: Coordinates, layer: parseInt(layer) }); - } - } - } - - return rooms; -} - -export default getRoomsFromLines; diff --git a/app/src/modules/builder/geomentries/lines/lineConvertions/arrayLineToObject.ts b/app/src/modules/builder/geomentries/lines/lineConvertions/arrayLineToObject.ts deleted file mode 100644 index dffac05..0000000 --- a/app/src/modules/builder/geomentries/lines/lineConvertions/arrayLineToObject.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as Types from "../../../../../types/world/worldTypes"; - -export default function arrayLineToObject(array: Types.Line) { - if (!Array.isArray(array)) { - return {}; - } - - // Extract common properties from the first point - const commonLayer = array[0][2]; - const commonType = array[0][3]; - - // Map points into a structured format - const line = array.map(([position, uuid]) => ({ - position, - uuid, - })); - - // Create the final structured object - return { - layer: commonLayer, - type: commonType, - line, - }; -} \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/lines/lineConvertions/arrayLinesToObject.ts b/app/src/modules/builder/geomentries/lines/lineConvertions/arrayLinesToObject.ts deleted file mode 100644 index 041b17c..0000000 --- a/app/src/modules/builder/geomentries/lines/lineConvertions/arrayLinesToObject.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as Types from "../../../../../types/world/worldTypes"; - -export default function arrayLinesToObject(array: Array) { - if (!Array.isArray(array)) { - return []; - } - - return array.map((lineArray) => { - if (!Array.isArray(lineArray)) { - return null; - } - - // Extract common properties from the first point - const commonLayer = lineArray[0][2]; - const commonType = lineArray[0][3]; - - // Map points into a structured format - const line = lineArray.map(([position, uuid]) => ({ - position, - uuid, - })); - - // Create the final structured object - return { - layer: commonLayer, - type: commonType, - line, - }; - }).filter((item) => item !== null); // Filter out invalid entries -} diff --git a/app/src/modules/builder/geomentries/lines/lineConvertions/objectLineToArray.ts b/app/src/modules/builder/geomentries/lines/lineConvertions/objectLineToArray.ts deleted file mode 100644 index ac0162c..0000000 --- a/app/src/modules/builder/geomentries/lines/lineConvertions/objectLineToArray.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as THREE from 'three'; - -export default function objectLineToArray(structuredObject: any) { - if (!structuredObject || !structuredObject.line) { - return []; - } - - // Destructure common properties - const { layer, type, line } = structuredObject; - - // Map points back to the original array format - return line.map(({ position, uuid }: any) => [new THREE.Vector3(position.x, position.y, position.z), uuid, layer, type]); -} \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/lines/lineConvertions/objectLinesToArray.ts b/app/src/modules/builder/geomentries/lines/lineConvertions/objectLinesToArray.ts deleted file mode 100644 index 856b935..0000000 --- a/app/src/modules/builder/geomentries/lines/lineConvertions/objectLinesToArray.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as THREE from 'three'; - -export default function objectLinesToArray(structuredObjects: any): any { - if (!Array.isArray(structuredObjects)) { - return []; - } - - return structuredObjects.map((structuredObject) => { - if (!structuredObject || !structuredObject.line) { - return []; - } - - const { layer, type, line } = structuredObject; - - return line.map(({ position, uuid }: any) => { - const vector = new THREE.Vector3(position.x, position.y, position.z); - return [vector, uuid, layer, type]; - }); - }); -} diff --git a/app/src/modules/builder/geomentries/lines/removeConnectedLines.ts b/app/src/modules/builder/geomentries/lines/removeConnectedLines.ts deleted file mode 100644 index ddf6452..0000000 --- a/app/src/modules/builder/geomentries/lines/removeConnectedLines.ts +++ /dev/null @@ -1,66 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function RemoveConnectedLines( - DeletedPointUUID: Types.String, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroupPoint: Types.RefGroup, - setDeletedLines: any, - lines: Types.RefLines, -): void { - - ////////// Check if any and how many lines are connected to the deleted point ////////// - - const removableLines: THREE.Mesh[] = []; - const connectedpoints: string[] = []; - - const removedLinePoints: [number, string, number][][] = []; // Array to hold linePoints of removed lines - - floorPlanGroupLine.current.children.forEach((line) => { - const linePoints = line.userData.linePoints as [number, string, number][]; - const uuid1 = linePoints[0][1]; - const uuid2 = linePoints[1][1]; - - if (uuid1 === DeletedPointUUID || uuid2 === DeletedPointUUID) { - connectedpoints.push(uuid1 === DeletedPointUUID ? uuid2 : uuid1); - removableLines.push(line as THREE.Mesh); - removedLinePoints.push(linePoints); - } - }); - - if (removableLines.length > 0) { - removableLines.forEach((line) => { - lines.current = lines.current.filter(item => item !== line.userData.linePoints); - (line.material).dispose(); - (line.geometry).dispose(); - floorPlanGroupLine.current.remove(line); - }); - } - setDeletedLines(removedLinePoints) - - ////////// Check and Remove point that are no longer connected to any lines ////////// - - connectedpoints.forEach((pointUUID) => { - let isConnected = false; - floorPlanGroupLine.current.children.forEach((line) => { - const linePoints = line.userData.linePoints as [number, string, number][]; - 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); - } - }); - } - }); -} - -export default RemoveConnectedLines; diff --git a/app/src/modules/builder/geomentries/lines/removeReferenceLine.ts b/app/src/modules/builder/geomentries/lines/removeReferenceLine.ts deleted file mode 100644 index 787389a..0000000 --- a/app/src/modules/builder/geomentries/lines/removeReferenceLine.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as Types from "../../../../types/world/worldTypes"; - -function removeReferenceLine( - floorPlanGroup: Types.RefGroup, - ReferenceLineMesh: Types.RefMesh, - LineCreated: Types.RefBoolean, - line: Types.RefLine -): void { - - ////////// Removes Dangling reference line if the draw mode is ended or any other case ////////// - - line.current = []; - if (ReferenceLineMesh.current) { - (ReferenceLineMesh.current.material).dispose(); - (ReferenceLineMesh.current.geometry).dispose(); - floorPlanGroup.current.remove(ReferenceLineMesh.current); - LineCreated.current = false; - ReferenceLineMesh.current = undefined; - } -} - -export default removeReferenceLine; \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/lines/splitLine.ts b/app/src/modules/builder/geomentries/lines/splitLine.ts deleted file mode 100644 index 31c2646..0000000 --- a/app/src/modules/builder/geomentries/lines/splitLine.ts +++ /dev/null @@ -1,153 +0,0 @@ -import * as THREE from "three"; - -import addLineToScene from "./addLineToScene"; -import addPointToScene from "../points/addPointToScene"; - -import * as Types from "../../../../types/world/worldTypes"; -import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject"; -import { Socket } from "socket.io-client"; -import { getUserData } from "../../../../functions/getUserData"; -// import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi'; -// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi'; - -function splitLine( - visibleIntersect: Types.IntersectionEvent, - intersectionPoint: Types.Vector3, - currentLayerPoint: Types.RefMeshArray, - floorPlanGroupPoint: Types.RefGroup, - dragPointControls: Types.RefDragControl, - isSnappedUUID: Types.RefString, - lines: Types.RefLines, - setDeletedLines: any, - floorPlanGroupLine: { current: THREE.Group }, - socket: Socket, - pointColor: Types.String, - lineColor: Types.String, - lineType: Types.String, - projectId?: string, - versionId?: string, -): [Types.Line, Types.Line] { - ////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines ////////// - - const { userId, organization, email } = getUserData(); - (visibleIntersect.object as any).material.dispose(); - (visibleIntersect.object as any).geometry.dispose(); - floorPlanGroupLine.current.remove(visibleIntersect.object); - setDeletedLines([visibleIntersect.object.userData.linePoints]); - - //REST - - // deleteLineApi( - // organization, - // [ - // { "uuid": visibleIntersect.object.userData.linePoints[0][1] }, - // { "uuid": visibleIntersect.object.userData.linePoints[1][1] } - // ] - // ) - - //SOCKET - - const data = { - organization, - line: [ - { uuid: visibleIntersect.object.userData.linePoints[0][1] }, - { uuid: visibleIntersect.object.userData.linePoints[1][1] }, - ], - socketId: socket.id, - versionId, - projectId, - userId, - }; - - socket.emit("v1:Line:delete", data); - - const point = addPointToScene( - intersectionPoint, - pointColor, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - lineType - ); - - const oldLinePoints = visibleIntersect.object.userData.linePoints; - lines.current = lines.current.filter((item) => item !== oldLinePoints); - - const clickedPoint: Types.Point = [ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - point.uuid, - oldLinePoints[0][2], - lineType, - ]; - - const start = oldLinePoints[0]; - const end = oldLinePoints[1]; - - const newLine1: Types.Line = [start, clickedPoint]; - const newLine2: Types.Line = [clickedPoint, end]; - - const line1 = arrayLineToObject(newLine1); - const line2 = arrayLineToObject(newLine2); - - //REST - - // setLine(organization, line1.layer!, line1.line!, line1.type!); - - //SOCKET - - const input1 = { - organization, - layer: line1.layer, - line: line1.line, - type: line1.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - console.log('input1: ', input1); - socket.emit("v1:Line:create", input1); - - //REST - - // setLine(organization, line2.layer!, line2.line!, line2.type!); - - //SOCKET - - const input2 = { - organization, - layer: line2.layer, - line: line2.line, - type: line2.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - console.log('input2: ', input2); - socket.emit("v1:Line:create", input2); - - lines.current.push(newLine1, newLine2); - - addLineToScene( - newLine1[0][0], - newLine1[1][0], - lineColor, - newLine1, - floorPlanGroupLine - ); - addLineToScene( - newLine2[0][0], - newLine2[1][0], - lineColor, - newLine2, - floorPlanGroupLine - ); - - return [newLine1, newLine2]; -} - -export default splitLine; diff --git a/app/src/modules/builder/geomentries/lines/updateDistanceText.ts b/app/src/modules/builder/geomentries/lines/updateDistanceText.ts deleted file mode 100644 index 8d7fbe2..0000000 --- a/app/src/modules/builder/geomentries/lines/updateDistanceText.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function updateDistanceText( - scene: THREE.Scene, - floorPlanGroupLine: Types.RefGroup, - affectedLines: Types.NumberArray -): void { - - ////////// Updating the Distance Texts of the lines that are affected during drag ////////// - - const DistanceGroup = scene.getObjectByName('Distance_Text') as THREE.Group; - - affectedLines.forEach((lineIndex) => { - const mesh = floorPlanGroupLine.current.children[lineIndex] as THREE.Mesh; - const linePoints = mesh.userData.linePoints; - - if (linePoints) { - const distance = linePoints[0][0].distanceTo(linePoints[1][0]).toFixed(1); - const position = new THREE.Vector3().addVectors(linePoints[0][0], linePoints[1][0]).divideScalar(2); - - if (!DistanceGroup || !linePoints) { - return - } - - DistanceGroup.children.forEach((text) => { - const textMesh = text as THREE.Mesh; - if (textMesh.userData[0][1] === linePoints[0][1] && textMesh.userData[1][1] === linePoints[1][1]) { - textMesh.position.set(position.x, 1, position.z); - const className = `distance line-${textMesh.userData[0][1]}_${textMesh.userData[1][1]}_${linePoints[0][2]}`; - const element = document.getElementsByClassName(className)[0] as HTMLElement; - if (element) { - element.innerHTML = `${distance} m`; - } - } - }); - } - }); -} - -export default updateDistanceText; diff --git a/app/src/modules/builder/geomentries/lines/updateLines.ts b/app/src/modules/builder/geomentries/lines/updateLines.ts deleted file mode 100644 index 0c4f22f..0000000 --- a/app/src/modules/builder/geomentries/lines/updateLines.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as THREE from 'three'; -import * as Types from "../../../../types/world/worldTypes"; -import * as CONSTANTS from '../../../../types/world/worldConstants'; - -function updateLines( - floorPlanGroupLine: Types.RefGroup, - affectedLines: Types.NumberArray -): void { - - ////////// Updating the positions for the affected lines only based on the updated positions ////////// - - affectedLines.forEach((lineIndex) => { - const mesh = floorPlanGroupLine.current.children[lineIndex] as Types.Mesh; - const linePoints = mesh.userData.linePoints as Types.Line; - if (linePoints) { - const newPositions = linePoints.map(([pos]) => pos); - const newPath = new THREE.CatmullRomCurve3(newPositions); - mesh.geometry.dispose(); - mesh.geometry = new THREE.TubeGeometry(newPath, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); - } - }); -} - -export default updateLines; \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/lines/updateLinesPositions.ts b/app/src/modules/builder/geomentries/lines/updateLinesPositions.ts deleted file mode 100644 index 6411a09..0000000 --- a/app/src/modules/builder/geomentries/lines/updateLinesPositions.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as Types from "../../../../types/world/worldTypes"; - -function updateLinesPositions( - DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 }, - lines: Types.RefLines -): Types.NumberArray { - - ////////// Updating the lines position based on the dragged point's position ////////// - - const objectUUID = DragedPoint.uuid; - const affectedLines: Types.NumberArray = []; - - lines.current.forEach((line, index) => { - let lineUpdated = false; - line.forEach((point) => { - const [position, uuid] = point; - if (uuid === objectUUID) { - position.x = DragedPoint.position.x; - position.y = 0.01; - position.z = DragedPoint.position.z; - lineUpdated = true; - } - }); - if (lineUpdated) { - affectedLines.push(index); - } - }); - - return affectedLines; -} - -export default updateLinesPositions; diff --git a/app/src/modules/builder/geomentries/lines/vectorizeLinesCurrent.ts b/app/src/modules/builder/geomentries/lines/vectorizeLinesCurrent.ts deleted file mode 100644 index a404a07..0000000 --- a/app/src/modules/builder/geomentries/lines/vectorizeLinesCurrent.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function vectorizeLinesCurrent( - lines: Types.Lines -): Types.Lines { - - ////////// Storing a vector3 array in localstorage makes the prototype functions go puff. This function brings back the prototype functions by creating it again ////////// - - return lines.map((line) => { - const p1: Types.Point = [new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), line[0][1], line[0][2], line[0][3],]; - const p2: Types.Point = [new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), line[1][1], line[0][2], line[1][3],]; - return [p1, p2]; - }); -} - -export default vectorizeLinesCurrent; diff --git a/app/src/modules/builder/geomentries/pillars/addAndUpdateReferencePillar.ts b/app/src/modules/builder/geomentries/pillars/addAndUpdateReferencePillar.ts deleted file mode 100644 index 04cad47..0000000 --- a/app/src/modules/builder/geomentries/pillars/addAndUpdateReferencePillar.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as THREE from 'three'; -import updateReferencePolesheight from './updateReferencePolesheight'; - -import * as Types from "../../../../types/world/worldTypes"; - -function addAndUpdateReferencePillar( - raycaster: THREE.Raycaster, - floorGroup: Types.RefGroup, - referencePole: Types.RefMesh -): void { - - ////////// Find Pillars position and scale based on the pointer interaction ////////// - - let Roofs = raycaster.intersectObjects(floorGroup.current.children, true); - const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor")); - - if (intersected) { - const intersectionPoint = intersected.point; - raycaster.ray.origin.copy(intersectionPoint); - raycaster.ray.direction.set(0, -1, 0); - const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true); - const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor")); - - let distance: Types.Number; - - if (validIntersections.length > 1) { - let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3); - if (valid) { - updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup); - } else { - const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z); - distance = intersected.point.distanceTo(belowPoint); - if (distance > 3) { - updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup); - } - } - } else { - const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z); - distance = intersected.point.distanceTo(belowPoint); - if (distance > 3) { - updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup); - } - } - } else { - if (referencePole.current) { - (referencePole.current.material).dispose(); - (referencePole.current.geometry).dispose(); - floorGroup.current.remove(referencePole.current); - referencePole.current = null; - } - } -} - -export default addAndUpdateReferencePillar; diff --git a/app/src/modules/builder/geomentries/pillars/addPillar.ts b/app/src/modules/builder/geomentries/pillars/addPillar.ts deleted file mode 100644 index e6e4b86..0000000 --- a/app/src/modules/builder/geomentries/pillars/addPillar.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as THREE from 'three'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import * as Types from "../../../../types/world/worldTypes"; - -function addPillar( - referencePole: Types.RefMesh, - floorGroup: Types.RefGroup -): void { - - ////////// Add Pillars to the scene based on the reference. current poles position and scale ////////// - - if (referencePole.current) { - let pole: THREE.Mesh; - const geometry = referencePole.current.userData.geometry.clone(); - const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor }); - pole = new THREE.Mesh(geometry, material); - pole.rotateX(Math.PI / 2); - pole.name = "Pole"; - pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z); - floorGroup.current.add(pole); - } -} - -export default addPillar; \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/pillars/deletableHoveredPillar.ts b/app/src/modules/builder/geomentries/pillars/deletableHoveredPillar.ts deleted file mode 100644 index 4fb65c0..0000000 --- a/app/src/modules/builder/geomentries/pillars/deletableHoveredPillar.ts +++ /dev/null @@ -1,34 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function DeletableHoveredPillar( - state: Types.ThreeState, - floorGroup: Types.RefGroup, - hoveredDeletablePillar: Types.RefMesh -): void { - - ////////// Altering the color of the hovered Pillar during the Deletion time ////////// - - const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true); - const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole"); - - if (poleIntersect) { - if (poleIntersect.object.name !== "Pole") { - return; - } - if (hoveredDeletablePillar.current) { - (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black"); - hoveredDeletablePillar.current = undefined; - } - hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion - (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red"); - } else { - if (hoveredDeletablePillar.current) { - (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black"); - hoveredDeletablePillar.current = undefined; - } - } -} - -export default DeletableHoveredPillar; \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/pillars/deletePillar.ts b/app/src/modules/builder/geomentries/pillars/deletePillar.ts deleted file mode 100644 index 39e0b28..0000000 --- a/app/src/modules/builder/geomentries/pillars/deletePillar.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { toast } from 'react-toastify'; - -import * as Types from "../../../../types/world/worldTypes"; - -function DeletePillar( - hoveredDeletablePillar: Types.RefMesh, - floorGroup: Types.RefGroup -): void { - - ////////// Deleting the hovered Pillar from the itemsGroup ////////// - - if (hoveredDeletablePillar.current) { - (hoveredDeletablePillar.current.material).dispose(); - (hoveredDeletablePillar.current.geometry).dispose(); - floorGroup.current.remove(hoveredDeletablePillar.current); - echo.success("Pillar Removed!"); - hoveredDeletablePillar.current = undefined; - } -} - -export default DeletePillar; diff --git a/app/src/modules/builder/geomentries/pillars/updateReferencePolesheight.ts b/app/src/modules/builder/geomentries/pillars/updateReferencePolesheight.ts deleted file mode 100644 index f538546..0000000 --- a/app/src/modules/builder/geomentries/pillars/updateReferencePolesheight.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function updateReferencePolesheight( - intersectionPoint: Types.Vector3, - distance: Types.Number, - referencePole: Types.RefMesh, - floorGroup: Types.RefGroup -): void { - - ////////// Add a Reference Pillar and update its position and scale based on the pointer interaction ////////// - - if (referencePole.current) { - (referencePole.current.material).dispose(); - (referencePole.current.geometry).dispose(); - floorGroup.current.remove(referencePole.current); - referencePole.current.geometry.dispose(); - } - - const shape = new THREE.Shape(); - shape.moveTo(0.5, 0); - shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false); - - const extrudeSettings = { - depth: distance, - bevelEnabled: false, - }; - - const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); - const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 }); - referencePole.current = new THREE.Mesh(geometry, material); - referencePole.current.rotateX(Math.PI / 2); - referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z); - referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } }; - - floorGroup.current.add(referencePole.current); -} - -export default updateReferencePolesheight; diff --git a/app/src/modules/builder/geomentries/points/addPointToScene.ts b/app/src/modules/builder/geomentries/points/addPointToScene.ts deleted file mode 100644 index b182128..0000000 --- a/app/src/modules/builder/geomentries/points/addPointToScene.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as THREE from 'three'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import * as Types from "../../../../types/world/worldTypes"; - -function addPointToScene( - position: Types.Vector3, - colour: Types.Color, - currentLayerPoint: Types.RefMeshArray, - floorPlanGroupPoint: Types.RefGroup, - dragPointControls: Types.RefDragControl | undefined, - uuid: Types.RefString | undefined, - Type: Types.String -): Types.Mesh { - - ////////// A function that creates and adds a cube (point) with an outline based on the position and colour given as params, It also updates the drag controls objects and sets the box uuid in uuid.current ////////// - - const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale); - const material = new THREE.ShaderMaterial({ - uniforms: { - uOuterColor: { value: new THREE.Color(colour) }, // Blue color for the border - uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square - }, - vertexShader: ` - varying vec2 vUv; - - void main() { - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - } - `, - fragmentShader: ` - varying vec2 vUv; - uniform vec3 uOuterColor; - 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(uOuterColor, 1.0); // Blue border - } - } - `, - }); - const point = new THREE.Mesh(geometry, material); - point.name = "point"; - point.userData = { type: Type, color: colour }; - point.position.set(position.x, 0.01, position.z); - - currentLayerPoint.current.push(point); - floorPlanGroupPoint.current.add(point); - if (uuid) { - uuid.current = point.uuid; - } - if (dragPointControls) { - dragPointControls.current!.objects = currentLayerPoint.current; - } - - return point; -} - -export default addPointToScene; diff --git a/app/src/modules/builder/geomentries/points/deletePoint.ts b/app/src/modules/builder/geomentries/points/deletePoint.ts deleted file mode 100644 index 9a58eb5..0000000 --- a/app/src/modules/builder/geomentries/points/deletePoint.ts +++ /dev/null @@ -1,72 +0,0 @@ -import * as Types from "../../../../types/world/worldTypes"; - -import { toast } from "react-toastify"; - -import RemoveConnectedLines from "../lines/removeConnectedLines"; -// import { deletePointApi } from "../../../../services/factoryBuilder/lines/deletePointApi"; -import { Socket } from "socket.io-client"; -import { getUserData } from "../../../../functions/getUserData"; - -function deletePoint( - hoveredDeletablePoint: Types.RefMesh, - onlyFloorlines: Types.RefOnlyFloorLines, - floorPlanGroupPoint: Types.RefGroup, - floorPlanGroupLine: Types.RefGroup, - lines: Types.RefLines, - setDeletedLines: any, - socket: Socket, - projectId?: string, - versionId?: string, -): void { - ////////// Deleting a Point and the lines that are connected to it ////////// - - if (!hoveredDeletablePoint.current) { - return; - } - const { userId, organization, email } = getUserData(); - (hoveredDeletablePoint.current.material).dispose(); - (hoveredDeletablePoint.current.geometry).dispose(); - floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current); - const DeletedPointUUID = hoveredDeletablePoint.current.uuid; - - //REST - - // deletePointApi(organization, DeletedPointUUID); - - //SOCKET - - const data = { - organization, - uuid: DeletedPointUUID, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - // console.log('data: ', data); - socket.emit("v1:Line:delete:point", data); - - ////////// Update onlyFloorlines.current to remove references to the deleted point ////////// - - onlyFloorlines.current = onlyFloorlines.current - .map((floorline) => - floorline.filter( - (line) => - line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID - ) - ) - .filter((floorline) => floorline.length > 0); - - RemoveConnectedLines( - DeletedPointUUID, - floorPlanGroupLine, - floorPlanGroupPoint, - setDeletedLines, - lines - ); - - echo.success("Point Removed!"); -} - -export default deletePoint; diff --git a/app/src/modules/builder/geomentries/points/dragPoint.ts b/app/src/modules/builder/geomentries/points/dragPoint.ts deleted file mode 100644 index 6494721..0000000 --- a/app/src/modules/builder/geomentries/points/dragPoint.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as THREE from "three"; -import * as Types from "../../../../types/world/worldTypes" -import * as CONSTANTS from '../../../../types/world/worldConstants'; - -import updateLinesPositions from "../lines/updateLinesPositions"; -import updateLines from "../lines/updateLines"; -import updateDistanceText from "../lines/updateDistanceText"; -import updateFloorLines from "../floors/updateFloorLines"; - -function DragPoint( - event: Types.IntersectionEvent, - floorPlanGroupPoint: Types.RefGroup, - floorPlanGroupLine: Types.RefGroup, - scene: THREE.Scene, - lines: Types.RefLines, - onlyFloorlines: Types.RefOnlyFloorLines -): void { - - ////////// Calling the line updation of the affected lines and Snapping of the point during the drag ////////// - - const snapThreshold = CONSTANTS.pointConfig.snappingThreshold; - const DragedPoint = event.object as Types.Mesh; - - floorPlanGroupPoint.current.children.forEach((point) => { - let canSnap = - ((DragedPoint.userData.type === CONSTANTS.lineConfig.wallName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) || - ((DragedPoint.userData.type === CONSTANTS.lineConfig.floorName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) || - ((DragedPoint.userData.type === CONSTANTS.lineConfig.aisleName) && point.userData.type === CONSTANTS.lineConfig.aisleName); - if (canSnap && point.uuid !== DragedPoint.uuid && point.visible) { - const distance = DragedPoint.position.distanceTo(point.position); - if (distance < snapThreshold) { - DragedPoint.position.copy(point.position); - } - } - }); - - const affectedLines = updateLinesPositions(DragedPoint, lines); - - updateLines(floorPlanGroupLine, affectedLines); - updateDistanceText(scene, floorPlanGroupLine, affectedLines); - updateFloorLines(onlyFloorlines, DragedPoint); -} - -export default DragPoint; \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/points/removeSoloPoint.ts b/app/src/modules/builder/geomentries/points/removeSoloPoint.ts deleted file mode 100644 index 56d3ee7..0000000 --- a/app/src/modules/builder/geomentries/points/removeSoloPoint.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as Types from "../../../../types/world/worldTypes"; - -function removeSoloPoint( - line: Types.RefLine, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroupPoint: Types.RefGroup -): void { - - ////////// Remove the point if there is only one point and if it is not connected to any other line and also the reference line ////////// - - if (line.current[0]) { - const pointUUID = line.current[0][1]; - let isConnected = false; - - floorPlanGroupLine.current.children.forEach((line) => { - 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); - } - }); - } - line.current = []; - } -} - -export default removeSoloPoint; diff --git a/app/src/modules/builder/geomentries/roofs/addRoofToScene.ts b/app/src/modules/builder/geomentries/roofs/addRoofToScene.ts deleted file mode 100644 index 4630efc..0000000 --- a/app/src/modules/builder/geomentries/roofs/addRoofToScene.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as THREE from 'three'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import * as Types from "../../../../types/world/worldTypes"; - -function addRoofToScene( - shape: Types.Shape, - floor: Types.Number, - userData: Types.UserData, - floorGroup: Types.RefGroup -): void { - - ////////// Creating a Polygon roof from the shape of the Polygon floor ////////// - - const extrudeSettings: THREE.ExtrudeGeometryOptions = { - depth: CONSTANTS.roofConfig.height, - bevelEnabled: false - }; - - const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); - const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide }); - const mesh = new THREE.Mesh(geometry, material); - mesh.position.y = CONSTANTS.wallConfig.height + floor; - mesh.castShadow = true; - mesh.receiveShadow = true; - mesh.rotateX(Math.PI / 2); - mesh.userData.uuids = userData; - mesh.name = `Roof_Layer_${(floor / CONSTANTS.wallConfig.height) + 1}`; - - floorGroup.current.add(mesh); -} - -export default addRoofToScene; diff --git a/app/src/modules/builder/geomentries/roofs/hideRoof.ts b/app/src/modules/builder/geomentries/roofs/hideRoof.ts deleted file mode 100644 index 8eb80f8..0000000 --- a/app/src/modules/builder/geomentries/roofs/hideRoof.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function hideRoof( - visibility: Types.Boolean, - floorGroup: Types.RefGroup, - camera: THREE.Camera -): void { - - ////////// Toggles the visibility of the roof based on the camera position and the Roof visibility button on UI ////////// - - const v = new THREE.Vector3(); - const u = new THREE.Vector3(); - - if (visibility === true && floorGroup.current) { - for (const child of floorGroup.current.children) { - if (child.name.includes("Roof")) { - const roofChild = child as Types.Mesh; - roofChild.getWorldDirection(v); - camera?.getWorldDirection(u); - if (roofChild.material) { - const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material]; - materials.forEach(material => { - material.visible = v.dot(u) < 0.25; - }); - } - } - } - } else { - if (floorGroup.current) { - for (const child of floorGroup.current.children) { - if (child.name.includes("Roof")) { - const roofChild = child as Types.Mesh; - if (roofChild.material) { - const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material]; - materials.forEach(material => { - material.visible = false; - }); - } - } - } - } - } -} - -export default hideRoof; diff --git a/app/src/modules/builder/geomentries/walls/addWallItems.ts b/app/src/modules/builder/geomentries/walls/addWallItems.ts deleted file mode 100644 index 809b093..0000000 --- a/app/src/modules/builder/geomentries/walls/addWallItems.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; -import { toast } from "react-toastify"; -import * as THREE from "three"; -import * as Types from "../../../../types/world/worldTypes"; -import * as CONSTANTS from "../../../../types/world/worldConstants"; -import { Socket } from "socket.io-client"; -import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils"; -import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; -import { getUserData } from "../../../../functions/getUserData"; - -async function AddWallItems( - selected: any, - raycaster: THREE.Raycaster, - CSGGroup: Types.RefMesh, - setWallItems: Types.setWallItemSetState, - socket: Socket, - projectId?: string, - versionId?: string -): Promise { - - const { userId, organization } = getUserData(); - let intersects = raycaster?.intersectObject(CSGGroup.current!, true); - const wallRaycastIntersection = intersects?.find((child) => - child.object.name.includes("WallRaycastReference") - ); - let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - - if (!wallRaycastIntersection) return; - - const intersectionPoint = wallRaycastIntersection; - 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); - - // Check THREE.js cache first - const cachedModel = THREE.Cache.get(selected.id); - if (cachedModel) { - handleModelLoad(cachedModel); - return; - } - - // Check IndexedDB cache - const cachedModelBlob = await retrieveGLTF(selected.id); - if (cachedModelBlob) { - const blobUrl = URL.createObjectURL(cachedModelBlob); - loader.load(blobUrl, (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(selected.id, gltf); - handleModelLoad(gltf); - }); - return; - } - - // Load from backend if not in any cache - loader.load( - `${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`, - async (gltf) => { - try { - const modelBlob = await fetch( - `${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}` - ).then((res) => res.blob()); - await storeGLTF(selected.id, modelBlob); - THREE.Cache.add(selected.id, gltf); - await handleModelLoad(gltf); - } catch (error) { - console.error("Failed to cache model:", error); - handleModelLoad(gltf); - } - } - ); - - async function handleModelLoad(gltf: GLTF) { - const model = gltf.scene.clone(); - model.userData = { wall: intersectionPoint.object.parent }; - - model.children[0].children.forEach((child) => { - if (child.name !== "CSG_REF") { - child.castShadow = true; - child.receiveShadow = true; - } - }); - - const boundingBox = new THREE.Box3().setFromObject(model); - const size = new THREE.Vector3(); - boundingBox.getSize(size); - - const csgscale = [size.x, size.y, size.z] as [number, number, number]; - - const center = new THREE.Vector3(); - boundingBox.getCenter(center); - const csgposition = [center.x, center.y, center.z] as [ - number, - number, - number - ]; - - let positionY = - selected.subCategory === "fixed-move" ? 0 : intersectionPoint.point.y; - if (positionY === 0) { - positionY = - Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * - CONSTANTS.wallConfig.height; - } - - const newWallItem = { - type: selected.subCategory, - model: model, - modelName: selected.name, - assetId: selected.id, - scale: [1, 1, 1] as [number, number, number], - csgscale: csgscale, - csgposition: csgposition, - position: [ - intersectionPoint.point.x, - positionY, - intersectionPoint.point.z, - ] as [number, number, number], - quaternion: - intersectionPoint.object.quaternion.clone() as Types.QuaternionType, - }; - - const data = { - organization, - modelUuid: model.uuid, - modelName: newWallItem.modelName, - assetId: selected.id, - type: selected.subCategory, - csgposition: newWallItem.csgposition, - csgscale: newWallItem.csgscale, - position: newWallItem.position, - quaternion: newWallItem.quaternion, - scale: newWallItem.scale, - socketId: socket.id, - versionId, - projectId, - userId, - }; - - socket.emit("v1:wallItems:set", data); - - setWallItems((prevItems) => { - const updatedItems = [...prevItems, newWallItem]; - - const WallItemsForStorage = updatedItems.map((item) => { - const { model, ...rest } = item; - return { - ...rest, - modelUuid: model?.uuid, - }; - }); - - localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); - echo.success("Model Added!"); - return updatedItems; - }); - } -} - -export default AddWallItems; diff --git a/app/src/modules/builder/geomentries/walls/deleteWallItems.ts b/app/src/modules/builder/geomentries/walls/deleteWallItems.ts deleted file mode 100644 index 5d16e91..0000000 --- a/app/src/modules/builder/geomentries/walls/deleteWallItems.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { getUserData } from "../../../../functions/getUserData"; -import * as Types from "../../../../types/world/worldTypes"; -// import { deleteWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/deleteWallItemApi'; -import { Socket } from "socket.io-client"; - -function DeleteWallItems( - hoveredDeletableWallItem: Types.RefMesh, - setWallItems: Types.setWallItemSetState, - wallItems: Types.wallItems, - socket: Socket, - projectId?: string, - versionId? : string, -): void { - ////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage ////////// - const { userId, organization, email } = getUserData(); - if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current) { - setWallItems([]); - let WallItemsRef = wallItems; - const removedItem = WallItemsRef.find( - (item) => item.model?.uuid === hoveredDeletableWallItem.current?.uuid - ); - const Items = WallItemsRef.filter( - (item) => item.model?.uuid !== hoveredDeletableWallItem.current?.uuid - ); - - setTimeout(async () => { - WallItemsRef = Items; - setWallItems(WallItemsRef); - - //REST - - // await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!) - - //SOCKET - - const data = { - organization, - modelUuid: removedItem?.model?.uuid!, - modelName: removedItem?.modelName!, - socketId: socket.id, - projectId, - versionId, - userId, - }; - - socket.emit("v1:wallItems:delete", data); - - const WallItemsForStorage = WallItemsRef.map((item) => { - const { model, ...rest } = item; - return { - ...rest, - modelUuid: model?.uuid, - }; - }); - - localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); - hoveredDeletableWallItem.current = null; - }, 50); - } -} - -export default DeleteWallItems; diff --git a/app/src/modules/builder/geomentries/walls/hideWalls.ts b/app/src/modules/builder/geomentries/walls/hideWalls.ts deleted file mode 100644 index 02233b0..0000000 --- a/app/src/modules/builder/geomentries/walls/hideWalls.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as THREE from 'three'; -import * as Types from "../../../../types/world/worldTypes"; - -function hideWalls( - visibility: Types.Boolean, - scene: THREE.Scene, - camera: THREE.Camera -): void { - const wallNormal = new THREE.Vector3(); - const cameraToWall = new THREE.Vector3(); - const cameraDirection = new THREE.Vector3(); - - if (visibility === true) { - for (const children of scene.children) { - if (children.name === "Walls" && children.children[0]?.children.length > 0) { - children.children[0].children.forEach((child: any) => { - if (child.children[0]?.userData.WallType === "RoomWall") { - const wallMesh = child.children[0]; - wallMesh.getWorldDirection(wallNormal); - cameraToWall.copy(wallMesh.position).sub(camera.position).normalize(); - camera.getWorldDirection(cameraDirection); - const isFacingCamera = wallNormal.dot(cameraToWall) > 0; - const isInFrontOfCamera = cameraDirection.dot(cameraToWall) > -0.3; - - if (wallMesh.material) { - wallMesh.material.visible = isFacingCamera && isInFrontOfCamera; - } - } - }); - } - } - } else { - for (const children of scene.children) { - if (children.name === "Walls" && children.children[0]?.children.length > 0) { - children.children[0].children.forEach((child: any) => { - if (child.children[0]?.userData.WallType === "RoomWall" && child.children[0].material) { - child.children[0].material.visible = true; - } - }); - } - } - } -} - -export default hideWalls; \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/walls/loadWalls.ts b/app/src/modules/builder/geomentries/walls/loadWalls.ts deleted file mode 100644 index 14d72c4..0000000 --- a/app/src/modules/builder/geomentries/walls/loadWalls.ts +++ /dev/null @@ -1,140 +0,0 @@ -import * as THREE from 'three'; -import * as turf from '@turf/turf'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; - -import * as Types from "../../../../types/world/worldTypes"; -import getRoomsFromLines from '../lines/getRoomsFromLines'; - -async function loadWalls( - lines: Types.RefLines, - setWalls: any, -): Promise { - ////////// Removes the old walls if any, Checks if there is any overlapping in lines if any updates it , starts function that creates floor and roof ////////// - - const Walls: Types.Walls = []; - const Rooms: Types.Rooms = []; - - localStorage.setItem("Lines", JSON.stringify(lines.current)); - - if (lines.current.length > 1) { - - ////////// Add Walls that are forming a room ////////// - - const wallSet = new Set(); - - const rooms: Types.Rooms = await getRoomsFromLines(lines); - Rooms.push(...rooms); - - Rooms.forEach(({ coordinates: room, layer }) => { - for (let i = 0; i < room.length - 1; i++) { - const uuid1 = room[i].uuid; - const uuid2 = room[(i + 1) % room.length].uuid; - const wallId = `${uuid1}_${uuid2}`; - - if (!wallSet.has(wallId)) { - const p1 = room[i].position; - const p2 = room[(i + 1) % room.length].position; - - const shape = new THREE.Shape(); - shape.moveTo(0, 0); - shape.lineTo(0, CONSTANTS.wallConfig.height); - shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height); - shape.lineTo(p2.distanceTo(p1), 0); - shape.lineTo(0, 0); - - const extrudeSettings = { - depth: CONSTANTS.wallConfig.width, - bevelEnabled: false - }; - const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); - const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x); - Walls.push([geometry, [0, -angle, 0], [p1.x, (layer - 1) * CONSTANTS.wallConfig.height, p1.z], "RoomWall", layer]); - - wallSet.add(wallId); - } - } - }); - - ////////// Add Walls that are not forming any room ////////// - - lines.current.forEach(line => { - if (line[0][3] && line[1][3] !== CONSTANTS.lineConfig.wallName) { - return; - } - const [uuid1, uuid2] = line.map(point => point[1]); - let isInRoom = false; - const lineLayer = line[0][2]; - - for (let room of Rooms) { - const roomLayer = room.layer; - if (roomLayer !== lineLayer) continue; - for (let i = 0; i < room.coordinates.length - 1; i++) { - const roomUuid1 = room.coordinates[i].uuid; - const roomUuid2 = room.coordinates[(i + 1) % room.coordinates.length].uuid; - if ( - (uuid1 === roomUuid1 && uuid2 === roomUuid2) || - (uuid1 === roomUuid2 && uuid2 === roomUuid1) - ) { - isInRoom = true; - break; - } - } - if (isInRoom) break; - } - - if (!isInRoom) { - const p1 = new THREE.Vector3(line[0][0].x, 0, line[0][0].z); - const p2 = new THREE.Vector3(line[1][0].x, 0, line[1][0].z); - - let isCollinear = false; - for (let room of Rooms) { - if (room.layer !== lineLayer) continue; - for (let i = 0; i < room.coordinates.length - 1; i++) { - const roomP1 = room.coordinates[i].position; - const roomP2 = room.coordinates[(i + 1) % room.coordinates.length].position; - const lineFeature = turf.lineString([[p1.x, p1.z], [p2.x, p2.z]]); - const roomFeature = turf.lineString([[roomP1.x, roomP1.z], [roomP2.x, roomP2.z]]); - if (turf.booleanOverlap(lineFeature, roomFeature)) { - isCollinear = true; - break; - } - } - if (isCollinear) break; - } - - if (!isCollinear) { - const shape = new THREE.Shape(); - shape.moveTo(0, 0); - shape.lineTo(0, CONSTANTS.wallConfig.height); - shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height); - shape.lineTo(p2.distanceTo(p1), 0); - shape.lineTo(0, 0); - - const extrudeSettings = { - depth: CONSTANTS.wallConfig.width, - bevelEnabled: false - }; - const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); - const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x); - Walls.push([geometry, [0, -angle, 0], [p1.x, (lineLayer - 1) * CONSTANTS.wallConfig.height, p1.z], "SegmentWall", lineLayer]); - } - } - }); - setWalls(Walls); - } else { - setWalls([]); - } -} - -export default loadWalls; - - -// A----- B----- C -// | | | -// | | | -// | | | -// F----- E----- D - -// 1. A -> B, B -> C, C -> D, D -> E, E -> F, F -> A, B -> E - -// 2. E -> F, F -> A, A -> B, B -> E, E -> D, D -> C, C -> B \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/zones/addZonesToScene.ts b/app/src/modules/builder/geomentries/zones/addZonesToScene.ts deleted file mode 100644 index 2832c7a..0000000 --- a/app/src/modules/builder/geomentries/zones/addZonesToScene.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as THREE from 'three'; -import * as Types from '../../../../types/world/worldTypes'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; - -const baseMaterial = new THREE.ShaderMaterial({ - side: THREE.DoubleSide, - vertexShader: ` - varying vec2 vUv; - void main(){ - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - vUv = uv; - } - `, - fragmentShader: ` - varying vec2 vUv; - uniform vec3 uOuterColor; - void main(){ - float alpha = 1.0 - vUv.y; - gl_FragColor = vec4(uOuterColor, alpha); - } - `, - uniforms: { - uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.defaultColor) }, - }, - transparent: true, -}); - -export default function addZonesToScene( - line: Types.Line, - floorGroupZone: Types.RefGroup, - color: THREE.Color -) { - const point1 = line[0][0]; - const point2 = line[1][0]; - - const length = (new THREE.Vector3(point2.x, point2.y, point2.z)).distanceTo(new THREE.Vector3(point1.x, point1.y, point1.z)); - const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x); - - const geometry = new THREE.PlaneGeometry(length, 10); - - const material = baseMaterial.clone(); - material.uniforms.uOuterColor.value.set(color.r, color.g, color.b); - - const mesh = new THREE.Mesh(geometry, material); - - mesh.position.set((point1.x + point2.x) / 2, ((line[0][2] - 1) * CONSTANTS.wallConfig.height) + 5, (point1.z + point2.z) / 2); - mesh.rotation.y = -angle; - - floorGroupZone.current.add(mesh); -} diff --git a/app/src/modules/builder/geomentries/zones/loadZones.ts b/app/src/modules/builder/geomentries/zones/loadZones.ts deleted file mode 100644 index aa78199..0000000 --- a/app/src/modules/builder/geomentries/zones/loadZones.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as Types from '../../../../types/world/worldTypes'; -import * as THREE from 'three'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; -import addZonesToScene from './addZonesToScene'; - -export default function loadZones( - lines: Types.RefLines, - floorGroupZone: Types.RefGroup -) { - if (!floorGroupZone.current) return - floorGroupZone.current.children = []; - const zones = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.zoneName); - - if (zones.length > 0) { - zones.forEach((zone: Types.Line) => { - addZonesToScene(zone, floorGroupZone, new THREE.Color(CONSTANTS.zoneConfig.color)) - }) - } -} \ No newline at end of file diff --git a/app/src/modules/builder/groups/floorGroup.tsx b/app/src/modules/builder/groups/floorGroup.tsx deleted file mode 100644 index 4af21b9..0000000 --- a/app/src/modules/builder/groups/floorGroup.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { useFrame, useThree } from "@react-three/fiber"; -import { - useAddAction, - useRoofVisibility, - useToggleView, - useWallVisibility, - useUpdateScene, - useRenameModeStore, - useToolMode, -} from "../../../store/builder/store"; -import hideRoof from "../geomentries/roofs/hideRoof"; -import hideWalls from "../geomentries/walls/hideWalls"; -import addAndUpdateReferencePillar from "../geomentries/pillars/addAndUpdateReferencePillar"; -import { useEffect } from "react"; -import addPillar from "../geomentries/pillars/addPillar"; -import DeletePillar from "../geomentries/pillars/deletePillar"; -import DeletableHoveredPillar from "../geomentries/pillars/deletableHoveredPillar"; -import loadFloor from "../geomentries/floors/loadFloor"; -import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore"; - -const FloorGroup = ({ - floorGroup, - lines, - referencePole, - hoveredDeletablePillar, -}: any) => { - const state = useThree(); - const { roofVisibility } = useRoofVisibility(); - const { wallVisibility } = useWallVisibility(); - const { toggleView } = useToggleView(); - const { scene, camera, raycaster, gl } = useThree(); - const { addAction } = useAddAction(); - const { toolMode } = useToolMode(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { setTop } = useTopData(); - const { setLeft } = useLeftData(); - const { isRenameMode, setIsRenameMode } = useRenameModeStore(); - - useEffect(() => { - if (updateScene) { - loadFloor(lines, floorGroup); - setUpdateScene(false); - } - }, [updateScene]); - - useEffect(() => { - if (!addAction) { - if (referencePole.current) { - (referencePole.current as any).material.dispose(); - (referencePole.current.geometry as any).dispose(); - floorGroup.current.remove(referencePole.current); - referencePole.current = undefined; - } - } - }, [addAction]); - - 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) => { - setIsRenameMode(false); - if (evt.button === 0) { - isLeftMouseDown = false; - if (!drag) { - if (addAction === "pillar") { - addPillar(referencePole, floorGroup); - } - if (toolMode === '3D-Delete') { - DeletePillar(hoveredDeletablePillar, floorGroup); - } - } - } - }; - - const onMouseMove = (evt: any) => { - if (!canvasElement) return; - const canvasRect = canvasElement.getBoundingClientRect(); - const relativeX = evt.clientX - canvasRect.left; - const relativeY = evt.clientY - canvasRect.top; - // if (!isRenameMode) { - // setTop(relativeY); - // setLeft(relativeX); - // } - if (isLeftMouseDown) { - drag = true; - } - }; - - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - }; - }, [toolMode, addAction, isRenameMode]); - - useFrame(() => { - hideRoof(roofVisibility, floorGroup, camera); - hideWalls(wallVisibility, scene, camera); - - if (addAction === "pillar") { - addAndUpdateReferencePillar(raycaster, floorGroup, referencePole); - } - if (toolMode === '3D-Delete') { - DeletableHoveredPillar(state, floorGroup, hoveredDeletablePillar); - } - }); - - return ( - - ); -}; - -export default FloorGroup; diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx deleted file mode 100644 index a9a845e..0000000 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import { useEffect } from "react"; -import * as Types from '../../../types/world/worldTypes'; -import { useActiveLayer, useDeletedLines, useToolMode, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/builder/store"; -import Layer2DVisibility from "../geomentries/layers/layer2DVisibility"; -import { useFrame, useThree } from "@react-three/fiber"; -import DeletableLineorPoint from "../functions/deletableLineOrPoint"; -import removeSoloPoint from "../geomentries/points/removeSoloPoint"; -import removeReferenceLine from "../geomentries/lines/removeReferenceLine"; -import DeleteLayer from "../geomentries/layers/deleteLayer"; -import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi"; -import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray"; -import loadInitialPoint from "../IntialLoad/loadInitialPoint"; -import loadInitialLine from "../IntialLoad/loadInitialLine"; -import deletePoint from "../geomentries/points/deletePoint"; -import deleteLine from "../geomentries/lines/deleteLine"; -import drawWall from "../geomentries/lines/drawWall"; -import drawOnlyFloor from "../geomentries/floors/drawOnlyFloor"; -import addDragControl from "../eventDeclaration/dragControlDeclaration"; -import { useParams } from "react-router-dom"; -import { getUserData } from "../../../functions/getUserData"; -import { useVersionContext } from "../version/versionContext"; - -const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, floorGroup, currentLayerPoint, dragPointControls, hoveredDeletablePoint, hoveredDeletableLine, plane, line, lines, onlyFloorline, onlyFloorlines, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => { - const state = useThree(); - const { camera, gl, raycaster, controls } = state; - const { activeLayer } = useActiveLayer(); - const { toggleView } = useToggleView(); - const { toolMode } = useToolMode(); - const { removedLayer, setRemovedLayer } = useRemovedLayer(); - const { setUpdateScene } = useUpdateScene(); - const { setNewLines } = useNewLines(); - const { setDeletedLines } = useDeletedLines(); - const { socket } = useSocketStore(); - const { selectedVersionStore } = useVersionContext(); - const { selectedVersion } = selectedVersionStore(); - const { projectId } = useParams(); - const { organization } = getUserData(); - - useEffect(() => { - if (toolMode === 'move') { - addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket, projectId, selectedVersion?.versionId || '',); - } - - return () => { - if (dragPointControls.current) { - dragPointControls.current.enabled = false; - } - }; - }, [toolMode, state]); - - useEffect(() => { - if (!selectedVersion) return; - - getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => { - - const Lines: Types.Lines = objectLinesToArray(data); - - if (Lines) { - lines.current = Lines; - loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls); - loadInitialLine(floorPlanGroupLine, lines); - setUpdateScene(true); - } - }) - }, [selectedVersion?.versionId]); - - useEffect(() => { - if (!toggleView) { - removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint); - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - }, [toggleView]); - - useEffect(() => { - removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint); - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - }, [toolMode]); - - useEffect(() => { - if (toolMode === 'move' && toggleView) { - if (dragPointControls.current) { - dragPointControls.current.enabled = true; - } - } else { - if (dragPointControls.current) { - dragPointControls.current.enabled = false; - } - } - }, [toolMode, toggleView, state]); - - useEffect(() => { - Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls); - }, [activeLayer]); - - useEffect(() => { - if (removedLayer !== null) { - DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket, projectId, selectedVersion?.versionId || '',); - } - }, [removedLayer]); - - 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; - } - if (controls) { - (controls as any).enabled = true; - } - } - - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - }; - - const onContextMenu = (e: any) => { - e.preventDefault(); - if (toolMode === "Wall" || toolMode === "Floor") { - removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint); - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - }; - - const onMouseClick = (evt: any) => { - if (!plane.current || drag) return; - - if (toolMode === "2D-Delete") { - if (hoveredDeletablePoint.current !== null) { - deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',); - } - if (hoveredDeletableLine.current !== null) { - deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',); - } - } - - if (toolMode === "Wall") { - // drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); - } - - if (toolMode === "Floor") { - // drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); - } - } - - if (toolMode === "2D-Delete" || toolMode === "Wall" || toolMode === "Floor") { - 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, activeLayer]) - - - useFrame(() => { - if (toolMode === '2D-Delete') { - DeletableLineorPoint(state, plane, floorPlanGroupLine, floorPlanGroupPoint, hoveredDeletableLine, hoveredDeletablePoint); - } - }) - - return ( - - - - - ) -} - -export default FloorPlanGroup; \ No newline at end of file diff --git a/app/src/modules/builder/groups/wallItemsGroup.tsx b/app/src/modules/builder/groups/wallItemsGroup.tsx index 210377b..28f4f4b 100644 --- a/app/src/modules/builder/groups/wallItemsGroup.tsx +++ b/app/src/modules/builder/groups/wallItemsGroup.tsx @@ -1,291 +1,291 @@ -import { useEffect } from "react"; -import { - useObjectPosition, - useObjectRotation, - useSelectedWallItem, - useSocketStore, - useWallItems, - useSelectedItem, - useToolMode, -} from "../../../store/builder/store"; -import { Csg } from "../csg/csg"; -import * as Types from "../../../types/world/worldTypes"; -import * as CONSTANTS from "../../../types/world/worldConstants"; -import * as THREE from "three"; -import { useThree } from "@react-three/fiber"; -import handleMeshMissed from "../eventFunctions/handleMeshMissed"; -import DeleteWallItems from "../geomentries/walls/deleteWallItems"; -import loadInitialWallItems from "../IntialLoad/loadInitialWallItems"; -import AddWallItems from "../geomentries/walls/addWallItems"; -import useModuleStore from "../../../store/useModuleStore"; -import { useParams } from "react-router-dom"; -import { getUserData } from "../../../functions/getUserData"; -import { useVersionContext } from "../version/versionContext"; +// import { useEffect } from "react"; +// import { +// useObjectPosition, +// useObjectRotation, +// useSelectedWallItem, +// useSocketStore, +// useWallItems, +// useSelectedItem, +// useToolMode, +// } from "../../../store/builder/store"; +// import { Csg } from "../csg/csg"; +// import * as Types from "../../../types/world/worldTypes"; +// import * as CONSTANTS from "../../../types/world/worldConstants"; +// import * as THREE from "three"; +// import { useThree } from "@react-three/fiber"; +// import handleMeshMissed from "../eventFunctions/handleMeshMissed"; +// import DeleteWallItems from "../geomentries/walls/deleteWallItems"; +// import loadInitialWallItems from "../IntialLoad/loadInitialWallItems"; +// import AddWallItems from "../geomentries/walls/addWallItems"; +// import useModuleStore from "../../../store/useModuleStore"; +// import { useParams } from "react-router-dom"; +// import { getUserData } from "../../../functions/getUserData"; +// import { useVersionContext } from "../version/versionContext"; -const WallItemsGroup = ({ - currentWallItem, - hoveredDeletableWallItem, - selectedItemsIndex, - setSelectedItemsIndex, - CSGGroup, -}: any) => { - const state = useThree(); - const { socket } = useSocketStore(); - const { pointer, camera, raycaster } = state; - const { toolMode } = useToolMode(); - const { wallItems, setWallItems } = useWallItems(); - const { setObjectPosition } = useObjectPosition(); - const { setObjectRotation } = useObjectRotation(); - const { setSelectedWallItem } = useSelectedWallItem(); - const { activeModule } = useModuleStore(); - const { selectedItem } = useSelectedItem(); - const { selectedVersionStore } = useVersionContext(); - const { selectedVersion } = selectedVersionStore(); - const { projectId } = useParams(); - const { userId, organization } = getUserData(); +// const WallItemsGroup = ({ +// currentWallItem, +// hoveredDeletableWallItem, +// selectedItemsIndex, +// setSelectedItemsIndex, +// CSGGroup, +// }: any) => { +// const state = useThree(); +// const { socket } = useSocketStore(); +// const { pointer, camera, raycaster } = state; +// const { toolMode } = useToolMode(); +// const { wallItems, setWallItems } = useWallItems(); +// const { setObjectPosition } = useObjectPosition(); +// const { setObjectRotation } = useObjectRotation(); +// const { setSelectedWallItem } = useSelectedWallItem(); +// const { activeModule } = useModuleStore(); +// const { selectedItem } = useSelectedItem(); +// const { selectedVersionStore } = useVersionContext(); +// const { selectedVersion } = selectedVersionStore(); +// const { projectId } = useParams(); +// const { userId, organization } = getUserData(); - useEffect(() => { - // Load Wall Items from the backend - if (!projectId || !selectedVersion) return; - loadInitialWallItems(setWallItems, projectId, selectedVersion?.versionId); - }, [selectedVersion?.versionId]); +// useEffect(() => { +// // Load Wall Items from the backend +// if (!projectId || !selectedVersion) return; +// loadInitialWallItems(setWallItems, projectId, selectedVersion?.versionId); +// }, [selectedVersion?.versionId]); - ////////// Update the Position value changes in the selected item ////////// +// ////////// Update the Position value changes in the selected item ////////// - useEffect(() => { - const canvasElement = state.gl.domElement; - function handlePointerMove(e: any) { - if (selectedItemsIndex !== null && toolMode === 'cursor' && e.buttons === 1) { - const Raycaster = state.raycaster; - const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true); - const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference")); +// useEffect(() => { +// const canvasElement = state.gl.domElement; +// function handlePointerMove(e: any) { +// if (selectedItemsIndex !== null && toolMode === 'cursor' && e.buttons === 1) { +// const Raycaster = state.raycaster; +// const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true); +// const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference")); - if (Object) { - (state.controls as any)!.enabled = false; - setWallItems((prevItems: any) => { - const updatedItems = [...prevItems]; - let position: [number, number, number] = [0, 0, 0]; +// if (Object) { +// (state.controls as any)!.enabled = false; +// setWallItems((prevItems: any) => { +// const updatedItems = [...prevItems]; +// let position: [number, number, number] = [0, 0, 0]; - if (updatedItems[selectedItemsIndex].type === "fixed-move") { - position = [ - Object!.point.x, - Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) * - CONSTANTS.wallConfig.height, - Object!.point.z, - ]; - } else if (updatedItems[selectedItemsIndex].type === "free-move") { - position = [Object!.point.x, Object!.point.y, Object!.point.z]; - } +// if (updatedItems[selectedItemsIndex].type === "fixed-move") { +// position = [ +// Object!.point.x, +// Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) * +// CONSTANTS.wallConfig.height, +// Object!.point.z, +// ]; +// } else if (updatedItems[selectedItemsIndex].type === "free-move") { +// position = [Object!.point.x, Object!.point.y, Object!.point.z]; +// } - requestAnimationFrame(() => { - setObjectPosition(new THREE.Vector3(...position)); - setObjectRotation({ - x: THREE.MathUtils.radToDeg(Object!.object.rotation.x), - y: THREE.MathUtils.radToDeg(Object!.object.rotation.y), - z: THREE.MathUtils.radToDeg(Object!.object.rotation.z), - }); - }); +// requestAnimationFrame(() => { +// setObjectPosition(new THREE.Vector3(...position)); +// setObjectRotation({ +// x: THREE.MathUtils.radToDeg(Object!.object.rotation.x), +// y: THREE.MathUtils.radToDeg(Object!.object.rotation.y), +// z: THREE.MathUtils.radToDeg(Object!.object.rotation.z), +// }); +// }); - updatedItems[selectedItemsIndex] = { - ...updatedItems[selectedItemsIndex], - position: position, - quaternion: Object!.object.quaternion.clone() as Types.QuaternionType, - }; +// updatedItems[selectedItemsIndex] = { +// ...updatedItems[selectedItemsIndex], +// position: position, +// quaternion: Object!.object.quaternion.clone() as Types.QuaternionType, +// }; - return updatedItems; - }); - } - } - } +// return updatedItems; +// }); +// } +// } +// } - async function handlePointerUp() { - const Raycaster = state.raycaster; - const intersects = Raycaster.intersectObjects( - CSGGroup.current?.children[0].children!, - true - ); - const Object = intersects.find((child) => - child.object.name.includes("WallRaycastReference") - ); - if (Object) { - if (selectedItemsIndex !== null) { - let currentItem: any = null; - setWallItems((prevItems: any) => { - const updatedItems = [...prevItems]; - const WallItemsForStorage = updatedItems.map((item) => { - const { model, ...rest } = item; - return { - ...rest, - modelUuid: model?.uuid, - }; - }); +// async function handlePointerUp() { +// const Raycaster = state.raycaster; +// const intersects = Raycaster.intersectObjects( +// CSGGroup.current?.children[0].children!, +// true +// ); +// const Object = intersects.find((child) => +// child.object.name.includes("WallRaycastReference") +// ); +// if (Object) { +// if (selectedItemsIndex !== null) { +// let currentItem: any = null; +// setWallItems((prevItems: any) => { +// const updatedItems = [...prevItems]; +// const WallItemsForStorage = updatedItems.map((item) => { +// const { model, ...rest } = item; +// return { +// ...rest, +// modelUuid: model?.uuid, +// }; +// }); - currentItem = updatedItems[selectedItemsIndex]; - localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); - return updatedItems; - }); +// currentItem = updatedItems[selectedItemsIndex]; +// localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); +// return updatedItems; +// }); - setTimeout(async () => { +// setTimeout(async () => { - //REST +// //REST - // await setWallItem( - // organization, - // currentItem?.model?.uuid, - // currentItem.modelName, - // currentItem.assetId, - // currentItem.type!, - // currentItem.csgposition!, - // currentItem.csgscale!, - // currentItem.position, - // currentItem.quaternion, - // currentItem.scale!, - // ) +// // await setWallItem( +// // organization, +// // currentItem?.model?.uuid, +// // currentItem.modelName, +// // currentItem.assetId, +// // currentItem.type!, +// // currentItem.csgposition!, +// // currentItem.csgscale!, +// // currentItem.position, +// // currentItem.quaternion, +// // currentItem.scale!, +// // ) - //SOCKET +// //SOCKET - const data = { - organization, - modelUuid: currentItem.model?.uuid!, - assetId: currentItem.assetId, - modelName: currentItem.modelName!, - type: currentItem.type!, - csgposition: currentItem.csgposition!, - csgscale: currentItem.csgscale!, - position: currentItem.position!, - quaternion: currentItem.quaternion, - scale: currentItem.scale!, - socketId: socket.id, - versionId: selectedVersion?.versionId || '', - projectId, - userId - }; +// const data = { +// organization, +// modelUuid: currentItem.model?.uuid!, +// assetId: currentItem.assetId, +// modelName: currentItem.modelName!, +// type: currentItem.type!, +// csgposition: currentItem.csgposition!, +// csgscale: currentItem.csgscale!, +// position: currentItem.position!, +// quaternion: currentItem.quaternion, +// scale: currentItem.scale!, +// socketId: socket.id, +// versionId: selectedVersion?.versionId || '', +// projectId, +// userId +// }; - // console.log('data: ', data); - socket.emit("v1:wallItems:set", data); - }, 0); - (state.controls as any)!.enabled = true; - } - } - } +// // console.log('data: ', data); +// socket.emit("v1:wallItems:set", data); +// }, 0); +// (state.controls as any)!.enabled = true; +// } +// } +// } - canvasElement.addEventListener("pointermove", handlePointerMove); - canvasElement.addEventListener("pointerup", handlePointerUp); +// canvasElement.addEventListener("pointermove", handlePointerMove); +// canvasElement.addEventListener("pointerup", handlePointerUp); - return () => { - canvasElement.removeEventListener("pointermove", handlePointerMove); - canvasElement.removeEventListener("pointerup", handlePointerUp); - }; - }, [selectedItemsIndex, selectedVersion?.versionId]); +// return () => { +// canvasElement.removeEventListener("pointermove", handlePointerMove); +// canvasElement.removeEventListener("pointerup", handlePointerUp); +// }; +// }, [selectedItemsIndex, selectedVersion?.versionId]); - useEffect(() => { - const canvasElement = state.gl.domElement; - let drag = false; - let isLeftMouseDown = false; +// useEffect(() => { +// const canvasElement = state.gl.domElement; +// let drag = false; +// let isLeftMouseDown = false; - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - } - }; +// const onMouseDown = (evt: any) => { +// if (evt.button === 0) { +// isLeftMouseDown = true; +// drag = false; +// } +// }; - const onMouseUp = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = false; - if (!drag && toolMode === '3D-Delete' && activeModule === "builder") { - DeleteWallItems( - hoveredDeletableWallItem, - setWallItems, - wallItems, - socket, - projectId, - selectedVersion?.versionId || '', - ); - } - } - }; +// const onMouseUp = (evt: any) => { +// if (evt.button === 0) { +// isLeftMouseDown = false; +// if (!drag && toolMode === '3D-Delete' && activeModule === "builder") { +// DeleteWallItems( +// hoveredDeletableWallItem, +// setWallItems, +// wallItems, +// socket, +// projectId, +// selectedVersion?.versionId || '', +// ); +// } +// } +// }; - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - }; +// const onMouseMove = () => { +// if (isLeftMouseDown) { +// drag = true; +// } +// }; - const onDrop = (event: any) => { - if (selectedItem.category !== 'Fenestration') return; +// const onDrop = (event: any) => { +// if (selectedItem.category !== 'Fenestration') return; - pointer.x = (event.clientX / window.innerWidth) * 2 - 1; - pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; +// pointer.x = (event.clientX / window.innerWidth) * 2 - 1; +// pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; - raycaster.setFromCamera(pointer, camera); +// raycaster.setFromCamera(pointer, camera); - if (selectedItem.id && selectedVersion && projectId) { - if (selectedItem.subCategory) { - AddWallItems( - selectedItem, - raycaster, - CSGGroup, - setWallItems, - socket, - projectId, - selectedVersion?.versionId || '', - ); - } - event.preventDefault(); - } - }; +// if (selectedItem.id && selectedVersion && projectId) { +// if (selectedItem.subCategory) { +// AddWallItems( +// selectedItem, +// raycaster, +// CSGGroup, +// setWallItems, +// socket, +// projectId, +// selectedVersion?.versionId || '', +// ); +// } +// event.preventDefault(); +// } +// }; - const onDragOver = (event: any) => { - event.preventDefault(); - }; +// const onDragOver = (event: any) => { +// event.preventDefault(); +// }; - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("drop", onDrop); - canvasElement.addEventListener("dragover", onDragOver); +// canvasElement.addEventListener("mousedown", onMouseDown); +// canvasElement.addEventListener("mouseup", onMouseUp); +// canvasElement.addEventListener("mousemove", onMouseMove); +// canvasElement.addEventListener("drop", onDrop); +// canvasElement.addEventListener("dragover", onDragOver); - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("drop", onDrop); - canvasElement.removeEventListener("dragover", onDragOver); - }; - }, [toolMode, wallItems, selectedItem, camera, selectedVersion?.versionId]); +// return () => { +// canvasElement.removeEventListener("mousedown", onMouseDown); +// canvasElement.removeEventListener("mouseup", onMouseUp); +// canvasElement.removeEventListener("mousemove", onMouseMove); +// canvasElement.removeEventListener("drop", onDrop); +// canvasElement.removeEventListener("dragover", onDragOver); +// }; +// }, [toolMode, wallItems, selectedItem, camera, selectedVersion?.versionId]); - useEffect(() => { - if (toolMode && activeModule === "builder") { - handleMeshMissed( - currentWallItem, - setSelectedWallItem, - setSelectedItemsIndex - ); - setSelectedWallItem(null); - setSelectedItemsIndex(null); - } - }, [toolMode]); +// useEffect(() => { +// if (toolMode && activeModule === "builder") { +// handleMeshMissed( +// currentWallItem, +// setSelectedWallItem, +// setSelectedItemsIndex +// ); +// setSelectedWallItem(null); +// setSelectedItemsIndex(null); +// } +// }, [toolMode]); - return ( - <> - {wallItems.map((item: Types.WallItem, index: number) => ( - - - - ))} - - ); -}; +// return ( +// <> +// {wallItems.map((item: Types.WallItem, index: number) => ( +// +// +// +// ))} +// +// ); +// }; -export default WallItemsGroup; +// export default WallItemsGroup; diff --git a/app/src/modules/builder/groups/wallsAndWallItems.tsx b/app/src/modules/builder/groups/wallsAndWallItems.tsx index d4d52ec..6961cf6 100644 --- a/app/src/modules/builder/groups/wallsAndWallItems.tsx +++ b/app/src/modules/builder/groups/wallsAndWallItems.tsx @@ -1,74 +1,74 @@ -import { Geometry } from "@react-three/csg"; -import { - useSelectedWallItem, - useToggleView, - useToolMode, - useWallItems, - useWalls, -} from "../../../store/builder/store"; -import handleMeshDown from "../eventFunctions/handleMeshDown"; -import handleMeshMissed from "../eventFunctions/handleMeshMissed"; -import WallsMesh from "./wallsMesh"; -import WallItemsGroup from "./wallItemsGroup"; +// import { Geometry } from "@react-three/csg"; +// import { +// useSelectedWallItem, +// useToggleView, +// useToolMode, +// useWallItems, +// useWalls, +// } from "../../../store/builder/store"; +// import handleMeshDown from "../eventFunctions/handleMeshDown"; +// import handleMeshMissed from "../eventFunctions/handleMeshMissed"; +// import WallsMesh from "./wallsMesh"; +// import WallItemsGroup from "./wallItemsGroup"; -const WallsAndWallItems = ({ - CSGGroup, - setSelectedItemsIndex, - selectedItemsIndex, - currentWallItem, - csg, - lines, - hoveredDeletableWallItem, -}: any) => { - const { walls } = useWalls(); - const { wallItems } = useWallItems(); - const { toggleView } = useToggleView(); - const { toolMode } = useToolMode(); - const { setSelectedWallItem } = useSelectedWallItem(); +// const WallsAndWallItems = ({ +// CSGGroup, +// setSelectedItemsIndex, +// selectedItemsIndex, +// currentWallItem, +// csg, +// lines, +// hoveredDeletableWallItem, +// }: any) => { +// const { walls } = useWalls(); +// const { wallItems } = useWallItems(); +// const { toggleView } = useToggleView(); +// const { toolMode } = useToolMode(); +// const { setSelectedWallItem } = useSelectedWallItem(); - return ( - { - if (toolMode === "cursor") { - handleMeshDown( - event, - currentWallItem, - setSelectedWallItem, - setSelectedItemsIndex, - wallItems, - toggleView - ); - } - }} - onPointerMissed={() => { - if (toolMode === "cursor") { - handleMeshMissed( - currentWallItem, - setSelectedWallItem, - setSelectedItemsIndex - ); - setSelectedWallItem(null); - setSelectedItemsIndex(null); - } - }} - > - - - - - - ); -}; +// return ( +// { +// if (toolMode === "cursor") { +// handleMeshDown( +// event, +// currentWallItem, +// setSelectedWallItem, +// setSelectedItemsIndex, +// wallItems, +// toggleView +// ); +// } +// }} +// onPointerMissed={() => { +// if (toolMode === "cursor") { +// handleMeshMissed( +// currentWallItem, +// setSelectedWallItem, +// setSelectedItemsIndex +// ); +// setSelectedWallItem(null); +// setSelectedItemsIndex(null); +// } +// }} +// > +// +// +// +// +// +// ); +// }; -export default WallsAndWallItems; +// export default WallsAndWallItems; diff --git a/app/src/modules/builder/groups/wallsMesh.tsx b/app/src/modules/builder/groups/wallsMesh.tsx index 6b22a8d..80468e5 100644 --- a/app/src/modules/builder/groups/wallsMesh.tsx +++ b/app/src/modules/builder/groups/wallsMesh.tsx @@ -1,82 +1,82 @@ -import * as THREE from "three"; -import * as Types from "../../../types/world/worldTypes"; -import * as CONSTANTS from "../../../types/world/worldConstants"; -import { Base } from "@react-three/csg"; -import { MeshDiscardMaterial } from "@react-three/drei"; -import { useUpdateScene, useWalls } from "../../../store/builder/store"; -import React, { useEffect } from "react"; -import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi"; -import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray"; -import loadWalls from "../geomentries/walls/loadWalls"; -import texturePath from "../../../assets/textures/floor/wall-tex.png"; -import { useParams } from "react-router-dom"; -import { getUserData } from "../../../functions/getUserData"; -import { useVersionContext } from "../version/versionContext"; +// import * as THREE from "three"; +// import * as Types from "../../../types/world/worldTypes"; +// import * as CONSTANTS from "../../../types/world/worldConstants"; +// import { Base } from "@react-three/csg"; +// import { MeshDiscardMaterial } from "@react-three/drei"; +// import { useUpdateScene, useWalls } from "../../../store/builder/store"; +// import React, { useEffect } from "react"; +// import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi"; +// import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray"; +// import loadWalls from "../geomentries/walls/loadWalls"; +// import texturePath from "../../../assets/textures/floor/wall-tex.png"; +// import { useParams } from "react-router-dom"; +// import { getUserData } from "../../../functions/getUserData"; +// import { useVersionContext } from "../version/versionContext"; -const WallsMeshComponent = ({ lines }: any) => { - const { walls, setWalls } = useWalls(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { projectId } = useParams(); - const { selectedVersionStore } = useVersionContext(); - const { selectedVersion } = selectedVersionStore(); - const { organization } = getUserData(); +// const WallsMeshComponent = ({ lines }: any) => { +// const { walls, setWalls } = useWalls(); +// const { updateScene, setUpdateScene } = useUpdateScene(); +// const { projectId } = useParams(); +// const { selectedVersionStore } = useVersionContext(); +// const { selectedVersion } = selectedVersionStore(); +// const { organization } = getUserData(); - useEffect(() => { - if (updateScene) { - if (!selectedVersion) { - setUpdateScene(false); - return; - }; - getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => { - const Lines: Types.Lines = objectLinesToArray(data); - localStorage.setItem("Lines", JSON.stringify(Lines)); +// useEffect(() => { +// if (updateScene) { +// if (!selectedVersion) { +// setUpdateScene(false); +// return; +// }; +// getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => { +// const Lines: Types.Lines = objectLinesToArray(data); +// localStorage.setItem("Lines", JSON.stringify(Lines)); - if (Lines) { - loadWalls(lines, setWalls); - } - }); - setUpdateScene(false); - } - }, [updateScene, selectedVersion?.versionId]); +// if (Lines) { +// loadWalls(lines, setWalls); +// } +// }); +// setUpdateScene(false); +// } +// }, [updateScene, selectedVersion?.versionId]); - const textureLoader = new THREE.TextureLoader(); - const wallTexture = textureLoader.load(texturePath); +// const textureLoader = new THREE.TextureLoader(); +// const wallTexture = textureLoader.load(texturePath); - wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping; - wallTexture.repeat.set(0.1, 0.1); - wallTexture.colorSpace = THREE.SRGBColorSpace; +// wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping; +// wallTexture.repeat.set(0.1, 0.1); +// wallTexture.colorSpace = THREE.SRGBColorSpace; - return ( - <> - {walls.map((wall: Types.Wall, index: number) => ( - - - - - - - - - ))} - - ); -}; +// return ( +// <> +// {walls.map((wall: Types.Wall, index: number) => ( +// +// +// +// +// +// +// +// +// ))} +// +// ); +// }; -const WallsMesh = React.memo(WallsMeshComponent); -export default WallsMesh; +// const WallsMesh = React.memo(WallsMeshComponent); +// export default WallsMesh; diff --git a/app/src/modules/builder/geomentries/lines/getClosestIntersection.ts b/app/src/modules/builder/line/helpers/getClosestIntersection.ts similarity index 96% rename from app/src/modules/builder/geomentries/lines/getClosestIntersection.ts rename to app/src/modules/builder/line/helpers/getClosestIntersection.ts index afae9d5..e5a803d 100644 --- a/app/src/modules/builder/geomentries/lines/getClosestIntersection.ts +++ b/app/src/modules/builder/line/helpers/getClosestIntersection.ts @@ -1,26 +1,26 @@ -import * as THREE from 'three'; - -import * as Types from "../../../../types/world/worldTypes"; - -function getClosestIntersection( - intersects: Types.Vector3Array, - point: Types.Vector3 -): Types.Vector3 { - - ////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing ////////// - - let closestNewPoint: THREE.Vector3 = point; - let minDistance = Infinity; - - for (const intersect of intersects) { - const distance = point.distanceTo(intersect); - if (distance < minDistance) { - minDistance = distance; - closestNewPoint = intersect; - } - } - - return closestNewPoint; -} - -export default getClosestIntersection; +import * as THREE from 'three'; + +import * as Types from "../../../../types/world/worldTypes"; + +function getClosestIntersection( + intersects: Types.Vector3Array, + point: Types.Vector3 +): Types.Vector3 { + + ////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing ////////// + + let closestNewPoint: THREE.Vector3 = point; + let minDistance = Infinity; + + for (const intersect of intersects) { + const distance = point.distanceTo(intersect); + if (distance < minDistance) { + minDistance = distance; + closestNewPoint = intersect; + } + } + + return closestNewPoint; +} + +export default getClosestIntersection; diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index f75be5d..5cf48bc 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -12,8 +12,8 @@ import { getUserData } from '../../../functions/getUserData'; // import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; // import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; -import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; -import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; +// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; +// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; interface LineProps { points: [Point, Point]; diff --git a/app/src/modules/builder/pillars/addAndUpdateReferencePillar.ts b/app/src/modules/builder/pillars/addAndUpdateReferencePillar.ts new file mode 100644 index 0000000..31407ee --- /dev/null +++ b/app/src/modules/builder/pillars/addAndUpdateReferencePillar.ts @@ -0,0 +1,54 @@ +// import * as THREE from 'three'; +// import updateReferencePolesheight from './updateReferencePolesheight'; + +// import * as Types from "../../../../types/world/worldTypes"; + +// function addAndUpdateReferencePillar( +// raycaster: THREE.Raycaster, +// floorGroup: Types.RefGroup, +// referencePole: Types.RefMesh +// ): void { + +// ////////// Find Pillars position and scale based on the pointer interaction ////////// + +// let Roofs = raycaster.intersectObjects(floorGroup.current.children, true); +// const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor")); + +// if (intersected) { +// const intersectionPoint = intersected.point; +// raycaster.ray.origin.copy(intersectionPoint); +// raycaster.ray.direction.set(0, -1, 0); +// const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true); +// const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor")); + +// let distance: Types.Number; + +// if (validIntersections.length > 1) { +// let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3); +// if (valid) { +// updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup); +// } else { +// const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z); +// distance = intersected.point.distanceTo(belowPoint); +// if (distance > 3) { +// updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup); +// } +// } +// } else { +// const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z); +// distance = intersected.point.distanceTo(belowPoint); +// if (distance > 3) { +// updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup); +// } +// } +// } else { +// if (referencePole.current) { +// (referencePole.current.material).dispose(); +// (referencePole.current.geometry).dispose(); +// floorGroup.current.remove(referencePole.current); +// referencePole.current = null; +// } +// } +// } + +// export default addAndUpdateReferencePillar; diff --git a/app/src/modules/builder/pillars/addPillar.ts b/app/src/modules/builder/pillars/addPillar.ts new file mode 100644 index 0000000..9839f16 --- /dev/null +++ b/app/src/modules/builder/pillars/addPillar.ts @@ -0,0 +1,24 @@ +// import * as THREE from 'three'; +// import * as CONSTANTS from '../../../../types/world/worldConstants'; +// import * as Types from "../../../../types/world/worldTypes"; + +// function addPillar( +// referencePole: Types.RefMesh, +// floorGroup: Types.RefGroup +// ): void { + +// ////////// Add Pillars to the scene based on the reference. current poles position and scale ////////// + +// if (referencePole.current) { +// let pole: THREE.Mesh; +// const geometry = referencePole.current.userData.geometry.clone(); +// const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor }); +// pole = new THREE.Mesh(geometry, material); +// pole.rotateX(Math.PI / 2); +// pole.name = "Pole"; +// pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z); +// floorGroup.current.add(pole); +// } +// } + +// export default addPillar; \ No newline at end of file diff --git a/app/src/modules/builder/pillars/deletableHoveredPillar.ts b/app/src/modules/builder/pillars/deletableHoveredPillar.ts new file mode 100644 index 0000000..1751fdb --- /dev/null +++ b/app/src/modules/builder/pillars/deletableHoveredPillar.ts @@ -0,0 +1,34 @@ +// import * as THREE from 'three'; + +// import * as Types from "../../../../types/world/worldTypes"; + +// function DeletableHoveredPillar( +// state: Types.ThreeState, +// floorGroup: Types.RefGroup, +// hoveredDeletablePillar: Types.RefMesh +// ): void { + +// ////////// Altering the color of the hovered Pillar during the Deletion time ////////// + +// const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true); +// const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole"); + +// if (poleIntersect) { +// if (poleIntersect.object.name !== "Pole") { +// return; +// } +// if (hoveredDeletablePillar.current) { +// (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black"); +// hoveredDeletablePillar.current = undefined; +// } +// hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion +// (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red"); +// } else { +// if (hoveredDeletablePillar.current) { +// (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black"); +// hoveredDeletablePillar.current = undefined; +// } +// } +// } + +// export default DeletableHoveredPillar; \ No newline at end of file diff --git a/app/src/modules/builder/pillars/deletePillar.ts b/app/src/modules/builder/pillars/deletePillar.ts new file mode 100644 index 0000000..22fc9bf --- /dev/null +++ b/app/src/modules/builder/pillars/deletePillar.ts @@ -0,0 +1,21 @@ +// import { toast } from 'react-toastify'; + +// import * as Types from "../../../../types/world/worldTypes"; + +// function DeletePillar( +// hoveredDeletablePillar: Types.RefMesh, +// floorGroup: Types.RefGroup +// ): void { + +// ////////// Deleting the hovered Pillar from the itemsGroup ////////// + +// if (hoveredDeletablePillar.current) { +// (hoveredDeletablePillar.current.material).dispose(); +// (hoveredDeletablePillar.current.geometry).dispose(); +// floorGroup.current.remove(hoveredDeletablePillar.current); +// echo.success("Pillar Removed!"); +// hoveredDeletablePillar.current = undefined; +// } +// } + +// export default DeletePillar; diff --git a/app/src/modules/builder/pillars/updateReferencePolesheight.ts b/app/src/modules/builder/pillars/updateReferencePolesheight.ts new file mode 100644 index 0000000..eaffd76 --- /dev/null +++ b/app/src/modules/builder/pillars/updateReferencePolesheight.ts @@ -0,0 +1,40 @@ +// import * as THREE from 'three'; + +// import * as Types from "../../../../types/world/worldTypes"; + +// function updateReferencePolesheight( +// intersectionPoint: Types.Vector3, +// distance: Types.Number, +// referencePole: Types.RefMesh, +// floorGroup: Types.RefGroup +// ): void { + +// ////////// Add a Reference Pillar and update its position and scale based on the pointer interaction ////////// + +// if (referencePole.current) { +// (referencePole.current.material).dispose(); +// (referencePole.current.geometry).dispose(); +// floorGroup.current.remove(referencePole.current); +// referencePole.current.geometry.dispose(); +// } + +// const shape = new THREE.Shape(); +// shape.moveTo(0.5, 0); +// shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false); + +// const extrudeSettings = { +// depth: distance, +// bevelEnabled: false, +// }; + +// const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); +// const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 }); +// referencePole.current = new THREE.Mesh(geometry, material); +// referencePole.current.rotateX(Math.PI / 2); +// referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z); +// referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } }; + +// floorGroup.current.add(referencePole.current); +// } + +// export default updateReferencePolesheight; diff --git a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx index b31ad82..a80a62d 100644 --- a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx +++ b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx @@ -8,7 +8,7 @@ import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; import { useParams } from 'react-router-dom'; import { useVersionContext } from '../../version/versionContext'; import { getUserData } from '../../../../functions/getUserData'; -import getClosestIntersection from '../../geomentries/lines/getClosestIntersection'; +import getClosestIntersection from '../../line/helpers/getClosestIntersection'; import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceWall from './referenceWall'; diff --git a/app/src/modules/collaboration/socket/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx index 6028329..3f4bfdb 100644 --- a/app/src/modules/collaboration/socket/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx @@ -1,891 +1,9 @@ -import { useEffect } from "react"; -import * as THREE from "three"; -import gsap from "gsap"; -import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; -import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; -import { - useSocketStore, - useActiveLayer, - useWallItems, - useLayers, - useUpdateScene, - useWalls, - useDeletedLines, - useNewLines, - useZonePoints, - useZones, -} from "../../../store/builder/store"; +import React from 'react'; -import * as Types from "../../../types/world/worldTypes"; -import * as CONSTANTS from "../../../types/world/worldConstants"; +export default function SocketResponses() { -// 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"; -import { useParams } from "react-router-dom"; -import { getUserData } from "../../../functions/getUserData"; -import { useSceneContext } from "../../scene/sceneContext"; -import { useVersionContext } from "../../builder/version/versionContext"; - -export default function SocketResponses({ - floorPlanGroup, - lines, - floorGroup, - scene, - onlyFloorlines, - currentLayerPoint, - floorPlanGroupPoint, - floorPlanGroupLine, - dragPointControls, -}: any) { - const { socket } = useSocketStore(); - const { activeLayer, setActiveLayer } = useActiveLayer(); - const { wallItems, setWallItems } = useWallItems(); - const { setLayers } = useLayers(); - const { setUpdateScene } = useUpdateScene(); - const { setWalls } = useWalls(); - const { setDeletedLines } = useDeletedLines(); - const { setNewLines } = useNewLines(); - const { zones, setZones } = useZones(); - const { zonePoints, setZonePoints } = useZonePoints(); - const { selectedVersionStore } = useVersionContext(); - const { selectedVersion } = selectedVersionStore(); - const { projectId } = useParams(); - const { assetStore, eventStore, productStore } = useSceneContext(); - const { addAsset, updateAsset, removeAsset } = assetStore(); - const { organization } = getUserData(); - - useEffect(() => { - - if (!socket) return; - - socket.on("cameraCreateResponse", (data: any) => { - // - }); - - socket.on("userConnectRespones", (data: any) => { - // - }); - - socket.on("userDisConnectRespones", (data: any) => { - // - }); - - socket.on("v1:camera:Response:update", (data: any) => { - // - }); - - socket.on("EnvironmentUpdateResponse", (data: any) => { - // - }); - - socket.on("v1:model-asset:response:add", async (data: any) => { - if (socket.id === data.socketId) { - return; - } - if (organization !== data.organization) { - return; - } - if (data.message === "Model created successfully") { - try { - - const asset: Asset = { - modelUuid: data.data.modelUuid, - modelName: data.data.modelName, - assetId: data.data.assetId, - position: data.data.position, - rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z], - isLocked: data.data.isLocked, - isCollidable: false, - isVisible: data.data.isVisible, - opacity: 1, - } - - addAsset(asset); - - echo.success("Added model through collaboration"); - } catch (error) { - echo.error("Failed to create model through collaboration"); - } - } else if (data.message === "Model updated successfully") { - try { - - const asset: Asset = { - modelUuid: data.data.modelUuid, - modelName: data.data.modelName, - assetId: data.data.assetId, - position: data.data.position, - rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z], - isLocked: data.data.isLocked, - isCollidable: false, - isVisible: data.data.isVisible, - opacity: 1, - } - - updateAsset(asset.modelUuid, { - position: asset.position, - rotation: asset.rotation, - }); - - echo.success("Updated model through collaboration"); - } catch (error) { - echo.error("Failed to update model through collaboration"); - } - } else { - echo.error("Failed executing action from collaboration"); - } - }); - - socket.on("v1:model-asset:response:delete", (data: any) => { - if (socket.id === data.socketId) { - return; - } - if (organization !== data.organization) { - return; - } - if (data.message === "Model deleted successfully") { - try { - const deletedUUID = data.data.modelUuid; - - eventStore.getState().removeEvent(deletedUUID); - productStore.getState().deleteEvent(deletedUUID); - - removeAsset(deletedUUID); - - echo.success("Model Removed successfully through collaboration"); - } catch (error) { - echo.error("Failed to remove model through collaboration"); - } - } - }); - - socket.on("v1:Line:response:update", (data: any) => { - // console.log('data: ', data); - 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("v1:Line:response:delete", (data: any) => { - // console.log('data: ', data); - 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); - - echo.success("Line Removed!"); - } - }); - - socket.on("v1: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); - - echo.success("Point Removed!"); - } - }); - - socket.on("v1: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, projectId, selectedVersion?.versionId || ''); - const highestLayer = Math.max( - 1, - lines.current.reduce( - (maxLayer: number, segment: any) => - Math.max(maxLayer, segment.layer || 0), - 0 - ), - zonesData.reduce( - (maxLayer: number, zone: any) => - Math.max(maxLayer, zone.layer || 0), - 0 - ) - ); - - setLayers(highestLayer); - - loadWalls(lines, setWalls); - setUpdateScene(true); - - echo.success("Layer Removed!"); - } - }); - - return () => { - socket.off("cameraCreateResponse"); - socket.off("userConnectRespones"); - socket.off("userDisConnectRespones"); - socket.off("v1:camera:Response:update"); - socket.off("EnvironmentUpdateResponse"); - socket.off("v1:model-asset:response:add"); - socket.off("v1:model-asset:response:delete"); - socket.off("v1:Line:response:update"); - socket.off("v1:Line:response:delete"); - socket.off("v1:Line:response:delete:point"); - socket.off("v1:Line:response:delete:layer"); - } - }, [socket, selectedVersion?.versionId]); - - useEffect(() => { - if (!socket) return; - let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - - socket.on("v1:wallItem:Response:Delete", (data: any) => { - // console.log('data: ', data); - if (socket.id === data.socketId) { - return; - } - if (organization !== data.organization) { - return; - } - if (data.message === "wall Item deleted successfully") { - 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)); - echo.success("Model Removed!"); - }, 50); - } - }); - - socket.on("v1:wallItems:Response:Update", (data: any) => { - // console.log('data: ', data); - // - if (socket.id === data.socketId) { - return; - } - if (organization !== data.organization) { - return; - } - if (data.message === "wall Item 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); - - // Check THREE.js cache first - const cachedModel = THREE.Cache.get(data.data.assetId); - if (cachedModel) { - handleModelLoad(cachedModel); - return; - } - - // Check IndexedDB cache - retrieveGLTF(data.data.assetId).then((cachedModelBlob) => { - if (cachedModelBlob) { - const blobUrl = URL.createObjectURL(cachedModelBlob); - loader.load(blobUrl, (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(data.data.assetId, gltf); - handleModelLoad(gltf); - }); - return; - } - }) - - // Load from backend if not in any cache - loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.assetId}`, async (gltf) => { - try { - const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.assetId}`).then((res) => res.blob()); - await storeGLTF(data.data.assetId, modelBlob); - THREE.Cache.add(data.data.assetId, gltf); - await handleModelLoad(gltf); - } catch (error) { - - handleModelLoad(gltf); - } - }); - - async function handleModelLoad(gltf: GLTF) { - const model = gltf.scene.clone(); - 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, - assetId: data.data.assetId, - scale: data.data.scale, - csgscale: data.data.csgscale, - csgposition: data.data.csgposition, - position: data.data.position, - quaternion: data.data.quaternion, - }; - - setWallItems((prevItems: Types.wallItems) => { - const updatedItems = [...prevItems, newWallItem]; - - const WallItemsForStorage = updatedItems.map(item => { - const { model, ...rest } = item; - return { - ...rest, - modelUuid: model?.uuid, - }; - }); - - localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); - echo.success("Model Added!"); - return updatedItems; - }); - } - - } else if (data.message === "Updated successfully") { - 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) - ); - echo.success("Model Updated!"); - - return updatedItems; - }); - } - }); - - return () => { - socket.off("v1:wallItem:Response:Delete"); - socket.off("v1:wallItems:Response:Update"); - }; - }, [socket, 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; - - socket.on("v1: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: { - uOuterColor: { 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 uOuterColor; - 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(uOuterColor, 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, projectId, selectedVersion?.versionId || ''); - const highestLayer = Math.max( - 1, - lines.current.reduce( - (maxLayer: number, segment: any) => - Math.max(maxLayer, segment.layer || 0), - 0 - ), - zonesData.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("v1:Line:response:create"); - }; - }, [socket, activeLayer, selectedVersion?.versionId]); - - useEffect(() => { - if (!socket) return; - - socket.on("v1:zone:response:updates", (data: any) => { - // console.log('data: ', data); - 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.zoneUuid === data.data.zoneUuid ? data.data : zone - ); - setZones(updatedZones); - setUpdateScene(true); - } - }); - - socket.on("v1:zone:response:delete", (data: any) => { - // console.log('data: ', data); - if (socket.id === data.socketId) { - return; - } - if (organization !== data.organization) { - return; - } - if (data.message === "zone deleted") { - const updatedZones = zones.filter( - (zone: any) => zone.zoneUuid !== data.data.zoneUuid - ); - setZones(updatedZones); - - const zoneIndex = zones.findIndex( - (zone: any) => zone.zoneUuid === data.data.zoneUuid - ); - 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("v1:zone:response:updates"); - socket.off("v1:zone:response:delete"); - }; - }, [socket, zones, zonePoints]); - - return <>; + return ( + <> + + ); } diff --git a/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx index 2dcb9b2..3c14ea1 100644 --- a/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx +++ b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx @@ -5,18 +5,14 @@ import NavMeshDetails from "./navMeshDetails"; import * as CONSTANTS from "../../../../types/world/worldConstants"; import * as Types from "../../../../types/world/worldTypes"; -type NavMeshProps = { - lines: Types.RefLines -}; - -function NavMesh({ lines }: NavMeshProps) { +function NavMesh() { let groupRef = useRef() as Types.RefGroup; const { setNavMesh } = useNavMesh(); return ( <> - - + + diff --git a/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx index df660fe..106f652 100644 --- a/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx +++ b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx @@ -9,11 +9,9 @@ import * as Types from "../../../../types/world/worldTypes"; interface NavMeshDetailsProps { setNavMesh: (navMesh: any) => void; groupRef: React.MutableRefObject; - lines: Types.RefLines; } export default function NavMeshDetails({ - lines, setNavMesh, groupRef, }: NavMeshDetailsProps) { @@ -63,7 +61,7 @@ export default function NavMeshDetails({ }; initializeNavigation(); - }, [scene, groupRef, lines.current]); + }, [scene, groupRef]); return null; } diff --git a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx index eaf5a24..34d9f26 100644 --- a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx +++ b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx @@ -2,26 +2,23 @@ import * as THREE from "three"; import { useEffect } from "react"; import * as turf from "@turf/turf"; import * as Types from "../../../../types/world/worldTypes"; -import arrayLinesToObject from "../../../builder/geomentries/lines/lineConvertions/arrayLinesToObject"; import { useThree } from "@react-three/fiber"; import { useSceneContext } from "../../../scene/sceneContext"; interface PolygonGeneratorProps { groupRef: React.MutableRefObject; - lines: Types.RefLines; } export default function PolygonGenerator({ groupRef, - lines, }: PolygonGeneratorProps) { const { aisleStore } = useSceneContext(); const { aisles } = aisleStore(); const { scene } = useThree(); useEffect(() => { - let allLines = arrayLinesToObject(lines.current); - const wallLines = allLines?.filter((line) => line?.type === "WallLine"); + // let allLines = arrayLinesToObject(lines.current); + // const wallLines = allLines?.filter((line) => line?.type === "WallLine"); const result = aisles .filter( (aisle) => @@ -64,9 +61,9 @@ export default function PolygonGenerator({ }); }); - const wallPoints = wallLines - .map((pair) => pair?.line.map((vals) => vals.position)) - .filter((wall): wall is THREE.Vector3[] => !!wall); + // const wallPoints = wallLines + // .map((pair) => pair?.line.map((vals) => vals.position)) + // .filter((wall): wall is THREE.Vector3[] => !!wall); if (!result || result.some((line) => !line)) { @@ -84,7 +81,7 @@ export default function PolygonGenerator({ const polygons = turf.polygonize(turf.featureCollection(validLineFeatures)); - renderWallGeometry(wallPoints); + // renderWallGeometry(wallPoints); if (polygons.features.length > 0) { polygons.features.forEach((feature) => { @@ -119,7 +116,7 @@ export default function PolygonGenerator({ }); } - }, [lines.current, aisles, scene]); + }, [ aisles, scene]); const renderWallGeometry = (walls: THREE.Vector3[][]) => { walls.forEach((wall) => { From fa6506c0be224881e6b1a054ba8a9764992acb37 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 17:51:57 +0530 Subject: [PATCH 11/18] Refactor: Remove deprecated API endpoints and implement new zone management features - Deleted obsolete API files for wall items, layers, lines, and points. - Introduced new zone management APIs including create, delete, and update functionalities. - Enhanced zone state management in the store with new properties for height and color. - Implemented 2D and 3D zone rendering components for better visualization. - Added asset fetching functionalities for marketplace integration. - Updated types to accommodate new zone properties and API responses. --- .../components/layout/scenes/MainScene.tsx | 2 +- .../components/layout/sidebarLeft/Assets.tsx | 2 +- app/src/components/ui/list/List.tsx | 2 +- .../IntialLoad/loadInitialWallItems.ts | 2 +- app/src/modules/builder/asset/assetsGroup.tsx | 2 +- .../builder/asset/functions/addAssetModel.ts | 2 +- app/src/modules/builder/builder.tsx | 39 +- .../Instances/Instance/floor2DInstance.tsx | 1 - app/src/modules/builder/groups/zoneGroup.tsx | 1302 ++++++++--------- .../builder/wall/Instances/wallInstances.tsx | 2 +- .../Instances/Instance/zone2DInstance.tsx | 50 + .../zone/Instances/Instance/zoneInstance.tsx | 73 + .../builder/zone/Instances/zoneInstances.tsx | 132 ++ .../builder/zone/zoneCreator/zoneCreator.tsx | 10 + app/src/modules/builder/zone/zoneGroup.tsx | 54 + app/src/modules/market/MarketPlace.tsx | 2 +- .../selectionControls/copyPasteControls.tsx | 2 +- .../selectionControls/duplicationControls.tsx | 2 +- .../selectionControls/moveControls.tsx | 2 +- .../selectionControls/rotateControls.tsx | 2 +- .../selectionControls/selectionControls.tsx | 2 +- .../transformControls/transformControls.tsx | 2 +- .../assest/wallAsset/deleteWallItemApi.ts | 42 - .../assest/wallAsset/getWallItemsApi.ts | 37 - .../assest/wallAsset/setWallItemApi.ts | 55 - .../assets/getAssetImages.ts | 48 +- .../{assest => asset}/assets/getAssetModel.ts | 58 +- .../assets/getCategoryAsset.ts | 0 .../floorAsset/deleteFloorItemApi.ts | 84 +- .../floorAsset/getFloorItemsApi.ts | 78 +- .../floorAsset/setAssetsApi.ts | 0 .../factoryBuilder/lines/deleteLayerApi.ts | 34 - .../factoryBuilder/lines/deleteLineApi.ts | 34 - .../factoryBuilder/lines/deletePointApi.ts | 35 - .../factoryBuilder/lines/getLinesApi.ts | 38 - .../factoryBuilder/lines/setLineApi.ts | 41 - .../factoryBuilder/lines/updatePointApi.ts | 38 - .../factoryBuilder/zone/deleteZoneApi.ts | 39 + .../factoryBuilder/zone/getZonesApi.ts | 37 + .../factoryBuilder/zone/upsertZoneApi.ts | 39 + .../factoryBuilder/zones/deleteZoneApi.ts | 39 - .../factoryBuilder/zones/getZonesApi.ts | 40 - .../factoryBuilder/zones/setZonesApi.ts | 38 - app/src/store/builder/useBuilderStore.ts | 34 + app/src/store/builder/useZoneStore.ts | 24 +- app/src/types/builderTypes.d.ts | 1 + 46 files changed, 1301 insertions(+), 1301 deletions(-) create mode 100644 app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx create mode 100644 app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx create mode 100644 app/src/modules/builder/zone/Instances/zoneInstances.tsx create mode 100644 app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx create mode 100644 app/src/modules/builder/zone/zoneGroup.tsx delete mode 100644 app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts delete mode 100644 app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts delete mode 100644 app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts rename app/src/services/factoryBuilder/{assest => asset}/assets/getAssetImages.ts (96%) rename app/src/services/factoryBuilder/{assest => asset}/assets/getAssetModel.ts (96%) rename app/src/services/factoryBuilder/{assest => asset}/assets/getCategoryAsset.ts (100%) rename app/src/services/factoryBuilder/{assest => asset}/floorAsset/deleteFloorItemApi.ts (96%) rename app/src/services/factoryBuilder/{assest => asset}/floorAsset/getFloorItemsApi.ts (96%) rename app/src/services/factoryBuilder/{assest => asset}/floorAsset/setAssetsApi.ts (100%) delete mode 100644 app/src/services/factoryBuilder/lines/deleteLayerApi.ts delete mode 100644 app/src/services/factoryBuilder/lines/deleteLineApi.ts delete mode 100644 app/src/services/factoryBuilder/lines/deletePointApi.ts delete mode 100644 app/src/services/factoryBuilder/lines/getLinesApi.ts delete mode 100644 app/src/services/factoryBuilder/lines/setLineApi.ts delete mode 100644 app/src/services/factoryBuilder/lines/updatePointApi.ts create mode 100644 app/src/services/factoryBuilder/zone/deleteZoneApi.ts create mode 100644 app/src/services/factoryBuilder/zone/getZonesApi.ts create mode 100644 app/src/services/factoryBuilder/zone/upsertZoneApi.ts delete mode 100644 app/src/services/factoryBuilder/zones/deleteZoneApi.ts delete mode 100644 app/src/services/factoryBuilder/zones/getZonesApi.ts delete mode 100644 app/src/services/factoryBuilder/zones/setZonesApi.ts diff --git a/app/src/components/layout/scenes/MainScene.tsx b/app/src/components/layout/scenes/MainScene.tsx index 25d579f..6b55a26 100644 --- a/app/src/components/layout/scenes/MainScene.tsx +++ b/app/src/components/layout/scenes/MainScene.tsx @@ -33,7 +33,7 @@ import { import { useProductContext } from "../../../modules/simulation/products/productContext"; import RegularDropDown from "../../ui/inputs/RegularDropDown"; import RenameTooltip from "../../ui/features/RenameTooltip"; -import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi"; +import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi"; import { useParams } from "react-router-dom"; import { useSceneContext } from "../../../modules/scene/sceneContext"; import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore"; diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index 391675b..0420d2a 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import Search from "../../ui/inputs/Search"; -import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets/getCategoryAsset"; +import { getCategoryAsset } from "../../../services/factoryBuilder/asset/assets/getCategoryAsset"; import { fetchAssets } from "../../../services/marketplace/fetchAssets"; import { useSelectedItem } from "../../../store/builder/store"; diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index 0d81bda..cf13a4f 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -17,7 +17,7 @@ import { useZones, } from "../../../store/builder/store"; import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation"; -import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi"; +import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi"; import { useParams } from "react-router-dom"; import { getUserData } from "../../../functions/getUserData"; import { useSceneContext } from "../../../modules/scene/sceneContext"; diff --git a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts index fd74916..80fdcb9 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts @@ -2,7 +2,7 @@ // import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; // import * as THREE from "three"; // import * as Types from "../../../types/world/worldTypes"; -// import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi"; +// import { getWallItems } from "../../../services/factoryBuilder/asset/wallAsset/getWallItemsApi"; // import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils"; // import { getUserData } from "../../../functions/getUserData"; diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 72e8033..fad2338 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -1,6 +1,6 @@ import * as THREE from "three" import { useEffect } from 'react' -import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; +import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi'; import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store'; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; diff --git a/app/src/modules/builder/asset/functions/addAssetModel.ts b/app/src/modules/builder/asset/functions/addAssetModel.ts index 3977fa7..7c85a49 100644 --- a/app/src/modules/builder/asset/functions/addAssetModel.ts +++ b/app/src/modules/builder/asset/functions/addAssetModel.ts @@ -3,7 +3,7 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import * as Types from "../../../../types/world/worldTypes"; import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils"; -// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi'; +// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; import { Socket } from "socket.io-client"; import * as CONSTANTS from "../../../../types/world/worldConstants"; import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator"; diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index 66a3502..adea2c6 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -24,7 +24,7 @@ import * as Types from "../../types/world/worldTypes"; import SocketResponses from "../collaboration/socket/socketResponses.dev"; import Ground from "../scene/environment/ground"; import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment"; -import ZoneGroup from "./groups/zoneGroup"; + import MeasurementTool from "../scene/tools/measurementTool"; import NavMesh from "../simulation/vehicle/navMesh/navMesh"; import CalculateAreaGroup from "./groups/calculateAreaGroup"; @@ -34,21 +34,19 @@ import DxfFile from "./dfx/LoadBlueprint"; import AislesGroup from "./aisle/aislesGroup"; import WallGroup from "./wall/wallGroup"; import FloorGroup from "./floor/floorGroup"; +import ZoneGroup from "./zone/zoneGroup"; + import { useParams } from "react-router-dom"; import { useBuilderStore } from "../../store/builder/useBuilderStore"; import { getUserData } from "../../functions/getUserData"; 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 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. 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 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 currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. const { toggleView } = useToggleView(); // State for toggling between 2D and 3D. const { setToolMode } = useToolMode(); @@ -111,28 +109,25 @@ export default function Builder() { hoveredDeletableWallItem={hoveredDeletableWallItem} /> */} - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + ); } diff --git a/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx index 166b1de..2f12360 100644 --- a/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx +++ b/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx @@ -32,7 +32,6 @@ function Floor2DInstance({ floor }: { floor: Floor }) { name={`Floor-${floor.floorUuid}`} args={[shape, { depth: Constants.floorConfig.height, - bevelEnabled: floor.isBeveled, }]} userData={floor} > diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 24f6ee4..3339c20 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -1,651 +1,651 @@ -import React, { useState, useEffect, useMemo, useRef } from "react"; -import { Html, Line, Sphere } from "@react-three/drei"; -import { useThree, useFrame } from "@react-three/fiber"; -import * as THREE from "three"; -import { - useActiveLayer, - useSocketStore, - useToggleView, - useToolMode, - useRemovedLayer, - useZones, - useZonePoints, -} from "../../../store/builder/store"; -import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; - -import * as CONSTANTS from "../../../types/world/worldConstants"; -import * as turf from "@turf/turf"; -import { computeArea } from "../functions/computeArea"; -import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; -import { useParams } from "react-router-dom"; -import { getUserData } from "../../../functions/getUserData"; -import { useVersionContext } from "../version/versionContext"; - -const ZoneGroup: React.FC = () => { - const { camera, pointer, gl, raycaster, scene, controls } = useThree(); - const [startPoint, setStartPoint] = useState(null); - const [endPoint, setEndPoint] = useState(null); - const { zones, setZones } = useZones(); - const { zonePoints, setZonePoints } = useZonePoints(); - const [isDragging, setIsDragging] = useState(false); - const { selectedZone } = useSelectedZoneStore(); - const [draggedSphere, setDraggedSphere] = useState(null); - const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); - const { toggleView } = useToggleView(); - const { removedLayer, setRemovedLayer } = useRemovedLayer(); - const { toolMode } = useToolMode(); - const { activeLayer } = useActiveLayer(); - const { socket } = useSocketStore(); - const { selectedVersionStore } = useVersionContext(); - const { selectedVersion } = selectedVersionStore(); - const { projectId } = useParams(); - const { userId, organization } = getUserData(); - - const groupsRef = useRef(); - - const zoneMaterial = useMemo( - () => - new THREE.ShaderMaterial({ - side: THREE.DoubleSide, - vertexShader: ` - varying vec2 vUv; - void main(){ - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - vUv = uv; - } - `, - fragmentShader: ` - varying vec2 vUv; - uniform vec3 uOuterColor; - void main(){ - float alpha = 1.0 - vUv.y; - gl_FragColor = vec4(uOuterColor, alpha); - } - `, - uniforms: { - uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, - }, - transparent: true, - depthWrite: false, - }), - [] - ); - - useEffect(() => { - if (!selectedVersion) return; - getZonesApi(organization, projectId, selectedVersion?.versionId || '').then((data) => { - if (data && data.length > 0) { - const fetchedZones = data.map((zone: any) => ({ - zoneUuid: zone.zoneUuid, - zoneName: zone.zoneName, - points: zone.points, - viewPortCenter: zone.viewPortCenter, - viewPortposition: zone.viewPortposition, - layer: zone.layer, - })); - - setZones(fetchedZones); - - const fetchedPoints = data.flatMap((zone: any) => - zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point)) - ); - - setZonePoints(fetchedPoints); - } else { - setZones([]); - } - }).catch((err) => { - console.error(err); - }) - }, [selectedVersion?.versionId]); - - useEffect(() => { - localStorage.setItem("zones", JSON.stringify(zones)); - }, [zones]); - - useEffect(() => { - if (removedLayer) { - const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer); - setZones(updatedZones); - - const updatedzonePoints = zonePoints.filter((_: any, index: any) => { - const zoneIndex = Math.floor(index / 4); - return zones[zoneIndex]?.layer !== removedLayer; - }); - setZonePoints(updatedzonePoints); - - zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { deleteZoneFromBackend(zone.zoneUuid); }); - - setRemovedLayer(null); - } - }, [removedLayer]); - - useEffect(() => { - if (toolMode !== "Zone") { - setStartPoint(null); - setEndPoint(null); - } - if (!toggleView) { - setStartPoint(null); - setEndPoint(null); - } - }, [toolMode, toggleView]); - - // eslint-disable-next-line react-hooks/exhaustive-deps - const addZoneToBackend = async (zone: { - zoneUuid: string; - zoneName: string; - points: [number, number, number][]; - layer: string; - }) => { - - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; - - let sumX = 0, sumY = 0, sumZ = 0; - const numPoints = points.length; - - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ - number, - number, - number - ]; - }; - - const target: [number, number, number] | null = calculateCenter(zone.points); - if (!target || zone.points.length < 4) return; - const position = [target[0], 10, target[2]]; - - const input = { - userId: userId, - versionId: selectedVersion?.versionId || '', - projectId, - organization, - zoneData: { - zoneName: zone.zoneName, - zoneUuid: zone.zoneUuid, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer, - }, - }; - - socket.emit("v1:zone:set", input); - }; - - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateZoneToBackend = async (zone: { - zoneUuid: string; - zoneName: string; - points: [number, number, number][]; - layer: string; - }) => { - - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; - - let sumX = 0, sumY = 0, sumZ = 0; - const numPoints = points.length; - - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ - number, - number, - number - ]; - }; - - const target: [number, number, number] | null = calculateCenter(zone.points); - if (!target || zone.points.length < 4) return; - const position = [target[0], 10, target[2]]; - - const input = { - userId: userId, - versionId: selectedVersion?.versionId || '', - projectId, - organization, - zoneData: { - zoneName: zone.zoneName, - zoneUuid: zone.zoneUuid, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer, - }, - }; - - socket.emit("v1:zone:set", input); - }; - - const deleteZoneFromBackend = async (zoneUuid: string) => { - - const input = { - userId: userId, - versionId: selectedVersion?.versionId || '', - projectId, - organization, - zoneUuid: zoneUuid, - }; - - socket.emit("v1:zone:delete", input); - }; - - // eslint-disable-next-line react-hooks/exhaustive-deps - const handleDeleteZone = (zoneUuid: string) => { - const updatedZones = zones.filter((zone: any) => zone.zoneUuid !== zoneUuid); - setZones(updatedZones); - - const zoneIndex = zones.findIndex((zone: any) => zone.zoneUuid === zoneUuid); - if (zoneIndex !== -1) { - const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4); - zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point)); - const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); - setZonePoints(updatedzonePoints); - } - deleteZoneFromBackend(zoneUuid); - }; - - useEffect(() => { - if (!camera || !toggleView) return; - const canvasElement = gl.domElement; - - let drag = false; - let isLeftMouseDown = false; - - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - - if (intersects.length > 0 && toolMode === "move") { - const clickedObject = intersects[0].object; - const sphereIndex = zonePoints.findIndex((point: any) => - point.equals(clickedObject.position) - ); - if (sphereIndex !== -1) { - (controls as any).enabled = false; - setDraggedSphere(zonePoints[sphereIndex]); - setIsDragging(true); - } - } - } - }; - - const onMouseUp = (evt: any) => { - if (evt.button === 0 && !drag && !isDragging && toolMode === 'Zone') { - isLeftMouseDown = false; - - if (!startPoint) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - setStartPoint(point); - setEndPoint(null); - } - } else if (startPoint) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (!point) return; - - const points = [ - [startPoint.x, 0.15, startPoint.z], - [point.x, 0.15, startPoint.z], - [point.x, 0.15, point.z], - [startPoint.x, 0.15, point.z], - [startPoint.x, 0.15, startPoint.z], - ] as [number, number, number][]; - - const zoneName = `Zone ${zones.length + 1}`; - const zoneUuid = THREE.MathUtils.generateUUID(); - const newZone = { - zoneUuid, - zoneName, - points: points, - layer: activeLayer, - }; - - const newZones = [...zones, newZone]; - - setZones(newZones); - - const newzonePoints = [ - new THREE.Vector3(startPoint.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, point.z), - new THREE.Vector3(startPoint.x, 0.15, point.z), - ]; - - const updatedZonePoints = [...zonePoints, ...newzonePoints]; - setZonePoints(updatedZonePoints); - - addZoneToBackend(newZone); - setStartPoint(null); - setEndPoint(null); - } - } else if (evt.button === 0 && !drag && !isDragging && toolMode === '2D-Delete') { - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects( - groupsRef.current.children, - true - ); - - if (intersects.length > 0) { - const clickedObject = intersects[0].object; - - const sphereIndex = zonePoints.findIndex((point: any) => - point.equals(clickedObject.position) - ); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const zoneUuid = zones[zoneIndex].zoneUuid; - handleDeleteZone(zoneUuid); - return; - } - } - } - - if (evt.button === 0) { - if (isDragging && draggedSphere) { - setIsDragging(false); - setDraggedSphere(null); - - const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - - if (zoneIndex !== -1 && zones[zoneIndex]) { - updateZoneToBackend(zones[zoneIndex]); - } - } - } - } - }; - - const onMouseMove = () => { - if (!groupsRef.current) return; - if (isLeftMouseDown) { - drag = true; - } - raycaster.setFromCamera(pointer, camera); - - if (isDragging && draggedSphere) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - draggedSphere.set(point.x, 0.15, point.z); - - const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const cornerIndex = sphereIndex % 4; - - const updatedZones = zones.map((zone: any, index: number) => { - if (index === zoneIndex) { - const updatedPoints = [...zone.points]; - updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; - updatedPoints[4] = updatedPoints[0]; - return { ...zone, points: updatedPoints }; - } - return zone; - }); - - setZones(updatedZones); - } - } - } - }; - - const onContext = (event: any) => { - event.preventDefault(); - setStartPoint(null); - setEndPoint(null); - }; - - if (toolMode === "Zone" || toolMode === '2D-Delete' || toolMode === "move") { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("contextmenu", onContext); - } - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("contextmenu", onContext); - }; - }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, zonePoints, draggedSphere, activeLayer, raycaster, pointer, controls, plane, setZones, setZonePoints, addZoneToBackend, handleDeleteZone, updateZoneToBackend, selectedVersion?.versionId]); - - useFrame(() => { - if (!startPoint) return; - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - setEndPoint(point); - } - }); - - return ( - - - {zones.map((zone: any) => ( - - {zone.points - .slice(0, -1) - .map((point: [number, number, number], index: number) => { - const nextPoint = zone.points[index + 1]; - - const point1 = new THREE.Vector3(point[0], point[1], point[2]); - const point2 = new THREE.Vector3( - nextPoint[0], - nextPoint[1], - nextPoint[2] - ); - - const planeWidth = point1.distanceTo(point2); - const planeHeight = CONSTANTS.zoneConfig.height; - - const midpoint = new THREE.Vector3( - (point1.x + point2.x) / 2, - CONSTANTS.zoneConfig.height / 2 + - (zone.layer - 1) * CONSTANTS.zoneConfig.height, - (point1.z + point2.z) / 2 - ); - - const angle = Math.atan2( - point2.z - point1.z, - point2.x - point1.x - ); - - return ( - - - - - ); - })} - {!toggleView && - (() => { - const points3D = zone.points || []; - const coords2D = points3D.map((p: any) => [p[0], p[2]]); - - // Ensure the polygon is closed - if ( - coords2D.length >= 4 && - (coords2D[0][0] !== coords2D[coords2D.length - 1][0] || - coords2D[0][1] !== coords2D[coords2D.length - 1][1]) - ) { - coords2D.push(coords2D[0]); - } - if (coords2D.length < 4) return null; - - const polygon = turf.polygon([coords2D]); - const center2D = turf.center(polygon).geometry.coordinates; - - // Calculate the average Y value - const sumY = points3D.reduce( - (sum: number, p: any) => sum + p[1], - 0 - ); - const avgY = points3D.length > 0 ? sumY / points3D.length : 0; - - const htmlPosition: [number, number, number] = [ - center2D[0], - avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5, - center2D[1], - ]; - - return ( - -
{zone.zoneName}
- - ); - })()} -
- ))} -
- - {zones - .filter((zone: any) => zone.layer === activeLayer) - .map((zone: any) => ( - { - e.stopPropagation(); - if (toolMode === '2D-Delete') { - handleDeleteZone(zone.zoneUuid); - } - }} - /> - ))} - - - {zones.map((zone: any, index: any) => { - if (!toggleView) return null; - const points3D = zone.points; - const coords2D = points3D.map((p: any) => [p[0], p[2]]); - - if ( - coords2D.length < 4 || - coords2D[0][0] !== coords2D[coords2D.length - 1][0] || - coords2D[0][1] !== coords2D[coords2D.length - 1][1] - ) { - coords2D.push(coords2D[0]); - } - if (coords2D.length < 4) return null; - - const polygon = turf.polygon([coords2D]); - const center2D = turf.center(polygon).geometry.coordinates; - - const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0); - const avgY = sumY / points3D.length; - - const area = computeArea(points3D, "zone"); - const formattedArea = `${area.toFixed(2)} m²`; - - const htmlPosition: [number, number, number] = [ - center2D[0], - avgY + CONSTANTS.zoneConfig.height, - center2D[1], - ]; - return ( - -
- {zone.zoneName} ({formattedArea}) -
- - ); - })} -
- - - {zones - .filter((zone: any) => zone.layer === activeLayer) - .flatMap((zone: any) => - zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( - - - - )) - )} - - - {startPoint && endPoint && ( - - )} - -
- ); -}; - -export default ZoneGroup; +// import React, { useState, useEffect, useMemo, useRef } from "react"; +// import { Html, Line, Sphere } from "@react-three/drei"; +// import { useThree, useFrame } from "@react-three/fiber"; +// import * as THREE from "three"; +// import { +// useActiveLayer, +// useSocketStore, +// useToggleView, +// useToolMode, +// useRemovedLayer, +// useZones, +// useZonePoints, +// } from "../../../store/builder/store"; +// import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; + +// import * as CONSTANTS from "../../../types/world/worldConstants"; +// import * as turf from "@turf/turf"; +// import { computeArea } from "../functions/computeArea"; +// import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; +// import { useParams } from "react-router-dom"; +// import { getUserData } from "../../../functions/getUserData"; +// import { useVersionContext } from "../version/versionContext"; + +// const ZoneGroup: React.FC = () => { +// const { camera, pointer, gl, raycaster, scene, controls } = useThree(); +// const [startPoint, setStartPoint] = useState(null); +// const [endPoint, setEndPoint] = useState(null); +// const { zones, setZones } = useZones(); +// const { zonePoints, setZonePoints } = useZonePoints(); +// const [isDragging, setIsDragging] = useState(false); +// const { selectedZone } = useSelectedZoneStore(); +// const [draggedSphere, setDraggedSphere] = useState(null); +// const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); +// const { toggleView } = useToggleView(); +// const { removedLayer, setRemovedLayer } = useRemovedLayer(); +// const { toolMode } = useToolMode(); +// const { activeLayer } = useActiveLayer(); +// const { socket } = useSocketStore(); +// const { selectedVersionStore } = useVersionContext(); +// const { selectedVersion } = selectedVersionStore(); +// const { projectId } = useParams(); +// const { userId, organization } = getUserData(); + +// const groupsRef = useRef(); + +// const zoneMaterial = useMemo( +// () => +// new THREE.ShaderMaterial({ +// side: THREE.DoubleSide, +// vertexShader: ` +// varying vec2 vUv; +// void main(){ +// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +// vUv = uv; +// } +// `, +// fragmentShader: ` +// varying vec2 vUv; +// uniform vec3 uOuterColor; +// void main(){ +// float alpha = 1.0 - vUv.y; +// gl_FragColor = vec4(uOuterColor, alpha); +// } +// `, +// uniforms: { +// uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, +// }, +// transparent: true, +// depthWrite: false, +// }), +// [] +// ); + +// useEffect(() => { +// if (!selectedVersion) return; +// getZonesApi(organization, projectId, selectedVersion?.versionId || '').then((data) => { +// if (data && data.length > 0) { +// const fetchedZones = data.map((zone: any) => ({ +// zoneUuid: zone.zoneUuid, +// zoneName: zone.zoneName, +// points: zone.points, +// viewPortCenter: zone.viewPortCenter, +// viewPortposition: zone.viewPortposition, +// layer: zone.layer, +// })); + +// setZones(fetchedZones); + +// const fetchedPoints = data.flatMap((zone: any) => +// zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point)) +// ); + +// setZonePoints(fetchedPoints); +// } else { +// setZones([]); +// } +// }).catch((err) => { +// console.error(err); +// }) +// }, [selectedVersion?.versionId]); + +// useEffect(() => { +// localStorage.setItem("zones", JSON.stringify(zones)); +// }, [zones]); + +// useEffect(() => { +// if (removedLayer) { +// const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer); +// setZones(updatedZones); + +// const updatedzonePoints = zonePoints.filter((_: any, index: any) => { +// const zoneIndex = Math.floor(index / 4); +// return zones[zoneIndex]?.layer !== removedLayer; +// }); +// setZonePoints(updatedzonePoints); + +// zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { deleteZoneFromBackend(zone.zoneUuid); }); + +// setRemovedLayer(null); +// } +// }, [removedLayer]); + +// useEffect(() => { +// if (toolMode !== "Zone") { +// setStartPoint(null); +// setEndPoint(null); +// } +// if (!toggleView) { +// setStartPoint(null); +// setEndPoint(null); +// } +// }, [toolMode, toggleView]); + +// // eslint-disable-next-line react-hooks/exhaustive-deps +// const addZoneToBackend = async (zone: { +// zoneUuid: string; +// zoneName: string; +// points: [number, number, number][]; +// layer: string; +// }) => { + +// const calculateCenter = (points: number[][]) => { +// if (!points || points.length === 0) return null; + +// let sumX = 0, sumY = 0, sumZ = 0; +// const numPoints = points.length; + +// points.forEach(([x, y, z]) => { +// sumX += x; +// sumY += y; +// sumZ += z; +// }); + +// return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ +// number, +// number, +// number +// ]; +// }; + +// const target: [number, number, number] | null = calculateCenter(zone.points); +// if (!target || zone.points.length < 4) return; +// const position = [target[0], 10, target[2]]; + +// const input = { +// userId: userId, +// versionId: selectedVersion?.versionId || '', +// projectId, +// organization, +// zoneData: { +// zoneName: zone.zoneName, +// zoneUuid: zone.zoneUuid, +// points: zone.points, +// viewPortCenter: target, +// viewPortposition: position, +// layer: zone.layer, +// }, +// }; + +// socket.emit("v1:zone:set", input); +// }; + +// // eslint-disable-next-line react-hooks/exhaustive-deps +// const updateZoneToBackend = async (zone: { +// zoneUuid: string; +// zoneName: string; +// points: [number, number, number][]; +// layer: string; +// }) => { + +// const calculateCenter = (points: number[][]) => { +// if (!points || points.length === 0) return null; + +// let sumX = 0, sumY = 0, sumZ = 0; +// const numPoints = points.length; + +// points.forEach(([x, y, z]) => { +// sumX += x; +// sumY += y; +// sumZ += z; +// }); + +// return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ +// number, +// number, +// number +// ]; +// }; + +// const target: [number, number, number] | null = calculateCenter(zone.points); +// if (!target || zone.points.length < 4) return; +// const position = [target[0], 10, target[2]]; + +// const input = { +// userId: userId, +// versionId: selectedVersion?.versionId || '', +// projectId, +// organization, +// zoneData: { +// zoneName: zone.zoneName, +// zoneUuid: zone.zoneUuid, +// points: zone.points, +// viewPortCenter: target, +// viewPortposition: position, +// layer: zone.layer, +// }, +// }; + +// socket.emit("v1:zone:set", input); +// }; + +// const deleteZoneFromBackend = async (zoneUuid: string) => { + +// const input = { +// userId: userId, +// versionId: selectedVersion?.versionId || '', +// projectId, +// organization, +// zoneUuid: zoneUuid, +// }; + +// socket.emit("v1:zone:delete", input); +// }; + +// // eslint-disable-next-line react-hooks/exhaustive-deps +// const handleDeleteZone = (zoneUuid: string) => { +// const updatedZones = zones.filter((zone: any) => zone.zoneUuid !== zoneUuid); +// setZones(updatedZones); + +// const zoneIndex = zones.findIndex((zone: any) => zone.zoneUuid === zoneUuid); +// if (zoneIndex !== -1) { +// const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4); +// zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point)); +// const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); +// setZonePoints(updatedzonePoints); +// } +// deleteZoneFromBackend(zoneUuid); +// }; + +// useEffect(() => { +// if (!camera || !toggleView) return; +// const canvasElement = gl.domElement; + +// let drag = false; +// let isLeftMouseDown = false; + +// const onMouseDown = (evt: any) => { +// if (evt.button === 0) { +// isLeftMouseDown = true; +// drag = false; + +// raycaster.setFromCamera(pointer, camera); +// const intersects = raycaster.intersectObjects(groupsRef.current.children, true); + +// if (intersects.length > 0 && toolMode === "move") { +// const clickedObject = intersects[0].object; +// const sphereIndex = zonePoints.findIndex((point: any) => +// point.equals(clickedObject.position) +// ); +// if (sphereIndex !== -1) { +// (controls as any).enabled = false; +// setDraggedSphere(zonePoints[sphereIndex]); +// setIsDragging(true); +// } +// } +// } +// }; + +// const onMouseUp = (evt: any) => { +// if (evt.button === 0 && !drag && !isDragging && toolMode === 'Zone') { +// isLeftMouseDown = false; + +// if (!startPoint) { +// raycaster.setFromCamera(pointer, camera); +// const intersectionPoint = new THREE.Vector3(); +// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); +// if (point) { +// setStartPoint(point); +// setEndPoint(null); +// } +// } else if (startPoint) { +// raycaster.setFromCamera(pointer, camera); +// const intersectionPoint = new THREE.Vector3(); +// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); +// if (!point) return; + +// const points = [ +// [startPoint.x, 0.15, startPoint.z], +// [point.x, 0.15, startPoint.z], +// [point.x, 0.15, point.z], +// [startPoint.x, 0.15, point.z], +// [startPoint.x, 0.15, startPoint.z], +// ] as [number, number, number][]; + +// const zoneName = `Zone ${zones.length + 1}`; +// const zoneUuid = THREE.MathUtils.generateUUID(); +// const newZone = { +// zoneUuid, +// zoneName, +// points: points, +// layer: activeLayer, +// }; + +// const newZones = [...zones, newZone]; + +// setZones(newZones); + +// const newzonePoints = [ +// new THREE.Vector3(startPoint.x, 0.15, startPoint.z), +// new THREE.Vector3(point.x, 0.15, startPoint.z), +// new THREE.Vector3(point.x, 0.15, point.z), +// new THREE.Vector3(startPoint.x, 0.15, point.z), +// ]; + +// const updatedZonePoints = [...zonePoints, ...newzonePoints]; +// setZonePoints(updatedZonePoints); + +// addZoneToBackend(newZone); +// setStartPoint(null); +// setEndPoint(null); +// } +// } else if (evt.button === 0 && !drag && !isDragging && toolMode === '2D-Delete') { +// raycaster.setFromCamera(pointer, camera); +// const intersects = raycaster.intersectObjects( +// groupsRef.current.children, +// true +// ); + +// if (intersects.length > 0) { +// const clickedObject = intersects[0].object; + +// const sphereIndex = zonePoints.findIndex((point: any) => +// point.equals(clickedObject.position) +// ); +// if (sphereIndex !== -1) { +// const zoneIndex = Math.floor(sphereIndex / 4); +// const zoneUuid = zones[zoneIndex].zoneUuid; +// handleDeleteZone(zoneUuid); +// return; +// } +// } +// } + +// if (evt.button === 0) { +// if (isDragging && draggedSphere) { +// setIsDragging(false); +// setDraggedSphere(null); + +// const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); +// if (sphereIndex !== -1) { +// const zoneIndex = Math.floor(sphereIndex / 4); + +// if (zoneIndex !== -1 && zones[zoneIndex]) { +// updateZoneToBackend(zones[zoneIndex]); +// } +// } +// } +// } +// }; + +// const onMouseMove = () => { +// if (!groupsRef.current) return; +// if (isLeftMouseDown) { +// drag = true; +// } +// raycaster.setFromCamera(pointer, camera); + +// if (isDragging && draggedSphere) { +// raycaster.setFromCamera(pointer, camera); +// const intersectionPoint = new THREE.Vector3(); +// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); +// if (point) { +// draggedSphere.set(point.x, 0.15, point.z); + +// const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); +// if (sphereIndex !== -1) { +// const zoneIndex = Math.floor(sphereIndex / 4); +// const cornerIndex = sphereIndex % 4; + +// const updatedZones = zones.map((zone: any, index: number) => { +// if (index === zoneIndex) { +// const updatedPoints = [...zone.points]; +// updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; +// updatedPoints[4] = updatedPoints[0]; +// return { ...zone, points: updatedPoints }; +// } +// return zone; +// }); + +// setZones(updatedZones); +// } +// } +// } +// }; + +// const onContext = (event: any) => { +// event.preventDefault(); +// setStartPoint(null); +// setEndPoint(null); +// }; + +// if (toolMode === "Zone" || toolMode === '2D-Delete' || toolMode === "move") { +// canvasElement.addEventListener("mousedown", onMouseDown); +// canvasElement.addEventListener("mouseup", onMouseUp); +// canvasElement.addEventListener("mousemove", onMouseMove); +// canvasElement.addEventListener("contextmenu", onContext); +// } +// return () => { +// canvasElement.removeEventListener("mousedown", onMouseDown); +// canvasElement.removeEventListener("mouseup", onMouseUp); +// canvasElement.removeEventListener("mousemove", onMouseMove); +// canvasElement.removeEventListener("contextmenu", onContext); +// }; +// }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, zonePoints, draggedSphere, activeLayer, raycaster, pointer, controls, plane, setZones, setZonePoints, addZoneToBackend, handleDeleteZone, updateZoneToBackend, selectedVersion?.versionId]); + +// useFrame(() => { +// if (!startPoint) return; +// raycaster.setFromCamera(pointer, camera); +// const intersectionPoint = new THREE.Vector3(); +// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); +// if (point) { +// setEndPoint(point); +// } +// }); + +// return ( +// +// +// {zones.map((zone: any) => ( +// +// {zone.points +// .slice(0, -1) +// .map((point: [number, number, number], index: number) => { +// const nextPoint = zone.points[index + 1]; + +// const point1 = new THREE.Vector3(point[0], point[1], point[2]); +// const point2 = new THREE.Vector3( +// nextPoint[0], +// nextPoint[1], +// nextPoint[2] +// ); + +// const planeWidth = point1.distanceTo(point2); +// const planeHeight = CONSTANTS.zoneConfig.height; + +// const midpoint = new THREE.Vector3( +// (point1.x + point2.x) / 2, +// CONSTANTS.zoneConfig.height / 2 + +// (zone.layer - 1) * CONSTANTS.zoneConfig.height, +// (point1.z + point2.z) / 2 +// ); + +// const angle = Math.atan2( +// point2.z - point1.z, +// point2.x - point1.x +// ); + +// return ( +// +// +// +// +// ); +// })} +// {!toggleView && +// (() => { +// const points3D = zone.points || []; +// const coords2D = points3D.map((p: any) => [p[0], p[2]]); + +// // Ensure the polygon is closed +// if ( +// coords2D.length >= 4 && +// (coords2D[0][0] !== coords2D[coords2D.length - 1][0] || +// coords2D[0][1] !== coords2D[coords2D.length - 1][1]) +// ) { +// coords2D.push(coords2D[0]); +// } +// if (coords2D.length < 4) return null; + +// const polygon = turf.polygon([coords2D]); +// const center2D = turf.center(polygon).geometry.coordinates; + +// // Calculate the average Y value +// const sumY = points3D.reduce( +// (sum: number, p: any) => sum + p[1], +// 0 +// ); +// const avgY = points3D.length > 0 ? sumY / points3D.length : 0; + +// const htmlPosition: [number, number, number] = [ +// center2D[0], +// avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5, +// center2D[1], +// ]; + +// return ( +// +//
{zone.zoneName}
+// +// ); +// })()} +//
+// ))} +//
+// +// {zones +// .filter((zone: any) => zone.layer === activeLayer) +// .map((zone: any) => ( +// { +// e.stopPropagation(); +// if (toolMode === '2D-Delete') { +// handleDeleteZone(zone.zoneUuid); +// } +// }} +// /> +// ))} +// +// +// {zones.map((zone: any, index: any) => { +// if (!toggleView) return null; +// const points3D = zone.points; +// const coords2D = points3D.map((p: any) => [p[0], p[2]]); + +// if ( +// coords2D.length < 4 || +// coords2D[0][0] !== coords2D[coords2D.length - 1][0] || +// coords2D[0][1] !== coords2D[coords2D.length - 1][1] +// ) { +// coords2D.push(coords2D[0]); +// } +// if (coords2D.length < 4) return null; + +// const polygon = turf.polygon([coords2D]); +// const center2D = turf.center(polygon).geometry.coordinates; + +// const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0); +// const avgY = sumY / points3D.length; + +// const area = computeArea(points3D, "zone"); +// const formattedArea = `${area.toFixed(2)} m²`; + +// const htmlPosition: [number, number, number] = [ +// center2D[0], +// avgY + CONSTANTS.zoneConfig.height, +// center2D[1], +// ]; +// return ( +// +//
+// {zone.zoneName} ({formattedArea}) +//
+// +// ); +// })} +//
+ +// +// {zones +// .filter((zone: any) => zone.layer === activeLayer) +// .flatMap((zone: any) => +// zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( +// +// +// +// )) +// )} +// +// +// {startPoint && endPoint && ( +// +// )} +// +//
+// ); +// }; + +// export default ZoneGroup; diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx index 267c91f..98d00fc 100644 --- a/app/src/modules/builder/wall/Instances/wallInstances.tsx +++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx @@ -17,7 +17,7 @@ import texturePathDark from "../../../../assets/textures/floor/black.png"; function WallInstances() { const { wallStore } = useSceneContext(); const { walls } = wallStore(); - const { rooms } = useWallClassification(walls) + const { rooms } = useWallClassification(walls); const { toggleView } = useToggleView(); useEffect(() => { diff --git a/app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx b/app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx new file mode 100644 index 0000000..9828d14 --- /dev/null +++ b/app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx @@ -0,0 +1,50 @@ +import { useMemo } from 'react'; +import { DoubleSide, Shape, Vector2 } from 'three'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../types/world/worldConstants'; + +function Zone2DInstance({ zone }: { zone: Zone }) { + const savedTheme: string | null = localStorage.getItem("theme"); + + const shape = useMemo(() => { + const shape = new Shape(); + const points = zone.points.map(p => new Vector2(p.position[0], p.position[2])); + if (points.length < 3) return null; + shape.moveTo(points[0].x, points[0].y); + for (let i = 1; i < points.length; i++) { + shape.lineTo(points[i].x, points[i].y); + } + return shape; + }, [zone]); + + if (!shape) return null; + + return ( + + + + + + ); +} + +export default Zone2DInstance; \ No newline at end of file diff --git a/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx b/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx new file mode 100644 index 0000000..5c29d5a --- /dev/null +++ b/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx @@ -0,0 +1,73 @@ +import { useMemo } from 'react' +import { Color, DoubleSide, ShaderMaterial } from 'three'; +import { Vector3 } from 'three'; + +function ZoneInstance({ zone }: { zone: Zone }) { + const zoneLayer = zone.points[0].layer; + + const zoneMaterial = useMemo(() => { + return new ShaderMaterial({ + side: DoubleSide, + vertexShader: ` + varying vec2 vUv; + void main(){ + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + vUv = uv; + } + `, + fragmentShader: ` + varying vec2 vUv; + uniform vec3 uOuterColor; + void main(){ + float alpha = 1.0 - vUv.y; + gl_FragColor = vec4(uOuterColor, alpha); + } + `, + uniforms: { + uOuterColor: { value: new Color(zone.zoneColor) }, + }, + transparent: true, + depthWrite: false, + }) + }, []); + + return ( + <> + + {zone.points.slice(0, -1).map((point, index: number) => { + const nextPoint = zone.points[index + 1]; + + const point1 = new Vector3(point.position[0], point.position[1], point.position[2]); + const point2 = new Vector3(nextPoint.position[0], nextPoint.position[1], nextPoint.position[2]); + + const planeWidth = point1.distanceTo(point2); + const planeHeight = zone.zoneHeight; + + const midpoint = new Vector3((point1.x + point2.x) / 2, zone.zoneHeight / 2 + (zoneLayer - 1) * zone.zoneHeight, (point1.z + point2.z) / 2); + + const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x); + + return ( + + + + + ); + })} + + + + ) +} + +export default ZoneInstance \ No newline at end of file diff --git a/app/src/modules/builder/zone/Instances/zoneInstances.tsx b/app/src/modules/builder/zone/Instances/zoneInstances.tsx new file mode 100644 index 0000000..48b426c --- /dev/null +++ b/app/src/modules/builder/zone/Instances/zoneInstances.tsx @@ -0,0 +1,132 @@ +import React, { useEffect, useMemo } from 'react'; +import { Vector3 } from 'three'; +import { Html } from '@react-three/drei'; +import { useSceneContext } from '../../../scene/sceneContext'; +import { useToggleView } from '../../../../store/builder/store'; +import Line from '../../line/line'; +import Point from '../../point/point'; +import ZoneInstance from './Instance/zoneInstance'; +import Zone2DInstance from './Instance/zone2DInstance'; + +function ZoneInstances() { + const { zoneStore } = useSceneContext(); + const { zones } = zoneStore(); + const { toggleView } = useToggleView(); + + useEffect(() => { + console.log('zones: ', zones); + }, [zones]); + + const allPoints = useMemo(() => { + const points: Point[] = []; + const seenUuids = new Set(); + + zones.forEach(zone => { + zone.points.forEach(point => { + if (!seenUuids.has(point.pointUuid)) { + seenUuids.add(point.pointUuid); + points.push(point); + } + }); + }); + + return points; + }, [zones]); + + const allLines = useMemo(() => { + const lines: { start: Point; end: Point; key: string }[] = []; + const seenUuids = new Set(); + + zones.forEach((zone) => { + const points = zone.points; + if (points.length < 2) return; + + for (let i = 0; i < points.length; i++) { + const current = points[i]; + const next = points[(i + 1) % points.length]; + const lineKey = `${current.pointUuid}-${next.pointUuid}`; + if (current.pointUuid !== next.pointUuid && !seenUuids.has(lineKey)) { + seenUuids.add(lineKey); + lines.push({ + start: current, + end: next, + key: lineKey + }); + } + } + }); + + return lines; + }, [zones]); + + return ( + <> + + {!toggleView && zones.length > 0 && ( + + {zones.map((zone) => ( + + ))} + + )} + + {toggleView && zones.length > 0 && ( + + {zones.map((zone) => ( + + ))} + + )} + + {toggleView && ( + <> + + {allPoints.map((point) => ( + + ))} + + + + + {allLines.map(({ start, end, key }) => ( + + ))} + + {allLines.map((line) => { + const { start, end, key } = line; + const textPosition = new Vector3().addVectors(new Vector3(...start.position), new Vector3(...end.position)).divideScalar(2); + const distance = new Vector3(...start.position).distanceTo(new Vector3(...end.position)); + + return ( + + {toggleView && + +
+ {distance.toFixed(2)} m +
+ + } +
+ ) + })} + +
+ + )} + + ) +} + +export default ZoneInstances \ No newline at end of file diff --git a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx new file mode 100644 index 0000000..a237b59 --- /dev/null +++ b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function ZoneCreator() { + return ( + <> + + ) +} + +export default ZoneCreator \ No newline at end of file diff --git a/app/src/modules/builder/zone/zoneGroup.tsx b/app/src/modules/builder/zone/zoneGroup.tsx new file mode 100644 index 0000000..46bddb7 --- /dev/null +++ b/app/src/modules/builder/zone/zoneGroup.tsx @@ -0,0 +1,54 @@ +import { useEffect } from 'react'; +import { useToggleView } from '../../../store/builder/store'; +import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import { useVersionContext } from '../version/versionContext'; +import { useSceneContext } from '../../scene/sceneContext'; +import { useParams } from 'react-router-dom'; +import useModuleStore from '../../../store/useModuleStore'; +import ZoneCreator from './zoneCreator/zoneCreator'; +import ZoneInstances from './Instances/zoneInstances'; + +import { getZonesApi } from '../../../services/factoryBuilder/zone/getZonesApi'; + +function ZoneGroup() { + const { togglView } = useToggleView(); + const { setSelectedZone } = useBuilderStore(); + const { activeModule } = useModuleStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { zoneStore } = useSceneContext(); + const { setZones } = zoneStore(); + const { projectId } = useParams(); + + useEffect(() => { + if (togglView || activeModule !== 'builder') { + setSelectedZone(null); + } + }, [togglView, activeModule]) + + useEffect(() => { + if (projectId && selectedVersion) { + getZonesApi(projectId, selectedVersion?.versionId || '').then((zones) => { + if (zones && zones.length > 0) { + setZones(zones); + } else { + setZones([]); + } + }).catch((err) => { + console.log(err); + }) + } + }, [projectId, selectedVersion?.versionId]) + + return ( + <> + + + + + + + ) +} + +export default ZoneGroup \ No newline at end of file diff --git a/app/src/modules/market/MarketPlace.tsx b/app/src/modules/market/MarketPlace.tsx index 1bf446e..85720d2 100644 --- a/app/src/modules/market/MarketPlace.tsx +++ b/app/src/modules/market/MarketPlace.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import FilterSearch from "./FilterSearch"; import CardsContainer from "./CardsContainer"; -import { getAssetImages } from "../../services/factoryBuilder/assest/assets/getAssetImages"; +import { getAssetImages } from "../../services/factoryBuilder/asset/assets/getAssetImages"; import SkeletonUI from "../../components/templates/SkeletonUI"; interface ModelData { CreatedBy: string; diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx index 5e0333e..3b9d232 100644 --- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx @@ -2,7 +2,7 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; -// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi'; +// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useParams } from "react-router-dom"; diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx index ef56601..5194952 100644 --- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx @@ -2,7 +2,7 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; -// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi'; +// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useParams } from "react-router-dom"; diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index e246081..79cf195 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -2,7 +2,7 @@ import * as THREE from "three"; import { useEffect, useMemo, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedAssets, useSocketStore, useToggleView, } from "../../../../store/builder/store"; -// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi'; +// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 6592e72..216d4f7 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -2,7 +2,7 @@ import * as THREE from "three"; import { useEffect, useMemo, useRef } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; -// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi'; +// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; import * as Types from "../../../../types/world/worldTypes"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { useParams } from "react-router-dom"; diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 1f26a6b..fdc6d9a 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -5,7 +5,7 @@ import { SelectionHelper } from "./selectionHelper"; import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedAssets, useSocketStore, useToggleView, useToolMode, } from "../../../../store/builder/store"; import BoundingBox from "./boundingBoxHelper"; -// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; +// import { deleteFloorItem } from '../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; import DuplicationControls from "./duplicationControls"; diff --git a/app/src/modules/scene/controls/transformControls/transformControls.tsx b/app/src/modules/scene/controls/transformControls/transformControls.tsx index 0b6a061..e0ce1cf 100644 --- a/app/src/modules/scene/controls/transformControls/transformControls.tsx +++ b/app/src/modules/scene/controls/transformControls/transformControls.tsx @@ -6,7 +6,7 @@ import { useThree } from "@react-three/fiber"; import { useEffect, useState } from "react"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; -// import { setAssetsApi } from "../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi"; +// import { setAssetsApi } from "../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi"; import { useParams } from "react-router-dom"; import { useProductContext } from "../../../simulation/products/productContext"; import { getUserData } from "../../../../functions/getUserData"; diff --git a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts deleted file mode 100644 index a959ebe..0000000 --- a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts +++ /dev/null @@ -1,42 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const deleteWallItem = async ( - organization: string, - modelUuid: string, - modelName: string -) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/V1/wallItems/delete`, - { - method: "DELETE", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ organization, modelUuid, modelName }), - } - ); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - - if (!response.ok) { - console.error("Failed to delete Wall Item"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to delete wall items"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts deleted file mode 100644 index ca72867..0000000 --- a/app/src/services/factoryBuilder/assest/wallAsset/getWallItemsApi.ts +++ /dev/null @@ -1,37 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const getWallItems = async (organization: string, projectId?: string, versionId?: string) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/V1/wallItems/${projectId}/${versionId}`, - { - method: "GET", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - } - ); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - // console.log('response: ', response); - if (!response.ok) { - console.error("Failed to get Wall Items"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to get wall items"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts deleted file mode 100644 index 4a7aab4..0000000 --- a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts +++ /dev/null @@ -1,55 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const setWallItem = async ( - organization: string, - modelUuid: string, - modelName: string, - type: string, - csgposition: Object, - csgscale: Object, - position: Object, - quaternion: Object, - scale: Object -) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/V1/wallItems`, { - method: "POST", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ - organization, - modelUuid, - modelName, - position, - type, - csgposition, - csgscale, - quaternion, - scale, - }), - }); - - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - if (!response.ok) { - console.error("Failed to set or update Wall Item"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to set wall items"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/assest/assets/getAssetImages.ts b/app/src/services/factoryBuilder/asset/assets/getAssetImages.ts similarity index 96% rename from app/src/services/factoryBuilder/assest/assets/getAssetImages.ts rename to app/src/services/factoryBuilder/asset/assets/getAssetImages.ts index faba588..7bc7fca 100644 --- a/app/src/services/factoryBuilder/assest/assets/getAssetImages.ts +++ b/app/src/services/factoryBuilder/asset/assets/getAssetImages.ts @@ -1,24 +1,24 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - -export const getAssetImages = async (cursor?: string) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/v3/AssetDatas?limit=10${cursor ? `&cursor=${cursor}` : ""}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ); - - if (!response.ok) { - console.error("Failed to fetch assets"); - } - - return await response.json(); - } catch (error: any) { - echo.error("Failed to get asset image"); - console.log(error.message); - } -}; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; + +export const getAssetImages = async (cursor?: string) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v3/AssetDatas?limit=10${cursor ? `&cursor=${cursor}` : ""}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + console.error("Failed to fetch assets"); + } + + return await response.json(); + } catch (error: any) { + echo.error("Failed to get asset image"); + console.log(error.message); + } +}; diff --git a/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts b/app/src/services/factoryBuilder/asset/assets/getAssetModel.ts similarity index 96% rename from app/src/services/factoryBuilder/assest/assets/getAssetModel.ts rename to app/src/services/factoryBuilder/asset/assets/getAssetModel.ts index 91c33b3..27fe88a 100644 --- a/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts +++ b/app/src/services/factoryBuilder/asset/assets/getAssetModel.ts @@ -1,29 +1,29 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - -export const getAssetModel = async (modelId: string) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/v2/AssetFile/${modelId}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ); - - if (!response.ok) { - console.error("Failed to fetch model"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to get asset model"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; + +export const getAssetModel = async (modelId: string) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/AssetFile/${modelId}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + console.error("Failed to fetch model"); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to get asset model"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts b/app/src/services/factoryBuilder/asset/assets/getCategoryAsset.ts similarity index 100% rename from app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts rename to app/src/services/factoryBuilder/asset/assets/getCategoryAsset.ts diff --git a/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts b/app/src/services/factoryBuilder/asset/floorAsset/deleteFloorItemApi.ts similarity index 96% rename from app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts rename to app/src/services/factoryBuilder/asset/floorAsset/deleteFloorItemApi.ts index a509909..1e66ec7 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts +++ b/app/src/services/factoryBuilder/asset/floorAsset/deleteFloorItemApi.ts @@ -1,42 +1,42 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const deleteFloorItem = async ( - organization: string, - modelUuid: string, - modelName: string -) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/v1/deletefloorItem`, - { - method: "DELETE", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ organization, modelUuid, modelName }), - } - ); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - - if (!response.ok) { - console.error("Failed to delete Floor Item"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to delete floor item"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteFloorItem = async ( + organization: string, + modelUuid: string, + modelName: string +) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v1/deletefloorItem`, + { + method: "DELETE", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ organization, modelUuid, modelName }), + } + ); + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + //console.log("New token received:", newAccessToken); + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to delete Floor Item"); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to delete floor item"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts b/app/src/services/factoryBuilder/asset/floorAsset/getFloorItemsApi.ts similarity index 96% rename from app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts rename to app/src/services/factoryBuilder/asset/floorAsset/getFloorItemsApi.ts index 83038fc..5ead053 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts +++ b/app/src/services/factoryBuilder/asset/floorAsset/getFloorItemsApi.ts @@ -1,39 +1,39 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const getFloorAssets = async (organization: string, projectId?: string, versionId?: string) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/V1/floorAssets/${projectId}/${versionId}`, - { - method: "GET", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - } - ); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - - // console.log('response: ', response); - if (!response.ok) { - console.error("Failed to get assets"); - } - - const result = await response.json(); - - return result; - } catch (error) { - echo.error("Failed to get floor asset"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getFloorAssets = async (organization: string, projectId?: string, versionId?: string) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/V1/floorAssets/${projectId}/${versionId}`, + { + method: "GET", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + } + ); + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + //console.log("New token received:", newAccessToken); + localStorage.setItem("token", newAccessToken); + } + + // console.log('response: ', response); + if (!response.ok) { + console.error("Failed to get assets"); + } + + const result = await response.json(); + + return result; + } catch (error) { + echo.error("Failed to get floor asset"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setAssetsApi.ts b/app/src/services/factoryBuilder/asset/floorAsset/setAssetsApi.ts similarity index 100% rename from app/src/services/factoryBuilder/assest/floorAsset/setAssetsApi.ts rename to app/src/services/factoryBuilder/asset/floorAsset/setAssetsApi.ts diff --git a/app/src/services/factoryBuilder/lines/deleteLayerApi.ts b/app/src/services/factoryBuilder/lines/deleteLayerApi.ts deleted file mode 100644 index f271061..0000000 --- a/app/src/services/factoryBuilder/lines/deleteLayerApi.ts +++ /dev/null @@ -1,34 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const deleteLayer = async (organization: string, layer: number) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/deleteLayer`, { - method: "POST", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ organization, layer }), - }); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - if (!response.ok) { - console.error("Failed to delete line"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to delete line"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/lines/deleteLineApi.ts b/app/src/services/factoryBuilder/lines/deleteLineApi.ts deleted file mode 100644 index bd04ee4..0000000 --- a/app/src/services/factoryBuilder/lines/deleteLineApi.ts +++ /dev/null @@ -1,34 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const deleteLineApi = async (organization: string, line: Object) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/deleteLine`, { - method: "DELETE", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ organization, line }), - }); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - if (!response.ok) { - console.error("Failed to delete line"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to delete line"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/lines/deletePointApi.ts b/app/src/services/factoryBuilder/lines/deletePointApi.ts deleted file mode 100644 index bc5b2d0..0000000 --- a/app/src/services/factoryBuilder/lines/deletePointApi.ts +++ /dev/null @@ -1,35 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const deletePointApi = async (organization: string, uuid: string) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/deletePoint`, { - method: "DELETE", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ organization, uuid }), - }); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - - if (!response.ok) { - console.error("Failed to delete point"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to delete point"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/lines/getLinesApi.ts b/app/src/services/factoryBuilder/lines/getLinesApi.ts deleted file mode 100644 index ca520f1..0000000 --- a/app/src/services/factoryBuilder/lines/getLinesApi.ts +++ /dev/null @@ -1,38 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const getLines = async (organization: string, projectId?: string, versionId?: string) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/V1/lines/${projectId}/${versionId}`, - { - method: "GET", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - } - ); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - - if (!response.ok) { - console.error("Failed to get Lines"); - } - - const result = await response.json(); - // console.log('result: ', result); - return result; - } catch (error) { - echo.error("Failed to get Lines"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/lines/setLineApi.ts b/app/src/services/factoryBuilder/lines/setLineApi.ts deleted file mode 100644 index 9269514..0000000 --- a/app/src/services/factoryBuilder/lines/setLineApi.ts +++ /dev/null @@ -1,41 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const setLine = async ( - organization: string, - layer: number, - line: Object, - type: string -) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/setLine`, { - method: "POST", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ organization, layer, line, type }), - }); - - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - - if (!response.ok) { - console.error("Failed to set line"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to set line"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/lines/updatePointApi.ts b/app/src/services/factoryBuilder/lines/updatePointApi.ts deleted file mode 100644 index ae1b917..0000000 --- a/app/src/services/factoryBuilder/lines/updatePointApi.ts +++ /dev/null @@ -1,38 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const updatePoint = async ( - organization: string, - position: Object, - uuid: string -) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/updatePoint`, { - method: "POST", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ organization, position, uuid }), - }); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - if (!response.ok) { - console.error("Failed to update point"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to update point"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/zone/deleteZoneApi.ts b/app/src/services/factoryBuilder/zone/deleteZoneApi.ts new file mode 100644 index 0000000..1f2b63b --- /dev/null +++ b/app/src/services/factoryBuilder/zone/deleteZoneApi.ts @@ -0,0 +1,39 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteZoneApi = async ( + projectId: string, + versionId: string, + zoneUuid: string +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V2/deleteZone`, { + method: "PATCH", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, zoneUuid }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to delete zone:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to delete zone"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/zone/getZonesApi.ts b/app/src/services/factoryBuilder/zone/getZonesApi.ts new file mode 100644 index 0000000..df94fef --- /dev/null +++ b/app/src/services/factoryBuilder/zone/getZonesApi.ts @@ -0,0 +1,37 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getZonesApi = async ( + projectId: string, + versionId: string, +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V2/zones/${projectId}/${versionId}`, { + method: "GET", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to get zones:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to get zones"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/zone/upsertZoneApi.ts b/app/src/services/factoryBuilder/zone/upsertZoneApi.ts new file mode 100644 index 0000000..eeab930 --- /dev/null +++ b/app/src/services/factoryBuilder/zone/upsertZoneApi.ts @@ -0,0 +1,39 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const upsertWallApi = async ( + projectId: string, + versionId: string, + ZoneData: Zone +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V2/UpsertZone`, { + method: "POST", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, ZoneData }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to upsert zone:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to upsert zone"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/zones/deleteZoneApi.ts b/app/src/services/factoryBuilder/zones/deleteZoneApi.ts deleted file mode 100644 index f0ee326..0000000 --- a/app/src/services/factoryBuilder/zones/deleteZoneApi.ts +++ /dev/null @@ -1,39 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const deleteZonesApi = async ( - userId: string, - organization: string, - zoneUuid: string -) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/setLine`, { - method: "POST", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ userId, organization, zoneUuid }), - }); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - if (!response.ok) { - console.error("Failed to delete zone"); - } - - const result = await response.json(); - - return result; - } catch (error) { - echo.error("Failed to delete zone"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/zones/getZonesApi.ts b/app/src/services/factoryBuilder/zones/getZonesApi.ts deleted file mode 100644 index 39f91a3..0000000 --- a/app/src/services/factoryBuilder/zones/getZonesApi.ts +++ /dev/null @@ -1,40 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -// let url_Backend_dwinzo = `http://192.168.0.102:5000`; - -export const getZonesApi = async (organization: string, projectId?: string, versionId?: string) => { - try { - const response = await fetch( - `${url_Backend_dwinzo}/api/V1/zones/${projectId}/${versionId}`, - { - method: "GET", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - } - ); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - - if (!response.ok) { - console.error("Failed to get Zones"); - } - - const result = await response.json(); - // console.log('result:zone ', result); - - return result; - } catch (error) { - echo.error("Failed to get zone data"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/services/factoryBuilder/zones/setZonesApi.ts b/app/src/services/factoryBuilder/zones/setZonesApi.ts deleted file mode 100644 index b5aa678..0000000 --- a/app/src/services/factoryBuilder/zones/setZonesApi.ts +++ /dev/null @@ -1,38 +0,0 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - -export const setZonesApi = async ( - userId: string, - organization: string, - zoneData: any -) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/setLine`, { - method: "POST", - headers: { - Authorization: "Bearer ", - "Content-Type": "application/json", - token: localStorage.getItem("token") || "", - refresh_token: localStorage.getItem("refreshToken") || "", - }, - body: JSON.stringify({ userId, organization, zoneData }), - }); - const newAccessToken = response.headers.get("x-access-token"); - if (newAccessToken) { - //console.log("New token received:", newAccessToken); - localStorage.setItem("token", newAccessToken); - } - if (!response.ok) { - console.error("Failed to set zone"); - } - - const result = await response.json(); - return result; - } catch (error) { - echo.error("Failed to zone data"); - if (error instanceof Error) { - console.log(error.message); - } else { - console.log("An unknown error occurred"); - } - } -}; diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index e7a60ca..066c2bb 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -24,6 +24,11 @@ interface BuilderState { sideMaterial: string; topMaterial: string; + // Zone Settings + selectedZone: Object3D | null; + zoneHeight: number; + zoneColor: string; + // Decal Settings selectedDecal: Object3D | null; @@ -59,6 +64,11 @@ interface BuilderState { setBevelStrength: (strength: number) => void; setFloorMaterial: (material: string, side: 'side' | 'top') => void; + // Setters - Zone + setSelectedZone: (zone: Object3D | null) => void; + setZoneHeight: (height: number) => void; + setZoneColor: (color: string) => void; + // Setters - Decal setSelectedDecal: (decal: Object3D | null) => void; @@ -103,6 +113,10 @@ export const useBuilderStore = create()( sideMaterial: 'Material 1', topMaterial: 'Default Material', + selectedZone: null, + zoneHeight: 7, + zoneColor: 'blue', + selectedDecal: null, selectedAisle: null, @@ -201,6 +215,26 @@ export const useBuilderStore = create()( }); }, + // === Setters: Zone === + + setSelectedZone: (zone: Object3D | null) => { + set((state) => { + state.selectedZone = zone; + }); + }, + + setZoneHeight: (height: number) => { + set((state) => { + state.zoneHeight = height; + }); + }, + + setZoneColor: (color: string) => { + set((state) => { + state.zoneColor = color; + }); + }, + // === Setters: Decal === setSelectedDecal: (decal: Object3D | null) => { diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts index 3740c13..39ff2a0 100644 --- a/app/src/store/builder/useZoneStore.ts +++ b/app/src/store/builder/useZoneStore.ts @@ -7,11 +7,12 @@ interface ZoneStore { addZone: (zone: Zone) => void; updateZone: (uuid: string, updated: Partial) => void; setZoneName: (uuid: string, name: string) => void; + setZoneHeight: (uuid: string, height: number) => void; + setZoneColor: (uuid: string, color: string) => void; removeZone: (uuid: string) => void; removePointFromZones: (pointUuid: string) => void; clearZones: () => void; setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void; - setColor: (uuid: string, color: string) => void; getZoneById: (uuid: string) => Zone | undefined; } @@ -43,6 +44,20 @@ export const createZoneStore = () => { } }), + setZoneHeight: (uuid, height) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + zone.zoneHeight = height; + } + }), + + setZoneColor: (uuid, color) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + zone.zoneColor = color; + } + }), + removeZone: (uuid) => set(state => { state.zones = state.zones.filter(z => z.zoneUuid !== uuid); }), @@ -65,13 +80,6 @@ export const createZoneStore = () => { } }), - setColor: (uuid, color) => set(state => { - const zone = state.zones.find(z => z.zoneUuid === uuid); - if (zone) { - zone.zoneColor = color; - } - }), - getZoneById: (uuid) => { return get().zones.find(z => z.zoneUuid === uuid); }, diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index c7eef96..d346547 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -131,6 +131,7 @@ type Floors = Floor[]; interface Zone { zoneUuid: string; zoneName: string; + zoneHeight: number; zoneColor: string; points: Point[]; viewPortTarget: [number, number, number]; From 90df6c2b011189d813e9fbbff0c32c0131bddfa3 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 18:06:19 +0530 Subject: [PATCH 12/18] Refactor: Update useEffect dependencies to include activeLayer for ReferenceAisle, ReferenceFloor, ReferenceWall; enhance usePointSnapping with zone snapping functionality and add ReferenceZone component for zone management --- .../aisle/aisleCreator/referenceAisle.tsx | 2 +- .../floor/floorCreator/referenceFloor.tsx | 2 +- .../point/helpers/usePointSnapping.tsx | 92 +++++++++- .../wall/wallCreator/referenceWall.tsx | 2 +- .../zone/zoneCreator/referenceZone.tsx | 163 ++++++++++++++++++ .../builder/zone/zoneCreator/zoneCreator.tsx | 12 +- app/src/store/builder/useZoneStore.ts | 12 ++ 7 files changed, 280 insertions(+), 5 deletions(-) create mode 100644 app/src/modules/builder/zone/zoneCreator/referenceZone.tsx diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx index 10bf6fa..6ce66fe 100644 --- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx @@ -177,7 +177,7 @@ function ReferenceAisle({ tempPoints }: Readonly) { useEffect(() => { setTempAisle(null); - }, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor]); + }, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor, activeLayer]); if (!tempAisle) return null; diff --git a/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx index 3c9d593..dde2002 100644 --- a/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx +++ b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx @@ -83,7 +83,7 @@ function ReferenceFloor({ tempPoints }: Readonly) { useEffect(() => { setTempFloor(null); - }, [toolMode, toggleView, tempPoints.length, floorDepth, bevelStrength, isBeveled]); + }, [toolMode, toggleView, tempPoints.length, floorDepth, bevelStrength, isBeveled, activeLayer]); const allLines = useMemo(() => { if (!tempFloor || tempFloor.points.length < 2) return []; diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx index 0d8f378..69f5e72 100644 --- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx +++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx @@ -11,10 +11,11 @@ const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping i const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => { - const { aisleStore, wallStore, floorStore } = useSceneContext(); + const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext(); const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore(); const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore(); const { floors, getConnectedPoints: getConnectedFloorPoints } = floorStore(); + const { zones, getConnectedPoints: getConnectedZonePoints } = zoneStore(); // Wall Snapping @@ -278,6 +279,93 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string }; }, [currentPoint, getConnectedFloorPoints]); + // Zone Snapping + + const getAllOtherZonePoints = useCallback(() => { + if (!currentPoint) return []; + + return zones.flatMap(zone => + zone.points.filter(point => point.pointUuid !== currentPoint.uuid) + ); + }, [zones, currentPoint]); + + const snapZonePoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => { + if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null }; + + const otherPoints = getAllOtherZonePoints(); + if (tempPoints) { + otherPoints.concat(tempPoints); + } + const currentVec = new THREE.Vector3(...position); + + for (const point of otherPoints) { + const pointVec = new THREE.Vector3(...point.position); + const distance = currentVec.distanceTo(pointVec); + + if (distance <= POINT_SNAP_THRESHOLD && currentPoint.pointType === 'Zone') { + return { position: point.position, isSnapped: true, snappedPoint: point }; + } + } + + return { position: position, isSnapped: false, snappedPoint: null }; + }, [currentPoint, getAllOtherZonePoints]); + + const snapZoneAngle = useCallback((newPosition: [number, number, number]): { + position: [number, number, number], + isSnapped: boolean, + snapSources: THREE.Vector3[] + } => { + if (!currentPoint || !CAN_ANGLE_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] }; + + const connectedPoints = getConnectedZonePoints(currentPoint.uuid); + if (connectedPoints.length === 0) { + return { position: newPosition, isSnapped: false, snapSources: [] }; + } + + const newPos = new THREE.Vector3(...newPosition); + let closestX: { pos: THREE.Vector3, dist: number } | null = null; + let closestZ: { pos: THREE.Vector3, dist: number } | null = null; + + for (const connectedPoint of connectedPoints) { + const cPos = new THREE.Vector3(...connectedPoint.position); + const xDist = Math.abs(newPos.x - cPos.x); + const zDist = Math.abs(newPos.z - cPos.z); + + if (xDist < ANGLE_SNAP_DISTANCE_THRESHOLD) { + if (!closestX || xDist < closestX.dist) { + closestX = { pos: cPos, dist: xDist }; + } + } + + if (zDist < ANGLE_SNAP_DISTANCE_THRESHOLD) { + if (!closestZ || zDist < closestZ.dist) { + closestZ = { pos: cPos, dist: zDist }; + } + } + } + + const snappedPos = newPos.clone(); + const snapSources: THREE.Vector3[] = []; + + if (closestX) { + snappedPos.x = closestX.pos.x; + snapSources.push(closestX.pos.clone()); + } + + if (closestZ) { + snappedPos.z = closestZ.pos.z; + snapSources.push(closestZ.pos.clone()); + } + + const isSnapped = snapSources.length > 0; + + return { + position: [snappedPos.x, snappedPos.y, snappedPos.z], + isSnapped, + snapSources + }; + }, [currentPoint, getConnectedZonePoints]); + return { snapAislePoint, snapAisleAngle, @@ -285,5 +373,7 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string snapWallAngle, snapFloorPoint, snapFloorAngle, + snapZonePoint, + snapZoneAngle, }; }; \ No newline at end of file diff --git a/app/src/modules/builder/wall/wallCreator/referenceWall.tsx b/app/src/modules/builder/wall/wallCreator/referenceWall.tsx index 278fe67..905c60d 100644 --- a/app/src/modules/builder/wall/wallCreator/referenceWall.tsx +++ b/app/src/modules/builder/wall/wallCreator/referenceWall.tsx @@ -82,7 +82,7 @@ function ReferenceWall({ tempPoints }: Readonly) { useEffect(() => { setTempWall(null); - }, [toolMode, toggleView, tempPoints.length, wallHeight, wallThickness]); + }, [toolMode, toggleView, tempPoints.length, wallHeight, wallThickness, activeLayer]); if (!tempWall) return null; diff --git a/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx b/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx new file mode 100644 index 0000000..940134f --- /dev/null +++ b/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx @@ -0,0 +1,163 @@ +import { useEffect, useRef, useState, useMemo } from 'react'; +import * as THREE from 'three'; +import { useFrame, useThree } from '@react-three/fiber'; +import { Extrude, Html } from '@react-three/drei'; +import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; +import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store'; +import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping'; +import { usePointSnapping } from '../../point/helpers/usePointSnapping'; +import ReferenceLine from '../../line/reference/referenceLine'; + +interface ReferenceZoneProps { + tempPoints: Point[]; +} + +function ReferenceZone({ tempPoints }: Readonly) { + const { zoneColor, zoneHeight, setSnappedPosition, setSnappedPoint } = useBuilderStore(); + const { pointer, raycaster, camera } = useThree(); + const { toolMode } = useToolMode(); + const { toggleView } = useToggleView(); + const { activeLayer } = useActiveLayer(); + const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); + const finalPosition = useRef<[number, number, number] | null>(null); + + const [tempZone, setTempZone] = useState(null); + const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position); + + const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[tempPoints.length - 1]?.position || null); + const { snapZonePoint } = usePointSnapping({ uuid: 'temp-Zone', pointType: 'Zone', position: directionalSnap.position || [0, 0, 0], }); + + useFrame(() => { + if (toolMode === 'Zone' && toggleView && tempPoints.length > 0) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + raycaster.ray.intersectPlane(plane, intersectionPoint); + + setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); + + if (!intersectionPoint) return; + const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.slice(0, -2)); + + if (snapped.isSnapped && snapped.snappedPoint) { + finalPosition.current = snapped.position; + setSnappedPosition(snapped.position); + setSnappedPoint(snapped.snappedPoint); + } else if (directionalSnap.isSnapped) { + finalPosition.current = directionalSnap.position; + setSnappedPosition(directionalSnap.position); + setSnappedPoint(null); + } else { + finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]; + setSnappedPosition(null); + setSnappedPoint(null); + } + + if (!finalPosition.current) return; + + const zonePoints: Point[] = [ + ...tempPoints, + { + pointUuid: 'temp-point', + pointType: 'Zone', + position: finalPosition.current, + layer: activeLayer, + }, + ]; + + setTempZone({ + zoneUuid: 'temp-zone', + zoneName: 'temp-zone', + points: zonePoints, + zoneColor, + zoneHeight, + viewPortPosition: [0, 0, 0], + viewPortTarget: [0, 0, 0], + }); + + } else if (tempZone !== null) { + setTempZone(null); + } + }); + + useEffect(() => { + setTempZone(null); + }, [toolMode, toggleView, tempPoints.length, zoneColor, zoneHeight, activeLayer]); + + const allLines = useMemo(() => { + if (!tempZone || tempZone.points.length < 2) return []; + + const lines: [Point, Point][] = []; + const pts = tempZone.points; + + for (let i = 0; i < pts.length - 1; i++) { + lines.push([pts[i], pts[i + 1]]); + } + + return lines; + }, [tempZone]); + + if (!tempZone) return null; + + return ( + + {allLines.map(([p1, p2], idx) => { + const v1 = new THREE.Vector3(...p1.position); + const v2 = new THREE.Vector3(...p2.position); + const mid = new THREE.Vector3().addVectors(v1, v2).multiplyScalar(0.5); + const dist = v1.distanceTo(v2); + + return ( + + + {toggleView && ( + +
{dist.toFixed(2)} m
+ + )} +
+ ); + })} + + {tempPoints.length >= 3 && ( + + )} +
+ ); +} + +export default ReferenceZone; + + +function Zone({ zone }: { zone: Point[] }) { + const savedTheme: string | null = localStorage.getItem('theme'); + + const shape = useMemo(() => { + const shape = new THREE.Shape(); + const points = zone.map(p => new THREE.Vector2(p.position[0], p.position[2])); + if (points.length < 3) return null; + shape.moveTo(points[0].x, points[0].y); + points.forEach((pt) => { shape.lineTo(pt.x, pt.y); }); + return shape; + }, [zone]); + + if (!shape) return null; + + return ( + + + + + + ); +} diff --git a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx index a237b59..af0fea2 100644 --- a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx +++ b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx @@ -1,4 +1,14 @@ -import React from 'react' +import * as THREE from 'three' +import { useEffect, useMemo, useRef, useState } from 'react' +import { useThree } from '@react-three/fiber'; +import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; +import { useSceneContext } from '../../../scene/sceneContext'; +import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; +import { useParams } from 'react-router-dom'; +import { useVersionContext } from '../../version/versionContext'; +import { getUserData } from '../../../../functions/getUserData'; +import ReferencePoint from '../../point/reference/referencePoint'; +import ReferenceZone from './referenceZone'; function ZoneCreator() { return ( diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts index 39ff2a0..148e88c 100644 --- a/app/src/store/builder/useZoneStore.ts +++ b/app/src/store/builder/useZoneStore.ts @@ -15,6 +15,7 @@ interface ZoneStore { setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void; getZoneById: (uuid: string) => Zone | undefined; + getConnectedPoints: (uuid: string) => Point[]; } export const createZoneStore = () => { @@ -83,6 +84,17 @@ export const createZoneStore = () => { getZoneById: (uuid) => { return get().zones.find(z => z.zoneUuid === uuid); }, + + getConnectedPoints: (pointUuid) => { + const connected: Point[] = []; + for (const zone of get().zones) { + if (zone.points.some(p => p.pointUuid === pointUuid)) { + connected.push(...zone.points.filter(p => p.pointUuid !== pointUuid)); + } + } + return connected; + } + })) ); }; From 7124a819b6ad97e5865a784f71527d6811f444aa Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 30 Jun 2025 12:22:42 +0530 Subject: [PATCH 13/18] feat: Implement zone management features including creation, deletion, and updates - Added zone handling in the Line component for removing and updating zones based on points. - Enhanced Point component to support snapping and updating zone positions. - Introduced zone-related API calls for upserting and deleting zones. - Updated zone store to manage zones more effectively, including methods for removing zones by points and getting zones by point IDs. - Improved zone instance rendering to handle dynamic point connections. - Refactored zone creation logic to allow for better interaction and snapping behavior. - Updated API endpoints for zone operations to use version 1 of the API. --- .../builder/asset/models/model/model.tsx | 17 +- .../floor/floorCreator/floorCreator.tsx | 57 +- .../floor/floorCreator/referenceFloor.tsx | 2 +- app/src/modules/builder/groups/zoneGroup.tsx | 651 ------------------ app/src/modules/builder/line/line.tsx | 83 ++- .../point/helpers/usePointSnapping.tsx | 8 +- app/src/modules/builder/point/point.tsx | 85 ++- .../instance/helpers/useWallClassification.ts | 5 +- .../zone/Instances/Instance/zoneInstance.tsx | 4 +- .../builder/zone/Instances/zoneInstances.tsx | 4 - .../zone/zoneCreator/referenceZone.tsx | 2 +- .../builder/zone/zoneCreator/zoneCreator.tsx | 241 +++++++ .../factoryBuilder/zone/deleteZoneApi.ts | 2 +- .../factoryBuilder/zone/getZonesApi.ts | 2 +- .../factoryBuilder/zone/upsertZoneApi.ts | 8 +- app/src/store/builder/store.ts | 1 + app/src/store/builder/useFloorStore.ts | 3 +- app/src/store/builder/useZoneStore.ts | 123 +++- 18 files changed, 601 insertions(+), 697 deletions(-) delete mode 100644 app/src/modules/builder/groups/zoneGroup.tsx diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index 9354232..2ffd49d 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -4,7 +4,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; import { ThreeEvent, useFrame, useThree } from '@react-three/fiber'; -import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store'; +import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store'; import { AssetBoundingBox } from '../../functions/assetBoundingBox'; import { CameraControls } from '@react-three/drei'; import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore'; @@ -34,6 +34,7 @@ function Model({ asset }: { readonly asset: Asset }) { const { socket } = useSocketStore(); const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); const { setSelectedFloorItem } = useSelectedFloorItem(); + const { limitDistance } = useLimitDistance(); const { renderDistance } = useRenderDistance(); const [isRendered, setIsRendered] = useState(false); const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -125,10 +126,16 @@ function Model({ asset }: { readonly asset: Asset }) { useFrame(() => { const assetPosition = new THREE.Vector3(...asset.position); - if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) { - setIsRendered(true); - } else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) { - setIsRendered(false); + if (limitDistance) { + if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) { + setIsRendered(true); + } else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) { + setIsRendered(false); + } + } else { + if (!isRendered) { + setIsRendered(true); + } } }) diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx index 35ba59e..acab425 100644 --- a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -30,7 +30,7 @@ function FloorCreator() { const [tempPoints, setTempPoints] = useState([]); const [isCreating, setIsCreating] = useState(false); - const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint } = useBuilderStore(); + const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore(); useEffect(() => { const canvasElement = gl.domElement; @@ -64,11 +64,11 @@ function FloorCreator() { const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Point'); - const floorIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Line'); + // const floorIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Line'); - if (floorIntersect && !pointIntersects) { + // if (floorIntersect && !pointIntersects) { - } + // } const newPoint: Point = { pointUuid: THREE.MathUtils.generateUUID(), @@ -89,7 +89,45 @@ function FloorCreator() { newPoint.position = snappedPosition; } - if (pointIntersects) { + if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) { + const floor: Floor = { + floorUuid: THREE.MathUtils.generateUUID(), + floorName: "Floor", + points: tempPoints, + topMaterial, + sideMaterial, + floorDepth, + isBeveled, + bevelStrength, + decals: [], + }; + + addFloor(floor); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + + } + setTempPoints([]); + setIsCreating(false); + } else if (isCreating && snappedPoint && !tempPoints.some(p => p.pointUuid === snappedPoint.pointUuid)) { + setTempPoints(prev => [...prev, newPoint]); + setIsCreating(true); + } else if (pointIntersects) { if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) { const floor: Floor = { floorUuid: THREE.MathUtils.generateUUID(), @@ -125,10 +163,7 @@ function FloorCreator() { } setTempPoints([]); setIsCreating(false); - } else if (tempPoints.length === 0 || (tempPoints.length > 1 && pointIntersects.object.uuid !== tempPoints[tempPoints.length - 2].pointUuid)) { - tempPoints.push(pointIntersects.object.userData as Point); - setIsCreating(true); - } else { + } else if (tempPoints.length === 0 || (tempPoints.length > 1 && !tempPoints.slice(1).some(p => p.pointUuid === pointIntersects.object.uuid))) { tempPoints.push(pointIntersects.object.userData as Point); setIsCreating(true); } @@ -182,6 +217,10 @@ function FloorCreator() { }; if (toolMode === "Floor" && toggleView) { + if (tempPoints.length === 0) { + setSnappedPosition(null); + setSnappedPoint(null); + } canvasElement.addEventListener("mousedown", onMouseDown); canvasElement.addEventListener("mouseup", onMouseUp); canvasElement.addEventListener("mousemove", onMouseMove); diff --git a/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx index dde2002..f663df9 100644 --- a/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx +++ b/app/src/modules/builder/floor/floorCreator/referenceFloor.tsx @@ -36,7 +36,7 @@ function ReferenceFloor({ tempPoints }: Readonly) { setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); if (!intersectionPoint) return; - const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.slice(0, -2)); + const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], [tempPoints[0]]); if (snapped.isSnapped && snapped.snappedPoint) { finalPosition.current = snapped.position; diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx deleted file mode 100644 index 3339c20..0000000 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ /dev/null @@ -1,651 +0,0 @@ -// import React, { useState, useEffect, useMemo, useRef } from "react"; -// import { Html, Line, Sphere } from "@react-three/drei"; -// import { useThree, useFrame } from "@react-three/fiber"; -// import * as THREE from "three"; -// import { -// useActiveLayer, -// useSocketStore, -// useToggleView, -// useToolMode, -// useRemovedLayer, -// useZones, -// useZonePoints, -// } from "../../../store/builder/store"; -// import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; - -// import * as CONSTANTS from "../../../types/world/worldConstants"; -// import * as turf from "@turf/turf"; -// import { computeArea } from "../functions/computeArea"; -// import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; -// import { useParams } from "react-router-dom"; -// import { getUserData } from "../../../functions/getUserData"; -// import { useVersionContext } from "../version/versionContext"; - -// const ZoneGroup: React.FC = () => { -// const { camera, pointer, gl, raycaster, scene, controls } = useThree(); -// const [startPoint, setStartPoint] = useState(null); -// const [endPoint, setEndPoint] = useState(null); -// const { zones, setZones } = useZones(); -// const { zonePoints, setZonePoints } = useZonePoints(); -// const [isDragging, setIsDragging] = useState(false); -// const { selectedZone } = useSelectedZoneStore(); -// const [draggedSphere, setDraggedSphere] = useState(null); -// const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); -// const { toggleView } = useToggleView(); -// const { removedLayer, setRemovedLayer } = useRemovedLayer(); -// const { toolMode } = useToolMode(); -// const { activeLayer } = useActiveLayer(); -// const { socket } = useSocketStore(); -// const { selectedVersionStore } = useVersionContext(); -// const { selectedVersion } = selectedVersionStore(); -// const { projectId } = useParams(); -// const { userId, organization } = getUserData(); - -// const groupsRef = useRef(); - -// const zoneMaterial = useMemo( -// () => -// new THREE.ShaderMaterial({ -// side: THREE.DoubleSide, -// vertexShader: ` -// varying vec2 vUv; -// void main(){ -// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); -// vUv = uv; -// } -// `, -// fragmentShader: ` -// varying vec2 vUv; -// uniform vec3 uOuterColor; -// void main(){ -// float alpha = 1.0 - vUv.y; -// gl_FragColor = vec4(uOuterColor, alpha); -// } -// `, -// uniforms: { -// uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, -// }, -// transparent: true, -// depthWrite: false, -// }), -// [] -// ); - -// useEffect(() => { -// if (!selectedVersion) return; -// getZonesApi(organization, projectId, selectedVersion?.versionId || '').then((data) => { -// if (data && data.length > 0) { -// const fetchedZones = data.map((zone: any) => ({ -// zoneUuid: zone.zoneUuid, -// zoneName: zone.zoneName, -// points: zone.points, -// viewPortCenter: zone.viewPortCenter, -// viewPortposition: zone.viewPortposition, -// layer: zone.layer, -// })); - -// setZones(fetchedZones); - -// const fetchedPoints = data.flatMap((zone: any) => -// zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point)) -// ); - -// setZonePoints(fetchedPoints); -// } else { -// setZones([]); -// } -// }).catch((err) => { -// console.error(err); -// }) -// }, [selectedVersion?.versionId]); - -// useEffect(() => { -// localStorage.setItem("zones", JSON.stringify(zones)); -// }, [zones]); - -// useEffect(() => { -// if (removedLayer) { -// const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer); -// setZones(updatedZones); - -// const updatedzonePoints = zonePoints.filter((_: any, index: any) => { -// const zoneIndex = Math.floor(index / 4); -// return zones[zoneIndex]?.layer !== removedLayer; -// }); -// setZonePoints(updatedzonePoints); - -// zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { deleteZoneFromBackend(zone.zoneUuid); }); - -// setRemovedLayer(null); -// } -// }, [removedLayer]); - -// useEffect(() => { -// if (toolMode !== "Zone") { -// setStartPoint(null); -// setEndPoint(null); -// } -// if (!toggleView) { -// setStartPoint(null); -// setEndPoint(null); -// } -// }, [toolMode, toggleView]); - -// // eslint-disable-next-line react-hooks/exhaustive-deps -// const addZoneToBackend = async (zone: { -// zoneUuid: string; -// zoneName: string; -// points: [number, number, number][]; -// layer: string; -// }) => { - -// const calculateCenter = (points: number[][]) => { -// if (!points || points.length === 0) return null; - -// let sumX = 0, sumY = 0, sumZ = 0; -// const numPoints = points.length; - -// points.forEach(([x, y, z]) => { -// sumX += x; -// sumY += y; -// sumZ += z; -// }); - -// return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ -// number, -// number, -// number -// ]; -// }; - -// const target: [number, number, number] | null = calculateCenter(zone.points); -// if (!target || zone.points.length < 4) return; -// const position = [target[0], 10, target[2]]; - -// const input = { -// userId: userId, -// versionId: selectedVersion?.versionId || '', -// projectId, -// organization, -// zoneData: { -// zoneName: zone.zoneName, -// zoneUuid: zone.zoneUuid, -// points: zone.points, -// viewPortCenter: target, -// viewPortposition: position, -// layer: zone.layer, -// }, -// }; - -// socket.emit("v1:zone:set", input); -// }; - -// // eslint-disable-next-line react-hooks/exhaustive-deps -// const updateZoneToBackend = async (zone: { -// zoneUuid: string; -// zoneName: string; -// points: [number, number, number][]; -// layer: string; -// }) => { - -// const calculateCenter = (points: number[][]) => { -// if (!points || points.length === 0) return null; - -// let sumX = 0, sumY = 0, sumZ = 0; -// const numPoints = points.length; - -// points.forEach(([x, y, z]) => { -// sumX += x; -// sumY += y; -// sumZ += z; -// }); - -// return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ -// number, -// number, -// number -// ]; -// }; - -// const target: [number, number, number] | null = calculateCenter(zone.points); -// if (!target || zone.points.length < 4) return; -// const position = [target[0], 10, target[2]]; - -// const input = { -// userId: userId, -// versionId: selectedVersion?.versionId || '', -// projectId, -// organization, -// zoneData: { -// zoneName: zone.zoneName, -// zoneUuid: zone.zoneUuid, -// points: zone.points, -// viewPortCenter: target, -// viewPortposition: position, -// layer: zone.layer, -// }, -// }; - -// socket.emit("v1:zone:set", input); -// }; - -// const deleteZoneFromBackend = async (zoneUuid: string) => { - -// const input = { -// userId: userId, -// versionId: selectedVersion?.versionId || '', -// projectId, -// organization, -// zoneUuid: zoneUuid, -// }; - -// socket.emit("v1:zone:delete", input); -// }; - -// // eslint-disable-next-line react-hooks/exhaustive-deps -// const handleDeleteZone = (zoneUuid: string) => { -// const updatedZones = zones.filter((zone: any) => zone.zoneUuid !== zoneUuid); -// setZones(updatedZones); - -// const zoneIndex = zones.findIndex((zone: any) => zone.zoneUuid === zoneUuid); -// if (zoneIndex !== -1) { -// const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4); -// zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point)); -// const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); -// setZonePoints(updatedzonePoints); -// } -// deleteZoneFromBackend(zoneUuid); -// }; - -// useEffect(() => { -// if (!camera || !toggleView) return; -// const canvasElement = gl.domElement; - -// let drag = false; -// let isLeftMouseDown = false; - -// const onMouseDown = (evt: any) => { -// if (evt.button === 0) { -// isLeftMouseDown = true; -// drag = false; - -// raycaster.setFromCamera(pointer, camera); -// const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - -// if (intersects.length > 0 && toolMode === "move") { -// const clickedObject = intersects[0].object; -// const sphereIndex = zonePoints.findIndex((point: any) => -// point.equals(clickedObject.position) -// ); -// if (sphereIndex !== -1) { -// (controls as any).enabled = false; -// setDraggedSphere(zonePoints[sphereIndex]); -// setIsDragging(true); -// } -// } -// } -// }; - -// const onMouseUp = (evt: any) => { -// if (evt.button === 0 && !drag && !isDragging && toolMode === 'Zone') { -// isLeftMouseDown = false; - -// if (!startPoint) { -// raycaster.setFromCamera(pointer, camera); -// const intersectionPoint = new THREE.Vector3(); -// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); -// if (point) { -// setStartPoint(point); -// setEndPoint(null); -// } -// } else if (startPoint) { -// raycaster.setFromCamera(pointer, camera); -// const intersectionPoint = new THREE.Vector3(); -// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); -// if (!point) return; - -// const points = [ -// [startPoint.x, 0.15, startPoint.z], -// [point.x, 0.15, startPoint.z], -// [point.x, 0.15, point.z], -// [startPoint.x, 0.15, point.z], -// [startPoint.x, 0.15, startPoint.z], -// ] as [number, number, number][]; - -// const zoneName = `Zone ${zones.length + 1}`; -// const zoneUuid = THREE.MathUtils.generateUUID(); -// const newZone = { -// zoneUuid, -// zoneName, -// points: points, -// layer: activeLayer, -// }; - -// const newZones = [...zones, newZone]; - -// setZones(newZones); - -// const newzonePoints = [ -// new THREE.Vector3(startPoint.x, 0.15, startPoint.z), -// new THREE.Vector3(point.x, 0.15, startPoint.z), -// new THREE.Vector3(point.x, 0.15, point.z), -// new THREE.Vector3(startPoint.x, 0.15, point.z), -// ]; - -// const updatedZonePoints = [...zonePoints, ...newzonePoints]; -// setZonePoints(updatedZonePoints); - -// addZoneToBackend(newZone); -// setStartPoint(null); -// setEndPoint(null); -// } -// } else if (evt.button === 0 && !drag && !isDragging && toolMode === '2D-Delete') { -// raycaster.setFromCamera(pointer, camera); -// const intersects = raycaster.intersectObjects( -// groupsRef.current.children, -// true -// ); - -// if (intersects.length > 0) { -// const clickedObject = intersects[0].object; - -// const sphereIndex = zonePoints.findIndex((point: any) => -// point.equals(clickedObject.position) -// ); -// if (sphereIndex !== -1) { -// const zoneIndex = Math.floor(sphereIndex / 4); -// const zoneUuid = zones[zoneIndex].zoneUuid; -// handleDeleteZone(zoneUuid); -// return; -// } -// } -// } - -// if (evt.button === 0) { -// if (isDragging && draggedSphere) { -// setIsDragging(false); -// setDraggedSphere(null); - -// const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); -// if (sphereIndex !== -1) { -// const zoneIndex = Math.floor(sphereIndex / 4); - -// if (zoneIndex !== -1 && zones[zoneIndex]) { -// updateZoneToBackend(zones[zoneIndex]); -// } -// } -// } -// } -// }; - -// const onMouseMove = () => { -// if (!groupsRef.current) return; -// if (isLeftMouseDown) { -// drag = true; -// } -// raycaster.setFromCamera(pointer, camera); - -// if (isDragging && draggedSphere) { -// raycaster.setFromCamera(pointer, camera); -// const intersectionPoint = new THREE.Vector3(); -// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); -// if (point) { -// draggedSphere.set(point.x, 0.15, point.z); - -// const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); -// if (sphereIndex !== -1) { -// const zoneIndex = Math.floor(sphereIndex / 4); -// const cornerIndex = sphereIndex % 4; - -// const updatedZones = zones.map((zone: any, index: number) => { -// if (index === zoneIndex) { -// const updatedPoints = [...zone.points]; -// updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; -// updatedPoints[4] = updatedPoints[0]; -// return { ...zone, points: updatedPoints }; -// } -// return zone; -// }); - -// setZones(updatedZones); -// } -// } -// } -// }; - -// const onContext = (event: any) => { -// event.preventDefault(); -// setStartPoint(null); -// setEndPoint(null); -// }; - -// if (toolMode === "Zone" || toolMode === '2D-Delete' || toolMode === "move") { -// canvasElement.addEventListener("mousedown", onMouseDown); -// canvasElement.addEventListener("mouseup", onMouseUp); -// canvasElement.addEventListener("mousemove", onMouseMove); -// canvasElement.addEventListener("contextmenu", onContext); -// } -// return () => { -// canvasElement.removeEventListener("mousedown", onMouseDown); -// canvasElement.removeEventListener("mouseup", onMouseUp); -// canvasElement.removeEventListener("mousemove", onMouseMove); -// canvasElement.removeEventListener("contextmenu", onContext); -// }; -// }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, zonePoints, draggedSphere, activeLayer, raycaster, pointer, controls, plane, setZones, setZonePoints, addZoneToBackend, handleDeleteZone, updateZoneToBackend, selectedVersion?.versionId]); - -// useFrame(() => { -// if (!startPoint) return; -// raycaster.setFromCamera(pointer, camera); -// const intersectionPoint = new THREE.Vector3(); -// const point = raycaster.ray.intersectPlane(plane, intersectionPoint); -// if (point) { -// setEndPoint(point); -// } -// }); - -// return ( -// -// -// {zones.map((zone: any) => ( -// -// {zone.points -// .slice(0, -1) -// .map((point: [number, number, number], index: number) => { -// const nextPoint = zone.points[index + 1]; - -// const point1 = new THREE.Vector3(point[0], point[1], point[2]); -// const point2 = new THREE.Vector3( -// nextPoint[0], -// nextPoint[1], -// nextPoint[2] -// ); - -// const planeWidth = point1.distanceTo(point2); -// const planeHeight = CONSTANTS.zoneConfig.height; - -// const midpoint = new THREE.Vector3( -// (point1.x + point2.x) / 2, -// CONSTANTS.zoneConfig.height / 2 + -// (zone.layer - 1) * CONSTANTS.zoneConfig.height, -// (point1.z + point2.z) / 2 -// ); - -// const angle = Math.atan2( -// point2.z - point1.z, -// point2.x - point1.x -// ); - -// return ( -// -// -// -// -// ); -// })} -// {!toggleView && -// (() => { -// const points3D = zone.points || []; -// const coords2D = points3D.map((p: any) => [p[0], p[2]]); - -// // Ensure the polygon is closed -// if ( -// coords2D.length >= 4 && -// (coords2D[0][0] !== coords2D[coords2D.length - 1][0] || -// coords2D[0][1] !== coords2D[coords2D.length - 1][1]) -// ) { -// coords2D.push(coords2D[0]); -// } -// if (coords2D.length < 4) return null; - -// const polygon = turf.polygon([coords2D]); -// const center2D = turf.center(polygon).geometry.coordinates; - -// // Calculate the average Y value -// const sumY = points3D.reduce( -// (sum: number, p: any) => sum + p[1], -// 0 -// ); -// const avgY = points3D.length > 0 ? sumY / points3D.length : 0; - -// const htmlPosition: [number, number, number] = [ -// center2D[0], -// avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5, -// center2D[1], -// ]; - -// return ( -// -//
{zone.zoneName}
-// -// ); -// })()} -//
-// ))} -//
-// -// {zones -// .filter((zone: any) => zone.layer === activeLayer) -// .map((zone: any) => ( -// { -// e.stopPropagation(); -// if (toolMode === '2D-Delete') { -// handleDeleteZone(zone.zoneUuid); -// } -// }} -// /> -// ))} -// -// -// {zones.map((zone: any, index: any) => { -// if (!toggleView) return null; -// const points3D = zone.points; -// const coords2D = points3D.map((p: any) => [p[0], p[2]]); - -// if ( -// coords2D.length < 4 || -// coords2D[0][0] !== coords2D[coords2D.length - 1][0] || -// coords2D[0][1] !== coords2D[coords2D.length - 1][1] -// ) { -// coords2D.push(coords2D[0]); -// } -// if (coords2D.length < 4) return null; - -// const polygon = turf.polygon([coords2D]); -// const center2D = turf.center(polygon).geometry.coordinates; - -// const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0); -// const avgY = sumY / points3D.length; - -// const area = computeArea(points3D, "zone"); -// const formattedArea = `${area.toFixed(2)} m²`; - -// const htmlPosition: [number, number, number] = [ -// center2D[0], -// avgY + CONSTANTS.zoneConfig.height, -// center2D[1], -// ]; -// return ( -// -//
-// {zone.zoneName} ({formattedArea}) -//
-// -// ); -// })} -//
- -// -// {zones -// .filter((zone: any) => zone.layer === activeLayer) -// .flatMap((zone: any) => -// zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( -// -// -// -// )) -// )} -// -// -// {startPoint && endPoint && ( -// -// )} -// -//
-// ); -// }; - -// export default ZoneGroup; diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index 5cf48bc..cc53b9d 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -14,6 +14,8 @@ import { getUserData } from '../../../functions/getUserData'; // import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; // import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; // import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; +// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi'; +// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi'; interface LineProps { points: [Point, Point]; @@ -26,9 +28,10 @@ function Line({ points }: Readonly) { const [isDeletable, setIsDeletable] = useState(false); const { socket } = useSocketStore(); const { toolMode } = useToolMode(); - const { wallStore, floorStore } = useSceneContext(); + const { wallStore, floorStore, zoneStore } = useSceneContext(); const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore(); const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId } = floorStore(); + const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId } = zoneStore(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); @@ -163,6 +166,53 @@ function Line({ points }: Readonly) { setHoveredLine(null); } + if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') { + const { removedZones, updatedZones } = removeZoneByPoints(points); + if (removedZones.length > 0) { + removedZones.forEach(zone => { + if (projectId) { + + // API + + // deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid); + + // SOCKET + + const data = { + zoneUuid: zone.zoneUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:delete', data); + } + }); + } + if (updatedZones.length > 0) { + updatedZones.forEach(zone => { + if (projectId) { + + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', zone); + + // SOCKET + + const data = { + zoneData: zone, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + } + }); + } + } gl.domElement.style.cursor = 'default'; } } @@ -194,6 +244,10 @@ function Line({ points }: Readonly) { setFloorPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]); setFloorPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]); } + if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') { + setZonePosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]); + setZonePosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]); + } } } }; @@ -271,6 +325,33 @@ function Line({ points }: Readonly) { socket.emit('v1:model-Floor:add', data); }) } + } else if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') { + const updatedZones1 = getZonesByPointId(points[0].pointUuid); + const updatedZones2 = getZonesByPointId(points[1].pointUuid); + const updatedZones = [...updatedZones1, ...updatedZones2].filter((zone, index, self) => index === self.findIndex((z) => z.zoneUuid === zone.zoneUuid)); + + if (updatedZones.length > 0 && projectId) { + updatedZones.forEach(updatedZone => { + + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone).catch((error) => { + // console.error('Error updating zone:', error); + // }); + + // SOCKET + + const data = { + zoneData: updatedZone, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + }) + } } } diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx index 69f5e72..648e4c5 100644 --- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx +++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx @@ -205,9 +205,9 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string const snapFloorPoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => { if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null }; - const otherPoints = getAllOtherFloorPoints(); + let otherPoints = getAllOtherFloorPoints(); if (tempPoints) { - otherPoints.concat(tempPoints); + otherPoints = [...otherPoints, ...tempPoints]; } const currentVec = new THREE.Vector3(...position); @@ -292,9 +292,9 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string const snapZonePoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => { if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null }; - const otherPoints = getAllOtherZonePoints(); + let otherPoints = getAllOtherZonePoints(); if (tempPoints) { - otherPoints.concat(tempPoints); + otherPoints = [...otherPoints, ...tempPoints]; } const currentVec = new THREE.Vector3(...position); diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index fe2dd6e..8689ac5 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -14,10 +14,12 @@ import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAis import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; // import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; // import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; -import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; +// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; +// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; +// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi'; +// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi'; import { getUserData } from '../../../functions/getUserData'; -import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; function Point({ point }: { readonly point: Point }) { const materialRef = useRef(null); @@ -27,11 +29,12 @@ function Point({ point }: { readonly point: Point }) { const [dragOffset, setDragOffset] = useState(null); const { socket } = useSocketStore(); const { toolMode } = useToolMode(); - const { aisleStore, wallStore, floorStore } = useSceneContext(); + const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext(); const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore(); const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore(); - const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); + const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore(); + const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); @@ -127,6 +130,10 @@ function Point({ point }: { readonly point: Point }) { const floorSnapped = snapFloorAngle(newPosition); const finalSnapped = snapFloorPoint(floorSnapped.position); setFloorPosition(point.pointUuid, finalSnapped.position); + } else if (point.pointType === 'Zone') { + const zoneSnapped = snapAisleAngle(newPosition); + const finalSnapped = snapZonePoint(zoneSnapped.position); + setZonePosition(point.pointUuid, finalSnapped.position); } } } @@ -199,6 +206,28 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Floor:add', data); }); } + } else if (point.pointType === 'Zone') { + const updatedZones = getZonesByPointId(point.pointUuid); + if (updatedZones && updatedZones.length > 0 && projectId) { + updatedZones.forEach((updatedZone) => { + + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone); + + // SOCKET + + const data = { + zoneData: updatedZone, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + }); + } } } @@ -289,6 +318,54 @@ function Point({ point }: { readonly point: Point }) { }); } } + if (point.pointType === 'Zone') { + const { removedZones, updatedZones } = removeZonePoint(point.pointUuid); + setHoveredPoint(null); + if (removedZones.length > 0) { + removedZones.forEach(zone => { + if (projectId) { + + // API + + // deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid); + + // SOCKET + + const data = { + zoneUuid: zone.zoneUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:delete', data); + } + }); + } + if (updatedZones.length > 0) { + updatedZones.forEach(zone => { + if (projectId) { + + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', zone); + + // SOCKET + + const data = { + zoneData: zone, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + } + }); + } + } gl.domElement.style.cursor = 'default'; } } diff --git a/app/src/modules/builder/wall/Instances/instance/helpers/useWallClassification.ts b/app/src/modules/builder/wall/Instances/instance/helpers/useWallClassification.ts index 5ae9a21..bc910b5 100644 --- a/app/src/modules/builder/wall/Instances/instance/helpers/useWallClassification.ts +++ b/app/src/modules/builder/wall/Instances/instance/helpers/useWallClassification.ts @@ -85,9 +85,12 @@ export function useWallClassification(walls: Walls) { })); } + const allCoords = mergedLineStrings.flatMap(ls => ls.geometry.coordinates); + const uniqueCoords = Array.from(new Set(allCoords.map(coord => coord.join(',')))); + if (uniqueCoords.length < 4) return []; + const lineStrings = turf.featureCollection(mergedLineStrings); - // Now polygonize merged line strings const polygons = turf.polygonize(lineStrings); const rooms: Point[][] = []; diff --git a/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx b/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx index 5c29d5a..e49400c 100644 --- a/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx +++ b/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx @@ -37,8 +37,8 @@ function ZoneInstance({ zone }: { zone: Zone }) { name={`Zone-${zone.zoneUuid}`} userData={zone} > - {zone.points.slice(0, -1).map((point, index: number) => { - const nextPoint = zone.points[index + 1]; + {zone.points.map((point, index: number) => { + const nextPoint = zone.points[(index + 1) % zone.points.length]; const point1 = new Vector3(point.position[0], point.position[1], point.position[2]); const point2 = new Vector3(nextPoint.position[0], nextPoint.position[1], nextPoint.position[2]); diff --git a/app/src/modules/builder/zone/Instances/zoneInstances.tsx b/app/src/modules/builder/zone/Instances/zoneInstances.tsx index 48b426c..c1b9d64 100644 --- a/app/src/modules/builder/zone/Instances/zoneInstances.tsx +++ b/app/src/modules/builder/zone/Instances/zoneInstances.tsx @@ -13,10 +13,6 @@ function ZoneInstances() { const { zones } = zoneStore(); const { toggleView } = useToggleView(); - useEffect(() => { - console.log('zones: ', zones); - }, [zones]); - const allPoints = useMemo(() => { const points: Point[] = []; const seenUuids = new Set(); diff --git a/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx b/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx index 940134f..f4429bf 100644 --- a/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx +++ b/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx @@ -36,7 +36,7 @@ function ReferenceZone({ tempPoints }: Readonly) { setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); if (!intersectionPoint) return; - const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.slice(0, -2)); + const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], [tempPoints[0]]); if (snapped.isSnapped && snapped.snappedPoint) { finalPosition.current = snapped.position; diff --git a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx index af0fea2..1df200f 100644 --- a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx +++ b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx @@ -10,9 +10,250 @@ import { getUserData } from '../../../../functions/getUserData'; import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceZone from './referenceZone'; +// import { upsertZoneApi } from '../../../../services/factoryBuilder/zone/upsertZoneApi'; + function ZoneCreator() { + const { scene, camera, raycaster, gl, pointer } = useThree(); + const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); + const { toggleView } = useToggleView(); + const { toolMode } = useToolMode(); + const { activeLayer } = useActiveLayer(); + const { socket } = useSocketStore(); + const { zoneStore } = useSceneContext(); + const { addZone, getZonePointById, getZoneByPoints } = zoneStore(); + const drag = useRef(false); + const isLeftMouseDown = useRef(false); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); + + const [tempPoints, setTempPoints] = useState([]); + const [isCreating, setIsCreating] = useState(false); + const { zoneColor, zoneHeight, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore(); + + useEffect(() => { + const canvasElement = gl.domElement; + + const onMouseDown = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown.current = true; + drag.current = false; + } + }; + + const onMouseUp = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown.current = false; + } + }; + + const onMouseMove = () => { + if (isLeftMouseDown) { + drag.current = true; + } + }; + + const onMouseClick = () => { + if (drag.current || !toggleView) return; + + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + let position = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (!position) return; + + const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Zone-Point'); + + // const zoneIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Zone-Line'); + + // if (zoneIntersect && !pointIntersects) { + + // } + + const newPoint: Point = { + pointUuid: THREE.MathUtils.generateUUID(), + pointType: 'Zone', + position: [position.x, position.y, position.z], + layer: activeLayer + }; + + if (snappedPosition && snappedPoint) { + newPoint.pointUuid = snappedPoint.pointUuid; + newPoint.position = snappedPosition; + newPoint.layer = snappedPoint.layer; + } + + if (snappedPoint && snappedPoint.pointUuid === tempPoints[tempPoints.length - 1]?.pointUuid) { return } + + if (snappedPosition && !snappedPoint) { + newPoint.position = snappedPosition; + } + + if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) { + const zone: Zone = { + zoneUuid: THREE.MathUtils.generateUUID(), + zoneName: "Zone", + points: tempPoints, + zoneColor, + zoneHeight, + viewPortPosition: [0, 0, 0], + viewPortTarget: [0, 0, 0] + }; + + addZone(zone); + if (projectId) { + + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', zone); + + // SOCKET + + const data = { + zoneData: zone, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + + } + setTempPoints([]); + setIsCreating(false); + } else if (isCreating && snappedPoint && !tempPoints.some(p => p.pointUuid === snappedPoint.pointUuid)) { + setTempPoints(prev => [...prev, newPoint]); + setIsCreating(true); + } else if (pointIntersects) { + if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) { + const zone: Zone = { + zoneUuid: THREE.MathUtils.generateUUID(), + zoneName: "Zone", + points: tempPoints, + zoneColor, + zoneHeight, + viewPortPosition: [0, 0, 0], + viewPortTarget: [0, 0, 0] + }; + + addZone(zone); + if (projectId) { + + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', zone); + + // SOCKET + + const data = { + zoneData: zone, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + + } + setTempPoints([]); + setIsCreating(false); + } else if (tempPoints.length === 0 || (tempPoints.length > 1 && !tempPoints.slice(1).some(p => p.pointUuid === pointIntersects.object.uuid))) { + tempPoints.push(pointIntersects.object.userData as Point); + setIsCreating(true); + } + } else { + setTempPoints(prev => [...prev, newPoint]); + setIsCreating(true); + } + + }; + + const onContext = (event: any) => { + event.preventDefault(); + if (isCreating) { + if (tempPoints.length >= 3) { + const zone: Zone = { + zoneUuid: THREE.MathUtils.generateUUID(), + zoneName: "Zone", + points: tempPoints, + zoneColor, + zoneHeight, + viewPortPosition: [0, 0, 0], + viewPortTarget: [0, 0, 0] + }; + + addZone(zone); + if (projectId) { + + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', zone); + + // SOCKET + + const data = { + zoneData: zone, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + + } + } + setTempPoints([]); + setIsCreating(false); + } + }; + + if (toolMode === "Zone" && toggleView) { + if (tempPoints.length === 0) { + setSnappedPosition(null); + setSnappedPoint(null); + } + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener("click", onMouseClick); + canvasElement.addEventListener("contextmenu", onContext); + } else { + setTempPoints([]); + setIsCreating(false); + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("click", onMouseClick); + canvasElement.removeEventListener("contextmenu", onContext); + } + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("click", onMouseClick); + canvasElement.removeEventListener("contextmenu", onContext); + }; + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addZone, getZonePointById, getZoneByPoints, zoneColor, zoneHeight, snappedPosition, snappedPoint]); + return ( <> + {toggleView && + <> + + {tempPoints.map((point) => ( + + ))} + + + {tempPoints.length > 0 && + + } + + } ) } diff --git a/app/src/services/factoryBuilder/zone/deleteZoneApi.ts b/app/src/services/factoryBuilder/zone/deleteZoneApi.ts index 1f2b63b..87b80dd 100644 --- a/app/src/services/factoryBuilder/zone/deleteZoneApi.ts +++ b/app/src/services/factoryBuilder/zone/deleteZoneApi.ts @@ -6,7 +6,7 @@ export const deleteZoneApi = async ( zoneUuid: string ) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/V2/deleteZone`, { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/zones/delete`, { method: "PATCH", headers: { Authorization: "Bearer ", diff --git a/app/src/services/factoryBuilder/zone/getZonesApi.ts b/app/src/services/factoryBuilder/zone/getZonesApi.ts index df94fef..f0ea687 100644 --- a/app/src/services/factoryBuilder/zone/getZonesApi.ts +++ b/app/src/services/factoryBuilder/zone/getZonesApi.ts @@ -5,7 +5,7 @@ export const getZonesApi = async ( versionId: string, ) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/V2/zones/${projectId}/${versionId}`, { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/zones/${projectId}/${versionId}`, { method: "GET", headers: { Authorization: "Bearer ", diff --git a/app/src/services/factoryBuilder/zone/upsertZoneApi.ts b/app/src/services/factoryBuilder/zone/upsertZoneApi.ts index eeab930..ffa79c5 100644 --- a/app/src/services/factoryBuilder/zone/upsertZoneApi.ts +++ b/app/src/services/factoryBuilder/zone/upsertZoneApi.ts @@ -1,12 +1,12 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const upsertWallApi = async ( +export const upsertZoneApi = async ( projectId: string, versionId: string, - ZoneData: Zone + zoneData: Zone ) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/V2/UpsertZone`, { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertZone`, { method: "POST", headers: { Authorization: "Bearer ", @@ -14,7 +14,7 @@ export const upsertWallApi = async ( token: localStorage.getItem("token") || "", refresh_token: localStorage.getItem("refreshToken") || "", }, - body: JSON.stringify({ projectId, versionId, ZoneData }), + body: JSON.stringify({ projectId, versionId, zoneData }), }); const newAccessToken = response.headers.get("x-access-token"); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index e788670..860e618 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -473,6 +473,7 @@ export const useWidgetSubOption = create((set: any) => ({ widgetSubOption: "2D", setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); + export const useLimitDistance = create((set: any) => ({ limitDistance: true, setLimitDistance: (x: any) => set({ limitDistance: x }), diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index 9f2d871..efb431b 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -257,8 +257,7 @@ export const createFloorStore = () => { return get().floors.find(floor => { const floorPointIds = new Set(floor.points.map(p => p.pointUuid)); const givenPointIds = new Set(points.map(p => p.pointUuid)); - return floorPointIds.size === givenPointIds.size && - [...floorPointIds].every(id => givenPointIds.has(id)); + return floorPointIds.size === givenPointIds.size && [...floorPointIds].every(id => givenPointIds.has(id)); }); }, diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts index 148e88c..1a93e57 100644 --- a/app/src/store/builder/useZoneStore.ts +++ b/app/src/store/builder/useZoneStore.ts @@ -10,11 +10,19 @@ interface ZoneStore { setZoneHeight: (uuid: string, height: number) => void; setZoneColor: (uuid: string, color: string) => void; removeZone: (uuid: string) => void; - removePointFromZones: (pointUuid: string) => void; + removePoint: (pointUuid: string) => { removedZones: Zone[], updatedZones: Zone[] }; + removeZoneByPoints: (points: Point[]) => { removedZones: Zone[], updatedZones: Zone[] }; clearZones: () => void; + setPosition: ( + pointUuid: string, + position: [number, number, number] + ) => Zone[] | []; setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void; getZoneById: (uuid: string) => Zone | undefined; + getZonesByPointId: (uuid: string) => Zone[] | []; + getZoneByPoints: (points: Point[]) => Zone | undefined; + getZonePointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; } @@ -63,16 +71,97 @@ export const createZoneStore = () => { state.zones = state.zones.filter(z => z.zoneUuid !== uuid); }), - removePointFromZones: (pointUuid) => set(state => { - for (const zone of state.zones) { - zone.points = zone.points.filter(p => p.pointUuid !== pointUuid); - } - }), + removePoint: (pointUuid) => { + const removedZones: Zone[] = []; + const updatedZones: Zone[] = []; + + set(state => { + for (const zone of state.zones) { + const pointIndex = zone.points.findIndex(p => p.pointUuid === pointUuid); + if (pointIndex === -1) { + updatedZones.push(JSON.parse(JSON.stringify(zone))); + continue; + } + + const remainingPoints = zone.points.filter(p => p.pointUuid !== pointUuid); + + if (remainingPoints.length <= 2) { + removedZones.push(JSON.parse(JSON.stringify(zone))); + continue; + } + zone.points = remainingPoints; + updatedZones.push(JSON.parse(JSON.stringify(zone))); + } + + state.zones = updatedZones; + }); + + return { removedZones, updatedZones }; + }, + + removeZoneByPoints: ([pointA, pointB]) => { + const removedZones: Zone[] = []; + const updatedZones: Zone[] = []; + + set(state => { + + for (const zone of state.zones) { + const indices = zone.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); + + const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; + const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; + + if (idxA === -1 || idxB === -1) { + updatedZones.push(JSON.parse(JSON.stringify(zone))); + continue; + } + + const areAdjacent = + Math.abs(idxA - idxB) === 1 || + (idxA === 0 && idxB === zone.points.length - 1) || + (idxB === 0 && idxA === zone.points.length - 1); + + if (!areAdjacent) { + updatedZones.push(JSON.parse(JSON.stringify(zone))); + continue; + } + + const remainingPoints = zone.points.filter( + p => p.pointUuid !== pointA.pointUuid && p.pointUuid !== pointB.pointUuid + ); + + if (remainingPoints.length > 2) { + zone.points = remainingPoints; + updatedZones.push(JSON.parse(JSON.stringify(zone))); + } else { + removedZones.push(JSON.parse(JSON.stringify(zone))); + } + } + + state.zones = updatedZones; + }); + + return { removedZones, updatedZones }; + }, clearZones: () => set(state => { state.zones = []; }), + setPosition: (pointUuid, position) => { + let updatedZone: Zone[] = []; + set((state) => { + for (const zone of state.zones) { + const point = zone.points.find((p) => p.pointUuid === pointUuid); + if (point) { + point.position = position; + updatedZone.push(JSON.parse(JSON.stringify(zone))); + } + } + }); + return updatedZone; + }, + setViewPort: (uuid, position, target) => set(state => { const zone = state.zones.find(z => z.zoneUuid === uuid); if (zone) { @@ -85,6 +174,28 @@ export const createZoneStore = () => { return get().zones.find(z => z.zoneUuid === uuid); }, + getZonesByPointId: (pointUuid) => { + return get().zones.filter(zone => { + return zone.points.some(p => p.pointUuid === pointUuid); + }); + }, + + getZoneByPoints: (points) => { + return get().zones.find(zone => { + const zonePointIds = new Set(zone.points.map(p => p.pointUuid)); + const givenPointIds = new Set(points.map(p => p.pointUuid)); + return zonePointIds.size === givenPointIds.size && [...zonePointIds].every(id => givenPointIds.has(id)); + }); + }, + + getZonePointById: (pointUuid) => { + for (const zone of get().zones) { + const point = zone.points.find(p => p.pointUuid === pointUuid); + if (point) return point; + } + return undefined; + }, + getConnectedPoints: (pointUuid) => { const connected: Point[] = []; for (const zone of get().zones) { From 943ad3ba4926ffabc925e103e6d873703e93037c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 30 Jun 2025 12:54:25 +0530 Subject: [PATCH 14/18] refactor: Update color scheme for Floor and Zone components; enhance snapping logic in ReferenceFloor and ReferenceZone --- .../builder/floor/Instances/Instance/floor2DInstance.tsx | 2 +- .../modules/builder/floor/floorCreator/referenceFloor.tsx | 6 +++--- app/src/modules/builder/point/point.tsx | 2 +- .../builder/zone/Instances/Instance/zone2DInstance.tsx | 2 +- app/src/modules/builder/zone/Instances/zoneInstances.tsx | 4 ++++ app/src/modules/builder/zone/zoneCreator/referenceZone.tsx | 4 ++-- app/src/modules/builder/zone/zoneGroup.tsx | 1 + 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx index 2f12360..1ba15f0 100644 --- a/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx +++ b/app/src/modules/builder/floor/Instances/Instance/floor2DInstance.tsx @@ -36,7 +36,7 @@ function Floor2DInstance({ floor }: { floor: Floor }) { userData={floor} > ) { const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position); const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[tempPoints.length - 1]?.position || null); - const { snapFloorPoint } = usePointSnapping({ uuid: 'temp-floor', pointType: 'Floor', position: directionalSnap.position || [0, 0, 0], }); + const { snapFloorPoint } = usePointSnapping({ uuid: 'temp-Floor', pointType: 'Floor', position: directionalSnap.position || [0, 0, 0], }); useFrame(() => { if (toolMode === 'Floor' && toggleView && tempPoints.length > 0) { @@ -36,7 +36,7 @@ function ReferenceFloor({ tempPoints }: Readonly) { setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); if (!intersectionPoint) return; - const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], [tempPoints[0]]); + const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.length > 2 ? [tempPoints[0]] : []); if (snapped.isSnapped && snapped.snappedPoint) { finalPosition.current = snapped.position; @@ -158,7 +158,7 @@ function Floor({ floor }: { floor: Point[] }) { position={[0, 0, 0]} receiveShadow > - +
); diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index 8689ac5..15777aa 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -131,7 +131,7 @@ function Point({ point }: { readonly point: Point }) { const finalSnapped = snapFloorPoint(floorSnapped.position); setFloorPosition(point.pointUuid, finalSnapped.position); } else if (point.pointType === 'Zone') { - const zoneSnapped = snapAisleAngle(newPosition); + const zoneSnapped = snapZoneAngle(newPosition); const finalSnapped = snapZonePoint(zoneSnapped.position); setZonePosition(point.pointUuid, finalSnapped.position); } diff --git a/app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx b/app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx index 9828d14..3489b32 100644 --- a/app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx +++ b/app/src/modules/builder/zone/Instances/Instance/zone2DInstance.tsx @@ -36,7 +36,7 @@ function Zone2DInstance({ zone }: { zone: Zone }) { userData={zone} > { + // console.log('zones: ', zones); + }, [zones]) + const allPoints = useMemo(() => { const points: Point[] = []; const seenUuids = new Set(); diff --git a/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx b/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx index f4429bf..e5cdf9f 100644 --- a/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx +++ b/app/src/modules/builder/zone/zoneCreator/referenceZone.tsx @@ -36,7 +36,7 @@ function ReferenceZone({ tempPoints }: Readonly) { setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]); if (!intersectionPoint) return; - const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], [tempPoints[0]]); + const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.length > 2 ? [tempPoints[0]] : []); if (snapped.isSnapped && snapped.snappedPoint) { finalPosition.current = snapped.position; @@ -156,7 +156,7 @@ function Zone({ zone }: { zone: Point[] }) { position={[0, 0, 0]} receiveShadow > - +
); diff --git a/app/src/modules/builder/zone/zoneGroup.tsx b/app/src/modules/builder/zone/zoneGroup.tsx index 46bddb7..fc9dc7f 100644 --- a/app/src/modules/builder/zone/zoneGroup.tsx +++ b/app/src/modules/builder/zone/zoneGroup.tsx @@ -29,6 +29,7 @@ function ZoneGroup() { useEffect(() => { if (projectId && selectedVersion) { getZonesApi(projectId, selectedVersion?.versionId || '').then((zones) => { + console.log('zones: ', zones); if (zones && zones.length > 0) { setZones(zones); } else { From 997775c27ec4892cd6b4e8a9ff40077767194cec Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 30 Jun 2025 16:21:54 +0530 Subject: [PATCH 15/18] feat: Implement wall asset management features including creation, instances, and rendering; enhance wall properties input validation --- .../properties/SelectedWallProperties.tsx | 6 + .../properties/WallProperties.tsx | 6 + .../modules/builder/Decal/decalInstance.tsx | 4 +- app/src/modules/builder/asset/assetsGroup.tsx | 2 +- app/src/modules/builder/builder.tsx | 54 +++---- .../builder/wall/Instances/instance/wall.tsx | 2 +- .../builder/wall/Instances/wallInstances.tsx | 11 +- .../Instances/Instances/wallAssetInstance.tsx | 135 ++++++++++++++++++ .../Instances/wallAssetInstances.tsx | 30 ++++ .../builder/wallAsset/wallAssetCreator.tsx | 85 +++++++++++ .../builder/wallAsset/wallAssetGroup.tsx | 17 +++ app/src/modules/builder/zone/zoneGroup.tsx | 1 - app/src/modules/scene/environment/ground.tsx | 3 +- .../factoryBuilder/zone/upsertZoneApi.ts | 2 +- app/src/types/builderTypes.d.ts | 2 + 15 files changed, 313 insertions(+), 47 deletions(-) create mode 100644 app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx create mode 100644 app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx create mode 100644 app/src/modules/builder/wallAsset/wallAssetCreator.tsx create mode 100644 app/src/modules/builder/wallAsset/wallAssetGroup.tsx diff --git a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx index 517927c..794ede0 100644 --- a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx @@ -133,11 +133,17 @@ const SelectedWallProperties = () => { diff --git a/app/src/components/layout/sidebarRight/properties/WallProperties.tsx b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx index ae17c1f..e158b44 100644 --- a/app/src/components/layout/sidebarRight/properties/WallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx @@ -63,11 +63,17 @@ const WallProperties = () => { handleHeightChange(val)} /> handleThicknessChange(val)} /> diff --git a/app/src/modules/builder/Decal/decalInstance.tsx b/app/src/modules/builder/Decal/decalInstance.tsx index dfdd622..1b68f3d 100644 --- a/app/src/modules/builder/Decal/decalInstance.tsx +++ b/app/src/modules/builder/Decal/decalInstance.tsx @@ -7,7 +7,7 @@ import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import defaultMaterial from '../../../assets/textures/floor/wall-tex.png'; import useModuleStore from '../../../store/useModuleStore'; -function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) { +function DecalInstance({ visible = true, decal, zPosition = decal.decalPosition[2] }: { visible?: boolean, decal: Decal, zPosition?: number }) { const { setSelectedWall, setSelectedFloor, selectedDecal, setSelectedDecal } = useBuilderStore(); const { togglView } = useToggleView(); const { activeModule } = useModuleStore(); @@ -17,7 +17,7 @@ function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: De { const canvasElement = gl.domElement; - const onDrop = (event: any) => { + const onDrop = (event: DragEvent) => { if (!event.dataTransfer?.files[0]) return; if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') { diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index adea2c6..ab9434b 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -2,8 +2,8 @@ import * as THREE from "three"; import { useEffect, useRef } from "react"; -import { useThree } from "@react-three/fiber"; -import { Bvh } from "@react-three/drei"; +import { useFrame, useThree } from "@react-three/fiber"; +import { Geometry } from "@react-three/csg"; ////////// Zustand State Imports ////////// @@ -39,16 +39,14 @@ import ZoneGroup from "./zone/zoneGroup"; import { useParams } from "react-router-dom"; import { useBuilderStore } from "../../store/builder/useBuilderStore"; import { getUserData } from "../../functions/getUserData"; +import WallAssetGroup from "./wallAsset/wallAssetGroup"; 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 state = useThree(); + const plane = useRef(null); + const csgRef = useRef(null); - // Assigning the scene and camera from the Three.js state to the references. - - 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 { toggleView } = useToggleView(); // State for toggling between 2D and 3D. + const { toggleView } = useToggleView(); const { setToolMode } = useToolMode(); const { setRoofVisibility } = useRoofVisibility(); const { setWallVisibility } = useWallVisibility(); @@ -59,14 +57,6 @@ export default function Builder() { const { setHoveredPoint, setHoveredLine } = useBuilderStore(); const { userId, organization } = getUserData(); - // 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); - - ////////// All Toggle's ////////// - useEffect(() => { if (!toggleView) { setHoveredLine(null); @@ -91,29 +81,31 @@ export default function Builder() { fetchVisibility(); }, []); - ////////// Return ////////// + useFrame(() => { + if (csgRef.current) { + csgRef.current.update(); + } + }) return ( <> - + - {/* */} - - + + - + + + + + + + + diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 0498b5b..280167d 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -154,7 +154,7 @@ function Wall({ wall }: { readonly wall: Wall }) { {wall.decals.map((decal) => ( - + ))}
diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx index 98d00fc..c5e22bf 100644 --- a/app/src/modules/builder/wall/Instances/wallInstances.tsx +++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useMemo } from 'react'; import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three'; -import { Geometry } from '@react-three/csg'; import { Html, Extrude } from '@react-three/drei'; import { useLoader } from '@react-three/fiber'; import { useSceneContext } from '../../../scene/sceneContext'; @@ -44,13 +43,9 @@ function WallInstances() { <> {!toggleView && walls.length > 1 && ( <> - - - {walls.map((wall) => ( - - ))} - - + {walls.map((wall) => ( + + ))} {rooms.map((room, index) => ( diff --git a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx new file mode 100644 index 0000000..6261be6 --- /dev/null +++ b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx @@ -0,0 +1,135 @@ +import * as THREE from 'three'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; +import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; +import { Base, Geometry, Subtraction } from '@react-three/csg'; +import { useFrame } from '@react-three/fiber'; +import { useSceneContext } from '../../../../scene/sceneContext'; + +function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { + const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; + const { wallStore } = useSceneContext(); + const { walls, getWallById } = wallStore(); + const [gltfScene, setGltfScene] = useState(null); + const [boundingBox, setBoundingBox] = useState(null); + const groupRef = useRef(null); + const csgRef = useRef(null); + const wall = useMemo(() => getWallById(wallAsset.wallUuid), [getWallById, wallAsset.wallUuid, walls]); + + useEffect(() => { + 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); + const loadModel = async () => { + try { + // Check Cache + const assetId = wallAsset.assetId; + const cachedModel = THREE.Cache.get(assetId); + if (cachedModel) { + setGltfScene(cachedModel.scene.clone()); + calculateBoundingBox(cachedModel.scene); + return; + } + + // Check IndexedDB + const indexedDBModel = await retrieveGLTF(assetId); + if (indexedDBModel) { + const blobUrl = URL.createObjectURL(indexedDBModel); + loader.load(blobUrl, (gltf) => { + URL.revokeObjectURL(blobUrl); + THREE.Cache.remove(blobUrl); + THREE.Cache.add(assetId, gltf); + setGltfScene(gltf.scene.clone()); + calculateBoundingBox(gltf.scene); + }, + undefined, + (error) => { + echo.error(`[IndexedDB] Error loading ${wallAsset.modelName}:`); + URL.revokeObjectURL(blobUrl); + } + ); + return; + } + + // Fetch from Backend + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${assetId}`; + const handleBackendLoad = async (gltf: GLTF) => { + try { + const response = await fetch(modelUrl); + const modelBlob = await response.blob(); + await storeGLTF(assetId, modelBlob); + THREE.Cache.add(assetId, gltf); + setGltfScene(gltf.scene.clone()); + calculateBoundingBox(gltf.scene); + } catch (error) { + console.error(`[Backend] Error storing/loading ${wallAsset.modelName}:`, error); + } + }; + loader.load( + modelUrl, + handleBackendLoad, + undefined, + (error) => { + echo.error(`[Backend] Error loading ${wallAsset.modelName}:`); + } + ); + } catch (err) { + console.error("Failed to load model:", wallAsset.assetId, err); + } + }; + + const calculateBoundingBox = (scene: THREE.Object3D) => { + const box = new THREE.Box3().setFromObject(scene); + setBoundingBox(box); + }; + + loadModel(); + + }, []); + + useFrame(() => { + if (csgRef.current) { + csgRef.current.update(); + } + }) + + if (!gltfScene || !boundingBox || !wall) { return null } + const size = new THREE.Vector3(); + boundingBox.getSize(size); + const center = new THREE.Vector3(); + boundingBox.getCenter(center); + + return ( + <> + + + + + + + {gltfScene && ( + { + console.log(wallAsset); + }} + > + + + )} + + + ) +} + +export default WallAssetInstance \ No newline at end of file diff --git a/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx b/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx new file mode 100644 index 0000000..581dfe7 --- /dev/null +++ b/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx @@ -0,0 +1,30 @@ +import { useEffect } from 'react'; +import { useSceneContext } from '../../../scene/sceneContext' +import { useToggleView } from '../../../../store/builder/store'; +import WallAssetInstance from './Instances/wallAssetInstance'; + +function WallAssetInstances() { + const { wallAssetStore } = useSceneContext(); + const { wallAssets } = wallAssetStore(); + const { toggleView } = useToggleView(); + + useEffect(() => { + // console.log('wallAssets: ', wallAssets); + }, [wallAssets]) + + return ( + <> + + {!toggleView && wallAssets.length > 0 && ( + <> + {wallAssets.map((wallAsset) => ( + + ))} + + )} + + + ) +} + +export default WallAssetInstances \ No newline at end of file diff --git a/app/src/modules/builder/wallAsset/wallAssetCreator.tsx b/app/src/modules/builder/wallAsset/wallAssetCreator.tsx new file mode 100644 index 0000000..a64d957 --- /dev/null +++ b/app/src/modules/builder/wallAsset/wallAssetCreator.tsx @@ -0,0 +1,85 @@ +import { useThree } from '@react-three/fiber'; +import { useEffect } from 'react' +import { useSelectedItem, useSocketStore, useToggleView } from '../../../store/builder/store'; +import useModuleStore from '../../../store/useModuleStore'; +import { MathUtils, Vector3 } from 'three'; +import { useSceneContext } from '../../scene/sceneContext'; + +function WallAssetCreator() { + const { socket } = useSocketStore(); + const { pointer, camera, raycaster, scene, gl } = useThree(); + const { togglView } = useToggleView(); + const { activeModule } = useModuleStore(); + const { wallAssetStore } = useSceneContext(); + const { addWallAsset } = wallAssetStore(); + const { selectedItem, setSelectedItem } = useSelectedItem(); + + function closestPointOnLineSegment(p: Vector3, a: Vector3, b: Vector3) { + const ab = new Vector3().subVectors(b, a); + const ap = new Vector3().subVectors(p, a); + + const abLengthSq = ab.lengthSq(); + const dot = ap.dot(ab); + const t = Math.max(0, Math.min(1, dot / abLengthSq)); + + return new Vector3().copy(a).add(ab.multiplyScalar(t)); + } + + useEffect(() => { + const canvasElement = gl.domElement; + + const onDrop = (event: DragEvent) => { + if (!event.dataTransfer?.files[0]) return; + if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category === 'Fenestration') { + pointer.x = (event.clientX / window.innerWidth) * 2 - 1; + pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; + + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects(scene.children, true); + const intersect = intersects.find((intersect) => intersect.object.name.includes('WallReference')); + + if (intersect) { + const wall = intersect.object.userData as Wall; + const closestPoint = closestPointOnLineSegment( + new Vector3(intersect.point.x, 0, intersect.point.z), + new Vector3(...wall.points[0].position), + new Vector3(...wall.points[1].position) + ) + + const wallRotation = intersect.object.rotation.clone(); + + const newWallAsset: WallAsset = { + modelName: selectedItem.name, + modelUuid: MathUtils.generateUUID(), + wallUuid: wall.wallUuid, + wallAssetType: selectedItem.subCategory, + assetId: selectedItem.id, + position: [closestPoint.x, selectedItem.subCategory === "fixed-move" ? 0 : intersect.point.y, closestPoint.z], + rotation: [wallRotation.x, wallRotation.y, wallRotation.z], + isLocked: false, + isVisible: true, + opacity: 1, + }; + + addWallAsset(newWallAsset); + } + } + }; + + if (!togglView && activeModule === 'builder') { + canvasElement.addEventListener('drop', onDrop); + } + + return () => { + canvasElement.removeEventListener('drop', onDrop); + }; + + }, [gl, camera, togglView, activeModule, socket, selectedItem, setSelectedItem]); + + return ( + <> + + ) +} + +export default WallAssetCreator \ No newline at end of file diff --git a/app/src/modules/builder/wallAsset/wallAssetGroup.tsx b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx new file mode 100644 index 0000000..d9ec309 --- /dev/null +++ b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx @@ -0,0 +1,17 @@ +import WallAssetCreator from './wallAssetCreator' +import WallAssetInstances from './Instances/wallAssetInstances' + +function WallAssetGroup() { + + return ( + <> + + + + + + + ) +} + +export default WallAssetGroup \ No newline at end of file diff --git a/app/src/modules/builder/zone/zoneGroup.tsx b/app/src/modules/builder/zone/zoneGroup.tsx index fc9dc7f..46bddb7 100644 --- a/app/src/modules/builder/zone/zoneGroup.tsx +++ b/app/src/modules/builder/zone/zoneGroup.tsx @@ -29,7 +29,6 @@ function ZoneGroup() { useEffect(() => { if (projectId && selectedVersion) { getZonesApi(projectId, selectedVersion?.versionId || '').then((zones) => { - console.log('zones: ', zones); if (zones && zones.length > 0) { setZones(zones); } else { diff --git a/app/src/modules/scene/environment/ground.tsx b/app/src/modules/scene/environment/ground.tsx index ef51791..f6baeef 100644 --- a/app/src/modules/scene/environment/ground.tsx +++ b/app/src/modules/scene/environment/ground.tsx @@ -1,14 +1,13 @@ import { useTileDistance, useToggleView } from "../../../store/builder/store"; import * as CONSTANTS from "../../../types/world/worldConstants"; -const Ground = ({ grid, plane }: any) => { +const Ground = ({ plane }: any) => { const { toggleView } = useToggleView(); const { planeValue, gridValue } = useTileDistance(); return ( diff --git a/app/src/services/factoryBuilder/zone/upsertZoneApi.ts b/app/src/services/factoryBuilder/zone/upsertZoneApi.ts index ffa79c5..e19eae8 100644 --- a/app/src/services/factoryBuilder/zone/upsertZoneApi.ts +++ b/app/src/services/factoryBuilder/zone/upsertZoneApi.ts @@ -6,7 +6,7 @@ export const upsertZoneApi = async ( zoneData: Zone ) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertZone`, { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/upsertZone`, { method: "POST", headers: { Authorization: "Bearer ", diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index d346547..de7586a 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -51,9 +51,11 @@ type Assets = Asset[]; interface WallAsset { modelUuid: string; modelName: string; + wallAssetType: string; assetId: string; wallUuid: string; position: [number, number, number]; + rotation: [number, number, number]; isLocked: boolean; isVisible: boolean; opacity: number; From 1a9aef323ac2ad2c5718d076316742668d6f5260 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 30 Jun 2025 16:59:27 +0530 Subject: [PATCH 16/18] feat: Add selectedWallAsset and selectedFloorAsset state management; implement corresponding setters in useBuilderStore --- .../Instances/Instances/wallAssetInstance.tsx | 40 +++++++++++++------ .../builder/wallAsset/wallAssetGroup.tsx | 23 ++++++++++- .../scene/postProcessing/postProcessing.tsx | 21 +++++++++- app/src/store/builder/useBuilderStore.ts | 32 +++++++++++++++ 4 files changed, 102 insertions(+), 14 deletions(-) diff --git a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx index 6261be6..e8255e1 100644 --- a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx +++ b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx @@ -4,17 +4,21 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; import { Base, Geometry, Subtraction } from '@react-three/csg'; -import { useFrame } from '@react-three/fiber'; +import useModuleStore from '../../../../../store/useModuleStore'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; +import { useToggleView } from '../../../../../store/builder/store'; function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; const { wallStore } = useSceneContext(); const { walls, getWallById } = wallStore(); + const { togglView } = useToggleView(); + const { activeModule } = useModuleStore(); + const { selectedWallAsset, setSelectedWallAsset } = useBuilderStore(); const [gltfScene, setGltfScene] = useState(null); const [boundingBox, setBoundingBox] = useState(null); const groupRef = useRef(null); - const csgRef = useRef(null); const wall = useMemo(() => getWallById(wallAsset.wallUuid), [getWallById, wallAsset.wallUuid, walls]); useEffect(() => { @@ -90,12 +94,6 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { }, []); - useFrame(() => { - if (csgRef.current) { - csgRef.current.update(); - } - }) - if (!gltfScene || !boundingBox || !wall) { return null } const size = new THREE.Vector3(); boundingBox.getSize(size); @@ -114,17 +112,35 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { userData={wallAsset} > - + {gltfScene && ( { - console.log(wallAsset); + onClick={(e) => { + if (!togglView && activeModule === 'builder') { + if (e.object) { + e.stopPropagation(); + let currentObject = e.object as THREE.Object3D; + while (currentObject) { + if (currentObject.name === "Scene") { + break; + } + currentObject = currentObject.parent as THREE.Object3D; + } + setSelectedWallAsset(currentObject); + } + } }} + onPointerMissed={() => { + if (selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) { + setSelectedWallAsset(null); + } + }} + userData={wallAsset} > - + )} diff --git a/app/src/modules/builder/wallAsset/wallAssetGroup.tsx b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx index d9ec309..ac55d01 100644 --- a/app/src/modules/builder/wallAsset/wallAssetGroup.tsx +++ b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx @@ -1,8 +1,29 @@ +import { useEffect } from 'react'; +import { useToggleView } from '../../../store/builder/store'; +import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import { useVersionContext } from '../version/versionContext'; +import { useSceneContext } from '../../scene/sceneContext'; +import { useParams } from 'react-router-dom'; +import useModuleStore from '../../../store/useModuleStore'; import WallAssetCreator from './wallAssetCreator' import WallAssetInstances from './Instances/wallAssetInstances' function WallAssetGroup() { - + const { togglView } = useToggleView(); + const { setSelectedFloorAsset } = useBuilderStore(); + const { activeModule } = useModuleStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { wallAssetStore } = useSceneContext(); + const { setWallAssets } = wallAssetStore(); + const { projectId } = useParams(); + + useEffect(() => { + if (togglView || activeModule !== 'builder') { + setSelectedFloorAsset(null); + } + }, [togglView, activeModule]) + return ( <> diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 4a222a5..e6ec6a2 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -15,7 +15,7 @@ export default function PostProcessing() { const { selectedWallItem } = useSelectedWallItem(); const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAisle, selectedWall, selectedDecal, selectedFloor } = useBuilderStore(); + const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset } = useBuilderStore(); function flattenChildren(children: any[]) { const allChildren: any[] = []; @@ -48,6 +48,10 @@ export default function PostProcessing() { // console.log('selectedFloor: ', selectedFloor); }, [selectedFloor]) + useEffect(() => { + // console.log('selectedWallAsset: ', selectedWallAsset); + }, [selectedWallAsset]) + return ( + {selectedWallAsset && ( + + )} {selectedAisle && ( void; setHoveredLine: (line: [Point, Point] | null) => void; + // Setters - Wall Asset + setSelectedWallAsset: (asset: Object3D | null) => void; + + // Setters - Floor Asset + setSelectedFloorAsset: (asset: Object3D | null) => void; + // Setters - Wall setSelectedWall: (wall: Object3D | null) => void; setWallThickness: (thickness: number) => void; @@ -100,6 +112,10 @@ export const useBuilderStore = create()( snappedPosition: null, hoveredLine: null, + selectedWallAsset: null, + + selectedFloorAsset: null, + selectedWall: null, wallThickness: 0.5, wallHeight: 7, @@ -156,6 +172,22 @@ export const useBuilderStore = create()( }) }, + // === Setters: Wall Asset === + + setSelectedWallAsset(asset: Object3D | null) { + set((state) => { + state.selectedWallAsset = asset; + }); + }, + + // === Setters: Floor Asset === + + setSelectedFloorAsset(asset: Object3D | null) { + set((state) => { + state.selectedFloorAsset = asset; + }); + }, + // === Setters: Wall === setSelectedWall: (wall: Object3D | null) => { From 364b643c724c4d28562e40617035d7108b4a73e0 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 30 Jun 2025 17:48:29 +0530 Subject: [PATCH 17/18] feat: Enhance wall asset interaction and management; implement position updates and add closest point calculation utility --- .../helpers/getClosestPointOnLineSegment.ts | 12 ++++ .../Instances/Instances/wallAssetInstance.tsx | 68 ++++++++++++++++++- .../Instances/wallAssetInstances.tsx | 47 ++++++++++++- .../builder/wallAsset/wallAssetCreator.tsx | 12 +--- .../selectionControls/selectionControls.tsx | 2 +- app/src/store/builder/useWallAssetStore.ts | 8 +++ 6 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 app/src/modules/builder/line/helpers/getClosestPointOnLineSegment.ts diff --git a/app/src/modules/builder/line/helpers/getClosestPointOnLineSegment.ts b/app/src/modules/builder/line/helpers/getClosestPointOnLineSegment.ts new file mode 100644 index 0000000..8b65282 --- /dev/null +++ b/app/src/modules/builder/line/helpers/getClosestPointOnLineSegment.ts @@ -0,0 +1,12 @@ +import { Vector3 } from "three"; + +export default function closestPointOnLineSegment(p: Vector3, a: Vector3, b: Vector3) { + const ab = new Vector3().subVectors(b, a); + const ap = new Vector3().subVectors(p, a); + + const abLengthSq = ab.lengthSq(); + const dot = ap.dot(ab); + const t = Math.max(0, Math.min(1, dot / abLengthSq)); + + return new Vector3().copy(a).add(ab.multiplyScalar(t)); +} \ No newline at end of file diff --git a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx index e8255e1..90b93ad 100644 --- a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx +++ b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx @@ -8,11 +8,15 @@ import useModuleStore from '../../../../../store/useModuleStore'; import { useSceneContext } from '../../../../scene/sceneContext'; import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; import { useToggleView } from '../../../../../store/builder/store'; +import closestPointOnLineSegment from '../../../line/helpers/getClosestPointOnLineSegment'; +import { useThree } from '@react-three/fiber'; function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; - const { wallStore } = useSceneContext(); + const { raycaster, pointer, camera, scene, controls, gl } = useThree(); + const { wallStore, wallAssetStore } = useSceneContext(); const { walls, getWallById } = wallStore(); + const { updateWallAsset } = wallAssetStore(); const { togglView } = useToggleView(); const { activeModule } = useModuleStore(); const { selectedWallAsset, setSelectedWallAsset } = useBuilderStore(); @@ -20,6 +24,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { const [boundingBox, setBoundingBox] = useState(null); const groupRef = useRef(null); const wall = useMemo(() => getWallById(wallAsset.wallUuid), [getWallById, wallAsset.wallUuid, walls]); + const draggingRef = useRef(false); useEffect(() => { const loader = new GLTFLoader(); @@ -94,6 +99,57 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { }, []); + useEffect(() => { + const canvasElement = gl.domElement; + + const onPointerUp = () => { + draggingRef.current = false; + if (controls) { + (controls as any).enabled = true; + } + }; + + const onPointerMove = (e: any) => { + if (!draggingRef.current || !wall || !selectedWallAsset) return; + if (controls) { + (controls as any).enabled = false; + } + pointer.x = (e.clientX / window.innerWidth) * 2 - 1; + pointer.y = -(e.clientY / window.innerHeight) * 2 + 1; + + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects(scene.children, true); + const intersect = intersects.find((i: any) => i.object.name.includes('WallReference')); + + if (intersect && intersect.object.userData.wallUuid) { + const newPoint = closestPointOnLineSegment( + new THREE.Vector3(intersect.point.x, 0, intersect.point.z), + new THREE.Vector3(...intersect.object.userData.points[0].position), + new THREE.Vector3(...intersect.object.userData.points[1].position) + ); + + const wallRotation = intersect.object.rotation.clone(); + + updateWallAsset(wallAsset.modelUuid, { + wallUuid: intersect.object.userData.wallUuid, + position: [newPoint.x, wallAsset.wallAssetType === 'fixed-move' ? 0 : intersect.point.y, newPoint.z], + rotation: [wallRotation.x, wallRotation.y, wallRotation.z], + }); + } + }; + + if (selectedWallAsset && !togglView && activeModule === 'builder') { + canvasElement.addEventListener('mousemove', onPointerMove); + canvasElement.addEventListener('pointerup', onPointerUp); + } + + return () => { + canvasElement.removeEventListener('mousemove', onPointerMove); + canvasElement.removeEventListener('pointerup', onPointerUp); + }; + + }, [gl, camera, togglView, activeModule, selectedWallAsset]) + if (!gltfScene || !boundingBox || !wall) { return null } const size = new THREE.Vector3(); boundingBox.getSize(size); @@ -118,6 +174,16 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { {gltfScene && ( { + if (!togglView && activeModule === 'builder' && selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) { + draggingRef.current = true; + e.stopPropagation(); + setSelectedWallAsset(groupRef.current); + if (controls) { + (controls as any).enabled = false; + } + } + }} onClick={(e) => { if (!togglView && activeModule === 'builder') { if (e.object) { diff --git a/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx b/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx index 581dfe7..3c5fbdd 100644 --- a/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx +++ b/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx @@ -5,9 +5,54 @@ import WallAssetInstance from './Instances/wallAssetInstance'; function WallAssetInstances() { const { wallAssetStore } = useSceneContext(); - const { wallAssets } = wallAssetStore(); + const { wallAssets, setWallAssets } = wallAssetStore(); const { toggleView } = useToggleView(); + useEffect(() => { + setWallAssets([ + { + "modelName": "shutter_open", + "modelUuid": "23bf68d5-10c9-4cd0-807f-80e5016707b5", + "wallUuid": "7fc7984d-6d62-4cec-afaa-289673dcce43", + "wallAssetType": "fixed-move", + "assetId": "274f6c32aa861255c2947bea", + "position": [ + -13.748701534598418, + 0, + 20.112805679001355 + ], + "rotation": [ + 0, + -3.141592653589793, + 0 + ], + "isLocked": false, + "isVisible": true, + "opacity": 1 + }, + { + "modelName": "window", + "modelUuid": "5d73f98e-6f17-42b0-a53c-9a2c4472f2be", + "wallUuid": "7fc7984d-6d62-4cec-afaa-289673dcce43", + "wallAssetType": "free-move", + "assetId": "e44a85ff2021392f4c4a03f4", + "position": [ + -4.522713460474861, + 4.189202463272018, + 20.112805679001355 + ], + "rotation": [ + 0, + -3.141592653589793, + 0 + ], + "isLocked": false, + "isVisible": true, + "opacity": 1 + } + ]) + }, []) + useEffect(() => { // console.log('wallAssets: ', wallAssets); }, [wallAssets]) diff --git a/app/src/modules/builder/wallAsset/wallAssetCreator.tsx b/app/src/modules/builder/wallAsset/wallAssetCreator.tsx index a64d957..aacca0e 100644 --- a/app/src/modules/builder/wallAsset/wallAssetCreator.tsx +++ b/app/src/modules/builder/wallAsset/wallAssetCreator.tsx @@ -4,6 +4,7 @@ import { useSelectedItem, useSocketStore, useToggleView } from '../../../store/b import useModuleStore from '../../../store/useModuleStore'; import { MathUtils, Vector3 } from 'three'; import { useSceneContext } from '../../scene/sceneContext'; +import closestPointOnLineSegment from '../line/helpers/getClosestPointOnLineSegment'; function WallAssetCreator() { const { socket } = useSocketStore(); @@ -14,17 +15,6 @@ function WallAssetCreator() { const { addWallAsset } = wallAssetStore(); const { selectedItem, setSelectedItem } = useSelectedItem(); - function closestPointOnLineSegment(p: Vector3, a: Vector3, b: Vector3) { - const ab = new Vector3().subVectors(b, a); - const ap = new Vector3().subVectors(p, a); - - const abLengthSq = ab.lengthSq(); - const dot = ap.dot(ab); - const t = Math.max(0, Math.min(1, dot / abLengthSq)); - - return new Vector3().copy(a).add(ab.multiplyScalar(t)); - } - useEffect(() => { const canvasElement = gl.domElement; diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index fdc6d9a..645ed1c 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -225,7 +225,7 @@ const SelectionControls: React.FC = () => { selectedObjects.forEach((object) => { let currentObject: THREE.Object3D | null = object; while (currentObject) { - if (currentObject.userData.modelUuid) { + if (currentObject.userData.modelUuid && !currentObject.userData.wallAssetType) { Objects.add(currentObject); break; } diff --git a/app/src/store/builder/useWallAssetStore.ts b/app/src/store/builder/useWallAssetStore.ts index 408aade..3d4e89d 100644 --- a/app/src/store/builder/useWallAssetStore.ts +++ b/app/src/store/builder/useWallAssetStore.ts @@ -6,6 +6,7 @@ interface WallAssetStore { setWallAssets: (assets: WallAsset[]) => void; addWallAsset: (asset: WallAsset) => void; updateWallAsset: (uuid: string, updated: Partial) => void; + setWallAssetPosition: (uuid: string, position: [number, number, number]) => void; removeWallAsset: (uuid: string) => void; clearWallAssets: () => void; @@ -37,6 +38,13 @@ export const createWallAssetStore = () => { } }), + setWallAssetPosition: (uuid, position) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + asset.position = position; + } + }), + removeWallAsset: (uuid) => set(state => { state.wallAssets = state.wallAssets.filter(a => a.modelUuid !== uuid); }), From 0a039f34b14dbd55a729431969d657943b28db74 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 30 Jun 2025 18:11:37 +0530 Subject: [PATCH 18/18] feat: Integrate active tool management across builder components; add deletableWallAsset state and related functionality --- app/src/modules/builder/floor/floorGroup.tsx | 5 +- app/src/modules/builder/wall/wallGroup.tsx | 5 +- .../Instances/Instances/wallAssetInstance.tsx | 62 ++++++++++++++++--- .../Instances/wallAssetInstances.tsx | 47 +------------- .../builder/wallAsset/wallAssetGroup.tsx | 8 ++- app/src/modules/builder/zone/zoneGroup.tsx | 5 +- .../scene/postProcessing/postProcessing.tsx | 21 ++++++- app/src/store/builder/useBuilderStore.ts | 9 +++ 8 files changed, 97 insertions(+), 65 deletions(-) diff --git a/app/src/modules/builder/floor/floorGroup.tsx b/app/src/modules/builder/floor/floorGroup.tsx index e0da8e5..47ea3b5 100644 --- a/app/src/modules/builder/floor/floorGroup.tsx +++ b/app/src/modules/builder/floor/floorGroup.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useToggleView } from '../../../store/builder/store' +import { useActiveTool, useToggleView } from '../../../store/builder/store' import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useVersionContext } from '../version/versionContext'; import { useSceneContext } from '../../scene/sceneContext'; @@ -13,6 +13,7 @@ function FloorGroup() { const { togglView } = useToggleView(); const { setSelectedFloor, setSelectedDecal } = useBuilderStore(); const { activeModule } = useModuleStore(); + const { activeTool } = useActiveTool(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { floorStore } = useSceneContext(); @@ -24,7 +25,7 @@ function FloorGroup() { setSelectedFloor(null); setSelectedDecal(null); } - }, [togglView, activeModule]) + }, [togglView, activeModule, activeTool]) useEffect(() => { if (projectId && selectedVersion) { diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index bd8bad1..084b969 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useToggleView } from '../../../store/builder/store'; +import { useActiveTool, useToggleView } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useVersionContext } from '../version/versionContext'; import { useSceneContext } from '../../scene/sceneContext'; @@ -14,6 +14,7 @@ function WallGroup() { const { togglView } = useToggleView(); const { setSelectedWall, setSelectedDecal } = useBuilderStore(); const { activeModule } = useModuleStore(); + const { activeTool } = useActiveTool(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { wallStore } = useSceneContext(); @@ -25,7 +26,7 @@ function WallGroup() { setSelectedWall(null); setSelectedDecal(null); } - }, [togglView, activeModule]) + }, [togglView, activeModule, activeTool]) useEffect(() => { if (projectId && selectedVersion) { diff --git a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx index 90b93ad..d9f8df0 100644 --- a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx +++ b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx @@ -1,5 +1,5 @@ import * as THREE from 'three'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; @@ -7,7 +7,7 @@ import { Base, Geometry, Subtraction } from '@react-three/csg'; import useModuleStore from '../../../../../store/useModuleStore'; import { useSceneContext } from '../../../../scene/sceneContext'; import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; -import { useToggleView } from '../../../../../store/builder/store'; +import { useActiveTool, useToggleView } from '../../../../../store/builder/store'; import closestPointOnLineSegment from '../../../line/helpers/getClosestPointOnLineSegment'; import { useThree } from '@react-three/fiber'; @@ -16,10 +16,11 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { const { raycaster, pointer, camera, scene, controls, gl } = useThree(); const { wallStore, wallAssetStore } = useSceneContext(); const { walls, getWallById } = wallStore(); - const { updateWallAsset } = wallAssetStore(); - const { togglView } = useToggleView(); + const { updateWallAsset, removeWallAsset } = wallAssetStore(); + const { toggleView } = useToggleView(); + const { activeTool } = useActiveTool(); const { activeModule } = useModuleStore(); - const { selectedWallAsset, setSelectedWallAsset } = useBuilderStore(); + const { selectedWallAsset, setSelectedWallAsset, setDeletableWallAsset, deletableWallAsset } = useBuilderStore(); const [gltfScene, setGltfScene] = useState(null); const [boundingBox, setBoundingBox] = useState(null); const groupRef = useRef(null); @@ -138,7 +139,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { } }; - if (selectedWallAsset && !togglView && activeModule === 'builder') { + if (selectedWallAsset && !toggleView && activeModule === 'builder') { canvasElement.addEventListener('mousemove', onPointerMove); canvasElement.addEventListener('pointerup', onPointerUp); } @@ -148,7 +149,29 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { canvasElement.removeEventListener('pointerup', onPointerUp); }; - }, [gl, camera, togglView, activeModule, selectedWallAsset]) + }, [gl, camera, toggleView, activeModule, selectedWallAsset]) + + const handlePointerClick = useCallback((wallAsset: WallAsset) => { + if (activeTool === 'delete' && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) { + removeWallAsset(wallAsset.modelUuid); + } + }, [activeTool, activeModule, deletableWallAsset]) + + const handlePointerOver = useCallback((wallAsset: WallAsset, currentObject: THREE.Object3D) => { + if (activeTool === "delete" && activeModule === 'builder') { + if (deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) { + return; + } else { + setDeletableWallAsset(currentObject); + } + } + }, [activeTool, activeModule, deletableWallAsset]); + + const handlePointerOut = useCallback((wallAsset: WallAsset) => { + if (activeTool === "delete" && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) { + setDeletableWallAsset(null); + } + }, [activeTool, deletableWallAsset]); if (!gltfScene || !boundingBox || !wall) { return null } const size = new THREE.Vector3(); @@ -175,7 +198,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { {gltfScene && ( { - if (!togglView && activeModule === 'builder' && selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) { + if (!toggleView && activeModule === 'builder' && selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) { draggingRef.current = true; e.stopPropagation(); setSelectedWallAsset(groupRef.current); @@ -185,7 +208,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { } }} onClick={(e) => { - if (!togglView && activeModule === 'builder') { + if (!toggleView && activeModule === 'builder' && activeTool !== 'delete') { if (e.object) { e.stopPropagation(); let currentObject = e.object as THREE.Object3D; @@ -197,6 +220,8 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { } setSelectedWallAsset(currentObject); } + } else if (!toggleView && activeModule === 'builder' && activeTool === 'delete') { + handlePointerClick(wallAsset); } }} onPointerMissed={() => { @@ -204,6 +229,25 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { setSelectedWallAsset(null); } }} + onPointerEnter={(e) => { + if (!toggleView) { + e.stopPropagation(); + let currentObject = e.object as THREE.Object3D; + while (currentObject) { + if (currentObject.name === "Scene") { + break; + } + currentObject = currentObject.parent as THREE.Object3D; + } + handlePointerOver(wallAsset, currentObject); + } + }} + onPointerOut={(e) => { + if (!toggleView) { + e.stopPropagation(); + handlePointerOut(wallAsset); + } + }} userData={wallAsset} > diff --git a/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx b/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx index 3c5fbdd..581dfe7 100644 --- a/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx +++ b/app/src/modules/builder/wallAsset/Instances/wallAssetInstances.tsx @@ -5,54 +5,9 @@ import WallAssetInstance from './Instances/wallAssetInstance'; function WallAssetInstances() { const { wallAssetStore } = useSceneContext(); - const { wallAssets, setWallAssets } = wallAssetStore(); + const { wallAssets } = wallAssetStore(); const { toggleView } = useToggleView(); - useEffect(() => { - setWallAssets([ - { - "modelName": "shutter_open", - "modelUuid": "23bf68d5-10c9-4cd0-807f-80e5016707b5", - "wallUuid": "7fc7984d-6d62-4cec-afaa-289673dcce43", - "wallAssetType": "fixed-move", - "assetId": "274f6c32aa861255c2947bea", - "position": [ - -13.748701534598418, - 0, - 20.112805679001355 - ], - "rotation": [ - 0, - -3.141592653589793, - 0 - ], - "isLocked": false, - "isVisible": true, - "opacity": 1 - }, - { - "modelName": "window", - "modelUuid": "5d73f98e-6f17-42b0-a53c-9a2c4472f2be", - "wallUuid": "7fc7984d-6d62-4cec-afaa-289673dcce43", - "wallAssetType": "free-move", - "assetId": "e44a85ff2021392f4c4a03f4", - "position": [ - -4.522713460474861, - 4.189202463272018, - 20.112805679001355 - ], - "rotation": [ - 0, - -3.141592653589793, - 0 - ], - "isLocked": false, - "isVisible": true, - "opacity": 1 - } - ]) - }, []) - useEffect(() => { // console.log('wallAssets: ', wallAssets); }, [wallAssets]) diff --git a/app/src/modules/builder/wallAsset/wallAssetGroup.tsx b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx index ac55d01..f9d1290 100644 --- a/app/src/modules/builder/wallAsset/wallAssetGroup.tsx +++ b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useToggleView } from '../../../store/builder/store'; +import { useActiveTool, useToggleView } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useVersionContext } from '../version/versionContext'; import { useSceneContext } from '../../scene/sceneContext'; @@ -10,8 +10,9 @@ import WallAssetInstances from './Instances/wallAssetInstances' function WallAssetGroup() { const { togglView } = useToggleView(); - const { setSelectedFloorAsset } = useBuilderStore(); + const { setSelectedFloorAsset, setDeletableWallAsset } = useBuilderStore(); const { activeModule } = useModuleStore(); + const { activeTool } = useActiveTool(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { wallAssetStore } = useSceneContext(); @@ -22,7 +23,8 @@ function WallAssetGroup() { if (togglView || activeModule !== 'builder') { setSelectedFloorAsset(null); } - }, [togglView, activeModule]) + setDeletableWallAsset(null); + }, [togglView, activeModule, activeTool]) return ( <> diff --git a/app/src/modules/builder/zone/zoneGroup.tsx b/app/src/modules/builder/zone/zoneGroup.tsx index 46bddb7..c44bf09 100644 --- a/app/src/modules/builder/zone/zoneGroup.tsx +++ b/app/src/modules/builder/zone/zoneGroup.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useToggleView } from '../../../store/builder/store'; +import { useActiveTool, useToggleView } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useVersionContext } from '../version/versionContext'; import { useSceneContext } from '../../scene/sceneContext'; @@ -14,6 +14,7 @@ function ZoneGroup() { const { togglView } = useToggleView(); const { setSelectedZone } = useBuilderStore(); const { activeModule } = useModuleStore(); + const { activeTool } = useActiveTool(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { zoneStore } = useSceneContext(); @@ -24,7 +25,7 @@ function ZoneGroup() { if (togglView || activeModule !== 'builder') { setSelectedZone(null); } - }, [togglView, activeModule]) + }, [togglView, activeModule, activeTool]) useEffect(() => { if (projectId && selectedVersion) { diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index e6ec6a2..6c2f8d6 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -15,7 +15,7 @@ export default function PostProcessing() { const { selectedWallItem } = useSelectedWallItem(); const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset } = useBuilderStore(); + const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset, deletableWallAsset } = useBuilderStore(); function flattenChildren(children: any[]) { const allChildren: any[] = []; @@ -52,6 +52,10 @@ export default function PostProcessing() { // console.log('selectedWallAsset: ', selectedWallAsset); }, [selectedWallAsset]) + useEffect(() => { + // console.log('deletableWallAsset: ', deletableWallAsset); + }, [deletableWallAsset]) + return ( )} + {deletableWallAsset && ( + + )} {selectedAisle && ( void; + setDeletableWallAsset: (asset: Object3D | null) => void; // Setters - Floor Asset setSelectedFloorAsset: (asset: Object3D | null) => void; @@ -113,6 +115,7 @@ export const useBuilderStore = create()( hoveredLine: null, selectedWallAsset: null, + deletableWallAsset: null, selectedFloorAsset: null, @@ -180,6 +183,12 @@ export const useBuilderStore = create()( }); }, + setDeletableWallAsset(asset: Object3D | null) { + set((state) => { + state.deletableWallAsset = asset; + }); + }, + // === Setters: Floor Asset === setSelectedFloorAsset(asset: Object3D | null) {