Refactor wall creator and socket responses; update nav mesh components and remove unused pillar functions

- Updated import path for getClosestIntersection in wallCreator.tsx
- Cleaned up socketResponses.dev.tsx by removing unused imports and code, simplifying the component structure
- Modified navMesh.tsx to remove lines prop and adjust NavMeshDetails accordingly
- Refactored navMeshDetails.tsx to remove lines dependency in useEffect
- Updated polygonGenerator.tsx to remove lines prop and commented out unused code
- Added getClosestIntersection helper function for better modularity
- Removed unused pillar-related functions and commented out code in addAndUpdateReferencePillar.ts, addPillar.ts, deletableHoveredPillar.ts, deletePillar.ts, and updateReferencePolesheight.ts
This commit is contained in:
2025-06-27 16:54:38 +05:30
parent bfa4d7bbc6
commit 812a4f6aef
72 changed files with 752 additions and 5417 deletions

View File

@@ -21,7 +21,7 @@ function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: De
rotation={[0, 0, decal.decalRotation]}
scale={[decal.decalScale, decal.decalScale, 0.01]}
userData={decal}
onDoubleClick={(e) => {
onClick={(e) => {
if (visible && !togglView && activeModule === 'builder') {
if (e.object.userData.decalUuid) {
e.stopPropagation();

View File

@@ -1,30 +0,0 @@
import addLineToScene from '../../builder/geomentries/lines/addLineToScene';
import * as CONSTANTS from '../../../types/world/worldConstants';
import * as Types from "../../../types/world/worldTypes";
function loadInitialLine(
floorPlanGroupLine: Types.RefGroup,
lines: Types.RefLines
): void {
if (!floorPlanGroupLine.current) return
////////// Load the Lines initially if there are any //////////
floorPlanGroupLine.current.children = [];
lines.current.forEach((line) => {
let colour;
if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName) {
colour = CONSTANTS.lineConfig.wallColor;
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName) {
colour = CONSTANTS.lineConfig.floorColor;
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName) {
colour = CONSTANTS.lineConfig.aisleColor;
}
if (colour) {
addLineToScene(line[0][0], line[1][0], colour, line, floorPlanGroupLine);
}
});
}
export default loadInitialLine;

View File

@@ -1,87 +0,0 @@
import * as THREE from 'three';
import * as CONSTANTS from '../../../types/world/worldConstants';
import * as Types from "../../../types/world/worldTypes";
////////// Load the Boxes initially if there are any //////////
function loadInitialPoint(
lines: Types.RefLines,
floorPlanGroupPoint: Types.RefGroup,
currentLayerPoint: Types.RefMeshArray,
dragPointControls: Types.RefDragControl
): void {
if (!floorPlanGroupPoint.current) return
floorPlanGroupPoint.current.children = [];
currentLayerPoint.current = [];
lines.current.forEach((line) => {
const colour = getPointColor(line[0][3]);
line.forEach((pointData) => {
const [point, id] = pointData;
/////////// Check if a box with this id already exists //////////
const existingBox = floorPlanGroupPoint.current?.getObjectByProperty('uuid', id);
if (existingBox) {
return;
}
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
const material = new THREE.ShaderMaterial({
uniforms: {
uOuterColor: { value: new THREE.Color(colour) }, // Blue color for the border
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
uniform vec3 uOuterColor;
uniform vec3 uInnerColor;
void main() {
// Define the size of the white square as a proportion of the face
float borderThickness = 0.2; // Adjust this value for border thickness
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
} else {
gl_FragColor = vec4(uOuterColor, 1.0); // Blue border
}
}
`,
});
const box = new THREE.Mesh(geometry, material);
box.name = "point";
box.uuid = id;
box.userData = { type: line[0][3], color: colour };
box.position.set(point.x, point.y, point.z);
currentLayerPoint.current.push(box);
floorPlanGroupPoint.current?.add(box);
});
});
function getPointColor(lineType: string | undefined): string {
switch (lineType) {
case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
default: return CONSTANTS.pointConfig.defaultOuterColor;
}
}
if (dragPointControls.current) {
dragPointControls.current!.objects = currentLayerPoint.current;
}
}
export default loadInitialPoint;

View File

@@ -1,110 +1,110 @@
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import * as THREE from "three";
import * as Types from "../../../types/world/worldTypes";
import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi";
import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
import { getUserData } from "../../../functions/getUserData";
// import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
// import * as THREE from "three";
// import * as Types from "../../../types/world/worldTypes";
// import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi";
// import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
// import { getUserData } from "../../../functions/getUserData";
async function loadInitialWallItems(
setWallItems: Types.setWallItemSetState,
projectId?: string,
versionId?: string
): Promise<void> {
if (!projectId || !versionId) return;
try {
const { organization, email } = getUserData();
// async function loadInitialWallItems(
// setWallItems: Types.setWallItemSetState,
// projectId?: string,
// versionId?: string
// ): Promise<void> {
// if (!projectId || !versionId) return;
// try {
// const { organization, email } = getUserData();
if (!email) {
console.error("No email found in localStorage");
}
// if (!email) {
// console.error("No email found in localStorage");
// }
const items = await getWallItems(organization, projectId, versionId);
// const items = await getWallItems(organization, projectId, versionId);
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
if (!items || items.length === 0) {
localStorage.removeItem("WallItems");
return;
}
// if (!items || items.length === 0) {
// localStorage.removeItem("WallItems");
// return;
// }
localStorage.setItem("WallItems", JSON.stringify(items));
// localStorage.setItem("WallItems", JSON.stringify(items));
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath(
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
);
loader.setDRACOLoader(dracoLoader);
// const loader = new GLTFLoader();
// const dracoLoader = new DRACOLoader();
// dracoLoader.setDecoderPath(
// "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
// );
// loader.setDRACOLoader(dracoLoader);
const loadedWallItems = await Promise.all(
items.map(async (item: Types.WallItem) => {
// Check THREE.js cache first
const cachedModel = THREE.Cache.get(item.assetId!);
if (cachedModel) {
return processModel(cachedModel, item);
}
// const loadedWallItems = await Promise.all(
// items.map(async (item: Types.WallItem) => {
// // Check THREE.js cache first
// const cachedModel = THREE.Cache.get(item.assetId!);
// if (cachedModel) {
// return processModel(cachedModel, item);
// }
// Check IndexedDB cache
const cachedModelBlob = await retrieveGLTF(item.assetId!);
if (cachedModelBlob) {
const blobUrl = URL.createObjectURL(cachedModelBlob);
return new Promise<Types.WallItem>((resolve) => {
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.add(item.assetId!, gltf);
resolve(processModel(gltf, item));
});
});
}
// // Check IndexedDB cache
// const cachedModelBlob = await retrieveGLTF(item.assetId!);
// if (cachedModelBlob) {
// const blobUrl = URL.createObjectURL(cachedModelBlob);
// return new Promise<Types.WallItem>((resolve) => {
// loader.load(blobUrl, (gltf) => {
// URL.revokeObjectURL(blobUrl);
// THREE.Cache.add(item.assetId!, gltf);
// resolve(processModel(gltf, item));
// });
// });
// }
// Load from original URL if not cached
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
return new Promise<Types.WallItem>((resolve) => {
loader.load(modelUrl, async (gltf) => {
try {
// Cache the model
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.assetId!, modelBlob);
THREE.Cache.add(item.assetId!, gltf);
resolve(processModel(gltf, item));
} catch (error) {
console.error("Failed to cache model:", error);
resolve(processModel(gltf, item));
}
});
});
})
);
// // Load from original URL if not cached
// const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
// return new Promise<Types.WallItem>((resolve) => {
// loader.load(modelUrl, async (gltf) => {
// try {
// // Cache the model
// const modelBlob = await fetch(modelUrl).then((res) => res.blob());
// await storeGLTF(item.assetId!, modelBlob);
// THREE.Cache.add(item.assetId!, gltf);
// resolve(processModel(gltf, item));
// } catch (error) {
// console.error("Failed to cache model:", error);
// resolve(processModel(gltf, item));
// }
// });
// });
// })
// );
setWallItems(loadedWallItems);
} catch (error) {
console.error("Failed to load wall items:", error);
}
}
// setWallItems(loadedWallItems);
// } catch (error) {
// console.error("Failed to load wall items:", error);
// }
// }
function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
const model = gltf.scene.clone();
model.uuid = item.modelUuid!;
// function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
// const model = gltf.scene.clone();
// model.uuid = item.modelUuid!;
model.children[0]?.children?.forEach((child: THREE.Object3D) => {
if (child.name !== "CSG_REF") {
child.castShadow = true;
child.receiveShadow = true;
}
});
// model.children[0]?.children?.forEach((child: THREE.Object3D) => {
// if (child.name !== "CSG_REF") {
// child.castShadow = true;
// child.receiveShadow = true;
// }
// });
return {
type: item.type,
model: model,
modelName: item.modelName,
assetId: item.assetId,
scale: item.scale,
csgscale: item.csgscale,
csgposition: item.csgposition,
position: item.position,
quaternion: item.quaternion,
};
}
// return {
// type: item.type,
// model: model,
// modelName: item.modelName,
// assetId: item.assetId,
// scale: item.scale,
// csgscale: item.csgscale,
// csgposition: item.csgposition,
// position: item.position,
// quaternion: item.quaternion,
// };
// }
export default loadInitialWallItems;
// export default loadInitialWallItems;

View File

@@ -23,7 +23,7 @@ const gltfLoaderWorker = new Worker(
)
);
function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) {
function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
const { activeModule } = useModuleStore();
const { socket } = useSocketStore();
const { controls, gl, pointer, camera, raycaster, scene } = useThree();

View File

@@ -1,109 +1,62 @@
////////// Three and React Three Fiber Imports //////////
import * as THREE from "three";
import { useEffect, useRef, useState } from "react";
import { useThree, useFrame } from "@react-three/fiber";
////////// Component Imports //////////
import DistanceText from "./geomentries/lines/distanceText/distanceText";
import ReferenceDistanceText from "./geomentries/lines/distanceText/referenceDistanceText";
import { useEffect, useRef } from "react";
import { useThree } from "@react-three/fiber";
import { Bvh } from "@react-three/drei";
////////// Zustand State Imports //////////
import {
useToggleView,
useActiveLayer,
useWallVisibility,
useRoofVisibility,
useShadows,
useUpdateScene,
useWalls,
useToolMode,
useRefTextUpdate,
useRenderDistance,
useLimitDistance,
} from "../../store/builder/store";
////////// 3D Function Imports //////////
import loadWalls from "./geomentries/walls/loadWalls";
import * as Types from "../../types/world/worldTypes";
import SocketResponses from "../collaboration/socket/socketResponses.dev";
import FloorPlanGroup from "./groups/floorPlanGroup";
// import FloorGroup from "./groups/floorGroup";
import Draw from "./functions/draw";
import WallsAndWallItems from "./groups/wallsAndWallItems";
import Ground from "../scene/environment/ground";
import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
import ZoneGroup from "./groups/zoneGroup";
import MeasurementTool from "../scene/tools/measurementTool";
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
import CalculateAreaGroup from "./groups/calculateAreaGroup";
import LayoutImage from "./layout/layoutImage";
import AssetsGroup from "./asset/assetsGroup";
import { Bvh } from "@react-three/drei";
import DxfFile from "./dfx/LoadBlueprint";
import { useParams } from "react-router-dom";
import AislesGroup from "./aisle/aislesGroup";
import WallGroup from "./wall/wallGroup";
import FloorGroup from "./floor/floorGroup";
import { useParams } from "react-router-dom";
import { useBuilderStore } from "../../store/builder/useBuilderStore";
import { getUserData } from "../../functions/getUserData";
import FloorGroup from "./floor/floorGroup";
export default function Builder() {
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
const scene = useRef() as Types.RefScene; // Reference to the scene.
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
// Assigning the scene and camera from the Three.js state to the references.
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // 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<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
const { toggleView } = useToggleView(); // State for toggling between 2D and 3D.
const { toolMode, setToolMode } = useToolMode();
const { setToolMode } = useToolMode();
const { setRoofVisibility } = useRoofVisibility();
const { setWallVisibility } = useWallVisibility();
const { setShadows } = useShadows();
const { setRenderDistance } = useRenderDistance();
const { setLimitDistance } = useLimitDistance();
const { setUpdateScene } = useUpdateScene();
const { setWalls } = useWalls();
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
const { projectId } = useParams();
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
const { userId, organization } = getUserData();
@@ -117,24 +70,11 @@ export default function Builder() {
////////// All Toggle's //////////
useEffect(() => {
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
if (toggleView) {
Layer2DVisibility(
activeLayer,
floorPlanGroup,
floorPlanGroupLine,
floorPlanGroupPoint,
currentLayerPoint,
dragPointControls
);
} else {
if (!toggleView) {
setHoveredLine(null);
setHoveredPoint(null);
state.gl.domElement.style.cursor = 'default';
setToolMode('cursor');
loadWalls(lines, setWalls);
setUpdateScene(true);
line.current = [];
}
}, [toggleView]);
@@ -153,60 +93,13 @@ export default function Builder() {
fetchVisibility();
}, []);
////////// UseFrame is Here //////////
useFrame(() => {
if (toolMode) {
Draw(
state,
plane,
cursorPosition,
floorPlanGroupPoint,
snappedPoint,
isSnapped,
isSnappedUUID,
line,
ispreSnapped,
floorPlanGroup,
ReferenceLineMesh,
LineCreated,
setRefTextUpdate,
Tube,
anglesnappedPoint,
isAngleSnapped,
toolMode
);
}
});
////////// Return //////////
return (
<>
<Ground grid={grid} plane={plane} />
<Bvh firstHitOnly>
{/* <DistanceText key={toggleView} /> */}
</Bvh>
<ReferenceDistanceText
key={refTextupdate}
line={ReferenceLineMesh.current}
/>
<Bvh firstHitOnly>
<SocketResponses
floorPlanGroup={floorPlanGroup}
lines={lines}
floorGroup={floorGroup}
scene={scene}
onlyFloorlines={onlyFloorlines}
currentLayerPoint={currentLayerPoint}
floorPlanGroupPoint={floorPlanGroupPoint}
floorPlanGroupLine={floorPlanGroupLine}
dragPointControls={dragPointControls}
/>
</Bvh>
<SocketResponses />
{/* <WallsAndWallItems
CSGGroup={CSGGroup}
@@ -220,43 +113,9 @@ export default function Builder() {
<Bvh firstHitOnly>
{/* <FloorGroup
floorGroup={floorGroup}
lines={lines}
referencePole={referencePole}
hoveredDeletablePillar={hoveredDeletablePillar}
/> */}
<FloorPlanGroup
floorPlanGroup={floorPlanGroup}
floorPlanGroupLine={floorPlanGroupLine}
floorPlanGroupPoint={floorPlanGroupPoint}
floorGroup={floorGroup}
currentLayerPoint={currentLayerPoint}
dragPointControls={dragPointControls}
hoveredDeletablePoint={hoveredDeletablePoint}
hoveredDeletableLine={hoveredDeletableLine}
plane={plane}
line={line}
lines={lines}
onlyFloorline={onlyFloorline}
onlyFloorlines={onlyFloorlines}
ReferenceLineMesh={ReferenceLineMesh}
LineCreated={LineCreated}
isSnapped={isSnapped}
ispreSnapped={ispreSnapped}
snappedPoint={snappedPoint}
isSnappedUUID={isSnappedUUID}
isAngleSnapped={isAngleSnapped}
anglesnappedPoint={anglesnappedPoint}
/>
<ZoneGroup />
<AssetsGroup
floorGroup={floorGroup}
plane={plane}
/>
<AssetsGroup plane={plane} />
<AislesGroup />
@@ -264,15 +123,9 @@ export default function Builder() {
<CalculateAreaGroup />
<NavMesh lines={lines} />
<NavMesh />
<DxfFile
lines={lines}
dragPointControls={dragPointControls}
currentLayerPoint={currentLayerPoint}
floorPlanGroupLine={floorPlanGroupLine}
floorPlanGroupPoint={floorPlanGroupPoint}
/>
<DxfFile />
<LayoutImage />
</Bvh>

View File

@@ -1,40 +1,21 @@
import { useEffect, useRef } from 'react';
import { useDfxUpload, useSocketStore, useToggleView, useUpdateScene } from '../../../store/builder/store';
import { LineBasicMaterial, Line } from 'three';
import loadInitialPoint from '../IntialLoad/loadInitialPoint';
import loadInitialLine from '../IntialLoad/loadInitialLine';
import { TransformControls } from '@react-three/drei';
import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBlueprint';
import * as Types from '../../../types/world/worldTypes';
import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject';
import { useParams } from 'react-router-dom';
import { getUserData } from '../../../functions/getUserData';
import { useVersionContext } from '../version/versionContext';
// Interface defining the props for the DxfFile component
interface DxfFileProps {
lines: Types.RefLines; // Reference to lines in the DXF file
floorPlanGroupPoint: Types.RefGroup; // Reference to floor plan points group
dragPointControls: Types.RefDragControl; // Reference to drag controls
floorPlanGroupLine: Types.RefGroup; // Reference to floor plan lines group
currentLayerPoint: Types.RefMeshArray; // Reference to current layer points
}
/**
* DxfFile component handles the rendering and manipulation of DXf file data in a 3D scene.
* It processes the DXF data to create points and lines representing walls and allows
* transformation controls for interactive editing.
*/
const DxfFile = ({
floorPlanGroupPoint,
currentLayerPoint,
dragPointControls,
floorPlanGroupLine,
lines,
}: DxfFileProps) => {
const DxfFile = () => {
// State management hooks
const { dfxuploaded, dfxWallGenerate, setObjValue, objValue } = useDfxUpload();
const { setUpdateScene } = useUpdateScene();
const { toggleView } = useToggleView();
const { socket } = useSocketStore();
const { selectedVersionStore } = useVersionContext();
@@ -50,55 +31,34 @@ const DxfFile = ({
* Loads initial points and lines from the DXF data and updates the scene.
*/
useEffect(() => {
if (
dfxWallGenerate &&
dragPointControls &&
floorPlanGroupPoint &&
currentLayerPoint &&
floorPlanGroupLine
) {
if (dfxWallGenerate) {
// Store generated lines in ref
lines.current.push(...dfxWallGenerate);
dfxWallGenerate.map((line: any) => {
const lineData = arrayLineToObject(line as Types.Line);
// lines.current.push(...dfxWallGenerate);
// dfxWallGenerate.map((line: any) => {
// const lineData = arrayLineToObject(line as Types.Line);
//REST
// //REST
// setLine(organization, lineData.layer!, lineData.line!, lineData.type!);
// // setLine(organization, lineData.layer!, lineData.line!, lineData.type!);
//SOCKET
// //SOCKET
const input = {
organization,
layer: lineData.layer,
line: lineData.line,
type: lineData.type,
socketId: socket.id,
versionId: selectedVersion?.versionId || '',
projectId,
userId
}
// const input = {
// organization,
// layer: lineData.layer,
// line: lineData.line,
// type: lineData.type,
// socketId: socket.id,
// versionId: selectedVersion?.versionId || '',
// projectId,
// userId
// }
console.log('input: ', input);
socket.emit('v1:Line:create', input);
// socket.emit('v1:Line:create', input);
})
// Load initial points and lines from DXF data
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
loadInitialLine(floorPlanGroupLine, lines);
// Trigger scene update
setUpdateScene(true);
// })
}
}, [
lines,
floorPlanGroupLine,
floorPlanGroupPoint,
currentLayerPoint,
dragPointControls,
dfxWallGenerate,
]);
}, [dfxWallGenerate]);
/**
* Handles transformation changes for individual lines.

View File

@@ -1,100 +0,0 @@
import * as THREE from "three";
import { DragControls } from "three/examples/jsm/controls/DragControls";
import * as CONSTANTS from "../../../types/world/worldConstants";
import DragPoint from "../geomentries/points/dragPoint";
import * as Types from "../../../types/world/worldTypes";
// import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi';
import { Socket } from "socket.io-client";
import { getUserData } from "../../../functions/getUserData";
export default async function addDragControl(
dragPointControls: Types.RefDragControl,
currentLayerPoint: Types.RefMeshArray,
state: Types.ThreeState,
floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup,
lines: Types.RefLines,
onlyFloorlines: Types.RefOnlyFloorLines,
socket: Socket<any>,
projectId?: string,
versionId?: string
) {
////////// Dragging Point and also change the size to indicate during hover //////////
dragPointControls.current = new DragControls(
currentLayerPoint.current,
state.camera,
state.gl.domElement
);
dragPointControls.current.enabled = false;
const { userId, organization, email } = getUserData();
dragPointControls.current.addEventListener("drag", function (event) {
const object = event.object;
if (object.visible) {
(state.controls as any).enabled = false;
DragPoint(
event as any,
floorPlanGroupPoint,
floorPlanGroupLine,
state.scene,
lines,
onlyFloorlines
);
} else {
(state.controls as any).enabled = true;
}
});
dragPointControls.current.addEventListener("dragstart", function (event) { });
dragPointControls.current.addEventListener("dragend", async function (event) {
if (!dragPointControls.current) return;
//REST
// await updatePoint(
// organization,
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
// event.object.uuid,
// )
//SOCKET
const data = {
organization,
position: {
x: event.object.position.x,
y: 0.01,
z: event.object.position.z,
},
uuid: event.object.uuid,
socketId: socket.id,
versionId,
projectId,
userId,
};
socket.emit("v1:Line:update", data);
if (state.controls) {
(state.controls as any).enabled = true;
}
});
dragPointControls.current.addEventListener("hoveron", function (event: any) {
if ((event.object as Types.Mesh).name === "point") {
event.object.material.uniforms.uInnerColor.value.set(
event.object.userData.color
);
}
});
dragPointControls.current.addEventListener("hoveroff", function (event: any) {
if ((event.object as Types.Mesh).name === "point") {
event.object.material.uniforms.uInnerColor.value.set(
new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor)
);
}
});
}

View File

@@ -1,8 +0,0 @@
import * as Types from "../../../types/world/worldTypes";
export default function handleContextMenu(
menuVisible: Types.Boolean,
setMenuVisible: Types.BooleanState
): void {
// setMenuVisible(true)
}

View File

@@ -1,61 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../types/world/worldTypes";
function handleMeshDown(
event: Types.MeshEvent,
currentWallItem: Types.RefMesh,
setSelectedWallItem: Types.setSelectedWallItemSetState,
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState,
wallItems: Types.wallItems,
toggleView: Types.Boolean
): void {
////////// To select which of the Wall item and CSG is selected to be dragged //////////
if (!toggleView) {
if (currentWallItem.current) {
currentWallItem.current.children.forEach((child) => {
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
const material = (child as THREE.Mesh).material;
if (Array.isArray(material)) {
material.forEach(mat => {
if (mat instanceof THREE.MeshStandardMaterial) {
mat.emissive = new THREE.Color("black");
}
});
} else if (material instanceof THREE.MeshStandardMaterial) {
material.emissive = new THREE.Color("black");
}
}
});
currentWallItem.current = null;
setSelectedWallItem(null);
setSelectedItemsIndex(null);
}
if (event.intersections.length > 0) {
if (event.object) {
const wallItemModel = event.object;
let currentObject = wallItemModel as THREE.Object3D;
while (currentObject) {
if (currentObject.name === "Scene") {
break;
}
currentObject = currentObject.parent as THREE.Object3D;
}
if (!currentObject) return;
const clickedIndex = wallItems.findIndex((item) => item.model?.uuid === currentObject.uuid);
if (clickedIndex !== -1) {
setSelectedItemsIndex(clickedIndex);
const wallItemModel = wallItems[clickedIndex]?.model;
if (wallItemModel) {
setSelectedWallItem(wallItemModel);
}
}
}
}
}
}
export default handleMeshDown;

View File

@@ -1,34 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../types/world/worldTypes";
function handleMeshMissed(
currentWallItem: Types.RefMesh,
setSelectedWallItem: Types.setSelectedWallItemSetState,
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState
): void {
////////// If an item is selected and then clicked outside other than the selected object, this runs and removes the color of the selected object and sets setSelectedWallItem and setSelectedItemsIndex as null //////////
if (currentWallItem.current) {
currentWallItem.current.children.forEach((child) => {
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
const material = (child as THREE.Mesh).material;
if (Array.isArray(material)) {
material.forEach(mat => {
if (mat instanceof THREE.MeshStandardMaterial) {
mat.emissive = new THREE.Color("black");
}
});
} else if (material instanceof THREE.MeshStandardMaterial) {
material.emissive = new THREE.Color("black");
}
}
});
currentWallItem.current = null;
setSelectedWallItem(null);
setSelectedItemsIndex(null);
}
}
export default handleMeshMissed;

View File

@@ -1,87 +0,0 @@
import * as THREE from 'three';
import * as CONSTANTS from '../../../types/world/worldConstants';
import * as Types from "../../../types/world/worldTypes";
function DeletableLineorPoint(
state: Types.ThreeState,
plane: Types.RefMesh,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup,
hoveredDeletableLine: Types.RefMesh,
hoveredDeletablePoint: Types.RefMesh
): void {
////////// Altering the color of the hovered line or point during the deletion time //////////
if (!plane.current) return;
let intersects = state.raycaster.intersectObject(plane.current, true);
let visibleIntersectLines;
if (floorPlanGroupLine.current) { visibleIntersectLines = state.raycaster?.intersectObjects(floorPlanGroupLine.current.children, true); }
const visibleIntersectLine = visibleIntersectLines?.find(intersect => intersect.object.visible) as THREE.Line | undefined || null;
let visibleIntersectPoints;
if (floorPlanGroupPoint.current) {
visibleIntersectPoints = state.raycaster?.intersectObjects(floorPlanGroupPoint.current.children, true);
}
const visibleIntersectPoint = visibleIntersectPoints?.find(intersect => intersect.object.visible) as THREE.Mesh | undefined;
function getLineColor(lineType: string | undefined): string {
switch (lineType) {
case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor;
case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor;
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor;
default: return CONSTANTS.lineConfig.defaultColor;
}
}
if (intersects.length > 0) {
if (visibleIntersectPoint) {
if (hoveredDeletableLine.current) {
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
const color = getLineColor(lineType);
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
hoveredDeletableLine.current = null;
}
hoveredDeletablePoint.current = (visibleIntersectPoint as any).object;
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(new THREE.Color("red"));
(hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set(new THREE.Color("red"));
// (hoveredDeletablePoint.current as THREE.Mesh).scale.set(1.5, 1.5, 1.5);
} else if (hoveredDeletablePoint.current) {
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
(hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set((hoveredDeletablePoint.current as any).userData.color);
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
hoveredDeletablePoint.current = null;
}
if (visibleIntersectLine && !visibleIntersectPoint) {
if (hoveredDeletableLine.current) {
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
const color = getLineColor(lineType);
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
hoveredDeletableLine.current = null;
}
if (hoveredDeletablePoint.current) {
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
(hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set((hoveredDeletablePoint.current as any).userData.color);
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
hoveredDeletablePoint.current = null;
}
hoveredDeletableLine.current = (visibleIntersectLine as any).object;
if (hoveredDeletableLine.current) {
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color("red");
}
} else if (hoveredDeletableLine.current) {
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
const color = getLineColor(lineType);
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
hoveredDeletableLine.current = null;
}
}
}
export default DeletableLineorPoint;

View File

@@ -1,93 +0,0 @@
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from '../../../types/world/worldConstants';
import createAndMoveReferenceLine from "../geomentries/lines/createAndMoveReferenceLine";
async function Draw(
state: Types.ThreeState,
plane: Types.RefMesh,
cursorPosition: Types.Vector3,
floorPlanGroupPoint: Types.RefGroup,
snappedPoint: Types.RefVector3,
isSnapped: Types.RefBoolean,
isSnappedUUID: Types.RefString,
line: Types.RefLine,
ispreSnapped: Types.RefBoolean,
floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean,
setRefTextUpdate: any,
Tube: Types.RefTubeGeometry,
anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean,
toolMode: Types.String,
): Promise<void> {
////////// Snapping the cursor during the drawing time and also changing the color of the intersected lines //////////
if (!plane.current) return;
const intersects = state.raycaster.intersectObject(plane.current, true);
if (intersects.length > 0 && (toolMode === "Wall" || toolMode === "Floor")) {
const intersectionPoint = intersects[0].point;
cursorPosition.copy(intersectionPoint);
const snapThreshold = 1;
if (line.current.length === 0) {
for (const point of floorPlanGroupPoint.current.children) {
const pointType = point.userData.type;
const canSnap =
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName))
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold + 0.5 && point.visible) {
cursorPosition.copy(point.position);
snappedPoint.current = point.position;
ispreSnapped.current = true;
isSnapped.current = false;
isSnappedUUID.current = point.uuid;
break;
} else {
ispreSnapped.current = false;
}
}
} else if (line.current.length > 0 && line.current[0]) {
for (const point of floorPlanGroupPoint.current.children) {
const pointType = point.userData.type;
let canSnap =
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName))
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold && point.visible) {
cursorPosition.copy(point.position);
snappedPoint.current = point.position;
isSnapped.current = true;
ispreSnapped.current = false;
isSnappedUUID.current = point.uuid;
break;
} else {
isSnapped.current = false;
}
}
createAndMoveReferenceLine(
line.current[0][0],
cursorPosition,
isSnapped,
ispreSnapped,
line,
setRefTextUpdate,
floorPlanGroup,
ReferenceLineMesh,
LineCreated,
Tube,
anglesnappedPoint,
isAngleSnapped
);
}
}
}
export default Draw;

View File

@@ -1,62 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import texturePath from "../../../../assets/textures/floor/white.png";
import texturePathDark from "../../../../assets/textures/floor/black.png";
// Cache for materials
const materialCache = new Map<string, THREE.Material>();
export default function addFloorToScene(
shape: THREE.Shape,
layer: number,
floorGroup: Types.RefGroup,
userData: any,
) {
const savedTheme: string | null = localStorage.getItem('theme');
const textureLoader = new THREE.TextureLoader();
const textureScale = CONSTANTS.floorConfig.textureScale;
const materialKey = `floorMaterial_${textureScale}`;
let material: THREE.Material;
if (materialCache.has(materialKey)) {
material = materialCache.get(materialKey) as THREE.Material;
} else {
const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath);
// const floorTexture = textureLoader.load(texturePath);
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(textureScale, textureScale);
floorTexture.colorSpace = THREE.SRGBColorSpace;
material = new THREE.MeshStandardMaterial({
map: floorTexture,
side: THREE.DoubleSide,
});
materialCache.set(materialKey, material);
}
const extrudeSettings = {
depth: CONSTANTS.floorConfig.height,
bevelEnabled: false,
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const mesh = new THREE.Mesh(geometry, material);
mesh.receiveShadow = true;
mesh.position.y = (layer) * CONSTANTS.wallConfig.height;
mesh.rotateX(Math.PI / 2);
mesh.name = `Floor_Layer_${layer}`;
// Store UUIDs for debugging or future processing
mesh.userData.uuids = userData;
floorGroup.current.add(mesh);
}

View File

@@ -1,275 +0,0 @@
import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import addPointToScene from "../points/addPointToScene";
import addLineToScene from "../lines/addLineToScene";
import splitLine from "../lines/splitLine";
import removeReferenceLine from "../lines/removeReferenceLine";
import getClosestIntersection from "../lines/getClosestIntersection";
import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject";
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
import { Socket } from "socket.io-client";
import { getUserData } from "../../../../functions/getUserData";
async function drawOnlyFloor(
raycaster: THREE.Raycaster,
state: Types.ThreeState,
camera: THREE.Camera,
plane: Types.RefMesh,
floorPlanGroupPoint: Types.RefGroup,
snappedPoint: Types.RefVector3,
isSnapped: Types.RefBoolean,
isSnappedUUID: Types.RefString,
line: Types.RefLine,
ispreSnapped: Types.RefBoolean,
anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean,
onlyFloorline: Types.RefOnlyFloorLine,
onlyFloorlines: Types.RefOnlyFloorLines,
lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean,
currentLayerPoint: Types.RefMeshArray,
dragPointControls: Types.RefDragControl,
setNewLines: any,
setDeletedLines: any,
activeLayer: Types.Number,
socket: Socket<any>,
projectId?: string,
versionId?: string,
): Promise<void> {
////////// Creating lines Based on the positions clicked //////////
if (!plane.current) return;
const { userId, organization, email } = getUserData();
const intersects = raycaster.intersectObject(plane.current, true);
const intersectsLines = raycaster.intersectObjects(
floorPlanGroupLine.current.children,
true
);
const intersectsPoint = raycaster.intersectObjects(
floorPlanGroupPoint.current.children,
true
);
const VisibleintersectsPoint = intersectsPoint.find(
(intersect) => intersect.object.visible
);
const visibleIntersect = intersectsLines.find(
(intersect) =>
intersect.object.visible &&
intersect.object.name !== CONSTANTS.lineConfig.referenceName
);
if (
(intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) &&
intersectsLines.length > 0 &&
!isSnapped.current &&
!ispreSnapped.current
) {
////////// Clicked on a preexisting Line //////////
if (
visibleIntersect &&
(intersectsLines[0].object.userData.linePoints[0][3] ===
CONSTANTS.lineConfig.floorName ||
intersectsLines[0].object.userData.linePoints[0][3] ===
CONSTANTS.lineConfig.wallName)
) {
let pointColor, lineColor;
if (
intersectsLines[0].object.userData.linePoints[0][3] ===
CONSTANTS.lineConfig.wallName
) {
pointColor = CONSTANTS.pointConfig.wallOuterColor;
lineColor = CONSTANTS.lineConfig.wallColor;
} else {
pointColor = CONSTANTS.pointConfig.floorOuterColor;
lineColor = CONSTANTS.lineConfig.floorColor;
}
let IntersectsPoint = new THREE.Vector3(
intersects[0].point.x,
0.01,
intersects[0].point.z
);
if (
isAngleSnapped.current &&
line.current.length > 0 &&
anglesnappedPoint.current
) {
IntersectsPoint = anglesnappedPoint.current;
}
if (visibleIntersect.object instanceof THREE.Mesh) {
const ThroughPoint =
visibleIntersect.object.geometry.parameters.path.getPoints(
CONSTANTS.lineConfig.lineIntersectionPoints
);
let intersectionPoint = getClosestIntersection(
ThroughPoint,
IntersectsPoint
);
if (intersectionPoint) {
const newLines = splitLine(
visibleIntersect,
intersectionPoint,
currentLayerPoint,
floorPlanGroupPoint,
dragPointControls,
isSnappedUUID,
lines,
setDeletedLines,
floorPlanGroupLine,
socket,
pointColor,
lineColor,
intersectsLines[0].object.userData.linePoints[0][3],
projectId
);
setNewLines([newLines[0], newLines[1]]);
(line.current as Types.Line).push([
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
isSnappedUUID.current!,
activeLayer,
CONSTANTS.lineConfig.floorName,
]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
lines.current.push(line.current as Types.Line);
const data = arrayLineToObject(line.current as Types.Line);
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id,
projectId,
versionId,
userId,
};
console.log('input: ', input);
socket.emit("v1:Line:create", input);
setNewLines([newLines[0], newLines[1], line.current]);
onlyFloorline.current.push(line.current as Types.Line);
onlyFloorlines.current.push(onlyFloorline.current);
onlyFloorline.current = [];
addLineToScene(
line.current[0][0],
line.current[1][0],
CONSTANTS.lineConfig.floorColor,
line.current,
floorPlanGroupLine
);
removeReferenceLine(
floorPlanGroup,
ReferenceLineMesh,
LineCreated,
line
);
}
return;
}
}
}
}
if (intersects.length > 0 && intersectsLines.length === 0) {
////////// Clicked on an empty place or a point //////////
let intersectionPoint = intersects[0].point;
if (
isAngleSnapped.current &&
line.current.length > 0 &&
anglesnappedPoint.current
) {
intersectionPoint = anglesnappedPoint.current;
}
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
intersectionPoint = snappedPoint.current;
}
if (ispreSnapped.current && snappedPoint.current) {
intersectionPoint = snappedPoint.current;
}
if (!isSnapped.current && !ispreSnapped.current) {
addPointToScene(
intersectionPoint,
CONSTANTS.pointConfig.floorOuterColor,
currentLayerPoint,
floorPlanGroupPoint,
dragPointControls,
isSnappedUUID,
CONSTANTS.lineConfig.floorName
);
} else {
ispreSnapped.current = false;
isSnapped.current = false;
}
(line.current as Types.Line).push([
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
isSnappedUUID.current!,
activeLayer,
CONSTANTS.lineConfig.floorName,
]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
onlyFloorline.current.push(line.current as Types.Line);
lines.current.push(line.current as Types.Line);
const data = arrayLineToObject(line.current as Types.Line);
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id,
versionId,
projectId,
userId,
};
console.log('input: ', input);
socket.emit("v1:Line:create", input);
setNewLines([line.current]);
addLineToScene(
line.current[0][0],
line.current[1][0],
CONSTANTS.lineConfig.floorColor,
line.current,
floorPlanGroupLine
);
const lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint];
}
if (isSnapped.current) {
////////// Add this to stop the drawing mode after snapping //////////
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
onlyFloorlines.current.push(onlyFloorline.current);
onlyFloorline.current = [];
}
}
}
export default drawOnlyFloor;

View File

@@ -1,50 +0,0 @@
import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import addRoofToScene from '../roofs/addRoofToScene';
import * as Types from "../../../../types/world/worldTypes";
import loadOnlyFloors from './loadOnlyFloors';
import addFloorToScene from './addFloorToScene';
import getRoomsFromLines from '../lines/getRoomsFromLines';
async function loadFloor(
lines: Types.RefLines,
floorGroup: Types.RefGroup,
): Promise<void> {
if (!floorGroup.current) return;
floorGroup.current.children = [];
if (lines.current.length > 2) {
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
const layer = pair[0][2];
if (!acc[layer]) acc[layer] = [];
acc[layer].push(pair);
return acc;
}, {});
for (const layer in linesByLayer) {
// Only Floor Polygons
loadOnlyFloors(floorGroup, linesByLayer, layer);
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
rooms.forEach(({ coordinates: room, layer }) => {
const userData = room.map(point => point.uuid);
const shape = new THREE.Shape();
shape.moveTo(room[0].position.x, room[0].position.z);
room.forEach(point => shape.lineTo(point.position.x, point.position.z));
shape.closePath();
// Floor Polygons
addFloorToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, floorGroup, userData);
// Roof Polygons
addRoofToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, userData, floorGroup);
});
}
}
}
export default loadFloor;

View File

@@ -1,183 +0,0 @@
import * as THREE from 'three';
import * as turf from '@turf/turf';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
function loadOnlyFloors(
floorGroup: Types.RefGroup,
linesByLayer: any,
layer: any,
): void {
////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well //////////
let floorsInLayer = linesByLayer[layer];
floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName);
const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
pair.map((point) => ({
position: [point[0].x, point[0].z],
uuid: point[1]
}))
);
const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position)));
function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) {
const floorpolygons = [];
const connectedLines = [];
const unprocessedLines = [...FloorLineFeatures]; // Copy the features
while (unprocessedLines.length > 0) {
const currentLine = unprocessedLines.pop();
const coordinates = currentLine.geometry.coordinates;
// Check if the line is closed (forms a polygon)
if (
coordinates[0][0] === coordinates[coordinates.length - 1][0] &&
coordinates[0][1] === coordinates[coordinates.length - 1][1]
) {
floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon
continue;
}
// Check if the line connects to another line
let connected = false;
for (let i = unprocessedLines.length - 1; i >= 0; i--) {
const otherCoordinates = unprocessedLines[i].geometry.coordinates;
// Check if lines share a start or end point
if (
coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] &&
coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1]
) {
// Merge lines
const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)];
unprocessedLines[i] = turf.lineString(mergedCoordinates);
connected = true;
break;
} else if (
coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] &&
coordinates[coordinates.length - 1][1] === otherCoordinates[0][1]
) {
// Merge lines
const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)];
unprocessedLines[i] = turf.lineString(mergedCoordinates);
connected = true;
break;
}
}
if (!connected) {
connectedLines.push(currentLine); // Add unconnected line as-is
}
}
return { floorpolygons, connectedLines };
}
const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures);
function convertConnectedLinesToPolygons(connectedLines: any) {
return connectedLines.map((line: any) => {
const coordinates = line.geometry.coordinates;
// If the line has more than two points, close the polygon
if (coordinates.length > 2) {
const firstPoint = coordinates[0];
const lastPoint = coordinates[coordinates.length - 1];
// Check if already closed; if not, close it
if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) {
coordinates.push(firstPoint);
}
// Convert the closed line into a polygon
return turf.polygon([coordinates]);
}
// If not enough points for a polygon, return the line unchanged
return line;
});
}
const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines);
if (convertedConnectedPolygons.length > 0) {
const validPolygons = convertedConnectedPolygons.filter(
(polygon: any) => polygon.geometry?.type === "Polygon"
);
if (validPolygons.length > 0) {
floorpolygons.push(...validPolygons);
}
}
function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) {
return floorpolygons.map((polygon: any) => {
const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon)
// Map each coordinate back to its original structure
const mappedPoints = coordinates.map((coord: [number, number]) => {
const [x, z] = coord;
// Find the original point matching this coordinate
const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z);
if (!originalPoint) {
console.error(`Original point for coordinate [${x}, ${z}] not found.`);
}
return originalPoint;
});
// Create pairs of consecutive points
const pairs: typeof originalLines = [];
for (let i = 0; i < mappedPoints.length - 1; i++) {
pairs.push([mappedPoints[i], mappedPoints[i + 1]]);
}
return pairs;
});
}
const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer);
convertedFloorPolygons.forEach((floor) => {
const points: THREE.Vector3[] = [];
floor.forEach((lineSegment) => {
const startPoint = lineSegment[0][0];
points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z));
});
const lastLine = floor[floor.length - 1];
const endPoint = lastLine[1][0];
points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z));
const shape = new THREE.Shape();
shape.moveTo(points[0].x, points[0].z);
points.forEach(point => shape.lineTo(point.x, point.z));
shape.closePath();
const extrudeSettings = {
depth: CONSTANTS.floorConfig.height,
bevelEnabled: false
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height;
mesh.rotateX(Math.PI / 2);
mesh.name = `Only_Floor_Line_${floor[0][0][2]}`;
mesh.userData = floor;
floorGroup?.current?.add(mesh);
});
}
export default loadOnlyFloors;

View File

@@ -1,24 +0,0 @@
import * as Types from "../../../../types/world/worldTypes";
function updateFloorLines(
onlyFloorlines: Types.RefOnlyFloorLines,
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 }
): void {
////////// Update onlyFloorlines.current if it contains the dragged point //////////
onlyFloorlines.current.forEach((floorline) => {
floorline.forEach((line) => {
line.forEach((point) => {
const [position, uuid] = point;
if (uuid === DragedPoint.uuid) {
position.x = DragedPoint.position.x;
position.y = 0.01;
position.z = DragedPoint.position.z;
}
});
});
});
}
export default updateFloorLines;

View File

@@ -1,104 +0,0 @@
import { toast } from "react-toastify";
import RemoveConnectedLines from "../lines/removeConnectedLines";
import * as Types from "../../../../types/world/worldTypes";
import { Socket } from "socket.io-client";
import { getUserData } from "../../../../functions/getUserData";
// import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi';
async function DeleteLayer(
removedLayer: Types.Number,
lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup,
onlyFloorlines: Types.RefOnlyFloorLines,
floorGroup: Types.RefGroup,
setDeletedLines: any,
setRemovedLayer: Types.setRemoveLayerSetState,
socket: Socket<any>,
projectId?: string,
versionId?: string,
): Promise<void> {
////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer //////////
const removedLines: Types.Lines = lines.current.filter(
(line) => line[0][2] === removedLayer
);
const { userId, organization } = getUserData();
//REST
// await deleteLayer(organization, removedLayer);
//SOCKET
const data = {
organization,
layer: removedLayer,
socketId: socket.id,
versionId,
projectId,
userId,
};
socket.emit("v1:Line:delete:layer", data);
////////// Remove Points and lines from the removed layer //////////
removedLines.forEach((line) => {
line.forEach((removedPoint) => {
RemoveConnectedLines(
removedPoint[1],
floorPlanGroupLine,
floorPlanGroupPoint,
setDeletedLines,
lines
);
});
});
////////// Update the remaining lines layer values in the userData and in lines.current //////////
let remaining = lines.current.filter((line) => line[0][2] !== removedLayer);
let updatedLines: Types.Lines = [];
remaining.forEach((line) => {
let newLines: Types.Line = [...line];
if (newLines[0][2] > removedLayer) {
newLines[0][2] -= 1;
newLines[1][2] -= 1;
}
const matchingLine = floorPlanGroupLine.current.children.find(
(l) =>
l.userData.linePoints[0][1] === line[0][1] &&
l.userData.linePoints[1][1] === line[1][1]
);
if (matchingLine) {
const updatedUserData = matchingLine.userData;
updatedUserData.linePoints[0][2] = newLines[0][2];
updatedUserData.linePoints[1][2] = newLines[1][2];
}
updatedLines.push(newLines);
});
lines.current = updatedLines;
localStorage.setItem("Lines", JSON.stringify(lines.current));
////////// Also remove OnlyFloorLines and update it in localstorage //////////
onlyFloorlines.current = onlyFloorlines.current.filter((floor) => {
return floor[0][0][2] !== removedLayer;
});
const meshToRemove: any = floorGroup.current?.children.find(
(mesh) => mesh.name === `Only_Floor_Line_${removedLayer}`
);
if (meshToRemove) {
(<any>meshToRemove.material).dispose();
(<any>meshToRemove.geometry).dispose();
floorGroup.current?.remove(meshToRemove);
}
echo.success("Layer Removed!");
setRemovedLayer(null);
}
export default DeleteLayer;

View File

@@ -1,35 +0,0 @@
import * as Types from "../../../../types/world/worldTypes";
function Layer2DVisibility(
activeLayer: Types.Number,
floorPlanGroup: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup,
currentLayerPoint: Types.RefMeshArray,
dragPointControls: Types.RefDragControl
): void {
if (floorPlanGroup.current && dragPointControls.current) {
currentLayerPoint.current = [];
floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints;
const point1 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[0][1]) as Types.Mesh;
const point2 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[1][1]) as Types.Mesh;
if (linePoints[0][2] !== activeLayer && linePoints[1][2] !== activeLayer) {
point1.visible = false;
point2.visible = false;
line.visible = false;
} else {
point1.visible = true;
point2.visible = true;
line.visible = true;
currentLayerPoint.current.push(point1, point2);
}
});
dragPointControls.current!.objects = currentLayerPoint.current;
}
}
export default Layer2DVisibility;

View File

@@ -1,24 +0,0 @@
import * as THREE from "three";
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
function addLineToScene(
start: Types.Vector3,
end: Types.Vector3,
colour: Types.Color,
userData: Types.UserData,
floorPlanGroupLine: Types.RefGroup
): void {
////////// A function that creates and adds lines based on the start, end, and colour from the params, Also adds the userData in the mesh userData //////////
const path = new THREE.CatmullRomCurve3([start, end]);
const geometry = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
const material = new THREE.MeshBasicMaterial({ color: colour });
const mesh = new THREE.Mesh(geometry, material);
floorPlanGroupLine.current.add(mesh);
mesh.userData.linePoints = userData;
}
export default addLineToScene;

View File

@@ -1,98 +0,0 @@
import * as THREE from "three";
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
function createAndMoveReferenceLine(
point: Types.Vector3,
cursorPosition: Types.Vector3,
isSnapped: Types.RefBoolean,
ispreSnapped: Types.RefBoolean,
line: Types.RefLine,
setRefTextUpdate: Types.NumberIncrementState,
floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean,
Tube: Types.RefTubeGeometry,
anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean
): void {
////////// Creating new and maintaining the old reference line and also snap the reference line based on its angle //////////
const startPoint = point;
const dx = cursorPosition.x - startPoint.x;
const dz = cursorPosition.z - startPoint.z;
let angle = Math.atan2(dz, dx);
angle = (angle * 180) / Math.PI;
angle = (angle + 360) % 360;
const snapAngles = [0, 90, 180, 270, 360];
const snapThreshold = 2.5;
const closestSnapAngle = snapAngles.reduce((prev, curr) =>
Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev
);
if (!isSnapped.current && !ispreSnapped.current && line.current.length > 0) {
if (Math.abs(closestSnapAngle - angle) <= snapThreshold) {
const snappedAngleRad = (closestSnapAngle * Math.PI) / 180;
const distance = Math.sqrt(dx * dx + dz * dz);
const snappedX = startPoint.x + distance * Math.cos(snappedAngleRad);
const snappedZ = startPoint.z + distance * Math.sin(snappedAngleRad);
if (
cursorPosition.distanceTo(
new THREE.Vector3(snappedX, 0.01, snappedZ)
) < 2
) {
cursorPosition.set(snappedX, 0.01, snappedZ);
isAngleSnapped.current = true;
anglesnappedPoint.current = new THREE.Vector3(
snappedX,
0.01,
snappedZ
);
} else {
isAngleSnapped.current = false;
anglesnappedPoint.current = null;
}
} else {
isAngleSnapped.current = false;
anglesnappedPoint.current = null;
}
} else {
isAngleSnapped.current = false;
anglesnappedPoint.current = null;
}
if (!LineCreated.current) {
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
const path = new THREE.LineCurve3(startPoint, cursorPosition);
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
const material = new THREE.MeshBasicMaterial({ color: CONSTANTS.lineConfig.helperColor });
ReferenceLineMesh.current = new THREE.Mesh(Tube.current, material);
ReferenceLineMesh.current.name = CONSTANTS.lineConfig.referenceName;
ReferenceLineMesh.current.userData = {
linePoints: { startPoint, cursorPosition },
};
floorPlanGroup.current?.add(ReferenceLineMesh.current);
LineCreated.current = true;
} else {
if (ReferenceLineMesh.current) {
const path = new THREE.LineCurve3(startPoint, new THREE.Vector3(cursorPosition.x, 0.01, cursorPosition.z));
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
if (ReferenceLineMesh.current) {
ReferenceLineMesh.current.userData = {
linePoints: { startPoint, cursorPosition },
};
ReferenceLineMesh.current.geometry.dispose();
ReferenceLineMesh.current.geometry = Tube.current;
}
}
}
}
export default createAndMoveReferenceLine;

View File

@@ -1,92 +0,0 @@
import { Socket } from "socket.io-client";
// import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi";
import * as Types from "../../../../types/world/worldTypes";
import { toast } from "react-toastify";
import { getUserData } from "../../../../functions/getUserData";
function deleteLine(
hoveredDeletableLine: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines,
lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup,
setDeletedLines: any,
socket: Socket<any>,
projectId?: string,
versionId?: string,
): void {
const { userId, organization, email } = getUserData();
////////// Deleting a line and the points if they are not connected to any other line //////////
if (!hoveredDeletableLine.current) {
return;
}
const linePoints = hoveredDeletableLine.current.userData.linePoints;
const connectedpoints = [linePoints[0][1], linePoints[1][1]];
//REST
// deleteLineApi(
// organization,
// [
// { "uuid": linePoints[0][1] },
// { "uuid": linePoints[1][1] }
// ]
// )
//SOCKET
const data = {
organization,
line: [{ uuid: linePoints[0][1] }, { uuid: linePoints[1][1] }],
socketId: socket.id,
versionId,
projectId,
userId,
};
socket.emit("v1:Line:delete", data);
onlyFloorlines.current = onlyFloorlines.current
.map((floorline) =>
floorline.filter(
(line) =>
line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1]
)
)
.filter((floorline) => floorline.length > 0);
lines.current = lines.current.filter((item) => item !== linePoints);
(<any>hoveredDeletableLine.current.material).dispose();
(<any>hoveredDeletableLine.current.geometry).dispose();
floorPlanGroupLine.current.remove(hoveredDeletableLine.current);
setDeletedLines([linePoints]);
connectedpoints.forEach((pointUUID) => {
let isConnected = false;
floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints;
const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1];
if (uuid1 === pointUUID || uuid2 === pointUUID) {
isConnected = true;
}
});
if (!isConnected) {
floorPlanGroupPoint.current.children.forEach((point: any) => {
if (point.uuid === pointUUID) {
(<any>point.material).dispose();
(<any>point.geometry).dispose();
floorPlanGroupPoint.current.remove(point);
}
});
}
});
echo.success("Line Removed!");
}
export default deleteLine;

View File

@@ -1,226 +0,0 @@
import { useEffect, useState } from "react";
import { getLines } from "../../../../../services/factoryBuilder/lines/getLinesApi";
import * as THREE from "three";
import {
useActiveLayer,
useDeletedLines,
useNewLines,
useRoomsState,
useToggleView,
} from "../../../../../store/builder/store";
import objectLinesToArray from "../lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei";
import { Vector2 } from "three";
import * as Types from "../../../../../types/world/worldTypes";
import getRoomsFromLines from "../getRoomsFromLines";
import * as turf from '@turf/turf';
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../../functions/getUserData";
import { useVersionContext } from "../../../version/versionContext";
const DistanceText = () => {
const [lines, setLines] = useState<
{
distance: string;
position: THREE.Vector3;
userData: Types.Line;
layer: string;
}[]
>([]);
const { activeLayer } = useActiveLayer();
const { toggleView } = useToggleView();
const { newLines, setNewLines } = useNewLines();
const { deletedLines, setDeletedLines } = useDeletedLines();
const [linesState, setLinesState] = useState<Types.Lines>([]);
const { roomsState, setRoomsState } = useRoomsState();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { organization, email } = getUserData();
useEffect(() => {
if (linesState.length === 0) return;
const getLines = async () => {
const points3D = linesState.map(line => {
const startPoint = line[0][0]; // First point of each wall line
return [startPoint.x, 0, startPoint.z];
});
// Ensure the polygon is closed
if (
points3D[0][0] !== points3D[points3D.length - 1][0] ||
points3D[0][1] !== points3D[points3D.length - 1][1]
) {
points3D.push(points3D[0]);
}
// Convert to 2D for turf (x, z)
const coords2D = points3D.map(p => [p[0], p[1]]);
const projected = points3D.map((p: any) => new Vector2(p[0], p[1]));
// Shoelace formula for 2D polygon
let area = 0;
const n = projected.length;
for (let i = 0; i < n - 1; i++) {
const curr = projected[i];
const next = projected[i + 1];
area += curr.x * next.y - next.x * curr.y;
}
// return Math.abs(area) / 2;
// Build polygon and compute area
// const polygon = turf.polygon([coords2D]);
// const area = turf.area(polygon);
// const area = computeAreaFrom3DPoints(coords2D)
//
if (lines.length > 2) {
const linesByLayer = linesState.reduce((acc: { [key: number]: any[] }, pair) => {
const layer = pair[0][2];
if (!acc[layer]) acc[layer] = [];
acc[layer].push(pair);
return acc;
}, {});
for (const layer in linesByLayer) {
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
setRoomsState(rooms)
}
}
}
getLines();
}, [linesState, roomsState])
useEffect(() => {
if (!email || !selectedVersion) return;
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
data = objectLinesToArray(data);
setLinesState(data);
const lines = data
.filter((line: Types.Line) => line[0][2] === activeLayer)
.map((line: Types.Line) => {
const point1 = new THREE.Vector3(
line[0][0].x,
line[0][0].y,
line[0][0].z
);
const point2 = new THREE.Vector3(
line[1][0].x,
line[1][0].y,
line[1][0].z
);
const distance = point1.distanceTo(point2);
const midpoint = new THREE.Vector3()
.addVectors(point1, point2)
.divideScalar(2);
return {
distance: distance.toFixed(1),
position: midpoint,
userData: line,
layer: activeLayer,
};
});
setLines(lines);
});
}, [activeLayer, selectedVersion?.versionId]);
useEffect(() => {
if (newLines.length > 0) {
if (newLines[0][0][2] !== activeLayer) return;
const newLinesData = newLines.map((line: Types.Line) => {
const point1 = new THREE.Vector3(
line[0][0].x,
line[0][0].y,
line[0][0].z
);
const point2 = new THREE.Vector3(
line[1][0].x,
line[1][0].y,
line[1][0].z
);
const distance = point1.distanceTo(point2);
const midpoint = new THREE.Vector3()
.addVectors(point1, point2)
.divideScalar(2);
return {
distance: distance.toFixed(1),
position: midpoint,
userData: line,
layer: activeLayer,
};
});
setLines((prevLines) => [...prevLines, ...newLinesData]);
setLinesState((prevLines) => [...prevLines, ...newLines]);
setNewLines([]);
}
}, [newLines, activeLayer]);
useEffect(() => {
if ((deletedLines as Types.Lines).length > 0) {
setLines((prevLines) =>
prevLines.filter(
(line) =>
!deletedLines.some(
(deletedLine: any) =>
deletedLine[0][1] === line.userData[0][1] &&
deletedLine[1][1] === line.userData[1][1]
)
)
);
setLinesState(prev =>
prev.filter(line =>
!(deletedLines as Types.Lines).some(
deleted =>
line[0][1] === deleted[0][1] && line[1][1] === deleted[1][1]
)
)
);
setDeletedLines([]);
setRoomsState([])
}
}, [deletedLines]);
return (
<>
{toggleView && (
<group name="Distance_Text">
{lines.map((text) => (
<Html
// data
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
userData={text.userData}
position={[text.position.x, 1, text.position.z]}
// class
wrapperClass="distance-text-wrapper"
className="distance-text"
// other
zIndexRange={[1, 0]}
prepend
sprite
>
<div
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
className={`distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`}
>
{text.distance} m
</div>
</Html>
))}
</group>
)}
</>
);
};
export default DistanceText;

View File

@@ -1,71 +0,0 @@
import * as THREE from "three";
import { Html } from "@react-three/drei";
import { useState, useEffect } from "react";
import { useActiveLayer } from "../../../../../store/builder/store";
const ReferenceDistanceText = ({ line }: { line: any }) => {
interface TextState {
distance: string;
position: THREE.Vector3;
userData: any;
layer: any;
}
const [text, setTexts] = useState<TextState | null>(null);
const { activeLayer } = useActiveLayer();
useEffect(() => {
if (line) {
if (line.parent === null) {
setTexts(null);
return;
}
const distance = line.userData.linePoints.cursorPosition.distanceTo(
line.userData.linePoints.startPoint
);
const midpoint = new THREE.Vector3()
.addVectors(
line.userData.linePoints.cursorPosition,
line.userData.linePoints.startPoint
)
.divideScalar(2);
const newTexts = {
distance: distance.toFixed(1),
position: midpoint,
userData: line,
layer: activeLayer,
};
setTexts(newTexts);
}
});
return (
<group name="Reference_Distance_Text">
<mesh>
{text !== null && (
<Html
// data
key={text.distance}
userData={text.userData}
position={[text.position.x, 1, text.position.z]}
// class
wrapperClass="distance-text-wrapper"
className="distance-text"
// other
zIndexRange={[1, 0]}
prepend
sprite
>
<div
className={`Reference_Distance line-${text.userData.userData}`}
>
{text.distance} m
</div>
</Html>
)}
</mesh>
</group>
);
};
export default ReferenceDistanceText;

View File

@@ -1,218 +0,0 @@
import * as THREE from "three";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import addPointToScene from "../points/addPointToScene";
import addLineToScene from "./addLineToScene";
import splitLine from "./splitLine";
import removeReferenceLine from "./removeReferenceLine";
import getClosestIntersection from "./getClosestIntersection";
import * as Types from "../../../../types/world/worldTypes";
import arrayLineToObject from "./lineConvertions/arrayLineToObject";
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
import { Socket } from "socket.io-client";
import { getUserData } from "../../../../functions/getUserData";
async function drawWall(
raycaster: THREE.Raycaster,
plane: Types.RefMesh,
floorPlanGroupPoint: Types.RefGroup,
snappedPoint: Types.RefVector3,
isSnapped: Types.RefBoolean,
isSnappedUUID: Types.RefString,
line: Types.RefLine,
ispreSnapped: Types.RefBoolean,
anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean,
lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean,
currentLayerPoint: Types.RefMeshArray,
dragPointControls: Types.RefDragControl,
setNewLines: any,
setDeletedLines: any,
activeLayer: Types.Number,
socket: Socket<any>,
projectId?: string,
versionId?: string,
): Promise<void> {
const { userId, organization } = getUserData();
////////// Creating lines Based on the positions clicked //////////
////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
if (!plane.current) return;
let intersects = raycaster.intersectObject(plane.current, true);
let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true);
const VisibleintersectsPoint = intersectsPoint.find((intersect) => intersect.object.visible);
const visibleIntersect = intersectsLines.find(
(intersect) =>
intersect.object.visible &&
intersect.object.name !== CONSTANTS.lineConfig.referenceName &&
intersect.object.userData.linePoints[0][3] ===
CONSTANTS.lineConfig.wallName
);
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
////////// Clicked on a preexisting Line //////////
if (visibleIntersect && intersects) {
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
if (isAngleSnapped.current && anglesnappedPoint.current) {
IntersectsPoint = anglesnappedPoint.current;
}
if (visibleIntersect.object instanceof THREE.Mesh) {
const ThroughPoint = visibleIntersect.object.geometry.parameters.path.getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint);
if (intersectionPoint) {
const newLines = splitLine(
visibleIntersect,
intersectionPoint,
currentLayerPoint,
floorPlanGroupPoint,
dragPointControls,
isSnappedUUID,
lines,
setDeletedLines,
floorPlanGroupLine,
socket,
CONSTANTS.pointConfig.wallOuterColor,
CONSTANTS.lineConfig.wallColor,
CONSTANTS.lineConfig.wallName,
projectId,
versionId
);
setNewLines([newLines[0], newLines[1]]);
(line.current as Types.Line).push([
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
isSnappedUUID.current!,
activeLayer,
CONSTANTS.lineConfig.wallName,
]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
const data = arrayLineToObject(line.current as Types.Line);
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id,
versionId,
projectId,
userId,
};
socket.emit("v1:Line:create", input);
setNewLines([newLines[0], newLines[1], line.current]);
lines.current.push(line.current as Types.Line);
addLineToScene(
line.current[0][0],
line.current[1][0],
CONSTANTS.lineConfig.wallColor,
line.current,
floorPlanGroupLine
);
let lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint];
}
return;
}
}
}
}
if (intersects && intersects.length > 0) {
////////// Clicked on a emply place or a point //////////
let intersectionPoint = intersects[0].point;
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
intersectionPoint = anglesnappedPoint.current;
}
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
intersectionPoint = snappedPoint.current;
}
if (ispreSnapped.current && snappedPoint.current) {
intersectionPoint = snappedPoint.current;
}
if (!isSnapped.current && !ispreSnapped.current) {
addPointToScene(
intersectionPoint,
CONSTANTS.pointConfig.wallOuterColor,
currentLayerPoint,
floorPlanGroupPoint,
dragPointControls,
isSnappedUUID,
CONSTANTS.lineConfig.wallName
);
} else {
ispreSnapped.current = false;
isSnapped.current = false;
}
(line.current as Types.Line).push([
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
isSnappedUUID.current!,
activeLayer,
CONSTANTS.lineConfig.wallName,
]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
const data = arrayLineToObject(line.current as Types.Line);
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id,
versionId,
projectId,
userId,
};
socket.emit("v1:Line:create", input);
setNewLines([line.current]);
lines.current.push(line.current as Types.Line);
addLineToScene(
line.current[0][0],
line.current[1][0],
CONSTANTS.lineConfig.wallColor,
line.current,
floorPlanGroupLine
);
let lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint];
}
if (isSnapped.current) {
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
}
}
}
export default drawWall;

View File

@@ -1,86 +0,0 @@
import * as THREE from 'three';
import * as turf from '@turf/turf';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
async function getRoomsFromLines(lines: Types.RefLines) {
const rooms: Types.Rooms = [];
if (lines.current.length > 2) {
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
const layer = pair[0][2];
if (!acc[layer]) acc[layer] = [];
acc[layer].push(pair);
return acc;
}, {});
////////// Use turf.polygonize to create polygons from the line points //////////
for (const layer in linesByLayer) {
let linesInLayer = linesByLayer[layer];
linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName);
const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
pair.map((point) => ({
position: [point[0].x, point[0].z],
uuid: point[1]
}))
);
const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
let union: any[] = [];
polygons.features.forEach((feature) => {
union.push(feature);
});
if (union.length > 1) {
const unionResult = turf.union(turf.featureCollection(union));
if (unionResult?.geometry.type === "MultiPolygon") {
unionResult?.geometry.coordinates.forEach((poly) => {
const Coordinates = poly[0].map(([x, z]) => {
const matchingPoint = result.flat().find(r =>
r.position[0].toFixed(10) === x.toFixed(10) &&
r.position[1].toFixed(10) === z.toFixed(10)
);
return {
position: new THREE.Vector3(x, 0, z),
uuid: matchingPoint ? matchingPoint.uuid : ''
};
});
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
});
} else if (unionResult?.geometry.type === "Polygon") {
const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => {
const matchingPoint = result.flat().find(r =>
r.position[0].toFixed(10) === x.toFixed(10) &&
r.position[1].toFixed(10) === z.toFixed(10)
);
return {
position: new THREE.Vector3(x, 0, z),
uuid: matchingPoint ? matchingPoint.uuid : ''
};
});
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
}
} else if (union.length === 1) {
const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => {
const matchingPoint = result.flat().find(r =>
r.position[0].toFixed(10) === x.toFixed(10) &&
r.position[1].toFixed(10) === z.toFixed(10)
);
return {
position: new THREE.Vector3(x, 0, z),
uuid: matchingPoint ? matchingPoint.uuid : ''
};
});
rooms.push({ coordinates: Coordinates, layer: parseInt(layer) });
}
}
}
return rooms;
}
export default getRoomsFromLines;

View File

@@ -1,24 +0,0 @@
import * as Types from "../../../../../types/world/worldTypes";
export default function arrayLineToObject(array: Types.Line) {
if (!Array.isArray(array)) {
return {};
}
// Extract common properties from the first point
const commonLayer = array[0][2];
const commonType = array[0][3];
// Map points into a structured format
const line = array.map(([position, uuid]) => ({
position,
uuid,
}));
// Create the final structured object
return {
layer: commonLayer,
type: commonType,
line,
};
}

View File

@@ -1,30 +0,0 @@
import * as Types from "../../../../../types/world/worldTypes";
export default function arrayLinesToObject(array: Array<Types.Line>) {
if (!Array.isArray(array)) {
return [];
}
return array.map((lineArray) => {
if (!Array.isArray(lineArray)) {
return null;
}
// Extract common properties from the first point
const commonLayer = lineArray[0][2];
const commonType = lineArray[0][3];
// Map points into a structured format
const line = lineArray.map(([position, uuid]) => ({
position,
uuid,
}));
// Create the final structured object
return {
layer: commonLayer,
type: commonType,
line,
};
}).filter((item) => item !== null); // Filter out invalid entries
}

View File

@@ -1,13 +0,0 @@
import * as THREE from 'three';
export default function objectLineToArray(structuredObject: any) {
if (!structuredObject || !structuredObject.line) {
return [];
}
// Destructure common properties
const { layer, type, line } = structuredObject;
// Map points back to the original array format
return line.map(({ position, uuid }: any) => [new THREE.Vector3(position.x, position.y, position.z), uuid, layer, type]);
}

View File

@@ -1,20 +0,0 @@
import * as THREE from 'three';
export default function objectLinesToArray(structuredObjects: any): any {
if (!Array.isArray(structuredObjects)) {
return [];
}
return structuredObjects.map((structuredObject) => {
if (!structuredObject || !structuredObject.line) {
return [];
}
const { layer, type, line } = structuredObject;
return line.map(({ position, uuid }: any) => {
const vector = new THREE.Vector3(position.x, position.y, position.z);
return [vector, uuid, layer, type];
});
});
}

View File

@@ -1,66 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function RemoveConnectedLines(
DeletedPointUUID: Types.String,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup,
setDeletedLines: any,
lines: Types.RefLines,
): void {
////////// Check if any and how many lines are connected to the deleted point //////////
const removableLines: THREE.Mesh[] = [];
const connectedpoints: string[] = [];
const removedLinePoints: [number, string, number][][] = []; // Array to hold linePoints of removed lines
floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints as [number, string, number][];
const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1];
if (uuid1 === DeletedPointUUID || uuid2 === DeletedPointUUID) {
connectedpoints.push(uuid1 === DeletedPointUUID ? uuid2 : uuid1);
removableLines.push(line as THREE.Mesh);
removedLinePoints.push(linePoints);
}
});
if (removableLines.length > 0) {
removableLines.forEach((line) => {
lines.current = lines.current.filter(item => item !== line.userData.linePoints);
(<any>line.material).dispose();
(<any>line.geometry).dispose();
floorPlanGroupLine.current.remove(line);
});
}
setDeletedLines(removedLinePoints)
////////// Check and Remove point that are no longer connected to any lines //////////
connectedpoints.forEach((pointUUID) => {
let isConnected = false;
floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints as [number, string, number][];
const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1];
if (uuid1 === pointUUID || uuid2 === pointUUID) {
isConnected = true;
}
});
if (!isConnected) {
floorPlanGroupPoint.current.children.forEach((point: any) => {
if (point.uuid === pointUUID) {
(<any>point.material).dispose();
(<any>point.geometry).dispose();
floorPlanGroupPoint.current.remove(point);
}
});
}
});
}
export default RemoveConnectedLines;

View File

@@ -1,22 +0,0 @@
import * as Types from "../../../../types/world/worldTypes";
function removeReferenceLine(
floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean,
line: Types.RefLine
): void {
////////// Removes Dangling reference line if the draw mode is ended or any other case //////////
line.current = [];
if (ReferenceLineMesh.current) {
(<any>ReferenceLineMesh.current.material).dispose();
(<any>ReferenceLineMesh.current.geometry).dispose();
floorPlanGroup.current.remove(ReferenceLineMesh.current);
LineCreated.current = false;
ReferenceLineMesh.current = undefined;
}
}
export default removeReferenceLine;

View File

@@ -1,153 +0,0 @@
import * as THREE from "three";
import addLineToScene from "./addLineToScene";
import addPointToScene from "../points/addPointToScene";
import * as Types from "../../../../types/world/worldTypes";
import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject";
import { Socket } from "socket.io-client";
import { getUserData } from "../../../../functions/getUserData";
// import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi';
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
function splitLine(
visibleIntersect: Types.IntersectionEvent,
intersectionPoint: Types.Vector3,
currentLayerPoint: Types.RefMeshArray,
floorPlanGroupPoint: Types.RefGroup,
dragPointControls: Types.RefDragControl,
isSnappedUUID: Types.RefString,
lines: Types.RefLines,
setDeletedLines: any,
floorPlanGroupLine: { current: THREE.Group },
socket: Socket<any>,
pointColor: Types.String,
lineColor: Types.String,
lineType: Types.String,
projectId?: string,
versionId?: string,
): [Types.Line, Types.Line] {
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
const { userId, organization, email } = getUserData();
(visibleIntersect.object as any).material.dispose();
(visibleIntersect.object as any).geometry.dispose();
floorPlanGroupLine.current.remove(visibleIntersect.object);
setDeletedLines([visibleIntersect.object.userData.linePoints]);
//REST
// deleteLineApi(
// organization,
// [
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
// ]
// )
//SOCKET
const data = {
organization,
line: [
{ uuid: visibleIntersect.object.userData.linePoints[0][1] },
{ uuid: visibleIntersect.object.userData.linePoints[1][1] },
],
socketId: socket.id,
versionId,
projectId,
userId,
};
socket.emit("v1:Line:delete", data);
const point = addPointToScene(
intersectionPoint,
pointColor,
currentLayerPoint,
floorPlanGroupPoint,
dragPointControls,
isSnappedUUID,
lineType
);
const oldLinePoints = visibleIntersect.object.userData.linePoints;
lines.current = lines.current.filter((item) => item !== oldLinePoints);
const clickedPoint: Types.Point = [
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
point.uuid,
oldLinePoints[0][2],
lineType,
];
const start = oldLinePoints[0];
const end = oldLinePoints[1];
const newLine1: Types.Line = [start, clickedPoint];
const newLine2: Types.Line = [clickedPoint, end];
const line1 = arrayLineToObject(newLine1);
const line2 = arrayLineToObject(newLine2);
//REST
// setLine(organization, line1.layer!, line1.line!, line1.type!);
//SOCKET
const input1 = {
organization,
layer: line1.layer,
line: line1.line,
type: line1.type,
socketId: socket.id,
versionId,
projectId,
userId,
};
console.log('input1: ', input1);
socket.emit("v1:Line:create", input1);
//REST
// setLine(organization, line2.layer!, line2.line!, line2.type!);
//SOCKET
const input2 = {
organization,
layer: line2.layer,
line: line2.line,
type: line2.type,
socketId: socket.id,
versionId,
projectId,
userId,
};
console.log('input2: ', input2);
socket.emit("v1:Line:create", input2);
lines.current.push(newLine1, newLine2);
addLineToScene(
newLine1[0][0],
newLine1[1][0],
lineColor,
newLine1,
floorPlanGroupLine
);
addLineToScene(
newLine2[0][0],
newLine2[1][0],
lineColor,
newLine2,
floorPlanGroupLine
);
return [newLine1, newLine2];
}
export default splitLine;

View File

@@ -1,42 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function updateDistanceText(
scene: THREE.Scene,
floorPlanGroupLine: Types.RefGroup,
affectedLines: Types.NumberArray
): void {
////////// Updating the Distance Texts of the lines that are affected during drag //////////
const DistanceGroup = scene.getObjectByName('Distance_Text') as THREE.Group;
affectedLines.forEach((lineIndex) => {
const mesh = floorPlanGroupLine.current.children[lineIndex] as THREE.Mesh;
const linePoints = mesh.userData.linePoints;
if (linePoints) {
const distance = linePoints[0][0].distanceTo(linePoints[1][0]).toFixed(1);
const position = new THREE.Vector3().addVectors(linePoints[0][0], linePoints[1][0]).divideScalar(2);
if (!DistanceGroup || !linePoints) {
return
}
DistanceGroup.children.forEach((text) => {
const textMesh = text as THREE.Mesh;
if (textMesh.userData[0][1] === linePoints[0][1] && textMesh.userData[1][1] === linePoints[1][1]) {
textMesh.position.set(position.x, 1, position.z);
const className = `distance line-${textMesh.userData[0][1]}_${textMesh.userData[1][1]}_${linePoints[0][2]}`;
const element = document.getElementsByClassName(className)[0] as HTMLElement;
if (element) {
element.innerHTML = `${distance} m`;
}
}
});
}
});
}
export default updateDistanceText;

View File

@@ -1,24 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from '../../../../types/world/worldConstants';
function updateLines(
floorPlanGroupLine: Types.RefGroup,
affectedLines: Types.NumberArray
): void {
////////// Updating the positions for the affected lines only based on the updated positions //////////
affectedLines.forEach((lineIndex) => {
const mesh = floorPlanGroupLine.current.children[lineIndex] as Types.Mesh;
const linePoints = mesh.userData.linePoints as Types.Line;
if (linePoints) {
const newPositions = linePoints.map(([pos]) => pos);
const newPath = new THREE.CatmullRomCurve3(newPositions);
mesh.geometry.dispose();
mesh.geometry = new THREE.TubeGeometry(newPath, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
}
});
}
export default updateLines;

View File

@@ -1,32 +0,0 @@
import * as Types from "../../../../types/world/worldTypes";
function updateLinesPositions(
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 },
lines: Types.RefLines
): Types.NumberArray {
////////// Updating the lines position based on the dragged point's position //////////
const objectUUID = DragedPoint.uuid;
const affectedLines: Types.NumberArray = [];
lines.current.forEach((line, index) => {
let lineUpdated = false;
line.forEach((point) => {
const [position, uuid] = point;
if (uuid === objectUUID) {
position.x = DragedPoint.position.x;
position.y = 0.01;
position.z = DragedPoint.position.z;
lineUpdated = true;
}
});
if (lineUpdated) {
affectedLines.push(index);
}
});
return affectedLines;
}
export default updateLinesPositions;

View File

@@ -1,18 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function vectorizeLinesCurrent(
lines: Types.Lines
): Types.Lines {
////////// Storing a vector3 array in localstorage makes the prototype functions go puff. This function brings back the prototype functions by creating it again //////////
return lines.map((line) => {
const p1: Types.Point = [new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), line[0][1], line[0][2], line[0][3],];
const p2: Types.Point = [new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), line[1][1], line[0][2], line[1][3],];
return [p1, p2];
});
}
export default vectorizeLinesCurrent;

View File

@@ -1,54 +0,0 @@
import * as THREE from 'three';
import updateReferencePolesheight from './updateReferencePolesheight';
import * as Types from "../../../../types/world/worldTypes";
function addAndUpdateReferencePillar(
raycaster: THREE.Raycaster,
floorGroup: Types.RefGroup,
referencePole: Types.RefMesh
): void {
////////// Find Pillars position and scale based on the pointer interaction //////////
let Roofs = raycaster.intersectObjects(floorGroup.current.children, true);
const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor"));
if (intersected) {
const intersectionPoint = intersected.point;
raycaster.ray.origin.copy(intersectionPoint);
raycaster.ray.direction.set(0, -1, 0);
const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor"));
let distance: Types.Number;
if (validIntersections.length > 1) {
let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3);
if (valid) {
updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup);
} else {
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
distance = intersected.point.distanceTo(belowPoint);
if (distance > 3) {
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
}
}
} else {
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
distance = intersected.point.distanceTo(belowPoint);
if (distance > 3) {
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
}
}
} else {
if (referencePole.current) {
(<any>referencePole.current.material).dispose();
(<any>referencePole.current.geometry).dispose();
floorGroup.current.remove(referencePole.current);
referencePole.current = null;
}
}
}
export default addAndUpdateReferencePillar;

View File

@@ -1,24 +0,0 @@
import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
function addPillar(
referencePole: Types.RefMesh,
floorGroup: Types.RefGroup
): void {
////////// Add Pillars to the scene based on the reference. current poles position and scale //////////
if (referencePole.current) {
let pole: THREE.Mesh;
const geometry = referencePole.current.userData.geometry.clone();
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor });
pole = new THREE.Mesh(geometry, material);
pole.rotateX(Math.PI / 2);
pole.name = "Pole";
pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z);
floorGroup.current.add(pole);
}
}
export default addPillar;

View File

@@ -1,34 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function DeletableHoveredPillar(
state: Types.ThreeState,
floorGroup: Types.RefGroup,
hoveredDeletablePillar: Types.RefMesh
): void {
////////// Altering the color of the hovered Pillar during the Deletion time //////////
const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true);
const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole");
if (poleIntersect) {
if (poleIntersect.object.name !== "Pole") {
return;
}
if (hoveredDeletablePillar.current) {
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
hoveredDeletablePillar.current = undefined;
}
hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red");
} else {
if (hoveredDeletablePillar.current) {
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
hoveredDeletablePillar.current = undefined;
}
}
}
export default DeletableHoveredPillar;

View File

@@ -1,21 +0,0 @@
import { toast } from 'react-toastify';
import * as Types from "../../../../types/world/worldTypes";
function DeletePillar(
hoveredDeletablePillar: Types.RefMesh,
floorGroup: Types.RefGroup
): void {
////////// Deleting the hovered Pillar from the itemsGroup //////////
if (hoveredDeletablePillar.current) {
(<any>hoveredDeletablePillar.current.material).dispose();
(<any>hoveredDeletablePillar.current.geometry).dispose();
floorGroup.current.remove(hoveredDeletablePillar.current);
echo.success("Pillar Removed!");
hoveredDeletablePillar.current = undefined;
}
}
export default DeletePillar;

View File

@@ -1,40 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function updateReferencePolesheight(
intersectionPoint: Types.Vector3,
distance: Types.Number,
referencePole: Types.RefMesh,
floorGroup: Types.RefGroup
): void {
////////// Add a Reference Pillar and update its position and scale based on the pointer interaction //////////
if (referencePole.current) {
(<any>referencePole.current.material).dispose();
(<any>referencePole.current.geometry).dispose();
floorGroup.current.remove(referencePole.current);
referencePole.current.geometry.dispose();
}
const shape = new THREE.Shape();
shape.moveTo(0.5, 0);
shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false);
const extrudeSettings = {
depth: distance,
bevelEnabled: false,
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 });
referencePole.current = new THREE.Mesh(geometry, material);
referencePole.current.rotateX(Math.PI / 2);
referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z);
referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } };
floorGroup.current.add(referencePole.current);
}
export default updateReferencePolesheight;

View File

@@ -1,65 +0,0 @@
import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
function addPointToScene(
position: Types.Vector3,
colour: Types.Color,
currentLayerPoint: Types.RefMeshArray,
floorPlanGroupPoint: Types.RefGroup,
dragPointControls: Types.RefDragControl | undefined,
uuid: Types.RefString | undefined,
Type: Types.String
): Types.Mesh {
////////// A function that creates and adds a cube (point) with an outline based on the position and colour given as params, It also updates the drag controls objects and sets the box uuid in uuid.current //////////
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
const material = new THREE.ShaderMaterial({
uniforms: {
uOuterColor: { value: new THREE.Color(colour) }, // Blue color for the border
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
uniform vec3 uOuterColor;
uniform vec3 uInnerColor;
void main() {
// Define the size of the white square as a proportion of the face
float borderThickness = 0.2; // Adjust this value for border thickness
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
} else {
gl_FragColor = vec4(uOuterColor, 1.0); // Blue border
}
}
`,
});
const point = new THREE.Mesh(geometry, material);
point.name = "point";
point.userData = { type: Type, color: colour };
point.position.set(position.x, 0.01, position.z);
currentLayerPoint.current.push(point);
floorPlanGroupPoint.current.add(point);
if (uuid) {
uuid.current = point.uuid;
}
if (dragPointControls) {
dragPointControls.current!.objects = currentLayerPoint.current;
}
return point;
}
export default addPointToScene;

View File

@@ -1,72 +0,0 @@
import * as Types from "../../../../types/world/worldTypes";
import { toast } from "react-toastify";
import RemoveConnectedLines from "../lines/removeConnectedLines";
// import { deletePointApi } from "../../../../services/factoryBuilder/lines/deletePointApi";
import { Socket } from "socket.io-client";
import { getUserData } from "../../../../functions/getUserData";
function deletePoint(
hoveredDeletablePoint: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines,
floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup,
lines: Types.RefLines,
setDeletedLines: any,
socket: Socket<any>,
projectId?: string,
versionId?: string,
): void {
////////// Deleting a Point and the lines that are connected to it //////////
if (!hoveredDeletablePoint.current) {
return;
}
const { userId, organization, email } = getUserData();
(<any>hoveredDeletablePoint.current.material).dispose();
(<any>hoveredDeletablePoint.current.geometry).dispose();
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
//REST
// deletePointApi(organization, DeletedPointUUID);
//SOCKET
const data = {
organization,
uuid: DeletedPointUUID,
socketId: socket.id,
versionId,
projectId,
userId,
};
// console.log('data: ', data);
socket.emit("v1:Line:delete:point", data);
////////// Update onlyFloorlines.current to remove references to the deleted point //////////
onlyFloorlines.current = onlyFloorlines.current
.map((floorline) =>
floorline.filter(
(line) =>
line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID
)
)
.filter((floorline) => floorline.length > 0);
RemoveConnectedLines(
DeletedPointUUID,
floorPlanGroupLine,
floorPlanGroupPoint,
setDeletedLines,
lines
);
echo.success("Point Removed!");
}
export default deletePoint;

View File

@@ -1,44 +0,0 @@
import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes"
import * as CONSTANTS from '../../../../types/world/worldConstants';
import updateLinesPositions from "../lines/updateLinesPositions";
import updateLines from "../lines/updateLines";
import updateDistanceText from "../lines/updateDistanceText";
import updateFloorLines from "../floors/updateFloorLines";
function DragPoint(
event: Types.IntersectionEvent,
floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup,
scene: THREE.Scene,
lines: Types.RefLines,
onlyFloorlines: Types.RefOnlyFloorLines
): void {
////////// Calling the line updation of the affected lines and Snapping of the point during the drag //////////
const snapThreshold = CONSTANTS.pointConfig.snappingThreshold;
const DragedPoint = event.object as Types.Mesh;
floorPlanGroupPoint.current.children.forEach((point) => {
let canSnap =
((DragedPoint.userData.type === CONSTANTS.lineConfig.wallName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
((DragedPoint.userData.type === CONSTANTS.lineConfig.floorName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
((DragedPoint.userData.type === CONSTANTS.lineConfig.aisleName) && point.userData.type === CONSTANTS.lineConfig.aisleName);
if (canSnap && point.uuid !== DragedPoint.uuid && point.visible) {
const distance = DragedPoint.position.distanceTo(point.position);
if (distance < snapThreshold) {
DragedPoint.position.copy(point.position);
}
}
});
const affectedLines = updateLinesPositions(DragedPoint, lines);
updateLines(floorPlanGroupLine, affectedLines);
updateDistanceText(scene, floorPlanGroupLine, affectedLines);
updateFloorLines(onlyFloorlines, DragedPoint);
}
export default DragPoint;

View File

@@ -1,37 +0,0 @@
import * as Types from "../../../../types/world/worldTypes";
function removeSoloPoint(
line: Types.RefLine,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup
): void {
////////// Remove the point if there is only one point and if it is not connected to any other line and also the reference line //////////
if (line.current[0]) {
const pointUUID = line.current[0][1];
let isConnected = false;
floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints;
const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1];
if (uuid1 === pointUUID || uuid2 === pointUUID) {
isConnected = true;
}
});
if (!isConnected) {
floorPlanGroupPoint.current.children.forEach((point: any) => {
if (point.uuid === pointUUID) {
(<any>point.material).dispose();
(<any>point.geometry).dispose();
floorPlanGroupPoint.current.remove(point);
}
});
}
line.current = [];
}
}
export default removeSoloPoint;

View File

@@ -1,32 +0,0 @@
import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
function addRoofToScene(
shape: Types.Shape,
floor: Types.Number,
userData: Types.UserData,
floorGroup: Types.RefGroup
): void {
////////// Creating a Polygon roof from the shape of the Polygon floor //////////
const extrudeSettings: THREE.ExtrudeGeometryOptions = {
depth: CONSTANTS.roofConfig.height,
bevelEnabled: false
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = CONSTANTS.wallConfig.height + floor;
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.rotateX(Math.PI / 2);
mesh.userData.uuids = userData;
mesh.name = `Roof_Layer_${(floor / CONSTANTS.wallConfig.height) + 1}`;
floorGroup.current.add(mesh);
}
export default addRoofToScene;

View File

@@ -1,47 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function hideRoof(
visibility: Types.Boolean,
floorGroup: Types.RefGroup,
camera: THREE.Camera
): void {
////////// Toggles the visibility of the roof based on the camera position and the Roof visibility button on UI //////////
const v = new THREE.Vector3();
const u = new THREE.Vector3();
if (visibility === true && floorGroup.current) {
for (const child of floorGroup.current.children) {
if (child.name.includes("Roof")) {
const roofChild = child as Types.Mesh;
roofChild.getWorldDirection(v);
camera?.getWorldDirection(u);
if (roofChild.material) {
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
materials.forEach(material => {
material.visible = v.dot(u) < 0.25;
});
}
}
}
} else {
if (floorGroup.current) {
for (const child of floorGroup.current.children) {
if (child.name.includes("Roof")) {
const roofChild = child as Types.Mesh;
if (roofChild.material) {
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
materials.forEach(material => {
material.visible = false;
});
}
}
}
}
}
}
export default hideRoof;

View File

@@ -1,164 +0,0 @@
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { toast } from "react-toastify";
import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import { Socket } from "socket.io-client";
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { getUserData } from "../../../../functions/getUserData";
async function AddWallItems(
selected: any,
raycaster: THREE.Raycaster,
CSGGroup: Types.RefMesh,
setWallItems: Types.setWallItemSetState,
socket: Socket<any>,
projectId?: string,
versionId?: string
): Promise<void> {
const { userId, organization } = getUserData();
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
const wallRaycastIntersection = intersects?.find((child) =>
child.object.name.includes("WallRaycastReference")
);
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
if (!wallRaycastIntersection) return;
const intersectionPoint = wallRaycastIntersection;
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath(
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
);
loader.setDRACOLoader(dracoLoader);
// Check THREE.js cache first
const cachedModel = THREE.Cache.get(selected.id);
if (cachedModel) {
handleModelLoad(cachedModel);
return;
}
// Check IndexedDB cache
const cachedModelBlob = await retrieveGLTF(selected.id);
if (cachedModelBlob) {
const blobUrl = URL.createObjectURL(cachedModelBlob);
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(selected.id, gltf);
handleModelLoad(gltf);
});
return;
}
// Load from backend if not in any cache
loader.load(
`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`,
async (gltf) => {
try {
const modelBlob = await fetch(
`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`
).then((res) => res.blob());
await storeGLTF(selected.id, modelBlob);
THREE.Cache.add(selected.id, gltf);
await handleModelLoad(gltf);
} catch (error) {
console.error("Failed to cache model:", error);
handleModelLoad(gltf);
}
}
);
async function handleModelLoad(gltf: GLTF) {
const model = gltf.scene.clone();
model.userData = { wall: intersectionPoint.object.parent };
model.children[0].children.forEach((child) => {
if (child.name !== "CSG_REF") {
child.castShadow = true;
child.receiveShadow = true;
}
});
const boundingBox = new THREE.Box3().setFromObject(model);
const size = new THREE.Vector3();
boundingBox.getSize(size);
const csgscale = [size.x, size.y, size.z] as [number, number, number];
const center = new THREE.Vector3();
boundingBox.getCenter(center);
const csgposition = [center.x, center.y, center.z] as [
number,
number,
number
];
let positionY =
selected.subCategory === "fixed-move" ? 0 : intersectionPoint.point.y;
if (positionY === 0) {
positionY =
Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) *
CONSTANTS.wallConfig.height;
}
const newWallItem = {
type: selected.subCategory,
model: model,
modelName: selected.name,
assetId: selected.id,
scale: [1, 1, 1] as [number, number, number],
csgscale: csgscale,
csgposition: csgposition,
position: [
intersectionPoint.point.x,
positionY,
intersectionPoint.point.z,
] as [number, number, number],
quaternion:
intersectionPoint.object.quaternion.clone() as Types.QuaternionType,
};
const data = {
organization,
modelUuid: model.uuid,
modelName: newWallItem.modelName,
assetId: selected.id,
type: selected.subCategory,
csgposition: newWallItem.csgposition,
csgscale: newWallItem.csgscale,
position: newWallItem.position,
quaternion: newWallItem.quaternion,
scale: newWallItem.scale,
socketId: socket.id,
versionId,
projectId,
userId,
};
socket.emit("v1:wallItems:set", data);
setWallItems((prevItems) => {
const updatedItems = [...prevItems, newWallItem];
const WallItemsForStorage = updatedItems.map((item) => {
const { model, ...rest } = item;
return {
...rest,
modelUuid: model?.uuid,
};
});
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
echo.success("Model Added!");
return updatedItems;
});
}
}
export default AddWallItems;

View File

@@ -1,62 +0,0 @@
import { getUserData } from "../../../../functions/getUserData";
import * as Types from "../../../../types/world/worldTypes";
// import { deleteWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/deleteWallItemApi';
import { Socket } from "socket.io-client";
function DeleteWallItems(
hoveredDeletableWallItem: Types.RefMesh,
setWallItems: Types.setWallItemSetState,
wallItems: Types.wallItems,
socket: Socket<any>,
projectId?: string,
versionId? : string,
): void {
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
const { userId, organization, email } = getUserData();
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current) {
setWallItems([]);
let WallItemsRef = wallItems;
const removedItem = WallItemsRef.find(
(item) => item.model?.uuid === hoveredDeletableWallItem.current?.uuid
);
const Items = WallItemsRef.filter(
(item) => item.model?.uuid !== hoveredDeletableWallItem.current?.uuid
);
setTimeout(async () => {
WallItemsRef = Items;
setWallItems(WallItemsRef);
//REST
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!)
//SOCKET
const data = {
organization,
modelUuid: removedItem?.model?.uuid!,
modelName: removedItem?.modelName!,
socketId: socket.id,
projectId,
versionId,
userId,
};
socket.emit("v1:wallItems:delete", data);
const WallItemsForStorage = WallItemsRef.map((item) => {
const { model, ...rest } = item;
return {
...rest,
modelUuid: model?.uuid,
};
});
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
hoveredDeletableWallItem.current = null;
}, 50);
}
}
export default DeleteWallItems;

View File

@@ -1,45 +0,0 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function hideWalls(
visibility: Types.Boolean,
scene: THREE.Scene,
camera: THREE.Camera
): void {
const wallNormal = new THREE.Vector3();
const cameraToWall = new THREE.Vector3();
const cameraDirection = new THREE.Vector3();
if (visibility === true) {
for (const children of scene.children) {
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
children.children[0].children.forEach((child: any) => {
if (child.children[0]?.userData.WallType === "RoomWall") {
const wallMesh = child.children[0];
wallMesh.getWorldDirection(wallNormal);
cameraToWall.copy(wallMesh.position).sub(camera.position).normalize();
camera.getWorldDirection(cameraDirection);
const isFacingCamera = wallNormal.dot(cameraToWall) > 0;
const isInFrontOfCamera = cameraDirection.dot(cameraToWall) > -0.3;
if (wallMesh.material) {
wallMesh.material.visible = isFacingCamera && isInFrontOfCamera;
}
}
});
}
}
} else {
for (const children of scene.children) {
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
children.children[0].children.forEach((child: any) => {
if (child.children[0]?.userData.WallType === "RoomWall" && child.children[0].material) {
child.children[0].material.visible = true;
}
});
}
}
}
}
export default hideWalls;

View File

@@ -1,140 +0,0 @@
import * as THREE from 'three';
import * as turf from '@turf/turf';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";
import getRoomsFromLines from '../lines/getRoomsFromLines';
async function loadWalls(
lines: Types.RefLines,
setWalls: any,
): Promise<void> {
////////// Removes the old walls if any, Checks if there is any overlapping in lines if any updates it , starts function that creates floor and roof //////////
const Walls: Types.Walls = [];
const Rooms: Types.Rooms = [];
localStorage.setItem("Lines", JSON.stringify(lines.current));
if (lines.current.length > 1) {
////////// Add Walls that are forming a room //////////
const wallSet = new Set<string>();
const rooms: Types.Rooms = await getRoomsFromLines(lines);
Rooms.push(...rooms);
Rooms.forEach(({ coordinates: room, layer }) => {
for (let i = 0; i < room.length - 1; i++) {
const uuid1 = room[i].uuid;
const uuid2 = room[(i + 1) % room.length].uuid;
const wallId = `${uuid1}_${uuid2}`;
if (!wallSet.has(wallId)) {
const p1 = room[i].position;
const p2 = room[(i + 1) % room.length].position;
const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(0, CONSTANTS.wallConfig.height);
shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
shape.lineTo(p2.distanceTo(p1), 0);
shape.lineTo(0, 0);
const extrudeSettings = {
depth: CONSTANTS.wallConfig.width,
bevelEnabled: false
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
Walls.push([geometry, [0, -angle, 0], [p1.x, (layer - 1) * CONSTANTS.wallConfig.height, p1.z], "RoomWall", layer]);
wallSet.add(wallId);
}
}
});
////////// Add Walls that are not forming any room //////////
lines.current.forEach(line => {
if (line[0][3] && line[1][3] !== CONSTANTS.lineConfig.wallName) {
return;
}
const [uuid1, uuid2] = line.map(point => point[1]);
let isInRoom = false;
const lineLayer = line[0][2];
for (let room of Rooms) {
const roomLayer = room.layer;
if (roomLayer !== lineLayer) continue;
for (let i = 0; i < room.coordinates.length - 1; i++) {
const roomUuid1 = room.coordinates[i].uuid;
const roomUuid2 = room.coordinates[(i + 1) % room.coordinates.length].uuid;
if (
(uuid1 === roomUuid1 && uuid2 === roomUuid2) ||
(uuid1 === roomUuid2 && uuid2 === roomUuid1)
) {
isInRoom = true;
break;
}
}
if (isInRoom) break;
}
if (!isInRoom) {
const p1 = new THREE.Vector3(line[0][0].x, 0, line[0][0].z);
const p2 = new THREE.Vector3(line[1][0].x, 0, line[1][0].z);
let isCollinear = false;
for (let room of Rooms) {
if (room.layer !== lineLayer) continue;
for (let i = 0; i < room.coordinates.length - 1; i++) {
const roomP1 = room.coordinates[i].position;
const roomP2 = room.coordinates[(i + 1) % room.coordinates.length].position;
const lineFeature = turf.lineString([[p1.x, p1.z], [p2.x, p2.z]]);
const roomFeature = turf.lineString([[roomP1.x, roomP1.z], [roomP2.x, roomP2.z]]);
if (turf.booleanOverlap(lineFeature, roomFeature)) {
isCollinear = true;
break;
}
}
if (isCollinear) break;
}
if (!isCollinear) {
const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(0, CONSTANTS.wallConfig.height);
shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
shape.lineTo(p2.distanceTo(p1), 0);
shape.lineTo(0, 0);
const extrudeSettings = {
depth: CONSTANTS.wallConfig.width,
bevelEnabled: false
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
Walls.push([geometry, [0, -angle, 0], [p1.x, (lineLayer - 1) * CONSTANTS.wallConfig.height, p1.z], "SegmentWall", lineLayer]);
}
}
});
setWalls(Walls);
} else {
setWalls([]);
}
}
export default loadWalls;
// A----- B----- C
// | | |
// | | |
// | | |
// F----- E----- D
// 1. A -> B, B -> C, C -> D, D -> E, E -> F, F -> A, B -> E
// 2. E -> F, F -> A, A -> B, B -> E, E -> D, D -> C, C -> B

View File

@@ -1,50 +0,0 @@
import * as THREE from 'three';
import * as Types from '../../../../types/world/worldTypes';
import * as CONSTANTS from '../../../../types/world/worldConstants';
const baseMaterial = new THREE.ShaderMaterial({
side: THREE.DoubleSide,
vertexShader: `
varying vec2 vUv;
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
vUv = uv;
}
`,
fragmentShader: `
varying vec2 vUv;
uniform vec3 uOuterColor;
void main(){
float alpha = 1.0 - vUv.y;
gl_FragColor = vec4(uOuterColor, alpha);
}
`,
uniforms: {
uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.defaultColor) },
},
transparent: true,
});
export default function addZonesToScene(
line: Types.Line,
floorGroupZone: Types.RefGroup,
color: THREE.Color
) {
const point1 = line[0][0];
const point2 = line[1][0];
const length = (new THREE.Vector3(point2.x, point2.y, point2.z)).distanceTo(new THREE.Vector3(point1.x, point1.y, point1.z));
const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x);
const geometry = new THREE.PlaneGeometry(length, 10);
const material = baseMaterial.clone();
material.uniforms.uOuterColor.value.set(color.r, color.g, color.b);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set((point1.x + point2.x) / 2, ((line[0][2] - 1) * CONSTANTS.wallConfig.height) + 5, (point1.z + point2.z) / 2);
mesh.rotation.y = -angle;
floorGroupZone.current.add(mesh);
}

View File

@@ -1,19 +0,0 @@
import * as Types from '../../../../types/world/worldTypes';
import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import addZonesToScene from './addZonesToScene';
export default function loadZones(
lines: Types.RefLines,
floorGroupZone: Types.RefGroup
) {
if (!floorGroupZone.current) return
floorGroupZone.current.children = [];
const zones = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.zoneName);
if (zones.length > 0) {
zones.forEach((zone: Types.Line) => {
addZonesToScene(zone, floorGroupZone, new THREE.Color(CONSTANTS.zoneConfig.color))
})
}
}

View File

@@ -1,127 +0,0 @@
import { useFrame, useThree } from "@react-three/fiber";
import {
useAddAction,
useRoofVisibility,
useToggleView,
useWallVisibility,
useUpdateScene,
useRenameModeStore,
useToolMode,
} from "../../../store/builder/store";
import hideRoof from "../geomentries/roofs/hideRoof";
import hideWalls from "../geomentries/walls/hideWalls";
import addAndUpdateReferencePillar from "../geomentries/pillars/addAndUpdateReferencePillar";
import { useEffect } from "react";
import addPillar from "../geomentries/pillars/addPillar";
import DeletePillar from "../geomentries/pillars/deletePillar";
import DeletableHoveredPillar from "../geomentries/pillars/deletableHoveredPillar";
import loadFloor from "../geomentries/floors/loadFloor";
import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore";
const FloorGroup = ({
floorGroup,
lines,
referencePole,
hoveredDeletablePillar,
}: any) => {
const state = useThree();
const { roofVisibility } = useRoofVisibility();
const { wallVisibility } = useWallVisibility();
const { toggleView } = useToggleView();
const { scene, camera, raycaster, gl } = useThree();
const { addAction } = useAddAction();
const { toolMode } = useToolMode();
const { updateScene, setUpdateScene } = useUpdateScene();
const { setTop } = useTopData();
const { setLeft } = useLeftData();
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
useEffect(() => {
if (updateScene) {
loadFloor(lines, floorGroup);
setUpdateScene(false);
}
}, [updateScene]);
useEffect(() => {
if (!addAction) {
if (referencePole.current) {
(referencePole.current as any).material.dispose();
(referencePole.current.geometry as any).dispose();
floorGroup.current.remove(referencePole.current);
referencePole.current = undefined;
}
}
}, [addAction]);
useEffect(() => {
const canvasElement = gl.domElement;
let drag = false;
let isLeftMouseDown = false;
const onMouseDown = (evt: any) => {
if (evt.button === 0) {
isLeftMouseDown = true;
drag = false;
}
};
const onMouseUp = (evt: any) => {
setIsRenameMode(false);
if (evt.button === 0) {
isLeftMouseDown = false;
if (!drag) {
if (addAction === "pillar") {
addPillar(referencePole, floorGroup);
}
if (toolMode === '3D-Delete') {
DeletePillar(hoveredDeletablePillar, floorGroup);
}
}
}
};
const onMouseMove = (evt: any) => {
if (!canvasElement) return;
const canvasRect = canvasElement.getBoundingClientRect();
const relativeX = evt.clientX - canvasRect.left;
const relativeY = evt.clientY - canvasRect.top;
// if (!isRenameMode) {
// setTop(relativeY);
// setLeft(relativeX);
// }
if (isLeftMouseDown) {
drag = true;
}
};
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
return () => {
canvasElement.removeEventListener("mousedown", onMouseDown);
canvasElement.removeEventListener("mouseup", onMouseUp);
canvasElement.removeEventListener("mousemove", onMouseMove);
};
}, [toolMode, addAction, isRenameMode]);
useFrame(() => {
hideRoof(roofVisibility, floorGroup, camera);
hideWalls(wallVisibility, scene, camera);
if (addAction === "pillar") {
addAndUpdateReferencePillar(raycaster, floorGroup, referencePole);
}
if (toolMode === '3D-Delete') {
DeletableHoveredPillar(state, floorGroup, hoveredDeletablePillar);
}
});
return (
<group ref={floorGroup} visible={!toggleView} name="floorGroup"></group>
);
};
export default FloorGroup;

View File

@@ -1,191 +0,0 @@
import { useEffect } from "react";
import * as Types from '../../../types/world/worldTypes';
import { useActiveLayer, useDeletedLines, useToolMode, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/builder/store";
import Layer2DVisibility from "../geomentries/layers/layer2DVisibility";
import { useFrame, useThree } from "@react-three/fiber";
import DeletableLineorPoint from "../functions/deletableLineOrPoint";
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
import DeleteLayer from "../geomentries/layers/deleteLayer";
import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
import loadInitialPoint from "../IntialLoad/loadInitialPoint";
import loadInitialLine from "../IntialLoad/loadInitialLine";
import deletePoint from "../geomentries/points/deletePoint";
import deleteLine from "../geomentries/lines/deleteLine";
import drawWall from "../geomentries/lines/drawWall";
import drawOnlyFloor from "../geomentries/floors/drawOnlyFloor";
import addDragControl from "../eventDeclaration/dragControlDeclaration";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../functions/getUserData";
import { useVersionContext } from "../version/versionContext";
const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, floorGroup, currentLayerPoint, dragPointControls, hoveredDeletablePoint, hoveredDeletableLine, plane, line, lines, onlyFloorline, onlyFloorlines, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
const state = useThree();
const { camera, gl, raycaster, controls } = state;
const { activeLayer } = useActiveLayer();
const { toggleView } = useToggleView();
const { toolMode } = useToolMode();
const { removedLayer, setRemovedLayer } = useRemovedLayer();
const { setUpdateScene } = useUpdateScene();
const { setNewLines } = useNewLines();
const { setDeletedLines } = useDeletedLines();
const { socket } = useSocketStore();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { organization } = getUserData();
useEffect(() => {
if (toolMode === 'move') {
addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket, projectId, selectedVersion?.versionId || '',);
}
return () => {
if (dragPointControls.current) {
dragPointControls.current.enabled = false;
}
};
}, [toolMode, state]);
useEffect(() => {
if (!selectedVersion) return;
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
const Lines: Types.Lines = objectLinesToArray(data);
if (Lines) {
lines.current = Lines;
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
loadInitialLine(floorPlanGroupLine, lines);
setUpdateScene(true);
}
})
}, [selectedVersion?.versionId]);
useEffect(() => {
if (!toggleView) {
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
}
}, [toggleView]);
useEffect(() => {
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
}, [toolMode]);
useEffect(() => {
if (toolMode === 'move' && toggleView) {
if (dragPointControls.current) {
dragPointControls.current.enabled = true;
}
} else {
if (dragPointControls.current) {
dragPointControls.current.enabled = false;
}
}
}, [toolMode, toggleView, state]);
useEffect(() => {
Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
}, [activeLayer]);
useEffect(() => {
if (removedLayer !== null) {
DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket, projectId, selectedVersion?.versionId || '',);
}
}, [removedLayer]);
useEffect(() => {
const canvasElement = gl.domElement;
let drag = false;
let isLeftMouseDown = false;
const onMouseDown = (evt: any) => {
if (evt.button === 0) {
isLeftMouseDown = true;
drag = false;
}
};
const onMouseUp = (evt: any) => {
if (evt.button === 0) {
isLeftMouseDown = false;
}
if (controls) {
(controls as any).enabled = true;
}
}
const onMouseMove = () => {
if (isLeftMouseDown) {
drag = true;
}
};
const onContextMenu = (e: any) => {
e.preventDefault();
if (toolMode === "Wall" || toolMode === "Floor") {
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
}
};
const onMouseClick = (evt: any) => {
if (!plane.current || drag) return;
if (toolMode === "2D-Delete") {
if (hoveredDeletablePoint.current !== null) {
deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',);
}
if (hoveredDeletableLine.current !== null) {
deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',);
}
}
if (toolMode === "Wall") {
// drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',);
}
if (toolMode === "Floor") {
// drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',);
}
}
if (toolMode === "2D-Delete" || toolMode === "Wall" || toolMode === "Floor") {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
canvasElement.addEventListener("click", onMouseClick);
canvasElement.addEventListener("contextmenu", onContextMenu);
}
return () => {
canvasElement.removeEventListener("mousedown", onMouseDown);
canvasElement.removeEventListener("mouseup", onMouseUp);
canvasElement.removeEventListener("mousemove", onMouseMove);
canvasElement.removeEventListener("click", onMouseClick);
canvasElement.removeEventListener("contextmenu", onContextMenu);
};
}, [toolMode, activeLayer])
useFrame(() => {
if (toolMode === '2D-Delete') {
DeletableLineorPoint(state, plane, floorPlanGroupLine, floorPlanGroupPoint, hoveredDeletableLine, hoveredDeletablePoint);
}
})
return (
<group ref={floorPlanGroup} visible={toggleView} name="floorPlanGroup">
<group ref={floorPlanGroupLine} name="floorPlanGroupLine"></group>
<group ref={floorPlanGroupPoint} name="floorPlanGroupPoint"></group>
</group>
)
}
export default FloorPlanGroup;

