itowns 2.44.3-next.4 → 2.44.3-next.40

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 (109) 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 +123 -48
  11. package/examples/config.json +3 -10
  12. package/examples/copc_simple_loader.html +15 -5
  13. package/examples/effects_stereo.html +2 -2
  14. package/examples/entwine_3d_loader.html +3 -1
  15. package/examples/entwine_simple_loader.html +1 -1
  16. package/examples/images/itowns_logo.svg +123 -0
  17. package/examples/js/plugins/COGParser.js +1 -1
  18. package/examples/jsm/OGC3DTilesHelper.js +6 -1
  19. package/examples/layers/JSONLayers/GeoidMNT.json +3 -1
  20. package/examples/misc_collada.html +2 -2
  21. package/examples/source_file_geojson_3d.html +0 -1
  22. package/examples/source_file_kml_raster_usgs.html +0 -1
  23. package/examples/source_stream_wfs_raster.html +0 -7
  24. package/examples/vector_tile_mapbox_raster.html +91 -0
  25. package/examples/view_3d_map_webxr.html +3 -1
  26. package/examples/view_multi_25d.html +2 -2
  27. package/lib/Controls/GlobeControls.js +45 -28
  28. package/lib/Controls/StateControl.js +5 -2
  29. package/lib/Converter/Feature2Mesh.js +10 -4
  30. package/lib/Converter/Feature2Texture.js +6 -1
  31. package/lib/Converter/convertToTile.js +3 -8
  32. package/lib/Converter/textureConverter.js +4 -5
  33. package/lib/Core/Deprecated/Undeprecator.js +0 -1
  34. package/lib/Core/Feature.js +3 -4
  35. package/lib/Core/Geographic/Coordinates.js +143 -132
  36. package/lib/Core/Geographic/Crs.js +140 -145
  37. package/lib/Core/Geographic/Extent.js +221 -397
  38. package/lib/Core/Geographic/GeoidGrid.js +1 -1
  39. package/lib/Core/MainLoop.js +1 -3
  40. package/lib/Core/Math/Ellipsoid.js +62 -21
  41. package/lib/Core/Prefab/Globe/Atmosphere.js +4 -8
  42. package/lib/Core/Prefab/Globe/GlobeLayer.js +22 -15
  43. package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +111 -0
  44. package/lib/Core/Prefab/GlobeView.js +2 -7
  45. package/lib/Core/Prefab/Planar/PlanarLayer.js +17 -11
  46. package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +43 -43
  47. package/lib/Core/Prefab/TileBuilder.js +42 -40
  48. package/lib/Core/Prefab/computeBufferTileGeometry.js +195 -130
  49. package/lib/Core/Scheduler/Cache.js +1 -240
  50. package/lib/Core/Style.js +34 -495
  51. package/lib/Core/StyleOptions.js +486 -0
  52. package/lib/Core/Tile/Tile.js +207 -0
  53. package/lib/Core/Tile/TileGrid.js +49 -0
  54. package/lib/Core/TileGeometry.js +112 -28
  55. package/lib/Core/TileMesh.js +3 -3
  56. package/lib/Core/View.js +15 -8
  57. package/lib/Layer/C3DTilesLayer.js +20 -16
  58. package/lib/Layer/ColorLayer.js +35 -9
  59. package/lib/Layer/CopcLayer.js +7 -2
  60. package/lib/Layer/ElevationLayer.js +39 -7
  61. package/lib/Layer/EntwinePointTileLayer.js +14 -7
  62. package/lib/Layer/FeatureGeometryLayer.js +20 -6
  63. package/lib/Layer/GeometryLayer.js +42 -11
  64. package/lib/Layer/LabelLayer.js +45 -27
  65. package/lib/Layer/Layer.js +92 -61
  66. package/lib/Layer/OGC3DTilesLayer.js +212 -56
  67. package/lib/Layer/OrientedImageLayer.js +11 -5
  68. package/lib/Layer/PointCloudLayer.js +76 -30
  69. package/lib/Layer/Potree2Layer.js +9 -2
  70. package/lib/Layer/PotreeLayer.js +10 -3
  71. package/lib/Layer/RasterLayer.js +12 -2
  72. package/lib/Layer/TiledGeometryLayer.js +69 -13
  73. package/lib/Main.js +2 -2
  74. package/lib/Parser/GeoJsonParser.js +1 -1
  75. package/lib/Parser/VectorTileParser.js +42 -29
  76. package/lib/Parser/XbilParser.js +14 -2
  77. package/lib/Provider/Fetcher.js +5 -1
  78. package/lib/Provider/URLBuilder.js +22 -11
  79. package/lib/Renderer/Camera.js +1 -1
  80. package/lib/Renderer/Label2DRenderer.js +9 -7
  81. package/lib/Renderer/OBB.js +11 -13
  82. package/lib/Renderer/PointsMaterial.js +5 -5
  83. package/lib/Renderer/RasterTile.js +1 -2
  84. package/lib/Renderer/SphereHelper.js +0 -6
  85. package/lib/Source/CopcSource.js +13 -2
  86. package/lib/Source/EntwinePointTileSource.js +14 -4
  87. package/lib/Source/FileSource.js +9 -10
  88. package/lib/Source/OrientedImageSource.js +2 -2
  89. package/lib/Source/Source.js +26 -46
  90. package/lib/Source/TMSSource.js +10 -9
  91. package/lib/Source/VectorTilesSource.js +38 -34
  92. package/lib/Source/WFSSource.js +18 -13
  93. package/lib/Source/WMSSource.js +56 -18
  94. package/lib/Source/WMTSSource.js +13 -7
  95. package/lib/ThreeExtended/libs/ktx-parse.module.js +310 -274
  96. package/lib/ThreeExtended/loaders/DRACOLoader.js +3 -2
  97. package/lib/ThreeExtended/loaders/GLTFLoader.js +6 -3
  98. package/lib/ThreeExtended/loaders/KTX2Loader.js +144 -60
  99. package/lib/ThreeExtended/math/ColorSpaces.js +59 -0
  100. package/lib/Utils/CameraUtils.js +1 -1
  101. package/lib/Utils/gui/C3DTilesStyle.js +2 -3
  102. package/lib/Utils/placeObjectOnGround.js +0 -1
  103. package/package.json +10 -8
  104. package/examples/3dtiles_25d.html +0 -120
  105. package/examples/3dtiles_basic.html +0 -94
  106. package/examples/3dtiles_batch_table.html +0 -86
  107. package/examples/3dtiles_ion.html +0 -126
  108. package/examples/3dtiles_pointcloud.html +0 -95
  109. package/lib/Core/Prefab/Globe/BuilderEllipsoidTile.js +0 -110
