itowns 2.42.1-next.4 → 2.42.1-next.6

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.
@@ -64,10 +64,17 @@
64
64
  }
65
65
 
66
66
  function readEPTURL() {
67
- var url = document.getElementById('ept_url').value || new URL(location.href).searchParams.get('ept');
67
+ const urlParams = new URL(location.href).searchParams
68
+ var url = document.getElementById('ept_url').value || urlParams.get('ept');
68
69
 
69
70
  if (url) {
70
- loadEPT(url);
71
+ const options = {};
72
+ urlParams.keys().forEach(key => {
73
+ if (key !== 'ept') {
74
+ options[key] = parseInt(urlParams.get(key), 10);
75
+ }
76
+ });
77
+ loadEPT(url, options);
71
78
 
72
79
  document.getElementById('share').innerHTML = '<a href="' +
73
80
  location.href.replace(location.search, '') +
@@ -77,7 +84,7 @@
77
84
  }
78
85
  }
79
86
 
80
- function loadEPT(url) {
87
+ function loadEPT(url, options) {
81
88
  eptSource = new itowns.EntwinePointTileSource({ url });
82
89
 
83
90
  if (eptLayer) {
@@ -87,14 +94,17 @@
87
94
  eptLayer.delete();
88
95
  }
89
96
 
90
- eptLayer = new itowns.EntwinePointTileLayer('Entwine Point Tile', {
97
+ const config = {
91
98
  source: eptSource,
92
99
  crs: view.referenceCrs,
93
- });
100
+ ...options,
101
+ }
102
+ eptLayer = new itowns.EntwinePointTileLayer('Entwine Point Tile', config);
94
103
 
95
104
  view.addLayer(eptLayer).then(onLayerReady);
96
105
 
97
- debug.PotreeDebug.initTools(view, eptLayer, debugGui);
106
+ eptLayer.whenReady
107
+ .then(() => debug.PotreeDebug.initTools(view, eptLayer, debugGui));
98
108
 
99
109
  function dblClickHandler(event) {
100
110
  var pick = view.pickObjectsAt(event, 5, eptLayer);
@@ -59,8 +59,6 @@
59
59
  this.updateMatrixWorld();
60
60
  }
61
61
 
62
- var waypointGeometry = new itowns.THREE.BoxGeometry(1, 1, 80);
63
- var waypointMaterial = new itowns.THREE.MeshBasicMaterial({ color: 0xffffff });
64
62
  const style = {
65
63
  stroke: {
66
64
  color: 'red',
@@ -70,6 +68,8 @@
70
68
  color: 'white',
71
69
  }
72
70
  };
71
+ var waypointGeometry = new itowns.THREE.BoxGeometry(1, 1, 80);
72
+ var waypointMaterial = new itowns.THREE.MeshBasicMaterial({ color: 0xffffff });
73
73
  // Listen for globe full initialisation event
74
74
  view.addEventListener(itowns.GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, function () {
75
75
  console.info('Globe initialized');
@@ -24,8 +24,8 @@ let style;
24
24
  const dim_ref = new THREE.Vector2();
25
25
  const dim = new THREE.Vector2();
26
26
  const normal = new THREE.Vector3();
27
- const base = new THREE.Vector3();
28
- const extrusion = new THREE.Vector3();
27
+ const baseCoord = new THREE.Vector3();
28
+ const topCoord = new THREE.Vector3();
29
29
  const inverseScale = new THREE.Vector3();
30
30
  const extent = new _Extent.default('EPSG:4326', 0, 0, 0, 0);
31
31
  const _color = new THREE.Color();
@@ -44,13 +44,6 @@ class FeatureMesh extends THREE.Group {
44
44
  this.#collection = new THREE.Group().add(this.meshes);
45
45
  this.#collection.quaternion.copy(collection.quaternion);
46
46
  this.#collection.position.copy(collection.position);
47
- if (collection.crs == 'EPSG:4978') {
48
- normal.copy(collection.center.geodesicNormal);
49
- } else {
50
- normal.set(0, 0, 1);
51
- }
52
- normal.multiplyScalar(collection.center.z);
53
- this.#collection.position.sub(normal);
54
47
  this.#collection.scale.copy(collection.scale);
55
48
  this.#collection.updateMatrix();
56
49
  this.#originalCrs = collection.crs;
@@ -194,21 +187,27 @@ function featureToPoint(feature, options) {
194
187
  if (feature.normals) {
195
188
  normal.fromArray(feature.normals, v).multiply(inverseScale);
196
189
  }
197
- coord.copy(context.setLocalCoordinatesFromArray(feature.vertices, v));
190
+ const localCoord = context.setLocalCoordinatesFromArray(feature.vertices, v);
198
191
  style.setContext(context);
199
192
  const {
200
193
  base_altitude,
201
194
  color,
202
195
  radius
203
196
  } = style.point;
204
- coord.z = 0;
205
- if (!pointMaterialSize.includes(radius)) {
206
- pointMaterialSize.push(radius);
197
+ coord.copy(localCoord).applyMatrix4(context.collection.matrixWorld);
198
+ if (coord.crs == 'EPSG:4978') {
199
+ // altitude convertion from geocentered to elevation (from ground)
200
+ coord.as('EPSG:4326', coord);
207
201
  }
208
202
 
209
- // populate vertices
210
- base.copy(normal).multiplyScalar(base_altitude).add(coord).toArray(vertices, v);
203
+ // Calculate the new coordinates using the elevation shift (baseCoord)
204
+ baseCoord.copy(normal).multiplyScalar(base_altitude - coord.z).add(localCoord)
205
+ // and update the geometry buffer (vertices).
206
+ .toArray(vertices, v);
211
207
  toColor(color).multiplyScalar(255).toArray(colors, v);
208
+ if (!pointMaterialSize.includes(radius)) {
209
+ pointMaterialSize.push(radius);
210
+ }
212
211
  batchIds[j] = id;
213
212
  }
214
213
  featureId++;
@@ -233,7 +232,6 @@ function featureToLine(feature, options) {
233
232
  let featureId = 0;
234
233
  const vertices = new Float32Array(ptsIn.length);
235
234
  const geom = new THREE.BufferGeometry();
236
- geom.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
237
235
  const lineMaterialWidth = [];
238
236
  context.setFeature(feature);
239
237
  const countIndices = (count - feature.geometries.length) * 2;
@@ -265,21 +263,27 @@ function featureToLine(feature, options) {
265
263
  if (feature.normals) {
266
264
  normal.fromArray(feature.normals, v).multiply(inverseScale);
267
265
  }
268
- coord.copy(context.setLocalCoordinatesFromArray(feature.vertices, v));
266
+ const localCoord = context.setLocalCoordinatesFromArray(feature.vertices, v);
269
267
  style.setContext(context);
270
268
  const {
271
269
  base_altitude,
272
270
  color,
273
271
  width
274
272
  } = style.stroke;
275
- coord.z = 0;
276
- if (!lineMaterialWidth.includes(width)) {
277
- lineMaterialWidth.push(width);
273
+ coord.copy(localCoord).applyMatrix4(context.collection.matrixWorld);
274
+ if (coord.crs == 'EPSG:4978') {
275
+ // altitude convertion from geocentered to elevation (from ground)
276
+ coord.as('EPSG:4326', coord);
278
277
  }
279
278
 
280
- // populate geometry buffers
281
- base.copy(normal).multiplyScalar(base_altitude).add(coord).toArray(vertices, v);
279
+ // Calculate the new coordinates using the elevation shift (baseCoord)
280
+ baseCoord.copy(normal).multiplyScalar(base_altitude - coord.z).add(localCoord)
281
+ // and update the geometry buffer (vertices).
282
+ .toArray(vertices, v);
282
283
  toColor(color).multiplyScalar(255).toArray(colors, v);
284
+ if (!lineMaterialWidth.includes(width)) {
285
+ lineMaterialWidth.push(width);
286
+ }
283
287
  batchIds[j] = id;
284
288
  }
285
289
  featureId++;
@@ -289,6 +293,7 @@ function featureToLine(feature, options) {
289
293
  // TODO CREATE material for each feature
290
294
  console.warn('Too many differents stroke.width, only the first one will be used');
291
295
  }
296
+ geom.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
292
297
  geom.setAttribute('color', new THREE.BufferAttribute(colors, 3, true));
293
298
  geom.setAttribute('batchId', new THREE.BufferAttribute(batchIds, 1));
294
299
  geom.setIndex(new THREE.BufferAttribute(indices, 1));
@@ -320,18 +325,24 @@ function featureToPolygon(feature, options) {
320
325
  if (feature.normals) {
321
326
  normal.fromArray(feature.normals, i).multiply(inverseScale);
322
327
  }
323
- coord.copy(context.setLocalCoordinatesFromArray(feature.vertices, i));
328
+ const localCoord = context.setLocalCoordinatesFromArray(feature.vertices, i);
324
329
  style.setContext(context);
325
330
  const {
326
331
  base_altitude,
327
332
  color
328
333
  } = style.fill;
329
- coord.z = 0;
334
+ coord.copy(localCoord).applyMatrix4(context.collection.matrixWorld);
335
+ if (coord.crs == 'EPSG:4978') {
336
+ // altitude convertion from geocentered to elevation (from ground)
337
+ coord.as('EPSG:4326', coord);
338
+ }
330
339
 
331
- // populate geometry buffers
332
- base.copy(normal).multiplyScalar(base_altitude).add(coord).toArray(vertices, i);
333
- batchIds[b] = id;
340
+ // Calculate the new coordinates using the elevation shift (baseCoord)
341
+ baseCoord.copy(normal).multiplyScalar(base_altitude - coord.z).add(localCoord)
342
+ // and update the geometry buffer (vertices).
343
+ .toArray(vertices, i);
334
344
  toColor(color).multiplyScalar(255).toArray(colors, i);
345
+ batchIds[b] = id;
335
346
  }
336
347
  featureId++;
337
348
  const geomVertices = vertices.slice(start * 3, end * 3);
@@ -386,21 +397,27 @@ function featureToExtrudedPolygon(feature, options) {
386
397
  if (feature.normals) {
387
398
  normal.fromArray(feature.normals, i).multiply(inverseScale);
388
399
  }
389
- coord.copy(context.setLocalCoordinatesFromArray(ptsIn, i));
400
+ const localCoord = context.setLocalCoordinatesFromArray(ptsIn, i);
390
401
  style.setContext(context);
391
402
  const {
392
403
  base_altitude,
393
404
  extrusion_height,
394
405
  color
395
406
  } = style.fill;
396
- coord.z = 0;
407
+ coord.copy(localCoord).applyMatrix4(context.collection.matrixWorld);
408
+ if (coord.crs == 'EPSG:4978') {
409
+ // altitude convertion from geocentered to elevation (from ground)
410
+ coord.as('EPSG:4326', coord);
411
+ }
397
412
 
398
- // populate base geometry buffers
399
- base.copy(normal).multiplyScalar(base_altitude).add(coord).toArray(vertices, i);
413
+ // Calculate the new base coordinates using the elevation shift (baseCoord)
414
+ baseCoord.copy(normal).multiplyScalar(base_altitude - coord.z).add(localCoord)
415
+ // and update the geometry buffer (vertices).
416
+ .toArray(vertices, i);
400
417
  batchIds[b] = id;
401
418
 
402
419
  // populate top geometry buffers
403
- extrusion.copy(normal).multiplyScalar(extrusion_height).add(base).toArray(vertices, t);
420
+ topCoord.copy(normal).multiplyScalar(extrusion_height).add(baseCoord).toArray(vertices, t);
404
421
  batchIds[b + totalVertices] = id;
405
422
 
406
423
  // coloring base and top mesh
package/lib/Core/Style.js CHANGED
@@ -24,8 +24,8 @@ const matrix = svg.createSVGMatrix();
24
24
  const inv255 = 1 / 255;
25
25
  const canvas = typeof document !== 'undefined' ? document.createElement('canvas') : {};
26
26
  function baseAltitudeDefault(properties, ctx) {
27
- var _ctx$coordinates, _ctx$collection, _ctx$collection$cente;
28
- return (ctx === null || ctx === void 0 ? void 0 : (_ctx$coordinates = ctx.coordinates) === null || _ctx$coordinates === void 0 ? void 0 : _ctx$coordinates.z) || (ctx === null || ctx === void 0 ? void 0 : (_ctx$collection = ctx.collection) === null || _ctx$collection === void 0 ? void 0 : (_ctx$collection$cente = _ctx$collection.center) === null || _ctx$collection$cente === void 0 ? void 0 : _ctx$collection$cente.z) || 0;
27
+ var _ctx$coordinates;
28
+ return (ctx === null || ctx === void 0 ? void 0 : (_ctx$coordinates = ctx.coordinates) === null || _ctx$coordinates === void 0 ? void 0 : _ctx$coordinates.z) || 0;
29
29
  }
30
30
  function readExpression(property, ctx) {
31
31
  if (property != undefined) {
@@ -60,6 +60,8 @@ class EntwinePointTileLayer extends _PointCloudLayer.default {
60
60
  this.root = new _EntwinePointTileNode.default(0, 0, 0, 0, this, -1);
61
61
  this.root.bbox.min.fromArray(this.source.boundsConforming, 0);
62
62
  this.root.bbox.max.fromArray(this.source.boundsConforming, 3);
63
+ this.minElevationRange = this.source.boundsConforming[2];
64
+ this.maxElevationRange = this.source.boundsConforming[5];
63
65
  this.extent = _Extent.default.fromBox3(config.crs || 'EPSG:4326', this.root.bbox);
64
66
  return this.root.loadOctree().then(resolve);
65
67
  });
@@ -82,9 +82,16 @@ function markForDeletion(elt) {
82
82
  }
83
83
  }
84
84
  function changeIntensityRange(layer) {
85
- if (layer.material.intensityRange) {
86
- layer.material.intensityRange.set(layer.minIntensityRange, layer.maxIntensityRange);
87
- }
85
+ var _layer$material$inten;
86
+ (_layer$material$inten = layer.material.intensityRange) === null || _layer$material$inten === void 0 ? void 0 : _layer$material$inten.set(layer.minIntensityRange, layer.maxIntensityRange);
87
+ }
88
+ function changeElevationRange(layer) {
89
+ var _layer$material$eleva;
90
+ (_layer$material$eleva = layer.material.elevationRange) === null || _layer$material$eleva === void 0 ? void 0 : _layer$material$eleva.set(layer.minElevationRange, layer.maxElevationRange);
91
+ }
92
+ function changeAngleRange(layer) {
93
+ var _layer$material$angle;
94
+ (_layer$material$angle = layer.material.angleRange) === null || _layer$material$angle === void 0 ? void 0 : _layer$material$angle.set(layer.minAngleRange, layer.maxAngleRange);
88
95
  }
89
96
 
90
97
  /**
@@ -154,12 +161,18 @@ class PointCloudLayer extends _GeometryLayer.default {
154
161
  this.pointBudget = config.pointBudget || 2000000;
155
162
  this.pointSize = config.pointSize === 0 || !isNaN(config.pointSize) ? config.pointSize : 4;
156
163
  this.sseThreshold = config.sseThreshold || 2;
157
- this.defineLayerProperty('minIntensityRange', config.minIntensityRange || 0, changeIntensityRange);
158
- this.defineLayerProperty('maxIntensityRange', config.maxIntensityRange || 1, changeIntensityRange);
164
+ this.defineLayerProperty('minIntensityRange', config.minIntensityRange || 1, changeIntensityRange);
165
+ this.defineLayerProperty('maxIntensityRange', config.maxIntensityRange || 65536, changeIntensityRange);
166
+ this.defineLayerProperty('minElevationRange', config.minElevationRange || 0, changeElevationRange);
167
+ this.defineLayerProperty('maxElevationRange', config.maxElevationRange || 1000, changeElevationRange);
168
+ this.defineLayerProperty('minAngleRange', config.minAngleRange || -90, changeAngleRange);
169
+ this.defineLayerProperty('maxAngleRange', config.maxAngleRange || 90, changeAngleRange);
159
170
  this.material = config.material || {};
160
171
  if (!this.material.isMaterial) {
161
172
  config.material = config.material || {};
162
173
  config.material.intensityRange = new THREE.Vector2(this.minIntensityRange, this.maxIntensityRange);
174
+ config.material.elevationRange = new THREE.Vector2(this.minElevationRange, this.maxElevationRange);
175
+ config.material.angleRange = new THREE.Vector2(this.minAngleRange, this.maxAngleRange);
163
176
  this.material = new _PointsMaterial.default(config.material);
164
177
  }
165
178
  this.material.defines = this.material.defines || {};
@@ -51,6 +51,7 @@ class LASLoader {
51
51
  const getClassification = view.getter('Classification');
52
52
  const getPointSourceID = view.getter('PointSourceId');
53
53
  const getColor = view.dimensions.Red ? ['Red', 'Green', 'Blue'].map(view.getter) : undefined;
54
+ const getScanAngle = view.getter('ScanAngle');
54
55
  const positions = new Float32Array(view.pointCount * 3);
55
56
  const intensities = new Uint16Array(view.pointCount);
56
57
  const returnNumbers = new Uint8Array(view.pointCount);
@@ -58,6 +59,14 @@ class LASLoader {
58
59
  const classifications = new Uint8Array(view.pointCount);
59
60
  const pointSourceIDs = new Uint16Array(view.pointCount);
60
61
  const colors = getColor ? new Uint8Array(view.pointCount * 4) : undefined;
62
+ /*
63
+ As described by the LAS spec, Scan Angle is encoded:
64
+ - as signed char in a valid range from -90 to +90 (degrees) prior to the LAS 1.4 Point Data Record Formats (PDRF) 6
65
+ - as a signed short in a valid range from -30 000 to +30 000. Those values represents scan angles from -180 to +180
66
+ degrees with an increment of 0.006 for PDRF >= 6.
67
+ The copc.js library does the degree convertion and stores it as a `Float32`.
68
+ */
69
+ const scanAngles = new Float32Array(view.pointCount);
61
70
  for (let i = 0; i < view.pointCount; i++) {
62
71
  // `getPosition` apply scale and offset transform to the X, Y, Z
63
72
  // values. See https://github.com/connormanning/copc.js/blob/master/src/las/extractor.ts.
@@ -85,6 +94,7 @@ class LASLoader {
85
94
  }
86
95
  classifications[i] = getClassification(i);
87
96
  pointSourceIDs[i] = getPointSourceID(i);
97
+ scanAngles[i] = getScanAngle(i);
88
98
  }
89
99
  return {
90
100
  position: positions,
@@ -93,7 +103,8 @@ class LASLoader {
93
103
  numberOfReturns,
94
104
  classification: classifications,
95
105
  pointSourceID: pointSourceIDs,
96
- color: colors
106
+ color: colors,
107
+ scanAngle: scanAngles
97
108
  };
98
109
  }
99
110
 
@@ -58,13 +58,13 @@ var _default = {
58
58
  geometry.userData = parsedData.header;
59
59
  const positionBuffer = new THREE.BufferAttribute(attributes.position, 3);
60
60
  geometry.setAttribute('position', positionBuffer);
61
- const intensityBuffer = new THREE.BufferAttribute(attributes.intensity, 1, true);
61
+ const intensityBuffer = new THREE.BufferAttribute(attributes.intensity, 1);
62
62
  geometry.setAttribute('intensity', intensityBuffer);
63
63
  const returnNumber = new THREE.BufferAttribute(attributes.returnNumber, 1);
64
64
  geometry.setAttribute('returnNumber', returnNumber);
65
65
  const numberOfReturns = new THREE.BufferAttribute(attributes.numberOfReturns, 1);
66
66
  geometry.setAttribute('numberOfReturns', numberOfReturns);
67
- const classBuffer = new THREE.BufferAttribute(attributes.classification, 1, true);
67
+ const classBuffer = new THREE.BufferAttribute(attributes.classification, 1);
68
68
  geometry.setAttribute('classification', classBuffer);
69
69
  const pointSourceID = new THREE.BufferAttribute(attributes.pointSourceID, 1);
70
70
  geometry.setAttribute('pointSourceID', pointSourceID);
@@ -72,6 +72,8 @@ var _default = {
72
72
  const colorBuffer = new THREE.BufferAttribute(attributes.color, 4, true);
73
73
  geometry.setAttribute('color', colorBuffer);
74
74
  }
75
+ const scanAngle = new THREE.BufferAttribute(attributes.scanAngle, 1);
76
+ geometry.setAttribute('scanAngle', scanAngle);
75
77
  geometry.computeBoundingBox();
76
78
  return geometry;
77
79
  });