Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/components/CameraOrientation.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import ToolPanel from "@ogw_front/components/ToolPanel";
import { applyCameraOptions } from "@ogw_front/utils/hybrid_viewer";
import { applyCameraOptions } from "@ogw_internal/stores/hybrid_viewer";
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
import { newInstance as vtkAnnotatedCubeActor } from "@kitware/vtk.js/Rendering/Core/AnnotatedCubeActor";
import { newInstance as vtkGenericRenderWindow } from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
Expand Down
7 changes: 7 additions & 0 deletions app/components/ViewToolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ const camera_options = [
hybridViewerStore.resetCamera();
},
},
{
tooltip: "Center on click",
icon: "mdi-crosshairs-question",
action: () => {
hybridViewerStore.is_picking = !hybridViewerStore.is_picking;
},
},
{
tooltip: "Camera orientation",
icon: "mdi-rotate-3d",
Expand Down
118 changes: 54 additions & 64 deletions app/stores/hybrid_viewer.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,3 @@
import {
ORIENTATIONS,
animateCamera,
applyCameraOptions,
computeAverageBrightness,
getCameraOptions,
} from "@ogw_front/utils/hybrid_viewer";
import { dot } from "@kitware/vtk.js/Common/Core/Math";
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";
import { newInstance as vtkXMLPolyDataReader } from "@kitware/vtk.js/IO/XML/XMLPolyDataReader";

import {
ACTOR_COLOR,
ALIGNMENT_THRESHOLD,
Expand All @@ -20,7 +7,17 @@ import {
LONG_ANIMATION_DURATION,
SHORT_ANIMATION_DURATION,
WHEEL_TIME_OUT_MS,
} from "@ogw_front/utils/vtk/constants";
applySnapshot,
computeAverageBrightness,
getCameraOptions,
performCameraOrientation,
performClickPicking,
} from "@ogw_internal/stores/hybrid_viewer";
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";
import { newInstance as vtkXMLPolyDataReader } from "@kitware/vtk.js/IO/XML/XMLPolyDataReader";

import { Status } from "@ogw_front/utils/status";
import { useDataStore } from "@ogw_front/stores/data";
import { useViewerStore } from "@ogw_front/stores/viewer";
Expand All @@ -35,11 +32,21 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
const camera_options = reactive({});
const genericRenderWindow = reactive({});
const is_moving = ref(false);
const is_picking = ref(false);
const zScale = ref(1);
let viewStream = undefined;
let imageStyle = undefined;
const gridActor = undefined;

watch(is_picking, (value) => {
const element = genericRenderWindow.value
?.getApiSpecificRenderWindow()
?.getCanvas()?.parentElement;
if (element) {
element.style.cursor = value ? "crosshair" : "default";
}
});

const latestImage = ref(undefined);
const offscreenCanvas =
typeof document === "undefined" ? undefined : document.createElement("canvas");
Expand Down Expand Up @@ -153,37 +160,17 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}

