@geode/opengeodeweb-front 10.14.1 → 10.14.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,17 @@
1
- // oxlint-disable-next-line import/no-unassigned-import
2
- import "@kitware/vtk.js/Rendering/Profiles/Geometry";
1
+ import {
2
+ applyCameraOptions,
3
+ computeAverageBrightness,
4
+ getCameraOptions,
5
+ } from "@ogw_front/utils/hybrid_viewer";
3
6
  import { newInstance as vtkActor } from "@kitware/vtk.js/Rendering/Core/Actor";
4
7
  import { newInstance as vtkGenericRenderWindow } from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
5
8
  import { newInstance as vtkMapper } from "@kitware/vtk.js/Rendering/Core/Mapper";
6
9
  import { newInstance as vtkXMLPolyDataReader } from "@kitware/vtk.js/IO/XML/XMLPolyDataReader";
7
10
 
8
- import { Status } from "@ogw_front/utils/status";
9
11
  import { useDataStore } from "@ogw_front/stores/data";
10
12
  import { useViewerStore } from "@ogw_front/stores/viewer";
13
+
14
+ import { Status } from "@ogw_front/utils/status";
11
15
  import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
12
16
 
13
17
  const RGB_MAX = 255;
@@ -37,6 +41,13 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
37
41
  let viewStream = undefined;
38
42
  const gridActor = undefined;
39
43
 
44
+ const latestImage = ref(undefined);
45
+ const offscreenCanvas =
46
+ typeof document === "undefined" ? undefined : document.createElement("canvas");
47
+ const offscreenCtx = offscreenCanvas
48
+ ? offscreenCanvas.getContext("2d", { willReadFrequently: true })
49
+ : undefined;
50
+
40
51
  async function initHybridViewer() {
41
52
  if (status.value !== Status.NOT_CREATED) {
42
53
  return;
@@ -58,6 +69,7 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
58
69
  if (is_moving.value) {
59
70
  return;
60
71
  }
72
+ latestImage.value = event.image;
61
73
  webGLRenderWindow.setBackgroundImage(event.image);
62
74
  imageStyle.opacity = 1;
63
75
  });
@@ -136,18 +148,10 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
136
148
  }
137
149
 
