diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index b863500..d0aaef2 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -234,14 +234,16 @@ const Assets: React.FC = () => { alt={asset.filename} className="asset-image" onPointerDown={() => { - setSelectedItem({ - name: asset.filename, - id: asset.AssetID, - type: - asset.type === "undefined" - ? undefined - : asset.type, - }); + if (asset.category !== 'Feneration') { + setSelectedItem({ + name: asset.filename, + id: asset.AssetID, + type: + asset.type === "undefined" + ? undefined + : asset.type, + }); + } }} />
diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 2187fdc..40fec27 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -29,7 +29,6 @@ import { useSocketStore, useToggleView, useToolMode, - useTransformMode, useActiveSubTool, } from "../../store/store"; import useToggleStore from "../../store/useUIToggleStore"; @@ -61,7 +60,6 @@ const Tools: React.FC = () => { const { setAddAction } = useAddAction(); const { setSelectedWallItem } = useSelectedWallItem(); - const { setTransformMode } = useTransformMode(); const { setDeletePointOrLine } = useDeletePointOrLine(); const { setToolMode } = useToolMode(); const { activeTool, setActiveTool } = useActiveTool(); @@ -126,7 +124,6 @@ const Tools: React.FC = () => { setToolMode(null); setDeleteTool(false); setAddAction(null); - setTransformMode(null); setDeletePointOrLine(false); setRefTextUpdate((prevUpdate) => prevUpdate - 1); @@ -134,20 +131,6 @@ const Tools: React.FC = () => { case "cursor": if (toggleView) { setToolMode('move'); - } else { - setTransformMode("translate"); - } - break; - - case "Rotate": - if (!toggleView) { - setTransformMode("rotate"); - } - break; - - case "Scale": - if (!toggleView) { - setTransformMode("scale"); } break; diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index dfae129..f43cf3d 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -54,57 +54,57 @@ import NavMesh from "../simulation/vehicle/navMesh/navMesh"; import CalculateAreaGroup from "./groups/calculateAreaGroup"; export default function Builder() { - const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. - const csg = useRef(); // Reference for CSG object, used for 3D modeling. - const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. - const scene = useRef() as Types.RefScene; // Reference to the scene. - const camera = useRef() as Types.RefCamera; // Reference to the camera object. - const controls = useRef(); // Reference to the controls object. - const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. - const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. + const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. + const csg = useRef(); // Reference for CSG object, used for 3D modeling. + const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. + const scene = useRef() as Types.RefScene; // Reference to the scene. + const camera = useRef() as Types.RefCamera; // Reference to the camera object. + const controls = useRef(); // Reference to the controls object. + const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. + const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. - // Assigning the scene and camera from the Three.js state to the references. + // Assigning the scene and camera from the Three.js state to the references. - scene.current = state.scene; - camera.current = state.camera; - controls.current = state.controls; - raycaster.current = state.raycaster; + scene.current = state.scene; + camera.current = state.camera; + controls.current = state.controls; + raycaster.current = state.raycaster; - const plane = useRef(null); // Reference for a plane object for raycaster reference. - const grid = useRef() as any; // Reference for a grid object for raycaster reference. - const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. - const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). - const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... - const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. - const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. - const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). - const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. - const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. - const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. - const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. - const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. - const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. - const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. - const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. - const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. - const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. - const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). - const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. - const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. - const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. - const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. - const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. - const floorGroupAisle = useRef() as Types.RefGroup; - const zoneGroup = useRef() as Types.RefGroup; - const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. - const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. - const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. - const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. - const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. - const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. - const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... + const plane = useRef(null); // Reference for a plane object for raycaster reference. + const grid = useRef() as any; // Reference for a grid object for raycaster reference. + const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. + const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). + const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... + const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. + const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. + const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). + const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. + const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. + const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. + const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. + const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. + const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. + const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. + const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. + const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. + const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. + const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). + const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. + const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. + const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. + const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. + const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. + const floorGroupAisle = useRef() as Types.RefGroup; + const zoneGroup = useRef() as Types.RefGroup; + const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. + const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. + const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. + const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. + const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. + const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. + const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... - const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. + const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item. const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. @@ -120,42 +120,39 @@ export default function Builder() { const { setWalls } = useWalls(); const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); - // const loader = new GLTFLoader(); - // const dracoLoader = new DRACOLoader(); + // const loader = new GLTFLoader(); + // const dracoLoader = new DRACOLoader(); - // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); - // loader.setDRACOLoader(dracoLoader); + // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); + // loader.setDRACOLoader(dracoLoader); - ////////// Assest Configuration Values ////////// + ////////// Assest Configuration Values ////////// - const AssetConfigurations: Types.AssetConfigurations = { - arch: { - modelUrl: arch, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - door: { - modelUrl: door, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - window: { - modelUrl: Window, - scale: [0.75, 0.75, 0.75], - csgscale: [5, 3, 0.5], - csgposition: [0, 1.5, 0], - positionY: (intersectionPoint) => intersectionPoint.point.y, - type: "Free-Move", - }, - }; + const AssetConfigurations: Types.AssetConfigurations = { + arch: { + modelUrl: arch, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + type: "Fixed-Move", + }, + door: { + modelUrl: door, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + type: "Fixed-Move", + }, + window: { + modelUrl: Window, + scale: [0.75, 0.75, 0.75], + csgscale: [5, 3, 0.5], + csgposition: [0, 1.5, 0], + type: "Free-Move", + }, + }; - ////////// All Toggle's ////////// + ////////// All Toggle's ////////// useEffect(() => { setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); @@ -177,167 +174,167 @@ export default function Builder() { } }, [toggleView]); - useEffect(() => { - THREE.Cache.clear(); - THREE.Cache.enabled = true; - }, []); + useEffect(() => { + THREE.Cache.clear(); + THREE.Cache.enabled = true; + }, []); - useEffect(() => { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; + useEffect(() => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - async function fetchVisibility() { - const visibility = await findEnvironment( - organization, - localStorage.getItem("userId")! - ); - if (visibility) { - setRoofVisibility(visibility.roofVisibility); - setWallVisibility(visibility.wallVisibility); - setShadows(visibility.shadowVisibility); - setRenderDistance(visibility.renderDistance); - setLimitDistance(visibility.limitDistance); - } - } - fetchVisibility(); - }, []); + async function fetchVisibility() { + const visibility = await findEnvironment( + organization, + localStorage.getItem("userId")! + ); + if (visibility) { + setRoofVisibility(visibility.roofVisibility); + setWallVisibility(visibility.wallVisibility); + setShadows(visibility.shadowVisibility); + setRenderDistance(visibility.renderDistance); + setLimitDistance(visibility.limitDistance); + } + } + fetchVisibility(); + }, []); - ////////// UseFrame is Here ////////// + ////////// UseFrame is Here ////////// - useFrame(() => { - if (toolMode) { - Draw( - state, - plane, - cursorPosition, - floorPlanGroupPoint, - floorPlanGroupLine, - snappedPoint, - isSnapped, - isSnappedUUID, - line, - lines, - ispreSnapped, - floorPlanGroup, - ReferenceLineMesh, - LineCreated, - setRefTextUpdate, - Tube, - anglesnappedPoint, - isAngleSnapped, - toolMode - ); - } - }); + useFrame(() => { + if (toolMode) { + Draw( + state, + plane, + cursorPosition, + floorPlanGroupPoint, + floorPlanGroupLine, + snappedPoint, + isSnapped, + isSnappedUUID, + line, + lines, + ispreSnapped, + floorPlanGroup, + ReferenceLineMesh, + LineCreated, + setRefTextUpdate, + Tube, + anglesnappedPoint, + isAngleSnapped, + toolMode + ); + } + }); - ////////// Return ////////// + ////////// Return ////////// - return ( - <> - + return ( + <> + - + - + - + - + - + - + - + - + - + - - - - - ); + + + + + ); } diff --git a/app/src/modules/builder/csg/csg.tsx b/app/src/modules/builder/csg/csg.tsx index 7e49598..eab8edc 100644 --- a/app/src/modules/builder/csg/csg.tsx +++ b/app/src/modules/builder/csg/csg.tsx @@ -4,51 +4,51 @@ import { useDeleteTool } from "../../../store/store"; import { useRef } from "react"; export interface CsgProps { - position: THREE.Vector3 | [number, number, number]; - scale: THREE.Vector3 | [number, number, number]; - model: THREE.Object3D; - hoveredDeletableWallItem: { current: THREE.Mesh | null }; + position: THREE.Vector3 | [number, number, number]; + scale: THREE.Vector3 | [number, number, number]; + model: THREE.Object3D; + hoveredDeletableWallItem: { current: THREE.Mesh | null }; } export const Csg: React.FC = (props) => { - const { deleteTool } = useDeleteTool(); - const modelRef = useRef(); - const originalMaterials = useRef>(new Map()); + const { deleteTool } = useDeleteTool(); + const modelRef = useRef(); + const originalMaterials = useRef>(new Map()); - const handleHover = (hovered: boolean, object: THREE.Mesh | null) => { - if (modelRef.current && deleteTool) { - modelRef.current.traverse((child) => { - if (child instanceof THREE.Mesh) { - if (!originalMaterials.current.has(child)) { - originalMaterials.current.set(child, child.material); - } - child.material = child.material.clone(); - child.material.color.set(hovered && deleteTool ? 0xff0000 : (originalMaterials.current.get(child) as any).color); + const handleHover = (hovered: boolean, object: THREE.Mesh | null) => { + if (modelRef.current && deleteTool) { + modelRef.current.traverse((child) => { + if (child instanceof THREE.Mesh) { + if (!originalMaterials.current.has(child)) { + originalMaterials.current.set(child, child.material); + } + child.material = child.material.clone(); + child.material.color.set(hovered && deleteTool ? 0xff0000 : (originalMaterials.current.get(child) as any).color); + } + }); } - }); - } - props.hoveredDeletableWallItem.current = hovered ? object : null; - }; + props.hoveredDeletableWallItem.current = hovered ? object : null; + }; - return ( - - + return ( - + + + + + + { + e.stopPropagation(); + handleHover(true, e.object.parent); + }} + onPointerOut={(e: any) => { + e.stopPropagation(); + handleHover(false, null); + }} + /> - - { - e.stopPropagation(); - handleHover(true, e.object.parent); - }} - onPointerOut={(e: any) => { - e.stopPropagation(); - handleHover(false, null); - }} - /> - - ); + ); }; diff --git a/app/src/modules/builder/geomentries/floors/addFloorToScene.ts b/app/src/modules/builder/geomentries/floors/addFloorToScene.ts index 7ee2ceb..71f2d24 100644 --- a/app/src/modules/builder/geomentries/floors/addFloorToScene.ts +++ b/app/src/modules/builder/geomentries/floors/addFloorToScene.ts @@ -26,7 +26,6 @@ export default function addFloorToScene( if (materialCache.has(materialKey)) { material = materialCache.get(materialKey) as THREE.Material; - // } else { } else { const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath); // const floorTexture = textureLoader.load(texturePath); diff --git a/app/src/modules/builder/geomentries/walls/addWallItems.ts b/app/src/modules/builder/geomentries/walls/addWallItems.ts index fd9eb48..8b472ec 100644 --- a/app/src/modules/builder/geomentries/walls/addWallItems.ts +++ b/app/src/modules/builder/geomentries/walls/addWallItems.ts @@ -35,7 +35,7 @@ async function AddWallItems( }); const config = AssetConfigurations[selected]; - let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY; + let positionY = config.type === 'Fixed-Move' ? 0 : intersectionPoint.point.y; if (positionY === 0) { positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height; } diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 206d00d..e58530b 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -11,7 +11,6 @@ import { useSelectedItem, useSocketStore, useToggleView, - useTransformMode, } from "../../../store/store"; import { useEffect } from "react"; import * as THREE from "three"; @@ -59,7 +58,6 @@ const FloorItemsGroup = ({ const { camMode } = useCamMode(); const { deleteTool } = useDeleteTool(); const { setDeletableFloorItem } = useDeletableFloorItem(); - const { transformMode } = useTransformMode(); const { setSelectedFloorItem } = useSelectedFloorItem(); const { activeTool } = useActiveTool(); const { selectedItem, setSelectedItem } = useSelectedItem(); @@ -257,9 +255,8 @@ const FloorItemsGroup = ({ socket ); } - const Mode = transformMode; - if (Mode !== null || activeTool === "cursor") { + if (activeTool === "cursor") { if (!itemsGroup.current) return; let intersects = raycaster.intersectObjects( itemsGroup.current.children, @@ -296,9 +293,8 @@ const FloorItemsGroup = ({ isLeftMouseDown = false; if (drag) return; - const Mode = transformMode; - if (Mode !== null || activeTool === "cursor") { + if (activeTool === "cursor") { if (!itemsGroup.current) return; let intersects = raycaster.intersectObjects( itemsGroup.current.children, @@ -412,16 +408,7 @@ const FloorItemsGroup = ({ canvasElement.removeEventListener("drop", onDrop); canvasElement.removeEventListener("dragover", onDragOver); }; - }, [ - deleteTool, - transformMode, - controls, - selectedItem, - state.camera, - state.pointer, - activeTool, - activeModule, - ]); + }, [deleteTool, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule,]); useFrame(() => { if (controls) diff --git a/app/src/modules/builder/groups/wallItemsGroup.tsx b/app/src/modules/builder/groups/wallItemsGroup.tsx index 76ba502..faae06d 100644 --- a/app/src/modules/builder/groups/wallItemsGroup.tsx +++ b/app/src/modules/builder/groups/wallItemsGroup.tsx @@ -1,12 +1,12 @@ import { useEffect } from "react"; import { - useDeleteTool, - useDeletePointOrLine, - useObjectPosition, - useObjectRotation, - useSelectedWallItem, - useSocketStore, - useWallItems, + useDeleteTool, + useDeletePointOrLine, + useObjectPosition, + useObjectRotation, + useSelectedWallItem, + useSocketStore, + useWallItems, } from "../../../store/store"; import { Csg } from "../csg/csg"; import * as Types from "../../../types/world/worldTypes"; @@ -20,276 +20,276 @@ import AddWallItems from "../geomentries/walls/addWallItems"; import useModuleStore from "../../../store/useModuleStore"; const WallItemsGroup = ({ - currentWallItem, - AssetConfigurations, - hoveredDeletableWallItem, - selectedItemsIndex, - setSelectedItemsIndex, - CSGGroup, + currentWallItem, + AssetConfigurations, + hoveredDeletableWallItem, + selectedItemsIndex, + setSelectedItemsIndex, + CSGGroup, }: any) => { - const state = useThree(); - const { socket } = useSocketStore(); - const { pointer, camera, raycaster } = state; - const { deleteTool } = useDeleteTool(); - const { wallItems, setWallItems } = useWallItems(); - const { setObjectPosition } = useObjectPosition(); - const { setObjectRotation } = useObjectRotation(); - const { deletePointOrLine } = useDeletePointOrLine(); - const { setSelectedWallItem } = useSelectedWallItem(); - const { activeModule } = useModuleStore(); + const state = useThree(); + const { socket } = useSocketStore(); + const { pointer, camera, raycaster } = state; + const { deleteTool } = useDeleteTool(); + const { wallItems, setWallItems } = useWallItems(); + const { setObjectPosition } = useObjectPosition(); + const { setObjectRotation } = useObjectRotation(); + const { deletePointOrLine } = useDeletePointOrLine(); + const { setSelectedWallItem } = useSelectedWallItem(); + const { activeModule } = useModuleStore(); - useEffect(() => { - // Load Wall Items from the backend - loadInitialWallItems(setWallItems, AssetConfigurations); - }, []); + useEffect(() => { + // Load Wall Items from the backend + loadInitialWallItems(setWallItems, AssetConfigurations); + }, []); - ////////// Update the Scale value changes in thewallItems State ////////// + ////////// Update the Scale value changes in thewallItems State ////////// - ////////// Update the Position value changes in the selected item ////////// + ////////// Update the Position value changes in the selected item ////////// - ////////// Update the Rotation value changes in the selected item ////////// + ////////// Update the Rotation value changes in the selected item ////////// - useEffect(() => { - const canvasElement = state.gl.domElement; - function handlePointerMove(e: any) { - if ( - selectedItemsIndex !== null && - !deletePointOrLine && - 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 && + !deletePointOrLine && + 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), + }); + }); + + updatedItems[selectedItemsIndex] = { + ...updatedItems[selectedItemsIndex], + position: position, + quaternion: + Object!.object.quaternion.clone() as Types.QuaternionType, + }; + + return updatedItems; + }); + } } - - 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, - }; - - 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, - }; - }); - - currentItem = updatedItems[selectedItemsIndex]; - localStorage.setItem( - "WallItems", - JSON.stringify(WallItemsForStorage) + async function handlePointerUp() { + const Raycaster = state.raycaster; + const intersects = Raycaster.intersectObjects( + CSGGroup.current?.children[0].children!, + true ); - return updatedItems; - }); + 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, + }; + }); - setTimeout(async () => { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; + currentItem = updatedItems[selectedItemsIndex]; + localStorage.setItem( + "WallItems", + JSON.stringify(WallItemsForStorage) + ); + return updatedItems; + }); - //REST + setTimeout(async () => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - // await setWallItem( - // organization, - // currentItem?.model?.uuid, - // currentItem.modelName, - // currentItem.type!, - // currentItem.csgposition!, - // currentItem.csgscale!, - // currentItem.position, - // currentItem.quaternion, - // currentItem.scale!, - // ) + //REST - //SOCKET + // await setWallItem( + // organization, + // currentItem?.model?.uuid, + // currentItem.modelName, + // currentItem.type!, + // currentItem.csgposition!, + // currentItem.csgscale!, + // currentItem.position, + // currentItem.quaternion, + // currentItem.scale!, + // ) - const data = { - organization: organization, - modelUuid: currentItem.model?.uuid!, - modelName: currentItem.modelName!, - type: currentItem.type!, - csgposition: currentItem.csgposition!, - csgscale: currentItem.csgscale!, - position: currentItem.position!, - quaternion: currentItem.quaternion, - scale: currentItem.scale!, - socketId: socket.id, - }; + //SOCKET - socket.emit("v1:wallItems:set", data); - }, 0); - (state.controls as any)!.enabled = true; + const data = { + organization: organization, + modelUuid: currentItem.model?.uuid!, + modelName: currentItem.modelName!, + type: currentItem.type!, + csgposition: currentItem.csgposition!, + csgscale: currentItem.csgscale!, + position: currentItem.position!, + quaternion: currentItem.quaternion, + scale: currentItem.scale!, + socketId: socket.id, + }; + + 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]); + return () => { + canvasElement.removeEventListener("pointermove", handlePointerMove); + canvasElement.removeEventListener("pointerup", handlePointerUp); + }; + }, [selectedItemsIndex]); - 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 && deleteTool && activeModule === "builder") { - DeleteWallItems( - hoveredDeletableWallItem, - setWallItems, - wallItems, - socket - ); + const onMouseUp = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown = false; + if (!drag && deleteTool && activeModule === "builder") { + DeleteWallItems( + hoveredDeletableWallItem, + setWallItems, + wallItems, + socket + ); + } + } + }; + + const onMouseMove = () => { + if (isLeftMouseDown) { + drag = true; + } + }; + + const onDrop = (event: any) => { + if (!event.dataTransfer?.files[0]) return; + + pointer.x = (event.clientX / window.innerWidth) * 2 - 1; + pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; + raycaster.setFromCamera(pointer, camera); + + if (AssetConfigurations[event.dataTransfer.files[0].name.split(".")[0]]) { + const selected = event.dataTransfer.files[0].name.split(".")[0]; + + if (AssetConfigurations[selected]?.type) { + AddWallItems( + selected, + raycaster, + CSGGroup, + AssetConfigurations, + setWallItems, + socket + ); + } + 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); + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("drop", onDrop); + canvasElement.removeEventListener("dragover", onDragOver); + }; + }, [deleteTool, wallItems]); + + useEffect(() => { + if (deleteTool && activeModule === "builder") { + handleMeshMissed( + currentWallItem, + setSelectedWallItem, + setSelectedItemsIndex + ); + setSelectedWallItem(null); + setSelectedItemsIndex(null); } - } - }; + }, [deleteTool]); - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - }; - - const onDrop = (event: any) => { - if (!event.dataTransfer?.files[0]) return; - - pointer.x = (event.clientX / window.innerWidth) * 2 - 1; - pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; - raycaster.setFromCamera(pointer, camera); - - if (AssetConfigurations[event.dataTransfer.files[0].name.split(".")[0]]) { - const selected = event.dataTransfer.files[0].name.split(".")[0]; - - if (AssetConfigurations[selected]?.type) { - AddWallItems( - selected, - raycaster, - CSGGroup, - AssetConfigurations, - setWallItems, - socket - ); - } - 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); - - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("drop", onDrop); - canvasElement.removeEventListener("dragover", onDragOver); - }; - }, [deleteTool, wallItems]); - - useEffect(() => { - if (deleteTool && activeModule === "builder") { - handleMeshMissed( - currentWallItem, - setSelectedWallItem, - setSelectedItemsIndex - ); - setSelectedWallItem(null); - setSelectedItemsIndex(null); - } - }, [deleteTool]); - - return ( - <> - {wallItems.map((item: Types.WallItem, index: number) => ( - - - - ))} - - ); + return ( + <> + {wallItems.map((item: Types.WallItem, index: number) => ( + + + + ))} + + ); }; export default WallItemsGroup; diff --git a/app/src/modules/builder/groups/wallsAndWallItems.tsx b/app/src/modules/builder/groups/wallsAndWallItems.tsx index 455896e..19d5833 100644 --- a/app/src/modules/builder/groups/wallsAndWallItems.tsx +++ b/app/src/modules/builder/groups/wallsAndWallItems.tsx @@ -1,11 +1,10 @@ import { Geometry } from "@react-three/csg"; import { - useDeleteTool, - useSelectedWallItem, - useToggleView, - useTransformMode, - useWallItems, - useWalls, + useDeleteTool, + useSelectedWallItem, + useToggleView, + useWallItems, + useWalls, } from "../../../store/store"; import handleMeshDown from "../eventFunctions/handleMeshDown"; import handleMeshMissed from "../eventFunctions/handleMeshMissed"; @@ -14,79 +13,65 @@ import WallItemsGroup from "./wallItemsGroup"; import { useEffect } from "react"; const WallsAndWallItems = ({ - CSGGroup, - AssetConfigurations, - setSelectedItemsIndex, - selectedItemsIndex, - currentWallItem, - csg, - lines, - hoveredDeletableWallItem, + CSGGroup, + AssetConfigurations, + setSelectedItemsIndex, + selectedItemsIndex, + currentWallItem, + csg, + lines, + hoveredDeletableWallItem, }: any) => { - const { walls } = useWalls(); - const { wallItems } = useWallItems(); - const { toggleView } = useToggleView(); - const { deleteTool } = useDeleteTool(); - const { transformMode } = useTransformMode(); - const { setSelectedWallItem } = useSelectedWallItem(); + const { walls } = useWalls(); + const { wallItems } = useWallItems(); + const { toggleView } = useToggleView(); + const { deleteTool } = useDeleteTool(); + const { setSelectedWallItem } = useSelectedWallItem(); - useEffect(() => { - if (transformMode === null) { - if (!deleteTool) { - handleMeshMissed( - currentWallItem, - setSelectedWallItem, - setSelectedItemsIndex - ); - setSelectedWallItem(null); - setSelectedItemsIndex(null); - } - } - }, [transformMode]); - return ( - { - if (!deleteTool && transformMode !== null) { - handleMeshDown( - event, - currentWallItem, - setSelectedWallItem, - setSelectedItemsIndex, - wallItems, - toggleView - ); - } - }} - onPointerMissed={() => { - if (!deleteTool) { - handleMeshMissed( - currentWallItem, - setSelectedWallItem, - setSelectedItemsIndex - ); - setSelectedWallItem(null); - setSelectedItemsIndex(null); - } - }} - > - - - - - - ); + return ( + { + if (!deleteTool) { + handleMeshDown( + event, + currentWallItem, + setSelectedWallItem, + setSelectedItemsIndex, + wallItems, + toggleView + ); + } + }} + onPointerMissed={() => { + if (!deleteTool) { + handleMeshMissed( + currentWallItem, + setSelectedWallItem, + setSelectedItemsIndex + ); + setSelectedWallItem(null); + setSelectedItemsIndex(null); + } + }} + > + + + + + + ); }; export default WallsAndWallItems; diff --git a/app/src/modules/builder/groups/wallsMesh.tsx b/app/src/modules/builder/groups/wallsMesh.tsx index 4f71680..9abf59d 100644 --- a/app/src/modules/builder/groups/wallsMesh.tsx +++ b/app/src/modules/builder/groups/wallsMesh.tsx @@ -15,63 +15,63 @@ import texturePath from "../../../assets/textures/floor/wall-tex.png"; const materialCache = new Map(); const WallsMeshComponent = ({ lines }: any) => { - const { walls, setWalls } = useWalls(); - const { updateScene, setUpdateScene } = useUpdateScene(); + const { walls, setWalls } = useWalls(); + const { updateScene, setUpdateScene } = useUpdateScene(); - useEffect(() => { - if (updateScene) { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; + useEffect(() => { + if (updateScene) { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - getLines(organization).then((data) => { - const Lines: Types.Lines = objectLinesToArray(data); - localStorage.setItem("Lines", JSON.stringify(Lines)); + getLines(organization).then((data) => { + const Lines: Types.Lines = objectLinesToArray(data); + localStorage.setItem("Lines", JSON.stringify(Lines)); - if (Lines) { - loadWalls(lines, setWalls); + if (Lines) { + loadWalls(lines, setWalls); + } + }); + setUpdateScene(false); } - }); - setUpdateScene(false); - } - }, [updateScene]); + }, [updateScene]); - 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); diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx index 8bdd3aa..1420d89 100644 --- a/app/src/modules/scene/controls/controls.tsx +++ b/app/src/modules/scene/controls/controls.tsx @@ -10,6 +10,7 @@ import updateCamPosition from "../camera/updateCameraPosition"; import CamMode from "../camera/camMode"; import SwitchView from "../camera/switchView"; import SelectionControls from "./selectionControls/selectionControls"; +import TransformControl from "./transformControls/transformControls"; export default function Controls() { const controlsRef = useRef(null); @@ -138,6 +139,8 @@ export default function Controls() { + + ); } \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx b/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx index 25e6c96..1cfe244 100644 --- a/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx @@ -1,270 +1,270 @@ import React, { useRef } 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 DistanceFindingControls = ({ - boundingBoxRef, - object, + boundingBoxRef, + object, }: DistanceFindingControlsProps) => { - const { camera, scene } = useThree(); + const { camera, scene } = useThree(); - // 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 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); + // 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(), - }); + // 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; + useFrame(() => { + if (!boundingBoxRef?.current) return; - boundingBoxRef.current.geometry.computeBoundingBox(); - const bbox = boundingBoxRef.current.geometry.boundingBox; + boundingBoxRef.current.geometry.computeBoundingBox(); + const bbox = boundingBoxRef.current.geometry.boundingBox; - if (!bbox) return; + 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 size = { + x: bbox.max.x - bbox.min.x, + y: bbox.max.y - bbox.min.y, + z: bbox.max.z - bbox.min.z, + }; + + const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone(); + + 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, + }); + updateLine({ + line: line2.current, + geometry: lineGeometries.current.negX, + direction: new Vector3(-1, 0, 0), // Negative X + angle: "neg", + mesh: textNegX, + vec, + size, + }); + 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 points = []; + + 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 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; + + // Find intersection points + const wallsGroup = scene.children.find((val) => + val?.name.includes("Walls") + ); + 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; + } + } + } + + // Update line geometry + if (points[1]) { + geometry.dispose(); + geometry.setFromPoints([points[0], points[1]]); + line.geometry = geometry; + + // 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 = `${points[0].distanceTo(points[1]).toFixed(2)}m`; + } + } + } 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 = ""; + } }; - const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone(); + const Material = new LineBasicMaterial({ color: "#d2baff" }); - 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, - }); - updateLine({ - line: line2.current, - geometry: lineGeometries.current.negX, - direction: new Vector3(-1, 0, 0), // Negative X - angle: "neg", - mesh: textNegX, - vec, - size, - }); - 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 points = []; - - 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 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; - - // Find intersection points - const wallsGroup = scene.children.find((val) => - val?.name.includes("Walls") - ); - 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; - } - } - } - - // Update line geometry - if (points[1]) { - geometry.dispose(); - geometry.setFromPoints([points[0], points[1]]); - line.geometry = geometry; - - // 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 = `${points[0].distanceTo(points[1]).toFixed(2)}m`; - } - } - } 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 = ""; - } - }; - - const Material = new LineBasicMaterial({ color: "#d2baff" }); - - return ( - <> - {/* Measurement text labels */} - {boundingBoxRef.current && object > 0 && ( + return ( <> - - -
- -
- - -
- -
- - -
- -
- - -
- -
+ {/* Measurement text labels */} + {boundingBoxRef.current && object > 0 && ( + <> + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
- {/* Measurement lines */} - - - - + {/* Measurement lines */} + + + + + + )} - )} - - ); + ); }; export default DistanceFindingControls; diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index 498056a..5398fe6 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -2,10 +2,10 @@ import * as THREE from "three"; import { useEffect, useMemo, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { - useFloorItems, - useSelectedAssets, - useSocketStore, - useToggleView, + useFloorItems, + useSelectedAssets, + useSocketStore, + useToggleView, } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; @@ -19,370 +19,337 @@ import { snapControls } from "../../../../utils/handleSnap"; import DistanceFindingControls from "./distanceFindingControls"; function MoveControls({ - movedObjects, - setMovedObjects, - itemsGroupRef, - copiedObjects, - setCopiedObjects, - pastedObjects, - setpastedObjects, - duplicatedObjects, - setDuplicatedObjects, - selectionGroup, - rotatedObjects, - setRotatedObjects, - boundingBoxRef, -}: any) { - const { camera, controls, gl, scene, pointer, raycaster } = useThree(); - const plane = useMemo( - () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), - [] - ); - - const { toggleView } = useToggleView(); - const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { selectedProduct } = useSelectedProduct(); - const { floorItems, setFloorItems } = useFloorItems(); - const { socket } = useSocketStore(); - const itemsData = useRef([]); - const [keyEvent, setKeyEvent] = useState< - "Ctrl" | "Shift" | "Ctrl+Shift" | "" - >(""); - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; - - const updateBackend = ( - productName: string, - productId: string, - organization: string, - eventData: EventsSchema - ) => { - upsertProductOrEventApi({ - productName: productName, - productId: productId, - organization: organization, - eventDatas: eventData, - }); - }; - - useEffect(() => { - if (!camera || !scene || toggleView || !itemsGroupRef.current) return; - - const canvasElement = gl.domElement; - canvasElement.tabIndex = 0; - - let isMoving = false; - - const onPointerDown = () => { - isMoving = false; - }; - - const onPointerMove = () => { - isMoving = true; - }; - const onKeyUp = (event: KeyboardEvent) => { - // When any modifier is released, reset snap - const isModifierKey = event.key === "Control" || event.key === "Shift"; - - if (isModifierKey) { - setKeyEvent(""); - } - }; - - const onPointerUp = (event: PointerEvent) => { - if (!isMoving && movedObjects.length > 0 && event.button === 0) { - event.preventDefault(); - placeMovedAssets(); - } - if (!isMoving && movedObjects.length > 0 && event.button === 2) { - event.preventDefault(); - - clearSelection(); - movedObjects.forEach((asset: any) => { - if (itemsGroupRef.current) { - itemsGroupRef.current.attach(asset); - } - }); - - setFloorItems([...floorItems, ...itemsData.current]); - - setMovedObjects([]); - itemsData.current = []; - } - setKeyEvent(""); - }; - - const onKeyDown = (event: KeyboardEvent) => { - const keyCombination = detectModifierKeys(event); - - if ( - pastedObjects.length > 0 || - duplicatedObjects.length > 0 || - rotatedObjects.length > 0 - ) - return; - - if ( - keyCombination === "Ctrl" || - keyCombination === "Ctrl+Shift" || - keyCombination === "Shift" - ) { - // update state here - setKeyEvent(keyCombination); - } else { - setKeyEvent(""); - } - - if (keyCombination === "G") { - if (selectedAssets.length > 0) { - moveAssets(); - itemsData.current = floorItems.filter((item: { modelUuid: string }) => - selectedAssets.some((asset: any) => asset.uuid === item.modelUuid) - ); - } - } - - if (keyCombination === "ESCAPE") { - event.preventDefault(); - - clearSelection(); - movedObjects.forEach((asset: any) => { - if (itemsGroupRef.current) { - itemsGroupRef.current.attach(asset); - } - }); - - setFloorItems([...floorItems, ...itemsData.current]); - - setMovedObjects([]); - itemsData.current = []; - } - }; - - if (!toggleView) { - canvasElement.addEventListener("pointerdown", onPointerDown); - canvasElement.addEventListener("pointermove", onPointerMove); - canvasElement.addEventListener("pointerup", onPointerUp); - canvasElement.addEventListener("keydown", onKeyDown); - canvasElement?.addEventListener("keyup", onKeyUp); - } - - return () => { - canvasElement.removeEventListener("pointerdown", onPointerDown); - canvasElement.removeEventListener("pointermove", onPointerMove); - canvasElement.removeEventListener("pointerup", onPointerUp); - canvasElement.removeEventListener("keydown", onKeyDown); - canvasElement?.removeEventListener("keyup", onKeyUp); - }; - }, [ - camera, - controls, - scene, - toggleView, - selectedAssets, - socket, - floorItems, - pastedObjects, - duplicatedObjects, movedObjects, + setMovedObjects, + itemsGroupRef, + pastedObjects, + setpastedObjects, + duplicatedObjects, + setDuplicatedObjects, + selectionGroup, rotatedObjects, - keyEvent, - ]); + setRotatedObjects, + boundingBoxRef, +}: any) { + const { camera, controls, gl, scene, pointer, raycaster } = useThree(); + const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); - let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25; + const { toggleView } = useToggleView(); + const { selectedAssets, setSelectedAssets } = useSelectedAssets(); + const { selectedProduct } = useSelectedProduct(); + const { floorItems, setFloorItems } = useFloorItems(); + const { socket } = useSocketStore(); + const itemsData = useRef([]); + const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">(""); + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - useFrame(() => { - if (movedObjects.length > 0) { - const intersectionPoint = new THREE.Vector3(); - raycaster.setFromCamera(pointer, camera); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData, + }); + }; - if (point) { - let targetX = point.x; - let targetZ = point.z; - if (keyEvent === "Ctrl") { - targetX = snapControls(targetX, "Ctrl"); - targetZ = snapControls(targetZ, "Ctrl"); - } - // else if (keyEvent === "Ctrl+Shift") { - // targetX = snapControls(targetX, "Ctrl+Shift"); - // targetZ = snapControls(targetZ, "Ctrl+Shift"); - // } else if (keyEvent === "Shift") { - // targetX = snapControls(targetX, "Shift"); - // targetZ = snapControls(targetZ, "Shift"); - // } else { - // } + useEffect(() => { + if (!camera || !scene || toggleView || !itemsGroupRef.current) return; - const position = new THREE.Vector3(); + const canvasElement = gl.domElement; + canvasElement.tabIndex = 0; - if (boundingBoxRef.current) { - boundingBoxRef.current.getWorldPosition(position); - selectionGroup.current.position.lerp( - new THREE.Vector3( - targetX - (position.x - selectionGroup.current.position.x), - selectionGroup.current.position.y, - targetZ - (position.z - selectionGroup.current.position.z) - ), - moveSpeed - ); - } else { - const box = new THREE.Box3(); - movedObjects.forEach((obj: THREE.Object3D) => - box.expandByObject(obj) - ); - const center = new THREE.Vector3(); - box.getCenter(center); + let isMoving = false; - selectionGroup.current.position.lerp( - new THREE.Vector3( - targetX - (center.x - selectionGroup.current.position.x), - selectionGroup.current.position.y, - targetZ - (center.z - selectionGroup.current.position.z) - ), - moveSpeed - ); - } - } - } - }); - - const moveAssets = () => { - const updatedItems = floorItems.filter( - (item: { modelUuid: string }) => - !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid) - ); - setFloorItems(updatedItems); - setMovedObjects(selectedAssets); - selectedAssets.forEach((asset: any) => { - selectionGroup.current.attach(asset); - }); - }; - - const placeMovedAssets = () => { - if (movedObjects.length === 0) return; - - movedObjects.forEach(async (obj: THREE.Object3D) => { - const worldPosition = new THREE.Vector3(); - obj.getWorldPosition(worldPosition); - - selectionGroup.current.remove(obj); - obj.position.copy(worldPosition); - - if (itemsGroupRef.current) { - const newFloorItem: Types.FloorItemType = { - modelUuid: obj.uuid, - modelName: obj.userData.name, - modelfileID: obj.userData.modelId, - position: [worldPosition.x, worldPosition.y, worldPosition.z], - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, - isLocked: false, - isVisible: true, + const onPointerDown = () => { + isMoving = false; }; - if (obj.userData.eventData) { - const eventData = useEventsStore - .getState() - .getEventByModelUuid(obj.userData.modelUuid); - const productData = useProductStore - .getState() - .getEventByModelUuid( - useSelectedProduct.getState().selectedProduct.productId, - obj.userData.modelUuid - ); + const onPointerMove = () => { + isMoving = true; + }; - if (eventData) { - useEventsStore.getState().updateEvent(obj.userData.modelUuid, { - position: [worldPosition.x, worldPosition.y, worldPosition.z], - rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], - }); - } - if (productData) { - const event = useProductStore - .getState() - .updateEvent( - useSelectedProduct.getState().selectedProduct.productId, - obj.userData.modelUuid, - { - position: [worldPosition.x, worldPosition.y, worldPosition.z], - rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], - } - ); + const onKeyUp = (event: KeyboardEvent) => { + const isModifierKey = event.key === "Control" || event.key === "Shift"; - if (event) { - updateBackend( - selectedProduct.productName, - selectedProduct.productId, - organization, - event - ); + if (isModifierKey) { + setKeyEvent(""); + } + }; + + const onPointerUp = (event: PointerEvent) => { + if (!isMoving && movedObjects.length > 0 && event.button === 0) { + event.preventDefault(); + placeMovedAssets(); + } + if (!isMoving && movedObjects.length > 0 && event.button === 2) { + event.preventDefault(); + + clearSelection(); + movedObjects.forEach((asset: any) => { + if (itemsGroupRef.current) { + itemsGroupRef.current.attach(asset); + } + }); + + setFloorItems([...floorItems, ...itemsData.current]); + + setMovedObjects([]); + itemsData.current = []; + } + setKeyEvent(""); + }; + + const onKeyDown = (event: KeyboardEvent) => { + const keyCombination = detectModifierKeys(event); + + if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) + return; + + if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") { + setKeyEvent(keyCombination); + } else { + setKeyEvent(""); } - newFloorItem.eventData = eventData; - } - } + if (keyCombination === "G") { + if (selectedAssets.length > 0) { + moveAssets(); + itemsData.current = floorItems.filter((item: { modelUuid: string }) => + selectedAssets.some((asset: any) => asset.uuid === item.modelUuid) + ); + } + } - setFloorItems((prevItems: Types.FloorItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); + if (keyCombination === "ESCAPE") { + event.preventDefault(); - //REST + clearSelection(); + movedObjects.forEach((asset: any) => { + if (itemsGroupRef.current) { + itemsGroupRef.current.attach(asset); + } + }); - // await setFloorItemApi( - // organization, - // obj.uuid, - // obj.userData.name, - // [worldPosition.x, worldPosition.y, worldPosition.z], - // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, - // obj.userData.modelId, - // false, - // true, - // ); + setFloorItems([...floorItems, ...itemsData.current]); - //SOCKET - - const data = { - organization, - modelUuid: newFloorItem.modelUuid, - modelName: newFloorItem.modelName, - modelfileID: newFloorItem.modelfileID, - position: newFloorItem.position, - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, - isLocked: false, - isVisible: true, - socketId: socket.id, + setMovedObjects([]); + itemsData.current = []; + } }; - socket.emit("v2:model-asset:add", data); + if (!toggleView) { + canvasElement.addEventListener("pointerdown", onPointerDown); + canvasElement.addEventListener("pointermove", onPointerMove); + canvasElement.addEventListener("pointerup", onPointerUp); + canvasElement.addEventListener("keydown", onKeyDown); + canvasElement?.addEventListener("keyup", onKeyUp); + } - itemsGroupRef.current.add(obj); - } + return () => { + canvasElement.removeEventListener("pointerdown", onPointerDown); + canvasElement.removeEventListener("pointermove", onPointerMove); + canvasElement.removeEventListener("pointerup", onPointerUp); + canvasElement.removeEventListener("keydown", onKeyDown); + canvasElement?.removeEventListener("keyup", onKeyUp); + }; + }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent,]); + + let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25; + + useFrame(() => { + if (movedObjects.length > 0) { + const intersectionPoint = new THREE.Vector3(); + raycaster.setFromCamera(pointer, camera); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + + if (point) { + let targetX = point.x; + let targetZ = point.z; + + if (keyEvent === "Ctrl") { + targetX = snapControls(targetX, "Ctrl"); + targetZ = snapControls(targetZ, "Ctrl"); + } + + // else if (keyEvent === "Ctrl+Shift") { + // targetX = snapControls(targetX, "Ctrl+Shift"); + // targetZ = snapControls(targetZ, "Ctrl+Shift"); + // } else if (keyEvent === "Shift") { + // targetX = snapControls(targetX, "Shift"); + // targetZ = snapControls(targetZ, "Shift"); + // } else { + // } + + const position = new THREE.Vector3(); + + if (boundingBoxRef.current) { + boundingBoxRef.current.getWorldPosition(position); + selectionGroup.current.position.lerp( + new THREE.Vector3( + targetX - (position.x - selectionGroup.current.position.x), + selectionGroup.current.position.y, + targetZ - (position.z - selectionGroup.current.position.z) + ), + moveSpeed + ); + } else { + const box = new THREE.Box3(); + movedObjects.forEach((obj: THREE.Object3D) => + box.expandByObject(obj) + ); + const center = new THREE.Vector3(); + box.getCenter(center); + + selectionGroup.current.position.lerp( + new THREE.Vector3( + targetX - (center.x - selectionGroup.current.position.x), + selectionGroup.current.position.y, + targetZ - (center.z - selectionGroup.current.position.z) + ), + moveSpeed + ); + } + } + } }); - toast.success("Object moved!"); - itemsData.current = []; - clearSelection(); - }; + const moveAssets = () => { + const updatedItems = floorItems.filter( + (item: { modelUuid: string }) => + !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid) + ); + setFloorItems(updatedItems); + setMovedObjects(selectedAssets); + selectedAssets.forEach((asset: any) => { + selectionGroup.current.attach(asset); + }); + }; - const clearSelection = () => { - selectionGroup.current.children = []; - selectionGroup.current.position.set(0, 0, 0); - selectionGroup.current.rotation.set(0, 0, 0); - setpastedObjects([]); - setDuplicatedObjects([]); - setMovedObjects([]); - setRotatedObjects([]); - setSelectedAssets([]); - setKeyEvent(""); - }; + const placeMovedAssets = () => { + if (movedObjects.length === 0) return; - return ( - - ); + movedObjects.forEach(async (obj: THREE.Object3D) => { + const worldPosition = new THREE.Vector3(); + obj.getWorldPosition(worldPosition); + + selectionGroup.current.remove(obj); + obj.position.copy(worldPosition); + + if (itemsGroupRef.current) { + const newFloorItem: Types.FloorItemType = { + modelUuid: obj.uuid, + modelName: obj.userData.name, + modelfileID: obj.userData.modelId, + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + }; + + if (obj.userData.eventData) { + const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(selectedProduct.productId, obj.userData.modelUuid); + + if (eventData) { + useEventsStore.getState().updateEvent(obj.userData.modelUuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + }); + } + + if (productData) { + const event = useProductStore + .getState() + .updateEvent( + selectedProduct.productId, + obj.userData.modelUuid, + { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + } + ); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + + newFloorItem.eventData = eventData; + } + } + + setFloorItems((prevItems: Types.FloorItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + //REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // obj.userData.modelId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + }; + + socket.emit("v2:model-asset:add", data); + + itemsGroupRef.current.add(obj); + } + }); + toast.success("Object moved!"); + + itemsData.current = []; + clearSelection(); + }; + + const clearSelection = () => { + selectionGroup.current.children = []; + selectionGroup.current.position.set(0, 0, 0); + selectionGroup.current.rotation.set(0, 0, 0); + setpastedObjects([]); + setDuplicatedObjects([]); + setMovedObjects([]); + setRotatedObjects([]); + setSelectedAssets([]); + setKeyEvent(""); + }; + + return ( + + ); } export default MoveControls; diff --git a/app/src/modules/scene/controls/transformControls/transformControls.tsx b/app/src/modules/scene/controls/transformControls/transformControls.tsx new file mode 100644 index 0000000..5311f4f --- /dev/null +++ b/app/src/modules/scene/controls/transformControls/transformControls.tsx @@ -0,0 +1,206 @@ +import { TransformControls } from "@react-three/drei"; +import * as THREE from "three"; +import { useSelectedFloorItem, useObjectPosition, useObjectRotation, useFloorItems, useActiveTool, useSocketStore } from "../../../../store/store"; +import { useThree } from "@react-three/fiber"; + +import * as Types from '../../../../types/world/worldTypes'; +import { useEffect, useState } from "react"; +import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; +import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; + +export default function TransformControl() { + const state = useThree(); + const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); + const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { setObjectPosition } = useObjectPosition(); + const { setObjectRotation } = useObjectRotation(); + const { setFloorItems } = useFloorItems(); + const { activeTool } = useActiveTool(); + const { socket } = useSocketStore(); + const { selectedProduct } = useSelectedProduct(); + + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData, + }); + }; + + function handleObjectChange() { + if (selectedFloorItem) { + setObjectPosition(selectedFloorItem.position); + setObjectRotation({ + x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x), + y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y), + z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z), + }); + } + } + + function handleMouseUp() { + if (selectedFloorItem) { + setObjectPosition(selectedFloorItem.position); + setObjectRotation({ + x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x), + y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y), + z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z), + }); + } + setFloorItems((prevItems: Types.FloorItems) => { + if (!prevItems) { + return + } + let updatedItem: any = null; + const updatedItems = prevItems.map((item) => { + if (item.modelUuid === selectedFloorItem?.uuid) { + updatedItem = { + ...item, + position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number], + rotation: { x: selectedFloorItem.rotation.x, y: selectedFloorItem.rotation.y, z: selectedFloorItem.rotation.z }, + }; + return updatedItem; + } + return item; + }); + if (updatedItem && selectedFloorItem) { + if (updatedItem.eventData) { + const eventData = useEventsStore.getState().getEventByModelUuid(updatedItem.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(selectedProduct.productId, updatedItem.modelUuid); + + if (eventData) { + useEventsStore.getState().updateEvent(updatedItem.modelUuid, { + position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z], + rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z], + }); + } + + if (productData) { + const event = useProductStore + .getState() + .updateEvent( + selectedProduct.productId, + updatedItem.modelUuid, + { + position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z], + rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z], + } + ); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + + updatedItem.eventData = eventData; + } + } + + setFloorItems((prevItems: Types.FloorItems) => { + const updatedItems = [...(prevItems || []), updatedItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + // REST + + // setFloorItemApi( + // organization, + // updatedItem.modelUuid, + // updatedItem.modelName, + // updatedItem.modelfileid, + // [selectedFloorItem.position.x, 0, selectedFloorItem.position.z,], + // { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z }, + // false, + // true, + // ); + + // SOCKET + + const data = { + organization: organization, + modelUuid: updatedItem.modelUuid, + modelName: updatedItem.modelName, + modelfileID: updatedItem.modelfileID, + position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z], + rotation: { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id + } + + socket.emit("v2:model-asset:add", data); + } + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + } + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + const keyCombination = detectModifierKeys(e); + if (!selectedFloorItem) return; + if (keyCombination === "G") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (keyCombination === "R") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; + + if (selectedFloorItem) { + window.addEventListener("keydown", handleKeyDown); + } else { + setTransformMode(null); + } + + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [selectedFloorItem]); + + useEffect(() => { + if (activeTool === "delete") { + if (state.controls) { + const target = (state.controls as any).getTarget(new THREE.Vector3()); + (state.controls as any).setTarget(target.x, 0, target.z, true); + } + setSelectedFloorItem(null); + setObjectPosition({ x: undefined, y: undefined, z: undefined }); + setObjectRotation({ x: undefined, y: undefined, z: undefined }); + } + }, [activeTool]); + + return ( + <> + {(selectedFloorItem && transformMode) && + + } + + ); +} diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 61d84d5..a86d289 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -144,11 +144,6 @@ export const useMovePoint = create((set: any) => ({ setMovePoint: (x: any) => set(() => ({ movePoint: x })), })); -export const useTransformMode = create((set: any) => ({ - transformMode: null, - setTransformMode: (x: any) => set(() => ({ transformMode: x })), -})); - export const useDeletePointOrLine = create((set: any) => ({ deletePointOrLine: false, setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index c148038..3d6115a 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -225,7 +225,6 @@ interface AssetConfiguration { scale?: [number, number, number]; csgscale?: [number, number, number]; csgposition?: [number, number, number]; - positionY?: (intersectionPoint: { point: THREE.Vector3 }) => number; type?: "Fixed-Move" | "Free-Move"; }