View File

@@ -1,291 +1,291 @@
import { useEffect } from "react";
import {
useObjectPosition,
useObjectRotation,
useSelectedWallItem,
useSocketStore,
useWallItems,
useSelectedItem,
useToolMode,
} from "../../../store/builder/store";
import { Csg } from "../csg/csg";
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
import DeleteWallItems from "../geomentries/walls/deleteWallItems";
import loadInitialWallItems from "../IntialLoad/loadInitialWallItems";
import AddWallItems from "../geomentries/walls/addWallItems";
import useModuleStore from "../../../store/useModuleStore";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../functions/getUserData";
import { useVersionContext } from "../version/versionContext";
// import { useEffect } from "react";
// import {
// useObjectPosition,
// useObjectRotation,
// useSelectedWallItem,
// useSocketStore,
// useWallItems,
// useSelectedItem,
// useToolMode,
// } from "../../../store/builder/store";
// import { Csg } from "../csg/csg";
// import * as Types from "../../../types/world/worldTypes";
// import * as CONSTANTS from "../../../types/world/worldConstants";
// import * as THREE from "three";
// import { useThree } from "@react-three/fiber";
// import handleMeshMissed from "../eventFunctions/handleMeshMissed";
// import DeleteWallItems from "../geomentries/walls/deleteWallItems";
// import loadInitialWallItems from "../IntialLoad/loadInitialWallItems";
// import AddWallItems from "../geomentries/walls/addWallItems";
// import useModuleStore from "../../../store/useModuleStore";
// import { useParams } from "react-router-dom";
// import { getUserData } from "../../../functions/getUserData";
// import { useVersionContext } from "../version/versionContext";
const WallItemsGroup = ({
currentWallItem,
hoveredDeletableWallItem,
selectedItemsIndex,
setSelectedItemsIndex,
CSGGroup,
}: any) => {
const state = useThree();
const { socket } = useSocketStore();
const { pointer, camera, raycaster } = state;
const { toolMode } = useToolMode();
const { wallItems, setWallItems } = useWallItems();
const { setObjectPosition } = useObjectPosition();
const { setObjectRotation } = useObjectRotation();
const { setSelectedWallItem } = useSelectedWallItem();
const { activeModule } = useModuleStore();
const { selectedItem } = useSelectedItem();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { userId, organization } = getUserData();
// const WallItemsGroup = ({
// currentWallItem,
// hoveredDeletableWallItem,
// selectedItemsIndex,
// setSelectedItemsIndex,
// CSGGroup,
// }: any) => {
// const state = useThree();
// const { socket } = useSocketStore();
// const { pointer, camera, raycaster } = state;
// const { toolMode } = useToolMode();
// const { wallItems, setWallItems } = useWallItems();
// const { setObjectPosition } = useObjectPosition();
// const { setObjectRotation } = useObjectRotation();
// const { setSelectedWallItem } = useSelectedWallItem();
// const { activeModule } = useModuleStore();
// const { selectedItem } = useSelectedItem();
// const { selectedVersionStore } = useVersionContext();
// const { selectedVersion } = selectedVersionStore();
// const { projectId } = useParams();
// const { userId, organization } = getUserData();
useEffect(() => {
// Load Wall Items from the backend
if (!projectId || !selectedVersion) return;
loadInitialWallItems(setWallItems, projectId, selectedVersion?.versionId);
}, [selectedVersion?.versionId]);
// useEffect(() => {
// // Load Wall Items from the backend
// if (!projectId || !selectedVersion) return;
// loadInitialWallItems(setWallItems, projectId, selectedVersion?.versionId);
// }, [selectedVersion?.versionId]);
////////// Update the Position value changes in the selected item //////////
// ////////// Update the Position value changes in the selected item //////////
useEffect(() => {
const canvasElement = state.gl.domElement;
function handlePointerMove(e: any) {
if (selectedItemsIndex !== null && toolMode === 'cursor' && e.buttons === 1) {
const Raycaster = state.raycaster;
const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
// useEffect(() => {
// const canvasElement = state.gl.domElement;
// function handlePointerMove(e: any) {
// if (selectedItemsIndex !== null && toolMode === 'cursor' && e.buttons === 1) {
// const Raycaster = state.raycaster;
// const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
// const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
if (Object) {
(state.controls as any)!.enabled = false;
setWallItems((prevItems: any) => {
const updatedItems = [...prevItems];
let position: [number, number, number] = [0, 0, 0];
// if (Object) {
// (state.controls as any)!.enabled = false;
// setWallItems((prevItems: any) => {
// const updatedItems = [...prevItems];
// let position: [number, number, number] = [0, 0, 0];
if (updatedItems[selectedItemsIndex].type === "fixed-move") {
position = [
Object!.point.x,
Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) *
CONSTANTS.wallConfig.height,
Object!.point.z,
];
} else if (updatedItems[selectedItemsIndex].type === "free-move") {
position = [Object!.point.x, Object!.point.y, Object!.point.z];
}
// if (updatedItems[selectedItemsIndex].type === "fixed-move") {
// position = [
// Object!.point.x,
// Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) *
// CONSTANTS.wallConfig.height,
// Object!.point.z,
// ];
// } else if (updatedItems[selectedItemsIndex].type === "free-move") {
// position = [Object!.point.x, Object!.point.y, Object!.point.z];
// }
requestAnimationFrame(() => {
setObjectPosition(new THREE.Vector3(...position));
setObjectRotation({
x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
});
});
// requestAnimationFrame(() => {
// setObjectPosition(new THREE.Vector3(...position));
// setObjectRotation({
// x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
// y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
// z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
// });
// });
updatedItems[selectedItemsIndex] = {
...updatedItems[selectedItemsIndex],
position: position,
quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
};
// updatedItems[selectedItemsIndex] = {
// ...updatedItems[selectedItemsIndex],
// position: position,
// quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
// };
return updatedItems;
});
}
}
}
// return updatedItems;
// });
// }
// }
// }
async function handlePointerUp() {
const Raycaster = state.raycaster;
const intersects = Raycaster.intersectObjects(
CSGGroup.current?.children[0].children!,
true
);
const Object = intersects.find((child) =>
child.object.name.includes("WallRaycastReference")
);
if (Object) {
if (selectedItemsIndex !== null) {
let currentItem: any = null;
setWallItems((prevItems: any) => {
const updatedItems = [...prevItems];
const WallItemsForStorage = updatedItems.map((item) => {
const { model, ...rest } = item;
return {
...rest,
modelUuid: model?.uuid,
};
});
// async function handlePointerUp() {
// const Raycaster = state.raycaster;
// const intersects = Raycaster.intersectObjects(
// CSGGroup.current?.children[0].children!,
// true
// );
// const Object = intersects.find((child) =>
// child.object.name.includes("WallRaycastReference")
// );
// if (Object) {
// if (selectedItemsIndex !== null) {
// let currentItem: any = null;
// setWallItems((prevItems: any) => {
// const updatedItems = [...prevItems];
// const WallItemsForStorage = updatedItems.map((item) => {
// const { model, ...rest } = item;
// return {
// ...rest,
// modelUuid: model?.uuid,
// };
// });
currentItem = updatedItems[selectedItemsIndex];
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
return updatedItems;
});
// currentItem = updatedItems[selectedItemsIndex];
// localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
// return updatedItems;
// });
setTimeout(async () => {
// setTimeout(async () => {
//REST
// //REST
// await setWallItem(
// organization,
// currentItem?.model?.uuid,
// currentItem.modelName,
// currentItem.assetId,
// currentItem.type!,
// currentItem.csgposition!,
// currentItem.csgscale!,
// currentItem.position,
// currentItem.quaternion,
// currentItem.scale!,
// )
// // await setWallItem(
// // organization,
// // currentItem?.model?.uuid,
// // currentItem.modelName,
// // currentItem.assetId,
// // currentItem.type!,
// // currentItem.csgposition!,
// // currentItem.csgscale!,
// // currentItem.position,
// // currentItem.quaternion,
// // currentItem.scale!,
// // )
//SOCKET
// //SOCKET
const data = {
organization,
modelUuid: currentItem.model?.uuid!,
assetId: currentItem.assetId,
modelName: currentItem.modelName!,
type: currentItem.type!,
csgposition: currentItem.csgposition!,
csgscale: currentItem.csgscale!,
position: currentItem.position!,
quaternion: currentItem.quaternion,
scale: currentItem.scale!,
socketId: socket.id,
versionId: selectedVersion?.versionId || '',
projectId,
userId
};
// const data = {
// organization,
// modelUuid: currentItem.model?.uuid!,
// assetId: currentItem.assetId,
// modelName: currentItem.modelName!,
// type: currentItem.type!,
// csgposition: currentItem.csgposition!,
// csgscale: currentItem.csgscale!,
// position: currentItem.position!,
// quaternion: currentItem.quaternion,
// scale: currentItem.scale!,
// socketId: socket.id,
// versionId: selectedVersion?.versionId || '',
// projectId,
// userId
// };
// console.log('data: ', data);
socket.emit("v1:wallItems:set", data);
}, 0);
(state.controls as any)!.enabled = true;
}
}
}
// // console.log('data: ', data);
// socket.emit("v1:wallItems:set", data);
// }, 0);
// (state.controls as any)!.enabled = true;
// }
// }
// }
canvasElement.addEventListener("pointermove", handlePointerMove);
canvasElement.addEventListener("pointerup", handlePointerUp);
// canvasElement.addEventListener("pointermove", handlePointerMove);
// canvasElement.addEventListener("pointerup", handlePointerUp);
return () => {
canvasElement.removeEventListener("pointermove", handlePointerMove);
canvasElement.removeEventListener("pointerup", handlePointerUp);
};
}, [selectedItemsIndex, selectedVersion?.versionId]);
// return () => {
// canvasElement.removeEventListener("pointermove", handlePointerMove);
// canvasElement.removeEventListener("pointerup", handlePointerUp);
// };
// }, [selectedItemsIndex, selectedVersion?.versionId]);
useEffect(() => {
const canvasElement = state.gl.domElement;
let drag = false;
let isLeftMouseDown = false;
// useEffect(() => {
// const canvasElement = state.gl.domElement;
// let drag = false;
// let isLeftMouseDown = false;
const onMouseDown = (evt: any) => {
if (evt.button === 0) {
isLeftMouseDown = true;
drag = false;
}
};
// const onMouseDown = (evt: any) => {
// if (evt.button === 0) {
// isLeftMouseDown = true;
// drag = false;
// }
// };
const onMouseUp = (evt: any) => {
if (evt.button === 0) {
isLeftMouseDown = false;
if (!drag && toolMode === '3D-Delete' && activeModule === "builder") {
DeleteWallItems(
hoveredDeletableWallItem,
setWallItems,
wallItems,
socket,
projectId,
selectedVersion?.versionId || '',
);
}
}
};
// const onMouseUp = (evt: any) => {
// if (evt.button === 0) {
// isLeftMouseDown = false;
// if (!drag && toolMode === '3D-Delete' && activeModule === "builder") {
// DeleteWallItems(
// hoveredDeletableWallItem,
// setWallItems,
// wallItems,
// socket,
// projectId,
// selectedVersion?.versionId || '',
// );
// }
// }
// };
const onMouseMove = () => {
if (isLeftMouseDown) {
drag = true;
}
};
// const onMouseMove = () => {
// if (isLeftMouseDown) {
// drag = true;
// }
// };
const onDrop = (event: any) => {
if (selectedItem.category !== 'Fenestration') return;
// const onDrop = (event: any) => {
// if (selectedItem.category !== 'Fenestration') return;
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
// pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
// pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
// raycaster.setFromCamera(pointer, camera);
if (selectedItem.id && selectedVersion && projectId) {
if (selectedItem.subCategory) {
AddWallItems(
selectedItem,
raycaster,
CSGGroup,
setWallItems,
socket,
projectId,
selectedVersion?.versionId || '',
);
}
event.preventDefault();
}
};
// if (selectedItem.id && selectedVersion && projectId) {
// if (selectedItem.subCategory) {
// AddWallItems(
// selectedItem,
// raycaster,
// CSGGroup,
// setWallItems,
// socket,
// projectId,
// selectedVersion?.versionId || '',
// );
// }
// event.preventDefault();
// }
// };
const onDragOver = (event: any) => {
event.preventDefault();
};
// const onDragOver = (event: any) => {
// event.preventDefault();
// };
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
canvasElement.addEventListener("drop", onDrop);
canvasElement.addEventListener("dragover", onDragOver);
// canvasElement.addEventListener("mousedown", onMouseDown);
// canvasElement.addEventListener("mouseup", onMouseUp);
// canvasElement.addEventListener("mousemove", onMouseMove);
// canvasElement.addEventListener("drop", onDrop);
// canvasElement.addEventListener("dragover", onDragOver);
return () => {
canvasElement.removeEventListener("mousedown", onMouseDown);
canvasElement.removeEventListener("mouseup", onMouseUp);
canvasElement.removeEventListener("mousemove", onMouseMove);
canvasElement.removeEventListener("drop", onDrop);
canvasElement.removeEventListener("dragover", onDragOver);
};
}, [toolMode, wallItems, selectedItem, camera, selectedVersion?.versionId]);
// return () => {
// canvasElement.removeEventListener("mousedown", onMouseDown);
// canvasElement.removeEventListener("mouseup", onMouseUp);
// canvasElement.removeEventListener("mousemove", onMouseMove);
// canvasElement.removeEventListener("drop", onDrop);
// canvasElement.removeEventListener("dragover", onDragOver);
// };
// }, [toolMode, wallItems, selectedItem, camera, selectedVersion?.versionId]);
useEffect(() => {
if (toolMode && activeModule === "builder") {
handleMeshMissed(
currentWallItem,
setSelectedWallItem,
setSelectedItemsIndex
);
setSelectedWallItem(null);
setSelectedItemsIndex(null);
}
}, [toolMode]);
// useEffect(() => {
// if (toolMode && activeModule === "builder") {
// handleMeshMissed(
// currentWallItem,
// setSelectedWallItem,
// setSelectedItemsIndex
// );
// setSelectedWallItem(null);
// setSelectedItemsIndex(null);
// }
// }, [toolMode]);
return (
<>
{wallItems.map((item: Types.WallItem, index: number) => (
<group
key={index}
position={item.position}
quaternion={item.quaternion}
scale={item.scale}
>
<Csg
position={item.csgposition!}
scale={item.csgscale!}
model={item.model!}
hoveredDeletableWallItem={hoveredDeletableWallItem}
/>
</group>
))}
</>
);
};
// return (
// <>
// {wallItems.map((item: Types.WallItem, index: number) => (
// <group
// key={index}
// position={item.position}
// quaternion={item.quaternion}
// scale={item.scale}
// >
// <Csg
// position={item.csgposition!}
// scale={item.csgscale!}
// model={item.model!}
// hoveredDeletableWallItem={hoveredDeletableWallItem}
// />
// </group>
// ))}
// </>
// );
// };
export default WallItemsGroup;
// export default WallItemsGroup;

