upstream pull + signIn/Up

This commit is contained in:
2025-03-25 17:34:20 +05:30
199 changed files with 40127 additions and 40128 deletions

View File

@@ -1,56 +1,56 @@
import * as THREE from 'three';
import * as Types from '../../../../types/world/worldTypes';
import * as CONSTANTS from '../../../../types/world/worldConstants';
export default async function addAisleToScene(
aisle: Types.Line,
floorGroupAisle: Types.RefGroup,
): Promise<void> {
if (aisle.length >= 2 && aisle[0] && aisle[1]) {
const start: Types.Vector3 = aisle[0][0];
const end: Types.Vector3 = aisle[1][0];
const direction = new THREE.Vector3(
end.x - start.x,
end.y - start.y,
end.z - start.z
).normalize();
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
const offsetDistance = CONSTANTS.aisleConfig.width;
const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance);
const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance);
const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance);
const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance);
const stripShape = new THREE.Shape();
stripShape.moveTo(leftStart.x, leftStart.z);
stripShape.lineTo(leftEnd.x, leftEnd.z);
stripShape.lineTo(rightEnd.x, rightEnd.z);
stripShape.lineTo(rightStart.x, rightStart.z);
stripShape.lineTo(leftStart.x, leftStart.z);
const extrudeSettings = {
depth: CONSTANTS.aisleConfig.height,
bevelEnabled: false,
};
const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings);
const stripMaterial = new THREE.MeshStandardMaterial({
color: CONSTANTS.aisleConfig.defaultColor,
polygonOffset: true,
polygonOffsetFactor: -1,
polygonOffsetUnits: -1,
});
const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial);
stripMesh.receiveShadow = true;
stripMesh.castShadow = true;
stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01;
stripMesh.rotateX(Math.PI / 2);
floorGroupAisle.current.add(stripMesh);
}
}
import * as THREE from 'three';
import * as Types from '../../../../types/world/worldTypes';
import * as CONSTANTS from '../../../../types/world/worldConstants';
export default async function addAisleToScene(
aisle: Types.Line,
floorGroupAisle: Types.RefGroup,
): Promise<void> {
if (aisle.length >= 2 && aisle[0] && aisle[1]) {
const start: Types.Vector3 = aisle[0][0];
const end: Types.Vector3 = aisle[1][0];
const direction = new THREE.Vector3(
end.x - start.x,
end.y - start.y,
end.z - start.z
).normalize();
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
const offsetDistance = CONSTANTS.aisleConfig.width;
const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance);
const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance);
const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance);
const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance);
const stripShape = new THREE.Shape();
stripShape.moveTo(leftStart.x, leftStart.z);
stripShape.lineTo(leftEnd.x, leftEnd.z);
stripShape.lineTo(rightEnd.x, rightEnd.z);
stripShape.lineTo(rightStart.x, rightStart.z);
stripShape.lineTo(leftStart.x, leftStart.z);
const extrudeSettings = {
depth: CONSTANTS.aisleConfig.height,
bevelEnabled: false,
};
const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings);
const stripMaterial = new THREE.MeshStandardMaterial({
color: CONSTANTS.aisleConfig.defaultColor,
polygonOffset: true,
polygonOffsetFactor: -1,
polygonOffsetUnits: -1,
});
const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial);
stripMesh.receiveShadow = true;
stripMesh.castShadow = true;
stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01;
stripMesh.rotateX(Math.PI / 2);
floorGroupAisle.current.add(stripMesh);
}
}

View File

@@ -1,19 +1,19 @@
import * as Types from '../../../../types/world/worldTypes';
import addAisleToScene from './addAilseToScene';
import * as CONSTANTS from '../../../../types/world/worldConstants';
export default async function loadAisles(
lines: Types.RefLines,
floorGroupAisle: Types.RefGroup
) {
// console.log('lines: ', lines.current[0][0][0]);
if (!floorGroupAisle.current) return
floorGroupAisle.current.children = [];
const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName);
if (aisles.length > 0) {
aisles.forEach((aisle: Types.Line) => {
addAisleToScene(aisle, floorGroupAisle)
})
}
import * as Types from '../../../../types/world/worldTypes';
import addAisleToScene from './addAilseToScene';
import * as CONSTANTS from '../../../../types/world/worldConstants';
export default async function loadAisles(
lines: Types.RefLines,
floorGroupAisle: Types.RefGroup
) {
// console.log('lines: ', lines.current[0][0][0]);
if (!floorGroupAisle.current) return
floorGroupAisle.current.children = [];
const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName);
if (aisles.length > 0) {
aisles.forEach((aisle: Types.Line) => {
addAisleToScene(aisle, floorGroupAisle)
})
}
}

View File

