Refactor AssetBoundingBox to use cylinders for edges and improve bounding box rendering logic; update Model component to adjust line width for better visibility; enhance distanceWorker to utilize Vector3 for distance calculations.

This commit is contained in:
2025-07-28 17:21:07 +05:30
parent c224d9bb3c
commit 1231bedbb1
4 changed files with 65 additions and 46 deletions

View File

@@ -1,47 +1,67 @@
import { Line } from "@react-three/drei"; import { Box3, Vector3, Quaternion } from "three";
import { Box3, Vector3 } from "three";
import { useMemo } from "react"; import { useMemo } from "react";
import { Cylinder } from "@react-three/drei";
export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth }: { name: string; boundingBox: Box3 | null; color: string; lineWidth: number; }) => { export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth, }: { name: string; boundingBox: Box3 | null; color: string; lineWidth: number; }) => {
const { points, size, center } = useMemo(() => { const { edgeCylinders, center, size } = useMemo(() => {
if (!boundingBox) { return { points: [], center: new Vector3(), size: new Vector3(), }; } if (!boundingBox) return { edgeCylinders: [], center: new Vector3(), size: new Vector3() };
const min = boundingBox.min; const min = boundingBox.min;
const max = boundingBox.max; const max = boundingBox.max;
const center = boundingBox.getCenter(new Vector3()); const center = boundingBox.getCenter(new Vector3());
const size = boundingBox.getSize(new Vector3()); const size = boundingBox.getSize(new Vector3());
const edges: Array<[number, number, number]> = [ const corners = [
[min.x, min.y, min.z], [max.x, min.y, min.z], new Vector3(min.x, min.y, min.z),
[max.x, min.y, min.z], [max.x, max.y, min.z], new Vector3(max.x, min.y, min.z),
[max.x, max.y, min.z], [min.x, max.y, min.z], new Vector3(max.x, max.y, min.z),
[min.x, max.y, min.z], [min.x, min.y, min.z], new Vector3(min.x, max.y, min.z),
new Vector3(min.x, min.y, max.z),
[min.x, min.y, max.z], [max.x, min.y, max.z], new Vector3(max.x, min.y, max.z),
[max.x, min.y, max.z], [max.x, max.y, max.z], new Vector3(max.x, max.y, max.z),
[max.x, max.y, max.z], [min.x, max.y, max.z], new Vector3(min.x, max.y, max.z),
[min.x, max.y, max.z], [min.x, min.y, max.z],
[min.x, min.y, min.z], [min.x, min.y, max.z],
[max.x, min.y, min.z], [max.x, min.y, max.z],
[max.x, max.y, min.z], [max.x, max.y, max.z],
[min.x, max.y, min.z], [min.x, max.y, max.z],
]; ];
return { points: edges, center, size }; const edgeIndices: [number, number][] = [
}, [boundingBox]); [0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7],
];
const radius = 0.005 * lineWidth;
const edgeCylinders = edgeIndices.map(([startIdx, endIdx], i) => {
const start = corners[startIdx];
const end = corners[endIdx];
const direction = new Vector3().subVectors(end, start);
const length = direction.length();
const midPoint = new Vector3().addVectors(start, end).multiplyScalar(0.5);
const quaternion = new Quaternion().setFromUnitVectors(
new Vector3(0, 1, 0),
direction.clone().normalize()
);
return {
key: `edge-cylinder-${i}`,
position: midPoint,
rotation: quaternion,
length,
radius,
};
});
return { edgeCylinders, center, size };
}, [boundingBox, lineWidth]);
if (!boundingBox) return null; if (!boundingBox) return null;
return ( return (
<group name={name}> <group name={name}>
<Line {edgeCylinders.map(({ key, position, rotation, length, radius }) => (
segments <Cylinder key={key} args={[radius, radius, length, 6]} position={position} quaternion={rotation} >
depthWrite={false} <meshBasicMaterial color={color} depthWrite={false} />
points={points} </Cylinder>
color={color} ))}
lineWidth={lineWidth}
/>
<mesh visible={false} position={center}> <mesh visible={false} position={center}>
<boxGeometry args={[size.x, size.y, size.z]} /> <boxGeometry args={[size.x, size.y, size.z]} />

View File

@@ -21,6 +21,8 @@ import { upsertProductOrEventApi } from '../../../../../services/simulation/prod
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs'; import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
import { ModelAnimator } from './animator/modelAnimator'; import { ModelAnimator } from './animator/modelAnimator';
const distanceWorker = new Worker(new URL("../../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url));
function Model({ asset }: { readonly asset: Asset }) { function Model({ asset }: { readonly asset: Asset }) {
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
const savedTheme: string = localStorage.getItem("theme") || "light"; const savedTheme: string = localStorage.getItem("theme") || "light";
@@ -59,6 +61,7 @@ function Model({ asset }: { readonly asset: Asset }) {
const { userId, organization } = getUserData(); const { userId, organization } = getUserData();
const { projectId } = useParams(); const { projectId } = useParams();
const { selectedAssets } = useSelectedAssets(); const { selectedAssets } = useSelectedAssets();
const intervalRef = useRef<NodeJS.Timeout | null>(null);
const updateBackend = ( const updateBackend = (
productName: string, productName: string,
@@ -474,7 +477,7 @@ function Model({ asset }: { readonly asset: Asset }) {
</> </>
) : ( ) : (
<AssetBoundingBox name='Asset Fallback' boundingBox={boundingBox} color='gray' lineWidth={1} /> <AssetBoundingBox name='Asset Fallback' boundingBox={boundingBox} color='gray' lineWidth={2.5} />
)} )}
{isSelected && {isSelected &&
<AssetBoundingBox name='Asset BBox' boundingBox={boundingBox} color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"} lineWidth={2.7} /> <AssetBoundingBox name='Asset BBox' boundingBox={boundingBox} color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"} lineWidth={2.7} />

View File

@@ -164,7 +164,7 @@ function MoveControls2D({
return new THREE.Vector3().subVectors(pointPosition, hitPoint); return new THREE.Vector3().subVectors(pointPosition, hitPoint);
}, []); }, []);
const movePoints = useCallback(() => { const movePoints = (() => {
if (selectedPoints.length === 0) return; if (selectedPoints.length === 0) return;
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {}; const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
@@ -192,9 +192,9 @@ function MoveControls2D({
setMovedObjects(selectedPoints); setMovedObjects(selectedPoints);
setIsMoving(true); setIsMoving(true);
}, [selectedPoints, camera, pointer, plane, raycaster, calculateDragOffset]); });
const resetToInitialPositions = useCallback(() => { const resetToInitialPositions = () => {
setTimeout(() => { setTimeout(() => {
movedObjects.forEach((movedPoint: THREE.Object3D) => { movedObjects.forEach((movedPoint: THREE.Object3D) => {
if (movedPoint.userData.pointUuid && initialStates[movedPoint.uuid]) { if (movedPoint.userData.pointUuid && initialStates[movedPoint.uuid]) {
@@ -218,7 +218,7 @@ function MoveControls2D({
} }
}); });
}, 0) }, 0)
}, [movedObjects, initialStates, setAislePosition, setWallPosition, setFloorPosition, setZonePosition]); };
const placeMovedAssets = () => { const placeMovedAssets = () => {
if (movedObjects.length === 0) return; if (movedObjects.length === 0) return;

View File

@@ -1,21 +1,17 @@
import { Vector3 } from "three";
onmessage = function (e) { onmessage = function (e) {
const { assetPosition, cameraPosition, limitDistance, renderDistance, isRendered } = e.data; const { modelUuid, assetPosition, cameraPosition, limitDistance, renderDistance, isRendered } = e.data;
if (limitDistance && assetPosition) { if (limitDistance && assetPosition) {
const distance = Math.sqrt( if (!isRendered && new Vector3(assetPosition.x, assetPosition.y, assetPosition.z).distanceTo(cameraPosition) <= renderDistance) {
Math.pow(assetPosition.x - cameraPosition.x, 2) + postMessage({ shouldRender: true, modelUuid });
Math.pow(assetPosition.y - cameraPosition.y, 2) + } else if (isRendered && new Vector3(assetPosition.x, assetPosition.y, assetPosition.z).distanceTo(cameraPosition) > renderDistance) {
Math.pow(assetPosition.z - cameraPosition.z, 2) postMessage({ shouldRender: false, modelUuid });
);
if (!isRendered && distance <= renderDistance) {
postMessage({ shouldRender: true });
} else if (isRendered && distance > renderDistance) {
postMessage({ shouldRender: false });
} }
} else { } else {
if (!isRendered) { if (!isRendered) {
postMessage({ shouldRender: true }); postMessage({ shouldRender: true, modelUuid });
} }
} }
}; };