@@ -1,3 +1,4 @@
1
+ import * as CRS from "../Core/Geographic/Crs.js";
1
2
  import Extent from "../Core/Geographic/Extent.js";
2
3
  import GeoJsonParser from "../Parser/GeoJsonParser.js";
3
4
  import KMLParser from "../Parser/KMLParser.js";
@@ -7,40 +8,17 @@ import GTXParser from "../Parser/GTXParser.js";
7
8
  import ISGParser from "../Parser/ISGParser.js";
8
9
  import VectorTileParser from "../Parser/VectorTileParser.js";
9
10
  import Fetcher from "../Provider/Fetcher.js";
10
- import Cache from "../Core/Scheduler/Cache.js";
11
- import CRS from "../Core/Geographic/Crs.js";
11
+ // import Cache from 'Core/Scheduler/Cache';
12
+ import { LRUCache } from 'lru-cache';
12
13
 
13
14
  /** @private */
14
15
  export const supportedParsers = new Map([['application/geo+json', GeoJsonParser.parse], ['application/json', GeoJsonParser.parse], ['application/kml', KMLParser.parse], ['application/gpx', GpxParser.parse], ['application/x-protobuf;type=mapbox-vector', VectorTileParser.parse], ['application/gtx', GTXParser.parse], ['application/isg', ISGParser.parse], ['application/gdf', GDFParser.parse]]);
15
16
  const noCache = {
16
- getByArray: () => {},
17
- setByArray: a => a,
17
+ get: () => {},
18
+ set: a => a,
18
19
  clear: () => {}
19
20
  };
20
21
 