@@ -1,186 +1,186 @@
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import gsap from 'gsap';
import { toast } from 'react-toastify';
import TempLoader from './tempLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import * as Types from "../../../../types/world/worldTypes";
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { Socket } from 'socket.io-client';
import * as CONSTANTS from '../../../../types/world/worldConstants';
async function addAssetModel(
raycaster: THREE.Raycaster,
camera: THREE.Camera,
pointer: THREE.Vector2,
floorGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState,
itemsGroup: Types.RefGroup,
isTempLoader: Types.RefBoolean,
tempLoader: Types.RefMesh,
socket: Socket<any>,
selectedItem: any,
setSelectedItem: any,
plane: Types.RefMesh,
): Promise<void> {
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
try {
isTempLoader.current = true;
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);
raycaster.setFromCamera(pointer, camera);
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor"));
const planeIntersections = raycaster.intersectObject(plane.current!, true);
const intersectedPlane = planeIntersections[0];
let intersectPoint: THREE.Vector3 | null = null;
if (intersectedFloor && intersectedPlane) {
intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z));
} else if (intersectedFloor) {
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
} else if (intersectedPlane) {
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
}
if (intersectPoint) {
if (intersectPoint.y < 0) {
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
}
const cachedModel = THREE.Cache.get(selectedItem.id);
if (cachedModel) {
// console.log(`[Cache] Fetching ${selectedItem.name}`);
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
return;
} else {
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
if (cachedModelBlob) {
// console.log(`Added ${selectedItem.name} from indexDB`);
const blobUrl = URL.createObjectURL(cachedModelBlob);
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(selectedItem.id, gltf);
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
});
} else {
// console.log(`Added ${selectedItem.name} from Backend`);
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
await storeGLTF(selectedItem.id, modelBlob);
THREE.Cache.add(selectedItem.id, gltf);
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
});
}
}
}
} catch (error) {
console.error('Error fetching asset model:', error);
} finally {
setSelectedItem({});
}
}
async function handleModelLoad(
gltf: any,
intersectPoint: THREE.Vector3,
selectedItem: any,
itemsGroup: Types.RefGroup,
tempLoader: Types.RefMesh,
isTempLoader: Types.RefBoolean,
setFloorItems: Types.setFloorItemSetState,
socket: Socket<any>
) {
const model = gltf.scene.clone();
model.userData = { name: selectedItem.name, modelId: selectedItem.id };
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.traverse((child: any) => {
if (child) {
child.castShadow = true;
child.receiveShadow = true;
}
});
itemsGroup.current.add(model);
if (tempLoader.current) {
(<any>tempLoader.current.material).dispose();
(<any>tempLoader.current.geometry).dispose();
itemsGroup.current.remove(tempLoader.current);
tempLoader.current = undefined;
}
const newFloorItem: Types.FloorItemType = {
modeluuid: model.uuid,
modelname: selectedItem.name,
modelfileID: selectedItem.id,
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
isLocked: false,
isVisible: true
};
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
// await setFloorItemApi(
// organization,
// newFloorItem.modeluuid,
// newFloorItem.modelname,
// newFloorItem.position,
// { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z },
// newFloorItem.modelfileID!,
// false,
// true,
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
};
socket.emit("v1:FloorItems:set", data);
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
}
export default addAssetModel;
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import gsap from 'gsap';
import { toast } from 'react-toastify';
import TempLoader from './tempLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import * as Types from "../../../../types/world/worldTypes";
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { Socket } from 'socket.io-client';
import * as CONSTANTS from '../../../../types/world/worldConstants';
async function addAssetModel(
raycaster: THREE.Raycaster,
camera: THREE.Camera,
pointer: THREE.Vector2,
floorGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState,
itemsGroup: Types.RefGroup,
isTempLoader: Types.RefBoolean,
tempLoader: Types.RefMesh,
socket: Socket<any>,
selectedItem: any,
setSelectedItem: any,
plane: Types.RefMesh,
): Promise<void> {
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
try {
isTempLoader.current = true;
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);
raycaster.setFromCamera(pointer, camera);
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor"));
const planeIntersections = raycaster.intersectObject(plane.current!, true);
const intersectedPlane = planeIntersections[0];
let intersectPoint: THREE.Vector3 | null = null;
if (intersectedFloor && intersectedPlane) {
intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z));
} else if (intersectedFloor) {
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
} else if (intersectedPlane) {
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
}
if (intersectPoint) {
if (intersectPoint.y < 0) {
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
}
const cachedModel = THREE.Cache.get(selectedItem.id);
if (cachedModel) {
// console.log(`[Cache] Fetching ${selectedItem.name}`);
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
return;
} else {
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
if (cachedModelBlob) {
// console.log(`Added ${selectedItem.name} from indexDB`);
const blobUrl = URL.createObjectURL(cachedModelBlob);
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(selectedItem.id, gltf);
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
});
} else {
// console.log(`Added ${selectedItem.name} from Backend`);
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
await storeGLTF(selectedItem.id, modelBlob);
THREE.Cache.add(selectedItem.id, gltf);
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
});
}
}
}
} catch (error) {
console.error('Error fetching asset model:', error);
} finally {
setSelectedItem({});
}
}
async function handleModelLoad(
gltf: any,
intersectPoint: THREE.Vector3,
selectedItem: any,
itemsGroup: Types.RefGroup,
tempLoader: Types.RefMesh,
isTempLoader: Types.RefBoolean,
setFloorItems: Types.setFloorItemSetState,
socket: Socket<any>
) {
const model = gltf.scene.clone();
model.userData = { name: selectedItem.name, modelId: selectedItem.id };
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.traverse((child: any) => {
if (child) {
child.castShadow = true;
child.receiveShadow = true;
}
});
itemsGroup.current.add(model);
if (tempLoader.current) {
(<any>tempLoader.current.material).dispose();
(<any>tempLoader.current.geometry).dispose();
itemsGroup.current.remove(tempLoader.current);
tempLoader.current = undefined;
}
const newFloorItem: Types.FloorItemType = {
modeluuid: model.uuid,
modelname: selectedItem.name,
modelfileID: selectedItem.id,
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
isLocked: false,
isVisible: true
};
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
// await setFloorItemApi(
// organization,
// newFloorItem.modeluuid,
// newFloorItem.modelname,
// newFloorItem.position,
// { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z },
// newFloorItem.modelfileID!,
// false,
// true,
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
};
socket.emit("v1:FloorItems:set", data);
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
}
export default addAssetModel;

