itowns 2.44.3-next.40 → 2.44.3-next.42

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.
Files changed (199) hide show
  1. package/README.md +3 -129
  2. package/package.json +16 -72
  3. package/CODING.md +0 -120
  4. package/CONTRIBUTING.md +0 -150
  5. package/CONTRIBUTORS.md +0 -56
  6. package/LICENSE.md +0 -44
  7. package/changelog.md +0 -1361
  8. package/dist/455.js +0 -2
  9. package/dist/455.js.map +0 -1
  10. package/dist/debug.js +0 -3
  11. package/dist/debug.js.LICENSE.txt +0 -13
  12. package/dist/debug.js.map +0 -1
  13. package/dist/itowns.js +0 -3
  14. package/dist/itowns.js.LICENSE.txt +0 -5
  15. package/dist/itowns.js.map +0 -1
  16. package/dist/itowns_lasparser.js +0 -2
  17. package/dist/itowns_lasparser.js.map +0 -1
  18. package/dist/itowns_lasworker.js +0 -2
  19. package/dist/itowns_lasworker.js.map +0 -1
  20. package/dist/itowns_potree2worker.js +0 -2
  21. package/dist/itowns_potree2worker.js.map +0 -1
  22. package/dist/itowns_widgets.js +0 -2
  23. package/dist/itowns_widgets.js.map +0 -1
  24. package/examples/.eslintrc.cjs +0 -35
  25. package/examples/jsm/.eslintrc.cjs +0 -38
  26. package/lib/Controls/FirstPersonControls.js +0 -308
  27. package/lib/Controls/FlyControls.js +0 -175
  28. package/lib/Controls/GlobeControls.js +0 -1179
  29. package/lib/Controls/PlanarControls.js +0 -1025
  30. package/lib/Controls/StateControl.js +0 -432
  31. package/lib/Controls/StreetControls.js +0 -392
  32. package/lib/Converter/Feature2Mesh.js +0 -614
  33. package/lib/Converter/Feature2Texture.js +0 -175
  34. package/lib/Converter/convertToTile.js +0 -70
  35. package/lib/Converter/textureConverter.js +0 -43
  36. package/lib/Core/3DTiles/C3DTBatchTable.js +0 -131
  37. package/lib/Core/3DTiles/C3DTBatchTableHierarchyExtension.js +0 -96
  38. package/lib/Core/3DTiles/C3DTBoundingVolume.js +0 -157
  39. package/lib/Core/3DTiles/C3DTExtensions.js +0 -97
  40. package/lib/Core/3DTiles/C3DTFeature.js +0 -110
  41. package/lib/Core/3DTiles/C3DTilesEnums.js +0 -20
  42. package/lib/Core/3DTiles/C3DTileset.js +0 -99
  43. package/lib/Core/3DTiles/utils/BinaryPropertyAccessor.js +0 -100
  44. package/lib/Core/AnimationPlayer.js +0 -142
  45. package/lib/Core/CopcNode.js +0 -174
  46. package/lib/Core/Deprecated/Undeprecator.js +0 -74
  47. package/lib/Core/EntwinePointTileNode.js +0 -126
  48. package/lib/Core/Feature.js +0 -489
  49. package/lib/Core/Geographic/CoordStars.js +0 -80
  50. package/lib/Core/Geographic/Coordinates.js +0 -331
  51. package/lib/Core/Geographic/Crs.js +0 -170
  52. package/lib/Core/Geographic/Extent.js +0 -550
  53. package/lib/Core/Geographic/GeoidGrid.js +0 -109
  54. package/lib/Core/Label.js +0 -222
  55. package/lib/Core/MainLoop.js +0 -209
  56. package/lib/Core/Math/Ellipsoid.js +0 -185
  57. package/lib/Core/Picking.js +0 -255
  58. package/lib/Core/PointCloudNode.js +0 -42
  59. package/lib/Core/Potree2Node.js +0 -206
  60. package/lib/Core/Potree2PointAttributes.js +0 -139
  61. package/lib/Core/PotreeNode.js +0 -101
  62. package/lib/Core/Prefab/Globe/Atmosphere.js +0 -295
  63. package/lib/Core/Prefab/Globe/GlobeLayer.js +0 -152
  64. package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +0 -111
  65. package/lib/Core/Prefab/Globe/SkyShader.js +0 -78
  66. package/lib/Core/Prefab/GlobeView.js +0 -156
  67. package/lib/Core/Prefab/Planar/PlanarLayer.js +0 -59
  68. package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +0 -72
  69. package/lib/Core/Prefab/PlanarView.js +0 -62
  70. package/lib/Core/Prefab/TileBuilder.js +0 -82
  71. package/lib/Core/Prefab/computeBufferTileGeometry.js +0 -248
  72. package/lib/Core/Scheduler/Cache.js +0 -17
  73. package/lib/Core/Scheduler/CancelledCommandException.js +0 -15
  74. package/lib/Core/Scheduler/Scheduler.js +0 -294
  75. package/lib/Core/Style.js +0 -660
  76. package/lib/Core/StyleOptions.js +0 -486
  77. package/lib/Core/System/Capabilities.js +0 -63
  78. package/lib/Core/Tile/Tile.js +0 -207
  79. package/lib/Core/Tile/TileGrid.js +0 -49
  80. package/lib/Core/TileGeometry.js +0 -124
  81. package/lib/Core/TileMesh.js +0 -108
  82. package/lib/Core/View.js +0 -1116
  83. package/lib/Layer/C3DTilesLayer.js +0 -459
  84. package/lib/Layer/ColorLayer.js +0 -154
  85. package/lib/Layer/CopcLayer.js +0 -63
  86. package/lib/Layer/ElevationLayer.js +0 -139
  87. package/lib/Layer/EntwinePointTileLayer.js +0 -71
  88. package/lib/Layer/FeatureGeometryLayer.js +0 -77
  89. package/lib/Layer/GeoidLayer.js +0 -80
  90. package/lib/Layer/GeometryLayer.js +0 -233
  91. package/lib/Layer/InfoLayer.js +0 -64
  92. package/lib/Layer/LabelLayer.js +0 -470
  93. package/lib/Layer/Layer.js +0 -335
  94. package/lib/Layer/LayerUpdateState.js +0 -89
  95. package/lib/Layer/LayerUpdateStrategy.js +0 -80
  96. package/lib/Layer/OGC3DTilesLayer.js +0 -543
  97. package/lib/Layer/OrientedImageLayer.js +0 -228
  98. package/lib/Layer/PointCloudLayer.js +0 -405
  99. package/lib/Layer/Potree2Layer.js +0 -171
  100. package/lib/Layer/PotreeLayer.js +0 -72
  101. package/lib/Layer/RasterLayer.js +0 -37
  102. package/lib/Layer/ReferencingLayerProperties.js +0 -62
  103. package/lib/Layer/TiledGeometryLayer.js +0 -459
  104. package/lib/Loader/LASLoader.js +0 -193
  105. package/lib/Loader/Potree2BrotliLoader.js +0 -261
  106. package/lib/Loader/Potree2Loader.js +0 -207
  107. package/lib/Main.js +0 -115
  108. package/lib/MainBundle.js +0 -4
  109. package/lib/Parser/B3dmParser.js +0 -174
  110. package/lib/Parser/CameraCalibrationParser.js +0 -94
  111. package/lib/Parser/GDFParser.js +0 -72
  112. package/lib/Parser/GTXParser.js +0 -75
  113. package/lib/Parser/GeoJsonParser.js +0 -212
  114. package/lib/Parser/GpxParser.js +0 -25
  115. package/lib/Parser/ISGParser.js +0 -71
  116. package/lib/Parser/KMLParser.js +0 -25
  117. package/lib/Parser/LASParser.js +0 -137
  118. package/lib/Parser/MapBoxUrlParser.js +0 -83
  119. package/lib/Parser/PntsParser.js +0 -131
  120. package/lib/Parser/Potree2BinParser.js +0 -92
  121. package/lib/Parser/PotreeBinParser.js +0 -106
  122. package/lib/Parser/PotreeCinParser.js +0 -29
  123. package/lib/Parser/ShapefileParser.js +0 -78
  124. package/lib/Parser/VectorTileParser.js +0 -215
  125. package/lib/Parser/XbilParser.js +0 -120
  126. package/lib/Parser/deprecated/LegacyGLTFLoader.js +0 -1386
  127. package/lib/Parser/iGLTFLoader.js +0 -168
  128. package/lib/Process/3dTilesProcessing.js +0 -304
  129. package/lib/Process/FeatureProcessing.js +0 -76
  130. package/lib/Process/LayeredMaterialNodeProcessing.js +0 -221
  131. package/lib/Process/ObjectRemovalHelper.js +0 -97
  132. package/lib/Process/handlerNodeError.js +0 -23
  133. package/lib/Provider/3dTilesProvider.js +0 -149
  134. package/lib/Provider/DataSourceProvider.js +0 -8
  135. package/lib/Provider/Fetcher.js +0 -233
  136. package/lib/Provider/PointCloudProvider.js +0 -45
  137. package/lib/Provider/TileProvider.js +0 -16
  138. package/lib/Provider/URLBuilder.js +0 -116
  139. package/lib/Renderer/Camera.js +0 -281
  140. package/lib/Renderer/Color.js +0 -56
  141. package/lib/Renderer/ColorLayersOrdering.js +0 -115
  142. package/lib/Renderer/CommonMaterial.js +0 -31
  143. package/lib/Renderer/Label2DRenderer.js +0 -192
  144. package/lib/Renderer/LayeredMaterial.js +0 -243
  145. package/lib/Renderer/OBB.js +0 -151
  146. package/lib/Renderer/OrientedImageCamera.js +0 -118
  147. package/lib/Renderer/OrientedImageMaterial.js +0 -167
  148. package/lib/Renderer/PointsMaterial.js +0 -485
  149. package/lib/Renderer/RasterTile.js +0 -208
  150. package/lib/Renderer/RenderMode.js +0 -31
  151. package/lib/Renderer/Shader/ShaderChunk.js +0 -160
  152. package/lib/Renderer/Shader/ShaderUtils.js +0 -47
  153. package/lib/Renderer/SphereHelper.js +0 -17
  154. package/lib/Renderer/WebXR.js +0 -51
  155. package/lib/Renderer/c3DEngine.js +0 -214
  156. package/lib/Source/C3DTilesGoogleSource.js +0 -74
  157. package/lib/Source/C3DTilesIonSource.js +0 -54
  158. package/lib/Source/C3DTilesSource.js +0 -30
  159. package/lib/Source/CopcSource.js +0 -126
  160. package/lib/Source/EntwinePointTileSource.js +0 -72
  161. package/lib/Source/FileSource.js +0 -188
  162. package/lib/Source/OGC3DTilesGoogleSource.js +0 -29
  163. package/lib/Source/OGC3DTilesIonSource.js +0 -34
  164. package/lib/Source/OGC3DTilesSource.js +0 -21
  165. package/lib/Source/OrientedImageSource.js +0 -59
  166. package/lib/Source/Potree2Source.js +0 -167
  167. package/lib/Source/PotreeSource.js +0 -82
  168. package/lib/Source/Source.js +0 -203
  169. package/lib/Source/TMSSource.js +0 -144
  170. package/lib/Source/VectorTilesSource.js +0 -182
  171. package/lib/Source/WFSSource.js +0 -170
  172. package/lib/Source/WMSSource.js +0 -168
  173. package/lib/Source/WMTSSource.js +0 -92
  174. package/lib/ThreeExtended/capabilities/WebGL.js +0 -69
  175. package/lib/ThreeExtended/libs/ktx-parse.module.js +0 -506
  176. package/lib/ThreeExtended/libs/zstddec.module.js +0 -29
  177. package/lib/ThreeExtended/loaders/DDSLoader.js +0 -200
  178. package/lib/ThreeExtended/loaders/DRACOLoader.js +0 -400
  179. package/lib/ThreeExtended/loaders/GLTFLoader.js +0 -2879
  180. package/lib/ThreeExtended/loaders/KTX2Loader.js +0 -709
  181. package/lib/ThreeExtended/math/ColorSpaces.js +0 -59
  182. package/lib/ThreeExtended/utils/BufferGeometryUtils.js +0 -846
  183. package/lib/ThreeExtended/utils/WorkerPool.js +0 -70
  184. package/lib/Utils/CameraUtils.js +0 -555
  185. package/lib/Utils/DEMUtils.js +0 -350
  186. package/lib/Utils/FeaturesUtils.js +0 -156
  187. package/lib/Utils/Gradients.js +0 -16
  188. package/lib/Utils/OrientationUtils.js +0 -457
  189. package/lib/Utils/ThreeUtils.js +0 -115
  190. package/lib/Utils/gui/C3DTilesStyle.js +0 -215
  191. package/lib/Utils/gui/Main.js +0 -7
  192. package/lib/Utils/gui/Minimap.js +0 -154
  193. package/lib/Utils/gui/Navigation.js +0 -245
  194. package/lib/Utils/gui/Scale.js +0 -107
  195. package/lib/Utils/gui/Searchbar.js +0 -234
  196. package/lib/Utils/gui/Widget.js +0 -80
  197. package/lib/Utils/placeObjectOnGround.js +0 -136
  198. package/lib/Worker/LASLoaderWorker.js +0 -19
  199. package/lib/Worker/Potree2Worker.js +0 -21