21
- /**
22
- * @property {string} crs - data crs projection.
23
- * @property {boolean} isInverted - This option is to be set to the
24
- * correct value, true or false (default being false), if the computation of
25
- * the coordinates needs to be inverted to same scheme as OSM, Google Maps
26
- * or other system. See [this link](
27
- * https://alastaira.wordpress.com/2011/07/06/converting-tms-tile-coordinates-to-googlebingosm-tile-coordinates)
28
- * for more informations.
29
- *
30
- */
31
- class InformationsData {
32
- constructor(options) {
33
- /* istanbul ignore next */
34
- if (options.projection) {
35
- console.warn('Source projection parameter is deprecated, use crs instead.');
36
- options.crs = options.crs || options.projection;
37
- }
38
- if (options.crs) {
39
- CRS.isValid(options.crs);
40
- }
41
- this.crs = options.crs;
42
- }
43
- }
44
22
  /**
45
23
  * This interface describes parsing options.
46
24
  * @typedef {Object} ParsingOptions
@@ -94,13 +72,20 @@ let uid = 0;
94
72
  * depending on the current fetched tile for example</li>
95
73
  * </ul>
96
74
  */
97
- class Source extends InformationsData {
75
+ class Source {
98
76
  /**
99
77
  * @param {Object} source - An object that can contain all properties of a
100
78
  * Source. Only the `url` property is mandatory.
101
79
  */
102
80
  constructor(source) {
103
- super(source);
81
+ if (source.projection) {
82
+ console.warn('Source projection parameter is deprecated, use crs instead.');
83
+ source.crs = source.crs || source.projection;
84
+ }
85
+ if (source.crs) {
86
+ CRS.isValid(source.crs);
87
+ }
88
+ this.crs = source.crs;
104
89
  this.isSource = true;
105
90
  if (!source.url) {
106
91
  throw new Error('New Source: url is required');
@@ -122,7 +107,7 @@ class Source extends InformationsData {
122
107
  this.whenReady = Promise.resolve();
123
108
  this._featuresCaches = {};
124
109
  if (source.extent && !source.extent.isExtent) {
125
- this.extent = new Extent(this.crs, source.extent);
110
+ this.extent = new Extent(this.crs).setFromExtent(source.extent);
126
111
  } else {
127
112
  this.extent = source.extent;
128
113
  }
@@ -142,8 +127,8 @@ class Source extends InformationsData {
142
127
  urlFromExtent() {
143
128
  throw new Error('In extended Source, you have to implement the method urlFromExtent!');
144
129
  }
145
- requestToKey(extent) {
146
- return [extent.zoom, extent.row, extent.col];
130
+ getDataKey(extent) {
131
+ return `z${extent.zoom}r${extent.row}c${extent.col}`;
147
132
  }
148
133
 
149
134
  /**
@@ -156,25 +141,18 @@ class Source extends InformationsData {
156
141
  */
157
142
  loadData(extent, out) {
158
143
  const cache = this._featuresCaches[out.crs];
159
- const key = this.requestToKey(extent);
144
+ const key = this.getDataKey(extent);
145
+ // console.log('Source.loadData', key);
160
146
  // try to get parsed data from cache
161
- let features = cache.getByArray(key);
147
+ let features = cache.get(key);
162
148
  if (!features) {
163
149
  // otherwise fetch/parse the data
164
- features = cache.setByArray(this.fetcher(this.urlFromExtent(extent), this.networkOptions).then(file => this.parser(file, {
150
+ features = this.fetcher(this.urlFromExtent(extent), this.networkOptions).then(file => this.parser(file, {
165
151
  out,
166
152
  in: this,
167
153
  extent
168
- })).catch(err => this.handlingError(err)), key);
169
-
170
- /* istanbul ignore next */
171
- if (this.onParsedFile) {
172
- features.then(feat => {
173
- this.onParsedFile(feat);
174
- console.warn('Source.onParsedFile was deprecated');
175
- return feat;
176
- });
177
- }
154
+ })).catch(err => this.handlingError(err));
155
+ cache.set(key, features);
178
156
  }
179
157
  return features;
180
158
  }
@@ -190,7 +168,9 @@ class Source extends InformationsData {
190
168
  // Cache feature only if it's vector data, the feature are cached in source.
191
169
  // It's not necessary to cache raster in Source,
192
170
  // because it's already cached on layer.
193
- this._featuresCaches[options.out.crs] = this.isVectorSource ? new Cache() : noCache;
171
+ this._featuresCaches[options.out.crs] = this.isVectorSource ? new LRUCache({
172
+ max: 500
173
+ }) : noCache;
194
174
  }
195
175
  }
196
176
 
@@ -1,8 +1,9 @@
1
1
  import Source from "./Source.js";
2
2
  import URLBuilder from "../Provider/URLBuilder.js";
3
- import Extent, { globalExtentTMS } from "../Core/Geographic/Extent.js";
4
- import CRS from "../Core/Geographic/Crs.js";
5
- const extent = new Extent(CRS.tms_4326, 0, 0, 0);
3
+ import Extent from "../Core/Geographic/Extent.js";
4
+ import Tile from "../Core/Tile/Tile.js";
5
+ import { globalExtentTMS } from "../Core/Tile/TileGrid.js";
6
+ const _tile = new Tile('EPSG:4326', 0, 0, 0);
6
7
 
7
8
  /**
8
9
  * An object defining the source of resources to get from a
@@ -86,7 +87,7 @@ class TMSSource extends Source {
86
87
  }
87
88
  this.zoom = source.zoom;
88
89
  this.isInverted = source.isInverted || false;
89
- this.crs = CRS.formatToTms(source.crs);
90
+ this.crs = source.crs;
90
91
  this.tileMatrixSetLimits = source.tileMatrixSetLimits;
91
92
  this.extentSetlimits = {};
92
93
  this.tileMatrixCallback = source.tileMatrixCallback || (zoomLevel => zoomLevel);
@@ -107,8 +108,8 @@ class TMSSource extends Source {
107
108
  }
108
109
  }
109
110
  }
110
- urlFromExtent(extent) {
111
- return URLBuilder.xyz(extent, this);
111
+ urlFromExtent(tile) {
112
+ return URLBuilder.xyz(tile, this);
112
113
  }
113
114
  onLayerAdded(options) {
114
115
  super.onLayerAdded(options);
@@ -118,17 +119,17 @@ class TMSSource extends Source {
118
119
  const crs = parent ? parent.extent.crs : options.out.crs;
119
120
  if (this.tileMatrixSetLimits && !this.extentSetlimits[crs]) {
120
121
  this.extentSetlimits[crs] = {};
121
- extent.crs = this.crs;
122
+ _tile.crs = this.crs;
122
123
  for (let i = this.zoom.max; i >= this.zoom.min; i--) {
123
124
  const tmsl = this.tileMatrixSetLimits[i];
124
125
  const {
125
126
  west,
126
127
  north
127
- } = extent.set(i, tmsl.minTileRow, tmsl.minTileCol).as(crs);
128
+ } = _tile.set(i, tmsl.minTileRow, tmsl.minTileCol).toExtent(crs);
128
129
  const {
129
130
  east,
130
131
  south
131
- } = extent.set(i, tmsl.maxTileRow, tmsl.maxTileCol).as(crs);
132
+ } = _tile.set(i, tmsl.maxTileRow, tmsl.maxTileCol).toExtent(crs);
132
133
  this.extentSetlimits[crs][i] = new Extent(crs, west, east, south, north);
133
134
  }
134
135
  }
@@ -1,5 +1,5 @@
1
- import { featureFilter } from '@mapbox/mapbox-gl-style-spec';
2
- import Style from "../Core/Style.js";
1
+ import { featureFilter } from '@maplibre/maplibre-gl-style-spec';
2
+ import StyleOptions from "../Core/StyleOptions.js";
3
3
  import TMSSource from "./TMSSource.js";
4
4
  import URLBuilder from "../Provider/URLBuilder.js";
5
5
  import Fetcher from "../Provider/Fetcher.js";
@@ -20,6 +20,15 @@ function mergeCollections(collections) {
20
20
  return collection;
21
21
  }
22
22
 
23
+ // A deprecated (but still in use) Mapbox spec allows using 'ref' as a propertie to reference an other layer
24
+ // instead of duplicating the following properties: 'type', 'source', 'source-layer', 'minzoom', 'maxzoom', 'filter', 'layout'
25
+ function getPropertiesFromRefLayer(layers, layer) {
26
+ const refLayer = layers.filter(l => l.id === layer.ref)[0];
27
+ ['type', 'source', 'source-layer', 'minzoom', 'maxzoom', 'filter', 'layout'].forEach(prop => {
28
+ layer[prop] = refLayer[prop];
29
+ });
30
+ }
31
+
23
32
  /**
24
33
  * VectorTilesSource are object containing informations on how to fetch vector
25
34
  * tiles resources.
@@ -69,36 +78,41 @@ class VectorTilesSource extends TMSSource {
69
78
  let promise;
70
79
  this.isVectorTileSource = true;
71
80
  this.accessToken = source.accessToken;
81
+ let mvtStyleUrl;
72
82
  if (source.style) {
73
83
  if (typeof source.style == 'string') {
74
- const styleUrl = urlParser.normalizeStyleURL(source.style, this.accessToken);
75
- promise = Fetcher.json(styleUrl, this.networkOptions);
84
+ mvtStyleUrl = urlParser.normalizeStyleURL(source.style, this.accessToken);
85
+ promise = Fetcher.json(mvtStyleUrl, this.networkOptions);
76
86
  } else {
77
87
  promise = Promise.resolve(source.style);
78
88
  }
79
89
  } else {
80
90
  throw new Error('New VectorTilesSource: style is required');
81
91
  }
82
- this.whenReady = promise.then(style => {
83
- this.jsonStyle = style;
84
- const baseurl = source.sprite || style.sprite;
92
+ this.whenReady = promise.then(mvtStyle => {
93
+ this.jsonStyle = mvtStyle;
94
+ let baseurl = source.sprite || mvtStyle.sprite;
85
95
  if (baseurl) {
96
+ baseurl = new URL(baseurl, mvtStyleUrl).toString();
86
97
  const spriteUrl = urlParser.normalizeSpriteURL(baseurl, '', '.json', this.accessToken);
87
98
  return Fetcher.json(spriteUrl, this.networkOptions).then(sprites => {
88
99
  this.sprites = sprites;
89
100
  const imgUrl = urlParser.normalizeSpriteURL(baseurl, '', '.png', this.accessToken);
90
101
  this.sprites.source = imgUrl;
91
- return style;
102
+ return mvtStyle;
92
103
  });
93
104
  }
94
- return style;
95
- }).then(style => {
96
- style.layers.forEach((layer, order) => {
105
+ return mvtStyle;
106
+ }).then(mvtStyle => {
107
+ mvtStyle.layers.forEach((layer, order) => {
97
108
  layer.sourceUid = this.uid;
98
109
  if (layer.type === 'background') {
99
110
  this.backgroundLayer = layer;
100
111
  } else if (ffilter(layer)) {
101
- const style = Style.setFromVectorTileLayer(layer, this.sprites, order, this.symbolToCircle);
112
+ if (layer['source-layer'] === undefined) {
113
+ getPropertiesFromRefLayer(mvtStyle.layers, layer);
114
+ }
115
+ const style = StyleOptions.setFromVectorTileLayer(layer, this.sprites, this.symbolToCircle);
102
116
  this.styles[layer.id] = style;
103
117
  if (!this.layers[layer['source-layer']]) {
104
118
  this.layers[layer['source-layer']] = [];
@@ -106,20 +120,18 @@ class VectorTilesSource extends TMSSource {
106
120
  this.layers[layer['source-layer']].push({
107
121
  id: layer.id,
108
122
  order,
109
- filterExpression: featureFilter(layer.filter),
110
- zoom: {
111
- min: layer.minzoom || 0,
112
- max: layer.maxzoom || 24
113
- }
123
+ filterExpression: featureFilter(layer.filter)
114
124
  });
115
125
  }
116
126
  });
117
127
  if (this.url == '.') {
118
- const TMSUrlList = Object.values(style.sources).map(sourceVT => {
128
+ const TMSUrlList = Object.values(mvtStyle.sources).map(sourceVT => {
119
129
  if (sourceVT.url) {
130
+ sourceVT.url = new URL(sourceVT.url, mvtStyleUrl).toString();
120
131
  const urlSource = urlParser.normalizeSourceURL(sourceVT.url, this.accessToken);
121
132
  return Fetcher.json(urlSource, this.networkOptions).then(tileJSON => {
122
133
  if (tileJSON.tiles[0]) {
134
+ tileJSON.tiles[0] = decodeURIComponent(new URL(tileJSON.tiles[0], urlSource).toString());
123
135
  return toTMSUrl(tileJSON.tiles[0]);
124
136
  }
125
137
  });
@@ -130,13 +142,13 @@ class VectorTilesSource extends TMSSource {
130
142
  });
131
143
  return Promise.all(TMSUrlList);
132
144
  }
133
- return Promise.resolve([this.url]);
145
+ return Promise.resolve([toTMSUrl(this.url)]);
134
146
  }).then(TMSUrlList => {
135
147
  this.urls = Array.from(new Set(TMSUrlList));
136
148
  });
137
149
  }
138
- urlFromExtent(extent, url) {
139
- return URLBuilder.xyz(extent, {
150
+ urlFromExtent(tile, url) {
151
+ return URLBuilder.xyz(tile, {
140
152
  tileMatrixCallback: this.tileMatrixCallback,
141
153
  url
142
154
  });
@@ -152,25 +164,17 @@ class VectorTilesSource extends TMSSource {
152
164
  }
153
165
  loadData(extent, out) {
154
166
  const cache = this._featuresCaches[out.crs];
155
- const key = this.requestToKey(extent);
167
+ const key = this.getDataKey(extent);
156
168
  // try to get parsed data from cache
157
- let features = cache.getByArray(key);
169
+ let features = cache.get(key);
158
170
  if (!features) {
159
171
  // otherwise fetch/parse the data
160
- features = cache.setByArray(Promise.all(this.urls.map(url => this.fetcher(this.urlFromExtent(extent, url), this.networkOptions).then(file => this.parser(file, {
172
+ features = Promise.all(this.urls.map(url => this.fetcher(this.urlFromExtent(extent, url), this.networkOptions).then(file => this.parser(file, {
161
173
  out,
162
174
  in: this,
163
175
  extent
164
- })))).then(collections => mergeCollections(collections)).catch(err => this.handlingError(err)), key);
165
-
166
- /* istanbul ignore next */
167
- if (this.onParsedFile) {
168
- features.then(feat => {
169
- this.onParsedFile(feat);
170
- console.warn('Source.onParsedFile was deprecated');
171
- return feat;
172
- });
173
- }
176
+ })))).then(collections => mergeCollections(collections)).catch(err => this.handlingError(err));
177
+ cache.set(key, features);
174
178
  }