View File

@@ -1,153 +1,153 @@
import * as THREE from "three";
import gsap from "gsap";
import * as Types from "../../../../types/world/worldTypes";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
import * as CONSTANTS from '../../../../types/world/worldConstants';
import { toast } from 'react-toastify';
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
let currentTaskId = 0; // Track the active task
let activePromises = new Map<number, boolean>(); // Map to track task progress
export default async function assetManager(
data: any,
itemsGroup: Types.RefGroup,
loader: GLTFLoader,
) {
const taskId = ++currentTaskId; // Increment taskId for each call
activePromises.set(taskId, true); // Mark task as active
// console.log("Received message from worker:", data);
if (data.toRemove.length > 0) {
data.toRemove.forEach((uuid: string) => {
const item = itemsGroup.current.getObjectByProperty("uuid", uuid);
if (item) {
// Traverse and dispose of resources
// item.traverse((child: THREE.Object3D) => {
// if (child instanceof THREE.Mesh) {
// if (child.geometry) child.geometry.dispose();
// if (Array.isArray(child.material)) {
// child.material.forEach((material) => {
// if (material.map) material.map.dispose();
// material.dispose();
// });
// } else if (child.material) {
// if (child.material.map) child.material.map.dispose();
// child.material.dispose();
// }
// }
// });
// Remove the object from the scene
itemsGroup.current.remove(item);
}
});
}
if (data.toAdd.length > 0) {
await initializeDB();
for (const item of data.toAdd) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
await new Promise<void>(async (resolve) => {
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
// Check Three.js Cache
const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve);
return;
}
// Check IndexedDB
const indexedDBModel = await retrieveGLTF(item.modelfileID!);
if (indexedDBModel) {
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
const blobUrl = URL.createObjectURL(indexedDBModel);
loader.load(
blobUrl,
(gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
},
undefined,
(error) => {
toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
resolve();
}
);
return;
}
// Fetch from Backend
// console.log(`[Backend] Fetching ${item.modelname}`);
loader.load(
modelUrl,
async (gltf) => {
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
},
undefined,
(error) => {
toast.error(`[Backend] Error loading ${item.modelname}:`);
resolve();
}
);
});
}
function processLoadedModel(
gltf: any,
item: Types.FloorItemType,
itemsGroup: Types.RefGroup,
resolve: () => void
) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid);
if (existingModel) {
// console.log(`Model ${item.modelname} already exists in the scene.`);
resolve();
return;
}
const model = gltf;
model.uuid = item.modeluuid;
model.userData = { name: item.modelname, modelId: item.modelfileID };
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.position.set(...item.position);
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
model.traverse((child: any) => {
if (child.isMesh) {
// Clone the material to ensure changes are independent
// child.material = child.material.clone();
child.castShadow = true;
child.receiveShadow = true;
}
});
itemsGroup?.current?.add(model);
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 0.5, ease: "power2.out", onStart: resolve, });
}
}
activePromises.delete(taskId); // Mark task as complete
}
// Cancel ongoing task when new call arrives
export function cancelOngoingTasks() {
activePromises.clear(); // Clear all ongoing tasks
}
import * as THREE from "three";
import gsap from "gsap";
import * as Types from "../../../../types/world/worldTypes";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
import * as CONSTANTS from '../../../../types/world/worldConstants';
import { toast } from 'react-toastify';
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
let currentTaskId = 0; // Track the active task
let activePromises = new Map<number, boolean>(); // Map to track task progress
export default async function assetManager(
data: any,
itemsGroup: Types.RefGroup,
loader: GLTFLoader,
) {
const taskId = ++currentTaskId; // Increment taskId for each call
activePromises.set(taskId, true); // Mark task as active
// console.log("Received message from worker:", data);
if (data.toRemove.length > 0) {
data.toRemove.forEach((uuid: string) => {
const item = itemsGroup.current.getObjectByProperty("uuid", uuid);
if (item) {
// Traverse and dispose of resources
// item.traverse((child: THREE.Object3D) => {
// if (child instanceof THREE.Mesh) {
// if (child.geometry) child.geometry.dispose();
// if (Array.isArray(child.material)) {
// child.material.forEach((material) => {
// if (material.map) material.map.dispose();
// material.dispose();
// });
// } else if (child.material) {
// if (child.material.map) child.material.map.dispose();
// child.material.dispose();
// }
// }
// });
// Remove the object from the scene
itemsGroup.current.remove(item);
}
});
}
if (data.toAdd.length > 0) {
await initializeDB();
for (const item of data.toAdd) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
await new Promise<void>(async (resolve) => {
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
// Check Three.js Cache
const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve);
return;
}
// Check IndexedDB
const indexedDBModel = await retrieveGLTF(item.modelfileID!);
if (indexedDBModel) {
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
const blobUrl = URL.createObjectURL(indexedDBModel);
loader.load(
blobUrl,
(gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
},
undefined,
(error) => {
toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
resolve();
}
);
return;
}
// Fetch from Backend
// console.log(`[Backend] Fetching ${item.modelname}`);
loader.load(
modelUrl,
async (gltf) => {
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
},
undefined,
(error) => {
toast.error(`[Backend] Error loading ${item.modelname}:`);
resolve();
}
);
});
}
function processLoadedModel(
gltf: any,
item: Types.FloorItemType,
itemsGroup: Types.RefGroup,
resolve: () => void
) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid);
if (existingModel) {
// console.log(`Model ${item.modelname} already exists in the scene.`);
resolve();
return;
}
const model = gltf;
model.uuid = item.modeluuid;
model.userData = { name: item.modelname, modelId: item.modelfileID };
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.position.set(...item.position);
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
model.traverse((child: any) => {
if (child.isMesh) {
// Clone the material to ensure changes are independent
// child.material = child.material.clone();
child.castShadow = true;
child.receiveShadow = true;
}
});
itemsGroup?.current?.add(model);
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 0.5, ease: "power2.out", onStart: resolve, });
}
}
activePromises.delete(taskId); // Mark task as complete
}
// Cancel ongoing task when new call arrives
export function cancelOngoingTasks() {
activePromises.clear(); // Clear all ongoing tasks
}

