itowns 2.34.0 → 2.36.2

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 (68) hide show
  1. package/CONTRIBUTORS.md +1 -0
  2. package/changelog.md +150 -0
  3. package/dist/debug.js +2 -16
  4. package/dist/debug.js.LICENSE.txt +6 -0
  5. package/dist/debug.js.map +1 -1
  6. package/dist/itowns.js +2 -19
  7. package/dist/itowns.js.LICENSE.txt +28 -0
  8. package/dist/itowns.js.map +1 -1
  9. package/examples/3dtiles_basic.html +2 -2
  10. package/examples/config.json +2 -1
  11. package/examples/js/plugins/CSVnVRTParser.js +0 -1
  12. package/examples/layers/JSONLayers/Administrative.json +1 -1
  13. package/examples/layers/JSONLayers/Cada.json +1 -1
  14. package/examples/layers/JSONLayers/EtatMajor.json +1 -1
  15. package/examples/layers/JSONLayers/IGN_MNT.json +1 -1
  16. package/examples/layers/JSONLayers/IGN_MNT_HIGHRES.json +1 -1
  17. package/examples/layers/JSONLayers/Ortho.json +1 -1
  18. package/examples/layers/JSONLayers/WORLD_DTM.json +1 -1
  19. package/examples/misc_camera_traveling.html +148 -0
  20. package/examples/misc_custom_label.html +0 -2
  21. package/examples/plugins_vrt.html +0 -1
  22. package/examples/source_file_geojson_raster.html +0 -3
  23. package/examples/source_file_shapefile.html +0 -1
  24. package/examples/source_stream_wfs_25d.html +8 -16
  25. package/examples/vector_tile_raster_2d.html +2 -2
  26. package/examples/vector_tile_raster_3d.html +2 -2
  27. package/examples/view_25d_map.html +28 -0
  28. package/examples/view_multi_25d.html +1 -1
  29. package/lib/Controls/FirstPersonControls.js +12 -14
  30. package/lib/Controls/FlyControls.js +2 -10
  31. package/lib/Controls/GlobeControls.js +231 -303
  32. package/lib/Controls/PlanarControls.js +5 -16
  33. package/lib/Controls/StateControl.js +362 -96
  34. package/lib/Converter/Feature2Mesh.js +20 -5
  35. package/lib/Converter/Feature2Texture.js +2 -2
  36. package/lib/Converter/convertToTile.js +1 -1
  37. package/lib/Core/AnimationPlayer.js +15 -0
  38. package/lib/Core/Feature.js +39 -38
  39. package/lib/Core/Geographic/Coordinates.js +56 -0
  40. package/lib/Core/Geographic/Crs.js +15 -0
  41. package/lib/Core/Geographic/Extent.js +99 -11
  42. package/lib/Core/Label.js +1 -1
  43. package/lib/Core/Math/Ellipsoid.js +26 -8
  44. package/lib/Core/Prefab/Globe/BuilderEllipsoidTile.js +1 -1
  45. package/lib/Core/Prefab/PlanarView.js +1 -1
  46. package/lib/Core/Style.js +1 -0
  47. package/lib/Core/TileMesh.js +3 -2
  48. package/lib/Core/View.js +3 -3
  49. package/lib/Layer/ElevationLayer.js +9 -16
  50. package/lib/Layer/LabelLayer.js +7 -1
  51. package/lib/Main.js +1 -1
  52. package/lib/Parser/ShapefileParser.js +1 -2
  53. package/lib/Parser/VectorTileParser.js +1 -1
  54. package/lib/Process/3dTilesProcessing.js +8 -8
  55. package/lib/Process/FeatureProcessing.js +1 -2
  56. package/lib/Process/ObjectRemovalHelper.js +5 -2
  57. package/lib/Renderer/Label2DRenderer.js +15 -11
  58. package/lib/Renderer/LayeredMaterial.js +2 -1
  59. package/lib/Renderer/OBB.js +2 -2
  60. package/lib/Renderer/RasterTile.js +22 -4
  61. package/lib/Renderer/Shader/ShaderChunk.js +3 -3
  62. package/lib/Renderer/c3DEngine.js +14 -2
  63. package/lib/Source/FileSource.js +2 -7
  64. package/lib/Source/VectorTilesSource.js +19 -0
  65. package/lib/ThreeExtended/loaders/GLTFLoader.js +320 -76
  66. package/lib/Utils/CameraUtils.js +8 -8
  67. package/lib/Utils/DEMUtils.js +2 -2
  68. package/package.json +29 -29