View File

@@ -1,74 +1,74 @@
import { Geometry } from "@react-three/csg";
import {
useSelectedWallItem,
useToggleView,
useToolMode,
useWallItems,
useWalls,
} from "../../../store/builder/store";
import handleMeshDown from "../eventFunctions/handleMeshDown";
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
import WallsMesh from "./wallsMesh";
import WallItemsGroup from "./wallItemsGroup";
// import { Geometry } from "@react-three/csg";
// import {
// useSelectedWallItem,
// useToggleView,
// useToolMode,
// useWallItems,
// useWalls,
// } from "../../../store/builder/store";
// import handleMeshDown from "../eventFunctions/handleMeshDown";
// import handleMeshMissed from "../eventFunctions/handleMeshMissed";
// import WallsMesh from "./wallsMesh";
// import WallItemsGroup from "./wallItemsGroup";
const WallsAndWallItems = ({
CSGGroup,
setSelectedItemsIndex,
selectedItemsIndex,
currentWallItem,
csg,
lines,
hoveredDeletableWallItem,
}: any) => {
const { walls } = useWalls();
const { wallItems } = useWallItems();
const { toggleView } = useToggleView();
const { toolMode } = useToolMode();
const { setSelectedWallItem } = useSelectedWallItem();
// const WallsAndWallItems = ({
// CSGGroup,
// setSelectedItemsIndex,
// selectedItemsIndex,
// currentWallItem,
// csg,
// lines,
// hoveredDeletableWallItem,
// }: any) => {
// const { walls } = useWalls();
// const { wallItems } = useWallItems();
// const { toggleView } = useToggleView();
// const { toolMode } = useToolMode();
// const { setSelectedWallItem } = useSelectedWallItem();
return (
<mesh
ref={CSGGroup as any}
name="Walls"
key={walls.length}
receiveShadow
visible={!toggleView}
onClick={(event) => {
if (toolMode === "cursor") {
handleMeshDown(
event,
currentWallItem,
setSelectedWallItem,
setSelectedItemsIndex,
wallItems,
toggleView
);
}
}}
onPointerMissed={() => {
if (toolMode === "cursor") {
handleMeshMissed(
currentWallItem,
setSelectedWallItem,
setSelectedItemsIndex
);
setSelectedWallItem(null);
setSelectedItemsIndex(null);
}
}}
>
<Geometry ref={csg as any} computeVertexNormals useGroups>
<WallsMesh lines={lines} />
<WallItemsGroup
currentWallItem={currentWallItem}
hoveredDeletableWallItem={hoveredDeletableWallItem}
selectedItemsIndex={selectedItemsIndex}
setSelectedItemsIndex={setSelectedItemsIndex}
CSGGroup={CSGGroup}
/>
</Geometry>
</mesh>
);
};
// return (
// <mesh
// ref={CSGGroup as any}
// name="Walls"
// key={walls.length}
// receiveShadow
// visible={!toggleView}
// onClick={(event) => {
// if (toolMode === "cursor") {
// handleMeshDown(
// event,
// currentWallItem,
// setSelectedWallItem,
// setSelectedItemsIndex,
// wallItems,
// toggleView
// );
// }
// }}
// onPointerMissed={() => {
// if (toolMode === "cursor") {
// handleMeshMissed(
// currentWallItem,
// setSelectedWallItem,
// setSelectedItemsIndex
// );
// setSelectedWallItem(null);
// setSelectedItemsIndex(null);
// }
// }}
// >
// <Geometry ref={csg as any} computeVertexNormals useGroups>
// <WallsMesh lines={lines} />
// <WallItemsGroup
// currentWallItem={currentWallItem}
// hoveredDeletableWallItem={hoveredDeletableWallItem}
// selectedItemsIndex={selectedItemsIndex}
// setSelectedItemsIndex={setSelectedItemsIndex}
// CSGGroup={CSGGroup}
// />
// </Geometry>
// </mesh>
// );
// };
export default WallsAndWallItems;
// export default WallsAndWallItems;