View File

@@ -1,25 +1,25 @@
import * as Types from "../../../../types/world/worldTypes";
let lastUpdateTime = 0;
export default function assetVisibility(
itemsGroup: Types.RefGroup,
cameraPosition: Types.Vector3,
renderDistance: Types.Number,
throttleTime = 100
): void {
const now = performance.now();
if (now - lastUpdateTime < throttleTime) return;
lastUpdateTime = now;
if (!itemsGroup?.current || !cameraPosition) return;
itemsGroup.current.children.forEach((child) => {
const Distance = cameraPosition.distanceTo(child.position);
if (Distance <= renderDistance) {
child.visible = true;
} else {
child.visible = false;
}
});
}
import * as Types from "../../../../types/world/worldTypes";
let lastUpdateTime = 0;
export default function assetVisibility(
itemsGroup: Types.RefGroup,
cameraPosition: Types.Vector3,
renderDistance: Types.Number,
throttleTime = 100
): void {
const now = performance.now();
if (now - lastUpdateTime < throttleTime) return;
lastUpdateTime = now;
if (!itemsGroup?.current || !cameraPosition) return;
itemsGroup.current.children.forEach((child) => {
const Distance = cameraPosition.distanceTo(child.position);
if (Distance <= renderDistance) {
child.visible = true;
} else {
child.visible = false;
}
});
}

View File

@@ -1,43 +1,43 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function DeletableHoveredFloorItems(
state: Types.ThreeState,
itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh,
setDeletableFloorItem: any
): void {
////////// Altering the color of the hovered GLTF item during the Deletion time //////////
state.raycaster.setFromCamera(state.pointer, state.camera);
const intersects = state.raycaster.intersectObjects(itemsGroup.current.children, true);
if (intersects.length > 0) {
if (intersects[0].object.name === "Pole") {
return;
}
if (hoveredDeletableFloorItem.current) {
hoveredDeletableFloorItem.current = undefined;
setDeletableFloorItem(null);
}
let currentObject = intersects[0].object;
while (currentObject) {
if (currentObject.name === "Scene") {
hoveredDeletableFloorItem.current = currentObject as THREE.Mesh;
setDeletableFloorItem(currentObject);
break;
}
currentObject = currentObject.parent as THREE.Object3D;
}
} else {
if (hoveredDeletableFloorItem.current) {
hoveredDeletableFloorItem.current = undefined;
setDeletableFloorItem(null);
}
}
}
export default DeletableHoveredFloorItems;
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function DeletableHoveredFloorItems(
state: Types.ThreeState,
itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh,
setDeletableFloorItem: any
): void {
////////// Altering the color of the hovered GLTF item during the Deletion time //////////
state.raycaster.setFromCamera(state.pointer, state.camera);
const intersects = state.raycaster.intersectObjects(itemsGroup.current.children, true);
if (intersects.length > 0) {
if (intersects[0].object.name === "Pole") {
return;
}
if (hoveredDeletableFloorItem.current) {
hoveredDeletableFloorItem.current = undefined;
setDeletableFloorItem(null);
}
let currentObject = intersects[0].object;
while (currentObject) {
if (currentObject.name === "Scene") {
hoveredDeletableFloorItem.current = currentObject as THREE.Mesh;
setDeletableFloorItem(currentObject);
break;
}
currentObject = currentObject.parent as THREE.Object3D;
}
} else {
if (hoveredDeletableFloorItem.current) {
hoveredDeletableFloorItem.current = undefined;
setDeletableFloorItem(null);
}
}
}
export default DeletableHoveredFloorItems;

View File

