itowns 2.44.3-next.8 → 2.45.0

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