itowns 2.44.3-next.3 → 2.44.3-next.30

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 (92) hide show
  1. package/CODING.md +1 -1
  2. package/CONTRIBUTORS.md +1 -0
  3. package/dist/debug.js +1 -1
  4. package/dist/debug.js.map +1 -1
  5. package/dist/itowns.js +1 -1
  6. package/dist/itowns.js.LICENSE.txt +0 -2
  7. package/dist/itowns.js.map +1 -1
  8. package/dist/itowns_widgets.js +1 -1
  9. package/dist/itowns_widgets.js.map +1 -1
  10. package/examples/3dtiles_loader.html +109 -45
  11. package/examples/config.json +2 -10
  12. package/examples/entwine_3d_loader.html +3 -1
  13. package/examples/entwine_simple_loader.html +1 -1
  14. package/examples/images/itowns_logo.svg +123 -0
  15. package/examples/js/plugins/COGParser.js +1 -1
  16. package/examples/jsm/OGC3DTilesHelper.js +1 -1
  17. package/examples/layers/JSONLayers/GeoidMNT.json +3 -1
  18. package/examples/source_file_geojson_3d.html +0 -1
  19. package/examples/source_stream_wfs_raster.html +0 -7
  20. package/lib/Controls/GlobeControls.js +45 -28
  21. package/lib/Controls/StateControl.js +5 -2
  22. package/lib/Converter/Feature2Mesh.js +10 -4
  23. package/lib/Converter/Feature2Texture.js +3 -1
  24. package/lib/Converter/convertToTile.js +3 -8
  25. package/lib/Converter/textureConverter.js +3 -4
  26. package/lib/Core/Deprecated/Undeprecator.js +0 -1
  27. package/lib/Core/Feature.js +1 -2
  28. package/lib/Core/Geographic/Coordinates.js +143 -132
  29. package/lib/Core/Geographic/Crs.js +140 -145
  30. package/lib/Core/Geographic/Extent.js +72 -267
  31. package/lib/Core/Geographic/GeoidGrid.js +1 -1
  32. package/lib/Core/Math/Ellipsoid.js +62 -21
  33. package/lib/Core/Prefab/Globe/Atmosphere.js +4 -8
  34. package/lib/Core/Prefab/Globe/GlobeLayer.js +22 -15
  35. package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +111 -0
  36. package/lib/Core/Prefab/GlobeView.js +2 -7
  37. package/lib/Core/Prefab/Planar/PlanarLayer.js +17 -11
  38. package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +43 -43
  39. package/lib/Core/Prefab/TileBuilder.js +27 -32
  40. package/lib/Core/Prefab/computeBufferTileGeometry.js +189 -130
  41. package/lib/Core/Style.js +3 -3
  42. package/lib/Core/Tile/Tile.js +219 -0
  43. package/lib/Core/Tile/TileGrid.js +43 -0
  44. package/lib/Core/TileGeometry.js +112 -28
  45. package/lib/Core/TileMesh.js +3 -3
  46. package/lib/Core/View.js +15 -8
  47. package/lib/Layer/C3DTilesLayer.js +20 -16
  48. package/lib/Layer/ColorLayer.js +35 -9
  49. package/lib/Layer/CopcLayer.js +5 -0
  50. package/lib/Layer/ElevationLayer.js +39 -7
  51. package/lib/Layer/EntwinePointTileLayer.js +12 -5
  52. package/lib/Layer/FeatureGeometryLayer.js +20 -6
  53. package/lib/Layer/GeometryLayer.js +42 -11
  54. package/lib/Layer/LabelLayer.js +19 -9
  55. package/lib/Layer/Layer.js +83 -57
  56. package/lib/Layer/OGC3DTilesLayer.js +81 -30
  57. package/lib/Layer/OrientedImageLayer.js +11 -5
  58. package/lib/Layer/PointCloudLayer.js +74 -30
  59. package/lib/Layer/Potree2Layer.js +7 -2
  60. package/lib/Layer/PotreeLayer.js +8 -3
  61. package/lib/Layer/RasterLayer.js +12 -2
  62. package/lib/Layer/TiledGeometryLayer.js +69 -13
  63. package/lib/Main.js +2 -2
  64. package/lib/Parser/GeoJsonParser.js +1 -1
  65. package/lib/Parser/VectorTileParser.js +1 -1
  66. package/lib/Parser/XbilParser.js +14 -2
  67. package/lib/Provider/Fetcher.js +5 -1
  68. package/lib/Provider/URLBuilder.js +22 -11
  69. package/lib/Renderer/Camera.js +1 -1
  70. package/lib/Renderer/OBB.js +11 -13
  71. package/lib/Renderer/PointsMaterial.js +1 -1
  72. package/lib/Renderer/RasterTile.js +1 -2
  73. package/lib/Renderer/SphereHelper.js +0 -6
  74. package/lib/Source/CopcSource.js +13 -2
  75. package/lib/Source/EntwinePointTileSource.js +14 -4
  76. package/lib/Source/FileSource.js +1 -4
  77. package/lib/Source/Source.js +1 -4
  78. package/lib/Source/TMSSource.js +10 -9
  79. package/lib/Source/VectorTilesSource.js +3 -5
  80. package/lib/Source/WFSSource.js +15 -10
  81. package/lib/Source/WMSSource.js +56 -18
  82. package/lib/Source/WMTSSource.js +13 -7
  83. package/lib/Utils/CameraUtils.js +1 -1
  84. package/lib/Utils/gui/C3DTilesStyle.js +2 -3
  85. package/lib/Utils/placeObjectOnGround.js +0 -1
  86. package/package.json +13 -6
  87. package/examples/3dtiles_25d.html +0 -120
  88. package/examples/3dtiles_basic.html +0 -94
  89. package/examples/3dtiles_batch_table.html +0 -86
  90. package/examples/3dtiles_ion.html +0 -126
  91. package/examples/3dtiles_pointcloud.html +0 -95
  92. package/lib/Core/Prefab/Globe/BuilderEllipsoidTile.js +0 -110
