init
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { DefaultCameraManager, type DMInstanceRef } from '@cognite/reveal';
|
||||
import { useReveal } from './useReveal';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { Box3, Vector3 } from 'three';
|
||||
import { use3dDataForSelectedInstance } from './use3dDataForSelectedInstance';
|
||||
import type { InstanceWithBoundingBox } from './useInstancesWithBoundingBoxes';
|
||||
|
||||
/**
|
||||
* Calculate an angled camera position for a bounding box
|
||||
* @param box - The bounding box to frame
|
||||
* @returns Camera position and target vectors
|
||||
*/
|
||||
function calculateAngledCameraPosition(box: Box3): {
|
||||
position: Vector3;
|
||||
target: Vector3;
|
||||
} {
|
||||
// Get bounding box center and size
|
||||
const center = new Vector3();
|
||||
box.getCenter(center);
|
||||
|
||||
const size = new Vector3();
|
||||
box.getSize(size);
|
||||
|
||||
// Calculate the maximum dimension to determine camera distance
|
||||
const maxDim = Math.max(size.x, size.y, size.z);
|
||||
const fov = 60; // Field of view in degrees
|
||||
const cameraDistance = (maxDim / (2 * Math.tan((fov * Math.PI) / 360))) * 1.5;
|
||||
|
||||
// Position camera at 45-degree angle (above and to the side)
|
||||
// Using spherical coordinates: 45° elevation, 45° azimuth
|
||||
const angle = Math.PI / 4; // 45 degrees
|
||||
const cameraPosition = new Vector3(
|
||||
center.x + cameraDistance * Math.cos(angle) * Math.cos(angle),
|
||||
center.y + cameraDistance * Math.sin(angle),
|
||||
center.z + cameraDistance * Math.cos(angle) * Math.sin(angle)
|
||||
);
|
||||
|
||||
return {
|
||||
position: cameraPosition,
|
||||
target: center,
|
||||
};
|
||||
}
|
||||
|
||||
const useFocusCameraWithInstanceBox = (
|
||||
instancesWithBoundingBox: InstanceWithBoundingBox[]
|
||||
) => {
|
||||
const viewer = useReveal();
|
||||
|
||||
useEffect(() => {
|
||||
if (viewer.cameraManager instanceof DefaultCameraManager) {
|
||||
viewer.cameraManager.setCameraControlsOptions({
|
||||
mouseWheelAction: 'zoomToCursor',
|
||||
});
|
||||
}
|
||||
}, [viewer.cameraManager]);
|
||||
|
||||
return useCallback(() => {
|
||||
if (instancesWithBoundingBox.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const box = instancesWithBoundingBox.reduce(
|
||||
(unionBox, instance) => unionBox.union(instance.boundingBox),
|
||||
new Box3()
|
||||
);
|
||||
|
||||
if (!box.isEmpty()) {
|
||||
const cameraState = calculateAngledCameraPosition(box);
|
||||
viewer.cameraManager.setCameraState(cameraState);
|
||||
}
|
||||
}, [instancesWithBoundingBox, viewer]);
|
||||
};
|
||||
|
||||
export const useFocusCamera = (instance: DMInstanceRef) => {
|
||||
const selectedInstanceData = use3dDataForSelectedInstance(instance);
|
||||
return useFocusCameraWithInstanceBox(
|
||||
selectedInstanceData?.instancesWithBoxes ?? []
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user