183 lines
7.4 KiB
TypeScript
183 lines
7.4 KiB
TypeScript
import { useEffect, useMemo, useRef, useState } from "react";
|
|
import { Html } from "@react-three/drei";
|
|
import * as THREE from "three";
|
|
import {
|
|
useToggleView,
|
|
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 { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore";
|
|
|
|
const ZoneDuplicate = ({ projectId }: { projectId: string }) => {
|
|
const [zones, setZones] = useState([]);
|
|
const { setZonePoints } = useZonePoints();
|
|
const { selectedZone } = useSelectedZoneStore();
|
|
const { toggleView } = useToggleView();
|
|
|
|
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(() => {
|
|
const fetchZones = async () => {
|
|
const email = localStorage.getItem("email");
|
|
if (!email) return;
|
|
|
|
const organization = email.split("@")[1].split(".")[0];
|
|
const data = await getZonesApi(organization, projectId);
|
|
|
|
if (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);
|
|
}
|
|
};
|
|
|
|
fetchZones();
|
|
}, []);
|
|
|
|
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>
|
|
);
|
|
};
|
|
|
|
export default ZoneDuplicate;
|