diff --git a/app/components/CameraOrientation.vue b/app/components/CameraOrientation.vue
index 146435f6..25f82066 100644
--- a/app/components/CameraOrientation.vue
+++ b/app/components/CameraOrientation.vue
@@ -1,6 +1,6 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/stores/hybrid_viewer.js b/app/stores/hybrid_viewer.js
index 5dc10023..bce5237f 100644
--- a/app/stores/hybrid_viewer.js
+++ b/app/stores/hybrid_viewer.js
@@ -1,15 +1,24 @@
import {
ACTOR_COLOR,
BACKGROUND_COLOR,
+ HOVER_THROTTLE_MS,
WHEEL_TIME_OUT_MS,
- applySnapshot,
computeAverageBrightness,
+ performAddItem,
+ performClearHoverHighlight,
+ performClickPicking,
+ performHoverHighlight,
+ performSetContainer,
+ performSetZScaling,
+} from "@ogw_internal/stores/hybrid_viewer";
+import {
+ applySnapshot,
getCameraOptions,
performCameraOrientation,
- performClickPicking,
performFocusCameraOnObject,
performSetCamera,
-} from "@ogw_internal/stores/hybrid_viewer";
+ performSyncRemoteCamera,
+} from "@ogw_internal/stores/hybrid_viewer_camera";
import { newInstance as vtkActor } from "@kitware/vtk.js/Rendering/Core/Actor";
import { newInstance as vtkGenericRenderWindow } from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
import { newInstance as vtkMapper } from "@kitware/vtk.js/Rendering/Core/Mapper";
@@ -30,6 +39,8 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
const status = ref(Status.NOT_CREATED);
const is_moving = ref(false);
const is_picking = ref(false);
+ const is_hover_highlight = ref(false);
+ const hover_highlight_field_type = ref("CELL");
const zScale = ref(1);
let imageStyle = undefined;
let viewStream = undefined;
@@ -83,25 +94,15 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}
async function addItem(id) {
- if (!genericRenderWindow.value) {
- return;
- }
- const reader = vtkXMLPolyDataReader();
- const value = await dataStore.item(id);
- await reader.parseAsArrayBuffer(new TextEncoder().encode(value.binary_light_viewable));
- const actor = vtkActor();
- const mapper = vtkMapper();
- const polydata = reader.getOutputData(0);
- mapper.setInputData(polydata);
- actor.getProperty().setColor(ACTOR_COLOR);
- actor.setMapper(mapper);
- const renderer = genericRenderWindow.value.getRenderer();
- const isFirst = renderer.getActors().length === 0;
- renderer.addActor(actor);
- if (isFirst) {
- renderer.resetCamera();
- }
- hybridDb[id] = { actor, polydata, mapper };
+ await performAddItem(id, {
+ genericRenderWindow: genericRenderWindow.value,
+ dataStore,
+ vtkXMLPolyDataReader,
+ vtkActor,
+ vtkMapper,
+ actorColor: ACTOR_COLOR,
+ hybridDb,
+ });
}
function removeItem(id) {
@@ -122,21 +123,14 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}
async function setZScaling(z_scale) {
- zScale.value = z_scale;
- const renderer = genericRenderWindow.value.getRenderer();
- for (const actor of renderer.getActors()) {
- if (actor !== gridActor) {
- const scale = actor.getScale();
- actor.setScale(scale[0], scale[1], z_scale);
- }
- }
- renderer.resetCamera();
- genericRenderWindow.value.getRenderWindow().render();
- const schema = viewer_schemas?.opengeodeweb_viewer?.viewer?.set_z_scaling;
- if (schema) {
- await viewerStore.request(schema, { z_scale });
- }
- remoteRender();
+ await performSetZScaling(z_scale, {
+ zScale,
+ genericRenderWindow: genericRenderWindow.value,
+ gridActor,
+ viewerStore,
+ viewer_schemas,
+ remoteRender,
+ });
}
function resetCamera() {
@@ -177,76 +171,59 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}
function syncRemoteCamera() {
- const camera = genericRenderWindow.value.getRenderer().getActiveCamera();
- const options = getCameraOptions(camera);
- viewerStore.request(
- viewer_schemas.opengeodeweb_viewer.viewer.update_camera,
- { camera_options: options },
- {
- response_function: () => {
- remoteRender();
- Object.assign(camera_options, options);
- },
- },
- );
+ performSyncRemoteCamera({
+ genericRenderWindow: genericRenderWindow.value,
+ viewerStore,
+ viewer_schemas,
+ remoteRender,
+ camera_options,
+ });
}
function remoteRender() {
return viewerStore.request(viewer_schemas.opengeodeweb_viewer.viewer.render);
}
- function setContainer(container) {
- if (!container.value) {
- return;
- }
- genericRenderWindow.value.setContainer(container.value.$el);
- const webGLRenderWindow = genericRenderWindow.value.getApiSpecificRenderWindow();
- webGLRenderWindow.setUseBackgroundImage(true);
- imageStyle = webGLRenderWindow.getReferenceByName("bgImage").style;
- Object.assign(imageStyle, { transition: "opacity 0.1s ease-in", zIndex: 1 });
- resize(container.value.$el.offsetWidth, container.value.$el.offsetHeight);
- useMousePressed({
- target: container,
- onPressed: (event) => {
- if (event.button !== 0) {
- return;
- }
- if (is_picking.value) {
- performClickPicking(event, {
- container: container.value.$el,
- viewerStore,
- viewer_schemas,
- genericRenderWindow: genericRenderWindow.value,
- syncRemoteCamera,
- });
- is_picking.value = false;
- return;
- }
- is_moving.value = true;
- event.stopPropagation();
- imageStyle.opacity = 0;
- },
- onReleased: () => {
- if (is_moving.value) {
- is_moving.value = false;
- syncRemoteCamera();
- }
- is_moving.value = false;
- genericRenderWindow.value.getRenderer().resetCameraClippingRange();
- syncRemoteCamera();
- },
+ const throttledHoverHighlight = useThrottleFn(
+ (event) =>
+ performHoverHighlight(event, {
+ is_hover_highlight,
+ genericRenderWindow: genericRenderWindow.value,
+ viewerStore,
+ viewer_schemas,
+ hover_highlight_field_type,
+ hybridDb,
+ }),
+ HOVER_THROTTLE_MS,
+ );
+
+ function clearHoverHighlight() {
+ performClearHoverHighlight({
+ viewerStore,
+ viewer_schemas,
+ hover_highlight_field_type,
+ hybridDb,
});
- useEventListener(container, "wheel", () => {
- is_moving.value = true;
- if (imageStyle) {
- imageStyle.opacity = 0;
- }
- clearTimeout(wheelEventEndTimeout);
- wheelEventEndTimeout = setTimeout(() => {
- is_moving.value = false;
- genericRenderWindow.value.getRenderer().resetCameraClippingRange();
- syncRemoteCamera();
- }, WHEEL_TIME_OUT_MS);
+ }
+
+ function setContainer(container) {
+ performSetContainer({
+ container,
+ genericRenderWindow: genericRenderWindow.value,
+ imageStyleSetter: (style) => (imageStyle = style),
+ resize,
+ useMousePressed,
+ useEventListener,
+ is_picking,
+ is_moving,
+ clickPickingCallback: performClickPicking,
+ viewerStore,
+ viewer_schemas,
+ syncRemoteCamera,
+ throttledHoverHighlight,
+ wheelTimeoutMs: WHEEL_TIME_OUT_MS,
+ wheelEventEndTimeout,
+ wheelTimeoutSetter: (timeout) => (wheelEventEndTimeout = timeout),
});
}
@@ -317,6 +294,9 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
setContainer,
zScale,
is_picking,
+ is_hover_highlight,
+ hover_highlight_field_type,
+ clearHoverHighlight,
clear,
exportStores,
importStores,
diff --git a/internal/stores/hybrid_viewer.js b/internal/stores/hybrid_viewer.js
index b84e5485..ff539e70 100644
--- a/internal/stores/hybrid_viewer.js
+++ b/internal/stores/hybrid_viewer.js
@@ -1,10 +1,4 @@
-import {
- LONG_ANIMATION_DURATION,
- SHORT_ANIMATION_DURATION,
- animateCamera,
- computeAnimationDuration,
-} from "@ogw_internal/stores/hybrid_viewer_camera_animation";
-import { dot } from "@kitware/vtk.js/Common/Core/Math";
+import { centerCameraOnPosition } from "./hybrid_viewer_camera";
const RGB_MAX = 255;
const BACKGROUND_GREY_VALUE = 180;
@@ -21,49 +15,12 @@ const ACTOR_COLOR = [
ACTOR_DARK_VALUE / RGB_MAX,
];
const WHEEL_TIME_OUT_MS = 600;
-const BUMP_MULTIPLIER = 0.2;
-const ALIGNMENT_THRESHOLD = 0.9;
-const EASE_EXPONENT = 1.1;
+const HOVER_THROTTLE_MS = 50;
const SAMPLE_SIZE = 10;
const TOTAL_CHANNELS = 400;
const RGBA_CHANNELS = 4;
-const ORIENTATIONS = {
- zplus: { position: [0, 0, 1], view_up: [0, 1, 0] },
- zminus: { position: [0, 0, -1], view_up: [0, 1, 0] },
- yplus: { position: [0, 1, 0], view_up: [0, 0, 1] },
- yminus: { position: [0, -1, 0], view_up: [0, 0, 1] },
- xplus: { position: [1, 0, 0], view_up: [0, 0, 1] },
- xminus: { position: [-1, 0, 0], view_up: [0, 0, 1] },
-};
-
-function getCameraOptions(camera) {
- if (!camera?.getFocalPoint) {
- return camera;
- }
- return {
- focal_point: [...(camera.getFocalPoint() ?? [])],
- view_up: [...(camera.getViewUp() ?? [])],
- position: [...(camera.getPosition() ?? [])],
- view_angle: camera.getViewAngle(),
- clipping_range: [...(camera.getClippingRange() ?? [])],
- distance: camera.getDistance(),
- };
-}
-
-function applyCameraOptions(camera, options) {
- if (camera?.set && options) {
- camera.set({
- focalPoint: options.focal_point,
- viewUp: options.view_up,
- position: options.position,
- viewAngle: options.view_angle,
- clippingRange: options.clipping_range,
- });
- }
-}
-
function mapRect(rect, latestImage, canvasRect) {
const scaleX = latestImage.width / canvasRect.width;
const scaleY = latestImage.height / canvasRect.height;
@@ -113,20 +70,6 @@ function computeAverageBrightness(rect, options) {
}
}
-function centerCameraOnPosition(camera, pickedPosition) {
- if (!camera || !pickedPosition) {
- return;
- }
- const focalPoint = camera.getFocalPoint();
- const position = camera.getPosition();
- camera.setFocalPoint(...pickedPosition);
- camera.setPosition(
- position[0] + pickedPosition[0] - focalPoint[0],
- position[1] + pickedPosition[1] - focalPoint[1],
- position[2] + pickedPosition[2] - focalPoint[2],
- );
-}
-
function performClickPicking(event, options) {
const { container, viewerStore, viewer_schemas, genericRenderWindow, syncRemoteCamera } = options;
const rect = container.getBoundingClientRect();
@@ -140,7 +83,8 @@ function performClickPicking(event, options) {
response_function: ({ x, y, z }) => {
const pickedPos = [x, y, z];
if (pickedPos.some((val) => val !== 0)) {
- centerCameraOnPosition(genericRenderWindow.getRenderer().getActiveCamera(), pickedPos);
+ const camera = genericRenderWindow.getRenderer().getActiveCamera();
+ centerCameraOnPosition(camera, pickedPos);
genericRenderWindow.getRenderWindow().render();
syncRemoteCamera();
}
@@ -148,131 +92,179 @@ function performClickPicking(event, options) {
},
);
}
-async function applySnapshot(snapshot, options) {
- const { genericRenderWindow, setZScaling, syncRemoteCamera, setCamera } = options;
- if (!snapshot) {
+
+function performHoverHighlight(event, options) {
+ const {
+ is_hover_highlight,
+ genericRenderWindow,
+ viewerStore,
+ viewer_schemas,
+ hover_highlight_field_type,
+ hybridDb,
+ onResponse,
+ } = options;
+ if (!is_hover_highlight.value) {
return;
}
- const z_scale = snapshot.zScale;
- if (typeof z_scale === "number") {
- await setZScaling(z_scale);
- }
- const { camera_options: snapshot_camera_options } = snapshot;
- if (snapshot_camera_options) {
- if (setCamera) {
- setCamera(snapshot_camera_options);
- } else {
- applyCameraOptions(
- genericRenderWindow.getRenderer().getActiveCamera(),
- snapshot_camera_options,
- );
- genericRenderWindow.getRenderWindow().render();
- syncRemoteCamera();
- }
+ const container = genericRenderWindow.getContainer();
+ if (!container) {
+ return;
}
+ const rect = container.getBoundingClientRect();
+ viewerStore.request(
+ viewer_schemas.opengeodeweb_viewer.viewer.hover_highlight,
+ {
+ x: Math.round(event.clientX - rect.left),
+ y: Math.round(rect.height - (event.clientY - rect.top)),
+ field_type: hover_highlight_field_type.value,
+ ids: Object.keys(hybridDb),
+ },
+ {
+ response_function: onResponse,
+ },
+ );
}
-function performSetCamera(targetCameraOptions, options) {
- const { genericRenderWindow, is_moving, imageStyle, syncRemoteCamera } = options;
- const camera = genericRenderWindow.getRenderer().getActiveCamera();
- const startState = getCameraOptions(camera);
- const duration = computeAnimationDuration(startState, targetCameraOptions);
- is_moving.value = true;
- if (imageStyle) {
- imageStyle.opacity = 0;
- }
- animateCamera({
- camera,
- startState,
- targetState: targetCameraOptions,
- duration,
- bumpMultiplier: 0,
- easeExponent: EASE_EXPONENT,
- onUpdate: () => genericRenderWindow.getRenderWindow().render(),
- onEnd: () => {
- applyCameraOptions(camera, targetCameraOptions);
- genericRenderWindow.getRenderWindow().render();
- is_moving.value = false;
- syncRemoteCamera();
- },
+function performClearHoverHighlight(options) {
+ const { viewerStore, viewer_schemas, hover_highlight_field_type, hybridDb } = options;
+ viewerStore.request(viewer_schemas.opengeodeweb_viewer.viewer.hover_highlight, {
+ x: -1,
+ y: -1,
+ field_type: hover_highlight_field_type.value,
+ ids: Object.keys(hybridDb),
});
}
-function performCameraOrientation(orientation, options) {
- const { genericRenderWindow, is_moving, imageStyle, syncRemoteCamera } = options;
- const config = ORIENTATIONS[orientation.toLowerCase()];
+async function performAddItem(id, options) {
+ const {
+ genericRenderWindow,
+ dataStore,
+ vtkXMLPolyDataReader,
+ vtkActor,
+ vtkMapper,
+ actorColor,
+ hybridDb,
+ } = options;
+ if (!genericRenderWindow) {
+ return;
+ }
+ const reader = vtkXMLPolyDataReader(),
+ value = await dataStore.item(id);
+ await reader.parseAsArrayBuffer(new TextEncoder().encode(value.binary_light_viewable));
+ const actor = vtkActor(),
+ mapper = vtkMapper(),
+ polydata = reader.getOutputData(0);
+ mapper.setInputData(polydata);
+ actor.getProperty().setColor(actorColor);
+ actor.setMapper(mapper);
const renderer = genericRenderWindow.getRenderer();
- const camera = renderer.getActiveCamera();
- const startState = getCameraOptions(camera);
+ const isFirst = renderer.getActors().length === 0;
+ renderer.addActor(actor);
+ if (isFirst) {
+ renderer.resetCamera();
+ }
+ hybridDb[id] = { actor, polydata, mapper };
+}
- applyCameraOptions(camera, {
- ...config,
- focal_point: [0, 0, 0],
- });
+async function performSetZScaling(z_scale, options) {
+ const { zScale, genericRenderWindow, gridActor, viewerStore, viewer_schemas, remoteRender } =
+ options;
+ zScale.value = z_scale;
+ const renderer = genericRenderWindow.getRenderer();
+ for (const actor of renderer.getActors()) {
+ if (actor !== gridActor) {
+ const scale = actor.getScale();
+ actor.setScale(scale[0], scale[1], z_scale);
+ }
+ }
renderer.resetCamera();
- const targetState = getCameraOptions(camera);
-
- applyCameraOptions(camera, startState);
-
- const alignment = dot(camera.getDirectionOfProjection(), config.position);
- const duration =
- alignment > ALIGNMENT_THRESHOLD ? LONG_ANIMATION_DURATION : SHORT_ANIMATION_DURATION;
- is_moving.value = true;
- imageStyle.opacity = 0;
-
- animateCamera({
- camera,
- startState,
- targetState,
- duration,
- bumpMultiplier: BUMP_MULTIPLIER,
- easeExponent: EASE_EXPONENT,
- onUpdate: () => genericRenderWindow.getRenderWindow().render(),
- onEnd: () => {
- is_moving.value = false;
- syncRemoteCamera();
- },
- });
+ genericRenderWindow.getRenderWindow().render();
+ const schema = viewer_schemas?.opengeodeweb_viewer?.viewer?.set_z_scaling;
+ if (schema) {
+ await viewerStore.request(schema, { z_scale });
+ }
+ remoteRender();
}
-async function performFocusCameraOnObject(id, options) {
+function performSetContainer(options) {
const {
- hybridDb,
- viewerStore,
- viewer_schemas,
+ container,
genericRenderWindow,
- block_ids = [],
+ imageStyleSetter,
+ resize,
+ useMousePressed,
+ useEventListener,
+ is_picking,
is_moving,
- imageStyle,
+ clickPickingCallback,
+ viewerStore,
+ viewer_schemas,
syncRemoteCamera,
+ throttledHoverHighlight,
+ wheelTimeoutMs,
+ wheelEventEndTimeout,
+ wheelTimeoutSetter,
} = options;
- if (!hybridDb[id]) {
+ if (!container.value) {
return;
}
- let bounds = [];
- if (block_ids.length > 0) {
- bounds = await viewerStore.request(viewer_schemas.opengeodeweb_viewer.model.get_blocks_bounds, {
- id,
- block_ids,
- });
- } else {
- bounds = hybridDb[id].actor.getBounds();
- }
+ genericRenderWindow.setContainer(container.value.$el);
+ const webGLRenderWindow = genericRenderWindow.getApiSpecificRenderWindow();
+ webGLRenderWindow.setUseBackgroundImage(true);
+ const imageStyle = webGLRenderWindow.getReferenceByName("bgImage").style;
+ Object.assign(imageStyle, { transition: "opacity 0.1s ease-in", zIndex: 1 });
+ imageStyleSetter(imageStyle);
- const renderer = genericRenderWindow.getRenderer();
- const camera = renderer.getActiveCamera();
- const startOptions = getCameraOptions(camera);
- renderer.resetCamera(bounds);
- const targetOptions = getCameraOptions(camera);
- applyCameraOptions(camera, startOptions);
+ resize(container.value.$el.offsetWidth, container.value.$el.offsetHeight);
- performSetCamera(targetOptions, {
- genericRenderWindow,
- is_moving,
- imageStyle,
- syncRemoteCamera,
+ useMousePressed({
+ target: container,
+ onPressed: (event) => {
+ if (event.button !== 0) {
+ return;
+ }
+ if (is_picking.value) {
+ clickPickingCallback(event, {
+ container: container.value.$el,
+ viewerStore,
+ viewer_schemas,
+ genericRenderWindow,
+ syncRemoteCamera,
+ });
+ is_picking.value = false;
+ return;
+ }
+ is_moving.value = true;
+ event.stopPropagation();
+ imageStyle.opacity = 0;
+ },
+ onReleased: () => {
+ if (is_moving.value) {
+ is_moving.value = false;
+ syncRemoteCamera();
+ }
+ is_moving.value = false;
+ genericRenderWindow.getRenderer().resetCameraClippingRange();
+ syncRemoteCamera();
+ },
+ });
+
+ useEventListener(container, "mousemove", throttledHoverHighlight);
+ useEventListener(container, "wheel", () => {
+ is_moving.value = true;
+ if (imageStyle) {
+ imageStyle.opacity = 0;
+ }
+ clearTimeout(wheelEventEndTimeout);
+ wheelTimeoutSetter(
+ setTimeout(() => {
+ is_moving.value = false;
+ genericRenderWindow.getRenderer().resetCameraClippingRange();
+ syncRemoteCamera();
+ }, wheelTimeoutMs),
+ );
});
}
@@ -280,17 +272,12 @@ export {
BACKGROUND_COLOR,
ACTOR_COLOR,
WHEEL_TIME_OUT_MS,
- BUMP_MULTIPLIER,
- ALIGNMENT_THRESHOLD,
- EASE_EXPONENT,
- ORIENTATIONS,
- applyCameraOptions,
- applySnapshot,
- centerCameraOnPosition,
+ HOVER_THROTTLE_MS,
computeAverageBrightness,
- getCameraOptions,
- performCameraOrientation,
+ performAddItem,
+ performClearHoverHighlight,
performClickPicking,
- performFocusCameraOnObject,
- performSetCamera,
+ performHoverHighlight,
+ performSetContainer,
+ performSetZScaling,
};
diff --git a/internal/stores/hybrid_viewer_camera.js b/internal/stores/hybrid_viewer_camera.js
new file mode 100644
index 00000000..f639fe54
--- /dev/null
+++ b/internal/stores/hybrid_viewer_camera.js
@@ -0,0 +1,220 @@
+import {
+ LONG_ANIMATION_DURATION,
+ SHORT_ANIMATION_DURATION,
+ animateCamera,
+ computeAnimationDuration,
+} from "@ogw_internal/stores/hybrid_viewer_camera_animation";
+import { dot } from "@kitware/vtk.js/Common/Core/Math";
+
+const BUMP_MULTIPLIER = 0.2;
+const ALIGNMENT_THRESHOLD = 0.9;
+const EASE_EXPONENT = 1.1;
+
+const ORIENTATIONS = {
+ zplus: { position: [0, 0, 1], view_up: [0, 1, 0] },
+ zminus: { position: [0, 0, -1], view_up: [0, 1, 0] },
+ yplus: { position: [0, 1, 0], view_up: [0, 0, 1] },
+ yminus: { position: [0, -1, 0], view_up: [0, 0, 1] },
+ xplus: { position: [1, 0, 0], view_up: [0, 0, 1] },
+ xminus: { position: [-1, 0, 0], view_up: [0, 0, 1] },
+};
+
+function getCameraOptions(camera) {
+ if (!camera?.getFocalPoint) {
+ return camera;
+ }
+ return {
+ focal_point: [...(camera.getFocalPoint() ?? [])],
+ view_up: [...(camera.getViewUp() ?? [])],
+ position: [...(camera.getPosition() ?? [])],
+ view_angle: camera.getViewAngle(),
+ clipping_range: [...(camera.getClippingRange() ?? [])],
+ distance: camera.getDistance(),
+ };
+}
+
+function applyCameraOptions(camera, options) {
+ if (camera?.set && options) {
+ camera.set({
+ focalPoint: options.focal_point,
+ viewUp: options.view_up,
+ position: options.position,
+ viewAngle: options.view_angle,
+ clippingRange: options.clipping_range,
+ });
+ }
+}
+
+function centerCameraOnPosition(camera, pickedPosition) {
+ if (!camera || !pickedPosition) {
+ return;
+ }
+ const focalPoint = camera.getFocalPoint();
+ const position = camera.getPosition();
+ camera.setFocalPoint(...pickedPosition);
+ camera.setPosition(
+ position[0] + pickedPosition[0] - focalPoint[0],
+ position[1] + pickedPosition[1] - focalPoint[1],
+ position[2] + pickedPosition[2] - focalPoint[2],
+ );
+}
+
+function performSetCamera(targetCameraOptions, options) {
+ const { genericRenderWindow, is_moving, imageStyle, syncRemoteCamera } = options;
+ const camera = genericRenderWindow.getRenderer().getActiveCamera();
+ const startState = getCameraOptions(camera);
+ const duration = computeAnimationDuration(startState, targetCameraOptions);
+ is_moving.value = true;
+ if (imageStyle) {
+ imageStyle.opacity = 0;
+ }
+ animateCamera({
+ camera,
+ startState,
+ targetState: targetCameraOptions,
+ duration,
+ bumpMultiplier: 0,
+ easeExponent: EASE_EXPONENT,
+ onUpdate: () => genericRenderWindow.getRenderWindow().render(),
+ onEnd: () => {
+ applyCameraOptions(camera, targetCameraOptions);
+ genericRenderWindow.getRenderWindow().render();
+ is_moving.value = false;
+ syncRemoteCamera();
+ },
+ });
+}
+
+function performCameraOrientation(orientation, options) {
+ const { genericRenderWindow, is_moving, imageStyle, syncRemoteCamera } = options;
+ const config = ORIENTATIONS[orientation.toLowerCase()];
+ const renderer = genericRenderWindow.getRenderer();
+ const camera = renderer.getActiveCamera();
+ const startState = getCameraOptions(camera);
+
+ applyCameraOptions(camera, {
+ ...config,
+ focal_point: [0, 0, 0],
+ });
+ renderer.resetCamera();
+ const targetState = getCameraOptions(camera);
+
+ applyCameraOptions(camera, startState);
+
+ const alignment = dot(camera.getDirectionOfProjection(), config.position);
+ const duration =
+ alignment > ALIGNMENT_THRESHOLD ? LONG_ANIMATION_DURATION : SHORT_ANIMATION_DURATION;
+ is_moving.value = true;
+ imageStyle.opacity = 0;
+
+ animateCamera({
+ camera,
+ startState,
+ targetState,
+ duration,
+ bumpMultiplier: BUMP_MULTIPLIER,
+ easeExponent: EASE_EXPONENT,
+ onUpdate: () => genericRenderWindow.getRenderWindow().render(),
+ onEnd: () => {
+ is_moving.value = false;
+ syncRemoteCamera();
+ },
+ });
+}
+
+async function performFocusCameraOnObject(id, options) {
+ const {
+ hybridDb,
+ viewerStore,
+ viewer_schemas,
+ genericRenderWindow,
+ block_ids = [],
+ is_moving,
+ imageStyle,
+ syncRemoteCamera,
+ } = options;
+
+ if (!hybridDb[id]) {
+ return;
+ }
+
+ let bounds = [];
+ if (block_ids.length > 0) {
+ bounds = await viewerStore.request(viewer_schemas.opengeodeweb_viewer.model.get_blocks_bounds, {
+ id,
+ block_ids,
+ });
+ } else {
+ bounds = hybridDb[id].actor.getBounds();
+ }
+
+ const renderer = genericRenderWindow.getRenderer();
+ const camera = renderer.getActiveCamera();
+ const startOptions = getCameraOptions(camera);
+ renderer.resetCamera(bounds);
+ const targetOptions = getCameraOptions(camera);
+ applyCameraOptions(camera, startOptions);
+
+ performSetCamera(targetOptions, {
+ genericRenderWindow,
+ is_moving,
+ imageStyle,
+ syncRemoteCamera,
+ });
+}
+
+function performSyncRemoteCamera(options) {
+ const { genericRenderWindow, viewerStore, viewer_schemas, remoteRender, camera_options } =
+ options;
+ const camera = genericRenderWindow.getRenderer().getActiveCamera();
+ const options_camera = getCameraOptions(camera);
+ viewerStore.request(
+ viewer_schemas.opengeodeweb_viewer.viewer.update_camera,
+ { camera_options: options_camera },
+ {
+ response_function: () => {
+ remoteRender();
+ Object.assign(camera_options, options_camera);
+ },
+ },
+ );
+}
+
+async function applySnapshot(snapshot, options) {
+ const { genericRenderWindow, setZScaling, syncRemoteCamera, setCamera } = options;
+ if (!snapshot) {
+ return;
+ }
+ const z_scale = snapshot.zScale;
+ if (typeof z_scale === "number") {
+ await setZScaling(z_scale);
+ }
+ const { camera_options: snapshot_camera_options } = snapshot;
+ if (snapshot_camera_options) {
+ if (setCamera) {
+ setCamera(snapshot_camera_options);
+ } else {
+ applyCameraOptions(
+ genericRenderWindow.getRenderer().getActiveCamera(),
+ snapshot_camera_options,
+ );
+ genericRenderWindow.getRenderWindow().render();
+ syncRemoteCamera();
+ }
+ }
+}
+
+export {
+ BUMP_MULTIPLIER,
+ ALIGNMENT_THRESHOLD,
+ EASE_EXPONENT,
+ ORIENTATIONS,
+ applyCameraOptions,
+ applySnapshot,
+ centerCameraOnPosition,
+ getCameraOptions,
+ performCameraOrientation,
+ performFocusCameraOnObject,
+ performSetCamera,
+ performSyncRemoteCamera,
+};