175
179
  return features;
176
180
  }
@@ -1,6 +1,7 @@
1
1
  import Source from "./Source.js";
2
2
  import URLBuilder from "../Provider/URLBuilder.js";
3
- import CRS from "../Core/Geographic/Crs.js";
3
+ import Extent from "../Core/Geographic/Extent.js";
4
+ const _extent = new Extent('EPSG:4326');
4
5
 
5
6
  /**
6
7
  * An object defining the source of resources to get from a
@@ -118,22 +119,25 @@ class WFSSource extends Source {
118
119
  this.typeName = source.typeName;
119
120
  this.version = source.version || '2.0.2';
120
121
  this.bboxDigits = source.bboxDigits;
121
-
122
- // Add ? at the end of the url if it is not already in the given URL
123
- if (!this.url.endsWith('?')) {
124
- this.url = `${this.url}?`;
125
- }
126
- this.url = `${source.url}SERVICE=WFS&REQUEST=GetFeature&typeName=${this.typeName}&VERSION=${this.version}&SRSNAME=${this.crs}&outputFormat=${this.format}&BBOX=%bbox,${this.crs}`;
127
122
  this.zoom = {
128
123
  min: 0,
129
124
  max: Infinity
130
125
  };
126
+ const urlObj = new URL(source.url);
127
+ urlObj.searchParams.set('SERVICE', 'WFS');
128
+ urlObj.searchParams.set('REQUEST', 'GetFeature');
129
+ urlObj.searchParams.set('typeName', this.typeName);
130
+ urlObj.searchParams.set('VERSION', this.version);
131
+ urlObj.searchParams.set('SRSNAME', this.crs);
132
+ urlObj.searchParams.set('outputFormat', this.format);
133
+ urlObj.searchParams.set('BBOX', `%bbox,${this.crs}`);
131
134
  this.vendorSpecific = source.vendorSpecific;
132
135
  for (const name in this.vendorSpecific) {
133
136
  if (Object.prototype.hasOwnProperty.call(this.vendorSpecific, name)) {
134
- this.url = `${this.url}&${name}=${this.vendorSpecific[name]}`;
137
+ urlObj.searchParams.set(name, this.vendorSpecific[name]);
135
138
  }
136
139
  }
140
+ this.url = decodeURIComponent(urlObj.toString());
137
141
  }
138
142
  handlingError(err) {
139
143
  if (err.response && err.response.status == 400) {
@@ -148,14 +152,15 @@ class WFSSource extends Source {
148
152
  }
149
153
  return super.handlingError(err);
150
154
  }
151
- requestToKey(extent) {
152
- if (CRS.isTms(extent.crs)) {
153
- return super.requestToKey(extent);
155
+ getDataKey(extent) {
156
+ if (extent.isTile) {
157
+ return super.getDataKey(extent);
154
158
  } else {
155
- return [extent.zoom, extent.south, extent.west];
159
+ return `z${extent.zoom}s${extent.south}w${extent.west}`;
156
160
  }
157
161
  }
158
- urlFromExtent(extent) {
162
+ urlFromExtent(extentOrTile) {
163
+ const extent = extentOrTile.isExtent ? extentOrTile.as(this.crs, _extent) : extentOrTile.toExtent(this.crs, _extent);
159
164
  return URLBuilder.bbox(extent, this);
160
165
  }
161
166
  extentInsideLimit(extent) {
@@ -1,5 +1,36 @@
1
1
  import Source from "./Source.js";
2
2
  import URLBuilder from "../Provider/URLBuilder.js";
3
+ import Extent from "../Core/Geographic/Extent.js";
4
+ import * as CRS from "../Core/Geographic/Crs.js";
5
+ const _extent = new Extent('EPSG:4326');
6
+
7
+ /**
8
+ * Proj provides an optional param to define axis order and orientation for a
9
+ * given projection. 'enu' for instance stands for east, north, up.
10
+ * Elevation is not needed here. The two first characters are sufficient to map
11
+ * proj axis to iTowns bbox order formalism.
12
+ * 'enu' corresponds to 'wsen' because bbox starts by lower value coordinates
13
+ * and preserves axis ordering, here long/lat.
14
+ */
15
+ const projAxisToBboxMappings = {
16
+ en: 'wsen',
17
+ es: 'wnes',
18
+ wn: 'eswn',
19
+ ws: 'enws',
20
+ ne: 'swne',
21
+ se: 'nwse',
22
+ nw: 'senw',
23
+ sw: 'nesw'
24
+ };
25
+
26
+ /**
27
+ * Provides the bbox axis order matching provided proj4 axis
28
+ * @param {string} projAxis the CRS axis order as defined in proj4
29
+ * @returns {string} the corresponding bbox axis order to use for WMS 1.3.0
30
+ */
31
+ function projAxisToWmsBbox(projAxis) {
32
+ return projAxis && projAxisToBboxMappings[projAxis.slice(0, 2)] || 'wsen';
33
+ }
3
34
 
