diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index cc53b9d..d6d9a1d 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -9,6 +9,7 @@ import * as Constants from '../../../types/world/worldConstants'; import { useVersionContext } from '../version/versionContext'; import { useParams } from 'react-router-dom'; import { getUserData } from '../../../functions/getUserData'; +import { useSelectedPoints } from '../../../store/simulation/useSimulationStore'; // import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; // import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; @@ -38,6 +39,7 @@ function Line({ points }: Readonly) { const { projectId } = useParams(); const [dragOffset, setDragOffset] = useState(null); const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore(); + const { selectedPoints } = useSelectedPoints(); const path = useMemo(() => { const [start, end] = points.map(p => new THREE.Vector3(...p.position)); @@ -372,8 +374,8 @@ function Line({ points }: Readonly) { onClick={() => { handlePointClick(points); }} - onPointerOver={() => { - if (!hoveredLine) { + onPointerOver={(e) => { + if (!hoveredLine && selectedPoints.length === 0 && e.buttons === 0 && !e.ctrlKey) { setHoveredLine(points); setIsHovered(true) if (toolMode === 'move' && !hoveredPoint) { diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index 73dec77..9ed9f36 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -5,6 +5,7 @@ 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 { useSelectedPoints } from '../../../store/simulation/useSimulationStore'; import { usePointSnapping } from './helpers/usePointSnapping'; import { useParams } from 'react-router-dom'; import { useVersionContext } from '../version/versionContext'; @@ -26,6 +27,7 @@ function Point({ point }: { readonly point: Point }) { 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 [isSelected, setIsSelected] = useState(false); const [dragOffset, setDragOffset] = useState(null); const { socket } = useSocketStore(); const { toolMode } = useToolMode(); @@ -36,6 +38,7 @@ function Point({ point }: { readonly point: Point }) { 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 { selectedPoints } = useSelectedPoints(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); @@ -406,50 +409,61 @@ function Point({ point }: { readonly point: Point }) { } }, [hoveredPoint]) + useEffect(() => { + if (selectedPoints.length > 0 && selectedPoints.some((selectedPoint) => (selectedPoint.userData.pointUuid && selectedPoint.userData.pointUuid === point.pointUuid))) { + setIsSelected(true); + } else { + setIsSelected(false); + } + }, [selectedPoints]) + if (!point) { return null; } + return ( - handleDragStart(point)} - onDrag={() => handleDrag(point)} - onDragEnd={() => handleDragEnd(point)} - > - { - handlePointClick(point); - }} - onPointerOver={() => { - if (!hoveredPoint) { - setHoveredPoint(point); - setIsHovered(true); - if (toolMode === 'move') { - gl.domElement.style.cursor = 'pointer'; - } - } - }} - onPointerOut={() => { - if (hoveredPoint) { - setHoveredPoint(null); - gl.domElement.style.cursor = 'default'; - } - setIsHovered(false) - }} - userData={point} - > - - + {!isSelected ? + handleDragStart(point)} + onDrag={() => handleDrag(point)} + onDragEnd={() => handleDragEnd(point)} + > + { + handlePointClick(point); + }} + onPointerOver={(e) => { + if (!hoveredPoint && selectedPoints.length === 0 && e.buttons === 0 && !e.ctrlKey) { + setHoveredPoint(point); + setIsHovered(true); + if (toolMode === 'move') { + gl.domElement.style.cursor = 'pointer'; + } + } + }} + onPointerOut={() => { + if (hoveredPoint) { + setHoveredPoint(null); + gl.domElement.style.cursor = 'default'; + } + setIsHovered(false) + }} + userData={point} + > + + - - + } + /> + + + : + + + + + + + + + + + + + } + ); } diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx index f0bbc29..975ab54 100644 --- a/app/src/modules/scene/controls/controls.tsx +++ b/app/src/modules/scene/controls/controls.tsx @@ -9,10 +9,11 @@ import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi" import updateCamPosition from "../camera/updateCameraPosition"; import CamMode from "../camera/camMode"; import SwitchView from "../camera/switchView"; -import SelectionControls from "./selectionControls/selectionControls"; +import SelectionControls3D from "./selectionControls/selection3D/selectionControls3D"; import TransformControl from "./transformControls/transformControls"; import { useParams } from "react-router-dom"; import { getUserData } from "../../../functions/getUserData"; +import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D"; export default function Controls() { const controlsRef = useRef(null); @@ -137,7 +138,9 @@ export default function Controls() { - + + + diff --git a/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx b/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx new file mode 100644 index 0000000..9081b4f --- /dev/null +++ b/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx @@ -0,0 +1,405 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import * as THREE from "three"; +import { useFrame, useThree } from "@react-three/fiber"; +import { SelectionHelper } from "../selectionHelper"; +import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox"; +import * as Types from "../../../../../types/world/worldTypes"; + +import useModuleStore from "../../../../../store/useModuleStore"; +import { useParams } from "react-router-dom"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useSceneContext } from "../../../sceneContext"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useProductContext } from "../../../../simulation/products/productContext"; +import { useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store"; +import { useSelectedPoints } from "../../../../../store/simulation/useSimulationStore"; +import { useBuilderStore } from "../../../../../store/builder/useBuilderStore"; + +// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi"; +// import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi"; +// import { deleteFloorApi } from "../../../../../services/factoryBuilder/floor/deleteFloorApi"; +// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi"; +// import { deleteZoneApi } from "../../../../../services/factoryBuilder/zone/deleteZoneApi"; +// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi"; + +const SelectionControls2D: React.FC = () => { + const { camera, controls, gl, scene, raycaster, pointer } = useThree(); + const selectionGroup = useRef() as Types.RefGroup; + const { toggleView } = useToggleView(); + const { selectedPoints, setSelectedPoints, clearSelectedPoints } = useSelectedPoints(); + const [movedObjects, setMovedObjects] = useState([]); + const [rotatedObjects, setRotatedObjects] = useState([]); + const [copiedObjects, setCopiedObjects] = useState([]); + const [pastedObjects, setpastedObjects] = useState([]); + const [duplicatedObjects, setDuplicatedObjects] = useState([]); + const boundingBoxRef = useRef(); + const { activeModule } = useModuleStore(); + const { socket } = useSocketStore(); + const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]); + const { toolMode } = useToolMode(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); + const { projectId } = useParams(); + const { hoveredLine, hoveredPoint } = useBuilderStore(); + 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 { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore(); + + const isDragging = useRef(false); + const isLeftMouseDown = useRef(false); + const isSelecting = useRef(false); + const isRightClick = useRef(false); + const rightClickMoved = useRef(false); + const isCtrlSelecting = useRef(false); + const isShiftSelecting = useRef(false); + const { userId, organization } = getUserData(); + + useEffect(() => { + if (!camera || !scene || !toggleView) return; + + const canvasElement = gl.domElement; + canvasElement.tabIndex = 0; + + const helper = new SelectionHelper(gl); + + const onPointerDown = (event: PointerEvent) => { + if (event.button === 2) { + isRightClick.current = true; + rightClickMoved.current = false; + } else if (event.button === 0) { + isSelecting.current = false; + isCtrlSelecting.current = event.ctrlKey; + isShiftSelecting.current = event.shiftKey; + isLeftMouseDown.current = true; + isDragging.current = false; + if (event.ctrlKey && duplicatedObjects.length === 0) { + if (controls) (controls as any).enabled = false; + selectionBox.startPoint.set(pointer.x, pointer.y, 0); + } + } + }; + + const onPointerMove = (event: PointerEvent) => { + if (isRightClick.current) { + rightClickMoved.current = true; + } + if (isLeftMouseDown.current) { + isDragging.current = true; + } + isSelecting.current = true; + if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting.current) { + selectionBox.endPoint.set(pointer.x, pointer.y, 0); + } + }; + + const onPointerUp = (event: PointerEvent) => { + if (event.button === 2 && !event.ctrlKey && !event.shiftKey) { + isRightClick.current = false; + if (!rightClickMoved.current) { + clearSelection(); + } + return; + } + + if (isSelecting.current && isCtrlSelecting.current) { + isCtrlSelecting.current = false; + isSelecting.current = false; + if (event.ctrlKey && duplicatedObjects.length === 0) { + selectAssets(); + } + } else if (!isSelecting.current && selectedPoints.length > 0 && ((!event.ctrlKey && !event.shiftKey && pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) || event.button !== 0)) { + clearSelection(); + helper.enabled = true; + isCtrlSelecting.current = false; + } else if (controls) { + (controls as any).enabled = true; + } + + if (!isDragging.current && isLeftMouseDown.current && isShiftSelecting.current && event.shiftKey) { + isShiftSelecting.current = false; + isLeftMouseDown.current = false; + isDragging.current = false; + + } else if (controls) { + (controls as any).enabled = true; + } + }; + + const onKeyDown = (event: KeyboardEvent) => { + if (movedObjects.length > 0 || rotatedObjects.length > 0) return; + if (event.key.toLowerCase() === "escape") { + event.preventDefault(); + clearSelection(); + } + if (event.key.toLowerCase() === "delete") { + event.preventDefault(); + deleteSelection(); + } + }; + + const onContextMenu = (event: MouseEvent) => { + event.preventDefault(); + if (!rightClickMoved.current) { + clearSelection(); + } + rightClickMoved.current = false; + }; + + if (toggleView && toolMode === 'move') { + helper.enabled = true; + canvasElement.addEventListener("pointermove", onPointerMove); + canvasElement.addEventListener("pointerup", onPointerUp); + canvasElement.addEventListener("pointerdown", onPointerDown); + canvasElement.addEventListener("contextmenu", onContextMenu); + canvasElement.addEventListener("keydown", onKeyDown); + } else { + helper.enabled = false; + helper.dispose(); + } + + return () => { + canvasElement.removeEventListener("pointerdown", onPointerDown); + canvasElement.removeEventListener("pointermove", onPointerMove); + canvasElement.removeEventListener("contextmenu", onContextMenu); + canvasElement.removeEventListener("pointerup", onPointerUp); + canvasElement.removeEventListener("keydown", onKeyDown); + helper.enabled = false; + helper.dispose(); + }; + }, [camera, controls, scene, toggleView, selectedPoints, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, rotatedObjects, toolMode, hoveredLine, hoveredPoint]); + + useEffect(() => { + if (toolMode !== 'move' || !toggleView) { + clearSelection(); + } + }, [activeModule, toolMode, toggleView]); + + useFrame(() => { + if (pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) { + selectionGroup.current.position.set(0, 0, 0); + } + }); + + const selectAssets = useCallback(() => { + selectionBox.endPoint.set(pointer.x, pointer.y, 0); + if (controls) (controls as any).enabled = true; + + let selectedObjects = selectionBox.select(); + let Objects = new Set(); + + selectedObjects.forEach((object) => { + let currentObject: THREE.Object3D | null = object; + while (currentObject) { + if (currentObject.userData.pointUuid) { + Objects.add(currentObject); + break; + } + currentObject = currentObject.parent || null; + } + }); + + if (Objects.size === 0) { + clearSelection(); + return; + } + + const updatedSelections = new Set(selectedPoints); + + Objects.forEach((obj) => { + const existing = Array.from(updatedSelections).find((o) => o.userData?.pointUuid === obj.userData?.pointUuid); + + if (existing) { + updatedSelections.delete(existing); + } else { + updatedSelections.add(obj); + } + }); + + const selected = Array.from(updatedSelections); + + setSelectedPoints(selected); + + }, [selectionBox, pointer, controls, selectedPoints, setSelectedPoints]); + + const clearSelection = () => { + selectionGroup.current.children = []; + selectionGroup.current.position.set(0, 0, 0); + selectionGroup.current.rotation.set(0, 0, 0); + setpastedObjects([]); + setDuplicatedObjects([]); + clearSelectedPoints(); + }; + + const deleteSelection = () => { + if (selectedPoints.length > 0 && duplicatedObjects.length === 0) { + + selectedPoints.map((selectedPoint) => { + if (selectedPoint.userData.pointUuid) { + const point: Point = selectedPoint.userData as Point; + if (point.pointType === 'Aisle') { + const removedAisles = removeAislePoint(point.pointUuid); + if (removedAisles.length > 0) { + removedAisles.forEach(aisle => { + if (projectId) { + + // API + + // deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || ''); + + // SOCKET + + const data = { + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization, + aisleUuid: aisle.aisleUuid + } + + socket.emit('v1:model-aisle:delete', data); + } + }); + } + } + if (point.pointType === 'Wall') { + const removedWalls = removeWallPoint(point.pointUuid); + if (removedWalls.length > 0) { + 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, updatedFloors } = removeFloorPoint(point.pointUuid); + 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); + } + }); + } + } + if (point.pointType === 'Zone') { + const { removedZones, updatedZones } = removeZonePoint(point.pointUuid); + 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); + } + }); + } + } + } + }) + + } + echo.success("Selected points removed!"); + clearSelection(); + }; + + return ( + <> + + + + + + ); +}; + +export default SelectionControls2D; diff --git a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/boundingBoxHelper3D.tsx similarity index 98% rename from app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx rename to app/src/modules/scene/controls/selectionControls/selection3D/boundingBoxHelper3D.tsx index b30b03e..aab6856 100644 --- a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/boundingBoxHelper3D.tsx @@ -1,7 +1,7 @@ import { Line } from "@react-three/drei"; import { useMemo } from "react"; import * as THREE from "three"; -import { useSelectedAssets } from "../../../../store/builder/store"; +import { useSelectedAssets } from "../../../../../store/builder/store"; interface BoundingBoxProps { boundingBoxRef?: any; diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx similarity index 97% rename from app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx rename to app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx index e8c8886..28b5363 100644 --- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx @@ -2,17 +2,17 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { SkeletonUtils } from "three-stdlib"; -import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; -import * as Types from "../../../../types/world/worldTypes"; -import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; +import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store"; +import * as Types from "../../../../../types/world/worldTypes"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; import { useParams } from "react-router-dom"; -import { getUserData } from "../../../../functions/getUserData"; -import { useSceneContext } from "../../sceneContext"; -import { useVersionContext } from "../../../builder/version/versionContext"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useSceneContext } from "../../../sceneContext"; +import { useVersionContext } from "../../../../builder/version/versionContext"; -// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; +// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; -const CopyPasteControls = ({ +const CopyPasteControls3D = ({ copiedObjects, setCopiedObjects, pastedObjects, @@ -490,4 +490,4 @@ const CopyPasteControls = ({ return null; }; -export default CopyPasteControls; \ No newline at end of file +export default CopyPasteControls3D; \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/distanceFindingControls.tsx similarity index 100% rename from app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx rename to app/src/modules/scene/controls/selectionControls/selection3D/distanceFindingControls.tsx diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx similarity index 97% rename from app/src/modules/scene/controls/selectionControls/duplicationControls.tsx rename to app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx index 3b52cdf..11d27ca 100644 --- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx @@ -2,17 +2,17 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { SkeletonUtils } from "three-stdlib"; -import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store"; -import * as Types from "../../../../types/world/worldTypes"; -import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; +import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store"; +import * as Types from "../../../../../types/world/worldTypes"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; import { useParams } from "react-router-dom"; -import { getUserData } from "../../../../functions/getUserData"; -import { useSceneContext } from "../../sceneContext"; -import { useVersionContext } from "../../../builder/version/versionContext"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useSceneContext } from "../../../sceneContext"; +import { useVersionContext } from "../../../../builder/version/versionContext"; -// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; +// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; -const DuplicationControls = ({ +const DuplicationControls3D = ({ duplicatedObjects, setDuplicatedObjects, setpastedObjects, @@ -459,4 +459,4 @@ const DuplicationControls = ({ return null; }; -export default DuplicationControls; \ No newline at end of file +export default DuplicationControls3D; \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx similarity index 94% rename from app/src/modules/scene/controls/selectionControls/moveControls.tsx rename to app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx index 79cf195..6658f62 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/moveControls3D.tsx @@ -1,20 +1,21 @@ 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/asset/floorAsset/setAssetsApi'; -import * as Types from "../../../../types/world/worldTypes"; -import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; -import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; -import { snapControls } from "../../../../utils/handleSnap"; +import { useSelectedAssets, useSocketStore, useToggleView, } from "../../../../../store/builder/store"; +import * as Types from "../../../../../types/world/worldTypes"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; +import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi"; +import { snapControls } from "../../../../../utils/handleSnap"; import DistanceFindingControls from "./distanceFindingControls"; import { useParams } from "react-router-dom"; -import { useProductContext } from "../../../simulation/products/productContext"; -import { getUserData } from "../../../../functions/getUserData"; -import { useSceneContext } from "../../sceneContext"; -import { useVersionContext } from "../../../builder/version/versionContext"; +import { useProductContext } from "../../../../simulation/products/productContext"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useSceneContext } from "../../../sceneContext"; +import { useVersionContext } from "../../../../builder/version/versionContext"; -function MoveControls({ +// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; + +function MoveControls3D({ movedObjects, setMovedObjects, pastedObjects, @@ -364,4 +365,4 @@ function MoveControls({ ); } -export default MoveControls; +export default MoveControls3D; diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/rotateControls3D.tsx similarity index 94% rename from app/src/modules/scene/controls/selectionControls/rotateControls.tsx rename to app/src/modules/scene/controls/selectionControls/selection3D/rotateControls3D.tsx index 216d4f7..fdde56a 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/rotateControls3D.tsx @@ -1,17 +1,18 @@ 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/asset/floorAsset/setAssetsApi'; -import * as Types from "../../../../types/world/worldTypes"; -import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store"; +import * as Types from "../../../../../types/world/worldTypes"; +import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useParams } from "react-router-dom"; -import { useProductContext } from "../../../simulation/products/productContext"; -import { getUserData } from "../../../../functions/getUserData"; -import { useSceneContext } from "../../sceneContext"; -import { useVersionContext } from "../../../builder/version/versionContext"; +import { useProductContext } from "../../../../simulation/products/productContext"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useSceneContext } from "../../../sceneContext"; +import { useVersionContext } from "../../../../builder/version/versionContext"; -function RotateControls({ +// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi'; + +function RotateControls3D({ rotatedObjects, setRotatedObjects, movedObjects, @@ -300,4 +301,4 @@ function RotateControls({ return null; } -export default RotateControls \ No newline at end of file +export default RotateControls3D \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx similarity index 84% rename from app/src/modules/scene/controls/selectionControls/selectionControls.tsx rename to app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx index 9a5ab33..a872a60 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx @@ -1,26 +1,27 @@ -import * as THREE from "three"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox"; -import { SelectionHelper } from "./selectionHelper"; +import * as THREE from "three"; 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/asset/floorAsset/deleteFloorItemApi'; -import * as Types from "../../../../types/world/worldTypes"; +import { SelectionHelper } from "../selectionHelper"; +import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox"; +import * as Types from "../../../../../types/world/worldTypes"; -import DuplicationControls from "./duplicationControls"; -import CopyPasteControls from "./copyPasteControls"; -import MoveControls from "./moveControls"; -import RotateControls from "./rotateControls"; -import useModuleStore from "../../../../store/useModuleStore"; +import useModuleStore from "../../../../../store/useModuleStore"; import { useParams } from "react-router-dom"; -import { getUserData } from "../../../../functions/getUserData"; -import { useSceneContext } from "../../sceneContext"; -import { useVersionContext } from "../../../builder/version/versionContext"; -import { useProductContext } from "../../../simulation/products/productContext"; -import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useSceneContext } from "../../../sceneContext"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useProductContext } from "../../../../simulation/products/productContext"; +import { useSelectedAssets, useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store"; +import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi"; +import BoundingBox from "./boundingBoxHelper3D"; +import DuplicationControls3D from "./duplicationControls3D"; +import CopyPasteControls3D from "./copyPasteControls3D"; +import MoveControls3D from "./moveControls3D"; +import RotateControls3D from "./rotateControls3D"; -const SelectionControls: React.FC = () => { +// import { deleteFloorItem } from '../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi'; + +const SelectionControls3D: React.FC = () => { const { camera, controls, gl, scene, raycaster, pointer } = useThree(); const selectionGroup = useRef() as Types.RefGroup; const { toggleView } = useToggleView(); @@ -350,15 +351,15 @@ const SelectionControls: React.FC = () => { - + - + - + - + ); }; -export default SelectionControls; +export default SelectionControls3D; diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 7c6c719..c70f733 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -6,11 +6,12 @@ import { useSelectedFloorItem, } from "../../../store/builder/store"; import * as CONSTANTS from "../../../types/world/worldConstants"; -import { useDeletableEventSphere, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; +import { useDeletableEventSphere, useSelectedEventSphere, useSelectedPoints } from "../../../store/simulation/useSimulationStore"; import { useEffect } from "react"; import { useBuilderStore } from "../../../store/builder/useBuilderStore"; export default function PostProcessing() { + const { selectedPoints } = useSelectedPoints(); const { deletableFloorItem } = useDeletableFloorItem(); const { selectedWallItem } = useSelectedWallItem(); const { selectedFloorItem } = useSelectedFloorItem(); @@ -61,6 +62,10 @@ export default function PostProcessing() { // console.log('deletableEventSphere: ', deletableEventSphere); }, [deletableEventSphere]) + useEffect(() => { + // console.log('selectedPoints: ', selectedPoints); + }, [selectedPoints]) + return ( ()( }); }, })) +); + +interface SelectedPointsState { + selectedPoints: THREE.Object3D[]; + setSelectedPoints: (points: THREE.Object3D[]) => void; + addSelectedPoint: (point: THREE.Object3D) => void; + removeSelectedPoint: (uuid: string) => void; + clearSelectedPoints: () => void; +} + +export const useSelectedPoints = create()( + immer((set) => ({ + selectedPoints: [], + setSelectedPoints: (points) => { + set((state) => { + state.selectedPoints = points; + }); + }, + addSelectedPoint: (point) => { + set((state) => { + if (!state.selectedPoints.find(p => p.uuid === point.uuid)) { + state.selectedPoints.push(point); + } + }); + }, + removeSelectedPoint: (uuid) => { + set((state) => { + state.selectedPoints = state.selectedPoints.filter(p => p.uuid !== uuid); + }); + }, + clearSelectedPoints: () => { + set((state) => { + state.selectedPoints = []; + }); + }, + })) ); \ No newline at end of file