From 982c92cf26041bf1ff850186e7a107299f73e2eb Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 12:20:53 +0530 Subject: [PATCH 1/6] Add WallAsset, Floor, and Zone interfaces to builderTypes --- app/src/types/builderTypes.d.ts | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index 26dcf65..decde1d 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -10,6 +10,7 @@ interface Version { type VersionHistory = Version[]; + // Asset interface Asset { @@ -45,6 +46,22 @@ interface Asset { type Assets = Asset[]; +// Wall-Asset + +interface WallAsset { + modelUuid: string; + modelName: string; + assetId: string; + wallUuid: string; + position: [number, number, number]; + isLocked: boolean; + isVisible: boolean; + opacity: number; +} + +type WallAssets = WallAsset[]; + + // Point type PointTypes = 'Aisle' | 'Wall' | 'Floor' | 'Zone'; @@ -81,6 +98,35 @@ interface Wall { type Walls = Wall[]; +// Floor + +interface Floor { + floorUuid: string; + points: Point[]; + sideMaterial: string; + topMaterial: string; + floorDepth: number; + isBeveled: boolean; + bevelStrength: number; +} + +type Floors = Floor[]; + + +// Zone + +interface Zone { + zoneUuid: string; + zoneName: string; + zoneColor: string; + points: Point[]; + viewPortTarget: [number, number, number]; + viewPortPosition: [number, number, number]; +} + +type Zones = Zone[]; + + // Aisle type AisleTypes = 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'; From 587ed6c9d7619c91d29b7bfee5b8fad3c7d21d41 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 15:26:53 +0530 Subject: [PATCH 2/6] Refactor builder store and remove wall store Refactor builder store and remove wall store - Consolidated wall-related state management into the builder store by removing the useWallStore. - Added new properties and setters for wall attributes (thickness, height, materials) in the builder store. - Introduced SelectedWallProperties and WallProperties components for managing wall properties in the sidebar. - Created a new floor store for managing floor-related state. - Added a wall asset store for managing wall assets. - Implemented a zone store for managing zones and their properties. - Updated sidebar styles for better layout and appearance. --- .../layout/sidebarRight/SideBarRight.tsx | 26 ++- .../properties/SelectedWallProperties.tsx | 143 ++++++++++++ .../{eventProperties => }/WallProperties.tsx | 78 ++----- app/src/modules/builder/builder.tsx | 2 +- .../modules/builder/groups/floorPlanGroup.tsx | 2 +- app/src/modules/builder/line/line.tsx | 10 +- .../point/helpers/usePointSnapping.tsx | 5 +- app/src/modules/builder/point/point.tsx | 9 +- .../builder/wall/Instances/instance/wall.tsx | 41 +++- .../builder/wall/Instances/wallInstances.tsx | 9 +- .../builder/wall/wallCreator/wallCreator.tsx | 5 +- app/src/modules/builder/wall/wallGroup.tsx | 14 ++ .../scene/postProcessing/postProcessing.tsx | 21 +- app/src/modules/scene/sceneContext.tsx | 24 +- app/src/store/builder/useBuilderStore.ts | 210 +++++++++-------- app/src/store/builder/useFloorStore.ts | 90 ++++++++ app/src/store/builder/useWallAssetStore.ts | 82 +++++++ app/src/store/builder/useWallStore.ts | 211 ++++++++++++++++++ app/src/store/builder/useWallStore.tsx | 200 ----------------- app/src/store/builder/useZoneStore.ts | 74 ++++++ app/src/styles/layout/sidebar.scss | 16 +- 21 files changed, 870 insertions(+), 402 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx rename app/src/components/layout/sidebarRight/properties/{eventProperties => }/WallProperties.tsx (67%) create mode 100644 app/src/store/builder/useFloorStore.ts create mode 100644 app/src/store/builder/useWallAssetStore.ts create mode 100644 app/src/store/builder/useWallStore.ts delete mode 100644 app/src/store/builder/useWallStore.tsx create mode 100644 app/src/store/builder/useZoneStore.ts diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index e7cc3db..d6413bc 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -23,12 +23,14 @@ import { useSelectedEventSphere, } from "../../../store/simulation/useSimulationStore"; import GlobalProperties from "./properties/GlobalProperties"; -import AsstePropertiies from "./properties/AssetProperties"; +import AssetProperties from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; import EventProperties from "./properties/eventProperties/EventProperties"; import VersionHistory from "./versionHisory/VersionHistory"; import AisleProperties from "./properties/AisleProperties"; -import WallProperties from "./properties/eventProperties/WallProperties"; +import WallProperties from "./properties/WallProperties"; +import { useBuilderStore } from "../../../store/builder/useBuilderStore"; +import SelectedWallProperties from "./properties/SelectedWallProperties"; const SideBarRight: React.FC = () => { const { activeModule } = useModuleStore(); @@ -36,6 +38,7 @@ const SideBarRight: React.FC = () => { const { toolMode } = useToolMode(); const { subModule, setSubModule } = useSubModuleStore(); const { selectedFloorItem } = useSelectedFloorItem(); + const { selectedWall } = useBuilderStore(); const { selectedEventData } = useSelectedEventData(); const { selectedEventSphere } = useSelectedEventSphere(); const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore(); @@ -143,7 +146,8 @@ const SideBarRight: React.FC = () => { {!viewVersionHistory && subModule === "properties" && activeModule !== "visualization" && - !selectedFloorItem && ( + !selectedFloorItem && + !selectedWall && (
{(() => { @@ -158,13 +162,26 @@ const SideBarRight: React.FC = () => {
)} + {!viewVersionHistory && subModule === "properties" && activeModule !== "visualization" && selectedFloorItem && (
- + +
+
+ )} + + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && + selectedWall && ( +
+
+
)} @@ -178,6 +195,7 @@ const SideBarRight: React.FC = () => { )} + {/* simulation */} {!isVersionSaved && !viewVersionHistory && diff --git a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx new file mode 100644 index 0000000..b647145 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx @@ -0,0 +1,143 @@ +import { useState } from "react"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; + +import defaultTexture from '../../../../assets/textures/floor/wall-tex.png'; +import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg'; + +import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; +import { useSceneContext } from "../../../../modules/scene/sceneContext"; + +const SelectedWallProperties = () => { + const { selectedWall } = useBuilderStore(); + const { wallStore } = useSceneContext(); + const { getWallById, updateWall } = wallStore(); + + const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1"); + + const materials = [ + { texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" }, + { texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" } + ]; + + const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null; + + const handleHeightChange = (val: string) => { + const height = parseFloat(val); + if (!isNaN(height) && wall) { + updateWall(wall.wallUuid, { wallHeight: height }); + } + }; + + const handleThicknessChange = (val: string) => { + const thickness = parseFloat(val); + if (!isNaN(thickness) && wall) { + updateWall(wall.wallUuid, { wallThickness: thickness }); + } + }; + + const handleSelectMaterial = (material: { textureId: string; textureName: string }) => { + if (!wall) return; + + const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId }) + + updateWall(wall.wallUuid, updated); + }; + + if (!wall) return null; + + const selectedMaterials = { + side1: { + texture: materials.find((material) => material.textureId === wall.insideMaterial)?.texture || 'Unknown', + textureId: materials.find((material) => material.textureId === wall.insideMaterial)?.textureId || 'Unknown', + textureName: materials.find((material) => material.textureId === wall.insideMaterial)?.textureName || 'Unknown' + }, + side2: { + texture: materials.find((material) => material.textureId === wall.outsideMaterial)?.texture || 'Unknown', + textureId: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureId || 'Unknown', + textureName: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureName || 'Unknown' + } + }; + + return ( +
+
+
Wall
+
+ + +
+
+
+
+
Materials
+
+ +
+
+ {(["side1", "side2"] as const).map((side) => ( + + ))} +
+ +
+ {selectedMaterials[activeSide].textureName} +
+
+ +
+
+ {materials.map((material, index) => { + const isSelected = selectedMaterials[activeSide].textureId === material.textureId; + + return ( + + ); + })} +
+
+
+
+ ); +}; + +export default SelectedWallProperties; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx similarity index 67% rename from app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx rename to app/src/components/layout/sidebarRight/properties/WallProperties.tsx index f3cb792..eb835f1 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx @@ -1,11 +1,12 @@ import { useEffect, useState } from "react"; -import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown"; -import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; // Texture Imports -import wallTexture1 from "../../../../../assets/image/wallTextures/wallTexture.png"; -import defaultTexture from "../../../../../assets/image/wallTextures/defaultTexture.jpg"; -import { useBuilderStore } from "../../../../../store/builder/useBuilderStore"; + +import defaultTexture from '../../../../assets/textures/floor/wall-tex.png'; +import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg'; + +import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; // Define Material type type Material = { @@ -58,14 +59,6 @@ const WallProperties = () => { setWallThickness(parseFloat(newValue)); }; - const handleAddMaterial = () => { - const newMaterial: Material = { - texture: defaultMaterial.texture, - textureName: `Material ${materials.length + 1}`, - }; - setMaterials([...materials, newMaterial]); - }; - const handleSelectMaterial = (material: Material) => { setSelectedMaterials((prev) => ({ ...prev, @@ -73,46 +66,26 @@ const WallProperties = () => { })); }; - const handleRemoveMaterial = (index: number) => { - const removedTexture = materials[index].texture; - - const updatedMaterials = materials.filter((_, i) => i !== index); - const newMaterials = updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials; - setMaterials(newMaterials); - - setSelectedMaterials((prev) => { - const updated = { ...prev }; - ["side1", "side2"].forEach((side) => { - if (updated[side as "side1" | "side2"]?.texture === removedTexture) { - updated[side as "side1" | "side2"] = defaultMaterial; - } - }); - return updated; - }); - }; - return (
-
Wall
-
- handleHeightChange(val)} - /> - handleThicknessChange(val)} - /> -
- +
+
Wall
+
+ handleHeightChange(val)} + /> + handleThicknessChange(val)} + /> +
+
Materials
-
@@ -185,15 +158,6 @@ const WallProperties = () => {
{material.textureName}
- ); })} diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index b977781..cbbf2fe 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -276,7 +276,7 @@ export default function Builder() { - {/* */} + ); } diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx index 8f1c2f2..ed3065d 100644 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ b/app/src/modules/builder/groups/floorPlanGroup.tsx @@ -148,7 +148,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin } if (toolMode === "Wall") { - drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); + // drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); } if (toolMode === "Floor") { diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index 68402d9..19f0810 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -1,11 +1,11 @@ import * as THREE from 'three'; +import { useThree } from '@react-three/fiber'; import { useEffect, useMemo, useState } from "react"; -import * as Constants from '../../../types/world/worldConstants'; import { DragControls, Tube } from '@react-three/drei'; import { useToolMode } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; -import { useWallStore } from '../../../store/builder/useWallStore'; -import { useThree } from '@react-three/fiber'; +import { useSceneContext } from '../../scene/sceneContext'; +import * as Constants from '../../../types/world/worldConstants'; interface LineProps { points: [Point, Point]; @@ -17,7 +17,8 @@ function Line({ points }: Readonly) { const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const [isDeletable, setIsDeletable] = useState(false); const { toolMode } = useToolMode(); - const { removeWallByPoints, setPosition } = useWallStore(); + const { wallStore } = useSceneContext(); + const { removeWallByPoints, setPosition } = wallStore(); const [dragOffset, setDragOffset] = useState(null); const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore(); @@ -79,6 +80,7 @@ function Line({ points }: Readonly) { if (toolMode === '2D-Delete') { if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') { removeWallByPoints(points); + setHoveredLine(null); } gl.domElement.style.cursor = 'default'; } diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx index 88c9890..c7d31cc 100644 --- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx +++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx @@ -1,6 +1,5 @@ import * as THREE from 'three'; import { useCallback } from 'react'; -import { useWallStore } from '../../../../store/builder/useWallStore'; import { useSceneContext } from '../../../scene/sceneContext'; const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters @@ -12,9 +11,9 @@ const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping i const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => { - const { aisleStore } = useSceneContext(); + const { aisleStore, wallStore } = useSceneContext(); const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore(); - const { walls, getConnectedPoints: getConnectedWallPoints } = useWallStore(); + const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore(); // Wall Snapping diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index 3545e99..a671806 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -6,7 +6,6 @@ import { DragControls } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { usePointSnapping } from './helpers/usePointSnapping'; -import { useWallStore } from '../../../store/builder/useWallStore'; import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; import { useParams } from 'react-router-dom'; import { createAisleApi } from '../../../services/factoryBuilder/aisle/createAisleApi'; @@ -20,9 +19,9 @@ function Point({ point }: { readonly point: Point }) { const [isHovered, setIsHovered] = useState(false); const [dragOffset, setDragOffset] = useState(null); const { toolMode } = useToolMode(); - const { aisleStore } = useSceneContext(); + const { aisleStore, wallStore } = useSceneContext(); const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); - const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore(); + const { setPosition: setWallPosition, removePoint: removeWallPoint } = wallStore(); const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { selectedVersionStore } = useVersionContext(); @@ -31,6 +30,10 @@ function Point({ point }: { readonly point: Point }) { const boxScale: [number, number, number] = Constants.pointConfig.boxScale; const colors = getColor(point); + useEffect(() => { + gl.domElement.style.cursor = 'default'; + }, [toolMode]) + function getColor(point: Point) { if (point.pointType === 'Aisle') { return { diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 6c2d858..4ada970 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -1,18 +1,25 @@ import * as THREE from 'three'; +import { Base } from '@react-three/csg'; import { useMemo, useRef, useState } from 'react'; -import * as Constants from '../../../../../types/world/worldConstants'; +import { Decal, MeshDiscardMaterial } from '@react-three/drei'; +import { useFrame, useThree } from '@react-three/fiber'; import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png'; import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg'; -import { useWallStore } from '../../../../../store/builder/useWallStore'; + +import useModuleStore from '../../../../../store/useModuleStore'; +import { useSceneContext } from '../../../../scene/sceneContext'; import { useWallClassification } from './helpers/useWallClassification'; -import { useFrame, useThree } from '@react-three/fiber'; -import { useWallVisibility } from '../../../../../store/builder/store'; -import { Decal } from '@react-three/drei'; -import { Base } from '@react-three/csg'; +import { useToggleView, useWallVisibility } from '../../../../../store/builder/store'; +import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; +import * as Constants from '../../../../../types/world/worldConstants'; function Wall({ wall }: { readonly wall: Wall }) { - const { walls } = useWallStore(); + const { wallStore } = useSceneContext(); + const { walls } = wallStore(); + const { togglView } = useToggleView(); + const { setSelectedWall } = useBuilderStore(); + const { activeModule } = useModuleStore(); const { camera } = useThree(); const { wallVisibility } = useWallVisibility(); const { getWallType, isWallFlipped } = useWallClassification(walls); @@ -67,7 +74,7 @@ function Wall({ wall }: { readonly wall: Wall }) { new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, - map: wall.outsideMaterial === 'Default Material`' ? defaultWallTexture : material1WallTexture, + map: wall.outsideMaterial === 'Default Material' ? defaultWallTexture : material1WallTexture, }), ]; }, [defaultWallTexture, material1WallTexture, wall]); @@ -100,6 +107,7 @@ function Wall({ wall }: { readonly wall: Wall }) { geometry={geometry} position={[centerX, centerY, centerZ]} rotation={[0, -angle, 0]} + userData={wall} > {materials.map((material, index) => ( @@ -112,6 +120,7 @@ function Wall({ wall }: { readonly wall: Wall }) { position={[decal.decalPosition[0], decal.decalPosition[1], wall.wallThickness / 2]} rotation={[0, 0, decal.decalRotation]} scale={[decal.decalScale, decal.decalScale, 0.001]} + userData={decal} > + { + if (visible && !togglView && activeModule === 'builder') { + setSelectedWall(e.object) + } + }} + onPointerMissed={() => { setSelectedWall(null) }} + > + + ); } diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx index 37f07e0..b22d0e6 100644 --- a/app/src/modules/builder/wall/Instances/wallInstances.tsx +++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx @@ -2,9 +2,10 @@ import React, { useEffect, useMemo } from 'react'; import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three'; import { Geometry } from '@react-three/csg'; import { Html, Extrude } from '@react-three/drei'; -import { useWallStore } from '../../../../store/builder/useWallStore' -import { useWallClassification } from './instance/helpers/useWallClassification'; +import { useLoader } from '@react-three/fiber'; +import { useSceneContext } from '../../../scene/sceneContext'; import { useToggleView } from '../../../../store/builder/store'; +import { useWallClassification } from './instance/helpers/useWallClassification'; import Line from '../../line/line'; import Point from '../../point/point'; import WallInstance from './instance/wallInstance'; @@ -12,10 +13,10 @@ import * as Constants from '../../../../types/world/worldConstants'; import texturePath from "../../../../assets/textures/floor/white.png"; import texturePathDark from "../../../../assets/textures/floor/black.png"; -import { useLoader } from '@react-three/fiber'; function WallInstances() { - const { walls } = useWallStore(); + const { wallStore } = useSceneContext(); + const { walls } = wallStore(); const { rooms } = useWallClassification(walls) const { toggleView } = useToggleView(); diff --git a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx index 61af916..a136a41 100644 --- a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx +++ b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from 'react' import { useThree } from '@react-three/fiber'; import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; import * as Constants from '../../../../types/world/worldConstants'; -import { useWallStore } from '../../../../store/builder/useWallStore'; +import { useSceneContext } from '../../../scene/sceneContext'; import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceWall from './referenceWall'; @@ -16,7 +16,8 @@ function WallCreator() { const { toolMode } = useToolMode(); const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); - const { addWall, getWallPointById, removeWall, getWallByPoints } = useWallStore(); + const { wallStore } = useSceneContext(); + const { addWall, getWallPointById, removeWall, getWallByPoints } = wallStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); const { wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint } = useBuilderStore(); diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index b3fe3c4..07ef700 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -1,7 +1,21 @@ +import { useEffect } from 'react'; +import { useToggleView } from '../../../store/builder/store' +import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import WallCreator from './wallCreator/wallCreator' import WallInstances from './Instances/wallInstances' +import useModuleStore from '../../../store/useModuleStore'; function WallGroup() { + const { togglView } = useToggleView(); + const { setSelectedWall } = useBuilderStore(); + const { activeModule } = useModuleStore(); + + useEffect(() => { + if (togglView || activeModule !== 'builder') { + setSelectedWall(null); + } + }, [togglView, activeModule]) + return ( <> diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 276f0bf..1b91386 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -15,7 +15,7 @@ export default function PostProcessing() { const { selectedWallItem } = useSelectedWallItem(); const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAisle } = useBuilderStore(); + const { selectedAisle, selectedWall } = useBuilderStore(); function flattenChildren(children: any[]) { const allChildren: any[] = []; @@ -40,6 +40,10 @@ export default function PostProcessing() { // console.log('selectedAisle: ', selectedAisle); }, [selectedAisle]) + useEffect(() => { + // console.log('selectedWall: ', selectedWall); + }, [selectedWall]) + return ( )} + {selectedWall && ( + + )} {deletableFloorItem && ( createAssetStore(), []); + const wallAssetStore = useMemo(() => createWallAssetStore(), []); + const wallStore = useMemo(() => createWallStore(), []); const aisleStore = useMemo(() => createAisleStore(), []); + const zoneStore = useMemo(() => createZoneStore(), []); + const floorStore = useMemo(() => createFloorStore(), []); const eventStore = useMemo(() => createEventStore(), []); const productStore = useMemo(() => createProductStore(), []); @@ -58,7 +70,11 @@ export function SceneProvider({ const clearStores = useMemo(() => () => { assetStore.getState().clearAssets(); + wallAssetStore.getState().clearWallAssets(); + wallStore.getState().clearWalls(); aisleStore.getState().clearAisles(); + zoneStore.getState().clearZones(); + floorStore.getState().clearFloors(); eventStore.getState().clearEvents(); productStore.getState().clearProducts(); materialStore.getState().clearMaterials(); @@ -67,12 +83,16 @@ export function SceneProvider({ conveyorStore.getState().clearConveyors(); vehicleStore.getState().clearVehicles(); storageUnitStore.getState().clearStorageUnits(); - }, [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]); + }, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]); const contextValue = useMemo(() => ( { assetStore, + wallAssetStore, + wallStore, aisleStore, + zoneStore, + floorStore, eventStore, productStore, materialStore, @@ -84,7 +104,7 @@ export function SceneProvider({ clearStores, layout } - ), [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]); + ), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]); return ( diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index 086a020..f59ab54 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -3,74 +3,58 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; interface BuilderState { - // Common properties - + // Point & Line Interaction hoveredPoint: Point | null; snappedPoint: Point | null; snappedPosition: [number, number, number] | null; - hoveredLine: [Point, Point] | null; - // Wall - + // Wall Settings + selectedWall: Object3D | null; wallThickness: number; wallHeight: number; outsideMaterial: string; insideMaterial: string; - setWallThickness: (thickness: number) => void; - setWallHeight: (height: number) => void; - setWallMaterial: (material: string, side: 'inside' | 'outside') => void; - - // Aisle - + // Aisle General selectedAisle: Object3D | null; - aisleType: AisleTypes; aisleWidth: number; aisleColor: AisleColors; - // Dashed aisle properties + // Aisle Specific Styles dashLength: number; gapLength: number; - - // Dotted aisle properties dotRadius: number; - - // Arrows aisle properties aisleLength: number; - - // Junction aisle properties isFlipped: boolean; - // Setters for common properties - + // Setters - Point/Line setHoveredPoint: (point: Point | null) => void; setSnappedPoint: (point: Point | null) => void; setSnappedPosition: (position: [number, number, number] | null) => void; - setHoveredLine: (line: [Point, Point] | null) => void; - setSelectedAisle: (aisle: Object3D | null) => void; + // Setters - Wall + setSelectedWall: (wall: Object3D | null) => void; + setWallThickness: (thickness: number) => void; + setWallHeight: (height: number) => void; + setWallMaterial: (material: string, side: 'inside' | 'outside') => void; + // Setters - Aisle General + setSelectedAisle: (aisle: Object3D | null) => void; setAisleType: (type: AisleTypes) => void; setAisleWidth: (width: number) => void; setAisleColor: (color: AisleColors) => void; - // Setters for dashed aisle + // Setters - Aisle Specific setDashLength: (length: number) => void; setGapLength: (length: number) => void; - - // Setters for dotted aisle setDotRadius: (radius: number) => void; - - // Setters for arrows aisle setAisleLength: (length: number) => void; - - // Setters for junction aisle setIsFlipped: (isFlipped: boolean) => void; - // Batch setters + // Batch Setters setDashedAisleProperties: (width: number, dashLength: number, gapLength: number) => void; setDottedAisleProperties: (width: number, dotRadius: number, gapLength: number) => void; setArrowsAisleProperties: (width: number, aisleLength: number, gapLength: number) => void; @@ -79,20 +63,62 @@ interface BuilderState { export const useBuilderStore = create()( immer((set) => ({ - // Default values - + // === Defaults === hoveredPoint: null, snappedPoint: null, snappedPosition: null, - hoveredLine: null, - // Wall - + selectedWall: null, wallThickness: 0.5, wallHeight: 7, outsideMaterial: 'Default Material', - insideMaterial: 'Default Material', + insideMaterial: 'Material 1', + + selectedAisle: null, + aisleType: 'solid-aisle', + aisleWidth: 0.1, + aisleColor: 'yellow', + + dashLength: 0.5, + gapLength: 0.3, + dotRadius: 0.1, + aisleLength: 0.6, + isFlipped: false, + + // === Setters: Point/Line === + + setHoveredPoint: (point: Point | null) => { + set((state) => { + state.hoveredPoint = point; + }); + }, + + setSnappedPoint: (point: Point | null) => { + set((state) => { + state.snappedPoint = point; + }); + }, + + setSnappedPosition: (position: [number, number, number] | null) => { + set((state) => { + state.snappedPosition = position; + }); + }, + + setHoveredLine: (line: [Point, Point] | null) => { + set((state) => { + state.hoveredLine = line; + }) + }, + + // === Setters: Wall === + + setSelectedWall: (wall: Object3D | null) => { + set((state) => { + state.selectedWall = wall; + }) + }, setWallThickness: (thickness: number) => { set((state) => { @@ -113,44 +139,7 @@ export const useBuilderStore = create()( }); }, - // Aisle - - selectedAisle: null, - - aisleType: 'solid-aisle', - aisleWidth: 0.1, - aisleColor: 'yellow', - dashLength: 0.5, - gapLength: 0.3, - dotRadius: 0.1, - aisleLength: 0.6, - isFlipped: false, - - // Individual setters - - setHoveredPoint: (point: Point | null) => { - set((state) => { - state.hoveredPoint = point; - }); - }, - - setHoveredLine: (line: [Point, Point] | null) => { - set((state) => { - state.hoveredLine = line; - }) - }, - - setSnappedPoint: (point: Point | null) => { - set((state) => { - state.snappedPoint = point; - }); - }, - - setSnappedPosition: (position: [number, number, number] | null) => { - set((state) => { - state.snappedPosition = position; - }); - }, + // === Setters: Aisle General === setSelectedAisle: (aisle: Object3D | null) => { set((state) => { @@ -163,73 +152,78 @@ export const useBuilderStore = create()( state.aisleType = type; }); }, + setAisleWidth: (width) => { set((state) => { state.aisleWidth = width; }); }, + setAisleColor: (color) => { set((state) => { state.aisleColor = color; }); }, + + // === Setters: Aisle Specific === + setDashLength: (length) => { set((state) => { state.dashLength = length; }); }, + setGapLength: (length) => { set((state) => { state.gapLength = length; }); }, + setDotRadius: (radius) => { set((state) => { state.dotRadius = radius; }); }, + setAisleLength: (length) => { set((state) => { state.aisleLength = length; }); }, + setIsFlipped: (isFlipped) => { set((state) => { state.isFlipped = isFlipped; }); }, - // Batch setters - setDashedAisleProperties: (width, dashLength, gapLength) => { - set((state) => { - state.aisleType = 'dashed-aisle'; - state.aisleWidth = width; - state.dashLength = dashLength; - state.gapLength = gapLength; - }); - }, - setDottedAisleProperties: (width, dotRadius, gapLength) => { - set((state) => { - state.aisleType = 'dotted-aisle'; - state.aisleWidth = width; - state.dotRadius = dotRadius; - state.gapLength = gapLength; - }); - }, - setArrowsAisleProperties: (width, aisleLength, gapLength) => { - set((state) => { - state.aisleType = 'arrows-aisle'; - state.aisleWidth = width; - state.aisleLength = aisleLength; - state.gapLength = gapLength; - }); - }, - setAisleProperties: (type, width, color) => { - set((state) => { - state.aisleType = type; - state.aisleWidth = width; - state.aisleColor = color; - }); - } + // === Batch Setters === + + setDashedAisleProperties: (width, dashLength, gapLength) => set((state) => { + state.aisleType = 'dashed-aisle'; + state.aisleWidth = width; + state.dashLength = dashLength; + state.gapLength = gapLength; + }), + + setDottedAisleProperties: (width, dotRadius, gapLength) => set((state) => { + state.aisleType = 'dotted-aisle'; + state.aisleWidth = width; + state.dotRadius = dotRadius; + state.gapLength = gapLength; + }), + + setArrowsAisleProperties: (width, aisleLength, gapLength) => set((state) => { + state.aisleType = 'arrows-aisle'; + state.aisleWidth = width; + state.aisleLength = aisleLength; + state.gapLength = gapLength; + }), + + setAisleProperties: (type, width, color) => set((state) => { + state.aisleType = type; + state.aisleWidth = width; + state.aisleColor = color; + }) })) -); \ No newline at end of file +); diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts new file mode 100644 index 0000000..4c89333 --- /dev/null +++ b/app/src/store/builder/useFloorStore.ts @@ -0,0 +1,90 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface FloorStore { + floors: Floor[]; + setFloors: (floors: Floor[]) => void; + addFloor: (floor: Floor) => void; + updateFloor: (uuid: string, updated: Partial) => void; + removeFloor: (uuid: string) => void; + removePointFromFloors: (pointUuid: string) => void; + clearFloors: () => void; + setIsBeveled: (uuid: string, isBeveled: boolean) => void; + setBevelStrength: (uuid: string, strength: number) => void; + setDepth: (uuid: string, depth: number) => void; + setMaterial: (uuid: string, sideMaterial: string, topMaterial: string) => void; + + getFloorById: (uuid: string) => Floor | undefined; +} + +export const createFloorStore = () => { + return create()( + immer((set, get) => ({ + floors: [], + + setFloors: (floors) => set(state => { + state.floors = floors; + }), + + addFloor: (floor) => set(state => { + state.floors.push(floor); + }), + + updateFloor: (uuid, updated) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + Object.assign(floor, updated); + } + }), + + removeFloor: (uuid) => set(state => { + state.floors = state.floors.filter(f => f.floorUuid !== uuid); + }), + + removePointFromFloors: (pointUuid) => set(state => { + for (const floor of state.floors) { + floor.points = floor.points.filter(p => p.pointUuid !== pointUuid); + } + }), + + clearFloors: () => set(state => { + state.floors = []; + }), + + setIsBeveled: (uuid, isBeveled) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.isBeveled = isBeveled; + } + }), + + setBevelStrength: (uuid, strength) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.bevelStrength = strength; + } + }), + + setDepth: (uuid, depth) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.floorDepth = depth; + } + }), + + setMaterial: (uuid, sideMaterial, topMaterial) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.sideMaterial = sideMaterial; + floor.topMaterial = topMaterial; + } + }), + + getFloorById: (uuid) => { + return get().floors.find(f => f.floorUuid === uuid); + }, + })) + ); +}; + +export type FloorStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/builder/useWallAssetStore.ts b/app/src/store/builder/useWallAssetStore.ts new file mode 100644 index 0000000..408aade --- /dev/null +++ b/app/src/store/builder/useWallAssetStore.ts @@ -0,0 +1,82 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface WallAssetStore { + wallAssets: WallAsset[]; + setWallAssets: (assets: WallAsset[]) => void; + addWallAsset: (asset: WallAsset) => void; + updateWallAsset: (uuid: string, updated: Partial) => void; + removeWallAsset: (uuid: string) => void; + clearWallAssets: () => void; + + setVisibility: (uuid: string, isVisible: boolean) => void; + setLock: (uuid: string, isLocked: boolean) => void; + setOpacity: (uuid: string, opacity: number) => void; + + getWallAssetById: (uuid: string) => WallAsset | undefined; + getAssetsByWall: (wallUuid: string) => WallAsset[]; +} + +export const createWallAssetStore = () => { + return create()( + immer((set, get) => ({ + wallAssets: [], + + setWallAssets: (assets) => set(state => { + state.wallAssets = assets; + }), + + addWallAsset: (asset) => set(state => { + state.wallAssets.push(asset); + }), + + updateWallAsset: (uuid, updated) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + Object.assign(asset, updated); + } + }), + + removeWallAsset: (uuid) => set(state => { + state.wallAssets = state.wallAssets.filter(a => a.modelUuid !== uuid); + }), + + clearWallAssets: () => { + set(state => { + state.wallAssets = []; + }) + }, + + setVisibility: (uuid, isVisible) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + asset.isVisible = isVisible; + } + }), + + setLock: (uuid, isLocked) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + asset.isLocked = isLocked; + } + }), + + setOpacity: (uuid, opacity) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + asset.opacity = opacity; + } + }), + + getWallAssetById: (uuid) => { + return get().wallAssets.find(a => a.modelUuid === uuid); + }, + + getAssetsByWall: (wallUuid) => { + return get().wallAssets.filter(a => a.wallUuid === wallUuid); + }, + })) + ); +}; + +export type WallAssetStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/builder/useWallStore.ts b/app/src/store/builder/useWallStore.ts new file mode 100644 index 0000000..3547330 --- /dev/null +++ b/app/src/store/builder/useWallStore.ts @@ -0,0 +1,211 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface WallStore { + walls: Wall[]; + setWalls: (walls: Wall[]) => void; + addWall: (wall: Wall) => void; + updateWall: (uuid: string, updated: Partial) => void; + removeWall: (uuid: string) => void; + clearWalls: () => void; + removeWallByPoints: (Points: [Point, Point]) => Wall | undefined; + addDecal: (wallUuid: string, decal: Decal) => void; + updateDecal: (decalUuid: string, decal: Decal) => void; + removeDecal: (decalUuid: string) => void; + updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void; + updateDecalRotation: (decalUuid: string, rotation: number) => void; + updateDecalScale: (decalUuid: string, scale: number) => void; + + removePoint: (pointUuid: string) => Wall[]; + setPosition: (pointUuid: string, position: [number, number, number]) => void; + setLayer: (pointUuid: string, layer: number) => void; + + getWallById: (uuid: string) => Wall | undefined; + getWallByPointId: (uuid: string) => Wall | undefined; + getWallByPoints: (points: Point[]) => Wall | undefined; + getWallPointById: (uuid: string) => Point | undefined; + getConnectedPoints: (uuid: string) => Point[]; +} + +export const createWallStore = () => { + return create()( + immer((set, get) => ({ + walls: [], + + setWalls: (walls) => set((state) => { + state.walls = walls; + }), + + addWall: (wall) => set((state) => { + state.walls.push(wall); + }), + + updateWall: (uuid, updated) => set((state) => { + const wall = state.walls.find(w => w.wallUuid === uuid); + if (wall) { + Object.assign(wall, updated); + } + }), + + removeWall: (uuid) => set((state) => { + state.walls = state.walls.filter(w => w.wallUuid !== uuid); + }), + + clearWalls: () => { + set((state) => { + state.walls = []; + }) + }, + + removeWallByPoints: (points) => { + let removedWall: Wall | undefined; + const [pointA, pointB] = points; + + set((state) => { + state.walls = state.walls.filter(wall => { + const wallPoints = wall.points.map(p => p.pointUuid); + const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid); + + if (hasBothPoints) { + removedWall = JSON.parse(JSON.stringify(wall)); + return false; + } + return true; + }); + }); + + return removedWall; + }, + + addDecal: (wallUuid, decal) => set((state) => { + const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid); + if (wallToUpdate) { + wallToUpdate.decals.push(decal); + } + }), + + updateDecal: (decalUuid, decal) => set((state) => { + for (const wall of state.walls) { + const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid); + if (decalToUpdate) { + Object.assign(decalToUpdate, decal); + } + } + }), + + removeDecal: (decalUuid) => set((state) => { + for (const wall of state.walls) { + wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid); + } + }), + + updateDecalPosition: (decalUuid, position) => set((state) => { + for (const wall of state.walls) { + const decal = wall.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalPosition = position; + break; + } + } + }), + + updateDecalRotation: (decalUuid, rotation) => set((state) => { + for (const wall of state.walls) { + const decal = wall.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalRotation = rotation; + break; + } + } + }), + + updateDecalScale: (decalUuid, scale) => set((state) => { + for (const wall of state.walls) { + const decal = wall.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalScale = scale; + break; + } + } + }), + + removePoint: (pointUuid) => { + const removedWalls: Wall[] = []; + set((state) => { + state.walls = state.walls.filter((wall) => { + const hasPoint = wall.points.some(p => p.pointUuid === pointUuid); + if (hasPoint) { + removedWalls.push(JSON.parse(JSON.stringify(wall))); + return false; + } + return true; + }); + }); + return removedWalls; + }, + + setPosition: (pointUuid, position) => set((state) => { + for (const wall of state.walls) { + const point = wall.points.find(p => p.pointUuid === pointUuid); + if (point) { + point.position = position; + } + } + }), + + setLayer: (pointUuid, layer) => set((state) => { + for (const wall of state.walls) { + const point = wall.points.find(p => p.pointUuid === pointUuid); + if (point) { + point.layer = layer; + } + } + }), + + getWallById: (uuid) => { + return get().walls.find(w => w.wallUuid === uuid); + }, + + getWallByPointId: (uuid) => { + for (const wall of get().walls) { + if (wall.points.some(p => p.pointUuid === uuid)) { + return wall; + } + } + return undefined; + }, + + getWallByPoints: (point) => { + for (const wall of get().walls) { + if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) && + ((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) { + return wall; + } + } + return undefined; + }, + + getWallPointById: (uuid) => { + for (const wall of get().walls) { + const point = wall.points.find(p => p.pointUuid === uuid); + if (point) return point; + } + return undefined; + }, + + getConnectedPoints: (uuid) => { + const connected: Point[] = []; + for (const wall of get().walls) { + for (const point of wall.points) { + if (point.pointUuid === uuid) { + connected.push(...wall.points.filter(p => p.pointUuid !== uuid)); + } + } + } + return connected; + }, + })) + ) +} + +export type WallStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/builder/useWallStore.tsx b/app/src/store/builder/useWallStore.tsx deleted file mode 100644 index 4f57849..0000000 --- a/app/src/store/builder/useWallStore.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import { create } from 'zustand'; -import { immer } from 'zustand/middleware/immer'; - -interface WallStore { - walls: Wall[]; - setWalls: (walls: Wall[]) => void; - addWall: (wall: Wall) => void; - updateWall: (uuid: string, updated: Partial) => void; - removeWall: (uuid: string) => void; - removeWallByPoints: (Points: [Point, Point]) => Wall | undefined; - addDecal: (wallUuid: string, decal: Decal) => void; - updateDecal: (decalUuid: string, decal: Decal) => void; - removeDecal: (decalUuid: string) => void; - updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void; - updateDecalRotation: (decalUuid: string, rotation: number) => void; - updateDecalScale: (decalUuid: string, scale: number) => void; - - removePoint: (pointUuid: string) => Wall[]; - setPosition: (pointUuid: string, position: [number, number, number]) => void; - setLayer: (pointUuid: string, layer: number) => void; - - getWallById: (uuid: string) => Wall | undefined; - getWallByPointId: (uuid: string) => Wall | undefined; - getWallByPoints: (points: Point[]) => Wall | undefined; - getWallPointById: (uuid: string) => Point | undefined; - getConnectedPoints: (uuid: string) => Point[]; -} - -export const useWallStore = create()( - immer((set, get) => ({ - walls: [], - - setWalls: (walls) => set((state) => { - state.walls = walls; - }), - - addWall: (wall) => set((state) => { - state.walls.push(wall); - }), - - updateWall: (uuid, updated) => set((state) => { - const wall = state.walls.find(w => w.wallUuid === uuid); - if (wall) { - Object.assign(wall, updated); - } - }), - - removeWall: (uuid) => set((state) => { - state.walls = state.walls.filter(w => w.wallUuid !== uuid); - }), - - removeWallByPoints: (points) => { - let removedWall: Wall | undefined; - const [pointA, pointB] = points; - - set((state) => { - state.walls = state.walls.filter(wall => { - const wallPoints = wall.points.map(p => p.pointUuid); - const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid); - - if (hasBothPoints) { - removedWall = JSON.parse(JSON.stringify(wall)); - return false; - } - return true; - }); - }); - - return removedWall; - }, - - addDecal: (wallUuid, decal) => set((state) => { - const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid); - if (wallToUpdate) { - wallToUpdate.decals.push(decal); - } - }), - - updateDecal: (decalUuid, decal) => set((state) => { - for (const wall of state.walls) { - const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid); - if (decalToUpdate) { - Object.assign(decalToUpdate, decal); - } - } - }), - - removeDecal: (decalUuid) => set((state) => { - for (const wall of state.walls) { - wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid); - } - }), - - updateDecalPosition: (decalUuid, position) => set((state) => { - for (const wall of state.walls) { - const decal = wall.decals.find(d => d.decalUuid === decalUuid); - if (decal) { - decal.decalPosition = position; - break; - } - } - }), - - updateDecalRotation: (decalUuid, rotation) => set((state) => { - for (const wall of state.walls) { - const decal = wall.decals.find(d => d.decalUuid === decalUuid); - if (decal) { - decal.decalRotation = rotation; - break; - } - } - }), - - updateDecalScale: (decalUuid, scale) => set((state) => { - for (const wall of state.walls) { - const decal = wall.decals.find(d => d.decalUuid === decalUuid); - if (decal) { - decal.decalScale = scale; - break; - } - } - }), - - removePoint: (pointUuid) => { - const removedWalls: Wall[] = []; - set((state) => { - state.walls = state.walls.filter((wall) => { - const hasPoint = wall.points.some(p => p.pointUuid === pointUuid); - if (hasPoint) { - removedWalls.push(JSON.parse(JSON.stringify(wall))); - return false; - } - return true; - }); - }); - return removedWalls; - }, - - setPosition: (pointUuid, position) => set((state) => { - for (const wall of state.walls) { - const point = wall.points.find(p => p.pointUuid === pointUuid); - if (point) { - point.position = position; - } - } - }), - - setLayer: (pointUuid, layer) => set((state) => { - for (const wall of state.walls) { - const point = wall.points.find(p => p.pointUuid === pointUuid); - if (point) { - point.layer = layer; - } - } - }), - - getWallById: (uuid) => { - return get().walls.find(w => w.wallUuid === uuid); - }, - - getWallByPointId: (uuid) => { - for (const wall of get().walls) { - if (wall.points.some(p => p.pointUuid === uuid)) { - return wall; - } - } - return undefined; - }, - - getWallByPoints: (point) => { - for (const wall of get().walls) { - if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) && - ((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) { - return wall; - } - } - return undefined; - }, - - getWallPointById: (uuid) => { - for (const wall of get().walls) { - const point = wall.points.find(p => p.pointUuid === uuid); - if (point) return point; - } - return undefined; - }, - - getConnectedPoints: (uuid) => { - const connected: Point[] = []; - for (const wall of get().walls) { - for (const point of wall.points) { - if (point.pointUuid === uuid) { - connected.push(...wall.points.filter(p => p.pointUuid !== uuid)); - } - } - } - return connected; - }, - })) -); diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts new file mode 100644 index 0000000..ee3c736 --- /dev/null +++ b/app/src/store/builder/useZoneStore.ts @@ -0,0 +1,74 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface ZoneStore { + zones: Zone[]; + setZones: (zones: Zone[]) => void; + addZone: (zone: Zone) => void; + updateZone: (uuid: string, updated: Partial) => void; + removeZone: (uuid: string) => void; + removePointFromZones: (pointUuid: string) => void; + clearZones: () => void; + setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void; + setColor: (uuid: string, color: string) => void; + + getZoneById: (uuid: string) => Zone | undefined; +} + +export const createZoneStore = () => { + return create()( + immer((set, get) => ({ + zones: [], + + setZones: (zones) => set(state => { + state.zones = zones; + }), + + addZone: (zone) => set(state => { + state.zones.push(zone); + }), + + updateZone: (uuid, updated) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + Object.assign(zone, updated); + } + }), + + removeZone: (uuid) => set(state => { + state.zones = state.zones.filter(z => z.zoneUuid !== uuid); + }), + + removePointFromZones: (pointUuid) => set(state => { + for (const zone of state.zones) { + zone.points = zone.points.filter(p => p.pointUuid !== pointUuid); + } + }), + + clearZones: () => set(state => { + state.zones = []; + }), + + setViewPort: (uuid, position, target) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + zone.viewPortPosition = position; + zone.viewPortTarget = target; + } + }), + + setColor: (uuid, color) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + zone.zoneColor = color; + } + }), + + getZoneById: (uuid) => { + return get().zones.find(z => z.zoneUuid === uuid); + }, + })) + ); +}; + +export type ZoneStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 51f32df..6b24256 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -1657,8 +1657,13 @@ .sidebar-right-wrapper { .wall-properties-container { + .wall-properties-section{ + padding: 14px; + padding-bottom: 0; + margin-bottom: 8px; + } .header { - color: var(--background-color-button); + color: var(--text-color); } .wall-properties { @@ -1692,7 +1697,7 @@ flex-direction: column; align-items: center; gap: 15px; - background: var(--Grays-Gray-6, #f2f2f7); + background: var(--background-color-secondary); padding: 18px 25px; .sides-wrapper { @@ -1736,8 +1741,10 @@ } .preview { - width: 90%; + width: 100%; height: 111px; + border-radius: 20px; + overflow: hidden; img { width: 100%; @@ -1750,7 +1757,8 @@ .materials { max-height: 250px; overflow: auto; - margin-bottom: 6px; + margin-top: 12px; + margin-bottom: 16px; padding: 0 12px; .material-container { From 08208528a5a96590d58563b69cbee0cdfedc4d34 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 17:20:35 +0530 Subject: [PATCH 3/6] Add decal management functionality and refactor wall components --- .../modules/builder/Decal/decalInstance.tsx | 48 +++++++++++++++++ .../builder/wall/Instances/instance/wall.tsx | 54 ++++++++++--------- .../builder/wall/Instances/wallInstances.tsx | 2 +- app/src/modules/builder/wall/wallGroup.tsx | 3 +- .../scene/postProcessing/postProcessing.tsx | 17 +++++- app/src/store/builder/useBuilderStore.ts | 16 ++++++ app/src/types/builderTypes.d.ts | 11 ++++ 7 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 app/src/modules/builder/Decal/decalInstance.tsx diff --git a/app/src/modules/builder/Decal/decalInstance.tsx b/app/src/modules/builder/Decal/decalInstance.tsx new file mode 100644 index 0000000..6ed0490 --- /dev/null +++ b/app/src/modules/builder/Decal/decalInstance.tsx @@ -0,0 +1,48 @@ +import * as THREE from 'three'; +import { Decal } from '@react-three/drei' +import { useLoader } from '@react-three/fiber'; +import { useToggleView } from '../../../store/builder/store'; +import { useBuilderStore } from '../../../store/builder/useBuilderStore'; + +import defaultMaterial from '../../../assets/textures/floor/wall-tex.png'; +import useModuleStore from '../../../store/useModuleStore'; + +function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) { + const { setSelectedWall, selectedDecal, setSelectedDecal } = useBuilderStore(); + const { togglView } = useToggleView(); + const { activeModule } = useModuleStore(); + const material = useLoader(THREE.TextureLoader, defaultMaterial); + + return ( + { + if (visible && !togglView && activeModule === 'builder') { + if (e.object.userData.decalUuid) { + setSelectedDecal(e.object); + setSelectedWall(null); + } + } + }} + onPointerMissed={() => { + if (selectedDecal && selectedDecal.userData.decalUuid === decal.decalUuid) { + setSelectedDecal(null); + } + }} + > + + + ) +} + +export default DecalInstance \ No newline at end of file diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 4ada970..037816b 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -13,12 +13,13 @@ import { useWallClassification } from './helpers/useWallClassification'; import { useToggleView, useWallVisibility } from '../../../../../store/builder/store'; import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; import * as Constants from '../../../../../types/world/worldConstants'; +import DecalInstance from '../../../Decal/decalInstance'; function Wall({ wall }: { readonly wall: Wall }) { const { wallStore } = useSceneContext(); - const { walls } = wallStore(); + const { walls, addDecal } = wallStore(); + const { selectedWall, setSelectedWall, setSelectedDecal } = useBuilderStore(); const { togglView } = useToggleView(); - const { setSelectedWall } = useBuilderStore(); const { activeModule } = useModuleStore(); const { camera } = useThree(); const { wallVisibility } = useWallVisibility(); @@ -112,25 +113,6 @@ function Wall({ wall }: { readonly wall: Wall }) { {materials.map((material, index) => ( ))} - - {wall.decals.map((decal) => { - return ( - - - - ) - })} { if (visible && !togglView && activeModule === 'builder') { - setSelectedWall(e.object) + if (e.object.userData.wallUuid) { + setSelectedWall(e.object); + setSelectedDecal(null); + + if (wall.decals.length > 0) return; + const decal: Decal = { + decalUuid: THREE.MathUtils.generateUUID(), + decalName: 'Decal', + decalId: 'Default Decal', + decalPosition: [0, 0, wall.wallThickness / 2 + 0.001], + decalRotation: 0, + decalScale: 1, + decalType: { type: 'Wall', wallUuid: wall.wallUuid } + } + addDecal(wall.wallUuid, decal); + + } + } + }} + onPointerMissed={() => { + if (selectedWall && selectedWall.userData.wallUuid === wall.wallUuid) { + setSelectedWall(null); } }} - onPointerMissed={() => { setSelectedWall(null) }} > + + {wall.decals.map((decal) => ( + + ))} ); diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx index b22d0e6..4d5da1e 100644 --- a/app/src/modules/builder/wall/Instances/wallInstances.tsx +++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx @@ -42,7 +42,7 @@ function WallInstances() { return ( <> - {!toggleView && ( + {!toggleView && walls.length > 1 && ( <> diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index 07ef700..aae36b9 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -7,12 +7,13 @@ import useModuleStore from '../../../store/useModuleStore'; function WallGroup() { const { togglView } = useToggleView(); - const { setSelectedWall } = useBuilderStore(); + const { setSelectedWall, setSelectedDecal } = useBuilderStore(); const { activeModule } = useModuleStore(); useEffect(() => { if (togglView || activeModule !== 'builder') { setSelectedWall(null); + setSelectedDecal(null); } }, [togglView, activeModule]) diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 1b91386..25d0e0c 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -15,7 +15,7 @@ export default function PostProcessing() { const { selectedWallItem } = useSelectedWallItem(); const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAisle, selectedWall } = useBuilderStore(); + const { selectedAisle, selectedWall, selectedDecal } = useBuilderStore(); function flattenChildren(children: any[]) { const allChildren: any[] = []; @@ -85,6 +85,21 @@ export default function PostProcessing() { xRay={true} /> )} + {selectedDecal && ( + + )} {deletableFloorItem && ( void; setWallMaterial: (material: string, side: 'inside' | 'outside') => void; + // Setters - Decal + setSelectedDecal: (decal: Object3D | null) => void; + // Setters - Aisle General setSelectedAisle: (aisle: Object3D | null) => void; setAisleType: (type: AisleTypes) => void; @@ -75,6 +81,8 @@ export const useBuilderStore = create()( outsideMaterial: 'Default Material', insideMaterial: 'Material 1', + selectedDecal: null, + selectedAisle: null, aisleType: 'solid-aisle', aisleWidth: 0.1, @@ -139,6 +147,14 @@ export const useBuilderStore = create()( }); }, + // === Setters: Decal === + + setSelectedDecal: (decal: Object3D | null) => { + set((state) => { + state.selectedDecal = decal; + }) + }, + // === Setters: Aisle General === setSelectedAisle: (aisle: Object3D | null) => { diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index decde1d..17349d7 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -80,11 +80,22 @@ interface Decal { decalUuid: string; decalName: string; decalId: string; + decalType: WallDecal | FloorDecal; decalPosition: [number, number, number]; decalRotation: number; decalScale: number; } +interface WallDecal { + type: 'Wall'; + wallUuid: string; +} + +interface FloorDecal { + type: 'Floor'; + floorUuid: string; +} + interface Wall { wallUuid: string; points: [Point, Point]; From d8a793c4216de2812baae9c4f863019ec9dbc942 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 17:32:36 +0530 Subject: [PATCH 4/6] Comment out WallGroup component and clean up drawWall function call --- app/src/modules/builder/builder.tsx | 2 +- app/src/modules/builder/groups/floorPlanGroup.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index cbbf2fe..b977781 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -276,7 +276,7 @@ export default function Builder() { - + {/* */} ); } diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx index ed3065d..8f1c2f2 100644 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ b/app/src/modules/builder/groups/floorPlanGroup.tsx @@ -148,7 +148,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin } if (toolMode === "Wall") { - // drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); + drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); } if (toolMode === "Floor") { From 9696bc0f1ebbdf3b83b2233a01892b064e519f31 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 17:39:28 +0530 Subject: [PATCH 5/6] Refactor drawWall function for improved readability and maintainability --- .../builder/geomentries/lines/drawWall.ts | 369 ++++++++---------- 1 file changed, 170 insertions(+), 199 deletions(-) diff --git a/app/src/modules/builder/geomentries/lines/drawWall.ts b/app/src/modules/builder/geomentries/lines/drawWall.ts index fb6cf10..80333ed 100644 --- a/app/src/modules/builder/geomentries/lines/drawWall.ts +++ b/app/src/modules/builder/geomentries/lines/drawWall.ts @@ -14,234 +14,205 @@ import { Socket } from "socket.io-client"; import { getUserData } from "../../../../functions/getUserData"; async function drawWall( - raycaster: THREE.Raycaster, - plane: Types.RefMesh, - floorPlanGroupPoint: Types.RefGroup, - snappedPoint: Types.RefVector3, - isSnapped: Types.RefBoolean, - isSnappedUUID: Types.RefString, - line: Types.RefLine, - ispreSnapped: Types.RefBoolean, - anglesnappedPoint: Types.RefVector3, - isAngleSnapped: Types.RefBoolean, - lines: Types.RefLines, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroup: Types.RefGroup, - ReferenceLineMesh: Types.RefMesh, - LineCreated: Types.RefBoolean, - currentLayerPoint: Types.RefMeshArray, - dragPointControls: Types.RefDragControl, - setNewLines: any, - setDeletedLines: any, - activeLayer: Types.Number, - socket: Socket, - projectId?: string, - versionId?: string, + raycaster: THREE.Raycaster, + plane: Types.RefMesh, + floorPlanGroupPoint: Types.RefGroup, + snappedPoint: Types.RefVector3, + isSnapped: Types.RefBoolean, + isSnappedUUID: Types.RefString, + line: Types.RefLine, + ispreSnapped: Types.RefBoolean, + anglesnappedPoint: Types.RefVector3, + isAngleSnapped: Types.RefBoolean, + lines: Types.RefLines, + floorPlanGroupLine: Types.RefGroup, + floorPlanGroup: Types.RefGroup, + ReferenceLineMesh: Types.RefMesh, + LineCreated: Types.RefBoolean, + currentLayerPoint: Types.RefMeshArray, + dragPointControls: Types.RefDragControl, + setNewLines: any, + setDeletedLines: any, + activeLayer: Types.Number, + socket: Socket, + projectId?: string, + versionId?: string, ): Promise { - const { userId, organization, email } = getUserData(); - ////////// Creating lines Based on the positions clicked ////////// + const { userId, organization } = getUserData(); + ////////// Creating lines Based on the positions clicked ////////// - ////////// Allows the user lines that represents walls and roof, floor if forms a polygon ////////// + ////////// Allows the user lines that represents walls and roof, floor if forms a polygon ////////// - if (!plane.current) return; - let intersects = raycaster.intersectObject(plane.current, true); + if (!plane.current) return; + let intersects = raycaster.intersectObject(plane.current, true); - let intersectsLines = raycaster.intersectObjects( - floorPlanGroupLine.current.children, - true - ); - let intersectsPoint = raycaster.intersectObjects( - floorPlanGroupPoint.current.children, - true - ); + let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true); + let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true); - const VisibleintersectsPoint = intersectsPoint.find( - (intersect) => intersect.object.visible - ); - const visibleIntersect = intersectsLines.find( - (intersect) => - intersect.object.visible && - intersect.object.name !== CONSTANTS.lineConfig.referenceName && - intersect.object.userData.linePoints[0][3] === - CONSTANTS.lineConfig.wallName - ); + const VisibleintersectsPoint = intersectsPoint.find((intersect) => intersect.object.visible); + const visibleIntersect = intersectsLines.find( + (intersect) => + intersect.object.visible && + intersect.object.name !== CONSTANTS.lineConfig.referenceName && + intersect.object.userData.linePoints[0][3] === + CONSTANTS.lineConfig.wallName + ); - if ( - (intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && - intersectsLines.length > 0 && - !isSnapped.current && - !ispreSnapped.current - ) { - ////////// Clicked on a preexisting Line ////////// + if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) { + ////////// Clicked on a preexisting Line ////////// - if (visibleIntersect && intersects) { - let IntersectsPoint = new THREE.Vector3( - intersects[0].point.x, - 0.01, - intersects[0].point.z - ); + if (visibleIntersect && intersects) { + let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z); - if (isAngleSnapped.current && anglesnappedPoint.current) { - IntersectsPoint = anglesnappedPoint.current; - } - if (visibleIntersect.object instanceof THREE.Mesh) { - const ThroughPoint = - visibleIntersect.object.geometry.parameters.path.getPoints( - CONSTANTS.lineConfig.lineIntersectionPoints - ); - let intersectionPoint = getClosestIntersection( - ThroughPoint, - IntersectsPoint - ); + if (isAngleSnapped.current && anglesnappedPoint.current) { + IntersectsPoint = anglesnappedPoint.current; + } + if (visibleIntersect.object instanceof THREE.Mesh) { + const ThroughPoint = visibleIntersect.object.geometry.parameters.path.getPoints(CONSTANTS.lineConfig.lineIntersectionPoints); + let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint); - if (intersectionPoint) { - const newLines = splitLine( - visibleIntersect, - intersectionPoint, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - lines, - setDeletedLines, - floorPlanGroupLine, - socket, - CONSTANTS.pointConfig.wallOuterColor, - CONSTANTS.lineConfig.wallColor, - CONSTANTS.lineConfig.wallName, - projectId, - versionId - ); - setNewLines([newLines[0], newLines[1]]); + if (intersectionPoint) { + const newLines = splitLine( + visibleIntersect, + intersectionPoint, + currentLayerPoint, + floorPlanGroupPoint, + dragPointControls, + isSnappedUUID, + lines, + setDeletedLines, + floorPlanGroupLine, + socket, + CONSTANTS.pointConfig.wallOuterColor, + CONSTANTS.lineConfig.wallColor, + CONSTANTS.lineConfig.wallName, + projectId, + versionId + ); + setNewLines([newLines[0], newLines[1]]); - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.wallName, - ]); + (line.current as Types.Line).push([ + new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), + isSnappedUUID.current!, + activeLayer, + CONSTANTS.lineConfig.wallName, + ]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - const data = arrayLineToObject(line.current as Types.Line); + if (line.current.length >= 2 && line.current[0] && line.current[1]) { + const data = arrayLineToObject(line.current as Types.Line); - //REST + //REST - // setLine(organization, data.layer!, data.line!, data.type!); + // setLine(organization, data.layer!, data.line!, data.type!); - //SOCKET + //SOCKET - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; + const input = { + organization, + layer: data.layer, + line: data.line, + type: data.type, + socketId: socket.id, + versionId, + projectId, + userId, + }; - console.log('input: ', input); - socket.emit("v1:Line:create", input); + socket.emit("v1:Line:create", input); - setNewLines([newLines[0], newLines[1], line.current]); - lines.current.push(line.current as Types.Line); - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.wallColor, - line.current, - floorPlanGroupLine - ); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - return; - } - } - } - } + setNewLines([newLines[0], newLines[1], line.current]); + lines.current.push(line.current as Types.Line); + addLineToScene( + line.current[0][0], + line.current[1][0], + CONSTANTS.lineConfig.wallColor, + line.current, + floorPlanGroupLine + ); + let lastPoint = line.current[line.current.length - 1]; + line.current = [lastPoint]; + } + return; + } + } + } + } - if (intersects && intersects.length > 0) { - ////////// Clicked on a emply place or a point ////////// + if (intersects && intersects.length > 0) { + ////////// Clicked on a emply place or a point ////////// - let intersectionPoint = intersects[0].point; + let intersectionPoint = intersects[0].point; - if ( - isAngleSnapped.current && - line.current.length > 0 && - anglesnappedPoint.current - ) { - intersectionPoint = anglesnappedPoint.current; - } - if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } - if (ispreSnapped.current && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } + if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) { + intersectionPoint = anglesnappedPoint.current; + } + if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { + intersectionPoint = snappedPoint.current; + } + if (ispreSnapped.current && snappedPoint.current) { + intersectionPoint = snappedPoint.current; + } - if (!isSnapped.current && !ispreSnapped.current) { - addPointToScene( - intersectionPoint, - CONSTANTS.pointConfig.wallOuterColor, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - CONSTANTS.lineConfig.wallName - ); - } else { - ispreSnapped.current = false; - isSnapped.current = false; - } + if (!isSnapped.current && !ispreSnapped.current) { + addPointToScene( + intersectionPoint, + CONSTANTS.pointConfig.wallOuterColor, + currentLayerPoint, + floorPlanGroupPoint, + dragPointControls, + isSnappedUUID, + CONSTANTS.lineConfig.wallName + ); + } else { + ispreSnapped.current = false; + isSnapped.current = false; + } - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.wallName, - ]); + (line.current as Types.Line).push([ + new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), + isSnappedUUID.current!, + activeLayer, + CONSTANTS.lineConfig.wallName, + ]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - const data = arrayLineToObject(line.current as Types.Line); + if (line.current.length >= 2 && line.current[0] && line.current[1]) { + const data = arrayLineToObject(line.current as Types.Line); - //REST + //REST - // setLine(organization, data.layer!, data.line!, data.type!); + // setLine(organization, data.layer!, data.line!, data.type!); - //SOCKET + //SOCKET - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; + const input = { + organization, + layer: data.layer, + line: data.line, + type: data.type, + socketId: socket.id, + versionId, + projectId, + userId, + }; - console.log('input: ', input); - socket.emit("v1:Line:create", input); + socket.emit("v1:Line:create", input); - setNewLines([line.current]); - lines.current.push(line.current as Types.Line); - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.wallColor, - line.current, - floorPlanGroupLine - ); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - if (isSnapped.current) { - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - } + setNewLines([line.current]); + lines.current.push(line.current as Types.Line); + addLineToScene( + line.current[0][0], + line.current[1][0], + CONSTANTS.lineConfig.wallColor, + line.current, + floorPlanGroupLine + ); + let lastPoint = line.current[line.current.length - 1]; + line.current = [lastPoint]; + } + if (isSnapped.current) { + removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); + } + } } export default drawWall; From b4745451d280c5ce2478f8e51f7aa9d8b0cf7473 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 26 Jun 2025 09:51:11 +0530 Subject: [PATCH 6/6] Refactor SidePannel component and update builderTypes to ensure consistent decal property syntax --- app/src/components/Dashboard/SidePannel.tsx | 8 ++------ app/src/types/builderTypes.d.ts | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/src/components/Dashboard/SidePannel.tsx b/app/src/components/Dashboard/SidePannel.tsx index 89b7ba9..5cfaeb0 100644 --- a/app/src/components/Dashboard/SidePannel.tsx +++ b/app/src/components/Dashboard/SidePannel.tsx @@ -42,7 +42,6 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { const projectId = generateProjectId(); useSocketStore.getState().initializeSocket(email, organization, token); - //API for creating new Project // const project = await createProject( // projectId, @@ -50,18 +49,16 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { // savedTheme === "dark" ? darkThemeImage : lightThemeImage, // organization // ); - // console.log('Created project: ', project); + const addProject = { userId, thumbnail: savedTheme === "dark" ? darkThemeImage : lightThemeImage, organization: organization, projectUuid: projectId, }; - // console.log("projectSocket: ", projectSocket); + if (projectSocket) { - // console.log('addProject: ', addProject); const handleResponse = (data: any) => { - // console.log('Project add response:', data); if (data.message === "Project created successfully") { setLoadingProgress(1) navigate(`/${data.data.projectId}`); @@ -70,7 +67,6 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { }; projectSocket.on("v1-project:response:add", handleResponse); - // console.log('addProject: ', addProject); projectSocket.emit("v1:project:add", addProject); } else { console.error("Socket is not connected."); diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index 17349d7..bbc9b7b 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -103,7 +103,7 @@ interface Wall { insideMaterial: string; wallThickness: number; wallHeight: number; - decals: Decal[] + decals: Decal[]; } type Walls = Wall[]; @@ -119,6 +119,7 @@ interface Floor { floorDepth: number; isBeveled: boolean; bevelStrength: number; + decals: Decal[]; } type Floors = Floor[];