feat: Implement zone management features including creation, deletion, and updates
- Added zone handling in the Line component for removing and updating zones based on points. - Enhanced Point component to support snapping and updating zone positions. - Introduced zone-related API calls for upserting and deleting zones. - Updated zone store to manage zones more effectively, including methods for removing zones by points and getting zones by point IDs. - Improved zone instance rendering to handle dynamic point connections. - Refactored zone creation logic to allow for better interaction and snapping behavior. - Updated API endpoints for zone operations to use version 1 of the API.
This commit is contained in:
@@ -4,7 +4,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
|||||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||||
import { CameraControls } from '@react-three/drei';
|
import { CameraControls } from '@react-three/drei';
|
||||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||||
@@ -34,6 +34,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
|
const { limitDistance } = useLimitDistance();
|
||||||
const { renderDistance } = useRenderDistance();
|
const { renderDistance } = useRenderDistance();
|
||||||
const [isRendered, setIsRendered] = useState(false);
|
const [isRendered, setIsRendered] = useState(false);
|
||||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
@@ -125,10 +126,16 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
const assetPosition = new THREE.Vector3(...asset.position);
|
const assetPosition = new THREE.Vector3(...asset.position);
|
||||||
if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) {
|
if (limitDistance) {
|
||||||
setIsRendered(true);
|
if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) {
|
||||||
} else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) {
|
setIsRendered(true);
|
||||||
setIsRendered(false);
|
} else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) {
|
||||||
|
setIsRendered(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isRendered) {
|
||||||
|
setIsRendered(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function FloorCreator() {
|
|||||||
|
|
||||||
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint } = useBuilderStore();
|
const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
@@ -64,11 +64,11 @@ function FloorCreator() {
|
|||||||
|
|
||||||
const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Point');
|
const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Point');
|
||||||
|
|
||||||
const floorIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Line');
|
// const floorIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Line');
|
||||||
|
|
||||||
if (floorIntersect && !pointIntersects) {
|
// if (floorIntersect && !pointIntersects) {
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
const newPoint: Point = {
|
const newPoint: Point = {
|
||||||
pointUuid: THREE.MathUtils.generateUUID(),
|
pointUuid: THREE.MathUtils.generateUUID(),
|
||||||
@@ -89,7 +89,45 @@ function FloorCreator() {
|
|||||||
newPoint.position = snappedPosition;
|
newPoint.position = snappedPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pointIntersects) {
|
if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) {
|
||||||
|
const floor: Floor = {
|
||||||
|
floorUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
floorName: "Floor",
|
||||||
|
points: tempPoints,
|
||||||
|
topMaterial,
|
||||||
|
sideMaterial,
|
||||||
|
floorDepth,
|
||||||
|
isBeveled,
|
||||||
|
bevelStrength,
|
||||||
|
decals: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
addFloor(floor);
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: floor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
} else if (isCreating && snappedPoint && !tempPoints.some(p => p.pointUuid === snappedPoint.pointUuid)) {
|
||||||
|
setTempPoints(prev => [...prev, newPoint]);
|
||||||
|
setIsCreating(true);
|
||||||
|
} else if (pointIntersects) {
|
||||||
if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) {
|
if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) {
|
||||||
const floor: Floor = {
|
const floor: Floor = {
|
||||||
floorUuid: THREE.MathUtils.generateUUID(),
|
floorUuid: THREE.MathUtils.generateUUID(),
|
||||||
@@ -125,10 +163,7 @@ function FloorCreator() {
|
|||||||
}
|
}
|
||||||
setTempPoints([]);
|
setTempPoints([]);
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
} else if (tempPoints.length === 0 || (tempPoints.length > 1 && pointIntersects.object.uuid !== tempPoints[tempPoints.length - 2].pointUuid)) {
|
} else if (tempPoints.length === 0 || (tempPoints.length > 1 && !tempPoints.slice(1).some(p => p.pointUuid === pointIntersects.object.uuid))) {
|
||||||
tempPoints.push(pointIntersects.object.userData as Point);
|
|
||||||
setIsCreating(true);
|
|
||||||
} else {
|
|
||||||
tempPoints.push(pointIntersects.object.userData as Point);
|
tempPoints.push(pointIntersects.object.userData as Point);
|
||||||
setIsCreating(true);
|
setIsCreating(true);
|
||||||
}
|
}
|
||||||
@@ -182,6 +217,10 @@ function FloorCreator() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (toolMode === "Floor" && toggleView) {
|
if (toolMode === "Floor" && toggleView) {
|
||||||
|
if (tempPoints.length === 0) {
|
||||||
|
setSnappedPosition(null);
|
||||||
|
setSnappedPoint(null);
|
||||||
|
}
|
||||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function ReferenceFloor({ tempPoints }: Readonly<ReferenceFloorProps>) {
|
|||||||
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||||
|
|
||||||
if (!intersectionPoint) return;
|
if (!intersectionPoint) return;
|
||||||
const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.slice(0, -2));
|
const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], [tempPoints[0]]);
|
||||||
|
|
||||||
if (snapped.isSnapped && snapped.snappedPoint) {
|
if (snapped.isSnapped && snapped.snappedPoint) {
|
||||||
finalPosition.current = snapped.position;
|
finalPosition.current = snapped.position;
|
||||||
|
|||||||
@@ -1,651 +0,0 @@
|
|||||||
// import React, { useState, useEffect, useMemo, useRef } from "react";
|
|
||||||
// import { Html, Line, Sphere } from "@react-three/drei";
|
|
||||||
// import { useThree, useFrame } from "@react-three/fiber";
|
|
||||||
// import * as THREE from "three";
|
|
||||||
// import {
|
|
||||||
// useActiveLayer,
|
|
||||||
// useSocketStore,
|
|
||||||
// useToggleView,
|
|
||||||
// useToolMode,
|
|
||||||
// useRemovedLayer,
|
|
||||||
// useZones,
|
|
||||||
// useZonePoints,
|
|
||||||
// } from "../../../store/builder/store";
|
|
||||||
// import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
|
|
||||||
|
|
||||||
// import * as CONSTANTS from "../../../types/world/worldConstants";
|
|
||||||
// import * as turf from "@turf/turf";
|
|
||||||
// import { computeArea } from "../functions/computeArea";
|
|
||||||
// import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
|
|
||||||
// import { useParams } from "react-router-dom";
|
|
||||||
// import { getUserData } from "../../../functions/getUserData";
|
|
||||||
// import { useVersionContext } from "../version/versionContext";
|
|
||||||
|
|
||||||
// const ZoneGroup: React.FC = () => {
|
|
||||||
// const { camera, pointer, gl, raycaster, scene, controls } = useThree();
|
|
||||||
// const [startPoint, setStartPoint] = useState<THREE.Vector3 | null>(null);
|
|
||||||
// const [endPoint, setEndPoint] = useState<THREE.Vector3 | null>(null);
|
|
||||||
// const { zones, setZones } = useZones();
|
|
||||||
// const { zonePoints, setZonePoints } = useZonePoints();
|
|
||||||
// const [isDragging, setIsDragging] = useState(false);
|
|
||||||
// const { selectedZone } = useSelectedZoneStore();
|
|
||||||
// const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(null);
|
|
||||||
// const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
|
||||||
// const { toggleView } = useToggleView();
|
|
||||||
// const { removedLayer, setRemovedLayer } = useRemovedLayer();
|
|
||||||
// const { toolMode } = useToolMode();
|
|
||||||
// const { activeLayer } = useActiveLayer();
|
|
||||||
// const { socket } = useSocketStore();
|
|
||||||
// const { selectedVersionStore } = useVersionContext();
|
|
||||||
// const { selectedVersion } = selectedVersionStore();
|
|
||||||
// const { projectId } = useParams();
|
|
||||||
// const { userId, organization } = getUserData();
|
|
||||||
|
|
||||||
// const groupsRef = useRef<any>();
|
|
||||||
|
|
||||||
// const zoneMaterial = useMemo(
|
|
||||||
// () =>
|
|
||||||
// new THREE.ShaderMaterial({
|
|
||||||
// side: THREE.DoubleSide,
|
|
||||||
// vertexShader: `
|
|
||||||
// varying vec2 vUv;
|
|
||||||
// void main(){
|
|
||||||
// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
||||||
// vUv = uv;
|
|
||||||
// }
|
|
||||||
// `,
|
|
||||||
// fragmentShader: `
|
|
||||||
// varying vec2 vUv;
|
|
||||||
// uniform vec3 uOuterColor;
|
|
||||||
// void main(){
|
|
||||||
// float alpha = 1.0 - vUv.y;
|
|
||||||
// gl_FragColor = vec4(uOuterColor, alpha);
|
|
||||||
// }
|
|
||||||
// `,
|
|
||||||
// uniforms: {
|
|
||||||
// uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) },
|
|
||||||
// },
|
|
||||||
// transparent: true,
|
|
||||||
// depthWrite: false,
|
|
||||||
// }),
|
|
||||||
// []
|
|
||||||
// );
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (!selectedVersion) return;
|
|
||||||
// getZonesApi(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
|
||||||
// if (data && data.length > 0) {
|
|
||||||
// const fetchedZones = data.map((zone: any) => ({
|
|
||||||
// zoneUuid: zone.zoneUuid,
|
|
||||||
// zoneName: zone.zoneName,
|
|
||||||
// points: zone.points,
|
|
||||||
// viewPortCenter: zone.viewPortCenter,
|
|
||||||
// viewPortposition: zone.viewPortposition,
|
|
||||||
// layer: zone.layer,
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// setZones(fetchedZones);
|
|
||||||
|
|
||||||
// const fetchedPoints = data.flatMap((zone: any) =>
|
|
||||||
// zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point))
|
|
||||||
// );
|
|
||||||
|
|
||||||
// setZonePoints(fetchedPoints);
|
|
||||||
// } else {
|
|
||||||
// setZones([]);
|
|
||||||
// }
|
|
||||||
// }).catch((err) => {
|
|
||||||
// console.error(err);
|
|
||||||
// })
|
|
||||||
// }, [selectedVersion?.versionId]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// localStorage.setItem("zones", JSON.stringify(zones));
|
|
||||||
// }, [zones]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (removedLayer) {
|
|
||||||
// const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer);
|
|
||||||
// setZones(updatedZones);
|
|
||||||
|
|
||||||
// const updatedzonePoints = zonePoints.filter((_: any, index: any) => {
|
|
||||||
// const zoneIndex = Math.floor(index / 4);
|
|
||||||
// return zones[zoneIndex]?.layer !== removedLayer;
|
|
||||||
// });
|
|
||||||
// setZonePoints(updatedzonePoints);
|
|
||||||
|
|
||||||
// zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { deleteZoneFromBackend(zone.zoneUuid); });
|
|
||||||
|
|
||||||
// setRemovedLayer(null);
|
|
||||||
// }
|
|
||||||
// }, [removedLayer]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (toolMode !== "Zone") {
|
|
||||||
// setStartPoint(null);
|
|
||||||
// setEndPoint(null);
|
|
||||||
// }
|
|
||||||
// if (!toggleView) {
|
|
||||||
// setStartPoint(null);
|
|
||||||
// setEndPoint(null);
|
|
||||||
// }
|
|
||||||
// }, [toolMode, toggleView]);
|
|
||||||
|
|
||||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
// const addZoneToBackend = async (zone: {
|
|
||||||
// zoneUuid: string;
|
|
||||||
// zoneName: string;
|
|
||||||
// points: [number, number, number][];
|
|
||||||
// layer: string;
|
|
||||||
// }) => {
|
|
||||||
|
|
||||||
// const calculateCenter = (points: number[][]) => {
|
|
||||||
// if (!points || points.length === 0) return null;
|
|
||||||
|
|
||||||
// let sumX = 0, sumY = 0, sumZ = 0;
|
|
||||||
// const numPoints = points.length;
|
|
||||||
|
|
||||||
// points.forEach(([x, y, z]) => {
|
|
||||||
// sumX += x;
|
|
||||||
// sumY += y;
|
|
||||||
// sumZ += z;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
|
|
||||||
// number,
|
|
||||||
// number,
|
|
||||||
// number
|
|
||||||
// ];
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const target: [number, number, number] | null = calculateCenter(zone.points);
|
|
||||||
// if (!target || zone.points.length < 4) return;
|
|
||||||
// const position = [target[0], 10, target[2]];
|
|
||||||
|
|
||||||
// const input = {
|
|
||||||
// userId: userId,
|
|
||||||
// versionId: selectedVersion?.versionId || '',
|
|
||||||
// projectId,
|
|
||||||
// organization,
|
|
||||||
// zoneData: {
|
|
||||||
// zoneName: zone.zoneName,
|
|
||||||
// zoneUuid: zone.zoneUuid,
|
|
||||||
// points: zone.points,
|
|
||||||
// viewPortCenter: target,
|
|
||||||
// viewPortposition: position,
|
|
||||||
// layer: zone.layer,
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
||||||
// socket.emit("v1:zone:set", input);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
// const updateZoneToBackend = async (zone: {
|
|
||||||
// zoneUuid: string;
|
|
||||||
// zoneName: string;
|
|
||||||
// points: [number, number, number][];
|
|
||||||
// layer: string;
|
|
||||||
// }) => {
|
|
||||||
|
|
||||||
// const calculateCenter = (points: number[][]) => {
|
|
||||||
// if (!points || points.length === 0) return null;
|
|
||||||
|
|
||||||
// let sumX = 0, sumY = 0, sumZ = 0;
|
|
||||||
// const numPoints = points.length;
|
|
||||||
|
|
||||||
// points.forEach(([x, y, z]) => {
|
|
||||||
// sumX += x;
|
|
||||||
// sumY += y;
|
|
||||||
// sumZ += z;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
|
|
||||||
// number,
|
|
||||||
// number,
|
|
||||||
// number
|
|
||||||
// ];
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const target: [number, number, number] | null = calculateCenter(zone.points);
|
|
||||||
// if (!target || zone.points.length < 4) return;
|
|
||||||
// const position = [target[0], 10, target[2]];
|
|
||||||
|
|
||||||
// const input = {
|
|
||||||
// userId: userId,
|
|
||||||
// versionId: selectedVersion?.versionId || '',
|
|
||||||
// projectId,
|
|
||||||
// organization,
|
|
||||||
// zoneData: {
|
|
||||||
// zoneName: zone.zoneName,
|
|
||||||
// zoneUuid: zone.zoneUuid,
|
|
||||||
// points: zone.points,
|
|
||||||
// viewPortCenter: target,
|
|
||||||
// viewPortposition: position,
|
|
||||||
// layer: zone.layer,
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
||||||
// socket.emit("v1:zone:set", input);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const deleteZoneFromBackend = async (zoneUuid: string) => {
|
|
||||||
|
|
||||||
// const input = {
|
|
||||||
// userId: userId,
|
|
||||||
// versionId: selectedVersion?.versionId || '',
|
|
||||||
// projectId,
|
|
||||||
// organization,
|
|
||||||
// zoneUuid: zoneUuid,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// socket.emit("v1:zone:delete", input);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
// const handleDeleteZone = (zoneUuid: string) => {
|
|
||||||
// const updatedZones = zones.filter((zone: any) => zone.zoneUuid !== zoneUuid);
|
|
||||||
// setZones(updatedZones);
|
|
||||||
|
|
||||||
// const zoneIndex = zones.findIndex((zone: any) => zone.zoneUuid === zoneUuid);
|
|
||||||
// if (zoneIndex !== -1) {
|
|
||||||
// const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4);
|
|
||||||
// zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point));
|
|
||||||
// const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4);
|
|
||||||
// setZonePoints(updatedzonePoints);
|
|
||||||
// }
|
|
||||||
// deleteZoneFromBackend(zoneUuid);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (!camera || !toggleView) return;
|
|
||||||
// const canvasElement = gl.domElement;
|
|
||||||
|
|
||||||
// let drag = false;
|
|
||||||
// let isLeftMouseDown = false;
|
|
||||||
|
|
||||||
// const onMouseDown = (evt: any) => {
|
|
||||||
// if (evt.button === 0) {
|
|
||||||
// isLeftMouseDown = true;
|
|
||||||
// drag = false;
|
|
||||||
|
|
||||||
// raycaster.setFromCamera(pointer, camera);
|
|
||||||
// const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
|
|
||||||
|
|
||||||
// if (intersects.length > 0 && toolMode === "move") {
|
|
||||||
// const clickedObject = intersects[0].object;
|
|
||||||
// const sphereIndex = zonePoints.findIndex((point: any) =>
|
|
||||||
// point.equals(clickedObject.position)
|
|
||||||
// );
|
|
||||||
// if (sphereIndex !== -1) {
|
|
||||||
// (controls as any).enabled = false;
|
|
||||||
// setDraggedSphere(zonePoints[sphereIndex]);
|
|
||||||
// setIsDragging(true);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onMouseUp = (evt: any) => {
|
|
||||||
// if (evt.button === 0 && !drag && !isDragging && toolMode === 'Zone') {
|
|
||||||
// isLeftMouseDown = false;
|
|
||||||
|
|
||||||
// if (!startPoint) {
|
|
||||||
// raycaster.setFromCamera(pointer, camera);
|
|
||||||
// const intersectionPoint = new THREE.Vector3();
|
|
||||||
// const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
// if (point) {
|
|
||||||
// setStartPoint(point);
|
|
||||||
// setEndPoint(null);
|
|
||||||
// }
|
|
||||||
// } else if (startPoint) {
|
|
||||||
// raycaster.setFromCamera(pointer, camera);
|
|
||||||
// const intersectionPoint = new THREE.Vector3();
|
|
||||||
// const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
// if (!point) return;
|
|
||||||
|
|
||||||
// const points = [
|
|
||||||
// [startPoint.x, 0.15, startPoint.z],
|
|
||||||
// [point.x, 0.15, startPoint.z],
|
|
||||||
// [point.x, 0.15, point.z],
|
|
||||||
// [startPoint.x, 0.15, point.z],
|
|
||||||
// [startPoint.x, 0.15, startPoint.z],
|
|
||||||
// ] as [number, number, number][];
|
|
||||||
|
|
||||||
// const zoneName = `Zone ${zones.length + 1}`;
|
|
||||||
// const zoneUuid = THREE.MathUtils.generateUUID();
|
|
||||||
// const newZone = {
|
|
||||||
// zoneUuid,
|
|
||||||
// zoneName,
|
|
||||||
// points: points,
|
|
||||||
// layer: activeLayer,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const newZones = [...zones, newZone];
|
|
||||||
|
|
||||||
// setZones(newZones);
|
|
||||||
|
|
||||||
// const newzonePoints = [
|
|
||||||
// new THREE.Vector3(startPoint.x, 0.15, startPoint.z),
|
|
||||||
// new THREE.Vector3(point.x, 0.15, startPoint.z),
|
|
||||||
// new THREE.Vector3(point.x, 0.15, point.z),
|
|
||||||
// new THREE.Vector3(startPoint.x, 0.15, point.z),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// const updatedZonePoints = [...zonePoints, ...newzonePoints];
|
|
||||||
// setZonePoints(updatedZonePoints);
|
|
||||||
|
|
||||||
// addZoneToBackend(newZone);
|
|
||||||
// setStartPoint(null);
|
|
||||||
// setEndPoint(null);
|
|
||||||
// }
|
|
||||||
// } else if (evt.button === 0 && !drag && !isDragging && toolMode === '2D-Delete') {
|
|
||||||
// raycaster.setFromCamera(pointer, camera);
|
|
||||||
// const intersects = raycaster.intersectObjects(
|
|
||||||
// groupsRef.current.children,
|
|
||||||
// true
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (intersects.length > 0) {
|
|
||||||
// const clickedObject = intersects[0].object;
|
|
||||||
|
|
||||||
// const sphereIndex = zonePoints.findIndex((point: any) =>
|
|
||||||
// point.equals(clickedObject.position)
|
|
||||||
// );
|
|
||||||
// if (sphereIndex !== -1) {
|
|
||||||
// const zoneIndex = Math.floor(sphereIndex / 4);
|
|
||||||
// const zoneUuid = zones[zoneIndex].zoneUuid;
|
|
||||||
// handleDeleteZone(zoneUuid);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (evt.button === 0) {
|
|
||||||
// if (isDragging && draggedSphere) {
|
|
||||||
// setIsDragging(false);
|
|
||||||
// setDraggedSphere(null);
|
|
||||||
|
|
||||||
// const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
|
|
||||||
// if (sphereIndex !== -1) {
|
|
||||||
// const zoneIndex = Math.floor(sphereIndex / 4);
|
|
||||||
|
|
||||||
// if (zoneIndex !== -1 && zones[zoneIndex]) {
|
|
||||||
// updateZoneToBackend(zones[zoneIndex]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onMouseMove = () => {
|
|
||||||
// if (!groupsRef.current) return;
|
|
||||||
// if (isLeftMouseDown) {
|
|
||||||
// drag = true;
|
|
||||||
// }
|
|
||||||
// raycaster.setFromCamera(pointer, camera);
|
|
||||||
|
|
||||||
// if (isDragging && draggedSphere) {
|
|
||||||
// raycaster.setFromCamera(pointer, camera);
|
|
||||||
// const intersectionPoint = new THREE.Vector3();
|
|
||||||
// const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
// if (point) {
|
|
||||||
// draggedSphere.set(point.x, 0.15, point.z);
|
|
||||||
|
|
||||||
// const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
|
|
||||||
// if (sphereIndex !== -1) {
|
|
||||||
// const zoneIndex = Math.floor(sphereIndex / 4);
|
|
||||||
// const cornerIndex = sphereIndex % 4;
|
|
||||||
|
|
||||||
// const updatedZones = zones.map((zone: any, index: number) => {
|
|
||||||
// if (index === zoneIndex) {
|
|
||||||
// const updatedPoints = [...zone.points];
|
|
||||||
// updatedPoints[cornerIndex] = [point.x, 0.15, point.z];
|
|
||||||
// updatedPoints[4] = updatedPoints[0];
|
|
||||||
// return { ...zone, points: updatedPoints };
|
|
||||||
// }
|
|
||||||
// return zone;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// setZones(updatedZones);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const onContext = (event: any) => {
|
|
||||||
// event.preventDefault();
|
|
||||||
// setStartPoint(null);
|
|
||||||
// setEndPoint(null);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// if (toolMode === "Zone" || toolMode === '2D-Delete' || toolMode === "move") {
|
|
||||||
// canvasElement.addEventListener("mousedown", onMouseDown);
|
|
||||||
// canvasElement.addEventListener("mouseup", onMouseUp);
|
|
||||||
// canvasElement.addEventListener("mousemove", onMouseMove);
|
|
||||||
// canvasElement.addEventListener("contextmenu", onContext);
|
|
||||||
// }
|
|
||||||
// return () => {
|
|
||||||
// canvasElement.removeEventListener("mousedown", onMouseDown);
|
|
||||||
// canvasElement.removeEventListener("mouseup", onMouseUp);
|
|
||||||
// canvasElement.removeEventListener("mousemove", onMouseMove);
|
|
||||||
// canvasElement.removeEventListener("contextmenu", onContext);
|
|
||||||
// };
|
|
||||||
// }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, zonePoints, draggedSphere, activeLayer, raycaster, pointer, controls, plane, setZones, setZonePoints, addZoneToBackend, handleDeleteZone, updateZoneToBackend, selectedVersion?.versionId]);
|
|
||||||
|
|
||||||
// useFrame(() => {
|
|
||||||
// if (!startPoint) return;
|
|
||||||
// raycaster.setFromCamera(pointer, camera);
|
|
||||||
// const intersectionPoint = new THREE.Vector3();
|
|
||||||
// const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
// if (point) {
|
|
||||||
// setEndPoint(point);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <group ref={groupsRef} name="zoneGroup">
|
|
||||||
// <group name="zones" visible={!toggleView}>
|
|
||||||
// {zones.map((zone: any) => (
|
|
||||||
// <group
|
|
||||||
// key={zone.zoneUuid}
|
|
||||||
// name={zone.zoneName}
|
|
||||||
// visible={zone.zoneUuid === selectedZone.zoneUuid}
|
|
||||||
// >
|
|
||||||
// {zone.points
|
|
||||||
// .slice(0, -1)
|
|
||||||
// .map((point: [number, number, number], index: number) => {
|
|
||||||
// const nextPoint = zone.points[index + 1];
|
|
||||||
|
|
||||||
// const point1 = new THREE.Vector3(point[0], point[1], point[2]);
|
|
||||||
// const point2 = new THREE.Vector3(
|
|
||||||
// nextPoint[0],
|
|
||||||
// nextPoint[1],
|
|
||||||
// nextPoint[2]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const planeWidth = point1.distanceTo(point2);
|
|
||||||
// const planeHeight = CONSTANTS.zoneConfig.height;
|
|
||||||
|
|
||||||
// const midpoint = new THREE.Vector3(
|
|
||||||
// (point1.x + point2.x) / 2,
|
|
||||||
// CONSTANTS.zoneConfig.height / 2 +
|
|
||||||
// (zone.layer - 1) * CONSTANTS.zoneConfig.height,
|
|
||||||
// (point1.z + point2.z) / 2
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const angle = Math.atan2(
|
|
||||||
// point2.z - point1.z,
|
|
||||||
// point2.x - point1.x
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <mesh
|
|
||||||
// key={index}
|
|
||||||
// position={midpoint}
|
|
||||||
// rotation={[0, -angle, 0]}
|
|
||||||
// >
|
|
||||||
// <planeGeometry args={[planeWidth, planeHeight]} />
|
|
||||||
// <primitive
|
|
||||||
// object={zoneMaterial.clone()}
|
|
||||||
// attach="material"
|
|
||||||
// />
|
|
||||||
// </mesh>
|
|
||||||
// );
|
|
||||||
// })}
|
|
||||||
// {!toggleView &&
|
|
||||||
// (() => {
|
|
||||||
// const points3D = zone.points || [];
|
|
||||||
// const coords2D = points3D.map((p: any) => [p[0], p[2]]);
|
|
||||||
|
|
||||||
// // Ensure the polygon is closed
|
|
||||||
// if (
|
|
||||||
// coords2D.length >= 4 &&
|
|
||||||
// (coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
|
|
||||||
// coords2D[0][1] !== coords2D[coords2D.length - 1][1])
|
|
||||||
// ) {
|
|
||||||
// coords2D.push(coords2D[0]);
|
|
||||||
// }
|
|
||||||
// if (coords2D.length < 4) return null;
|
|
||||||
|
|
||||||
// const polygon = turf.polygon([coords2D]);
|
|
||||||
// const center2D = turf.center(polygon).geometry.coordinates;
|
|
||||||
|
|
||||||
// // Calculate the average Y value
|
|
||||||
// const sumY = points3D.reduce(
|
|
||||||
// (sum: number, p: any) => sum + p[1],
|
|
||||||
// 0
|
|
||||||
// );
|
|
||||||
// const avgY = points3D.length > 0 ? sumY / points3D.length : 0;
|
|
||||||
|
|
||||||
// const htmlPosition: [number, number, number] = [
|
|
||||||
// center2D[0],
|
|
||||||
// avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5,
|
|
||||||
// center2D[1],
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <Html
|
|
||||||
// // data
|
|
||||||
// key={zone.zoneUuid}
|
|
||||||
// position={htmlPosition}
|
|
||||||
// // class
|
|
||||||
// className="zone-name-wrapper"
|
|
||||||
// // others
|
|
||||||
// center
|
|
||||||
// >
|
|
||||||
// <div className="zone-name">{zone.zoneName}</div>
|
|
||||||
// </Html>
|
|
||||||
// );
|
|
||||||
// })()}
|
|
||||||
// </group>
|
|
||||||
// ))}
|
|
||||||
// </group>
|
|
||||||
// <group name="zoneLines" visible={toggleView}>
|
|
||||||
// {zones
|
|
||||||
// .filter((zone: any) => zone.layer === activeLayer)
|
|
||||||
// .map((zone: any) => (
|
|
||||||
// <Line
|
|
||||||
// key={zone.zoneUuid}
|
|
||||||
// points={zone.points}
|
|
||||||
// color="#007BFF"
|
|
||||||
// lineWidth={3}
|
|
||||||
// onClick={(e) => {
|
|
||||||
// e.stopPropagation();
|
|
||||||
// if (toolMode === '2D-Delete') {
|
|
||||||
// handleDeleteZone(zone.zoneUuid);
|
|
||||||
// }
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// ))}
|
|
||||||
// </group>
|
|
||||||
// <group name="zoneArea" visible={toggleView}>
|
|
||||||
// {zones.map((zone: any, index: any) => {
|
|
||||||
// if (!toggleView) return null;
|
|
||||||
// const points3D = zone.points;
|
|
||||||
// const coords2D = points3D.map((p: any) => [p[0], p[2]]);
|
|
||||||
|
|
||||||
// if (
|
|
||||||
// coords2D.length < 4 ||
|
|
||||||
// coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
|
|
||||||
// coords2D[0][1] !== coords2D[coords2D.length - 1][1]
|
|
||||||
// ) {
|
|
||||||
// coords2D.push(coords2D[0]);
|
|
||||||
// }
|
|
||||||
// if (coords2D.length < 4) return null;
|
|
||||||
|
|
||||||
// const polygon = turf.polygon([coords2D]);
|
|
||||||
// const center2D = turf.center(polygon).geometry.coordinates;
|
|
||||||
|
|
||||||
// const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0);
|
|
||||||
// const avgY = sumY / points3D.length;
|
|
||||||
|
|
||||||
// const area = computeArea(points3D, "zone");
|
|
||||||
// const formattedArea = `${area.toFixed(2)} m²`;
|
|
||||||
|
|
||||||
// const htmlPosition: [number, number, number] = [
|
|
||||||
// center2D[0],
|
|
||||||
// avgY + CONSTANTS.zoneConfig.height,
|
|
||||||
// center2D[1],
|
|
||||||
// ];
|
|
||||||
// return (
|
|
||||||
// <Html
|
|
||||||
// // data
|
|
||||||
// key={`${index}-${zone}`}
|
|
||||||
// position={htmlPosition}
|
|
||||||
// // class
|
|
||||||
// wrapperClass="distance-text-wrapper"
|
|
||||||
// className="distance-text"
|
|
||||||
// // other
|
|
||||||
// zIndexRange={[1, 0]}
|
|
||||||
// prepend
|
|
||||||
// center
|
|
||||||
// sprite
|
|
||||||
// >
|
|
||||||
// <div
|
|
||||||
// className={`distance area line-${zone}`}
|
|
||||||
// key={`${index}-${zone}`}
|
|
||||||
// >
|
|
||||||
// {zone.zoneName} ({formattedArea})
|
|
||||||
// </div>
|
|
||||||
// </Html>
|
|
||||||
// );
|
|
||||||
// })}
|
|
||||||
// </group>
|
|
||||||
|
|
||||||
// <group name="zonePoints" visible={toggleView}>
|
|
||||||
// {zones
|
|
||||||
// .filter((zone: any) => zone.layer === activeLayer)
|
|
||||||
// .flatMap((zone: any) =>
|
|
||||||
// zone.points.slice(0, 4).map((point: any, pointIndex: number) => (
|
|
||||||
// <Sphere
|
|
||||||
// key={`${zone.zoneUuid}-point-${pointIndex}`}
|
|
||||||
// position={new THREE.Vector3(...point)}
|
|
||||||
// args={[0.3, 16, 16]}
|
|
||||||
// name={`point-${zone.zoneUuid}-${pointIndex}`}
|
|
||||||
// >
|
|
||||||
// <meshBasicMaterial color="red" />
|
|
||||||
// </Sphere>
|
|
||||||
// ))
|
|
||||||
// )}
|
|
||||||
// </group>
|
|
||||||
// <group name="tempGroup" visible={toggleView}>
|
|
||||||
// {startPoint && endPoint && (
|
|
||||||
// <Line
|
|
||||||
// points={[
|
|
||||||
// [startPoint.x, 0.15, startPoint.z],
|
|
||||||
// [endPoint.x, 0.15, startPoint.z],
|
|
||||||
// [endPoint.x, 0.15, endPoint.z],
|
|
||||||
// [startPoint.x, 0.15, endPoint.z],
|
|
||||||
// [startPoint.x, 0.15, startPoint.z],
|
|
||||||
// ]}
|
|
||||||
// color="#C164FF"
|
|
||||||
// lineWidth={3}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// </group>
|
|
||||||
// </group>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default ZoneGroup;
|
|
||||||
@@ -14,6 +14,8 @@ import { getUserData } from '../../../functions/getUserData';
|
|||||||
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||||
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||||
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||||
|
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||||
|
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||||
|
|
||||||
interface LineProps {
|
interface LineProps {
|
||||||
points: [Point, Point];
|
points: [Point, Point];
|
||||||
@@ -26,9 +28,10 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
const [isDeletable, setIsDeletable] = useState(false);
|
const [isDeletable, setIsDeletable] = useState(false);
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { wallStore, floorStore } = useSceneContext();
|
const { wallStore, floorStore, zoneStore } = useSceneContext();
|
||||||
const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore();
|
const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore();
|
||||||
const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId } = floorStore();
|
const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId } = floorStore();
|
||||||
|
const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId } = zoneStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
@@ -163,6 +166,53 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
setHoveredLine(null);
|
setHoveredLine(null);
|
||||||
}
|
}
|
||||||
|
if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
||||||
|
const { removedZones, updatedZones } = removeZoneByPoints(points);
|
||||||
|
if (removedZones.length > 0) {
|
||||||
|
removedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneUuid: zone.zoneUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:delete', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedZones.length > 0) {
|
||||||
|
updatedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
gl.domElement.style.cursor = 'default';
|
gl.domElement.style.cursor = 'default';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,6 +244,10 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
setFloorPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
setFloorPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
||||||
setFloorPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
setFloorPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
||||||
}
|
}
|
||||||
|
if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
||||||
|
setZonePosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
||||||
|
setZonePosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -271,6 +325,33 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
socket.emit('v1:model-Floor:add', data);
|
socket.emit('v1:model-Floor:add', data);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
} else if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
||||||
|
const updatedZones1 = getZonesByPointId(points[0].pointUuid);
|
||||||
|
const updatedZones2 = getZonesByPointId(points[1].pointUuid);
|
||||||
|
const updatedZones = [...updatedZones1, ...updatedZones2].filter((zone, index, self) => index === self.findIndex((z) => z.zoneUuid === zone.zoneUuid));
|
||||||
|
|
||||||
|
if (updatedZones.length > 0 && projectId) {
|
||||||
|
updatedZones.forEach(updatedZone => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone).catch((error) => {
|
||||||
|
// console.error('Error updating zone:', error);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: updatedZone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,9 +205,9 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string
|
|||||||
const snapFloorPoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => {
|
const snapFloorPoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => {
|
||||||
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||||
|
|
||||||
const otherPoints = getAllOtherFloorPoints();
|
let otherPoints = getAllOtherFloorPoints();
|
||||||
if (tempPoints) {
|
if (tempPoints) {
|
||||||
otherPoints.concat(tempPoints);
|
otherPoints = [...otherPoints, ...tempPoints];
|
||||||
}
|
}
|
||||||
const currentVec = new THREE.Vector3(...position);
|
const currentVec = new THREE.Vector3(...position);
|
||||||
|
|
||||||
@@ -292,9 +292,9 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string
|
|||||||
const snapZonePoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => {
|
const snapZonePoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => {
|
||||||
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||||
|
|
||||||
const otherPoints = getAllOtherZonePoints();
|
let otherPoints = getAllOtherZonePoints();
|
||||||
if (tempPoints) {
|
if (tempPoints) {
|
||||||
otherPoints.concat(tempPoints);
|
otherPoints = [...otherPoints, ...tempPoints];
|
||||||
}
|
}
|
||||||
const currentVec = new THREE.Vector3(...position);
|
const currentVec = new THREE.Vector3(...position);
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAis
|
|||||||
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
||||||
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||||
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||||
import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||||
|
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||||
|
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||||
|
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||||
|
|
||||||
import { getUserData } from '../../../functions/getUserData';
|
import { getUserData } from '../../../functions/getUserData';
|
||||||
import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
|
||||||
|
|
||||||
function Point({ point }: { readonly point: Point }) {
|
function Point({ point }: { readonly point: Point }) {
|
||||||
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
||||||
@@ -27,11 +29,12 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { aisleStore, wallStore, floorStore } = useSceneContext();
|
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
|
||||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
||||||
const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore();
|
const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore();
|
||||||
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
|
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
|
||||||
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore();
|
||||||
|
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
||||||
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
|
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -127,6 +130,10 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
const floorSnapped = snapFloorAngle(newPosition);
|
const floorSnapped = snapFloorAngle(newPosition);
|
||||||
const finalSnapped = snapFloorPoint(floorSnapped.position);
|
const finalSnapped = snapFloorPoint(floorSnapped.position);
|
||||||
setFloorPosition(point.pointUuid, finalSnapped.position);
|
setFloorPosition(point.pointUuid, finalSnapped.position);
|
||||||
|
} else if (point.pointType === 'Zone') {
|
||||||
|
const zoneSnapped = snapAisleAngle(newPosition);
|
||||||
|
const finalSnapped = snapZonePoint(zoneSnapped.position);
|
||||||
|
setZonePosition(point.pointUuid, finalSnapped.position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,6 +206,28 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
socket.emit('v1:model-Floor:add', data);
|
socket.emit('v1:model-Floor:add', data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else if (point.pointType === 'Zone') {
|
||||||
|
const updatedZones = getZonesByPointId(point.pointUuid);
|
||||||
|
if (updatedZones && updatedZones.length > 0 && projectId) {
|
||||||
|
updatedZones.forEach((updatedZone) => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: updatedZone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +318,54 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (point.pointType === 'Zone') {
|
||||||
|
const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
|
||||||
|
setHoveredPoint(null);
|
||||||
|
if (removedZones.length > 0) {
|
||||||
|
removedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneUuid: zone.zoneUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:delete', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedZones.length > 0) {
|
||||||
|
updatedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
gl.domElement.style.cursor = 'default';
|
gl.domElement.style.cursor = 'default';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,9 +85,12 @@ export function useWallClassification(walls: Walls) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allCoords = mergedLineStrings.flatMap(ls => ls.geometry.coordinates);
|
||||||
|
const uniqueCoords = Array.from(new Set(allCoords.map(coord => coord.join(','))));
|
||||||
|
if (uniqueCoords.length < 4) return [];
|
||||||
|
|
||||||
const lineStrings = turf.featureCollection(mergedLineStrings);
|
const lineStrings = turf.featureCollection(mergedLineStrings);
|
||||||
|
|
||||||
// Now polygonize merged line strings
|
|
||||||
const polygons = turf.polygonize(lineStrings);
|
const polygons = turf.polygonize(lineStrings);
|
||||||
|
|
||||||
const rooms: Point[][] = [];
|
const rooms: Point[][] = [];
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ function ZoneInstance({ zone }: { zone: Zone }) {
|
|||||||
name={`Zone-${zone.zoneUuid}`}
|
name={`Zone-${zone.zoneUuid}`}
|
||||||
userData={zone}
|
userData={zone}
|
||||||
>
|
>
|
||||||
{zone.points.slice(0, -1).map((point, index: number) => {
|
{zone.points.map((point, index: number) => {
|
||||||
const nextPoint = zone.points[index + 1];
|
const nextPoint = zone.points[(index + 1) % zone.points.length];
|
||||||
|
|
||||||
const point1 = new Vector3(point.position[0], point.position[1], point.position[2]);
|
const point1 = new Vector3(point.position[0], point.position[1], point.position[2]);
|
||||||
const point2 = new Vector3(nextPoint.position[0], nextPoint.position[1], nextPoint.position[2]);
|
const point2 = new Vector3(nextPoint.position[0], nextPoint.position[1], nextPoint.position[2]);
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ function ZoneInstances() {
|
|||||||
const { zones } = zoneStore();
|
const { zones } = zoneStore();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('zones: ', zones);
|
|
||||||
}, [zones]);
|
|
||||||
|
|
||||||
const allPoints = useMemo(() => {
|
const allPoints = useMemo(() => {
|
||||||
const points: Point[] = [];
|
const points: Point[] = [];
|
||||||
const seenUuids = new Set<string>();
|
const seenUuids = new Set<string>();
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function ReferenceZone({ tempPoints }: Readonly<ReferenceZoneProps>) {
|
|||||||
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||||
|
|
||||||
if (!intersectionPoint) return;
|
if (!intersectionPoint) return;
|
||||||
const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.slice(0, -2));
|
const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], [tempPoints[0]]);
|
||||||
|
|
||||||
if (snapped.isSnapped && snapped.snappedPoint) {
|
if (snapped.isSnapped && snapped.snappedPoint) {
|
||||||
finalPosition.current = snapped.position;
|
finalPosition.current = snapped.position;
|
||||||
|
|||||||
@@ -10,9 +10,250 @@ import { getUserData } from '../../../../functions/getUserData';
|
|||||||
import ReferencePoint from '../../point/reference/referencePoint';
|
import ReferencePoint from '../../point/reference/referencePoint';
|
||||||
import ReferenceZone from './referenceZone';
|
import ReferenceZone from './referenceZone';
|
||||||
|
|
||||||
|
// import { upsertZoneApi } from '../../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||||
|
|
||||||
function ZoneCreator() {
|
function ZoneCreator() {
|
||||||
|
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||||
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
|
const { toggleView } = useToggleView();
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
|
const { activeLayer } = useActiveLayer();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { zoneStore } = useSceneContext();
|
||||||
|
const { addZone, getZonePointById, getZoneByPoints } = zoneStore();
|
||||||
|
const drag = useRef(false);
|
||||||
|
const isLeftMouseDown = useRef(false);
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||||
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
|
const { zoneColor, zoneHeight, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
|
const onMouseDown = (evt: any) => {
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown.current = true;
|
||||||
|
drag.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseUp = (evt: any) => {
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseMove = () => {
|
||||||
|
if (isLeftMouseDown) {
|
||||||
|
drag.current = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseClick = () => {
|
||||||
|
if (drag.current || !toggleView) return;
|
||||||
|
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
let position = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
if (!position) return;
|
||||||
|
|
||||||
|
const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Zone-Point');
|
||||||
|
|
||||||
|
// const zoneIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Zone-Line');
|
||||||
|
|
||||||
|
// if (zoneIntersect && !pointIntersects) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
const newPoint: Point = {
|
||||||
|
pointUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
pointType: 'Zone',
|
||||||
|
position: [position.x, position.y, position.z],
|
||||||
|
layer: activeLayer
|
||||||
|
};
|
||||||
|
|
||||||
|
if (snappedPosition && snappedPoint) {
|
||||||
|
newPoint.pointUuid = snappedPoint.pointUuid;
|
||||||
|
newPoint.position = snappedPosition;
|
||||||
|
newPoint.layer = snappedPoint.layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snappedPoint && snappedPoint.pointUuid === tempPoints[tempPoints.length - 1]?.pointUuid) { return }
|
||||||
|
|
||||||
|
if (snappedPosition && !snappedPoint) {
|
||||||
|
newPoint.position = snappedPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) {
|
||||||
|
const zone: Zone = {
|
||||||
|
zoneUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
zoneName: "Zone",
|
||||||
|
points: tempPoints,
|
||||||
|
zoneColor,
|
||||||
|
zoneHeight,
|
||||||
|
viewPortPosition: [0, 0, 0],
|
||||||
|
viewPortTarget: [0, 0, 0]
|
||||||
|
};
|
||||||
|
|
||||||
|
addZone(zone);
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
} else if (isCreating && snappedPoint && !tempPoints.some(p => p.pointUuid === snappedPoint.pointUuid)) {
|
||||||
|
setTempPoints(prev => [...prev, newPoint]);
|
||||||
|
setIsCreating(true);
|
||||||
|
} else if (pointIntersects) {
|
||||||
|
if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) {
|
||||||
|
const zone: Zone = {
|
||||||
|
zoneUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
zoneName: "Zone",
|
||||||
|
points: tempPoints,
|
||||||
|
zoneColor,
|
||||||
|
zoneHeight,
|
||||||
|
viewPortPosition: [0, 0, 0],
|
||||||
|
viewPortTarget: [0, 0, 0]
|
||||||
|
};
|
||||||
|
|
||||||
|
addZone(zone);
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
} else if (tempPoints.length === 0 || (tempPoints.length > 1 && !tempPoints.slice(1).some(p => p.pointUuid === pointIntersects.object.uuid))) {
|
||||||
|
tempPoints.push(pointIntersects.object.userData as Point);
|
||||||
|
setIsCreating(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTempPoints(prev => [...prev, newPoint]);
|
||||||
|
setIsCreating(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const onContext = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (isCreating) {
|
||||||
|
if (tempPoints.length >= 3) {
|
||||||
|
const zone: Zone = {
|
||||||
|
zoneUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
zoneName: "Zone",
|
||||||
|
points: tempPoints,
|
||||||
|
zoneColor,
|
||||||
|
zoneHeight,
|
||||||
|
viewPortPosition: [0, 0, 0],
|
||||||
|
viewPortTarget: [0, 0, 0]
|
||||||
|
};
|
||||||
|
|
||||||
|
addZone(zone);
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (toolMode === "Zone" && toggleView) {
|
||||||
|
if (tempPoints.length === 0) {
|
||||||
|
setSnappedPosition(null);
|
||||||
|
setSnappedPoint(null);
|
||||||
|
}
|
||||||
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.addEventListener("click", onMouseClick);
|
||||||
|
canvasElement.addEventListener("contextmenu", onContext);
|
||||||
|
} else {
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener("click", onMouseClick);
|
||||||
|
canvasElement.removeEventListener("contextmenu", onContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener("click", onMouseClick);
|
||||||
|
canvasElement.removeEventListener("contextmenu", onContext);
|
||||||
|
};
|
||||||
|
}, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addZone, getZonePointById, getZoneByPoints, zoneColor, zoneHeight, snappedPosition, snappedPoint]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{toggleView &&
|
||||||
|
<>
|
||||||
|
<group name='Zone-Reference-Points-Group'>
|
||||||
|
{tempPoints.map((point) => (
|
||||||
|
<ReferencePoint key={point.pointUuid} point={point} />
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
|
||||||
|
{tempPoints.length > 0 &&
|
||||||
|
<ReferenceZone tempPoints={tempPoints} />
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const deleteZoneApi = async (
|
|||||||
zoneUuid: string
|
zoneUuid: string
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/V2/deleteZone`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/V1/zones/delete`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer <access_token>",
|
Authorization: "Bearer <access_token>",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const getZonesApi = async (
|
|||||||
versionId: string,
|
versionId: string,
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/V2/zones/${projectId}/${versionId}`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/V1/zones/${projectId}/${versionId}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer <access_token>",
|
Authorization: "Bearer <access_token>",
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
export const upsertWallApi = async (
|
export const upsertZoneApi = async (
|
||||||
projectId: string,
|
projectId: string,
|
||||||
versionId: string,
|
versionId: string,
|
||||||
ZoneData: Zone
|
zoneData: Zone
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/V2/UpsertZone`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertZone`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer <access_token>",
|
Authorization: "Bearer <access_token>",
|
||||||
@@ -14,7 +14,7 @@ export const upsertWallApi = async (
|
|||||||
token: localStorage.getItem("token") || "",
|
token: localStorage.getItem("token") || "",
|
||||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ projectId, versionId, ZoneData }),
|
body: JSON.stringify({ projectId, versionId, zoneData }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const newAccessToken = response.headers.get("x-access-token");
|
const newAccessToken = response.headers.get("x-access-token");
|
||||||
|
|||||||
@@ -473,6 +473,7 @@ export const useWidgetSubOption = create<any>((set: any) => ({
|
|||||||
widgetSubOption: "2D",
|
widgetSubOption: "2D",
|
||||||
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
|
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useLimitDistance = create<any>((set: any) => ({
|
export const useLimitDistance = create<any>((set: any) => ({
|
||||||
limitDistance: true,
|
limitDistance: true,
|
||||||
setLimitDistance: (x: any) => set({ limitDistance: x }),
|
setLimitDistance: (x: any) => set({ limitDistance: x }),
|
||||||
|
|||||||
@@ -257,8 +257,7 @@ export const createFloorStore = () => {
|
|||||||
return get().floors.find(floor => {
|
return get().floors.find(floor => {
|
||||||
const floorPointIds = new Set(floor.points.map(p => p.pointUuid));
|
const floorPointIds = new Set(floor.points.map(p => p.pointUuid));
|
||||||
const givenPointIds = new Set(points.map(p => p.pointUuid));
|
const givenPointIds = new Set(points.map(p => p.pointUuid));
|
||||||
return floorPointIds.size === givenPointIds.size &&
|
return floorPointIds.size === givenPointIds.size && [...floorPointIds].every(id => givenPointIds.has(id));
|
||||||
[...floorPointIds].every(id => givenPointIds.has(id));
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,19 @@ interface ZoneStore {
|
|||||||
setZoneHeight: (uuid: string, height: number) => void;
|
setZoneHeight: (uuid: string, height: number) => void;
|
||||||
setZoneColor: (uuid: string, color: string) => void;
|
setZoneColor: (uuid: string, color: string) => void;
|
||||||
removeZone: (uuid: string) => void;
|
removeZone: (uuid: string) => void;
|
||||||
removePointFromZones: (pointUuid: string) => void;
|
removePoint: (pointUuid: string) => { removedZones: Zone[], updatedZones: Zone[] };
|
||||||
|
removeZoneByPoints: (points: Point[]) => { removedZones: Zone[], updatedZones: Zone[] };
|
||||||
clearZones: () => void;
|
clearZones: () => void;
|
||||||
|
setPosition: (
|
||||||
|
pointUuid: string,
|
||||||
|
position: [number, number, number]
|
||||||
|
) => Zone[] | [];
|
||||||
setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void;
|
setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void;
|
||||||
|
|
||||||
getZoneById: (uuid: string) => Zone | undefined;
|
getZoneById: (uuid: string) => Zone | undefined;
|
||||||
|
getZonesByPointId: (uuid: string) => Zone[] | [];
|
||||||
|
getZoneByPoints: (points: Point[]) => Zone | undefined;
|
||||||
|
getZonePointById: (uuid: string) => Point | undefined;
|
||||||
getConnectedPoints: (uuid: string) => Point[];
|
getConnectedPoints: (uuid: string) => Point[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,16 +71,97 @@ export const createZoneStore = () => {
|
|||||||
state.zones = state.zones.filter(z => z.zoneUuid !== uuid);
|
state.zones = state.zones.filter(z => z.zoneUuid !== uuid);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
removePointFromZones: (pointUuid) => set(state => {
|
removePoint: (pointUuid) => {
|
||||||
for (const zone of state.zones) {
|
const removedZones: Zone[] = [];
|
||||||
zone.points = zone.points.filter(p => p.pointUuid !== pointUuid);
|
const updatedZones: Zone[] = [];
|
||||||
}
|
|
||||||
}),
|
set(state => {
|
||||||
|
for (const zone of state.zones) {
|
||||||
|
const pointIndex = zone.points.findIndex(p => p.pointUuid === pointUuid);
|
||||||
|
if (pointIndex === -1) {
|
||||||
|
updatedZones.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingPoints = zone.points.filter(p => p.pointUuid !== pointUuid);
|
||||||
|
|
||||||
|
if (remainingPoints.length <= 2) {
|
||||||
|
removedZones.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
zone.points = remainingPoints;
|
||||||
|
updatedZones.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
}
|
||||||
|
|
||||||
|
state.zones = updatedZones;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { removedZones, updatedZones };
|
||||||
|
},
|
||||||
|
|
||||||
|
removeZoneByPoints: ([pointA, pointB]) => {
|
||||||
|
const removedZones: Zone[] = [];
|
||||||
|
const updatedZones: Zone[] = [];
|
||||||
|
|
||||||
|
set(state => {
|
||||||
|
|
||||||
|
for (const zone of state.zones) {
|
||||||
|
const indices = zone.points.map((p, i) => ({ uuid: p.pointUuid, index: i }));
|
||||||
|
|
||||||
|
const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1;
|
||||||
|
const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1;
|
||||||
|
|
||||||
|
if (idxA === -1 || idxB === -1) {
|
||||||
|
updatedZones.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const areAdjacent =
|
||||||
|
Math.abs(idxA - idxB) === 1 ||
|
||||||
|
(idxA === 0 && idxB === zone.points.length - 1) ||
|
||||||
|
(idxB === 0 && idxA === zone.points.length - 1);
|
||||||
|
|
||||||
|
if (!areAdjacent) {
|
||||||
|
updatedZones.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingPoints = zone.points.filter(
|
||||||
|
p => p.pointUuid !== pointA.pointUuid && p.pointUuid !== pointB.pointUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (remainingPoints.length > 2) {
|
||||||
|
zone.points = remainingPoints;
|
||||||
|
updatedZones.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
} else {
|
||||||
|
removedZones.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.zones = updatedZones;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { removedZones, updatedZones };
|
||||||
|
},
|
||||||
|
|
||||||
clearZones: () => set(state => {
|
clearZones: () => set(state => {
|
||||||
state.zones = [];
|
state.zones = [];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
setPosition: (pointUuid, position) => {
|
||||||
|
let updatedZone: Zone[] = [];
|
||||||
|
set((state) => {
|
||||||
|
for (const zone of state.zones) {
|
||||||
|
const point = zone.points.find((p) => p.pointUuid === pointUuid);
|
||||||
|
if (point) {
|
||||||
|
point.position = position;
|
||||||
|
updatedZone.push(JSON.parse(JSON.stringify(zone)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return updatedZone;
|
||||||
|
},
|
||||||
|
|
||||||
setViewPort: (uuid, position, target) => set(state => {
|
setViewPort: (uuid, position, target) => set(state => {
|
||||||
const zone = state.zones.find(z => z.zoneUuid === uuid);
|
const zone = state.zones.find(z => z.zoneUuid === uuid);
|
||||||
if (zone) {
|
if (zone) {
|
||||||
@@ -85,6 +174,28 @@ export const createZoneStore = () => {
|
|||||||
return get().zones.find(z => z.zoneUuid === uuid);
|
return get().zones.find(z => z.zoneUuid === uuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getZonesByPointId: (pointUuid) => {
|
||||||
|
return get().zones.filter(zone => {
|
||||||
|
return zone.points.some(p => p.pointUuid === pointUuid);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getZoneByPoints: (points) => {
|
||||||
|
return get().zones.find(zone => {
|
||||||
|
const zonePointIds = new Set(zone.points.map(p => p.pointUuid));
|
||||||
|
const givenPointIds = new Set(points.map(p => p.pointUuid));
|
||||||
|
return zonePointIds.size === givenPointIds.size && [...zonePointIds].every(id => givenPointIds.has(id));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getZonePointById: (pointUuid) => {
|
||||||
|
for (const zone of get().zones) {
|
||||||
|
const point = zone.points.find(p => p.pointUuid === pointUuid);
|
||||||
|
if (point) return point;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
getConnectedPoints: (pointUuid) => {
|
getConnectedPoints: (pointUuid) => {
|
||||||
const connected: Point[] = [];
|
const connected: Point[] = [];
|
||||||
for (const zone of get().zones) {
|
for (const zone of get().zones) {
|
||||||
|
|||||||
Reference in New Issue
Block a user