@@ -1,82 +1,82 @@
import { toast } from 'react-toastify';
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
import { getFloorItems } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
import { Socket } from 'socket.io-client';
async function DeleteFloorItems(
itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh,
setFloorItems: Types.setFloorItemSetState,
socket: Socket<any>
): Promise<void> {
////////// Deleting the hovered Floor GLTF from the scene (itemsGroup.current) and from the floorItems and also update it in the localstorage //////////
if (hoveredDeletableFloorItem.current) {
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
const items = await getFloorItems(organization);
const removedItem = items.find(
(item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid
);
if (!removedItem) {
return
}
//REST
// const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname);
//SOCKET
const data = {
organization: organization,
modeluuid: removedItem.modeluuid,
modelname: removedItem.modelname,
socketId: socket.id
}
const response = socket.emit('v1:FloorItems:delete', data)
if (response) {
const updatedItems = items.filter(
(item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid
);
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid);
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
if (hoveredDeletableFloorItem.current) {
// Traverse and dispose of resources
hoveredDeletableFloorItem.current.traverse((child: THREE.Object3D) => {
if (child instanceof THREE.Mesh) {
if (child.geometry) child.geometry.dispose();
if (Array.isArray(child.material)) {
child.material.forEach((material) => {
if (material.map) material.map.dispose();
material.dispose();
});
} else if (child.material) {
if (child.material.map) child.material.map.dispose();
child.material.dispose();
}
}
});
// Remove the object from the scene
itemsGroup.current.remove(hoveredDeletableFloorItem.current);
}
setFloorItems(updatedItems);
toast.success("Model Removed!");
}
}
}
export default DeleteFloorItems;
import { toast } from 'react-toastify';
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
import { getFloorItems } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
import { Socket } from 'socket.io-client';
async function DeleteFloorItems(
itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh,
setFloorItems: Types.setFloorItemSetState,
socket: Socket<any>
): Promise<void> {
////////// Deleting the hovered Floor GLTF from the scene (itemsGroup.current) and from the floorItems and also update it in the localstorage //////////
if (hoveredDeletableFloorItem.current) {
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
const items = await getFloorItems(organization);
const removedItem = items.find(
(item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid
);
if (!removedItem) {
return
}
//REST
// const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname);
//SOCKET
const data = {
organization: organization,
modeluuid: removedItem.modeluuid,
modelname: removedItem.modelname,
socketId: socket.id
}
const response = socket.emit('v1:FloorItems:delete', data)
if (response) {
const updatedItems = items.filter(
(item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid
);
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid);
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
if (hoveredDeletableFloorItem.current) {
// Traverse and dispose of resources
hoveredDeletableFloorItem.current.traverse((child: THREE.Object3D) => {
if (child instanceof THREE.Mesh) {
if (child.geometry) child.geometry.dispose();
if (Array.isArray(child.material)) {
child.material.forEach((material) => {
if (material.map) material.map.dispose();
material.dispose();
});
} else if (child.material) {
if (child.material.map) child.material.map.dispose();
child.material.dispose();
}
}
});
// Remove the object from the scene
itemsGroup.current.remove(hoveredDeletableFloorItem.current);
}
setFloorItems(updatedItems);
toast.success("Model Removed!");
}
}
}
export default DeleteFloorItems;

View File

@@ -1,29 +1,29 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function TempLoader(
intersectPoint: Types.Vector3,
isTempLoader: Types.RefBoolean,
tempLoader: Types.RefMesh,
itemsGroup: Types.RefGroup
): void {
////////// Temporary Loader that indicates the gltf is being loaded //////////
////////// Bug: Can't Load More than one TempLoader if done, it won't leave the scene //////////
if (tempLoader.current) {
itemsGroup.current.remove(tempLoader.current);
}
if (isTempLoader.current) {
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: "white" });
tempLoader.current = new THREE.Mesh(cubeGeometry, cubeMaterial);
tempLoader.current.position.set(intersectPoint.x, 0.5 + intersectPoint.y, intersectPoint.z);
itemsGroup.current.add(tempLoader.current);
isTempLoader.current = false;
}
}
export default TempLoader;
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function TempLoader(
intersectPoint: Types.Vector3,
isTempLoader: Types.RefBoolean,
tempLoader: Types.RefMesh,
itemsGroup: Types.RefGroup
): void {
////////// Temporary Loader that indicates the gltf is being loaded //////////
////////// Bug: Can't Load More than one TempLoader if done, it won't leave the scene //////////
if (tempLoader.current) {
itemsGroup.current.remove(tempLoader.current);
}
if (isTempLoader.current) {
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: "white" });
tempLoader.current = new THREE.Mesh(cubeGeometry, cubeMaterial);
tempLoader.current.position.set(intersectPoint.x, 0.5 + intersectPoint.y, intersectPoint.z);
itemsGroup.current.add(tempLoader.current);
isTempLoader.current = false;
}
}
export default TempLoader;

View File

@@ -1,64 +1,64 @@
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/concreteFloorWorn001Diff2k.jpg";
import normalPath from "../../../../assets/textures/floor/concreteFloorWorn001NorGl2k.jpg";
// 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 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(texturePath);
const normalMap = textureLoader.load(normalPath);
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(textureScale, textureScale);
floorTexture.colorSpace = THREE.SRGBColorSpace;
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
normalMap.repeat.set(textureScale, textureScale);
material = new THREE.MeshStandardMaterial({
map: floorTexture,
normalMap: normalMap,
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;
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);
}
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/concreteFloorWorn001Diff2k.jpg";
import normalPath from "../../../../assets/textures/floor/concreteFloorWorn001NorGl2k.jpg";
// 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 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(texturePath);
const normalMap = textureLoader.load(normalPath);
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(textureScale, textureScale);
floorTexture.colorSpace = THREE.SRGBColorSpace;
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
normalMap.repeat.set(textureScale, textureScale);
material = new THREE.MeshStandardMaterial({
map: floorTexture,
normalMap: normalMap,
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;
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,179 +1,179 @@
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';
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>
): Promise<void> {
////////// Creating lines Based on the positions clicked //////////
if (!plane.current) return
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]);
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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 = [];
}
}
}
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';
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>
): Promise<void> {
////////// Creating lines Based on the positions clicked //////////
if (!plane.current) return
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]);
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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 +1,50 @@
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;
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 +1,183 @@
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) {
throw new 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 + 0.03;
mesh.rotateX(Math.PI / 2);
mesh.name = `Only_Floor_Line_${floor[0][0][2]}`;
mesh.userData = floor;
floorGroup?.current?.add(mesh);
});
}
export default loadOnlyFloors;
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) {
throw new 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 + 0.03;
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 +1,24 @@
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;
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,89 +1,89 @@
import { toast } from 'react-toastify';
import RemoveConnectedLines from '../lines/removeConnectedLines';
import * as Types from '../../../../types/world/worldTypes';
import { Socket } from 'socket.io-client';
// 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>
): 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 email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// await deleteLayer(organization, removedLayer);
//SOCKET
const data = {
organization: organization,
layer: removedLayer,
socketId: socket.id
}
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);
}
toast.success("Layer Removed!");
setRemovedLayer(null);
}
export default DeleteLayer;
import { toast } from 'react-toastify';
import RemoveConnectedLines from '../lines/removeConnectedLines';
import * as Types from '../../../../types/world/worldTypes';
import { Socket } from 'socket.io-client';
// 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>
): 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 email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// await deleteLayer(organization, removedLayer);
//SOCKET
const data = {
organization: organization,
layer: removedLayer,
socketId: socket.id
}
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);
}
toast.success("Layer Removed!");
setRemovedLayer(null);
}
export default DeleteLayer;