package/lib/Core/View.js DELETED
@@ -1,1116 +0,0 @@
1
- import * as THREE from 'three';
2
- import * as CRS from "./Geographic/Crs.js";
3
- import Camera from "../Renderer/Camera.js";
4
- import initializeWebXR from "../Renderer/WebXR.js";
5
- import MainLoop, { MAIN_LOOP_EVENTS, RENDERING_PAUSED } from "./MainLoop.js";
6
- import Capabilities from "./System/Capabilities.js";
7
- import { COLOR_LAYERS_ORDER_CHANGED } from "../Renderer/ColorLayersOrdering.js";
8
- import c3DEngine from "../Renderer/c3DEngine.js";
9
- import RenderMode from "../Renderer/RenderMode.js";
10
- import Coordinates from "./Geographic/Coordinates.js";
11
- import FeaturesUtils from "../Utils/FeaturesUtils.js";
12
- import { getMaxColorSamplerUnitsCount } from "../Renderer/LayeredMaterial.js";
13
- import Scheduler from "./Scheduler/Scheduler.js";
14
- import Picking from "./Picking.js";
15
- import LabelLayer from "../Layer/LabelLayer.js";
16
- import ObjectRemovalHelper from "../Process/ObjectRemovalHelper.js";
17
- export const VIEW_EVENTS = {
18
- /**
19
- * Fires when all the layers of the view are considered initialized.
20
- * Initialized in this context means: all layers are ready to be
21
- * displayed (no pending network access, no visual improvement to be
22
- * expected, ...).
23
- * If you add new layers, the event will be fired again when all
24
- * layers are ready.
25
- * @event View#layers-initialized
26
- * @property type {string} layers-initialized
27
- */
28
- LAYERS_INITIALIZED: 'layers-initialized',
29
- LAYER_REMOVED: 'layer-removed',
30
- LAYER_ADDED: 'layer-added',
31
- INITIALIZED: 'initialized',
32
- COLOR_LAYERS_ORDER_CHANGED,
33
- CAMERA_MOVED: 'camera-moved',
34
- DISPOSED: 'disposed'
35
- };
36
-
37
- /**
38
- * Fired on current view's domElement when double right-clicking it. Copies all properties of the second right-click
39
- * MouseEvent (such as cursor position).
40
- * @event View#dblclick-right
41
- * @property {string} type dblclick-right
42
- */
43
-
44
- function _preprocessLayer(view, layer, parentLayer) {
45
- const source = layer.source;
46
- if (parentLayer && !layer.extent) {
47
- layer.extent = parentLayer.extent;
48
- if (source && !source.extent) {
49
- source.extent = parentLayer.extent;
50
- }
51
- }
52
- if (layer.isGeometryLayer && !layer.isLabelLayer) {
53
- // Find crs projection layer, this is projection destination
54
- layer.crs = view.referenceCrs;
55
- } else if (!layer.crs) {
56
- if (parentLayer && parentLayer.tileMatrixSets && parentLayer.tileMatrixSets.includes(source.crs)) {
57
- layer.crs = source.crs;
58
- } else {
59
- layer.crs = parentLayer && parentLayer.extent.crs;
60
- }
61
- }
62
- if (layer.isLabelLayer) {
63
- view.mainLoop.gfxEngine.label2dRenderer.registerLayer(layer);
64
- } else if (layer.labelEnabled || layer.addLabelLayer) {
65
- if (layer.labelEnabled) {
66
- // eslint-disable-next-line no-console
67
- console.info('layer.labelEnabled is deprecated use addLabelLayer, instead of');
68
- }
69
- // Because the features are shared between layer and labelLayer.
70
- layer.buildExtent = true;
71
- // label layer needs 3d data structure.
72
- layer.structure = '3d';
73
- const labelLayer = new LabelLayer(`${layer.id}-label`, {
74
- source,
75
- style: layer.style,
76
- zoom: layer.zoom,
77
- performance: layer.addLabelLayer.performance,
78
- crs: source.crs,
79
- visible: layer.visible,
80
- margin: 15,
81
- forceClampToTerrain: layer.addLabelLayer.forceClampToTerrain
82
- });
83
- layer.addEventListener('visible-property-changed', () => {
84
- labelLayer.visible = layer.visible;
85
- });
86
- const removeLabelLayer = e => {
87
- if (e.layerId === layer.id) {
88
- view.removeLayer(labelLayer.id);
89
- }
90
- view.removeEventListener(VIEW_EVENTS.LAYER_REMOVED, removeLabelLayer);
91
- };
92
- view.addEventListener(VIEW_EVENTS.LAYER_REMOVED, removeLabelLayer);
93
- layer.whenReady = layer.whenReady.then(() => {
94
- view.addLayer(labelLayer);
95
- return layer;
96
- });
97
- }
98
- if (layer.isOGC3DTilesLayer) {
99
- layer._setup(view);
100
- }
101
- return layer;
102
- }
103
- const _eventCoords = new THREE.Vector2();
104
- const matrix = new THREE.Matrix4();
105
- const screen = new THREE.Vector2();
106
- const ray = new THREE.Ray();
107
- const direction = new THREE.Vector3();
108
- const positionVector = new THREE.Vector3();
109
- const coordinates = new Coordinates('EPSG:4326');
110
- const viewers = [];
111
- // Size of the camera frustrum, in meters
112
- let screenMeters;
113
- let id = 0;
114
-
115
- /**
116
- * @property {number} id - The id of the view. It's incremented at each new view instance, starting at 0.
117
- * @property {HTMLElement} domElement - The domElement holding the canvas where the view is displayed
118
- * @property {String} referenceCrs - The coordinate reference system of the view
119
- * @property {MainLoop} mainLoop - itowns mainloop scheduling the operations
120
- * @property {THREE.Scene} scene - threejs scene of the view
121
- * @property {Camera} camera - itowns camera (that holds a threejs camera that is directly accessible with View.camera3D)
122
- * @property {THREE.Camera} camera3D - threejs camera that is stored in itowns camera
123
- * @property {THREE.WebGLRenderer} renderer - threejs webglrenderer rendering this view
124
- */
125
- class View extends THREE.EventDispatcher {
126
- #layers = [];
127
- #pixelDepthBuffer = (() => new Uint8Array(4))();
128
- #fullSizeDepthBuffer;
129
- /**
130
- * Constructs an Itowns View instance
131
- *
132
- * @example <caption><b>Create a view with a custom Three.js camera.</b></caption>
133
- * var viewerDiv = document.getElementById('viewerDiv');
134
- * var customCamera = itowns.THREE.PerspectiveCamera();
135
- * var view = itowns.View('EPSG:4326', viewerDiv, { camera: { cameraThree: customCamera } });
136
- *
137
- * @example <caption><b>Create a view with an orthographic camera, and grant it with Three.js custom controls.</b></caption>
138
- * var viewerDiv = document.getElementById('viewerDiv');
139
- * var view = itowns.View('EPSG:4326', viewerDiv, { camera: { type: itowns.CAMERA_TYPE.ORTHOGRAPHIC } });
140
- * var customControls = itowns.THREE.OrbitControls(view.camera3D, viewerDiv);
141
- *
142
- * @param {String} crs - The default CRS of Three.js coordinates. Should be a cartesian CRS.
143
- * @param {HTMLElement} viewerDiv - Where to instanciate the Three.js scene in the DOM
144
- * @param {Object} [options] - Optional properties.
145
- * @param {Object} [options.camera] - Options for the camera associated to the view. See {@link Camera} options.
146
- * @param {MainLoop} [options.mainLoop] - {@link MainLoop} instance to use, otherwise a default one will be constructed
147
- * @param {WebGLRenderer|Object} [options.renderer] - {@link WebGLRenderer} instance to use, otherwise
148
- * a default one will be constructed. In this case, if options.renderer is an object, it will be used to
149
- * configure the renderer (see {@link c3DEngine}. If not present, a new &lt;canvas> will be created and
150
- * added to viewerDiv (mutually exclusive with mainLoop)
151
- * @param {Object} [options.webXR] - enable webxr button to switch on VR visualization.
152
- * @param {number} [options.webXR.scale=1.0] - apply webxr scale tranformation.
153
- * @param {Scene} [options.scene3D] - [THREE.Scene](https://threejs.org/docs/#api/en/scenes/Scene) instance to use, otherwise a default one will be constructed
154
- * @param {Color} [options.diffuse] - [THREE.Color](https://threejs.org/docs/?q=color#api/en/math/Color) Diffuse color terrain material.
155
- * This color is applied to terrain if there isn't color layer on terrain extent (by example on pole).
156
- * @param {boolean} [options.enableFocusOnStart=true] - enable focus on dom element on start.
157
- */
158
- constructor(crs, viewerDiv) {
159
- let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
160
- if (!viewerDiv) {
161
- throw new Error('Invalid viewerDiv parameter (must non be null/undefined)');
162
- }
163
- super();
164
- this.domElement = viewerDiv;
165
- this.id = id++;
166
- this.referenceCrs = crs;
167
- let engine;
168
- // options.renderer can be 2 separate things:
169
- // - an actual renderer (in this case we don't use viewerDiv)
170
- // - options for the renderer to be created
171
- if (options.renderer && options.renderer.domElement) {
172
- engine = new c3DEngine(options.renderer);
173
- } else {
174
- engine = new c3DEngine(viewerDiv, options.renderer);
175
- }
176
- this.mainLoop = options.mainLoop || new MainLoop(new Scheduler(), engine);
177
- this.scene = options.scene3D || new THREE.Scene();
178
- if (!options.scene3D) {
179
- this.scene.matrixWorldAutoUpdate = false;
180
- }
181
- this.camera = new Camera(this.referenceCrs, this.mainLoop.gfxEngine.getWindowSize().x, this.mainLoop.gfxEngine.getWindowSize().y, options.camera);
182
- this._frameRequesters = {};
183
- this._resizeListener = () => this.resize();
184
- window.addEventListener('resize', this._resizeListener, false);
185
- this._changeSources = new Set();
186
- this._delayedFrameRequesterRemoval = [];
187
- this._allLayersAreReadyCallback = () => {
188
- // all layers must be ready
189
- const allReady = this.getLayers().every(layer => layer.ready);
190
- if (allReady && this.mainLoop.scheduler.commandsWaitingExecutionCount() == 0 && this.mainLoop.renderingState == RENDERING_PAUSED) {
191
- this.dispatchEvent({
192
- type: VIEW_EVENTS.LAYERS_INITIALIZED
193
- });
194
- this.removeFrameRequester(MAIN_LOOP_EVENTS.UPDATE_END, this._allLayersAreReadyCallback);
195
- }
196
- };
197
- this.camera.resize(this.domElement.clientWidth, this.domElement.clientHeight);
198
- const fn = () => {
199
- this.removeEventListener(VIEW_EVENTS.LAYERS_INITIALIZED, fn);
200
- this.dispatchEvent({
201
- type: VIEW_EVENTS.INITIALIZED
202
- });
203
- };
204
- this.addEventListener(VIEW_EVENTS.LAYERS_INITIALIZED, fn);
205
- this.#fullSizeDepthBuffer = new Uint8Array(4 * this.camera.width * this.camera.height);
206
-
207
- // Indicates that view's domElement can be focused (the negative value indicates that domElement can't be
208
- // focused sequentially using tab key). Focus is needed to capture some key events.
209
- this.domElement.tabIndex = -1;
210
- // Set focus on view's domElement.
211
- if (!options.disableFocusOnStart) {
212
- this.domElement.focus();
213
- }
214
-
215
- // Create a custom `dblclick-right` event that is triggered when double right-clicking
216
- let rightClickTimeStamp;
217
- this.domElement.addEventListener('mouseup', event => {
218
- if (event.button === 2) {
219
- // If pressed mouse button is right button
220
- // If time between two right-clicks is bellow 500 ms, triggers a `dblclick-right` event
221
- if (rightClickTimeStamp && event.timeStamp - rightClickTimeStamp < 500) {
222
- this.domElement.dispatchEvent(new MouseEvent('dblclick-right', event));
223
- }
224
- rightClickTimeStamp = event.timeStamp;
225
- }
226
- });
227
-
228
- // push all viewer to keep source.cache
229
- viewers.push(this);
230
- if (options.webXR) {
231
- initializeWebXR(this, options.webXR);
232
- }
233
- }
234
-
235
- /**
236
- * Get the Threejs renderer used to render this view.
237
- * @returns {THREE.WebGLRenderer} the WebGLRenderer used to render this view.
238
- */
239
- get renderer() {
240
- return this.mainLoop?.gfxEngine?.getRenderer();
241
- }
242
-
243
- /**
244
- * Get the threejs Camera of this view
245
- * @returns {THREE.Camera} the threejs camera of this view
246
- */
247
- get camera3D() {
248
- return this.camera?.camera3D;
249
- }
250
-
251
- /**
252
- * Dispose viewer before delete it.
253
- *
254
- * Method dispose all viewer objects
255
- * - remove control
256
- * - remove all layers
257
- * - remove all frame requester
258
- * - remove all events
259
- * @param {boolean} [clearCache=false] Whether to clear all the caches or not (layers cache, style cache, tilesCache)
260
- */
261
- dispose() {
262
- let clearCache = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
263
- const id = viewers.indexOf(this);
264
- if (id == -1) {
265
- console.warn('View already disposed');
266
- return;
267
- }
268
- window.removeEventListener('resize', this._resizeListener);
269
-
270
- // controls dispose
271
- if (this.controls) {
272
- if (typeof this.controls.dispose === 'function') {
273
- this.controls.dispose();
274
- }
275
- delete this.controls;
276
- }
277
- // remove alls frameRequester
278
- this.removeAllFrameRequesters();
279
- // remove all layers
280
- const layers = this.getLayers(l => !l.isTiledGeometryLayer && !l.isAtmosphere);
281
- for (const layer of layers) {
282
- this.removeLayer(layer.id, clearCache);
283
- }
284
- const atmospheres = this.getLayers(l => l.isAtmosphere);
285
- for (const atmosphere of atmospheres) {
286
- this.removeLayer(atmosphere.id, clearCache);
287
- }
288
- const tileLayers = this.getLayers(l => l.isTiledGeometryLayer);
289
- for (const tileLayer of tileLayers) {
290
- this.removeLayer(tileLayer.id, clearCache);
291
- }
292
- viewers.splice(id, 1);
293
- // Remove remaining objects in the scene (e.g. helpers, debug, etc.)
294
- this.scene.traverse(ObjectRemovalHelper.cleanup);
295
- this.dispatchEvent({
296
- type: VIEW_EVENTS.DISPOSED
297
- });
298
- // remove alls events
299
- this.removeAllEvents();
300
- }
301
-
302
- /**
303
- * Add layer in viewer.
304
- * The layer id must be unique.
305
- *
306
- * The `layer.whenReady` is a promise that resolves when
307
- * the layer is done. This promise is also returned by
308
- * `addLayer` allowing to chain call.
309
- *
310
- * @param {LayerOptions|Layer|GeometryLayer} layer The layer to add in view.
311
- * @param {Layer=} parentLayer it's the layer to which the layer will be attached.
312
- * @return {Promise} a promise resolved with the new layer object when it is fully initialized or rejected if any error occurred.
313
- */
314
- addLayer(layer, parentLayer) {
315
- if (!layer || !layer.isLayer) {
316
- return Promise.reject(new Error('Add Layer type object'));
317
- }
318
- const duplicate = this.getLayerById(layer.id);
319
- if (duplicate) {
320
- return layer._reject(new Error(`Invalid id '${layer.id}': id already used`));
321
- }
322
- layer = _preprocessLayer(this, layer, parentLayer);
323
- if (parentLayer) {
324
- if (layer.isColorLayer) {
325
- const layerColors = this.getLayers(l => l.isColorLayer);
326
- layer.sequence = layerColors.length;
327
- const sumColorLayers = parentLayer.countColorLayersTextures(...layerColors, layer);
328
- if (sumColorLayers <= getMaxColorSamplerUnitsCount()) {
329
- parentLayer.attach(layer);
330
- } else {
331
- return layer._reject(new Error(`Cant add color layer ${layer.id}: the maximum layer is reached`));
332
- }
333
- } else {
334
- parentLayer.attach(layer);
335
- }
336
- } else {
337
- if (typeof layer.update !== 'function') {
338
- return layer._reject(new Error('Cant add GeometryLayer: missing a update function'));
339
- }
340
- if (typeof layer.preUpdate !== 'function') {
341
- return layer._reject(new Error('Cant add GeometryLayer: missing a preUpdate function'));
342
- }
343
- this.#layers.push(layer);
344
- }
345
- if (layer.object3d && !layer.object3d.parent && layer.object3d !== this.scene) {
346
- this.scene.add(layer.object3d);
347
- }
348
- Promise.all(layer._promises).then(() => {
349
- layer._resolve();
350
- this.notifyChange(parentLayer || layer, false);
351
- if (!this._frameRequesters[MAIN_LOOP_EVENTS.UPDATE_END] || !this._frameRequesters[MAIN_LOOP_EVENTS.UPDATE_END].includes(this._allLayersAreReadyCallback)) {
352
- this.addFrameRequester(MAIN_LOOP_EVENTS.UPDATE_END, this._allLayersAreReadyCallback);
353
- }
354
- this.dispatchEvent({
355
- type: VIEW_EVENTS.LAYER_ADDED,
356
- layerId: layer.id
357
- });
358
- }, layer._reject);
359
- return layer.whenReady;
360
- }
361
-
362
- /**
363
- * Removes a specific imagery layer from the current layer list. This removes layers inserted with attach().
364
- * @example
365
- * view.removeLayer('layerId');
366
- * @param {string} layerId The identifier
367
- * @param {boolean} [clearCache=false] Whether to clear all the layer cache or not
368
- * @return {boolean}
369
- */
370
- removeLayer(layerId, clearCache) {
371
- const layer = this.getLayerById(layerId);
372
- if (layer) {
373
- const parentLayer = layer.parent;
374
-
375
- // Remove and dispose all nodes
376
- layer.delete(clearCache);
377
-
378
- // Detach layer if it's attached
379
- if (parentLayer && !parentLayer.detach(layer)) {
380
- throw new Error(`Error to detach ${layerId} from ${parentLayer.id}`);
381
- } else if (parentLayer == undefined) {
382
- // Remove layer from viewer
383
- this.#layers.splice(this.#layers.findIndex(l => l.id == layerId), 1);
384
- }
385
- if (layer.isColorLayer) {
386
- // Update color layers sequence
387
- const imageryLayers = this.getLayers(l => l.isColorLayer);
388
- for (const color of imageryLayers) {
389
- if (color.sequence > layer.sequence) {
390
- color.sequence--;
391
- }
392
- }
393
- }
394
-
395
- // Remove unused cache in all viewers
396
-
397
- // count of times the source is used in all viewer
398
- let sharedSourceCount = 0;
399
- for (const view of viewers) {
400
- // add count of times the source is used in other layers
401
- sharedSourceCount += view.getLayers(l => l.source.uid == layer.source.uid && l.crs == layer.crs).length;
402
- }
403
- // if sharedSourceCount equals to 0 so remove unused cache for this CRS
404
- layer.source.onLayerRemoved({
405
- unusedCrs: sharedSourceCount == 0 ? layer.crs : undefined
406
- });
407
- this.notifyChange(this.camera);
408
- this.dispatchEvent({
409
- type: VIEW_EVENTS.LAYER_REMOVED,
410
- layerId
411
- });
412
- return true;
413
- } else {
414
- throw new Error(`${layerId} doesn't exist`);
415
- }
416
- }
417
-
418
- /**
419
- * Notifies the scene it needs to be updated due to changes exterior to the
420
- * scene itself (e.g. camera movement).
421
- * non-interactive events (e.g: texture loaded)
422
- * @param {*} changeSource
423
- * @param {boolean} needsRedraw - indicates if notified change requires a full scene redraw.
424
- */
425
- notifyChange() {
426
- let changeSource = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
427
- let needsRedraw = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
428
- if (changeSource) {
429
- this._changeSources.add(changeSource);
430
- if (!this.mainLoop.gfxEngine.renderer.xr.isPresenting && (changeSource.isTileMesh || changeSource.isCamera)) {
431
- this.#fullSizeDepthBuffer.needsUpdate = true;
432
- }
433
- }
434
- this.mainLoop.scheduleViewUpdate(this, needsRedraw);
435
- }
436
-
437
- /**
438
- * Get all layers, with an optionnal filter applied.
439
- * The filter method will be called with 2 args:
440
- * - 1st: current layer
441
- * - 2nd: (optional) the geometry layer to which the current layer is attached
442
- * @example
443
- * // get all layers
444
- * view.getLayers();
445
- * // get all color layers
446
- * view.getLayers(layer => layer.isColorLayer);
447
- * // get all elevation layers
448
- * view.getLayers(layer => layer.isElevationLayer);
449
- * // get all geometry layers
450
- * view.getLayers(layer => layer.isGeometryLayer);
451
- * // get one layer with id
452
- * view.getLayers(layer => layer.id === 'itt');
453
- * @param {function(Layer):boolean} filter
454
- * @returns {Array<Layer>}
455
- */
456
- getLayers(filter) {
457
- const result = [];
458
- for (const layer of this.#layers) {
459
- if (!filter || filter(layer)) {
460
- result.push(layer);
461
- }
462
- if (layer.attachedLayers) {
463
- for (const attached of layer.attachedLayers) {
464
- if (!filter || filter(attached, layer)) {
465
- result.push(attached);
466
- }
467
- }
468
- }
469
- }
470
- return result;
471
- }
472
-
473
- /**
474
- * Gets the layer by identifier.
475
- *
476
- * @param {String} layerId The layer identifier
477
- * @return {Layer} The layer by identifier.
478
- */
479
-
480
- getLayerById(layerId) {
481
- return this.getLayers(l => l.id === layerId)[0];
482
- }
483
-
484
- /**
485
- * @name FrameRequester
486
- * @function
487
- *
488
- * @description
489
- * Method that will be called each time the `MainLoop` updates. This function
490
- * will be given as parameter the delta (in ms) between this update and the
491
- * previous one, and whether or not we just started to render again. This update
492
- * is considered as the "next" update if `view.notifyChange` was called during a
493
- * precedent update. If `view.notifyChange` has been called by something else
494
- * (other micro/macrotask, UI events etc...), then this update is considered as
495
- * being the "first". It can also receive optional arguments, depending on the
496
- * attach point of this function. Currently only `BEFORE_LAYER_UPDATE /
497
- * AFTER_LAYER_UPDATE` attach points provide an additional argument: the layer
498
- * being updated.
499
- * <br><br>
500
- *
501
- * This means that if a `frameRequester` function wants to animate something, it
502
- * should keep on calling `view.notifyChange` until its task is done.
503
- * <br><br>
504
- *
505
- * Implementors of `frameRequester` should keep in mind that this function will
506
- * be potentially called at each frame, thus care should be given about
507
- * performance.
508
- * <br><br>
509
- *
510
- * Typical frameRequesters are controls, module wanting to animate moves or UI
511
- * elements etc... Basically anything that would want to call
512
- * requestAnimationFrame.
513
- *
514
- * @param {number} dt
515
- * @param {boolean} updateLoopRestarted
516
- * @param {...*} args
517
- */
518
- /**
519
- * Add a frame requester to this view.
520
- *
521
- * FrameRequesters can activate the MainLoop update by calling view.notifyChange.
522
- *
523
- * @param {String} when - decide when the frameRequester should be called during
524
- * the update cycle. Can be any of {@link MAIN_LOOP_EVENTS}.
525
- * @param {FrameRequester} frameRequester - this function will be called at each
526
- * MainLoop update with the time delta between last update, or 0 if the MainLoop
527
- * has just been relaunched.
528
- */
529
- addFrameRequester(when, frameRequester) {
530
- if (typeof frameRequester !== 'function') {
531
- throw new Error('frameRequester must be a function');
532
- }
533
- if (!this._frameRequesters[when]) {
534
- this._frameRequesters[when] = [frameRequester];
535
- } else {
536
- this._frameRequesters[when].push(frameRequester);
537
- }
538
- }
539
-
540
- /**
541
- * Remove a frameRequester.
542
- * The effective removal will happen either later; at worst it'll be at
543
- * the beginning of the next frame.
544
- *
545
- * @param {String} when - attach point of this requester. Can be any of
546
- * {@link MAIN_LOOP_EVENTS}.
547
- * @param {FrameRequester} frameRequester
548
- */
549
- removeFrameRequester(when, frameRequester) {
550
- if (this._frameRequesters[when].includes(frameRequester)) {
551
- this._delayedFrameRequesterRemoval.push({
552
- when,
553
- frameRequester
554
- });
555
- } else {
556
- console.error('Invalid call to removeFrameRequester: frameRequester isn\'t registered');
557
- }
558
- }
559
-
560
- /**
561
- * Removes all frame requesters.
562
- */
563
- removeAllFrameRequesters() {
564
- for (const when in this._frameRequesters) {
565
- if (Object.prototype.hasOwnProperty.call(this._frameRequesters, when)) {
566
- const frameRequesters = this._frameRequesters[when];
567
- for (const frameRequester of frameRequesters) {
568
- this.removeFrameRequester(when, frameRequester);
569
- }
570
- }
571
- }
572
- this._executeFrameRequestersRemovals();
573
- }
574
-
575
- /**
576
- * Removes all viewer events.
577
- */
578
- removeAllEvents() {
579
- if (this._listeners === undefined) {
580
- return;
581
- }
582
- for (const type in this._listeners) {
583
- if (Object.prototype.hasOwnProperty.call(this._listeners, type)) {
584
- delete this._listeners[type];
585
- }
586
- }
587
- this._listeners = undefined;
588
- }
589
- _executeFrameRequestersRemovals() {
590
- for (const toDelete of this._delayedFrameRequesterRemoval) {
591
- const index = this._frameRequesters[toDelete.when].indexOf(toDelete.frameRequester);
592
- if (index >= 0) {
593
- this._frameRequesters[toDelete.when].splice(index, 1);
594
- } else {
595
- console.warn('FrameReq has already been removed');
596
- }
597
- }
598
- this._delayedFrameRequesterRemoval.length = 0;
599
- }
600
-
601
- /**
602
- * Execute a frameRequester.
603
- *
604
- * @param {String} when - attach point of this (these) requester(s). Can be any
605
- * of {@link MAIN_LOOP_EVENTS}.
606
- * @param {Number} dt - delta between this update and the previous one
607
- * @param {boolean} updateLoopRestarted
608
- * @param {...*} args - optional arguments
609
- */
610
- execFrameRequesters(when, dt, updateLoopRestarted) {
611
- if (!this._frameRequesters[when]) {
612
- return;
613
- }
614
- if (this._delayedFrameRequesterRemoval.length > 0) {
615
- this._executeFrameRequestersRemovals();
616
- }
617
- for (var _len = arguments.length, args = new Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
618
- args[_key - 3] = arguments[_key];
619
- }
620
- for (const frameRequester of this._frameRequesters[when]) {
621
- if (frameRequester.update) {
622
- frameRequester.update(dt, updateLoopRestarted, args);
623
- } else {
624
- frameRequester(dt, updateLoopRestarted, args);
625
- }
626
- }
627
- }
628
-
629
- /**
630
- * Extract view coordinates from a mouse-event / touch-event
631
- * @param {event} event - event can be a MouseEvent or a TouchEvent
632
- * @param {THREE.Vector2} target - the target to set the view coords in
633
- * @param {number} [touchIdx=0] - finger index when using a TouchEvent
634
- * @return {THREE.Vector2|undefined} - view coordinates (in pixels, 0-0 = top-left of the View).
635
- * If the event is neither a `MouseEvent` nor a `TouchEvent`, the return is `undefined`.
636
- */
637
- eventToViewCoords(event) {
638
- let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _eventCoords;
639
- let touchIdx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
640
- const br = this.domElement.getBoundingClientRect();
641
- if (event.touches && event.touches.length) {
642
- return target.set(event.touches[touchIdx].clientX - br.x, event.touches[touchIdx].clientY - br.y);
643
- } else if (event.offsetX !== undefined && event.offsetY !== undefined) {
644
- const targetBoundingRect = event.target.getBoundingClientRect();
645
- return target.set(targetBoundingRect.x + event.offsetX - br.x, targetBoundingRect.y + event.offsetY - br.y);
646
- }
647
- }
648
-
649
- /**
650
- * Extract normalized coordinates (NDC) from a mouse-event / touch-event
651
- * @param {event} event - event can be a MouseEvent or a TouchEvent
652
- * @param {number} touchIdx - finger index when using a TouchEvent (default: 0)
653
- * @return {THREE.Vector2} - NDC coordinates (x and y are [-1, 1])
654
- */
655
- eventToNormalizedCoords(event) {
656
- let touchIdx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
657
- return this.viewToNormalizedCoords(this.eventToViewCoords(event, _eventCoords, touchIdx));
658
- }
659
-
660
- /**
661
- * Convert view coordinates to normalized coordinates (NDC)
662
- * @param {THREE.Vector2} viewCoords (in pixels, 0-0 = top-left of the View)
663
- * @param {THREE.Vector2} target
664
- * @return {THREE.Vector2} - NDC coordinates (x and y are [-1, 1])
665
- */
666
- viewToNormalizedCoords(viewCoords) {
667
- let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _eventCoords;
668
- target.x = 2 * (viewCoords.x / this.camera.width) - 1;
669
- target.y = -2 * (viewCoords.y / this.camera.height) + 1;
670
- return target;
671
- }
672
-
673
- /**
674
- * Convert NDC coordinates to view coordinates
675
- * @param {THREE.Vector2} ndcCoords
676
- * @return {THREE.Vector2} - view coordinates (in pixels, 0-0 = top-left of the View)
677
- */
678
- normalizedToViewCoords(ndcCoords) {
679
- _eventCoords.x = (ndcCoords.x + 1) * 0.5 * this.camera.width;
680
- _eventCoords.y = (ndcCoords.y - 1) * -0.5 * this.camera.height;
681
- return _eventCoords;
682
- }
683
-
684
- /**
685
- * Searches for objects in {@link GeometryLayer} and specified
686
- * `THREE.Object3D`, under the mouse or at a specified coordinates, in this
687
- * view.
688
- *
689
- * @param {Object} mouseOrEvt - Mouse position in window coordinates (from
690
- * the top left corner of the window) or `MouseEvent` or `TouchEvent`.
691
- * @param {number} [radius=0] - The picking will happen in a circle centered
692
- * on mouseOrEvt. This is the radius of this circle, in pixels.
693
- * @param {GeometryLayer|string|Object3D|Array<GeometryLayer|string|Object3D>} [where] - Where to look for
694
- * objects. It can be a single {@link GeometryLayer}, `THREE.Object3D`, ID of a layer or an array of one of these or
695
- * of a mix of these. If no location is specified, it will query on all {@link GeometryLayer} present in this `View`.
696
- *
697
- * @return {Object[]} - An array of objects. Each element contains at least
698
- * an object property which is the `THREE.Object3D` under the cursor. Then
699
- * depending on the queried layer/source, there may be additionnal
700
- * properties (coming from `THREE.Raycaster` for instance).
701
- *
702
- * @example
703
- * view.pickObjectsAt({ x, y })
704
- * view.pickObjectsAt({ x, y }, 1, 'wfsBuilding')
705
- * view.pickObjectsAt({ x, y }, 3, 'wfsBuilding', myLayer)
706
- */
707
- pickObjectsAt(mouseOrEvt) {
708
- let radius = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
709
- let where = arguments.length > 2 ? arguments[2] : undefined;
710
- const sources = [];
711
- if (!where || where.length === 0) {
712
- where = this.getLayers(l => l.isGeometryLayer);
713
- }
714
- if (!Array.isArray(where)) {
715
- where = [where];
716
- }
717
- where.forEach(l => {
718
- if (typeof l === 'string') {
719
- l = this.getLayerById(l);
720
- }
721
- if (l && (l.isGeometryLayer || l.isObject3D)) {
722
- sources.push(l);
723
- }
724
- });
725
- if (sources.length == 0) {
726
- return [];
727
- }
728
- const results = [];
729
- const mouse = mouseOrEvt instanceof Event ? this.eventToViewCoords(mouseOrEvt) : mouseOrEvt;
730
- for (const source of sources) {
731
- if (source.isAtmosphere) {
732
- continue;
733
- }
734
- if (source.isGeometryLayer) {
735
- if (!source.ready) {
736
- console.warn('view.pickObjectAt : layer is not ready : ', source);
737
- continue;
738
- }
739
- source.pickObjectsAt(this, mouse, radius, results);
740
- } else {
741
- Picking.pickObjectsAt(this, mouse, radius, source, results);
742
- }
743
- }
744
- return results;
745
- }
746
-
747
- /**
748
- * Return the current zoom scale at the central point of the view. This
749
- * function compute the scale of a map.
750
- *
751
- * @param {number} pitch - Screen pitch, in millimeters ; 0.28 by default
752
- *
753
- * @return {number} The zoom scale.
754
- */
755
- getScale() {
756
- let pitch = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.28;
757
- if (this.camera3D.isOrthographicCamera) {
758
- return pitch * 1E-3 / this.getPixelsToMeters();
759
- }
760
- return this.getScaleFromDistance(pitch, this.getDistanceFromCamera());
761
- }
762
- getScaleFromDistance() {
763
- let pitch = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.28;
764
- let distance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
765
- pitch /= 1000;
766
- const fov = THREE.MathUtils.degToRad(this.camera3D.fov);
767
- const unit = this.camera.height / (2 * distance * Math.tan(fov * 0.5));
768
- return pitch * unit;
769
- }
770
-
771
- /**
772
- * Given a screen coordinates, get the distance between the projected
773
- * coordinates and the camera associated to this view.
774
- *
775
- * @param {THREE.Vector2} [screenCoord] - The screen coordinate to get the
776
- * distance at. By default this is the middle of the screen.
777
- *
778
- * @return {number} The distance in meters.
779
- */
780
- getDistanceFromCamera(screenCoord) {
781
- this.getPickingPositionFromDepth(screenCoord, positionVector);
782
- return this.camera3D.position.distanceTo(positionVector);
783
- }
784
-
785
- /**
786
- * Get, for a specific screen coordinate, the projected distance on the
787
- * surface of the main layer of the view.
788
- *
789
- * @param {number} [pixels=1] - The size, in pixels, to get in meters.
790
- * @param {THREE.Vector2} [screenCoord] - The screen coordinate to get the
791
- * projected distance at. By default, this is the middle of the screen.
792
- *
793
- * @return {number} The projected distance in meters.
794
- */
795
- getPixelsToMeters() {
796
- let pixels = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
797
- let screenCoord = arguments.length > 1 ? arguments[1] : undefined;
798
- if (this.camera3D.isOrthographicCamera) {
799
- screenMeters = (this.camera3D.right - this.camera3D.left) / this.camera3D.zoom;
800
- return pixels * screenMeters / this.camera.width;
801
- }
802
- return this.getPixelsToMetersFromDistance(pixels, this.getDistanceFromCamera(screenCoord));
803
- }
804
- getPixelsToMetersFromDistance() {
805
- let pixels = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
806
- let distance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
807
- return pixels * distance / this.camera._preSSE;
808
- }
809
-
810
- /**
811
- * Get, for a specific screen coordinate, the size in pixels of a projected
812
- * distance on the surface of the main layer of the view.
813
- *
814
- * @param {number} [meters=1] - The size, in meters, to get in pixels.
815
- * @param {THREE.Vector2} [screenCoord] - The screen coordinate to get the
816
- * projected distance at. By default, this is the middle of the screen.
817
- *
818
- * @return {number} The projected distance in pixels.
819
- */
820
- getMetersToPixels() {
821
- let meters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
822
- let screenCoord = arguments.length > 1 ? arguments[1] : undefined;
823
- if (this.camera3D.isOrthographicCamera) {
824
- screenMeters = (this.camera3D.right - this.camera3D.left) / this.camera3D.zoom;
825
- return meters * this.camera.width / screenMeters;
826
- }
827
- return this.getMetersToPixelsFromDistance(meters, this.getDistanceFromCamera(screenCoord));
828
- }
829
- getMetersToPixelsFromDistance() {
830
- let meters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
831
- let distance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
832
- return this.camera._preSSE * meters / distance;
833
- }
834
-
835
- /**
836
- * Searches for {@link FeatureGeometry} in {@link ColorLayer}, under the mouse or at
837
- * the specified coordinates, in this view. Combining them per layer and in a Feature
838
- * like format.
839
- *
840
- * @param {Object} mouseOrEvt - Mouse position in window coordinates (from
841
- * the top left corner of the window) or `MouseEvent` or `TouchEvent`.
842
- * @param {number} [radius=3] - The picking will happen in a circle centered
843
- * on mouseOrEvt. This is the radius of this circle, in pixels.
844
- * @param {...ColorLayer|GeometryLayer|string} [where] - The layers to look
845
- * into. If not specified, all {@link ColorLayer} and {@link GeometryLayer}
846
- * layers of this view will be looked in.
847
- *
848
- * @return {Object} - An object, having one property per layer.
849
- * For example, looking for features on layers `wfsBuilding` and `wfsRoads`
850
- * will give an object like `{ wfsBuilding: [...], wfsRoads: [] }`.
851
- * Each property is made of an array, that can be empty or filled with
852
- * Feature like objects composed of:
853
- * - the FeatureGeometry
854
- * - the feature type
855
- * - the style
856
- * - the coordinate if the FeatureGeometry is a point
857
- *
858
- * @example
859
- * view.pickFeaturesAt({ x, y });
860
- * view.pickFeaturesAt({ x, y }, 1, 'wfsBuilding');
861
- * view.pickFeaturesAt({ x, y }, 3, 'wfsBuilding', myLayer);
862
- */
863
- pickFeaturesAt(mouseOrEvt) {
864
- let radius = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
865
- for (var _len2 = arguments.length, where = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
866
- where[_key2 - 2] = arguments[_key2];
867
- }
868
- if (Array.isArray(where[0])) {
869
- console.warn('Deprecated: the ...where argument of View#pickFeaturesAt should not be an array anymore, but a list: use the spread operator if needed.');
870
- where = where[0];
871
- }
872
- const layers = [];
873
- const result = {};
874
- where = where.length == 0 ? this.getLayers(l => l.isColorLayer || l.isGeometryLayer) : where;
875
- where.forEach(l => {
876
- if (typeof l === 'string') {
877
- l = this.getLayerById(l);
878
- }
879
- if (l && l.isLayer) {
880
- result[l.id] = [];
881
- if (l.isColorLayer) {
882
- layers.push(l.id);
883
- }
884
- }
885
- });
886
-
887
- // Get the mouse coordinates to the correct system
888
- const mouse = mouseOrEvt instanceof Event ? this.eventToViewCoords(mouseOrEvt, _eventCoords) : mouseOrEvt;
889
- const objects = this.pickObjectsAt(mouse, radius, ...where);
890
- if (objects.length > 0) {
891
- objects.forEach(o => result[o.layer.id].push(o));
892
- }
893
- if (layers.length == 0) {
894
- return result;
895
- }
896
- this.getPickingPositionFromDepth(mouse, positionVector);
897
- coordinates.crs = this.referenceCrs;
898
- coordinates.setFromVector3(positionVector);
899
-
900
- // Get the correct precision; the position variable will be set in this
901
- // function.
902
- let precision;
903
- const precisions = {
904
- M: this.getPixelsToMeters(radius, mouse),
905
- D: 0.001 * radius
906
- };
907
- if (this.isPlanarView) {
908
- precisions.D = precisions.M;
909
- } else if (this.getPixelsToDegrees) {
910
- precisions.D = this.getMetersToDegrees(precisions.M);
911
- }
912
-
913
- // Get the tile corresponding to where the cursor is
914
- const tiles = Picking.pickTilesAt(this, mouse, radius, this.tileLayer);
915
- for (const tile of tiles) {
916
- if (!tile.object.material) {
917
- continue;
918
- }
919
- for (const materialLayer of tile.object.material.getLayers(layers)) {
920
- for (const texture of materialLayer.textures) {
921
- if (!texture.features) {
922
- continue;
923
- }
924
- precision = CRS.isMetricUnit(texture.features.crs) ? precisions.M : precisions.D;
925
- const featuresUnderCoor = FeaturesUtils.filterFeaturesUnderCoordinate(coordinates, texture.features, precision);
926
- featuresUnderCoor.forEach(feature => {
927
- if (!result[materialLayer.id].find(f => f.geometry === feature.geometry)) {
928
- result[materialLayer.id].push(feature);
929
- }
930
- });
931
- }
932
- }
933
- }
934
- return result;
935
- }
936
- readDepthBuffer(x, y, width, height, buffer) {
937
- const g = this.mainLoop.gfxEngine;
938
- const currentWireframe = this.tileLayer.wireframe;
939
- const currentOpacity = this.tileLayer.opacity;
940
- const currentVisibility = this.tileLayer.visible;
941
- if (currentWireframe) {
942
- this.tileLayer.wireframe = false;
943
- }
944
- if (currentOpacity < 1.0) {
945
- this.tileLayer.opacity = 1.0;
946
- }
947
- if (!currentVisibility) {
948
- this.tileLayer.visible = true;
949
- }
950
- const restore = this.tileLayer.level0Nodes.map(n => RenderMode.push(n, RenderMode.MODES.DEPTH));
951
- buffer = g.renderViewToBuffer({
952
- camera: this.camera,
953
- scene: this.tileLayer.object3d
954
- }, {
955
- x,
956
- y,
957
- width,
958
- height,
959
- buffer
960
- });
961
- restore.forEach(r => r());
962
- if (this.tileLayer.wireframe !== currentWireframe) {
963
- this.tileLayer.wireframe = currentWireframe;
964
- }
965
- if (this.tileLayer.opacity !== currentOpacity) {
966
- this.tileLayer.opacity = currentOpacity;
967
- }
968
- if (this.tileLayer.visible !== currentVisibility) {
969
- this.tileLayer.visible = currentVisibility;
970
- }
971
- return buffer;
972
- }
973
-
974
- /**
975
- * Returns the world position on the terrain (view's crs: referenceCrs) under view coordinates.
976
- * This position is computed with depth buffer.
977
- *
978
- * @param {THREE.Vector2} mouse position in view coordinates (in pixel), if it's null so it's view's center.
979
- * @param {THREE.Vector3} [target=THREE.Vector3()] target. the result will be copied into this Vector3. If not present a new one will be created.
980
- * @return {THREE.Vector3} the world position on the terrain in view's crs: referenceCrs.
981
- */
982
-
983
- getPickingPositionFromDepth(mouse) {
984
- let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Vector3();
985
- if (!this.tileLayer || this.tileLayer.level0Nodes.length == 0 || !this.tileLayer.level0Nodes[0]) {
986
- target = undefined;
987
- return;
988
- }
989
- const l = this.mainLoop;
990
- const viewPaused = l.scheduler.commandsWaitingExecutionCount() == 0 && l.renderingState == RENDERING_PAUSED;
991
- const g = l.gfxEngine;
992
- const dim = g.getWindowSize();
993
- mouse = mouse || dim.clone().multiplyScalar(0.5);
994
- mouse.x = Math.floor(mouse.x);
995
- mouse.y = Math.floor(mouse.y);
996
-
997
- // Render/Read to buffer
998
- let buffer;
999
- if (viewPaused) {
1000
- if (this.#fullSizeDepthBuffer.needsUpdate) {
1001
- this.readDepthBuffer(0, 0, dim.x, dim.y, this.#fullSizeDepthBuffer);
1002
- this.#fullSizeDepthBuffer.needsUpdate = false;
1003
- }
1004
- const id = ((dim.y - mouse.y - 1) * dim.x + mouse.x) * 4;
1005
- buffer = this.#fullSizeDepthBuffer.slice(id, id + 4);
1006
- } else {
1007
- buffer = this.readDepthBuffer(mouse.x, mouse.y, 1, 1, this.#pixelDepthBuffer);
1008
- }
1009
- screen.x = mouse.x / dim.x * 2 - 1;
1010
- screen.y = -(mouse.y / dim.y) * 2 + 1;
1011
- if (Capabilities.isLogDepthBufferSupported() && this.camera3D.type == 'PerspectiveCamera') {
1012
- // TODO: solve this part with gl_FragCoord_Z and unproject
1013
- // Origin
1014
- ray.origin.copy(this.camera3D.position);
1015
-
1016
- // Direction
1017
- ray.direction.set(screen.x, screen.y, 0.5);
1018
- // Unproject
1019
- matrix.multiplyMatrices(this.camera3D.matrixWorld, matrix.copy(this.camera3D.projectionMatrix).invert());
1020
- ray.direction.applyMatrix4(matrix);
1021
- ray.direction.sub(ray.origin);
1022
- direction.set(0, 0, 1.0);
1023
- direction.applyMatrix4(matrix);
1024
- direction.sub(ray.origin);
1025
- const angle = direction.angleTo(ray.direction);
1026
- const orthoZ = g.depthBufferRGBAValueToOrthoZ(buffer, this.camera3D);
1027
- const length = orthoZ / Math.cos(angle);
1028
- target.addVectors(this.camera3D.position, ray.direction.setLength(length));
1029
- } else {
1030
- const gl_FragCoord_Z = g.depthBufferRGBAValueToOrthoZ(buffer, this.camera3D);
1031
- target.set(screen.x, screen.y, gl_FragCoord_Z);
1032
- target.unproject(this.camera3D);
1033
- }
1034
- if (target.length() > 10000000) {
1035
- return undefined;
1036
- }
1037
- return target;
1038
- }
1039
-
1040
- /**
1041
- * Returns the world {@link Coordinates} of the terrain at given view coordinates.
1042
- *
1043
- * @param {THREE.Vector2|event} [mouse] The view coordinates at which the world coordinates must be returned. This
1044
- * parameter can also be set to a mouse event from which the view coordinates will be deducted. If not specified,
1045
- * it will be defaulted to the view's center coordinates.
1046
- * @param {Coordinates} [target] The result will be copied into this {@link Coordinates} in the coordinate reference
1047
- * system of the given coordinate. If not specified, a new {@link Coordinates} instance will be created (in the
1048
- * view referenceCrs).
1049
- *
1050
- * @returns {Coordinates} The world {@link Coordinates} of the terrain at the given view coordinates in the
1051
- * coordinate reference system of the target or in the view referenceCrs if no target is specified.
1052
- */
1053
- pickTerrainCoordinates(mouse) {
1054
- let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Coordinates(this.referenceCrs);
1055
- if (mouse instanceof Event) {
1056
- this.eventToViewCoords(mouse);
1057
- } else if (mouse && mouse.x !== undefined && mouse.y !== undefined) {
1058
- _eventCoords.copy(mouse);
1059
- } else {
1060
- _eventCoords.set(this.mainLoop.gfxEngine.width / 2, this.mainLoop.gfxEngine.height / 2);
1061
- }
1062
- this.getPickingPositionFromDepth(_eventCoords, positionVector);
1063
- coordinates.crs = this.referenceCrs;
1064
- coordinates.setFromVector3(positionVector);
1065
- coordinates.as(target.crs, target);
1066
- return target;
1067
- }
1068
-
1069
- /**
1070
- * Returns the world {@link Coordinates} of the terrain at given view coordinates.
1071
- *
1072
- * @param {THREE.Vector2|event} [mouse] The view coordinates at which the world coordinates must be
1073
- * returned. This parameter can also be set to a mouse event from
1074
- * which the view coordinates will be deducted. If not specified, it
1075
- * will be defaulted to the view's center coordinates.
1076
- * @param {Coordinates} [target] The result will be copied into this {@link Coordinates}. If not
1077
- * specified, a new {@link Coordinates} instance will be created.
1078
- *
1079
- * @returns {Coordinates} The world {@link Coordinates} of the terrain at the given view coordinates.
1080
- *
1081
- * @deprecated Use View#pickTerrainCoordinates instead.
1082
- */
1083
- pickCoordinates(mouse) {
1084
- let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Coordinates(this.referenceCrs);
1085
- console.warn('Deprecated, use View#pickTerrainCoordinates instead.');
1086
- return this.pickTerrainCoordinates(mouse, target);
1087
- }
1088
-
1089
- /**
1090
- * Resize the viewer.
1091
- *
1092
- * @param {number} [width=viewerDiv.clientWidth] - The width to resize the
1093
- * viewer with. By default it is the `clientWidth` of the `viewerDiv`.
1094
- * @param {number} [height=viewerDiv.clientHeight] - The height to resize
1095
- * the viewer with. By default it is the `clientHeight` of the `viewerDiv`.
1096
- */
1097
- resize(width, height) {
1098
- if (width < 0 || height < 0) {
1099
- console.warn(`Trying to resize the View with negative height (${height}) or width (${width}). Skipping resize.`);
1100
- return;
1101
- }
1102
- if (width == undefined) {
1103
- width = this.domElement.clientWidth;
1104
- }
1105
- if (height == undefined) {
1106
- height = this.domElement.clientHeight;
1107
- }
1108
- this.#fullSizeDepthBuffer = new Uint8Array(4 * width * height);
1109
- this.mainLoop.gfxEngine.onWindowResize(width, height);
1110
- if (width !== 0 && height !== 0) {
1111
- this.camera.resize(width, height);
1112
- this.notifyChange(this.camera3D);
1113
- }
1114
- }
1115
- }
1116
- export default View;