View File

@@ -1,82 +1,82 @@
import * as THREE from "three";
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
import { Base } from "@react-three/csg";
import { MeshDiscardMaterial } from "@react-three/drei";
import { useUpdateScene, useWalls } from "../../../store/builder/store";
import React, { useEffect } from "react";
import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
import loadWalls from "../geomentries/walls/loadWalls";
import texturePath from "../../../assets/textures/floor/wall-tex.png";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../functions/getUserData";
import { useVersionContext } from "../version/versionContext";
// import * as THREE from "three";
// import * as Types from "../../../types/world/worldTypes";
// import * as CONSTANTS from "../../../types/world/worldConstants";
// import { Base } from "@react-three/csg";
// import { MeshDiscardMaterial } from "@react-three/drei";
// import { useUpdateScene, useWalls } from "../../../store/builder/store";
// import React, { useEffect } from "react";
// import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
// import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
// import loadWalls from "../geomentries/walls/loadWalls";
// import texturePath from "../../../assets/textures/floor/wall-tex.png";
// import { useParams } from "react-router-dom";
// import { getUserData } from "../../../functions/getUserData";
// import { useVersionContext } from "../version/versionContext";
const WallsMeshComponent = ({ lines }: any) => {
const { walls, setWalls } = useWalls();
const { updateScene, setUpdateScene } = useUpdateScene();
const { projectId } = useParams();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { organization } = getUserData();
// const WallsMeshComponent = ({ lines }: any) => {
// const { walls, setWalls } = useWalls();
// const { updateScene, setUpdateScene } = useUpdateScene();
// const { projectId } = useParams();
// const { selectedVersionStore } = useVersionContext();
// const { selectedVersion } = selectedVersionStore();
// const { organization } = getUserData();
useEffect(() => {
if (updateScene) {
if (!selectedVersion) {
setUpdateScene(false);
return;
};
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
const Lines: Types.Lines = objectLinesToArray(data);
localStorage.setItem("Lines", JSON.stringify(Lines));
// useEffect(() => {
// if (updateScene) {
// if (!selectedVersion) {
// setUpdateScene(false);
// return;
// };
// getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
// const Lines: Types.Lines = objectLinesToArray(data);
// localStorage.setItem("Lines", JSON.stringify(Lines));
if (Lines) {
loadWalls(lines, setWalls);
}
});
setUpdateScene(false);
}
}, [updateScene, selectedVersion?.versionId]);
// if (Lines) {
// loadWalls(lines, setWalls);
// }
// });
// setUpdateScene(false);
// }
// }, [updateScene, selectedVersion?.versionId]);
const textureLoader = new THREE.TextureLoader();
const wallTexture = textureLoader.load(texturePath);
// const textureLoader = new THREE.TextureLoader();
// const wallTexture = textureLoader.load(texturePath);
wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
wallTexture.repeat.set(0.1, 0.1);
wallTexture.colorSpace = THREE.SRGBColorSpace;
// wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
// wallTexture.repeat.set(0.1, 0.1);
// wallTexture.colorSpace = THREE.SRGBColorSpace;
return (
<>
{walls.map((wall: Types.Wall, index: number) => (
<mesh key={index} renderOrder={1}>
<Base
name={`Wall${index + 1}`}
geometry={wall[0]}
rotation={wall[1]}
position={wall[2]}
userData={{ WallType: wall[3], Layer: wall[4] }}
>
<meshStandardMaterial
side={THREE.DoubleSide}
color={CONSTANTS.wallConfig.defaultColor}
map={wallTexture}
/>
</Base>
<mesh
castShadow
geometry={wall[0]}
rotation={wall[1]}
position={wall[2]}
name={`WallRaycastReference_${index + 1}`}
>
<MeshDiscardMaterial />
</mesh>
</mesh>
))}
</>
);
};
// return (
// <>
// {walls.map((wall: Types.Wall, index: number) => (
// <mesh key={index} renderOrder={1}>
// <Base
// name={`Wall${index + 1}`}
// geometry={wall[0]}
// rotation={wall[1]}
// position={wall[2]}
// userData={{ WallType: wall[3], Layer: wall[4] }}
// >
// <meshStandardMaterial
// side={THREE.DoubleSide}
// color={CONSTANTS.wallConfig.defaultColor}
// map={wallTexture}
// />
// </Base>
// <mesh
// castShadow
// geometry={wall[0]}
// rotation={wall[1]}
// position={wall[2]}
// name={`WallRaycastReference_${index + 1}`}
// >
// <MeshDiscardMaterial />
// </mesh>
// </mesh>
// ))}
// </>
// );
// };
const WallsMesh = React.memo(WallsMeshComponent);
export default WallsMesh;
// const WallsMesh = React.memo(WallsMeshComponent);
// export default WallsMesh;