View File

@@ -1,35 +1,35 @@
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;
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 +1,24 @@
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;
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 +1,98 @@
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;
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,88 +1,88 @@
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';
function deleteLine(
hoveredDeletableLine: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines,
lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup,
setDeletedLines: any,
socket: Socket<any>
): void {
////////// 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]];
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// deleteLineApi(
// organization,
// [
// { "uuid": linePoints[0][1] },
// { "uuid": linePoints[1][1] }
// ]
// )
//SOCKET
const data = {
organization: organization,
line: [
{ "uuid": linePoints[0][1] },
{ "uuid": linePoints[1][1] }
],
socketId: socket.id
}
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);
}
});
}
});
toast.success("Line Removed!");
}
export default deleteLine;
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';
function deleteLine(
hoveredDeletableLine: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines,
lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup,
setDeletedLines: any,
socket: Socket<any>
): void {
////////// 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]];
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// deleteLineApi(
// organization,
// [
// { "uuid": linePoints[0][1] },
// { "uuid": linePoints[1][1] }
// ]
// )
//SOCKET
const data = {
organization: organization,
line: [
{ "uuid": linePoints[0][1] },
{ "uuid": linePoints[1][1] }
],
socketId: socket.id
}
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);
}
});
}
});
toast.success("Line Removed!");
}
export default deleteLine;

View File

@@ -1,90 +1,90 @@
import { useEffect, useState } from "react"
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
import * as THREE from "three";
import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store";
import objectLinesToArray from "./lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei";
import * as Types from "../../../../types/world/worldTypes";
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();
useEffect(() => {
const email = localStorage.getItem('email')
if (!email) return;
const organization = (email.split("@")[1]).split(".")[0];
getLines(organization).then((data) => {
data = objectLinesToArray(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])
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]);
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])
)
);
setDeletedLines([]);
}
}, [deletedLines]);
return (
<>
{toggleView && (
<group name='Distance_Text'>
{lines.map((text) => (
<Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} >
<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>
)}
</>
)
}
import { useEffect, useState } from "react"
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
import * as THREE from "three";
import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store";
import objectLinesToArray from "./lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei";
import * as Types from "../../../../types/world/worldTypes";
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();
useEffect(() => {
const email = localStorage.getItem('email')
if (!email) return;
const organization = (email.split("@")[1]).split(".")[0];
getLines(organization).then((data) => {
data = objectLinesToArray(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])
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]);
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])
)
);
setDeletedLines([]);
}
}, [deletedLines]);
return (
<>
{toggleView && (
<group name='Distance_Text'>
{lines.map((text) => (
<Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} >
<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,167 +1,167 @@
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';
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>
): Promise<void> {
////////// 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);
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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;
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';
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>
): Promise<void> {
////////// 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);
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
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,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 | null {
////////// 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 | null = null;
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 | null {
////////// 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 | null = null;
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

@@ -1,86 +1,86 @@
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;
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 +1,24 @@
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,
};
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 +1,30 @@
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
}
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 +1,13 @@
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]);
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 +1,20 @@
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];
});
});
}
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,48 +1,48 @@
import * as THREE from 'three';
import { Html } from '@react-three/drei';
import { useState, useEffect } from 'react';
import { useActiveLayer } from '../../../../store/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 transform sprite key={text.distance} userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }}>
<div className={`Reference_Distance line-${text.userData.userData}`}>{text.distance} m</div>
</Html>
}
</mesh>
</group >
);
};
import * as THREE from 'three';
import { Html } from '@react-three/drei';
import { useState, useEffect } from 'react';
import { useActiveLayer } from '../../../../store/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 transform sprite key={text.distance} userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }}>
<div className={`Reference_Distance line-${text.userData.userData}`}>{text.distance} m</div>
</Html>
}
</mesh>
</group >
);
};
export default ReferenceDistanceText;

View File

