|
1 | | -// Third party imports |
| 1 | +import "@kitware/vtk.js/Rendering/Profiles/Geometry" |
| 2 | +import vtkGenericRenderWindow from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow" |
| 3 | +import vtkXMLPolyDataReader from "@kitware/vtk.js/IO/XML/XMLPolyDataReader" |
| 4 | +import vtkMapper from "@kitware/vtk.js/Rendering/Core/Mapper" |
| 5 | +import vtkActor from "@kitware/vtk.js/Rendering/Core/Actor" |
| 6 | + |
2 | 7 | import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json" |
| 8 | +import Status from "@ogw_f/utils/status.js" |
| 9 | + |
| 10 | +export const useHybridViewerStore = defineStore("hybridViewer", () => { |
| 11 | + const viewerStore = useViewerStore() |
| 12 | + const dataBaseStore = useDataBaseStore() |
| 13 | + const db = reactive({}) |
| 14 | + const status = ref(Status.NOT_CREATED) |
| 15 | + const camera_options = reactive({}) |
| 16 | + const genericRenderWindow = reactive({}) |
| 17 | + const is_moving = ref(false) |
| 18 | + const zScale = ref(1.0) |
| 19 | + let viewStream |
| 20 | + let gridActor = null |
| 21 | + |
| 22 | + async function initHybridViewer() { |
| 23 | + if (status.value !== Status.NOT_CREATED) return |
| 24 | + status.value = Status.CREATING |
| 25 | + genericRenderWindow.value = vtkGenericRenderWindow.newInstance({ |
| 26 | + background: [180 / 255, 180 / 255, 180 / 255], |
| 27 | + listenWindowResize: false, |
| 28 | + }) |
3 | 29 |
|
4 | | -// Local imports |
5 | | -import { useMeshPointsStyle } from "./points.js" |
6 | | -import { useMeshEdgesStyle } from "./edges.js" |
7 | | -import { useMeshPolygonsStyle } from "./polygons.js" |
8 | | -import { useMeshPolyhedraStyle } from "./polyhedra.js" |
| 30 | + const webGLRenderWindow = |
| 31 | + genericRenderWindow.value.getApiSpecificRenderWindow() |
| 32 | + const imageStyle = webGLRenderWindow.getReferenceByName("bgImage").style |
| 33 | + imageStyle.transition = "opacity 0.1s ease-in" |
| 34 | + imageStyle.zIndex = 1 |
9 | 35 |
|
10 | | -// Local constants |
11 | | -const mesh_schemas = viewer_schemas.opengeodeweb_viewer.mesh |
| 36 | + await viewerStore.ws_connect() |
| 37 | + viewStream = viewerStore.client.getImageStream().createViewStream("-1") |
| 38 | + viewStream.onImageReady((e) => { |
| 39 | + if (is_moving.value) return |
| 40 | + const webGLRenderWindow = |
| 41 | + genericRenderWindow.value.getApiSpecificRenderWindow() |
| 42 | + const imageStyle = webGLRenderWindow.getReferenceByName("bgImage").style |
| 43 | + webGLRenderWindow.setBackgroundImage(e.image) |
| 44 | + imageStyle.opacity = 1 |
| 45 | + }) |
12 | 46 |
|
13 | | -export default function useMeshStyle() { |
14 | | - const dataStyleStore = useDataStyleStore() |
15 | | - const pointsStyleStore = useMeshPointsStyle() |
16 | | - const edgesStyleStore = useMeshEdgesStyle() |
17 | | - const meshPolygonsStyleStore = useMeshPolygonsStyle() |
18 | | - const meshPolyhedraStyleStore = useMeshPolyhedraStyle() |
19 | | - const hybridViewerStore = useHybridViewerStore() |
| 47 | + status.value = Status.CREATED |
| 48 | + } |
| 49 | + |
| 50 | + async function addItem(id) { |
| 51 | + if (!genericRenderWindow.value) { |
| 52 | + return |
| 53 | + } |
| 54 | + const value = dataBaseStore.db[id] |
| 55 | + console.log("hybridViewerStore.addItem", { value }) |
| 56 | + const reader = vtkXMLPolyDataReader.newInstance() |
| 57 | + const textEncoder = new TextEncoder() |
| 58 | + await reader.parseAsArrayBuffer( |
| 59 | + textEncoder.encode(value.vtk_js.binary_light_viewable), |
| 60 | + ) |
| 61 | + const polydata = reader.getOutputData(0) |
| 62 | + const mapper = vtkMapper.newInstance() |
| 63 | + mapper.setInputData(polydata) |
| 64 | + const actor = vtkActor.newInstance() |
| 65 | + actor.getProperty().setColor(20 / 255, 20 / 255, 20 / 255) |
| 66 | + actor.setMapper(mapper) |
| 67 | + const renderer = genericRenderWindow.value.getRenderer() |
| 68 | + const renderWindow = genericRenderWindow.value.getRenderWindow() |
| 69 | + renderer.addActor(actor) |
| 70 | + renderer.resetCamera() |
| 71 | + renderWindow.render() |
| 72 | + db[id] = { actor, polydata, mapper } |
| 73 | + } |
20 | 74 |
|
21 | | - function meshVisibility(id) { |
22 | | - return dataStyleStore.getStyle(id).visibility |
| 75 | + async function setVisibility(id, visibility) { |
| 76 | + db[id].actor.setVisibility(visibility) |
| 77 | + const renderWindow = genericRenderWindow.value.getRenderWindow() |
| 78 | + renderWindow.render() |
| 79 | + } |
| 80 | + async function setZScaling(z_scale) { |
| 81 | + zScale.value = z_scale |
| 82 | + const renderer = genericRenderWindow.value.getRenderer() |
| 83 | + const actors = renderer.getActors() |
| 84 | + actors.forEach((actor) => { |
| 85 | + if (actor !== gridActor) { |
| 86 | + const scale = actor.getScale() |
| 87 | + actor.setScale(scale[0], scale[1], z_scale) |
| 88 | + } |
| 89 | + }) |
| 90 | + renderer.resetCamera() |
| 91 | + genericRenderWindow.value.getRenderWindow().render() |
| 92 | + const schema = viewer_schemas?.opengeodeweb_viewer?.viewer?.set_z_scaling |
| 93 | + if (!schema) return |
| 94 | + await viewer_call({ |
| 95 | + schema, |
| 96 | + params: { |
| 97 | + z_scale: z_scale, |
| 98 | + }, |
| 99 | + }) |
23 | 100 | } |
24 | | - function setMeshVisibility(id, visibility) { |
25 | | - return viewer_call( |
| 101 | + |
| 102 | + function syncRemoteCamera() { |
| 103 | + console.log("syncRemoteCamera") |
| 104 | + const renderer = genericRenderWindow.value.getRenderer() |
| 105 | + const camera = renderer.getActiveCamera() |
| 106 | + const params = { |
| 107 | + camera_options: { |
| 108 | + focal_point: camera.getFocalPoint(), |
| 109 | + view_up: camera.getViewUp(), |
| 110 | + position: camera.getPosition(), |
| 111 | + view_angle: camera.getViewAngle(), |
| 112 | + clipping_range: camera.getClippingRange(), |
| 113 | + distance: camera.getDistance(), |
| 114 | + }, |
| 115 | + } |
| 116 | + viewer_call( |
26 | 117 | { |
27 | | - schema: mesh_schemas.visibility, |
28 | | - params: { id, visibility }, |
| 118 | + schema: viewer_schemas.opengeodeweb_viewer.viewer.update_camera, |
| 119 | + params, |
29 | 120 | }, |
30 | 121 | { |
31 | 122 | response_function: () => { |
32 | | - hybridViewerStore.setVisibility(id, visibility) |
33 | | - dataStyleStore.getStyle(id).visibility = visibility |
34 | | - console.log(setMeshVisibility.name, { id }, meshVisibility(id)) |
| 123 | + remoteRender() |
| 124 | + for (const key in params.camera_options) { |
| 125 | + camera_options[key] = params.camera_options[key] |
| 126 | + } |
35 | 127 | }, |
36 | 128 | }, |
37 | 129 | ) |
38 | 130 | } |
39 | 131 |
|
40 | | - function applyMeshStyle(id) { |
41 | | - const style = dataStyleStore.getStyle(id) |
42 | | - console.log( |
43 | | - "[MeshStyle] applyMeshDefaultStyle for id:", |
44 | | - id, |
45 | | - "style:", |
46 | | - style, |
47 | | - ) |
48 | | - const promise_array = [] |
49 | | - for (const [key, value] of Object.entries(style)) { |
50 | | - if (key === "visibility") { |
51 | | - promise_array.push(setMeshVisibility(id, value)) |
52 | | - } else if (key === "points") { |
53 | | - promise_array.push(pointsStyleStore.applyMeshPointsStyle(id)) |
54 | | - } else if (key === "edges") { |
55 | | - promise_array.push(edgesStyleStore.applyMeshEdgesStyle(id)) |
56 | | - } else if (key === "polygons") { |
57 | | - promise_array.push(meshPolygonsStyleStore.applyMeshPolygonsStyle(id)) |
58 | | - } else if (key === "polyhedra") { |
59 | | - promise_array.push(meshPolyhedraStyleStore.applyMeshPolyhedraStyle(id)) |
60 | | - } else { |
61 | | - throw new Error("Unknown mesh key: " + key) |
62 | | - } |
| 132 | + function remoteRender() { |
| 133 | + viewer_call({ |
| 134 | + schema: viewer_schemas.opengeodeweb_viewer.viewer.render, |
| 135 | + }) |
| 136 | + } |
| 137 | + |
| 138 | + function setContainer(container) { |
| 139 | + genericRenderWindow.value.setContainer(container.value.$el) |
| 140 | + const webGLRenderWindow = |
| 141 | + genericRenderWindow.value.getApiSpecificRenderWindow() |
| 142 | + webGLRenderWindow.setUseBackgroundImage(true) |
| 143 | + const imageStyle = webGLRenderWindow.getReferenceByName("bgImage").style |
| 144 | + imageStyle.transition = "opacity 0.1s ease-in" |
| 145 | + imageStyle.zIndex = 1 |
| 146 | + resize(container.value.$el.offsetWidth, container.value.$el.offsetHeight) |
| 147 | + console.log("setContainer", container.value.$el) |
| 148 | + |
| 149 | + useMousePressed({ |
| 150 | + target: container, |
| 151 | + onPressed: (event) => { |
| 152 | + console.log("onPressed") |
| 153 | + if (event.button == 0) { |
| 154 | + is_moving.value = true |
| 155 | + event.stopPropagation() |
| 156 | + imageStyle.opacity = 0 |
| 157 | + } |
| 158 | + }, |
| 159 | + onReleased: () => { |
| 160 | + if (!is_moving.value) { |
| 161 | + return |
| 162 | + } |
| 163 | + is_moving.value = false |
| 164 | + console.log("onReleased") |
| 165 | + syncRemoteCamera() |
| 166 | + }, |
| 167 | + }) |
| 168 | + |
| 169 | + let wheelEventEndTimeout = null |
| 170 | + useEventListener(container, "wheel", () => { |
| 171 | + is_moving.value = true |
| 172 | + imageStyle.opacity = 0 |
| 173 | + clearTimeout(wheelEventEndTimeout) |
| 174 | + wheelEventEndTimeout = setTimeout(() => { |
| 175 | + is_moving.value = false |
| 176 | + syncRemoteCamera() |
| 177 | + }, 600) |
| 178 | + }) |
| 179 | + } |
| 180 | + |
| 181 | + async function resize(width, height) { |
| 182 | + if ( |
| 183 | + viewerStore.status !== Status.CONNECTED || |
| 184 | + status.value !== Status.CREATED |
| 185 | + ) { |
| 186 | + return |
63 | 187 | } |
64 | | - return Promise.all(promise_array) |
| 188 | + const webGLRenderWindow = |
| 189 | + genericRenderWindow.value.getApiSpecificRenderWindow() |
| 190 | + const canvas = webGLRenderWindow.getCanvas() |
| 191 | + canvas.width = width |
| 192 | + canvas.height = height |
| 193 | + await nextTick() |
| 194 | + webGLRenderWindow.setSize(width, height) |
| 195 | + viewStream.setSize(width, height) |
| 196 | + const renderWindow = genericRenderWindow.value.getRenderWindow() |
| 197 | + renderWindow.render() |
| 198 | + remoteRender() |
65 | 199 | } |
66 | 200 |
|
67 | 201 | return { |
68 | | - meshVisibility, |
69 | | - setMeshVisibility, |
70 | | - applyMeshStyle, |
71 | | - ...useMeshPointsStyle(), |
72 | | - ...useMeshEdgesStyle(), |
73 | | - ...useMeshPolygonsStyle(), |
74 | | - ...useMeshPolyhedraStyle(), |
| 202 | + db, |
| 203 | + genericRenderWindow, |
| 204 | + addItem, |
| 205 | + setVisibility, |
| 206 | + setZScaling, |
| 207 | + syncRemoteCamera, |
| 208 | + initHybridViewer, |
| 209 | + remoteRender, |
| 210 | + resize, |
| 211 | + setContainer, |
| 212 | + zScale, |
75 | 213 | } |
76 | | -} |
| 214 | +}) |
0 commit comments