function setCameraOrientation(orientation) {
const config = ORIENTATIONS[orientation.toLowerCase()];
const renderer = genericRenderWindow.value.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.value.getRenderWindow().render(),
onEnd: () => {
is_moving.value = false;
syncRemoteCamera();
performCameraOrientation(orientation, {
genericRenderWindow: genericRenderWindow.value,
is_moving,
imageStyle,
syncRemoteCamera,
constants: {
ALIGNMENT_THRESHOLD,
BUMP_MULTIPLIER,
EASE_EXPONENT,
LONG_ANIMATION_DURATION,
SHORT_ANIMATION_DURATION,
},
});
}
Expand Down Expand Up @@ -219,11 +206,23 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
useMousePressed({
target: container,
onPressed: (event) => {
if (event.button === 0) {
is_moving.value = true;
event.stopPropagation();
imageStyle.opacity = 0;
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;
}
Comment on lines +212 to 222
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logique pour center on click

is_moving.value = true;
event.stopPropagation();
imageStyle.opacity = 0;
},
onReleased: () => {
if (!is_moving.value) {
Expand Down Expand Up @@ -279,21 +278,11 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}

async function importStores(snapshot) {
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) {
const renderer = genericRenderWindow.value.getRenderer();
applyCameraOptions(renderer.getActiveCamera(), snapshot_camera_options);
genericRenderWindow.value.getRenderWindow().render();
syncRemoteCamera();
}
await applySnapshot(snapshot, {
genericRenderWindow: genericRenderWindow.value,
setZScaling,
syncRemoteCamera,
});
}

function clear() {
Expand Down Expand Up @@ -323,6 +312,7 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
setCameraOrientation,
setContainer,
zScale,
is_picking,
clear,
exportStores,
importStores,
Expand Down
31 changes: 0 additions & 31 deletions app/utils/vtk/constants.js

This file was deleted.

129 changes: 128 additions & 1 deletion app/utils/hybrid_viewer.js → internal/stores/hybrid_viewer.js
Comment thread
MaxNumerique marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
import { SHORT_ANIMATION_DURATION } from "@ogw_front/utils/vtk/constants";
import { dot } from "@kitware/vtk.js/Common/Core/Math";

const RGB_MAX = 255;
const BACKGROUND_GREY_VALUE = 180;
const ACTOR_DARK_VALUE = 20;

const BACKGROUND_COLOR = [
BACKGROUND_GREY_VALUE / RGB_MAX,
BACKGROUND_GREY_VALUE / RGB_MAX,
BACKGROUND_GREY_VALUE / RGB_MAX,
];
const ACTOR_COLOR = [
ACTOR_DARK_VALUE / RGB_MAX,
ACTOR_DARK_VALUE / RGB_MAX,
ACTOR_DARK_VALUE / RGB_MAX,
];
const WHEEL_TIME_OUT_MS = 600;
const BUMP_MULTIPLIER = 0.2;
const ALIGNMENT_THRESHOLD = 0.9;
const LONG_ANIMATION_DURATION = 1000;
const SHORT_ANIMATION_DURATION = 500;
const EASE_EXPONENT = 1.1;

const SAMPLE_SIZE = 10;
const TOTAL_CHANNELS = 400;
const RGBA_CHANNELS = 4;
Expand Down Expand Up @@ -95,6 +115,42 @@ 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();
viewerStore.request(
viewer_schemas.opengeodeweb_viewer.viewer.get_point_position,
{
x: Math.round(event.clientX - rect.left),
y: Math.round(rect.height - (event.clientY - rect.top)),
},
{
response_function: ({ x, y, z }) => {
const pickedPos = [x, y, z];
if (pickedPos.some((val) => val !== 0)) {
centerCameraOnPosition(genericRenderWindow.getRenderer().getActiveCamera(), pickedPos);
genericRenderWindow.getRenderWindow().render();
syncRemoteCamera();
}
},
},
);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logique pour center on click

function animateCamera(options) {
const {
camera,
Expand Down Expand Up @@ -140,10 +196,81 @@ function animateCamera(options) {
requestAnimationFrame(animate);
}

async function applySnapshot(snapshot, options) {
const { genericRenderWindow, setZScaling, syncRemoteCamera } = 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) {
applyCameraOptions(
genericRenderWindow.getRenderer().getActiveCamera(),
snapshot_camera_options,
);
genericRenderWindow.getRenderWindow().render();
syncRemoteCamera();
}
}

function performCameraOrientation(orientation, options) {
const { genericRenderWindow, is_moving, imageStyle, syncRemoteCamera, constants } = 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 > constants.ALIGNMENT_THRESHOLD
? constants.LONG_ANIMATION_DURATION
: constants.SHORT_ANIMATION_DURATION;
is_moving.value = true;
imageStyle.opacity = 0;

animateCamera({
camera,
startState,
targetState,
duration,
bumpMultiplier: constants.BUMP_MULTIPLIER,
easeExponent: constants.EASE_EXPONENT,
onUpdate: () => genericRenderWindow.getRenderWindow().render(),
onEnd: () => {
is_moving.value = false;
syncRemoteCamera();
},
});
}

export {
BACKGROUND_COLOR,
ACTOR_COLOR,
WHEEL_TIME_OUT_MS,
BUMP_MULTIPLIER,
ALIGNMENT_THRESHOLD,
LONG_ANIMATION_DURATION,
SHORT_ANIMATION_DURATION,
EASE_EXPONENT,
ORIENTATIONS,
animateCamera,
applyCameraOptions,
applySnapshot,
centerCameraOnPosition,
computeAverageBrightness,
getCameraOptions,
performCameraOrientation,
performClickPicking,
};
Loading