@@ -176,7 +176,7 @@ function drawPoint(ctx, x, y) {
176
176
  var coord = new _Coordinates["default"]('EPSG:4326', 0, 0, 0);
177
177
 
178
178
  function drawFeature(ctx, feature, extent, style, invCtxScale) {
179
- var extentDim = extent.dimensions();
179
+ var extentDim = extent.planarDimensions();
180
180
  var scaleRadius = extentDim.x / ctx.canvas.width;
181
181
  var globals = {
182
182
  zoom: extent.zoom
@@ -259,7 +259,7 @@ var _default = {
259
259
  if (collection) {
260
260
  // A texture is instancied drawn canvas
261
261
  // origin and dimension are used to transform the feature's coordinates to canvas's space
262
- extent.dimensions(dimension);
262
+ extent.planarDimensions(dimension);
263
263
  var c = document.createElement('canvas');
264
264
  coord.crs = extent.crs;
265
265
  c.width = sizeTexture;
@@ -41,7 +41,7 @@ function setTileFromTiledLayer(tile, tileLayer) {
41
41
  // If the point is below the horizon,
42
42
  // the tile is guaranteed to be below the horizon as well.
43
43
  tile.horizonCullingPoint = tile.extent.center().as('EPSG:4978').toVector3();
44
- tile.extent.dimensions(dimensions).multiplyScalar(THREE.MathUtils.DEG2RAD); // alpha is maximum angle between two points of tile
44
+ tile.extent.planarDimensions(dimensions).multiplyScalar(THREE.MathUtils.DEG2RAD); // alpha is maximum angle between two points of tile
45
45
 
46
46
  var alpha = dimensions.length();
47
47
  var h = Math.abs(1.0 / Math.cos(alpha * 0.5));
@@ -98,6 +98,9 @@ var AnimationPlayer = /*#__PURE__*/function (_THREE$EventDispatche) {
98
98
  _this.duration = 0;
99
99
  _this.state = PLAYER_STATE.STOP;
100
100
  _this.waitTimer = null;
101
+
102
+ _this.callback = function () {};
103
+
101
104
  return _this;
102
105
  }
103
106
 
@@ -117,6 +120,17 @@ var AnimationPlayer = /*#__PURE__*/function (_THREE$EventDispatche) {
117
120
  return this.state === PLAYER_STATE.END;
118
121
  } // Public functions
119
122
 
123
+ /**
124
+ * Set the Player `callback` property. This callback is executed at each animation frame.
125
+ *
126
+ * @param {function} callback - The callback to execute at each animation frame.
127
+ */
128
+
129
+ }, {
130
+ key: "setCallback",
131
+ value: function setCallback(callback) {
132
+ this.callback = callback;
133
+ }
120
134
  /**
121
135
  * Play one animation.
122
136
  * If another animation is playing, it's stopped and the new animation is played.
@@ -177,6 +191,7 @@ var AnimationPlayer = /*#__PURE__*/function (_THREE$EventDispatche) {
177
191
  this.dispatchEvent({
178
192
  type: 'animation-frame'
179
193
  });
194
+ this.callback();
180
195
  } else {
181
196
  this.state = PLAYER_STATE.END;
182
197
  finishAnimation(this);
@@ -57,6 +57,19 @@ function _extendBuffer(feature, size) {
57
57
  }
58
58
  }
59
59
 
60
+ function _setGeometryValues(geom, feature, _long, lat, alt, normal) {
61
+ if (feature.normals) {
62
+ normal.toArray(feature.normals, feature._pos);
63
+ }
64
+
65
+ feature._pushValues(_long, lat, alt);
66
+
67
+ if (geom.size == 3) {
68
+ geom.altitude.min = Math.min(geom.altitude.min, alt);
69
+ geom.altitude.max = Math.max(geom.altitude.max, alt);
70
+ }
71
+ }
72
+
60
73
  var coordOut = new _Coordinates["default"]('EPSG:4326', 0, 0, 0);
61
74
  var defaultNormal = new THREE.Vector3(0, 0, 1);
62
75
  var FEATURE_TYPES = {
@@ -68,17 +81,18 @@ exports.FEATURE_TYPES = FEATURE_TYPES;
68
81
  var typeToStyleProperty = ['point', 'stroke', 'fill'];
69
82
  /**
70
83
  * @property {string} crs - The CRS to convert the input coordinates to.
84
+ * @property {string} [structure='2d'] - data structure type : 2d or 3d.
85
+ * If the structure is 3d, the feature have 3 dimensions by vertices positions and
86
+ * a normal for each vertices.
71
87
  * @property {Extent|boolean} [filteringExtent=undefined] - Optional filter to reject
72
- * features outside of extent. Extent filetring is file extent if filteringExtent is true.
73
- * @property {boolean} [buildExtent=false] - If true the geometry will
88
+ * features outside of extent. Extent filtering is file extent if filteringExtent is true.
89
+ * @property {boolean} [buildExtent] - If true the geometry will
74
90
  * have an extent property containing the area covered by the geometry.
91
+ * Default value is false if `structure` parameter is set to '3d', and true otherwise.
75
92
  * True if the layer does not inherit from {@link GeometryLayer}.
76
93
  * @property {string} forcedExtentCrs - force feature extent crs if buildExtent is true.
77
94
  * @property {function} [filter] - Filter function to remove features
78
- * @property {boolean} [mergeFeatures=true] - If true all geometries are merged by type and multi-type
79
- * @property {string} [structure='2d'] - data structure type : 2d or 3d.
80
- * If the structure is 3d, the feature have 3 dimensions by vertices positions and
81
- * a normal for each vertices.
95
+ * @property {boolean} [mergeFeatures=true] - If true all geometries are merged by type and multi-type.
82
96
  * @property {Style} style - The style to inherit when creating
83
97
  * style for all new features.
84
98
  *
@@ -175,6 +189,12 @@ var FeatureGeometry = /*#__PURE__*/function () {
175
189
  var last = this.indices.length - 1;
176
190
  return this.indices[last];
177
191
  }
192
+ }, {
193
+ key: "baseAltitude",
194
+ value: function baseAltitude(feature, coordinates) {
195
+ var base_altitude = feature.style[typeToStyleProperty[feature.type]].base_altitude || 0;
196
+ return isNaN(base_altitude) ? base_altitude(this.properties, coordinates) : base_altitude;
197
+ }
178
198
  /**
179
199
  * Push new coordinates in vertices buffer.
180
200
  * @param {Coordinates} coordIn The coordinates to push.
@@ -184,30 +204,16 @@ var FeatureGeometry = /*#__PURE__*/function () {
184
204
  }, {
185
205
  key: "pushCoordinates",
186
206
  value: function pushCoordinates(coordIn, feature) {
187
- if (this.size == 3) {
188
- // set altitude from context
189
- var base_altitude = feature.style[typeToStyleProperty[feature.type]].base_altitude;
190
- coordIn.z = isNaN(base_altitude) ? base_altitude(this.properties, coordIn) : base_altitude;
191
- }
192
-
207
+ coordIn.z = this.baseAltitude(feature, coordIn);
193
208
  coordIn.as(feature.crs, coordOut);
194
209
  feature.transformToLocalSystem(coordOut);
195
210
 
196
- if (feature.normals) {
197
- coordOut.geodesicNormal.toArray(feature.normals, feature._pos);
198
- }
199
-
200
- feature._pushValues(coordOut.x, coordOut.y, coordOut.z); // expand extent if present
211
+ _setGeometryValues(this, feature, coordOut.x, coordOut.y, coordOut.z, coordOut.geodesicNormal); // expand extent if present
201
212
 
202
213
 
203
214
  if (this._currentExtent) {
204
215
  this._currentExtent.expandByCoordinates(feature.useCrsOut ? coordOut : coordIn);
205
216
  }
206
-
207
- if (this.size == 3) {
208
- this.altitude.min = Math.min(this.altitude.min, coordIn.z);
209
- this.altitude.max = Math.max(this.altitude.max, coordIn.z);
210
- }
211
217
  }
212
218
  /**
213
219
  * Push new values coordinates in vertices buffer.
@@ -217,30 +223,20 @@ var FeatureGeometry = /*#__PURE__*/function () {
217
223
  * @param {Feature} feature - the feature containing the geometry
218
224
  * @param {number} long The longitude coordinate.
219
225
  * @param {number} lat The latitude coordinate.
220
- * @param {number} [alt=0] The altitude coordinate.
221
226
  * @param {THREE.Vector3} [normal=THREE.Vector3(0,0,1)] the normal on coordinates.
222
227
  */
223
228
 
224
229
  }, {
225
230
  key: "pushCoordinatesValues",
226
- value: function pushCoordinatesValues(feature, _long, lat) {
227
- var alt = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
228
- var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : defaultNormal;
231
+ value: function pushCoordinatesValues(feature, _long2, lat) {
232
+ var normal = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultNormal;
233
+ var altitude = this.baseAltitude(feature);
229
234
 
230
- if (feature.normals) {
231
- normal.toArray(feature.normals, feature._pos);
232
- }
233
-
234
- feature._pushValues(_long, lat, alt); // expand extent if present
235
+ _setGeometryValues(this, feature, _long2, lat, altitude, normal); // expand extent if present
235
236
 
236
237
 
237
238
  if (this._currentExtent) {
238
- this._currentExtent.expandByValuesCoordinates(_long, lat);
239
- }
240
-
241
- if (this.size == 3) {
242
- this.altitude.min = Math.min(this.altitude.min, alt);
243
- this.altitude.max = Math.max(this.altitude.max, alt);
239
+ this._currentExtent.expandByValuesCoordinates(_long2, lat);
244
240
  }
245
241
  }
246
242
  /**
@@ -469,7 +465,6 @@ var FeatureCollection = /*#__PURE__*/function (_THREE$Object3D) {
469
465
  _this.crs = _Crs["default"].formatToEPSG(options.crs);
470
466
  _this.features = [];
471
467
  _this.mergeFeatures = options.mergeFeatures === undefined ? true : options.mergeFeatures;
472
- _this.extent = options.buildExtent ? defaultExtent(options.forcedExtentCrs || _this.crs) : undefined;
473
468
  _this.size = options.structure == '3d' ? 3 : 2;
474
469
  _this.filterExtent = options.filterExtent;
475
470
  _this.style = options.style;
@@ -478,6 +473,8 @@ var FeatureCollection = /*#__PURE__*/function (_THREE$Object3D) {
478
473
  _this.center = new _Coordinates["default"]('EPSG:4326', 0, 0);
479
474
 
480
475
  if (_this.size == 2) {
476
+ _this.extent = options.buildExtent === false ? undefined : defaultExtent(options.forcedExtentCrs || _this.crs);
477
+
481
478
  _this._setLocalSystem = function (center) {
482
479
  // set local system center
483
480
  center.as('EPSG:4326', _this.center); // set position to local system center
@@ -491,6 +488,8 @@ var FeatureCollection = /*#__PURE__*/function (_THREE$Object3D) {
491
488
 
492
489
  _this._transformToLocalSystem = transformToLocalSystem2D;
493
490
  } else {
491
+ _this.extent = options.buildExtent ? defaultExtent(options.forcedExtentCrs || _this.crs) : undefined;
492
+
494
493
  _this._setLocalSystem = function (center) {
495
494
  // set local system center
496
495
  center.as('EPSG:4326', _this.center);
@@ -686,6 +685,8 @@ var FeatureCollection = /*#__PURE__*/function (_THREE$Object3D) {
686
685
  ref.normals = feature.normals;
687
686
  ref.size = feature.size;
688
687
  ref.vertices = feature.vertices;
688
+ ref.altitude.min = feature.altitude.min;
689
+ ref.altitude.max = feature.altitude.max;
689
690
  ref._pos = feature._pos;
690
691
  this.features.push(ref);
691
692
  return ref;
@@ -29,6 +29,10 @@ _proj["default"].defs('EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs
29
29
 
30
30
  var ellipsoid = new _Ellipsoid["default"]();
31
31
  var projectionCache = {};
32
+ var v0 = new THREE.Vector3();
33
+ var v1 = new THREE.Vector3();
34
+ var coord0;
35
+ var coord1;
32
36
 
33
37
  function proj4cache(crsIn, crsOut) {
34
38
  if (!projectionCache[crsIn]) {
@@ -242,6 +246,56 @@ var Coordinates = /*#__PURE__*/function () {
242
246
  var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new THREE.Vector3();
243
247
  return target.copy(this);
244
248
  }
249
+ /**
250
+ * Calculate planar distance between this coordinates and `coord`.
251
+ * Planar distance is the straight-line euclidean distance calculated in a 2D cartesian coordinate system.
252
+ *
253
+ * @param {Coordinates} coord The coordinate
254
+ * @return {number} planar distance
255
+ *
256
+ */
257
+
258
+ }, {
259
+ key: "planarDistanceTo",
260
+ value: function planarDistanceTo(coord) {
261
+ this.toVector3(v0).setZ(0);
262
+ coord.toVector3(v1).setZ(0);
263
+ return v0.distanceTo(v1);
264
+ }
265
+ /**
266
+ * Calculate geodetic distance between this coordinates and `coord`.
267
+ * **Geodetic distance** is calculated in an ellispoid space as the shortest distance
268
+ * across the curved surface of the world.
269
+ *
270
+ * => As the crow flies/ Orthodromy
271
+ *
272
+ * @param {Coordinates} coord The coordinate
273
+ * @return {number} geodetic distance
274
+ *
275
+ */
276
+
277
+ }, {
278
+ key: "geodeticDistanceTo",
279
+ value: function geodeticDistanceTo(coord) {
280
+ this.as('EPSG:4326', coord0);
281
+ coord.as('EPSG:4326', coord1);
282
+ return ellipsoid.geodesicDistance(coord0, coord1);
283
+ }
284
+ /**
285
+ * Calculate earth euclidean distance between this coordinates and `coord`.
286
+ *
287
+ * @param {Coordinates} coord The coordinate
288
+ * @return {number} earth euclidean distance
289
+ *
290
+ */
291
+
292
+ }, {
293
+ key: "spatialEuclideanDistanceTo",
294
+ value: function spatialEuclideanDistanceTo(coord) {
295
+ this.as('EPSG:4978', coord0).toVector3(v0);
296
+ coord.as('EPSG:4978', coord1).toVector3(v1);
297
+ return v0.distanceTo(v1);
298
+ }
245
299
  /**
246
300
  * Multiplies this `coordinates` (with an implicit 1 in the 4th dimension) and `mat`.
247
301
  *
@@ -302,5 +356,7 @@ var Coordinates = /*#__PURE__*/function () {
302
356
  return Coordinates;
303
357
  }();
304
358
 
359
+ coord0 = new Coordinates('EPSG:4326', 0, 0, 0);
360
+ coord1 = new Coordinates('EPSG:4326', 0, 0, 0);
305
361
  var _default = Coordinates;
306
362
  exports["default"] = _default;
@@ -36,6 +36,12 @@ function is4326(crs) {
36
36
  return crs === 'EPSG:4326';
37
37
  }
38
38
 
39
+ function isGeocentric(crs) {
40
+ var projection = _proj["default"].defs(crs);
41
+
42
+ return !projection ? false : projection.projName == 'geocent';
43
+ }
44
+
39
45
  function _unitFromProj4Unit(projunit) {
40
46
  if (projunit === 'degrees') {
41
47
  return UNIT.DEGREE;
@@ -140,6 +146,15 @@ var _default = {
140
146
  */
141
147
  is4326: is4326,
142
148
 
149
+ /**
150
+ * Is the CRS geocentric ?
151
+ * if crs isn't defined the method returns false.
152
+ *
153
+ * @param {string} crs - The CRS to test.
154
+ * @return {boolean}
155
+ */
156
+ isGeocentric: isGeocentric,
157
+
143
158
  /**
144
159
  * Give a reasonnable epsilon to use with this CRS.
145
160
  *
@@ -33,6 +33,8 @@ var _dim2 = new THREE.Vector2();
33
33
 
34
34
  var _countTiles = new THREE.Vector2();
35
35
 
36
+ var _box = new THREE.Box3();
37
+
36
38
  var tmsCoord = new THREE.Vector2();
37
39
  var dimensionTile = new THREE.Vector2();
38
40
  var defaultScheme = new THREE.Vector2(2, 2);
@@ -41,6 +43,9 @@ var r = {
41
43
  col: 0,
42
44
  invDiff: 0
43
45
  };
46
+ var cNorthWest = new _Coordinates["default"]('EPSG:4326', 0, 0, 0);
47
+ var cSouthWest = new _Coordinates["default"]('EPSG:4326', 0, 0, 0);
48
+ var cNorthEast = new _Coordinates["default"]('EPSG:4326', 0, 0, 0);
44
49
  var southWest = new THREE.Vector3();
45
50
  var northEast = new THREE.Vector3();
46
51
 
@@ -74,7 +79,7 @@ function getInfoTms(crs) {
74
79
  var epsg = _Crs["default"].formatToEPSG(crs);
75
80
 
76
81
  var globalExtent = globalExtentTMS.get(epsg);
77
- var globalDimension = globalExtent.dimensions(_dim2);
82
+ var globalDimension = globalExtent.planarDimensions(_dim2);
78
83
 
79
84
  var tms = _Crs["default"].formatToTms(crs);
80
85
 
@@ -109,6 +114,8 @@ var Extent = /*#__PURE__*/function () {
109
114
  * Extent is geographical bounding rectangle defined by 4 limits: west, east, south and north.
110
115
  * If crs is tiled projection (WMTS or TMS), the extent is defined by zoom, row and column.
111
116
  *
117
+ * Warning, using geocentric projection isn't consistent with geographical extent.
118
+ *
112
119
  * @param {String} crs projection of limit values.
113
120
  * @param {number|Array.<number>|Coordinates|Object} v0 west value, zoom
114
121
  * value, Array of values [west, east, south and north], Coordinates of
@@ -120,6 +127,11 @@ var Extent = /*#__PURE__*/function () {
120
127
  */
121
128
  function Extent(crs, v0, v1, v2, v3) {
122
129
  (0, _classCallCheck2["default"])(this, Extent);
130
+
131
+ if (_Crs["default"].isGeocentric(crs)) {
132
+ throw new Error("".concat(crs, " is a geocentric projection, it doesn't make sense with a geographical extent"));
133
+ }
134
+
123
135
  this.isExtent = true;
124
136
  this.crs = crs; // Scale/zoom
125
137
 
@@ -173,7 +185,7 @@ var Extent = /*#__PURE__*/function () {
173
185
  sTs = _getInfoTms.sTs;
174
186
 
175
187
  extent.clampByExtent(globalExtent);
176
- extent.dimensions(dimensionTile);
188
+ extent.planarDimensions(dimensionTile);
177
189
  var zoom = this.zoom + 1 || Math.floor(Math.log2(Math.round(globalDimension.x / (dimensionTile.x * sTs.x))));
178
190
  var countTiles = getCountTiles(crs, zoom);
179
191
  var center = extent.center(_c);
@@ -199,7 +211,7 @@ var Extent = /*#__PURE__*/function () {
199
211
 
200
212
  var _center = this.center(_c);
201
213
 
202
- this.dimensions(dimensionTile); // Each level has 2^n * 2^n tiles...
214
+ this.planarDimensions(dimensionTile); // Each level has 2^n * 2^n tiles...
203
215
  // ... so we count how many tiles of the same width as tile we can fit in the layer
204
216
  // ... 2^zoom = tilecount => zoom = log2(tilecount)
205
217
 
@@ -297,7 +309,7 @@ var Extent = /*#__PURE__*/function () {
297
309
  throw new Error('Invalid operation for WMTS bbox');
298
310
  }
299
311
 
300
- this.dimensions(_dim);
312
+ this.planarDimensions(_dim);
301
313
  target.crs = this.crs;
302
314
  target.setFromValues(this.west + _dim.x * 0.5, this.south + _dim.y * 0.5);
303
315
  return target;
@@ -314,10 +326,71 @@ var Extent = /*#__PURE__*/function () {
314
326
  key: "dimensions",
315
327
  value: function dimensions() {
316
328
  var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new THREE.Vector2();
329
+ console.warn('Extent.dimensions is deprecated, use planarDimensions, geodeticDimensions or spatialEuclideanDimensions');
317
330
  target.x = Math.abs(this.east - this.west);
318
331
  target.y = Math.abs(this.north - this.south);
319
332
  return target;
320
333
  }
334
+ /**
335
+ * Planar dimensions are two planar distances west/east and south/north.
336
+ * Planar distance straight-line Euclidean distance calculated in a 2D Cartesian coordinate system.
337
+ *
338
+ * @param {THREE.Vector2} [target=new THREE.Vector2()] The target
339
+ * @return {THREE.Vector2} Planar dimensions
340
+ */
341
+
342
+ }, {
343
+ key: "planarDimensions",
344
+ value: function planarDimensions() {
345
+ var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new THREE.Vector2();
346
+ // Calculte the dimensions for x and y
347
+ return target.set(Math.abs(this.east - this.west), Math.abs(this.north - this.south));
348
+ }
349
+ /**
350
+ * Geodetic dimensions are two planar distances west/east and south/north.
351
+ * Geodetic distance is calculated in an ellispoid space as the distance
352
+ * across the curved surface of the world.
353
+ *
354
+ * @param {THREE.Vector2} [target=new THREE.Vector2()] The target
355
+ * @return {THREE.Vector2} geodetic dimensions
356
+ */
357
+
358
+ }, {
359
+ key: "geodeticDimensions",
360
+ value: function geodeticDimensions() {
361
+ var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new THREE.Vector2();
362
+ // set 3 corners extent
363
+ cNorthWest.crs = this.crs;
364
+ cSouthWest.crs = this.crs;
365
+ cNorthEast.crs = this.crs;
366
+ cNorthWest.setFromValues(this.west, this.north, 0);
367
+ cSouthWest.setFromValues(this.west, this.south, 0);
368
+ cNorthEast.setFromValues(this.east, this.north, 0); // calcul geodetic distance northWest/northEast and northWest/southWest
369
+
370
+ return target.set(cNorthWest.geodeticDistanceTo(cNorthEast), cNorthWest.geodeticDistanceTo(cSouthWest));
371
+ }
372
+ /**
373
+ * Spatial euclidean dimensions are two spatial euclidean distances between west/east corner and south/north corner.
374
+ * Spatial euclidean distance chord is calculated in a ellispoid space.
375
+ *
376
+ * @param {THREE.Vector2} [target=new THREE.Vector2()] The target
377
+ * @return {THREE.Vector2} spatial euclidean dimensions
378
+ */
379
+
380
+ }, {
381
+ key: "spatialEuclideanDimensions",
382
+ value: function spatialEuclideanDimensions() {
383
+ var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new THREE.Vector2();
384
+ // set 3 corners extent
385
+ cNorthWest.crs = this.crs;
386
+ cSouthWest.crs = this.crs;
387
+ cNorthEast.crs = this.crs;
388
+ cNorthWest.setFromValues(this.west, this.north, 0);
389
+ cSouthWest.setFromValues(this.west, this.south, 0);
390
+ cNorthEast.setFromValues(this.east, this.north, 0); // calcul chord distance northWest/northEast and northWest/southWest
391
+
392
+ return target.set(cNorthWest.spatialEuclideanDistanceTo(cNorthEast), cNorthWest.spatialEuclideanDistanceTo(cSouthWest));
393
+ }
321
394
  /**
322
395
  * Return true if `coord` is inside the bounding box.
323
396
  *
@@ -394,8 +467,8 @@ var Extent = /*#__PURE__*/function () {
394
467
  return target.set(this.col * r.invDiff - r.col, this.row * r.invDiff - r.row, r.invDiff, r.invDiff);
395
468
  }
396
469
 
397
- extent.dimensions(_dim);
398
- this.dimensions(_dim2);
470
+ extent.planarDimensions(_dim);
471
+ this.planarDimensions(_dim2);
399
472
  var originX = (this.west - extent.west) / _dim.x;
400
473
  var originY = (extent.north - this.north) / _dim.y;
401
474
  var scaleX = _dim2.x / _dim.x;
@@ -609,9 +682,14 @@ var Extent = /*#__PURE__*/function () {
609
682
  }
610
683
  }
611
684
  /**
612
- * Instance Extent with THREE.Box2
685
+ * Instance Extent with THREE.Box3.
686
+ *
687
+ * If crs is a geocentric projection, the `box3.min` and `box3.max`
688
+ * should be the geocentric coordinates of `min` and `max` of a `box3`
689
+ * in local tangent plane.
690
+ *
613
691
  * @param {string} crs Projection of extent to instancied.
614
- * @param {THREE.Box2} box
692
+ * @param {THREE.Box3} box
615
693
  * @return {Extent}
616
694
  */
617
695
 
@@ -657,7 +735,7 @@ var Extent = /*#__PURE__*/function () {
657
735
  value: function subdivisionByScheme() {
658
736
  var scheme = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultScheme;
659
737
  var subdivisedExtents = [];
660
- var dimSub = this.dimensions(_dim).divide(scheme);
738
+ var dimSub = this.planarDimensions(_dim).divide(scheme);
661
739
 
662
740
  for (var x = scheme.x - 1; x >= 0; x--) {
663
741
  for (var y = scheme.y - 1; y >= 0; y--) {
@@ -680,8 +758,8 @@ var Extent = /*#__PURE__*/function () {
680
758
  key: "applyMatrix4",
681
759
  value: function applyMatrix4(matrix) {
682
760
  if (!_Crs["default"].isTms(this.crs)) {
683
- southWest.set(this.west, this.south).applyMatrix4(matrix);
684
- northEast.set(this.east, this.north).applyMatrix4(matrix);
761
+ southWest.set(this.west, this.south, 0).applyMatrix4(matrix);
762
+ northEast.set(this.east, this.north, 0).applyMatrix4(matrix);
685
763
  this.west = southWest.x;
686
764
  this.east = northEast.x;
687
765
  this.south = southWest.y;
@@ -752,6 +830,16 @@ var Extent = /*#__PURE__*/function () {
752
830
  }], [{
753
831
  key: "fromBox3",
754
832
  value: function fromBox3(crs, box) {
833
+ if (_Crs["default"].isGeocentric(crs)) {
834
+ // if geocentric reproject box on 'EPSG:4326'
835
+ crs = 'EPSG:4326';
836
+ box = _box.copy(box);
837
+ cSouthWest.crs = crs;
838
+ cSouthWest.setFromVector3(box.min).as(crs, cSouthWest).toVector3(box.min);
839
+ cNorthEast.crs = crs;
840
+ cNorthEast.setFromVector3(box.max).as(crs, cNorthEast).toVector3(box.max);
841
+ }
842
+
755
843
  return new Extent(crs, {
756
844
  west: box.min.x,
757
845
  east: box.max.x,
package/lib/Core/Label.js CHANGED
@@ -262,7 +262,7 @@ var Label = /*#__PURE__*/function (_THREE$Object3D) {
262
262
  }, {
263
263
  key: "updateElevationFromLayer",
264
264
  value: function updateElevationFromLayer(layer) {
265
- var elevation = _DEMUtils["default"].getElevationValueAt(layer, this.coordinates, _DEMUtils["default"].FAST_READ_Z);
265
+ var elevation = Math.max(0, _DEMUtils["default"].getElevationValueAt(layer, this.coordinates, _DEMUtils["default"].FAST_READ_Z));
266
266
 
267
267
  if (elevation && elevation != this.coordinates.z) {
268
268
  this.coordinates.z = elevation;
@@ -34,6 +34,7 @@ var Ellipsoid = /*#__PURE__*/function () {
34
34
  this.size = new THREE.Vector3();
35
35
  this._radiiSquared = new THREE.Vector3();
36
36
  this._invRadiiSquared = new THREE.Vector3();
37
+ this.eccentricity = 0;
37
38
  this.setSize(size);
38
39
  }
39
40
 
@@ -62,6 +63,7 @@ var Ellipsoid = /*#__PURE__*/function () {
62
63
  this._invRadiiSquared.x = size.x == 0 ? 0 : 1 / this._radiiSquared.x;
63
64
  this._invRadiiSquared.y = size.y == 0 ? 0 : 1 / this._radiiSquared.y;
64
65
  this._invRadiiSquared.z = size.z == 0 ? 0 : 1 / this._radiiSquared.z;
66
+ this.eccentricity = Math.sqrt(this._radiiSquared.x - this._radiiSquared.z) / this.size.x;
65
67
  }
66
68
  }, {
67
69
  key: "cartographicToCartesian",
@@ -165,19 +167,35 @@ var Ellipsoid = /*#__PURE__*/function () {
165
167
  }, {
166
168
  key: "computeDistance",
167
169
  value: function computeDistance(coordCarto1, coordCarto2) {
170
+ console.warn('computeDistance is renamed to geodesicDistance');
171
+ this.geodesicDistance(coordCarto1, coordCarto2);
172
+ }
173
+ /**
174
+ * Calculate the geodesic distance, between coordCarto1 and coordCarto2.
175
+ * It's most short distance on ellipsoid surface between coordCarto1 and coordCarto2.
176
+ * It's called orthodromy.
177
+ *
178
+ * @param {Coordinates} coordCarto1 The coordinate carto 1
179
+ * @param {Coordinates} coordCarto2 The coordinate carto 2
180
+ * @return {number} The orthodromic distance between the two given coordinates.
181
+ */
182
+
183
+ }, {
184
+ key: "geodesicDistance",
185
+ value: function geodesicDistance(coordCarto1, coordCarto2) {
186
+ // The formula uses the distance on approximated sphere,
187
+ // with the nearest local radius of curvature of the ellipsoid
188
+ // https://geodesie.ign.fr/contenu/fichiers/Distance_longitude_latitude.pdf
168
189
  var longitude1 = THREE.MathUtils.degToRad(coordCarto1.longitude);
169
190
  var latitude1 = THREE.MathUtils.degToRad(coordCarto1.latitude);
170
191
  var longitude2 = THREE.MathUtils.degToRad(coordCarto2.longitude);
171
192
  var latitude2 = THREE.MathUtils.degToRad(coordCarto2.latitude);
172
193
  var distRad = Math.acos(Math.sin(latitude1) * Math.sin(latitude2) + Math.cos(latitude1) * Math.cos(latitude2) * Math.cos(longitude2 - longitude1));
173
- var a = this.size.x;
174
- var b = this.size.z;
175
- var e = Math.sqrt((a * a - b * b) / (a * a));
176
- var latMoy = (latitude1 + latitude2) / 2;
177
- var rho = a * (1 - e * e) / Math.sqrt(1 - e * e * Math.sin(latMoy) * Math.sin(latMoy));
178
- var N = a / Math.sqrt(1 - e * e * Math.sin(latMoy) * Math.sin(latMoy));
179
- var distMeter = distRad * Math.sqrt(rho * N);
180
- return distMeter;
194
+ var e = this.eccentricity;
195
+ var es = Math.pow(e * Math.sin((latitude1 + latitude2) * 0.5), 2);
196
+ var rho = this.size.x * (1 - Math.pow(e, 2)) / Math.pow(1 - es, 3 / 2);
197
+ var N = this.size.x / Math.sqrt(1 - es);
198
+ return distRad * Math.sqrt(rho * N);
181
199
  }
182
200
  }]);
183
201
  return Ellipsoid;
@@ -79,7 +79,7 @@ var BuilderEllipsoidTile = /*#__PURE__*/function () {
79
79
  longitude: 0,
80
80
  latitude: 0
81
81
  };
82
- params.extent.dimensions(this.tmp.dimension);
82
+ params.extent.planarDimensions(this.tmp.dimension);
83
83
  } // get center tile in cartesian 3D
84
84
 
85
85
  }, {
@@ -81,7 +81,7 @@ var PlanarView = /*#__PURE__*/function (_View) {
81
81
  _this = _super.call(this, extent.crs, viewerDiv, options);
82
82
  _this.isPlanarView = true; // Configure camera
83
83
 
84
- var dim = extent.dimensions();
84
+ var dim = extent.planarDimensions();
85
85
  var max = Math.max(dim.x, dim.y);
86
86
  var camera3D = _this.camera.camera3D;
87
87
  camera3D.near = 0.1;
package/lib/Core/Style.js CHANGED
@@ -472,6 +472,7 @@ var Style = /*#__PURE__*/function () {
472
472
  mapPropertiesFromContext('icon', this, style, context);
473
473
  }
474
474
 
475
+ style.order = this.order;
475
476
  return style;
476
477
  }
477
478
  /**
@@ -113,10 +113,11 @@ var TileMesh = /*#__PURE__*/function (_THREE$Mesh) {
113
113
  value: function setBBoxZ(min, max, scale) {
114
114
  if (min == null && max == null) {
115
115
  return;
116
- } // FIXME: Why the floors ? This is not conservative : the obb may be too short by almost 1m !
116
+ } // update bbox if min or max have changed by at least one decimal
117
+ // or if scale changed
117
118
 
118
119
 
119
- if (Math.floor(min) !== Math.floor(this.obb.z.min) || Math.floor(max) !== Math.floor(this.obb.z.max)) {
120
+ if (min.toFixed(1) !== this.obb.z.min.toFixed(1) || max.toFixed(1) !== this.obb.z.max.toFixed(1) || scale != this.obb.z.scale) {
120
121
  this.obb.updateZ(min, max, scale);
121
122
 
122
123
  if (this.horizonCullingPointElevationScaled) {