@@ -1,66 +1,66 @@
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;
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 +1,22 @@
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;
}
}
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,124 +1,124 @@
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 { 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,
): [Types.Line, Types.Line] {
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
((visibleIntersect.object as any).material).dispose();
((visibleIntersect.object as any).geometry).dispose();
floorPlanGroupLine.current.remove(visibleIntersect.object);
setDeletedLines([visibleIntersect.object.userData.linePoints]);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// deleteLineApi(
// organization,
// [
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
// ]
// )
//SOCKET
const data = {
organization: organization,
line: [
{ "uuid": visibleIntersect.object.userData.linePoints[0][1] },
{ "uuid": visibleIntersect.object.userData.linePoints[1][1] }
],
socketId: socket.id
}
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: organization,
layer: line1.layer,
line: line1.line,
type: line1.type,
socketId: socket.id
}
socket.emit('v1:Line:create', input1);
//REST
// setLine(organization, line2.layer!, line2.line!, line2.type!);
//SOCKET
const input2 = {
organization: organization,
layer: line2.layer,
line: line2.line,
type: line2.type,
socketId: socket.id
}
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;
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 { 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,
): [Types.Line, Types.Line] {
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
((visibleIntersect.object as any).material).dispose();
((visibleIntersect.object as any).geometry).dispose();
floorPlanGroupLine.current.remove(visibleIntersect.object);
setDeletedLines([visibleIntersect.object.userData.linePoints]);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// deleteLineApi(
// organization,
// [
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
// ]
// )
//SOCKET
const data = {
organization: organization,
line: [
{ "uuid": visibleIntersect.object.userData.linePoints[0][1] },
{ "uuid": visibleIntersect.object.userData.linePoints[1][1] }
],
socketId: socket.id
}
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: organization,
layer: line1.layer,
line: line1.line,
type: line1.type,
socketId: socket.id
}
socket.emit('v1:Line:create', input1);
//REST
// setLine(organization, line2.layer!, line2.line!, line2.type!);
//SOCKET
const input2 = {
organization: organization,
layer: line2.layer,
line: line2.line,
type: line2.type,
socketId: socket.id
}
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 +1,42 @@
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.children.find((child) => child.name === "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;
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.children.find((child) => child.name === "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 +1,24 @@
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);
}
});
}
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 +1,32 @@
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;
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 +1,18 @@
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;
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 +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;
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 +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);
}
}
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 +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;
}
}
}
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 +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);
toast.success("Pillar Removed!");
hoveredDeletablePillar.current = undefined;
}
}
export default DeletePillar;
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);
toast.success("Pillar Removed!");
hoveredDeletablePillar.current = undefined;
}
}
export default DeletePillar;

View File

@@ -1,40 +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;
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 +1,65 @@
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: {
uColor: { 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 uColor;
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(uColor, 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;
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: {
uColor: { 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 uColor;
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(uColor, 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,57 +1,57 @@
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";
function deletePoint(
hoveredDeletablePoint: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines,
floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup,
lines: Types.RefLines,
setDeletedLines: any,
socket: Socket<any>
): void {
////////// Deleting a Point and the lines that are connected to it //////////
if (!hoveredDeletablePoint.current) {
return;
}
(<any>hoveredDeletablePoint.current.material).dispose();
(<any>hoveredDeletablePoint.current.geometry).dispose();
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// deletePointApi(organization, DeletedPointUUID);
//SOCKET
const data = {
organization: organization,
uuid: DeletedPointUUID,
socketId: socket.id
}
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);
toast.success("Point Removed!");
}
export default deletePoint;
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";
function deletePoint(
hoveredDeletablePoint: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines,
floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup,
lines: Types.RefLines,
setDeletedLines: any,
socket: Socket<any>
): void {
////////// Deleting a Point and the lines that are connected to it //////////
if (!hoveredDeletablePoint.current) {
return;
}
(<any>hoveredDeletablePoint.current.material).dispose();
(<any>hoveredDeletablePoint.current.geometry).dispose();
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// deletePointApi(organization, DeletedPointUUID);
//SOCKET
const data = {
organization: organization,
uuid: DeletedPointUUID,
socketId: socket.id
}
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);
toast.success("Point Removed!");
}
export default deletePoint;

View File

@@ -1,44 +1,44 @@
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);
}
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 +1,37 @@
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;
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 +1,32 @@
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, transparent: true, depthWrite: false });
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;
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, transparent: true, depthWrite: false });
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 +1,47 @@
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;
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,108 +1,108 @@
import { 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 { setWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/setWallItemApi';
import { Socket } from 'socket.io-client';
async function AddWallItems(
selected: Types.String,
raycaster: THREE.Raycaster,
CSGGroup: Types.RefMesh,
AssetConfigurations: Types.AssetConfigurations,
setWallItems: Types.setWallItemSetState,
socket: Socket<any>
): Promise<void> {
////////// Load Wall GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference"));
if (wallRaycastIntersection) {
const intersectionPoint = wallRaycastIntersection;
const loader = new GLTFLoader();
loader.load(AssetConfigurations[selected].modelUrl, async (gltf) => {
const model = gltf.scene;
model.userData = { wall: intersectionPoint.object.parent };
model.children[0].children.forEach((child) => {
if (child.name !== "CSG_REF") {
child.castShadow = true;
child.receiveShadow = true;
}
});
const config = AssetConfigurations[selected];
let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY;
if (positionY === 0) {
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
}
const newWallItem = {
type: config.type,
model: model,
modelname: selected,
scale: config.scale,
csgscale: config.csgscale,
csgposition: config.csgposition,
position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number],
quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType
};
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// await setWallItem(
// organization,
// model.uuid,
// newWallItem.modelname,
// newWallItem.type!,
// newWallItem.csgposition!,
// newWallItem.csgscale!,
// newWallItem.position,
// newWallItem.quaternion,
// newWallItem.scale!,
// )
//SOCKET
const data = {
organization: organization,
modeluuid: model.uuid,
modelname: newWallItem.modelname,
type: newWallItem.type!,
csgposition: newWallItem.csgposition!,
csgscale: newWallItem.csgscale!,
position: newWallItem.position,
quaternion: newWallItem.quaternion,
scale: newWallItem.scale!,
socketId: socket.id
}
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));
toast.success("Model Added!");
return updatedItems;
});
});
}
}
export default AddWallItems;
import { 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 { setWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/setWallItemApi';
import { Socket } from 'socket.io-client';
async function AddWallItems(
selected: Types.String,
raycaster: THREE.Raycaster,
CSGGroup: Types.RefMesh,
AssetConfigurations: Types.AssetConfigurations,
setWallItems: Types.setWallItemSetState,
socket: Socket<any>
): Promise<void> {
////////// Load Wall GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference"));
if (wallRaycastIntersection) {
const intersectionPoint = wallRaycastIntersection;
const loader = new GLTFLoader();
loader.load(AssetConfigurations[selected].modelUrl, async (gltf) => {
const model = gltf.scene;
model.userData = { wall: intersectionPoint.object.parent };
model.children[0].children.forEach((child) => {
if (child.name !== "CSG_REF") {
child.castShadow = true;
child.receiveShadow = true;
}
});
const config = AssetConfigurations[selected];
let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY;
if (positionY === 0) {
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
}
const newWallItem = {
type: config.type,
model: model,
modelname: selected,
scale: config.scale,
csgscale: config.csgscale,
csgposition: config.csgposition,
position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number],
quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType
};
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// await setWallItem(
// organization,
// model.uuid,
// newWallItem.modelname,
// newWallItem.type!,
// newWallItem.csgposition!,
// newWallItem.csgscale!,
// newWallItem.position,
// newWallItem.quaternion,
// newWallItem.scale!,
// )
//SOCKET
const data = {
organization: organization,
modeluuid: model.uuid,
modelname: newWallItem.modelname,
type: newWallItem.type!,
csgposition: newWallItem.csgposition!,
csgscale: newWallItem.csgscale!,
position: newWallItem.position,
quaternion: newWallItem.quaternion,
scale: newWallItem.scale!,
socketId: socket.id
}
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));
toast.success("Model Added!");
return updatedItems;
});
});
}
}
export default AddWallItems;