View File

@@ -1,26 +1,26 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function getClosestIntersection(
intersects: Types.Vector3Array,
point: Types.Vector3
): Types.Vector3 {
////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing //////////
let closestNewPoint: THREE.Vector3 = point;
let minDistance = Infinity;
for (const intersect of intersects) {
const distance = point.distanceTo(intersect);
if (distance < minDistance) {
minDistance = distance;
closestNewPoint = intersect;
}
}
return closestNewPoint;
}
export default getClosestIntersection;
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function getClosestIntersection(
intersects: Types.Vector3Array,
point: Types.Vector3
): Types.Vector3 {
////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing //////////
let closestNewPoint: THREE.Vector3 = point;
let minDistance = Infinity;
for (const intersect of intersects) {
const distance = point.distanceTo(intersect);
if (distance < minDistance) {
minDistance = distance;
closestNewPoint = intersect;
}
}
return closestNewPoint;
}
export default getClosestIntersection;

View File

@@ -12,8 +12,8 @@ import { getUserData } from '../../../functions/getUserData';
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
interface LineProps {
points: [Point, Point];

View File

@@ -0,0 +1,54 @@
// import * as THREE from 'three';
// import updateReferencePolesheight from './updateReferencePolesheight';
// import * as Types from "../../../../types/world/worldTypes";
// function addAndUpdateReferencePillar(
// raycaster: THREE.Raycaster,
// floorGroup: Types.RefGroup,
// referencePole: Types.RefMesh
// ): void {
// ////////// Find Pillars position and scale based on the pointer interaction //////////
// let Roofs = raycaster.intersectObjects(floorGroup.current.children, true);
// const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor"));
// if (intersected) {
// const intersectionPoint = intersected.point;
// raycaster.ray.origin.copy(intersectionPoint);
// raycaster.ray.direction.set(0, -1, 0);
// const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
// const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor"));
// let distance: Types.Number;
// if (validIntersections.length > 1) {
// let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3);
// if (valid) {
// updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup);
// } else {
// const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
// distance = intersected.point.distanceTo(belowPoint);
// if (distance > 3) {
// updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
// }
// }
// } else {
// const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
// distance = intersected.point.distanceTo(belowPoint);
// if (distance > 3) {
// updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
// }
// }
// } else {
// if (referencePole.current) {
// (<any>referencePole.current.material).dispose();
// (<any>referencePole.current.geometry).dispose();
// floorGroup.current.remove(referencePole.current);
// referencePole.current = null;
// }
// }
// }
// export default addAndUpdateReferencePillar;

View File

@@ -0,0 +1,24 @@
// import * as THREE from 'three';
// import * as CONSTANTS from '../../../../types/world/worldConstants';
// import * as Types from "../../../../types/world/worldTypes";
// function addPillar(
// referencePole: Types.RefMesh,
// floorGroup: Types.RefGroup
// ): void {
// ////////// Add Pillars to the scene based on the reference. current poles position and scale //////////
// if (referencePole.current) {
// let pole: THREE.Mesh;
// const geometry = referencePole.current.userData.geometry.clone();
// const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor });
// pole = new THREE.Mesh(geometry, material);
// pole.rotateX(Math.PI / 2);
// pole.name = "Pole";
// pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z);
// floorGroup.current.add(pole);
// }
// }
// export default addPillar;

View File

@@ -0,0 +1,34 @@
// import * as THREE from 'three';
// import * as Types from "../../../../types/world/worldTypes";
// function DeletableHoveredPillar(
// state: Types.ThreeState,
// floorGroup: Types.RefGroup,
// hoveredDeletablePillar: Types.RefMesh
// ): void {
// ////////// Altering the color of the hovered Pillar during the Deletion time //////////
// const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true);
// const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole");
// if (poleIntersect) {
// if (poleIntersect.object.name !== "Pole") {
// return;
// }
// if (hoveredDeletablePillar.current) {
// (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
// hoveredDeletablePillar.current = undefined;
// }
// hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion
// (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red");
// } else {
// if (hoveredDeletablePillar.current) {
// (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
// hoveredDeletablePillar.current = undefined;
// }
// }
// }
// export default DeletableHoveredPillar;

View File

@@ -0,0 +1,21 @@
// import { toast } from 'react-toastify';
// import * as Types from "../../../../types/world/worldTypes";
// function DeletePillar(
// hoveredDeletablePillar: Types.RefMesh,
// floorGroup: Types.RefGroup
// ): void {
// ////////// Deleting the hovered Pillar from the itemsGroup //////////
// if (hoveredDeletablePillar.current) {
// (<any>hoveredDeletablePillar.current.material).dispose();
// (<any>hoveredDeletablePillar.current.geometry).dispose();
// floorGroup.current.remove(hoveredDeletablePillar.current);
// echo.success("Pillar Removed!");
// hoveredDeletablePillar.current = undefined;
// }
// }
// export default DeletePillar;

View File

@@ -0,0 +1,40 @@
// import * as THREE from 'three';
// import * as Types from "../../../../types/world/worldTypes";
// function updateReferencePolesheight(
// intersectionPoint: Types.Vector3,
// distance: Types.Number,
// referencePole: Types.RefMesh,
// floorGroup: Types.RefGroup
// ): void {
// ////////// Add a Reference Pillar and update its position and scale based on the pointer interaction //////////
// if (referencePole.current) {
// (<any>referencePole.current.material).dispose();
// (<any>referencePole.current.geometry).dispose();
// floorGroup.current.remove(referencePole.current);
// referencePole.current.geometry.dispose();
// }
// const shape = new THREE.Shape();
// shape.moveTo(0.5, 0);
// shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false);
// const extrudeSettings = {
// depth: distance,
// bevelEnabled: false,
// };
// const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
// const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 });
// referencePole.current = new THREE.Mesh(geometry, material);
// referencePole.current.rotateX(Math.PI / 2);
// referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z);
// referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } };
// floorGroup.current.add(referencePole.current);
// }
// export default updateReferencePolesheight;

View File

@@ -8,7 +8,7 @@ import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import { useParams } from 'react-router-dom';
import { useVersionContext } from '../../version/versionContext';
import { getUserData } from '../../../../functions/getUserData';
import getClosestIntersection from '../../geomentries/lines/getClosestIntersection';
import getClosestIntersection from '../../line/helpers/getClosestIntersection';
import ReferencePoint from '../../point/reference/referencePoint';
import ReferenceWall from './referenceWall';

View File

@@ -1,891 +1,9 @@
import { useEffect } from "react";
import * as THREE from "three";
import gsap from "gsap";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import {
useSocketStore,
useActiveLayer,
useWallItems,
useLayers,
useUpdateScene,
useWalls,
useDeletedLines,
useNewLines,
useZonePoints,
useZones,
} from "../../../store/builder/store";
import React from 'react';
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
export default function SocketResponses() {
// import { setFloorItemApi } from "../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
import objectLineToArray from "../../builder/geomentries/lines/lineConvertions/objectLineToArray";
import addLineToScene from "../../builder/geomentries/lines/addLineToScene";
import updateLinesPositions from "../../builder/geomentries/lines/updateLinesPositions";
import updateLines from "../../builder/geomentries/lines/updateLines";
import updateDistanceText from "../../builder/geomentries/lines/updateDistanceText";
import updateFloorLines from "../../builder/geomentries/floors/updateFloorLines";
import loadWalls from "../../builder/geomentries/walls/loadWalls";
import RemoveConnectedLines from "../../builder/geomentries/lines/removeConnectedLines";
import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../functions/getUserData";
import { useSceneContext } from "../../scene/sceneContext";
import { useVersionContext } from "../../builder/version/versionContext";
export default function SocketResponses({
floorPlanGroup,
lines,
floorGroup,
scene,
onlyFloorlines,
currentLayerPoint,
floorPlanGroupPoint,
floorPlanGroupLine,
dragPointControls,
}: any) {
const { socket } = useSocketStore();
const { activeLayer, setActiveLayer } = useActiveLayer();
const { wallItems, setWallItems } = useWallItems();
const { setLayers } = useLayers();
const { setUpdateScene } = useUpdateScene();
const { setWalls } = useWalls();
const { setDeletedLines } = useDeletedLines();
const { setNewLines } = useNewLines();
const { zones, setZones } = useZones();
const { zonePoints, setZonePoints } = useZonePoints();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { assetStore, eventStore, productStore } = useSceneContext();
const { addAsset, updateAsset, removeAsset } = assetStore();
const { organization } = getUserData();
useEffect(() => {
if (!socket) return;
socket.on("cameraCreateResponse", (data: any) => {
//
});
socket.on("userConnectRespones", (data: any) => {
//
});
socket.on("userDisConnectRespones", (data: any) => {
//
});
socket.on("v1:camera:Response:update", (data: any) => {
//
});
socket.on("EnvironmentUpdateResponse", (data: any) => {
//
});
socket.on("v1:model-asset:response:add", async (data: any) => {
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "Model created successfully") {
try {
const asset: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: false,
isVisible: data.data.isVisible,
opacity: 1,
}
addAsset(asset);
echo.success("Added model through collaboration");
} catch (error) {
echo.error("Failed to create model through collaboration");
}
} else if (data.message === "Model updated successfully") {
try {
const asset: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: false,
isVisible: data.data.isVisible,
opacity: 1,
}
updateAsset(asset.modelUuid, {
position: asset.position,
rotation: asset.rotation,
});
echo.success("Updated model through collaboration");
} catch (error) {
echo.error("Failed to update model through collaboration");
}
} else {
echo.error("Failed executing action from collaboration");
}
});
socket.on("v1:model-asset:response:delete", (data: any) => {
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "Model deleted successfully") {
try {
const deletedUUID = data.data.modelUuid;
eventStore.getState().removeEvent(deletedUUID);
productStore.getState().deleteEvent(deletedUUID);
removeAsset(deletedUUID);
echo.success("Model Removed successfully through collaboration");
} catch (error) {
echo.error("Failed to remove model through collaboration");
}
}
});
socket.on("v1:Line:response:update", (data: any) => {
// console.log('data: ', data);
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "line updated") {
const DraggedUUID = data.data.uuid;
const DraggedPosition = new THREE.Vector3(
data.data.position.x,
data.data.position.y,
data.data.position.z
);
const point = floorPlanGroupPoint.current.getObjectByProperty(
"uuid",
DraggedUUID
);
point.position.set(
DraggedPosition.x,
DraggedPosition.y,
DraggedPosition.z
);
const affectedLines = updateLinesPositions(
{ uuid: DraggedUUID, position: DraggedPosition },
lines
);
updateLines(floorPlanGroupLine, affectedLines);
updateDistanceText(scene, floorPlanGroupLine, affectedLines);
updateFloorLines(onlyFloorlines, {
uuid: DraggedUUID,
position: DraggedPosition,
});
loadWalls(lines, setWalls);
setUpdateScene(true);
}
});
socket.on("v1:Line:response:delete", (data: any) => {
// console.log('data: ', data);
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "line deleted") {
const line = objectLineToArray(data.data);
const linePoints = line;
const connectedpoints = [linePoints[0][1], linePoints[1][1]];
onlyFloorlines.current = onlyFloorlines.current
.map((floorline: any) =>
floorline.filter(
(line: any) =>
line[0][1] !== connectedpoints[0] &&
line[1][1] !== connectedpoints[1]
)
)
.filter((floorline: any) => floorline.length > 0);
const removedLine = lines.current.find(
(item: any) =>
(item[0][1] === linePoints[0][1] &&
item[1][1] === linePoints[1][1]) ||
(item[0][1] === linePoints[1][1] && item[1][1] === linePoints[0][1])
);
lines.current = lines.current.filter(
(item: any) => item !== removedLine
);
floorPlanGroupLine.current.children.forEach((line: any) => {
const linePoints = line.userData.linePoints as [
number,
string,
number
][];
const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1];
if (
(uuid1 === connectedpoints[0] && uuid2 === connectedpoints[1]) ||
(uuid1 === connectedpoints[1] && uuid2 === connectedpoints[0])
) {
line.material.dispose();
line.geometry.dispose();
floorPlanGroupLine.current.remove(line);
setDeletedLines([line.userData.linePoints]);
}
});
connectedpoints.forEach((pointUUID) => {
let isConnected = false;
floorPlanGroupLine.current.children.forEach((line: any) => {
const linePoints = line.userData.linePoints;
const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1];
if (uuid1 === pointUUID || uuid2 === pointUUID) {
isConnected = true;
}
});
if (!isConnected) {
floorPlanGroupPoint.current.children.forEach((point: any) => {
if (point.uuid === pointUUID) {
point.material.dispose();
point.geometry.dispose();
floorPlanGroupPoint.current.remove(point);
}
});
}
});
loadWalls(lines, setWalls);
setUpdateScene(true);
echo.success("Line Removed!");
}
});
socket.on("v1:Line:response:delete:point", (data: any) => {
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "point deleted") {
const point = floorPlanGroupPoint.current?.getObjectByProperty(
"uuid",
data.data
);
point.material.dispose();
point.geometry.dispose();
floorPlanGroupPoint.current.remove(point);
onlyFloorlines.current = onlyFloorlines.current
.map((floorline: any) =>
floorline.filter(
(line: any) =>
line[0][1] !== data.data && line[1][1] !== data.data
)
)
.filter((floorline: any) => floorline.length > 0);
RemoveConnectedLines(
data.data,
floorPlanGroupLine,
floorPlanGroupPoint,
setDeletedLines,
lines
);
loadWalls(lines, setWalls);
setUpdateScene(true);
echo.success("Point Removed!");
}
});
socket.on("v1:Line:response:delete:layer", async (data: any) => {
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "layer deleted") {
setActiveLayer(1);
const removedLayer = data.data;
const removedLines: Types.Lines = lines.current.filter(
(line: any) => line[0][2] === removedLayer
);
////////// Remove Points and lines from the removed layer //////////
removedLines.forEach(async (line) => {
line.forEach(async (removedPoint) => {
const removableLines: THREE.Mesh[] = [];
const connectedpoints: string[] = [];
floorPlanGroupLine.current.children.forEach((line: any) => {
const linePoints = line.userData.linePoints as [
number,
string,
number
][];
const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1];
if (uuid1 === removedPoint[1] || uuid2 === removedPoint[1]) {
connectedpoints.push(uuid1 === removedPoint[1] ? uuid2 : uuid1);
removableLines.push(line as THREE.Mesh);
}
});
if (removableLines.length > 0) {
removableLines.forEach((line: any) => {
lines.current = lines.current.filter(
(item: any) =>
JSON.stringify(item) !==
JSON.stringify(line.userData.linePoints)
);
line.material.dispose();
line.geometry.dispose();
floorPlanGroupLine.current.remove(line);
});
}
const point = floorPlanGroupPoint.current.getObjectByProperty(
"uuid",
removedPoint[1]
);
if (point) {
point.material.dispose();
point.geometry.dispose();
floorPlanGroupPoint.current.remove(point);
}
});
});
////////// Update the remaining lines layer values in the userData and in lines.current //////////
let remaining = lines.current.filter(
(line: any) => line[0][2] !== removedLayer
);
let updatedLines: Types.Lines = [];
remaining.forEach((line: any) => {
let newLines = JSON.parse(JSON.stringify(line));
if (newLines[0][2] > removedLayer) {
newLines[0][2] -= 1;
newLines[1][2] -= 1;
}
const matchingLine = floorPlanGroupLine.current.children.find(
(l: any) =>
l.userData.linePoints[0][1] === line[0][1] &&
l.userData.linePoints[1][1] === line[1][1]
);
if (matchingLine) {
const updatedUserData = JSON.parse(
JSON.stringify(matchingLine.userData)
);
updatedUserData.linePoints[0][2] = newLines[0][2];
updatedUserData.linePoints[1][2] = newLines[1][2];
matchingLine.userData = updatedUserData;
}
updatedLines.push(newLines);
});
lines.current = updatedLines;
localStorage.setItem("Lines", JSON.stringify(lines.current));
////////// Also remove OnlyFloorLines and update it in localstorage //////////
onlyFloorlines.current = onlyFloorlines.current.filter((floor: any) => {
return floor[0][0][2] !== removedLayer;
});
const meshToRemove = floorGroup.current?.children.find(
(mesh: any) => mesh.name === `Only_Floor_Line_${removedLayer}`
);
if (meshToRemove) {
meshToRemove.geometry.dispose();
meshToRemove.material.dispose();
floorGroup.current?.remove(meshToRemove);
}
const zonesData = await getZonesApi(organization, projectId, selectedVersion?.versionId || '');
const highestLayer = Math.max(
1,
lines.current.reduce(
(maxLayer: number, segment: any) =>
Math.max(maxLayer, segment.layer || 0),
0
),
zonesData.reduce(
(maxLayer: number, zone: any) =>
Math.max(maxLayer, zone.layer || 0),
0
)
);
setLayers(highestLayer);
loadWalls(lines, setWalls);
setUpdateScene(true);
echo.success("Layer Removed!");
}
});
return () => {
socket.off("cameraCreateResponse");
socket.off("userConnectRespones");
socket.off("userDisConnectRespones");
socket.off("v1:camera:Response:update");
socket.off("EnvironmentUpdateResponse");
socket.off("v1:model-asset:response:add");
socket.off("v1:model-asset:response:delete");
socket.off("v1:Line:response:update");
socket.off("v1:Line:response:delete");
socket.off("v1:Line:response:delete:point");
socket.off("v1:Line:response:delete:layer");
}
}, [socket, selectedVersion?.versionId]);
useEffect(() => {
if (!socket) return;
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
socket.on("v1:wallItem:Response:Delete", (data: any) => {
// console.log('data: ', data);
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "wall Item deleted successfully") {
const deletedUUID = data.data.modelUuid;
let WallItemsRef = wallItems;
const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID);
setWallItems([]);
setTimeout(async () => {
WallItemsRef = Items;
setWallItems(WallItemsRef);
const WallItemsForStorage = WallItemsRef.map((item: any) => {
const { model, ...rest } = item;
return {
...rest,
modelUuid: model?.uuid,
};
});
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
echo.success("Model Removed!");
}, 50);
}
});
socket.on("v1:wallItems:Response:Update", (data: any) => {
// console.log('data: ', data);
//
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "wall Item created successfully") {
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
loader.setDRACOLoader(dracoLoader);
// Check THREE.js cache first
const cachedModel = THREE.Cache.get(data.data.assetId);
if (cachedModel) {
handleModelLoad(cachedModel);
return;
}
// Check IndexedDB cache
retrieveGLTF(data.data.assetId).then((cachedModelBlob) => {
if (cachedModelBlob) {
const blobUrl = URL.createObjectURL(cachedModelBlob);
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(data.data.assetId, gltf);
handleModelLoad(gltf);
});
return;
}
})
// Load from backend if not in any cache
loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.assetId}`, async (gltf) => {
try {
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.assetId}`).then((res) => res.blob());
await storeGLTF(data.data.assetId, modelBlob);
THREE.Cache.add(data.data.assetId, gltf);
await handleModelLoad(gltf);
} catch (error) {
handleModelLoad(gltf);
}
});
async function handleModelLoad(gltf: GLTF) {
const model = gltf.scene.clone();
model.uuid = data.data.modelUuid;
model.children[0].children.forEach((child) => {
if (child.name !== "CSG_REF") {
child.castShadow = true;
child.receiveShadow = true;
}
});
const newWallItem = {
type: data.data.type,
model: model,
modelName: data.data.modelName,
assetId: data.data.assetId,
scale: data.data.scale,
csgscale: data.data.csgscale,
csgposition: data.data.csgposition,
position: data.data.position,
quaternion: data.data.quaternion,
};
setWallItems((prevItems: Types.wallItems) => {
const updatedItems = [...prevItems, newWallItem];
const WallItemsForStorage = updatedItems.map(item => {
const { model, ...rest } = item;
return {
...rest,
modelUuid: model?.uuid,
};
});
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
echo.success("Model Added!");
return updatedItems;
});
}
} else if (data.message === "Updated successfully") {
const updatedUUID = data.data.modelUuid;
setWallItems((prevItems: any) => {
const updatedItems = prevItems.map((item: any) => {
if (item.model.uuid === updatedUUID) {
return {
...item,
position: data.data.position,
quaternion: data.data.quaternion,
scale: data.data.scale,
csgscale: data.data.csgscale,
csgposition: data.data.csgposition,
};
}
return item;
});
const WallItemsForStorage = updatedItems.map((item: any) => {
const { model, ...rest } = item;
return {
...rest,
modelUuid: model?.uuid,
};
});
localStorage.setItem(
"WallItems",
JSON.stringify(WallItemsForStorage)
);
echo.success("Model Updated!");
return updatedItems;
});
}
});
return () => {
socket.off("v1:wallItem:Response:Delete");
socket.off("v1:wallItems:Response:Update");
};
}, [socket, wallItems]);
function getPointColor(lineType: string | undefined): string {
switch (lineType) {
case CONSTANTS.lineConfig.wallName:
return CONSTANTS.pointConfig.wallOuterColor;
case CONSTANTS.lineConfig.floorName:
return CONSTANTS.pointConfig.floorOuterColor;
case CONSTANTS.lineConfig.aisleName:
return CONSTANTS.pointConfig.aisleOuterColor;
default:
return CONSTANTS.pointConfig.defaultOuterColor;
}
}
function getLineColor(lineType: string | undefined): string {
switch (lineType) {
case CONSTANTS.lineConfig.wallName:
return CONSTANTS.lineConfig.wallColor;
case CONSTANTS.lineConfig.floorName:
return CONSTANTS.lineConfig.floorColor;
case CONSTANTS.lineConfig.aisleName:
return CONSTANTS.lineConfig.aisleColor;
default:
return CONSTANTS.lineConfig.defaultColor;
}
}
useEffect(() => {
if (!socket) return;
socket.on("v1:Line:response:create", async (data: any) => {
//
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "line create") {
const line: Types.Line = objectLineToArray(data.data);
const type = line[0][3];
const pointColour = getPointColor(type);
const lineColour = getLineColor(type);
setNewLines([line]);
line.forEach((line) => {
const existingPoint =
floorPlanGroupPoint.current?.getObjectByProperty("uuid", line[1]);
if (existingPoint) {
return;
}
const geometry = new THREE.BoxGeometry(
...CONSTANTS.pointConfig.boxScale
);
const material = new THREE.ShaderMaterial({
uniforms: {
uOuterColor: { value: new THREE.Color(pointColour) }, // Blue color for the border
uInnerColor: {
value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor),
}, // White color for the inner square
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
uniform vec3 uOuterColor;
uniform vec3 uInnerColor;
void main() {
// Define the size of the white square as a proportion of the face
float borderThickness = 0.2; // Adjust this value for border thickness
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
} else {
gl_FragColor = vec4(uOuterColor, 1.0); // Blue border
}
}
`,
});
const point = new THREE.Mesh(geometry, material);
point.name = "point";
point.uuid = line[1];
point.userData = { type: type, color: pointColour };
point.position.set(line[0].x, line[0].y, line[0].z);
currentLayerPoint.current.push(point);
floorPlanGroupPoint.current?.add(point);
});
if (dragPointControls.current) {
dragPointControls.current!.objects = currentLayerPoint.current;
}
addLineToScene(
new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z),
new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z),
lineColour,
line,
floorPlanGroupLine
);
lines.current.push(line);
const zonesData = await getZonesApi(organization, projectId, selectedVersion?.versionId || '');
const highestLayer = Math.max(
1,
lines.current.reduce(
(maxLayer: number, segment: any) =>
Math.max(maxLayer, segment.layer || 0),
0
),
zonesData.reduce(
(maxLayer: number, zone: any) =>
Math.max(maxLayer, zone.layer || 0),
0
)
);
setLayers(highestLayer);
Layer2DVisibility(
activeLayer,
floorPlanGroup,
floorPlanGroupLine,
floorPlanGroupPoint,
currentLayerPoint,
dragPointControls
);
loadWalls(lines, setWalls);
setUpdateScene(true);
}
});
return () => {
socket.off("v1:Line:response:create");
};
}, [socket, activeLayer, selectedVersion?.versionId]);
useEffect(() => {
if (!socket) return;
socket.on("v1:zone:response:updates", (data: any) => {
// console.log('data: ', data);
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "zone created") {
const pointsArray: [number, number, number][] = data.data.points;
const vector3Array = pointsArray.map(
([x, y, z]) => new THREE.Vector3(x, y, z)
);
const newZones = [...zones, data.data];
setZones(newZones);
const updatedZonePoints = [...zonePoints, ...vector3Array];
setZonePoints(updatedZonePoints);
const highestLayer = Math.max(
1,
lines.current.reduce(
(maxLayer: number, segment: any) =>
Math.max(maxLayer, segment.layer || 0),
0
),
newZones.reduce(
(maxLayer: number, zone: any) =>
Math.max(maxLayer, zone.layer || 0),
0
)
);
setLayers(highestLayer);
setUpdateScene(true);
}
if (data.message === "zone updated") {
const updatedZones = zones.map((zone: any) =>
zone.zoneUuid === data.data.zoneUuid ? data.data : zone
);
setZones(updatedZones);
setUpdateScene(true);
}
});
socket.on("v1:zone:response:delete", (data: any) => {
// console.log('data: ', data);
if (socket.id === data.socketId) {
return;
}
if (organization !== data.organization) {
return;
}
if (data.message === "zone deleted") {
const updatedZones = zones.filter(
(zone: any) => zone.zoneUuid !== data.data.zoneUuid
);
setZones(updatedZones);
const zoneIndex = zones.findIndex(
(zone: any) => zone.zoneUuid === data.data.zoneUuid
);
if (zoneIndex !== -1) {
const updatedzonePoints = zonePoints.filter(
(_: any, index: any) =>
index < zoneIndex * 4 || index >= zoneIndex * 4 + 4
);
setZonePoints(updatedzonePoints);
}
const highestLayer = Math.max(
1,
lines.current.reduce(
(maxLayer: number, segment: any) =>
Math.max(maxLayer, segment.layer || 0),
0
),
updatedZones.reduce(
(maxLayer: number, zone: any) =>
Math.max(maxLayer, zone.layer || 0),
0
)
);
setLayers(highestLayer);
setUpdateScene(true);
}
});
return () => {
socket.off("v1:zone:response:updates");
socket.off("v1:zone:response:delete");
};
}, [socket, zones, zonePoints]);
return <></>;
return (
<>
</>
);
}

View File

@@ -5,18 +5,14 @@ import NavMeshDetails from "./navMeshDetails";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import * as Types from "../../../../types/world/worldTypes";
type NavMeshProps = {
lines: Types.RefLines
};
function NavMesh({ lines }: NavMeshProps) {
function NavMesh() {
let groupRef = useRef() as Types.RefGroup;
const { setNavMesh } = useNavMesh();
return (
<>
<PolygonGenerator groupRef={groupRef} lines={lines} />
<NavMeshDetails lines={lines} setNavMesh={setNavMesh} groupRef={groupRef} />
<PolygonGenerator groupRef={groupRef} />
<NavMeshDetails setNavMesh={setNavMesh} groupRef={groupRef} />
<group ref={groupRef} visible={false} name="Meshes">
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} receiveShadow>

View File

@@ -9,11 +9,9 @@ import * as Types from "../../../../types/world/worldTypes";
interface NavMeshDetailsProps {
setNavMesh: (navMesh: any) => void;
groupRef: React.MutableRefObject<THREE.Group | null>;
lines: Types.RefLines;
}
export default function NavMeshDetails({
lines,
setNavMesh,
groupRef,
}: NavMeshDetailsProps) {
@@ -63,7 +61,7 @@ export default function NavMeshDetails({
};
initializeNavigation();
}, [scene, groupRef, lines.current]);
}, [scene, groupRef]);
return null;
}

View File

@@ -2,26 +2,23 @@ import * as THREE from "three";
import { useEffect } from "react";
import * as turf from "@turf/turf";
import * as Types from "../../../../types/world/worldTypes";
import arrayLinesToObject from "../../../builder/geomentries/lines/lineConvertions/arrayLinesToObject";
import { useThree } from "@react-three/fiber";
import { useSceneContext } from "../../../scene/sceneContext";
interface PolygonGeneratorProps {
groupRef: React.MutableRefObject<THREE.Group | null>;
lines: Types.RefLines;
}
export default function PolygonGenerator({
groupRef,
lines,
}: PolygonGeneratorProps) {
const { aisleStore } = useSceneContext();
const { aisles } = aisleStore();
const { scene } = useThree();
useEffect(() => {
let allLines = arrayLinesToObject(lines.current);
const wallLines = allLines?.filter((line) => line?.type === "WallLine");
// let allLines = arrayLinesToObject(lines.current);
// const wallLines = allLines?.filter((line) => line?.type === "WallLine");
const result = aisles
.filter(
(aisle) =>
@@ -64,9 +61,9 @@ export default function PolygonGenerator({
});
});
const wallPoints = wallLines
.map((pair) => pair?.line.map((vals) => vals.position))
.filter((wall): wall is THREE.Vector3[] => !!wall);
// const wallPoints = wallLines
// .map((pair) => pair?.line.map((vals) => vals.position))
// .filter((wall): wall is THREE.Vector3[] => !!wall);
if (!result || result.some((line) => !line)) {
@@ -84,7 +81,7 @@ export default function PolygonGenerator({
const polygons = turf.polygonize(turf.featureCollection(validLineFeatures));
renderWallGeometry(wallPoints);
// renderWallGeometry(wallPoints);
if (polygons.features.length > 0) {
polygons.features.forEach((feature) => {
@@ -119,7 +116,7 @@ export default function PolygonGenerator({
});
}
}, [lines.current, aisles, scene]);
}, [ aisles, scene]);
const renderWallGeometry = (walls: THREE.Vector3[][]) => {
walls.forEach((wall) => {