4
35
  /**
5
36
  * An object defining the source of images to get from a
@@ -95,32 +126,39 @@ class WMSSource extends Source {
95
126
  this.version = source.version || '1.3.0';
96
127
  this.transparent = source.transparent || false;
97
128
  this.bboxDigits = source.bboxDigits;
98
- if (!source.axisOrder) {
99
- // 4326 (lat/long) axis order depends on the WMS version used
100
- if (this.crs == 'EPSG:4326') {
101
- // EPSG 4326 x = lat, long = y
102
- // version 1.1.0 long/lat while version 1.3.0 mandates xy (so lat,long)
103
- this.axisOrder = this.version === '1.1.0' ? 'wsen' : 'swne';
104
- } else {
105
- // xy,xy order
106
- this.axisOrder = 'wsen';
107
- }
129
+ if (source.axisOrder) {
130
+ this.axisOrder = source.axisOrder;
131
+ } else if (this.version === '1.3.0') {
132
+ // If not set, axis order depends on WMS version
133
+ // Version 1.3.0 depends on CRS axis order as defined in epsg.org database
134
+ this.axisOrder = projAxisToWmsBbox(CRS.axisOrder(this.crs));
135
+ } else {
136
+ // Versions 1.X.X mandate long/lat order, east-north orientation
137
+ this.axisOrder = 'wsen';
108
138
  }
109
139
  const crsPropName = this.version === '1.3.0' ? 'CRS' : 'SRS';
110
-
111
- // Add ? at the end of the url if it is not already in the given URL
112
- if (!this.url.endsWith('?')) {
113
- this.url = `${this.url}?`;
114
- }
115
- this.url = `${this.url}SERVICE=WMS&REQUEST=GetMap&LAYERS=${this.name}&VERSION=${this.version}&STYLES=${this.style}&FORMAT=${this.format}&TRANSPARENT=${this.transparent}&BBOX=%bbox&${crsPropName}=${this.crs}&WIDTH=${this.width}&HEIGHT=${this.height}`;
140
+ const urlObj = new URL(this.url);
141
+ urlObj.searchParams.set('SERVICE', 'WMS');
142
+ urlObj.searchParams.set('REQUEST', 'GetMap');
143
+ urlObj.searchParams.set('LAYERS', this.name);
144
+ urlObj.searchParams.set('VERSION', this.version);
145
+ urlObj.searchParams.set('STYLES', this.style);
146
+ urlObj.searchParams.set('FORMAT', this.format);
147
+ urlObj.searchParams.set('TRANSPARENT', this.transparent);
148
+ urlObj.searchParams.set('BBOX', '%bbox');
149
+ urlObj.searchParams.set(crsPropName, this.crs);
150
+ urlObj.searchParams.set('WIDTH', this.width);
151
+ urlObj.searchParams.set('HEIGHT', this.height);
116
152
  this.vendorSpecific = source.vendorSpecific;
117
153
  for (const name in this.vendorSpecific) {
118
154
  if (Object.prototype.hasOwnProperty.call(this.vendorSpecific, name)) {
119
- this.url = `${this.url}&${name}=${this.vendorSpecific[name]}`;
155
+ urlObj.searchParams.set(name, this.vendorSpecific[name]);
120
156
  }
121
157
  }
158
+ this.url = decodeURIComponent(urlObj.toString());
122
159
  }
123
- urlFromExtent(extent) {
160
+ urlFromExtent(extentOrTile) {
161
+ const extent = extentOrTile.isExtent ? extentOrTile.as(this.crs, _extent) : extentOrTile.toExtent(this.crs, _extent);
124
162
  return URLBuilder.bbox(extent, this);
125
163
  }
126
164
  extentInsideLimit(extent) {
@@ -69,18 +69,24 @@ class WMTSSource extends TMSSource {
69
69
  }
70
70
  super(source);
71
71
  this.isWMTSSource = true;
72
-
73
- // Add ? at the end of the url if it is not already in the given URL
74
- if (!this.url.endsWith('?')) {
75
- this.url = `${this.url}?`;
76
- }
77
- this.url = `${this.url}` + `LAYER=${source.name}` + `&FORMAT=${this.format}` + '&SERVICE=WMTS' + `&VERSION=${source.version || '1.0.0'}` + '&REQUEST=GetTile' + `&STYLE=${source.style || 'normal'}` + `&TILEMATRIXSET=${source.tileMatrixSet}` + '&TILEMATRIX=%TILEMATRIX&TILEROW=%ROW&TILECOL=%COL';
72
+ const urlObj = new URL(this.url);
73
+ urlObj.searchParams.set('LAYER', source.name);
74
+ urlObj.searchParams.set('FORMAT', this.format);
75
+ urlObj.searchParams.set('SERVICE', 'WMTS');
76
+ urlObj.searchParams.set('VERSION', source.version || '1.0.0');
77
+ urlObj.searchParams.set('REQUEST', 'GetTile');
78
+ urlObj.searchParams.set('STYLE', source.style || 'normal');
79
+ urlObj.searchParams.set('TILEMATRIXSET', source.tileMatrixSet);
80
+ urlObj.searchParams.set('TILEMATRIX', '%TILEMATRIX');
81
+ urlObj.searchParams.set('TILEROW', '%ROW');
82
+ urlObj.searchParams.set('TILECOL', '%COL');
78
83
  this.vendorSpecific = source.vendorSpecific;
79
84
  for (const name in this.vendorSpecific) {
80
85
  if (Object.prototype.hasOwnProperty.call(this.vendorSpecific, name)) {
81
- this.url = `${this.url}&${name}=${this.vendorSpecific[name]}`;
86
+ urlObj.searchParams.set(name, this.vendorSpecific[name]);
82
87
  }
83
88
  }
89
+ this.url = decodeURIComponent(urlObj.toString());
84
90
  }
85
91
  }
86
92
  export default WMTSSource;