View File

@@ -1,59 +1,59 @@
import { toast } from 'react-toastify';
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>
): void {
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current.parent) {
setWallItems([]);
let WallItemsRef = wallItems;
const removedItem = WallItemsRef.find((item) => item.model?.uuid === hoveredDeletableWallItem.current?.parent?.uuid);
const Items = WallItemsRef.filter((item) => item.model?.uuid !== hoveredDeletableWallItem.current?.parent?.uuid);
setTimeout(async () => {
WallItemsRef = Items;
setWallItems(WallItemsRef);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!)
//SOCKET
const data = {
organization: organization,
modeluuid: removedItem?.model?.uuid!,
modelname: removedItem?.modelname!,
socketId: socket.id
}
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));
toast.success("Model Removed!");
hoveredDeletableWallItem.current = null;
}, 50);
}
}
export default DeleteWallItems;
import { toast } from 'react-toastify';
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>
): void {
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current.parent) {
setWallItems([]);
let WallItemsRef = wallItems;
const removedItem = WallItemsRef.find((item) => item.model?.uuid === hoveredDeletableWallItem.current?.parent?.uuid);
const Items = WallItemsRef.filter((item) => item.model?.uuid !== hoveredDeletableWallItem.current?.parent?.uuid);
setTimeout(async () => {
WallItemsRef = Items;
setWallItems(WallItemsRef);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!)
//SOCKET
const data = {
organization: organization,
modeluuid: removedItem?.model?.uuid!,
modelname: removedItem?.modelname!,
socketId: socket.id
}
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));
toast.success("Model Removed!");
hoveredDeletableWallItem.current = null;
}, 50);
}
}
export default DeleteWallItems;

View File

@@ -1,45 +1,45 @@
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function hideWalls(
visibility: Types.Boolean,
scene: THREE.Scene,
camera: THREE.Camera
): void {
////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera //////////
const v = new THREE.Vector3();
const u = 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") {
child.children[0].getWorldDirection(v);
camera.getWorldDirection(u);
if (child.children[0].material) {
child.children[0].material.visible = (2 * v.dot(u)) >= -0.5;
}
}
});
}
}
} 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") {
if (child.children[0].material) {
child.children[0].material.visible = true;
}
}
});
}
}
}
}
export default hideWalls;
import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes";
function hideWalls(
visibility: Types.Boolean,
scene: THREE.Scene,
camera: THREE.Camera
): void {
////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera //////////
const v = new THREE.Vector3();
const u = 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") {
child.children[0].getWorldDirection(v);
camera.getWorldDirection(u);
if (child.children[0].material) {
child.children[0].material.visible = (2 * v.dot(u)) >= -0.5;
}
}
});
}
}
} 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") {
if (child.children[0].material) {
child.children[0].material.visible = true;
}
}
});
}
}
}
}
export default hideWalls;

View File

@@ -1,129 +1,129 @@
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;
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;

View File

@@ -1,50 +1,50 @@
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 uColor;
void main(){
float alpha = 1.0 - vUv.y;
gl_FragColor = vec4(uColor, alpha);
}
`,
uniforms: {
uColor: { 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.uColor.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);
}
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 uColor;
void main(){
float alpha = 1.0 - vUv.y;
gl_FragColor = vec4(uColor, alpha);
}
`,
uniforms: {
uColor: { 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.uColor.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 +1,19 @@
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))
})
}
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))
})
}
}