138
150
  function syncRemoteCamera() {
139
- console.log("syncRemoteCamera");
140
151
  const renderer = genericRenderWindow.value.getRenderer();
141
152
  const camera = renderer.getActiveCamera();
142
153
  const params = {
143
- camera_options: {
144
- focal_point: [...camera.getFocalPoint()],
145
- view_up: [...camera.getViewUp()],
146
- position: [...camera.getPosition()],
147
- view_angle: camera.getViewAngle(),
148
- clipping_range: [...camera.getClippingRange()],
149
- distance: camera.getDistance(),
150
- },
154
+ camera_options: getCameraOptions(camera),
151
155
  };
152
156
  viewerStore.request(viewer_schemas.opengeodeweb_viewer.viewer.update_camera, params, {
153
157
  response_function: () => {
@@ -173,12 +177,10 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
173
177
  imageStyle.transition = "opacity 0.1s ease-in";
174
178
  imageStyle.zIndex = 1;
175
179
  resize(container.value.$el.offsetWidth, container.value.$el.offsetHeight);
176
- console.log("setContainer", container.value.$el);
177
180
 
178
181
  useMousePressed({
179
182
  target: container,
180
183
  onPressed: (event) => {
181
- console.log("onPressed");
182
184
  if (event.button === 0) {
183
185
  is_moving.value = true;
184
186
  event.stopPropagation();
@@ -190,7 +192,6 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
190
192
  return;
191
193
  }
192
194
  is_moving.value = false;
193
- console.log("onReleased");
194
195
  syncRemoteCamera();
195
196
  },
196
197
  });
@@ -223,25 +224,24 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
223
224
  remoteRender();
224
225
  }
225
226
 
227
+ function getAverageBrightness(rect) {
228
+ return computeAverageBrightness(rect, {
229
+ latestImage: latestImage.value,
230
+ offscreenCtx,
231
+ offscreenCanvas,
232
+ genericRenderWindow: genericRenderWindow.value,
233
+ });
234
+ }
235
+
226
236
  function exportStores() {
227
237
  const renderer = genericRenderWindow.value.getRenderer();
228
238
  const camera = renderer.getActiveCamera();
229
- const cameraSnapshot = camera
230
- ? {
231
- focal_point: [...camera.getFocalPoint()],
232
- view_up: [...camera.getViewUp()],
233
- position: [...camera.getPosition()],
234
- view_angle: camera.getViewAngle(),
235
- clipping_range: [...camera.getClippingRange()],
236
- distance: camera.getDistance(),
237
- }
238
- : camera_options;
239
+ const cameraSnapshot = getCameraOptions(camera) || camera_options;
239
240
  return { zScale: zScale.value, camera_options: cameraSnapshot };
240
241
  }
241
242
 
242
243
  async function importStores(snapshot) {
243
244
  if (!snapshot) {
244
- console.warn("importStores called with undefined snapshot");
245
245
  return;
246
246
  }
247
247
  const z_scale = snapshot.zScale;
@@ -255,22 +255,12 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
255
255
  const renderer = genericRenderWindow.value.getRenderer();
256
256
  const camera = renderer.getActiveCamera();
257
257
 
258
- camera.setFocalPoint(...snapshot_camera_options.focal_point);
259
- camera.setViewUp(...snapshot_camera_options.view_up);
260
- camera.setPosition(...snapshot_camera_options.position);
261
- camera.setViewAngle(snapshot_camera_options.view_angle);
262
- camera.setClippingRange(...snapshot_camera_options.clipping_range);
258
+ applyCameraOptions(camera, snapshot_camera_options);
263
259
 
264
260
  genericRenderWindow.value.getRenderWindow().render();
265
261
 
266
262
  const payload = {
267
- camera_options: {
268
- focal_point: [...snapshot_camera_options.focal_point],
269
- view_up: [...snapshot_camera_options.view_up],
270
- position: [...snapshot_camera_options.position],
271
- view_angle: snapshot_camera_options.view_angle,
272
- clipping_range: [...snapshot_camera_options.clipping_range],
273
- },
263
+ camera_options: getCameraOptions(snapshot_camera_options),
274
264
  };
275
265
  return viewerStore.request(viewer_schemas.opengeodeweb_viewer.viewer.update_camera, payload, {
276
266
  response_function: () => {
@@ -316,5 +306,7 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
316
306
  clear,
317
307
  exportStores,
318
308
  importStores,
309
+ latestImage,
310
+ getAverageBrightness,
319
311
  };
320
312
  });
@@ -0,0 +1,101 @@
1
+ const RGB_MAX = 255;
2
+ const BACKGROUND_GREY_VALUE = 180;
3
+ const SAMPLE_SIZE = 10;
4
+ const TOTAL_CHANNELS = 400;
5
+ const RGBA_CHANNELS = 4;
6
+
7
+ function getCameraOptions(camera) {
8
+ if (!camera) {
9
+ return undefined;
10
+ }
11
+
12
+ if (typeof camera.getFocalPoint !== "function") {
13
+ return { ...camera };
14
+ }
15
+ return {
16
+ focal_point: [...camera.getFocalPoint()],
17
+ view_up: [...camera.getViewUp()],
18
+ position: [...camera.getPosition()],
19
+ view_angle: camera.getViewAngle(),
20
+ clipping_range: [...camera.getClippingRange()],
21
+ distance: camera.getDistance(),
22
+ };
23
+ }
24
+
25
+ function applyCameraOptions(camera, options) {
26
+ if (!camera || !options) {
27
+ return;
28
+ }
29
+ if (options.focal_point) {
30
+ camera.setFocalPoint(...options.focal_point);
31
+ }
32
+ if (options.view_up) {
33
+ camera.setViewUp(...options.view_up);
34
+ }
35
+ if (options.position) {
36
+ camera.setPosition(...options.position);
37
+ }
38
+ if (options.view_angle) {
39
+ camera.setViewAngle(options.view_angle);
40
+ }
41
+ if (options.clipping_range) {
42
+ camera.setClippingRange(...options.clipping_range);
43
+ }
44
+ }
45
+
46
+ function mapRect(rect, latestImage, canvasRect) {
47
+ const scaleX = latestImage.width / canvasRect.width;
48
+ const scaleY = latestImage.height / canvasRect.height;
49
+ return {
50
+ relX: (rect.x - canvasRect.left) * scaleX,
51
+ relY: (rect.y - canvasRect.top) * scaleY,
52
+ relW: rect.width * scaleX,
53
+ relH: rect.height * scaleY,
54
+ };
55
+ }
56
+
57
+ function computeAverageBrightness(rect, options) {
58
+ const { latestImage, offscreenCtx, offscreenCanvas, genericRenderWindow } = options;
59
+ if (!latestImage || !offscreenCtx || !offscreenCanvas || !genericRenderWindow) {
60
+ return BACKGROUND_GREY_VALUE / RGB_MAX;
61
+ }
62
+
63
+ const canvas = genericRenderWindow.getApiSpecificRenderWindow().getCanvas();
64
+ if (!canvas) {
65
+ return BACKGROUND_GREY_VALUE / RGB_MAX;
66
+ }
67
+
68
+ const { relX, relY, relW, relH } = mapRect(rect, latestImage, canvas.getBoundingClientRect());
69
+
70
+ offscreenCanvas.width = SAMPLE_SIZE;
71
+ offscreenCanvas.height = SAMPLE_SIZE;
72
+
73
+ try {
74
+ offscreenCtx.drawImage(
75
+ latestImage,
76
+ Math.max(0, relX),
77
+ Math.max(0, relY),
78
+ Math.min(latestImage.width, relW),
79
+ Math.min(latestImage.height, relH),
80
+ 0,
81
+ 0,
82
+ SAMPLE_SIZE,
83
+ SAMPLE_SIZE,
84
+ );
85
+ const { data } = offscreenCtx.getImageData(0, 0, SAMPLE_SIZE, SAMPLE_SIZE);
86
+
87
+ let minBrightness = 1;
88
+ for (let i = 0; i < TOTAL_CHANNELS; i += RGBA_CHANNELS) {
89
+ const brightness = (data[i] + data[i + 1] + data[i + 2]) / (3 * RGB_MAX);
90
+ if (brightness < minBrightness) {
91
+ minBrightness = brightness;
92
+ }
93
+ }
94
+
95
+ return minBrightness;
96
+ } catch {
97
+ return BACKGROUND_GREY_VALUE / RGB_MAX;
98
+ }
99
+ }
100
+
101
+ export { applyCameraOptions, computeAverageBrightness, getCameraOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geode/opengeodeweb-front",
3
- "version": "10.14.1",
3
+ "version": "10.14.2-rc.1",
4
4
  "description": "OpenSource Vue/Nuxt/Pinia/Vuetify framework for web applications",
5
5
  "homepage": "https://github.com/Geode-solutions/OpenGeodeWeb-Front",
6
6
  "bugs": {
@@ -34,8 +34,8 @@
34
34
  "build": ""
35
35
  },
36
36
  "dependencies": {
37
- "@geode/opengeodeweb-back": "latest",
38
- "@geode/opengeodeweb-viewer": "latest",
37
+ "@geode/opengeodeweb-back": "next",
38
+ "@geode/opengeodeweb-viewer": "next",
39
39
  "@google-cloud/run": "3.2.0",
40
40
  "@kitware/vtk.js": "33.3.0",
41
41
  "@mdi/font": "7.4.47",
@@ -1,48 +0,0 @@
1
- import { useViewerStore } from "@ogw_front/stores/viewer";
2
- import vtk_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
3
-
4
- const HOVER_DELAY = 1000;
5
-
6
- export function useHoverhighlight() {
7
- const viewerStore = useViewerStore();
8
- let timer = undefined;
9
- let currentId = undefined;
10
- let currentType = undefined;
11
-
12
- function onHoverEnter(id, block_ids = [], type = "model") {
13
- if (timer) {
14
- clearTimeout(timer);
15
- }
16
- const schema = vtk_schemas.opengeodeweb_viewer[type].highlight;
17
- timer = setTimeout(async () => {
18
- currentId = id;
19
- currentType = type;
20
- const params = {
21
- id,
22
- visibility: true,
23
- ...(type === "model" && { block_ids }),
24
- };
25
- await viewerStore.request(schema, params);
26
- }, HOVER_DELAY);
27
- }
28
-
29
- function onHoverLeave(id) {
30
- if (timer) {
31
- clearTimeout(timer);
32
- timer = undefined;
33
- }
34
- if (currentId === id) {
35
- const schema = vtk_schemas.opengeodeweb_viewer[currentType].highlight;
36
- const params = {
37
- id,
38
- visibility: false,
39
- ...(currentType === "model" && { block_ids: [] }),
40
- };
41
- viewerStore.request(schema, params);
42
- currentId = undefined;
43
- currentType = undefined;
44
- }
45
- }
46
-
47
- return { onHoverEnter, onHoverLeave };
48
- }