v2-ui #84

Merged
Vishnu merged 53 commits from v2-ui into main 2025-05-10 13:42:19 +00:00
7 changed files with 798 additions and 664 deletions
Showing only changes of commit 6d45a89197 - Show all commits

View File

@ -52,6 +52,7 @@ import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
import ZoneGroup from "./groups/zoneGroup";
import MeasurementTool from "../scene/tools/measurementTool";
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
import CalculateAreaGroup from "./groups/calculateAreaGroup";
export default function Builder() {
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
@ -341,7 +342,7 @@ export default function Builder() {
/>
<MeasurementTool />
<CalculateAreaGroup />
<NavMesh lines={lines} />
</>
);

View File

@ -0,0 +1,29 @@
import { Vector2 } from "three";
export function computeArea(data: any, type: "zone" | "rooms" | "aisle"): any {
if (type === "zone") {
const points3D = data.map((p: any) => new Vector2(p[0], p[2]));
let area = 0;
for (let i = 0; i < points3D.length - 1; i++) {
const current = points3D[i];
const next = points3D[i + 1];
area += current.x * next.y - next.x * current.y;
}
return Math.abs(area) / 2;
}
if (type === "rooms") {
const points2D = data.coordinates.map(
(coordinate: any) =>
new Vector2(coordinate.position.x, coordinate.position.z)
);
let area = 0;
for (let i = 0; i < points2D.length - 1; i++) {
const current = points2D[i];
const next = points2D[i + 1];
area += current.x * next.y - next.x * current.y;
}
return Math.abs(area) / 2;
}
}

View File

@ -1,17 +0,0 @@
import { Vector2 } from "three";
export function computeAreaFrom3DPoints(points3D: any) {
// Project 3D points onto XZ plane
const projected = points3D.map((p: any) => new Vector2(p[0], p[2]));
// Shoelace formula for 2D polygon
let area = 0;
const n = projected.length;
for (let i = 0; i < n - 1; i++) {
const curr = projected[i];
const next = projected[i + 1];
area += curr.x * next.y - next.x * curr.y;
}
return Math.abs(area) / 2;
}

View File

@ -10,8 +10,10 @@ import {
} from "../../../../../store/store";
import objectLinesToArray from "../lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei";
import { Vector2 } from "three";
import * as Types from "../../../../../types/world/worldTypes";
import getRoomsFromLines from "../getRoomsFromLines";
import * as turf from '@turf/turf';
const DistanceText = () => {
const [lines, setLines] = useState<
@ -29,10 +31,52 @@ const DistanceText = () => {
const [linesState, setLinesState] = useState<Types.Lines>([]);
const { roomsState, setRoomsState } = useRoomsState();
useEffect(() => {
if (linesState.length === 0) return;
const getLines = async () => {
const points3D = linesState.map(line => {
const startPoint = line[0][0]; // First point of each wall line
return [startPoint.x, 0, startPoint.z];
});
// Ensure the polygon is closed
if (
points3D[0][0] !== points3D[points3D.length - 1][0] ||
points3D[0][1] !== points3D[points3D.length - 1][1]
) {
points3D.push(points3D[0]);
}
// Convert to 2D for turf (x, z)
const coords2D = points3D.map(p => [p[0], p[1]]);
const projected = points3D.map((p: any) => new Vector2(p[0], p[1]));
// Shoelace formula for 2D polygon
let area = 0;
const n = projected.length;
for (let i = 0; i < n - 1; i++) {
const curr = projected[i];
const next = projected[i + 1];
area += curr.x * next.y - next.x * curr.y;
}
// return Math.abs(area) / 2;
// Build polygon and compute area
// const polygon = turf.polygon([coords2D]);
// const area = turf.area(polygon);
// const area = computeAreaFrom3DPoints(coords2D)
//
if (lines.length > 2) {
const linesByLayer = linesState.reduce((acc: { [key: number]: any[] }, pair) => {
const layer = pair[0][2];
@ -41,15 +85,16 @@ const DistanceText = () => {
return acc;
}, {});
for (const layer in linesByLayer) {
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
setRoomsState(rooms)
}
}
}
getLines();
}, [linesState])
}, [linesState, roomsState])
useEffect(() => {
const email = localStorage.getItem("email");
@ -143,6 +188,7 @@ const DistanceText = () => {
);
setDeletedLines([]);
setRoomsState([])
}
}, [deletedLines]);

View File

@ -0,0 +1,65 @@
import React, { useEffect } from 'react';
import { useRoomsState, useToggleView } from '../../../store/store';
import { computeArea } from '../functions/computeArea';
import { Html } from '@react-three/drei';
import * as CONSTANTS from "../../../types/world/worldConstants";
import * as turf from '@turf/turf';
const CalculateAreaGroup = () => {
const { roomsState } = useRoomsState();
const { toggleView } = useToggleView();
return (
<group name="roomArea" visible={toggleView}>
{roomsState.length > 0 &&
roomsState.flat().map((room: any, index: number) => {
if (!toggleView) return null;
const coordinates = room.coordinates;
if (!coordinates || coordinates.length < 3) return null;
let coords2D = coordinates.map((p: any) => [p.position.x, p.position.z]);
const first = coords2D[0];
const last = coords2D[coords2D.length - 1];
if (first[0] !== last[0] || first[1] !== last[1]) {
coords2D.push(first);
}
const polygon = turf.polygon([coords2D]);
const center2D = turf.center(polygon).geometry.coordinates;
const sumY = coordinates.reduce((sum: number, p: any) => sum + p.position.y, 0);
const avgY = sumY / coordinates.length;
const area = computeArea(room, "rooms");
const formattedArea = `${area.toFixed(2)}`;
const htmlPosition: [number, number, number] = [
center2D[0],
avgY + CONSTANTS.zoneConfig.height,
center2D[1],
];
return (
<Html
key={`${index}-${room.layer || index}`}
position={htmlPosition}
wrapperClass="distance-text-wrapper"
className="distance-text"
zIndexRange={[1, 0]}
prepend
center
sprite
>
<div className={`distance area line-${room.layer || index}`}>
Room ({formattedArea})
</div>
</Html>
);
})}
</group>
);
}
export default CalculateAreaGroup;

View File

@ -18,7 +18,7 @@ import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"
import * as CONSTANTS from "../../../types/world/worldConstants";
import * as turf from '@turf/turf';
import { computeAreaFrom3DPoints } from "../functions/computeAreaFrom3DPoints";
import { computeArea } from "../functions/computeArea";
const ZoneGroup: React.FC = () => {
const { camera, pointer, gl, raycaster, scene, controls } = useThree();
@ -597,8 +597,9 @@ const ZoneGroup: React.FC = () => {
))}
</group>
<group name="zoneArea">
<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]]);
@ -616,7 +617,7 @@ const ZoneGroup: React.FC = () => {
const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0);
const avgY = sumY / points3D.length;
const area = computeAreaFrom3DPoints(points3D);
const area = computeArea(points3D, "zone");
const formattedArea = `${area.toFixed(2)}`;
const htmlPosition: [number, number, number] = [
@ -686,3 +687,12 @@ const ZoneGroup: React.FC = () => {
};
export default ZoneGroup;

View File

@ -68,7 +68,7 @@ export const useWalls = create<any>((set: any) => ({
export const useRoomsState = create<any>((set: any) => ({
roomsState: [],
setRoomsState: (x: any) => set(() => ({ walls: x })),
setRoomsState: (x: any) => set(() => ({ roomsState: x })),
}));
export const useZones = create<any>((set: any) => ({