Refactor distance finding controls and move controls for improved functionality and performance
- Updated `getRoomsFromLines.ts` to filter valid line features before polygonization. - Enhanced `distanceFindingControls.tsx` to streamline measurement line updates and improve text label rendering. - Refactored `moveControls.tsx` to optimize event handling and asset movement logic, ensuring smoother interactions. - Adjusted `selectionControls.tsx` to safely parse stored floor items from local storage. - Commented out unused imports in `roboticArmInstances.tsx` for cleaner code. - Modified `polygonGenerator.tsx` to ensure only valid line features are processed for polygon generation.
This commit is contained in:
@@ -27,7 +27,12 @@ async function getRoomsFromLines(lines: Types.RefLines) {
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
|
const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
|
||||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
const validLineFeatures = lineFeatures.filter((line) => {
|
||||||
|
const coords = line.geometry.coordinates;
|
||||||
|
return coords.length >= 4;
|
||||||
|
});
|
||||||
|
|
||||||
|
const polygons = turf.polygonize(turf.featureCollection(validLineFeatures));
|
||||||
|
|
||||||
let union: any[] = [];
|
let union: any[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,253 +1,270 @@
|
|||||||
import React, { useEffect, useRef } from "react";
|
import React, { useRef } from "react";
|
||||||
import { Vector3, Raycaster, BufferGeometry, LineBasicMaterial, Line, Object3D, Mesh } from "three";
|
import {
|
||||||
|
Vector3,
|
||||||
|
Raycaster,
|
||||||
|
BufferGeometry,
|
||||||
|
LineBasicMaterial,
|
||||||
|
Line,
|
||||||
|
Mesh,
|
||||||
|
Group,
|
||||||
|
} from "three";
|
||||||
import { useThree, useFrame } from "@react-three/fiber";
|
import { useThree, useFrame } from "@react-three/fiber";
|
||||||
import { Group } from "three";
|
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
import * as THREE from "three";
|
|
||||||
|
|
||||||
interface DistanceFindingControlsProps {
|
interface DistanceFindingControlsProps {
|
||||||
boundingBoxRef: React.RefObject<Mesh>;
|
boundingBoxRef: React.RefObject<Mesh>;
|
||||||
|
object: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DistanceFindingControls = ({ boundingBoxRef }: DistanceFindingControlsProps) => {
|
const DistanceFindingControls = ({
|
||||||
const { camera, scene } = useThree();
|
boundingBoxRef,
|
||||||
|
object,
|
||||||
|
}: DistanceFindingControlsProps) => {
|
||||||
|
const { camera, scene } = useThree();
|
||||||
|
|
||||||
|
// Refs for measurement lines
|
||||||
|
const line1 = useRef<Line>(null);
|
||||||
|
const line2 = useRef<Line>(null);
|
||||||
|
const line3 = useRef<Line>(null);
|
||||||
|
const line4 = useRef<Line>(null);
|
||||||
|
const line5 = useRef<Line>(null);
|
||||||
|
|
||||||
// Refs for measurement lines
|
// Refs for measurement text labels
|
||||||
const line1 = useRef<Line>(null);
|
const textPosX = useRef<Group>(null);
|
||||||
const line2 = useRef<Line>(null);
|
const textNegX = useRef<Group>(null);
|
||||||
const line3 = useRef<Line>(null);
|
const textPosZ = useRef<Group>(null);
|
||||||
const line4 = useRef<Line>(null);
|
const textNegZ = useRef<Group>(null);
|
||||||
const line5 = useRef<Line>(null);
|
const textPosY = useRef<Group>(null);
|
||||||
|
|
||||||
// Refs for measurement text labels
|
// Store line geometries to avoid recreation
|
||||||
const textPosX = useRef<Group>(null);
|
const lineGeometries = useRef({
|
||||||
const textNegX = useRef<Group>(null);
|
posX: new BufferGeometry(),
|
||||||
const textPosZ = useRef<Group>(null);
|
negX: new BufferGeometry(),
|
||||||
const textNegZ = useRef<Group>(null);
|
posZ: new BufferGeometry(),
|
||||||
const textPosY = useRef<Group>(null);
|
negZ: new BufferGeometry(),
|
||||||
|
posY: new BufferGeometry(),
|
||||||
|
});
|
||||||
|
|
||||||
// Store line geometries to avoid recreation
|
useFrame(() => {
|
||||||
const lineGeometries = useRef({
|
if (!boundingBoxRef?.current) return;
|
||||||
posX: new BufferGeometry(),
|
|
||||||
negX: new BufferGeometry(),
|
|
||||||
posZ: new BufferGeometry(),
|
|
||||||
negZ: new BufferGeometry(),
|
|
||||||
posY: new BufferGeometry()
|
|
||||||
});
|
|
||||||
|
|
||||||
|
boundingBoxRef.current.geometry.computeBoundingBox();
|
||||||
|
const bbox = boundingBoxRef.current.geometry.boundingBox;
|
||||||
|
|
||||||
useFrame(() => {
|
if (!bbox) return;
|
||||||
if (!boundingBoxRef?.current) return;
|
|
||||||
|
|
||||||
boundingBoxRef.current.geometry.computeBoundingBox();
|
const size = {
|
||||||
const bbox = boundingBoxRef.current.geometry.boundingBox;
|
x: bbox.max.x - bbox.min.x,
|
||||||
|
y: bbox.max.y - bbox.min.y,
|
||||||
if (!bbox) return;
|
z: bbox.max.z - bbox.min.z,
|
||||||
|
|
||||||
const size = {
|
|
||||||
x: bbox.max.x - bbox.min.x,
|
|
||||||
y: bbox.max.y - bbox.min.y,
|
|
||||||
z: bbox.max.z - bbox.min.z
|
|
||||||
};
|
|
||||||
|
|
||||||
const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone();
|
|
||||||
|
|
||||||
if (!vec) return;
|
|
||||||
updateLine({
|
|
||||||
line: line1.current,
|
|
||||||
geometry: lineGeometries.current.posX,
|
|
||||||
direction: new Vector3(1, 0, 0), // Positive X
|
|
||||||
angle: 'pos',
|
|
||||||
mesh: textPosX,
|
|
||||||
vec,
|
|
||||||
size
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line2.current,
|
|
||||||
geometry: lineGeometries.current.negX,
|
|
||||||
direction: new Vector3(-1, 0, 0), // Negative X
|
|
||||||
angle: 'neg',
|
|
||||||
mesh: textNegX,
|
|
||||||
vec,
|
|
||||||
size
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line3.current,
|
|
||||||
geometry: lineGeometries.current.posZ,
|
|
||||||
direction: new Vector3(0, 0, 1), // Positive Z
|
|
||||||
angle: 'pos',
|
|
||||||
mesh: textPosZ,
|
|
||||||
vec,
|
|
||||||
size
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line4.current,
|
|
||||||
geometry: lineGeometries.current.negZ,
|
|
||||||
direction: new Vector3(0, 0, -1), // Negative Z
|
|
||||||
angle: 'neg',
|
|
||||||
mesh: textNegZ,
|
|
||||||
vec,
|
|
||||||
size
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line5.current,
|
|
||||||
geometry: lineGeometries.current.posY,
|
|
||||||
direction: new Vector3(0, -1, 0), // Down (Y)
|
|
||||||
angle: 'posY',
|
|
||||||
mesh: textPosY,
|
|
||||||
vec,
|
|
||||||
size
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateLine = ({
|
|
||||||
line,
|
|
||||||
geometry,
|
|
||||||
direction,
|
|
||||||
angle,
|
|
||||||
mesh,
|
|
||||||
vec,
|
|
||||||
size
|
|
||||||
}: {
|
|
||||||
line: Line | null,
|
|
||||||
geometry: BufferGeometry,
|
|
||||||
direction: Vector3,
|
|
||||||
angle: string,
|
|
||||||
mesh: React.RefObject<Group>,
|
|
||||||
vec: Vector3,
|
|
||||||
size: { x: number, y: number, z: number }
|
|
||||||
}) => {
|
|
||||||
if (!line) return;
|
|
||||||
|
|
||||||
const points = [];
|
|
||||||
|
|
||||||
if (angle === "pos") {
|
|
||||||
points[0] = new Vector3(vec.x, vec.y, vec.z).add(
|
|
||||||
new Vector3((direction.x * size.x) / 2, 0, (direction.z * size.z) / 2)
|
|
||||||
);
|
|
||||||
} else if (angle === "neg") {
|
|
||||||
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
|
||||||
new Vector3((-direction.x * size.x) / 2, 0, (-direction.z * size.z) / 2)
|
|
||||||
);
|
|
||||||
} else if (angle === "posY") {
|
|
||||||
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
|
||||||
new Vector3(0, size.y / 2, 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ray = new Raycaster();
|
|
||||||
if (camera) ray.camera = camera;
|
|
||||||
ray.set(new Vector3(vec.x, vec.y, vec.z), direction);
|
|
||||||
ray.params.Line.threshold = 0.1;
|
|
||||||
|
|
||||||
// Find intersection points
|
|
||||||
const wallsGroup = scene.children.find(val => val?.name.includes("Walls"));
|
|
||||||
const intersects = wallsGroup ? ray.intersectObjects([wallsGroup], true) : [];
|
|
||||||
|
|
||||||
// Find intersection point
|
|
||||||
if (intersects[0]) {
|
|
||||||
for (const intersect of intersects) {
|
|
||||||
if (intersect.object.name.includes("Wall")) {
|
|
||||||
points[1] = angle !== "posY" ? intersect.point : new Vector3(vec.x, 0, vec.z); // Floor
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update line geometry
|
|
||||||
if (points[1]) {
|
|
||||||
geometry.dispose();
|
|
||||||
geometry.setFromPoints([points[0], points[1]]);
|
|
||||||
line.geometry = geometry;
|
|
||||||
|
|
||||||
// Update measurement text
|
|
||||||
if (mesh?.current) {
|
|
||||||
geometry.computeBoundingSphere();
|
|
||||||
const center = geometry.boundingSphere?.center;
|
|
||||||
if (center) {
|
|
||||||
mesh.current.position.copy(center);
|
|
||||||
}
|
|
||||||
const label = document.getElementById(mesh.current.name);
|
|
||||||
if (label) {
|
|
||||||
label.innerText = `${points[0].distanceTo(points[1]).toFixed(2)}m`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No intersection found - clear the line
|
|
||||||
geometry.dispose();
|
|
||||||
geometry.setFromPoints([new Vector3(), new Vector3()]);
|
|
||||||
line.geometry = geometry;
|
|
||||||
const label = document.getElementById(mesh?.current?.name || "");
|
|
||||||
if (label) label.innerText = "";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Material = new LineBasicMaterial({ color: "red" });
|
const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone();
|
||||||
|
|
||||||
return (
|
if (!vec) return;
|
||||||
<>
|
updateLine({
|
||||||
{/* Measurement text labels */}
|
line: line1.current,
|
||||||
{boundingBoxRef.current && (
|
geometry: lineGeometries.current.posX,
|
||||||
<>
|
direction: new Vector3(1, 0, 0), // Positive X
|
||||||
<group name="textPosX" ref={textPosX}>
|
angle: "pos",
|
||||||
<Html zIndexRange={[1, 0]} style={{ pointerEvents: 'none' }}>
|
mesh: textPosX,
|
||||||
<div className="distance-label" id="textPosX" style={{
|
vec,
|
||||||
background: 'rgba(0,0,0,0.7)',
|
size,
|
||||||
color: 'white',
|
});
|
||||||
padding: '2px 5px',
|
updateLine({
|
||||||
borderRadius: '3px',
|
line: line2.current,
|
||||||
fontSize: '12px',
|
geometry: lineGeometries.current.negX,
|
||||||
whiteSpace: 'nowrap'
|
direction: new Vector3(-1, 0, 0), // Negative X
|
||||||
}}></div>
|
angle: "neg",
|
||||||
</Html>
|
mesh: textNegX,
|
||||||
</group>
|
vec,
|
||||||
<group name="textNegX" ref={textNegX}>
|
size,
|
||||||
<Html zIndexRange={[1, 0]} style={{ pointerEvents: 'none' }}>
|
});
|
||||||
<div className="distance-label" id="textNegX" style={{
|
updateLine({
|
||||||
background: 'rgba(0,0,0,0.7)',
|
line: line3.current,
|
||||||
color: 'white',
|
geometry: lineGeometries.current.posZ,
|
||||||
padding: '2px 5px',
|
direction: new Vector3(0, 0, 1), // Positive Z
|
||||||
borderRadius: '3px',
|
angle: "pos",
|
||||||
fontSize: '12px',
|
mesh: textPosZ,
|
||||||
whiteSpace: 'nowrap'
|
vec,
|
||||||
}}></div>
|
size,
|
||||||
</Html>
|
});
|
||||||
</group>
|
updateLine({
|
||||||
<group name="textPosZ" ref={textPosZ}>
|
line: line4.current,
|
||||||
<Html zIndexRange={[2, 0]} style={{ pointerEvents: 'none' }}>
|
geometry: lineGeometries.current.negZ,
|
||||||
<div className="distance-label" id="textPosZ" style={{
|
direction: new Vector3(0, 0, -1), // Negative Z
|
||||||
background: 'rgba(0,0,0,0.7)',
|
angle: "neg",
|
||||||
color: 'white',
|
mesh: textNegZ,
|
||||||
padding: '2px 5px',
|
vec,
|
||||||
borderRadius: '3px',
|
size,
|
||||||
fontSize: '12px',
|
});
|
||||||
whiteSpace: 'nowrap'
|
updateLine({
|
||||||
}}></div>
|
line: line5.current,
|
||||||
</Html>
|
geometry: lineGeometries.current.posY,
|
||||||
</group>
|
direction: new Vector3(0, -1, 0), // Down (Y)
|
||||||
<group name="textNegZ" ref={textNegZ}>
|
angle: "posY",
|
||||||
<Html zIndexRange={[1, 0]} style={{ pointerEvents: 'none' }}>
|
mesh: textPosY,
|
||||||
<div className="distance-label" id="textNegZ" style={{
|
vec,
|
||||||
background: 'rgba(0,0,0,0.7)',
|
size,
|
||||||
color: 'white',
|
});
|
||||||
padding: '2px 5px',
|
});
|
||||||
borderRadius: '3px',
|
|
||||||
fontSize: '12px',
|
|
||||||
whiteSpace: 'nowrap'
|
|
||||||
}}></div>
|
|
||||||
</Html>
|
|
||||||
</group>
|
|
||||||
|
|
||||||
{/* Measurement lines */}
|
const updateLine = ({
|
||||||
<primitive object={new Line(new BufferGeometry(), Material)} ref={line1} />
|
line,
|
||||||
<primitive object={new Line(new BufferGeometry(), Material)} ref={line2} />
|
geometry,
|
||||||
<primitive object={new Line(new BufferGeometry(), Material)} ref={line3} />
|
direction,
|
||||||
<primitive object={new Line(new BufferGeometry(), Material)} ref={line4} />
|
angle,
|
||||||
</>
|
mesh,
|
||||||
)}
|
vec,
|
||||||
</>
|
size,
|
||||||
|
}: {
|
||||||
|
line: Line | null;
|
||||||
|
geometry: BufferGeometry;
|
||||||
|
direction: Vector3;
|
||||||
|
angle: string;
|
||||||
|
mesh: React.RefObject<Group>;
|
||||||
|
vec: Vector3;
|
||||||
|
size: { x: number; y: number; z: number };
|
||||||
|
}) => {
|
||||||
|
if (!line) return;
|
||||||
|
|
||||||
|
const points = [];
|
||||||
|
|
||||||
|
if (angle === "pos") {
|
||||||
|
points[0] = new Vector3(vec.x, vec.y, vec.z).add(
|
||||||
|
new Vector3((direction.x * size.x) / 2, 0, (direction.z * size.z) / 2)
|
||||||
|
);
|
||||||
|
} else if (angle === "neg") {
|
||||||
|
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
||||||
|
new Vector3((-direction.x * size.x) / 2, 0, (-direction.z * size.z) / 2)
|
||||||
|
);
|
||||||
|
} else if (angle === "posY") {
|
||||||
|
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
||||||
|
new Vector3(0, size.y / 2, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ray = new Raycaster();
|
||||||
|
if (camera) ray.camera = camera;
|
||||||
|
ray.set(new Vector3(vec.x, vec.y, vec.z), direction);
|
||||||
|
ray.params.Line.threshold = 0.1;
|
||||||
|
|
||||||
|
// Find intersection points
|
||||||
|
const wallsGroup = scene.children.find((val) =>
|
||||||
|
val?.name.includes("Walls")
|
||||||
);
|
);
|
||||||
|
const intersects = wallsGroup
|
||||||
|
? ray.intersectObjects([wallsGroup], true)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// Find intersection point
|
||||||
|
if (intersects[0]) {
|
||||||
|
for (const intersect of intersects) {
|
||||||
|
if (intersect.object.name.includes("Wall")) {
|
||||||
|
points[1] =
|
||||||
|
angle !== "posY" ? intersect.point : new Vector3(vec.x, 0, vec.z); // Floor
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update line geometry
|
||||||
|
if (points[1]) {
|
||||||
|
geometry.dispose();
|
||||||
|
geometry.setFromPoints([points[0], points[1]]);
|
||||||
|
line.geometry = geometry;
|
||||||
|
|
||||||
|
// Update measurement text
|
||||||
|
if (mesh?.current) {
|
||||||
|
geometry.computeBoundingSphere();
|
||||||
|
const center = geometry.boundingSphere?.center;
|
||||||
|
if (center) {
|
||||||
|
mesh.current.position.copy(center);
|
||||||
|
}
|
||||||
|
const label = document.getElementById(mesh.current.name);
|
||||||
|
if (label) {
|
||||||
|
label.innerText = `${points[0].distanceTo(points[1]).toFixed(2)}m`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No intersection found - clear the line
|
||||||
|
geometry.dispose();
|
||||||
|
geometry.setFromPoints([new Vector3(), new Vector3()]);
|
||||||
|
line.geometry = geometry;
|
||||||
|
const label = document.getElementById(mesh?.current?.name ?? "");
|
||||||
|
if (label) label.innerText = "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Material = new LineBasicMaterial({ color: "#d2baff" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Measurement text labels */}
|
||||||
|
{boundingBoxRef.current && object > 0 && (
|
||||||
|
<>
|
||||||
|
<group name="textPosX" ref={textPosX}>
|
||||||
|
<Html
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
style={{ pointerEvents: "none" }}
|
||||||
|
>
|
||||||
|
<div className="distance-label" id="textPosX"></div>
|
||||||
|
</Html>
|
||||||
|
</group>
|
||||||
|
<group name="textNegX" ref={textNegX}>
|
||||||
|
<Html
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
style={{ pointerEvents: "none" }}
|
||||||
|
>
|
||||||
|
<div className="distance-label" id="textNegX"></div>
|
||||||
|
</Html>
|
||||||
|
</group>
|
||||||
|
<group name="textPosZ" ref={textPosZ}>
|
||||||
|
<Html
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
zIndexRange={[2, 0]}
|
||||||
|
style={{ pointerEvents: "none" }}
|
||||||
|
>
|
||||||
|
<div className="distance-label" id="textPosZ"></div>
|
||||||
|
</Html>
|
||||||
|
</group>
|
||||||
|
<group name="textNegZ" ref={textNegZ}>
|
||||||
|
<Html
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
style={{ pointerEvents: "none" }}
|
||||||
|
>
|
||||||
|
<div className="distance-label" id="textNegZ"></div>
|
||||||
|
</Html>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
{/* Measurement lines */}
|
||||||
|
<primitive
|
||||||
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
|
ref={line1}
|
||||||
|
/>
|
||||||
|
<primitive
|
||||||
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
|
ref={line2}
|
||||||
|
/>
|
||||||
|
<primitive
|
||||||
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
|
ref={line3}
|
||||||
|
/>
|
||||||
|
<primitive
|
||||||
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
|
ref={line4}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DistanceFindingControls;
|
export default DistanceFindingControls;
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSocketStore, useStartSimulation, useToggleView } from "../../../../store/store";
|
import {
|
||||||
|
useFloorItems,
|
||||||
|
useSelectedAssets,
|
||||||
|
useSocketStore,
|
||||||
|
useToggleView,
|
||||||
|
} from "../../../../store/store";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
@@ -13,307 +18,371 @@ import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertP
|
|||||||
import { snapControls } from "../../../../utils/handleSnap";
|
import { snapControls } from "../../../../utils/handleSnap";
|
||||||
import DistanceFindingControls from "./distanceFindingControls";
|
import DistanceFindingControls from "./distanceFindingControls";
|
||||||
|
|
||||||
function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) {
|
function MoveControls({
|
||||||
|
movedObjects,
|
||||||
|
setMovedObjects,
|
||||||
|
itemsGroupRef,
|
||||||
|
copiedObjects,
|
||||||
|
setCopiedObjects,
|
||||||
|
pastedObjects,
|
||||||
|
setpastedObjects,
|
||||||
|
duplicatedObjects,
|
||||||
|
setDuplicatedObjects,
|
||||||
|
selectionGroup,
|
||||||
|
rotatedObjects,
|
||||||
|
setRotatedObjects,
|
||||||
|
boundingBoxRef,
|
||||||
|
}: any) {
|
||||||
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
|
const plane = useMemo(
|
||||||
|
() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { toggleView } = useToggleView();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { toggleView } = useToggleView();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { socket } = useSocketStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const itemsData = useRef<Types.FloorItems>([]);
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const [keyEvent, setKeyEvent] = useState<
|
||||||
const { socket } = useSocketStore();
|
"Ctrl" | "Shift" | "Ctrl+Shift" | ""
|
||||||
const itemsData = useRef<Types.FloorItems>([]);
|
>("");
|
||||||
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("")
|
const email = localStorage.getItem("email");
|
||||||
const email = localStorage.getItem('email')
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
const organization = (email!.split("@")[1]).split(".")[0];
|
|
||||||
|
|
||||||
const updateBackend = (
|
|
||||||
productName: string,
|
|
||||||
productId: string,
|
|
||||||
organization: string,
|
|
||||||
eventData: EventsSchema
|
|
||||||
) => {
|
|
||||||
upsertProductOrEventApi({
|
|
||||||
productName: productName,
|
|
||||||
productId: productId,
|
|
||||||
organization: organization,
|
|
||||||
eventDatas: eventData
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
|
|
||||||
|
|
||||||
const canvasElement = gl.domElement;
|
|
||||||
canvasElement.tabIndex = 0;
|
|
||||||
|
|
||||||
let isMoving = false;
|
|
||||||
|
|
||||||
const onPointerDown = () => {
|
|
||||||
isMoving = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPointerMove = () => {
|
|
||||||
isMoving = true;
|
|
||||||
};
|
|
||||||
const onKeyUp = (event: KeyboardEvent) => {
|
|
||||||
// When any modifier is released, reset snap
|
|
||||||
const isModifierKey =
|
|
||||||
event.key === "Control" || event.key === "Shift";
|
|
||||||
|
|
||||||
if (isModifierKey) {
|
|
||||||
setKeyEvent("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
|
||||||
event.preventDefault();
|
|
||||||
placeMovedAssets();
|
|
||||||
}
|
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
clearSelection();
|
|
||||||
movedObjects.forEach((asset: any) => {
|
|
||||||
if (itemsGroupRef.current) {
|
|
||||||
itemsGroupRef.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setFloorItems([...floorItems, ...itemsData.current]);
|
|
||||||
|
|
||||||
setMovedObjects([]);
|
|
||||||
itemsData.current = [];
|
|
||||||
}
|
|
||||||
setKeyEvent("")
|
|
||||||
};
|
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
|
||||||
const keyCombination = detectModifierKeys(event);
|
|
||||||
|
|
||||||
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return;
|
|
||||||
|
|
||||||
if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
|
||||||
// update state here
|
|
||||||
setKeyEvent(keyCombination)
|
|
||||||
} else {
|
|
||||||
setKeyEvent("")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCombination === "G") {
|
|
||||||
if (selectedAssets.length > 0) {
|
|
||||||
moveAssets();
|
|
||||||
itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCombination === "ESCAPE") {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
clearSelection();
|
|
||||||
movedObjects.forEach((asset: any) => {
|
|
||||||
if (itemsGroupRef.current) {
|
|
||||||
itemsGroupRef.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setFloorItems([...floorItems, ...itemsData.current]);
|
|
||||||
|
|
||||||
setMovedObjects([]);
|
|
||||||
itemsData.current = [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!toggleView) {
|
|
||||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
|
||||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
|
||||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
|
||||||
canvasElement.addEventListener("keydown", onKeyDown);
|
|
||||||
canvasElement?.addEventListener("keyup", onKeyUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
|
||||||
canvasElement.removeEventListener("pointermove", onPointerMove);
|
|
||||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
|
||||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
|
||||||
canvasElement?.removeEventListener("keyup", onKeyUp);
|
|
||||||
};
|
|
||||||
}, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent]);
|
|
||||||
|
|
||||||
let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25;
|
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
if (movedObjects.length > 0) {
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
|
|
||||||
if (point) {
|
|
||||||
let targetX = point.x;
|
|
||||||
let targetZ = point.z;
|
|
||||||
if (keyEvent === "Ctrl") {
|
|
||||||
targetX = snapControls(targetX, "Ctrl");
|
|
||||||
targetZ = snapControls(targetZ, "Ctrl");
|
|
||||||
}
|
|
||||||
// else if (keyEvent === "Ctrl+Shift") {
|
|
||||||
// targetX = snapControls(targetX, "Ctrl+Shift");
|
|
||||||
// targetZ = snapControls(targetZ, "Ctrl+Shift");
|
|
||||||
// } else if (keyEvent === "Shift") {
|
|
||||||
// targetX = snapControls(targetX, "Shift");
|
|
||||||
// targetZ = snapControls(targetZ, "Shift");
|
|
||||||
// } else {
|
|
||||||
// }
|
|
||||||
|
|
||||||
const position = new THREE.Vector3();
|
|
||||||
|
|
||||||
if (boundingBoxRef.current) {
|
|
||||||
boundingBoxRef.current.getWorldPosition(position);
|
|
||||||
selectionGroup.current.position.lerp(
|
|
||||||
new THREE.Vector3(
|
|
||||||
targetX - (position.x - selectionGroup.current.position.x),
|
|
||||||
selectionGroup.current.position.y,
|
|
||||||
targetZ - (position.z - selectionGroup.current.position.z)
|
|
||||||
),
|
|
||||||
moveSpeed
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const box = new THREE.Box3();
|
|
||||||
movedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
|
|
||||||
const center = new THREE.Vector3();
|
|
||||||
box.getCenter(center);
|
|
||||||
|
|
||||||
selectionGroup.current.position.lerp(
|
|
||||||
new THREE.Vector3(
|
|
||||||
targetX - (center.x - selectionGroup.current.position.x),
|
|
||||||
selectionGroup.current.position.y,
|
|
||||||
targetZ - (center.z - selectionGroup.current.position.z)
|
|
||||||
),
|
|
||||||
moveSpeed
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productId: string,
|
||||||
|
organization: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productId: productId,
|
||||||
|
organization: organization,
|
||||||
|
eventDatas: eventData,
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
|
||||||
|
|
||||||
const moveAssets = () => {
|
const canvasElement = gl.domElement;
|
||||||
const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
|
canvasElement.tabIndex = 0;
|
||||||
setFloorItems(updatedItems);
|
|
||||||
setMovedObjects(selectedAssets);
|
|
||||||
selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); });
|
|
||||||
}
|
|
||||||
|
|
||||||
const placeMovedAssets = () => {
|
let isMoving = false;
|
||||||
if (movedObjects.length === 0) return;
|
|
||||||
|
|
||||||
movedObjects.forEach(async (obj: THREE.Object3D) => {
|
const onPointerDown = () => {
|
||||||
const worldPosition = new THREE.Vector3();
|
isMoving = false;
|
||||||
obj.getWorldPosition(worldPosition);
|
};
|
||||||
|
|
||||||
selectionGroup.current.remove(obj);
|
const onPointerMove = () => {
|
||||||
obj.position.copy(worldPosition);
|
isMoving = true;
|
||||||
|
};
|
||||||
|
const onKeyUp = (event: KeyboardEvent) => {
|
||||||
|
// When any modifier is released, reset snap
|
||||||
|
const isModifierKey = event.key === "Control" || event.key === "Shift";
|
||||||
|
|
||||||
if (itemsGroupRef.current) {
|
if (isModifierKey) {
|
||||||
const newFloorItem: Types.FloorItemType = {
|
setKeyEvent("");
|
||||||
modelUuid: obj.uuid,
|
}
|
||||||
modelName: obj.userData.name,
|
};
|
||||||
modelfileID: obj.userData.modelId,
|
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (obj.userData.eventData) {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid);
|
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
||||||
const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid);
|
event.preventDefault();
|
||||||
|
placeMovedAssets();
|
||||||
|
}
|
||||||
|
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
if (eventData) {
|
|
||||||
useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
|
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (productData) {
|
|
||||||
const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
|
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
|
||||||
})
|
|
||||||
|
|
||||||
if (event) {
|
|
||||||
updateBackend(
|
|
||||||
selectedProduct.productName,
|
|
||||||
selectedProduct.productId,
|
|
||||||
organization,
|
|
||||||
event
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
newFloorItem.eventData = eventData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setFloorItems((prevItems: Types.FloorItems) => {
|
|
||||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
|
||||||
return updatedItems;
|
|
||||||
});
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await setFloorItemApi(
|
|
||||||
// organization,
|
|
||||||
// obj.uuid,
|
|
||||||
// obj.userData.name,
|
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
|
||||||
// obj.userData.modelId,
|
|
||||||
// false,
|
|
||||||
// true,
|
|
||||||
// );
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
modelUuid: newFloorItem.modelUuid,
|
|
||||||
modelName: newFloorItem.modelName,
|
|
||||||
modelfileID: newFloorItem.modelfileID,
|
|
||||||
position: newFloorItem.position,
|
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
socketId: socket.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
|
||||||
|
|
||||||
itemsGroupRef.current.add(obj);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
toast.success("Object moved!");
|
|
||||||
|
|
||||||
itemsData.current = [];
|
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
movedObjects.forEach((asset: any) => {
|
||||||
|
if (itemsGroupRef.current) {
|
||||||
|
itemsGroupRef.current.attach(asset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setFloorItems([...floorItems, ...itemsData.current]);
|
||||||
|
|
||||||
const clearSelection = () => {
|
|
||||||
selectionGroup.current.children = [];
|
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
selectionGroup.current.rotation.set(0, 0, 0);
|
|
||||||
setpastedObjects([]);
|
|
||||||
setDuplicatedObjects([]);
|
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
setRotatedObjects([]);
|
itemsData.current = [];
|
||||||
setSelectedAssets([]);
|
}
|
||||||
setKeyEvent("")
|
setKeyEvent("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
|
if (
|
||||||
|
pastedObjects.length > 0 ||
|
||||||
|
duplicatedObjects.length > 0 ||
|
||||||
|
rotatedObjects.length > 0
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (
|
||||||
|
keyCombination === "Ctrl" ||
|
||||||
|
keyCombination === "Ctrl+Shift" ||
|
||||||
|
keyCombination === "Shift"
|
||||||
|
) {
|
||||||
|
// update state here
|
||||||
|
setKeyEvent(keyCombination);
|
||||||
|
} else {
|
||||||
|
setKeyEvent("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCombination === "G") {
|
||||||
|
if (selectedAssets.length > 0) {
|
||||||
|
moveAssets();
|
||||||
|
itemsData.current = floorItems.filter((item: { modelUuid: string }) =>
|
||||||
|
selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCombination === "ESCAPE") {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
clearSelection();
|
||||||
|
movedObjects.forEach((asset: any) => {
|
||||||
|
if (itemsGroupRef.current) {
|
||||||
|
itemsGroupRef.current.attach(asset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setFloorItems([...floorItems, ...itemsData.current]);
|
||||||
|
|
||||||
|
setMovedObjects([]);
|
||||||
|
itemsData.current = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!toggleView) {
|
||||||
|
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||||
|
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||||
|
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||||
|
canvasElement.addEventListener("keydown", onKeyDown);
|
||||||
|
canvasElement?.addEventListener("keyup", onKeyUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <DistanceFindingControls boundingBoxRef={boundingBoxRef} />;
|
return () => {
|
||||||
|
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
||||||
|
canvasElement.removeEventListener("pointermove", onPointerMove);
|
||||||
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||||
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||||
|
canvasElement?.removeEventListener("keyup", onKeyUp);
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
camera,
|
||||||
|
controls,
|
||||||
|
scene,
|
||||||
|
toggleView,
|
||||||
|
selectedAssets,
|
||||||
|
socket,
|
||||||
|
floorItems,
|
||||||
|
pastedObjects,
|
||||||
|
duplicatedObjects,
|
||||||
|
movedObjects,
|
||||||
|
rotatedObjects,
|
||||||
|
keyEvent,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25;
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (movedObjects.length > 0) {
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (point) {
|
||||||
|
let targetX = point.x;
|
||||||
|
let targetZ = point.z;
|
||||||
|
if (keyEvent === "Ctrl") {
|
||||||
|
targetX = snapControls(targetX, "Ctrl");
|
||||||
|
targetZ = snapControls(targetZ, "Ctrl");
|
||||||
|
}
|
||||||
|
// else if (keyEvent === "Ctrl+Shift") {
|
||||||
|
// targetX = snapControls(targetX, "Ctrl+Shift");
|
||||||
|
// targetZ = snapControls(targetZ, "Ctrl+Shift");
|
||||||
|
// } else if (keyEvent === "Shift") {
|
||||||
|
// targetX = snapControls(targetX, "Shift");
|
||||||
|
// targetZ = snapControls(targetZ, "Shift");
|
||||||
|
// } else {
|
||||||
|
// }
|
||||||
|
|
||||||
|
const position = new THREE.Vector3();
|
||||||
|
|
||||||
|
if (boundingBoxRef.current) {
|
||||||
|
boundingBoxRef.current.getWorldPosition(position);
|
||||||
|
selectionGroup.current.position.lerp(
|
||||||
|
new THREE.Vector3(
|
||||||
|
targetX - (position.x - selectionGroup.current.position.x),
|
||||||
|
selectionGroup.current.position.y,
|
||||||
|
targetZ - (position.z - selectionGroup.current.position.z)
|
||||||
|
),
|
||||||
|
moveSpeed
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const box = new THREE.Box3();
|
||||||
|
movedObjects.forEach((obj: THREE.Object3D) =>
|
||||||
|
box.expandByObject(obj)
|
||||||
|
);
|
||||||
|
const center = new THREE.Vector3();
|
||||||
|
box.getCenter(center);
|
||||||
|
|
||||||
|
selectionGroup.current.position.lerp(
|
||||||
|
new THREE.Vector3(
|
||||||
|
targetX - (center.x - selectionGroup.current.position.x),
|
||||||
|
selectionGroup.current.position.y,
|
||||||
|
targetZ - (center.z - selectionGroup.current.position.z)
|
||||||
|
),
|
||||||
|
moveSpeed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const moveAssets = () => {
|
||||||
|
const updatedItems = floorItems.filter(
|
||||||
|
(item: { modelUuid: string }) =>
|
||||||
|
!selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
|
||||||
|
);
|
||||||
|
setFloorItems(updatedItems);
|
||||||
|
setMovedObjects(selectedAssets);
|
||||||
|
selectedAssets.forEach((asset: any) => {
|
||||||
|
selectionGroup.current.attach(asset);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const placeMovedAssets = () => {
|
||||||
|
if (movedObjects.length === 0) return;
|
||||||
|
|
||||||
|
movedObjects.forEach(async (obj: THREE.Object3D) => {
|
||||||
|
const worldPosition = new THREE.Vector3();
|
||||||
|
obj.getWorldPosition(worldPosition);
|
||||||
|
|
||||||
|
selectionGroup.current.remove(obj);
|
||||||
|
obj.position.copy(worldPosition);
|
||||||
|
|
||||||
|
if (itemsGroupRef.current) {
|
||||||
|
const newFloorItem: Types.FloorItemType = {
|
||||||
|
modelUuid: obj.uuid,
|
||||||
|
modelName: obj.userData.name,
|
||||||
|
modelfileID: obj.userData.modelId,
|
||||||
|
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (obj.userData.eventData) {
|
||||||
|
const eventData = useEventsStore
|
||||||
|
.getState()
|
||||||
|
.getEventByModelUuid(obj.userData.modelUuid);
|
||||||
|
const productData = useProductStore
|
||||||
|
.getState()
|
||||||
|
.getEventByModelUuid(
|
||||||
|
useSelectedProduct.getState().selectedProduct.productId,
|
||||||
|
obj.userData.modelUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (eventData) {
|
||||||
|
useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
|
||||||
|
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (productData) {
|
||||||
|
const event = useProductStore
|
||||||
|
.getState()
|
||||||
|
.updateEvent(
|
||||||
|
useSelectedProduct.getState().selectedProduct.productId,
|
||||||
|
obj.userData.modelUuid,
|
||||||
|
{
|
||||||
|
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productId,
|
||||||
|
organization,
|
||||||
|
event
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
newFloorItem.eventData = eventData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFloorItems((prevItems: Types.FloorItems) => {
|
||||||
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
itemsGroupRef.current.add(obj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toast.success("Object moved!");
|
||||||
|
|
||||||
|
itemsData.current = [];
|
||||||
|
clearSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearSelection = () => {
|
||||||
|
selectionGroup.current.children = [];
|
||||||
|
selectionGroup.current.position.set(0, 0, 0);
|
||||||
|
selectionGroup.current.rotation.set(0, 0, 0);
|
||||||
|
setpastedObjects([]);
|
||||||
|
setDuplicatedObjects([]);
|
||||||
|
setMovedObjects([]);
|
||||||
|
setRotatedObjects([]);
|
||||||
|
setSelectedAssets([]);
|
||||||
|
setKeyEvent("");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DistanceFindingControls
|
||||||
|
boundingBoxRef={boundingBoxRef}
|
||||||
|
object={movedObjects.length}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MoveControls
|
export default MoveControls;
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ const SelectionControls: React.FC = () => {
|
|||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]");
|
const storedItems = JSON.parse(localStorage.getItem("FloorItems") ?? "[]");
|
||||||
const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
|
const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
|
||||||
|
|
||||||
const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid));
|
const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import RoboticArmInstance from "./armInstance/roboticArmInstance";
|
import RoboticArmInstance from "./armInstance/roboticArmInstance";
|
||||||
import { useArmBotStore } from "../../../../store/simulation/useArmBotStore";
|
import { useArmBotStore } from "../../../../store/simulation/useArmBotStore";
|
||||||
import RoboticArmContentUi from "../../ui3d/RoboticArmContentUi";
|
// import RoboticArmContentUi from "../../ui3d/RoboticArmContentUi";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
function RoboticArmInstances() {
|
function RoboticArmInstances() {
|
||||||
@@ -11,7 +11,7 @@ function RoboticArmInstances() {
|
|||||||
{armBots?.map((robot: ArmBotStatus) => (
|
{armBots?.map((robot: ArmBotStatus) => (
|
||||||
<React.Fragment key={robot.modelUuid}>
|
<React.Fragment key={robot.modelUuid}>
|
||||||
<RoboticArmInstance armBot={robot} />
|
<RoboticArmInstance armBot={robot} />
|
||||||
<RoboticArmContentUi roboticArm={robot} />
|
{/* <RoboticArmContentUi roboticArm={robot} /> */}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -38,7 +38,12 @@ export default function PolygonGenerator({
|
|||||||
turf.lineString(line.map((p: any) => p?.position))
|
turf.lineString(line.map((p: any) => p?.position))
|
||||||
);
|
);
|
||||||
|
|
||||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
const validLineFeatures = lineFeatures.filter((line) => {
|
||||||
|
const coords = line.geometry.coordinates;
|
||||||
|
return coords.length >= 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
const polygons = turf.polygonize(turf.featureCollection(validLineFeatures));
|
||||||
|
|
||||||
renderWallGeometry(wallPoints);
|
renderWallGeometry(wallPoints);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user