@@ -168,17 +168,23 @@ class LabelLayer extends GeometryLayer {
168
168
  */
169
169
  constructor(id) {
170
170
  let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
171
- const domElement = config.domElement;
172
- delete config.domElement;
173
- super(id, config.object3d || new THREE.Group(), config);
171
+ const {
172
+ domElement,
173
+ performance = true,
174
+ forceClampToTerrain = false,
175
+ margin,
176
+ ...geometryConfig
177
+ } = config;
178
+ super(id, config.object3d || new THREE.Group(), geometryConfig);
174
179
  this.isLabelLayer = true;
175
180
  this.domElement = new DomNode();
176
181
  this.domElement.show();
177
182
  this.domElement.dom.id = `itowns-label-${this.id}`;
178
183
  this.buildExtent = true;
179
184
  this.crs = config.source.crs;
180
- this.performance = config.performance || true;
181
- this.forceClampToTerrain = config.forceClampToTerrain || false;
185
+ this.performance = performance;
186
+ this.forceClampToTerrain = forceClampToTerrain;
187
+ this.margin = margin;
182
188
  this.toHide = new THREE.Group();
183
189
  this.labelDomelement = domElement;
184
190
 
@@ -216,17 +222,21 @@ class LabelLayer extends GeometryLayer {
216
222
  *
217
223
  * @param {FeatureCollection} data - The FeatureCollection to read the
218
224
  * labels from.
219
- * @param {Extent} extent
225
+ * @param {Extent|Tile} extentOrTile
220
226
  *
221
227
  * @return {Label[]} An array containing all the created labels.
222
228
  */
223
- convert(data, extent) {
229
+ convert(data, extentOrTile) {
224
230
  const labels = [];
225
231
 
226
232
  // Converting the extent now is faster for further operation
227
- extent.as(data.crs, _extent);
233
+ if (extentOrTile.isExtent) {
234
+ extentOrTile.as(data.crs, _extent);
235
+ } else {
236
+ extentOrTile.toExtent(data.crs, _extent);
237
+ }
228
238
  coord.crs = data.crs;
229
- context.setZoom(extent.zoom);
239
+ context.setZoom(extentOrTile.zoom);
230
240
  data.features.forEach(f => {
231
241
  // TODO: add support for LINE and POLYGON
232
242
  if (f.type !== FEATURE_TYPES.POINT) {
@@ -90,62 +90,96 @@ class Layer extends THREE.EventDispatcher {
90
90
  */
91
91
  constructor(id) {
92
92
  let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
93
- /* istanbul ignore next */
94
- if (config.projection) {
95
- console.warn('Layer projection parameter is deprecated, use crs instead.');
96
- config.crs = config.crs || config.projection;
97
- }
98
- if (config.source === undefined || config.source === true) {
99
- throw new Error(`Layer ${id} needs Source`);
100
- }
93
+ const {
94
+ source,
95
+ name,
96
+ style = {},
97
+ subdivisionThreshold = 256,
98
+ addLabelLayer = false,
99
+ cacheLifeTime,
100
+ options = {},
101
+ updateStrategy,
102
+ zoom,
103
+ mergeFeatures = true,
104
+ crs
105
+ } = config;
101
106
  super();
107
+
108
+ /**
109
+ * @type {boolean}
110
+ * @readonly
111
+ */
102
112
  this.isLayer = true;
103
- if (config.style && !(config.style instanceof Style)) {
104
- if (typeof config.style.fill?.pattern === 'string') {
105
- console.warn('Using style.fill.pattern = { source: Img|url } is adviced');
106
- config.style.fill.pattern = {
107
- source: config.style.fill.pattern
108
- };
109
- }
110
- config.style = new Style(config.style);
111
- }
112
- this.style = config.style || new Style();
113
- this.subdivisionThreshold = config.subdivisionThreshold || 256;
114
- this.sizeDiagonalTexture = (2 * (this.subdivisionThreshold * this.subdivisionThreshold)) ** 0.5;
115
- Object.assign(this, config);
113
+
114
+ /**
115
+ * @type {string}
116
+ * @readonly
117
+ */
118
+ this.id = id;
116
119
  Object.defineProperty(this, 'id', {
117
- value: id,
118
120
  writable: false
119
121
  });
120
- // Default properties
121
- this.options = config.options || {};
122
- if (!this.updateStrategy) {
123
- this.updateStrategy = {
124
- type: STRATEGY_MIN_NETWORK_TRAFFIC,
125
- options: {}
126
- };
122
+
123
+ /**
124
+ * @type {string}
125
+ */
126
+ this.name = name;
127
+ if (source === undefined || source === true) {
128
+ throw new Error(`Layer ${id} needs Source`);
127
129
  }
128
- this.defineLayerProperty('frozen', false);
129
- if (config.zoom) {
130
- this.zoom = {
131
- max: config.zoom.max,
132
- min: config.zoom.min || 0
133
- };
134
- if (this.zoom.max == undefined) {
135
- this.zoom.max = Infinity;
130
+ /**
131
+ * @type {Source}
132
+ */
133
+ this.source = source || new Source({
134
+ url: 'none'
135
+ });
136
+ this.crs = crs;
137
+ if (style && !(style instanceof Style)) {
138
+ if (typeof style.fill?.pattern === 'string') {
139
+ console.warn('Using style.fill.pattern = { source: Img|url } is adviced');
140
+ style.fill.pattern = {
141
+ source: style.fill.pattern
142
+ };
136
143
  }
144
+ this.style = new Style(style);
137
145
  } else {
138
- this.zoom = {
139
- max: Infinity,
140
- min: 0
141
- };
146
+ this.style = style || new Style();
142
147
  }
148
+
149
+ /**
150
+ * @type {number}
151
+ */
152
+ this.subdivisionThreshold = subdivisionThreshold;
153
+ this.sizeDiagonalTexture = (2 * (this.subdivisionThreshold * this.subdivisionThreshold)) ** 0.5;
154
+ this.addLabelLayer = addLabelLayer;
155
+
156
+ // Default properties
157
+ this.options = options;
158
+ this.updateStrategy = updateStrategy ?? {
159
+ type: STRATEGY_MIN_NETWORK_TRAFFIC,
160
+ options: {}
161
+ };
162
+ this.defineLayerProperty('frozen', false);
163
+ this.zoom = {
164
+ min: zoom?.min ?? 0,
165
+ max: zoom?.max ?? Infinity
166
+ };
143
167
  this.info = new InfoLayer(this);
144
- this.source = this.source || new Source({
145
- url: 'none'
146
- });
168
+
169
+ /**
170
+ * @type {boolean}
171
+ */
147
172
  this.ready = false;
173
+
174
+ /**
175
+ * @type {Array<Promise<any>>}
176
+ * @protected
177
+ */
148
178
  this._promises = [];
179
+
180
+ /**
181
+ * @type {Promise<this>}
182
+ */
149
183
  this.whenReady = new Promise((re, rj) => {
150
184
  this._resolve = re;
151
185
  this._reject = rj;
@@ -157,11 +191,12 @@ class Layer extends THREE.EventDispatcher {
157
191
  return this;
158
192
  });
159
193
  this._promises.push(this.source.whenReady);
160
- this.cache = new Cache(config.cacheLifeTime);
161
- this.mergeFeatures = this.mergeFeatures === undefined ? true : config.mergeFeatures;
162
194
 
163
- // TODO: verify but this.source.filter seems be always undefined.
164
- this.filter = this.filter || this.source.filter;
195
+ /**
196
+ * @type {Cache}
197
+ */
198
+ this.cache = new Cache(cacheLifeTime);
199
+ this.mergeFeatures = mergeFeatures;
165
200
  }
166
201
  addInitializationStep() {
167
202
  // Possibility to add rejection handler, if it's necessary.
@@ -243,15 +278,6 @@ class Layer extends THREE.EventDispatcher {
243
278
  return data;
244
279
  }
245
280
 
246
- /**
247
- * Determines whether the specified feature is valid data.
248
- *
249
- * @param {Feature} feature The feature
250
- * @returns {Feature} the feature is returned if it's valided
251
- */
252
- // eslint-disable-next-line
253
- isValidData() {}
254
-
255
281
  /**
256
282
  * Remove and dispose all objects from layer.
257
283
  * @param {boolean} [clearCache=false] Whether to clear the layer cache or not
@@ -6,19 +6,20 @@ import { DRACOLoader } from "../ThreeExtended/loaders/DRACOLoader.js";
6
6
  import { KTX2Loader } from "../ThreeExtended/loaders/KTX2Loader.js";
7
7
  import ReferLayerProperties from "./ReferencingLayerProperties.js";
8
8
  import PointsMaterial, { PNTS_MODE, PNTS_SHAPE, PNTS_SIZE_MODE, ClassificationScheme } from "../Renderer/PointsMaterial.js";
9
+ import { VIEW_EVENTS } from "../Core/View.js";
9
10
  const _raycaster = new THREE.Raycaster();
10
11
 
12
+ // Stores lruCache, downloadQueue and parseQueue for each id of view {@link View}
13
+ // every time a tileset has been added
14
+ // https://github.com/iTowns/itowns/issues/2426
15
+ const viewers = {};
16
+
11
17
  // Internal instance of GLTFLoader, passed to 3d-tiles-renderer-js to support GLTF 1.0 and 2.0
12
18
  // Temporary exported to be used in deprecated B3dmParser
13
19
  export const itownsGLTFLoader = new iGLTFLoader();
14
20
  itownsGLTFLoader.register(() => new GLTFMeshFeaturesExtension());
15
21
  itownsGLTFLoader.register(() => new GLTFStructuralMetadataExtension());
16
22
  itownsGLTFLoader.register(() => new GLTFCesiumRTCExtension());
17
-
18
- // Instantiated by the first tileset. Used to share cache and download and parse queues between tilesets
19
- let lruCache = null;
20
- let downloadQueue = null;
21
- let parseQueue = null;
22
23
  export const OGC3DTILES_LAYER_EVENTS = {
23
24
  /**
24
25
  * Fired when a new root or child tile set is loaded
@@ -52,7 +53,19 @@ export const OGC3DTILES_LAYER_EVENTS = {
52
53
  * @property {Object} tile - the tile metadata from the tileset
53
54
  * @property {boolean} visible - the tile visible state
54
55
  */
55
- TILE_VISIBILITY_CHANGE: 'tile-visibility-change'
56
+ TILE_VISIBILITY_CHANGE: 'tile-visibility-change',
57
+ /**
58
+ * Fired when a new batch of tiles start loading (can be fired multiple times, e.g. when the camera moves and new tiles
59
+ * start loading)
60
+ * @event OGC3DTilesLayer#tiles-load-start
61
+ */
62
+ TILES_LOAD_START: 'tiles-load-start',
63
+ /**
64
+ * Fired when all visible tiles are loaded (can be fired multiple times, e.g. when the camera moves and new tiles
65
+ * are loaded)
66
+ * @event OGC3DTilesLayer#tiles-load-end
67
+ */
68
+ TILES_LOAD_END: 'tiles-load-end'
56
69
  };
57
70
 
58
71
  /**
@@ -92,9 +105,37 @@ export function enableKtx2Loader(path, renderer) {
92
105
  ktx2Loader.detectSupport(renderer);
93
106
  itownsGLTFLoader.setKTX2Loader(ktx2Loader);
94
107
  }
108
+
109
+ /**
110
+ * Enable loading 3D Tiles and GLTF with
111
+ * [meshopt](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Vendor/EXT_meshopt_compression/README.md) compression extension.
112
+ *
113
+ * @param {MeshOptDecoder.constructor} MeshOptDecoder - The Meshopt decoder
114
+ * module.
115
+ *
116
+ * @example
117
+ * import * as itowns from 'itowns';
118
+ * import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
119
+ *
120
+ * // Enable support of EXT_meshopt_compression
121
+ * itowns.enableMeshoptDecoder(MeshoptDecoder);
122
+ */
123
+ export function enableMeshoptDecoder(MeshOptDecoder) {
124
+ if (!MeshOptDecoder) {
125
+ throw new Error('MeshOptDecoder module is mandatory');
126
+ }
127
+ itownsGLTFLoader.setMeshoptDecoder(MeshOptDecoder);
128
+ }
95
129
  class OGC3DTilesLayer extends GeometryLayer {
96
130
  /**
97
131
  * Layer for [3D Tiles](https://www.ogc.org/standard/3dtiles/) datasets.
132
+ *
133
+ * Advanced configuration note: 3D Tiles rendering is delegated to 3DTilesRendererJS that exposes several
134
+ * configuration options accessible through the tilesRenderer property of this class. see the
135
+ * [3DTilesRendererJS doc](https://github.com/NASA-AMMOS/3DTilesRendererJS/blob/master/README.md). Also note that
136
+ * the cache is shared amongst 3D tiles layers and can be configured through tilesRenderer.lruCache (see the
137
+ * [following documentation](https://github.com/NASA-AMMOS/3DTilesRendererJS/blob/master/README.md#lrucache-1).
138
+ *
98
139
  * @extends Layer
99
140
  *
100
141
  * @param {String} id - unique layer id.
@@ -109,8 +150,8 @@ class OGC3DTilesLayer extends GeometryLayer {
109
150
  * @param {String} [config.pntsSizeMode= PNTS_SIZE_MODE.VALUE] {@link PointsMaterial} Point cloud size mode (passed to {@link PointsMaterial}).
110
151
  * Only 'VALUE' or 'ATTENUATED' are possible. VALUE use constant size, ATTENUATED compute size depending on distance
111
152
  * from point to camera.
112
- * @param {Number} [config.pntsMinAttenuatedSize=1] Minimum scale used by 'ATTENUATED' size mode.
113
- * @param {Number} [config.pntsMaxAttenuatedSize=7] Maximum scale used by 'ATTENUATED' size mode.
153
+ * @param {Number} [config.pntsMinAttenuatedSize=3] Minimum scale used by 'ATTENUATED' size mode.
154
+ * @param {Number} [config.pntsMaxAttenuatedSize=10] Maximum scale used by 'ATTENUATED' size mode.
114
155
  */
115
156
  constructor(id, config) {
116
157
  super(id, new THREE.Group(), {
@@ -133,8 +174,6 @@ class OGC3DTilesLayer extends GeometryLayer {
133
174
  }
134
175
  this.tilesRenderer.registerPlugin(new ImplicitTilingPlugin());
135
176
  this.tilesRenderer.manager.addHandler(/\.gltf$/, itownsGLTFLoader);
136
- this._setupCacheAndQueues();
137
- this._setupEvents();
138
177
  this.object3d.add(this.tilesRenderer.group);
139
178
 
140
179
  // Add an initialization step that is resolved when the root tileset is loaded (see this._setup below), meaning
@@ -169,29 +208,31 @@ class OGC3DTilesLayer extends GeometryLayer {
169
208
  this.pntsShape = config.pntsShape ?? PNTS_SHAPE.CIRCLE;
170
209
  this.classification = config.classification ?? ClassificationScheme.DEFAULT;
171
210
  this.pntsSizeMode = config.pntsSizeMode ?? PNTS_SIZE_MODE.VALUE;
172
- this.pntsMinAttenuatedSize = config.pntsMinAttenuatedSize || 1;
173
- this.pntsMaxAttenuatedSize = config.pntsMaxAttenuatedSize || 7;
211
+ this.pntsMinAttenuatedSize = config.pntsMinAttenuatedSize || 3;
212
+ this.pntsMaxAttenuatedSize = config.pntsMaxAttenuatedSize || 10;
174
213
  }
175
214
 
176
215
  /**
177
- * Sets the lruCache and download and parse queues so they are shared amongst all tilesets.
216
+ * Sets the lruCache and download and parse queues so they are shared amongst
217
+ * all tilesets from a same {@link View} view.
218
+ * @param {View} view - view associated to this layer.
178
219
  * @private
179
220
  */
180
- _setupCacheAndQueues() {
181
- if (lruCache === null) {
182
- lruCache = this.tilesRenderer.lruCache;
183
- } else {
184
- this.tilesRenderer.lruCache = lruCache;
185
- }
186
- if (downloadQueue === null) {
187
- downloadQueue = this.tilesRenderer.downloadQueue;
221
+ _setupCacheAndQueues(view) {
222
+ const id = view.id;
223
+ if (viewers[id]) {
224
+ this.tilesRenderer.lruCache = viewers[id].lruCache;
225
+ this.tilesRenderer.downloadQueue = viewers[id].downloadQueue;
226
+ this.tilesRenderer.parseQueue = viewers[id].parseQueue;
188
227
  } else {
189
- this.tilesRenderer.downloadQueue = downloadQueue;
190
- }
191
- if (parseQueue === null) {
192
- parseQueue = this.tilesRenderer.parseQueue;
193
- } else {
194
- this.tilesRenderer.parseQueue = parseQueue;
228
+ viewers[id] = {
229
+ lruCache: this.tilesRenderer.lruCache,
230
+ downloadQueue: this.tilesRenderer.downloadQueue,
231
+ parseQueue: this.tilesRenderer.parseQueue
232
+ };
233
+ view.addEventListener(VIEW_EVENTS.DISPOSED, evt => {
234
+ delete viewers[evt.target.id];
235
+ });
195
236
  }
196
237
  }
197
238
 
@@ -235,6 +276,9 @@ class OGC3DTilesLayer extends GeometryLayer {
235
276
  });
236
277
  view.notifyChange(this);
237
278
  });
279
+ this._setupCacheAndQueues(view);
280
+ this._setupEvents();
281
+
238
282
  // Start loading tileset and tiles
239
283
  this.tilesRenderer.update();
240
284
  }
@@ -312,7 +356,8 @@ class OGC3DTilesLayer extends GeometryLayer {
312
356
  const {
313
357
  face,
314
358
  index,
315
- object
359
+ object,
360
+ instanceId
316
361
  } = intersects[0];
317
362
 
318
363
  /** @type{number|null} */
@@ -320,7 +365,7 @@ class OGC3DTilesLayer extends GeometryLayer {
320
365
  if (object.isPoints && index) {
321
366
  batchId = object.geometry.getAttribute('_BATCHID')?.getX(index) ?? index;
322
367
  } else if (object.isMesh && face) {
323
- batchId = object.geometry.getAttribute('_BATCHID')?.getX(face.a);
368
+ batchId = object.geometry.getAttribute('_BATCHID')?.getX(face.a) ?? instanceId;
324
369
  }
325
370
  if (batchId === undefined) {
326
371
  return null;
@@ -350,7 +395,13 @@ class OGC3DTilesLayer extends GeometryLayer {
350
395
  _raycaster.near = camera.near;
351
396
  _raycaster.far = camera.far;
352
397
  _raycaster.firstHitOnly = true;
353
- _raycaster.intersectObject(this.tilesRenderer.group, true, target);
398
+ const picked = _raycaster.intersectObject(this.tilesRenderer.group, true);
399
+ // Store the layer of the picked object to conform to the interface of what's returned by Picking.js (used for
400
+ // other GeometryLayers
401
+ picked.forEach(p => {
402
+ p.layer = this;
403
+ });
404
+ target.push(...picked);
354
405
  return target;
355
406
  }
356
407
 
@@ -96,14 +96,20 @@ class OrientedImageLayer extends GeometryLayer {
96
96
  */
97
97
  constructor(id) {
98
98
  let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
99
- /* istanbul ignore next */
99
+ const {
100
+ backgroundDistance,
101
+ background = createBackground(backgroundDistance),
102
+ onPanoChanged = () => {},
103
+ getCamerasNameFromFeature = () => {},
104
+ ...geometryOptions
105
+ } = config;
100
106
  if (config.projection) {
101
107
  console.warn('OrientedImageLayer projection parameter is deprecated, use crs instead.');
102
108
  config.crs = config.crs || config.projection;
103
109
  }
104
- super(id, new THREE.Group(), config);
110
+ super(id, new THREE.Group(), geometryOptions);
105
111
  this.isOrientedImageLayer = true;
106
- this.background = config.background || createBackground(config.backgroundDistance);
112
+ this.background = background;
107
113
  if (this.background) {
108
114
  // Add layer id to easily identify the objects later on (e.g. to delete the geometries when deleting the layer)
109
115
  this.background.layer = this.background.layer ?? {};
@@ -115,10 +121,10 @@ class OrientedImageLayer extends GeometryLayer {
115
121
  this.currentPano = undefined;
116
122
 
117
123
  // store a callback to fire event when current panoramic change
118
- this.onPanoChanged = config.onPanoChanged || (() => {});
124
+ this.onPanoChanged = onPanoChanged;
119
125
 
120
126
  // function to get cameras name from panoramic feature
121
- this.getCamerasNameFromFeature = config.getCamerasNameFromFeature || (() => {});
127
+ this.getCamerasNameFromFeature = getCamerasNameFromFeature;
122
128
  const resolve = this.addInitializationStep();
123
129
  this.mergeFeatures = false;
124
130
  this.filteringExtent = false;
@@ -113,6 +113,8 @@ function changeAngleRange(layer) {
113
113
  * @property {number} [maxIntensityRange=1] - The maximal intensity of the
114
114
  * layer. Changing this value will affect the material, if it has the
115
115
  * corresponding uniform. The value is normalized between 0 and 1.
116
+ *
117
+ * @extends GeometryLayer
116
118
  */
117
119
  class PointCloudLayer extends GeometryLayer {
118
120
  /**
@@ -120,8 +122,6 @@ class PointCloudLayer extends GeometryLayer {
120
122
  * Constructs a new instance of a Point Cloud Layer. This should not be used
121
123
  * directly, but rather implemented using `extends`.
122
124
  *
123
- * @extends GeometryLayer
124
- *
125
125
  * @param {string} id - The id of the layer, that should be unique. It is
126
126
  * not mandatory, but an error will be emitted if this layer is added a
127
127
  * {@link View} that already has a layer going by that id.
@@ -130,40 +130,86 @@ class PointCloudLayer extends GeometryLayer {
130
130
  * contains three elements `name, protocol, extent`, these elements will be
131
131
  * available using `layer.name` or something else depending on the property
132
132
  * name. See the list of properties to know which one can be specified.
133
+ * @param {Source} config.source - Description and options of the source.
133
134
  */
134
135
  constructor(id) {
135
136
  let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
136
- super(id, config.object3d || new THREE.Group(), config);
137
+ const {
138
+ object3d = new THREE.Group(),
139
+ group = new THREE.Group(),
140
+ bboxes = new THREE.Group(),
141
+ octreeDepthLimit = -1,
142
+ pointBudget = 2000000,
143
+ pointSize = 2,
144
+ sseThreshold = 2,
145
+ minIntensityRange = 1,
146
+ maxIntensityRange = 65536,
147
+ minElevationRange = 0,
148
+ maxElevationRange = 1000,
149
+ minAngleRange = -90,
150
+ maxAngleRange = 90,
151
+ material = {},
152
+ mode = PNTS_MODE.COLOR,
153
+ ...geometryLayerConfig
154
+ } = config;
155
+ super(id, object3d, geometryLayerConfig);
156
+
157
+ /**
158
+ * @type {boolean}
159
+ * @readonly
160
+ */
137
161
  this.isPointCloudLayer = true;
138
162
  this.protocol = 'pointcloud';
139
- this.group = config.group || new THREE.Group();
163
+ this.group = group;
140
164
  this.object3d.add(this.group);
141
- this.bboxes = config.bboxes || new THREE.Group();
165
+ this.bboxes = bboxes || new THREE.Group();
142
166
  this.bboxes.visible = false;
143
167
  this.object3d.add(this.bboxes);
144
168
  this.group.updateMatrixWorld();
145
169
 
146
170
  // default config
147
- this.octreeDepthLimit = config.octreeDepthLimit || -1;
148
- this.pointBudget = config.pointBudget || 2000000;
149
- this.pointSize = config.pointSize === 0 || !isNaN(config.pointSize) ? config.pointSize : 4;
150
- this.sseThreshold = config.sseThreshold || 2;
151
- this.defineLayerProperty('minIntensityRange', config.minIntensityRange || 1, changeIntensityRange);
152
- this.defineLayerProperty('maxIntensityRange', config.maxIntensityRange || 65536, changeIntensityRange);
153
- this.defineLayerProperty('minElevationRange', config.minElevationRange || 0, changeElevationRange);
154
- this.defineLayerProperty('maxElevationRange', config.maxElevationRange || 1000, changeElevationRange);
155
- this.defineLayerProperty('minAngleRange', config.minAngleRange || -90, changeAngleRange);
156
- this.defineLayerProperty('maxAngleRange', config.maxAngleRange || 90, changeAngleRange);
157
- this.material = config.material || {};
171
+ /**
172
+ * @type {number}
173
+ */
174
+ this.octreeDepthLimit = octreeDepthLimit;
175
+
176
+ /**
177
+ * @type {number}
178
+ */
179
+ this.pointBudget = pointBudget;
180
+
181
+ /**
182
+ * @type {number}
183
+ */
184
+ this.pointSize = pointSize;
185
+
186
+ /**
187
+ * @type {number}
188
+ */
189
+ this.sseThreshold = sseThreshold;
190
+ this.defineLayerProperty('minIntensityRange', minIntensityRange, changeIntensityRange);
191
+ this.defineLayerProperty('maxIntensityRange', maxIntensityRange, changeIntensityRange);
192
+ this.defineLayerProperty('minElevationRange', minElevationRange, changeElevationRange);
193
+ this.defineLayerProperty('maxElevationRange', maxElevationRange, changeElevationRange);
194
+ this.defineLayerProperty('minAngleRange', minAngleRange, changeAngleRange);
195
+ this.defineLayerProperty('maxAngleRange', maxAngleRange, changeAngleRange);
196
+
197
+ /**
198
+ * @type {THREE.Material}
199
+ */
200
+ this.material = material;
158
201
  if (!this.material.isMaterial) {
159
- config.material = config.material || {};
160
- config.material.intensityRange = new THREE.Vector2(this.minIntensityRange, this.maxIntensityRange);
161
- config.material.elevationRange = new THREE.Vector2(this.minElevationRange, this.maxElevationRange);
162
- config.material.angleRange = new THREE.Vector2(this.minAngleRange, this.maxAngleRange);
163
- this.material = new PointsMaterial(config.material);
202
+ this.material.intensityRange = new THREE.Vector2(this.minIntensityRange, this.maxIntensityRange);
203
+ this.material.elevationRange = new THREE.Vector2(this.minElevationRange, this.maxElevationRange);
204
+ this.material.angleRange = new THREE.Vector2(this.minAngleRange, this.maxAngleRange);
205
+ this.material = new PointsMaterial(this.material);
164
206
  }
165
- this.material.defines = this.material.defines || {};
166
- this.mode = config.mode || PNTS_MODE.COLOR;
207
+ this.mode = mode || PNTS_MODE.COLOR;
208
+
209
+ /**
210
+ * @type {PointCloudNode | undefined}
211
+ */
212
+ this.root = undefined;
167
213
  }
168
214
  preUpdate(context, changeSources) {
169
215
  // See https://cesiumjs.org/hosted-apps/massiveworlds/downloads/Ring/WorldScaleTerrainRendering.pptx
@@ -245,9 +291,6 @@ class PointCloudLayer extends GeometryLayer {
245
291
  redraw: true,
246
292
  earlyDropFunction: cmd => !cmd.requester.visible || !this.visible
247
293
  }).then(pts => {
248
- if (this.onPointsCreated) {
249
- this.onPointsCreated(layer, pts);
250
- }
251
294
  elt.obj = pts;
252
295
  // store tightbbox to avoid ping-pong (bbox = larger => visible, tight => invisible)
253
296
  elt.tightbbox = pts.tightbbox;
@@ -256,11 +299,12 @@ class PointCloudLayer extends GeometryLayer {
256
299
  // be added nor cleaned
257
300
  this.group.add(elt.obj);
258
301
  elt.obj.updateMatrixWorld(true);
259
- elt.promise = null;
260
- }, err => {
261
- if (err.isCancelledCommandException) {
262
- elt.promise = null;
302
+ }).catch(err => {
303
+ if (!err.isCancelledCommandException) {
304
+ return err;
263
305
  }
306
+ }).finally(() => {
307
+ elt.promise = null;
264
308
  });
265
309
  }
266
310
  }
@@ -99,13 +99,13 @@ function parseAttributes(jsonAttributes) {
99
99
  * @property {boolean} isPotreeLayer - Used to checkout whether this layer
100
100
  * is a Potree2Layer. Default is `true`. You should not change this, as it is
101
101
  * used internally for optimisation.
102
+ *
103
+ * @extends PointCloudLayer
102
104
  */
103
105
  class Potree2Layer extends PointCloudLayer {
104
106
  /**
105
107
  * Constructs a new instance of Potree2 layer.
106
108
  *
107
- * @extends PointCloudLayer
108
- *
109
109
  * @example
110
110
  * // Create a new point cloud layer
111
111
  * const points = new Potree2Layer('points',
@@ -132,6 +132,11 @@ class Potree2Layer extends PointCloudLayer {
132
132
  */
133
133
  constructor(id, config) {
134
134
  super(id, config);
135
+
136
+ /**
137
+ * @type {boolean}
138
+ * @readonly
139
+ */
135
140
  this.isPotreeLayer = true;
136
141
  const resolve = this.addInitializationStep();
137
142
  this.source.whenReady.then(metadata => {
@@ -10,13 +10,13 @@ bboxMesh.geometry.boundingBox = box3;
10
10
  * @property {boolean} isPotreeLayer - Used to checkout whether this layer
11
11
  * is a PotreeLayer. Default is `true`. You should not change this, as it is
12
12
  * used internally for optimisation.
13
+ *
14
+ * @extends PointCloudLayer
13
15
  */
14
16
  class PotreeLayer extends PointCloudLayer {
15
17
  /**
16
18
  * Constructs a new instance of Potree layer.
17
19
  *
18
- * @extends PointCloudLayer
19
- *
20
20
  * @example
21
21
  * // Create a new point cloud layer
22
22
  * const points = new PotreeLayer('points',
@@ -37,12 +37,17 @@ class PotreeLayer extends PointCloudLayer {
37
37
  * contains three elements `name, protocol, extent`, these elements will be
38
38
  * available using `layer.name` or something else depending on the property
39
39
  * name. See the list of properties to know which one can be specified.
40
- * @param {string} [config.crs=ESPG:4326] - The CRS of the {@link View} this
40
+ * @param {string} [config.crs='ESPG:4326'] - The CRS of the {@link View} this
41
41
  * layer will be attached to. This is used to determine the extent of this
42
42
  * layer. Default to `EPSG:4326`.
43
43
  */
44
44
  constructor(id, config) {
45
45
  super(id, config);
46
+
47
+ /**
48
+ * @type {boolean}
49
+ * @readonly
50
+ */
46
51
  this.isPotreeLayer = true;
47
52
  const resolve = this.addInitializationStep();
48
53
  this.source.whenReady.then(cloud => {