itowns 2.45.1-next.0 → 2.45.1-next.1

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 (185) hide show
  1. package/dist/455.js +2 -0
  2. package/dist/455.js.map +1 -0
  3. package/dist/debug.js +3 -0
  4. package/dist/debug.js.LICENSE.txt +13 -0
  5. package/dist/debug.js.map +1 -0
  6. package/dist/itowns.js +3 -0
  7. package/dist/itowns.js.LICENSE.txt +5 -0
  8. package/dist/itowns.js.map +1 -0
  9. package/dist/itowns_lasparser.js +2 -0
  10. package/dist/itowns_lasparser.js.map +1 -0
  11. package/dist/itowns_lasworker.js +2 -0
  12. package/dist/itowns_lasworker.js.map +1 -0
  13. package/dist/itowns_potree2worker.js +2 -0
  14. package/dist/itowns_potree2worker.js.map +1 -0
  15. package/dist/itowns_widgets.js +2 -0
  16. package/dist/itowns_widgets.js.map +1 -0
  17. package/lib/Controls/FirstPersonControls.js +308 -0
  18. package/lib/Controls/FlyControls.js +175 -0
  19. package/lib/Controls/GlobeControls.js +1178 -0
  20. package/lib/Controls/PlanarControls.js +1025 -0
  21. package/lib/Controls/StateControl.js +432 -0
  22. package/lib/Controls/StreetControls.js +392 -0
  23. package/lib/Converter/Feature2Mesh.js +612 -0
  24. package/lib/Converter/Feature2Texture.js +174 -0
  25. package/lib/Converter/convertToTile.js +70 -0
  26. package/lib/Converter/textureConverter.js +43 -0
  27. package/lib/Core/3DTiles/C3DTBatchTable.js +131 -0
  28. package/lib/Core/3DTiles/C3DTBatchTableHierarchyExtension.js +96 -0
  29. package/lib/Core/3DTiles/C3DTBoundingVolume.js +156 -0
  30. package/lib/Core/3DTiles/C3DTExtensions.js +97 -0
  31. package/lib/Core/3DTiles/C3DTFeature.js +110 -0
  32. package/lib/Core/3DTiles/C3DTilesEnums.js +20 -0
  33. package/lib/Core/3DTiles/C3DTileset.js +99 -0
  34. package/lib/Core/3DTiles/utils/BinaryPropertyAccessor.js +100 -0
  35. package/lib/Core/AnimationPlayer.js +142 -0
  36. package/lib/Core/CopcNode.js +174 -0
  37. package/lib/Core/Deprecated/Undeprecator.js +74 -0
  38. package/lib/Core/EntwinePointTileNode.js +126 -0
  39. package/lib/Core/Feature.js +488 -0
  40. package/lib/Core/Geographic/GeoidGrid.js +108 -0
  41. package/lib/Core/Label.js +222 -0
  42. package/lib/Core/MainLoop.js +209 -0
  43. package/lib/Core/Picking.js +255 -0
  44. package/lib/Core/PointCloudNode.js +42 -0
  45. package/lib/Core/Potree2Node.js +206 -0
  46. package/lib/Core/Potree2PointAttributes.js +139 -0
  47. package/lib/Core/PotreeNode.js +101 -0
  48. package/lib/Core/Prefab/Globe/Atmosphere.js +293 -0
  49. package/lib/Core/Prefab/Globe/GlobeLayer.js +152 -0
  50. package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +110 -0
  51. package/lib/Core/Prefab/Globe/SkyShader.js +78 -0
  52. package/lib/Core/Prefab/GlobeView.js +155 -0
  53. package/lib/Core/Prefab/Planar/PlanarLayer.js +59 -0
  54. package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +71 -0
  55. package/lib/Core/Prefab/PlanarView.js +62 -0
  56. package/lib/Core/Prefab/TileBuilder.js +82 -0
  57. package/lib/Core/Prefab/computeBufferTileGeometry.js +248 -0
  58. package/lib/Core/Scheduler/Cache.js +17 -0
  59. package/lib/Core/Scheduler/CancelledCommandException.js +15 -0
  60. package/lib/Core/Scheduler/Scheduler.js +294 -0
  61. package/lib/Core/Style.js +660 -0
  62. package/lib/Core/StyleOptions.js +486 -0
  63. package/lib/Core/System/Capabilities.js +63 -0
  64. package/lib/Core/Tile/Tile.js +205 -0
  65. package/lib/Core/Tile/TileGrid.js +49 -0
  66. package/lib/Core/TileGeometry.js +124 -0
  67. package/lib/Core/TileMesh.js +108 -0
  68. package/lib/Core/View.js +1115 -0
  69. package/lib/Layer/C3DTilesLayer.js +459 -0
  70. package/lib/Layer/ColorLayer.js +154 -0
  71. package/lib/Layer/CopcLayer.js +63 -0
  72. package/lib/Layer/ElevationLayer.js +139 -0
  73. package/lib/Layer/EntwinePointTileLayer.js +71 -0
  74. package/lib/Layer/FeatureGeometryLayer.js +77 -0
  75. package/lib/Layer/GeoidLayer.js +80 -0
  76. package/lib/Layer/GeometryLayer.js +233 -0
  77. package/lib/Layer/InfoLayer.js +64 -0
  78. package/lib/Layer/LabelLayer.js +469 -0
  79. package/lib/Layer/Layer.js +335 -0
  80. package/lib/Layer/LayerUpdateState.js +89 -0
  81. package/lib/Layer/LayerUpdateStrategy.js +80 -0
  82. package/lib/Layer/OGC3DTilesLayer.js +543 -0
  83. package/lib/Layer/OrientedImageLayer.js +227 -0
  84. package/lib/Layer/PointCloudLayer.js +405 -0
  85. package/lib/Layer/Potree2Layer.js +171 -0
  86. package/lib/Layer/PotreeLayer.js +72 -0
  87. package/lib/Layer/RasterLayer.js +37 -0
  88. package/lib/Layer/ReferencingLayerProperties.js +62 -0
  89. package/lib/Layer/TiledGeometryLayer.js +459 -0
  90. package/lib/Loader/LASLoader.js +193 -0
  91. package/lib/Loader/Potree2BrotliLoader.js +261 -0
  92. package/lib/Loader/Potree2Loader.js +207 -0
  93. package/lib/Main.js +113 -0
  94. package/lib/MainBundle.js +4 -0
  95. package/lib/Parser/B3dmParser.js +174 -0
  96. package/lib/Parser/CameraCalibrationParser.js +94 -0
  97. package/lib/Parser/GDFParser.js +72 -0
  98. package/lib/Parser/GTXParser.js +75 -0
  99. package/lib/Parser/GeoJsonParser.js +212 -0
  100. package/lib/Parser/GpxParser.js +25 -0
  101. package/lib/Parser/ISGParser.js +71 -0
  102. package/lib/Parser/KMLParser.js +25 -0
  103. package/lib/Parser/LASParser.js +137 -0
  104. package/lib/Parser/MapBoxUrlParser.js +83 -0
  105. package/lib/Parser/PntsParser.js +131 -0
  106. package/lib/Parser/Potree2BinParser.js +92 -0
  107. package/lib/Parser/PotreeBinParser.js +106 -0
  108. package/lib/Parser/PotreeCinParser.js +29 -0
  109. package/lib/Parser/ShapefileParser.js +78 -0
  110. package/lib/Parser/VectorTileParser.js +215 -0
  111. package/lib/Parser/XbilParser.js +120 -0
  112. package/lib/Parser/deprecated/LegacyGLTFLoader.js +1386 -0
  113. package/lib/Parser/iGLTFLoader.js +168 -0
  114. package/lib/Process/3dTilesProcessing.js +304 -0
  115. package/lib/Process/FeatureProcessing.js +76 -0
  116. package/lib/Process/LayeredMaterialNodeProcessing.js +229 -0
  117. package/lib/Process/ObjectRemovalHelper.js +97 -0
  118. package/lib/Process/handlerNodeError.js +23 -0
  119. package/lib/Provider/3dTilesProvider.js +149 -0
  120. package/lib/Provider/DataSourceProvider.js +24 -0
  121. package/lib/Provider/Fetcher.js +233 -0
  122. package/lib/Provider/PointCloudProvider.js +45 -0
  123. package/lib/Provider/TileProvider.js +16 -0
  124. package/lib/Provider/URLBuilder.js +116 -0
  125. package/lib/Renderer/Camera.js +281 -0
  126. package/lib/Renderer/Color.js +56 -0
  127. package/lib/Renderer/ColorLayersOrdering.js +115 -0
  128. package/lib/Renderer/CommonMaterial.js +31 -0
  129. package/lib/Renderer/Label2DRenderer.js +192 -0
  130. package/lib/Renderer/LayeredMaterial.js +243 -0
  131. package/lib/Renderer/OBB.js +150 -0
  132. package/lib/Renderer/OrientedImageCamera.js +118 -0
  133. package/lib/Renderer/OrientedImageMaterial.js +167 -0
  134. package/lib/Renderer/PointsMaterial.js +485 -0
  135. package/lib/Renderer/RasterTile.js +243 -0
  136. package/lib/Renderer/RenderMode.js +31 -0
  137. package/lib/Renderer/Shader/ShaderChunk.js +160 -0
  138. package/lib/Renderer/Shader/ShaderUtils.js +47 -0
  139. package/lib/Renderer/SphereHelper.js +17 -0
  140. package/lib/Renderer/WebXR.js +51 -0
  141. package/lib/Renderer/c3DEngine.js +214 -0
  142. package/lib/Source/C3DTilesGoogleSource.js +74 -0
  143. package/lib/Source/C3DTilesIonSource.js +54 -0
  144. package/lib/Source/C3DTilesSource.js +30 -0
  145. package/lib/Source/CopcSource.js +126 -0
  146. package/lib/Source/EntwinePointTileSource.js +72 -0
  147. package/lib/Source/FileSource.js +188 -0
  148. package/lib/Source/OGC3DTilesGoogleSource.js +29 -0
  149. package/lib/Source/OGC3DTilesIonSource.js +34 -0
  150. package/lib/Source/OGC3DTilesSource.js +21 -0
  151. package/lib/Source/OrientedImageSource.js +59 -0
  152. package/lib/Source/Potree2Source.js +167 -0
  153. package/lib/Source/PotreeSource.js +82 -0
  154. package/lib/Source/Source.js +202 -0
  155. package/lib/Source/TMSSource.js +144 -0
  156. package/lib/Source/VectorTilesSource.js +182 -0
  157. package/lib/Source/WFSSource.js +170 -0
  158. package/lib/Source/WMSSource.js +167 -0
  159. package/lib/Source/WMTSSource.js +92 -0
  160. package/lib/ThreeExtended/capabilities/WebGL.js +69 -0
  161. package/lib/ThreeExtended/libs/ktx-parse.module.js +506 -0
  162. package/lib/ThreeExtended/libs/zstddec.module.js +29 -0
  163. package/lib/ThreeExtended/loaders/DDSLoader.js +200 -0
  164. package/lib/ThreeExtended/loaders/DRACOLoader.js +400 -0
  165. package/lib/ThreeExtended/loaders/GLTFLoader.js +2879 -0
  166. package/lib/ThreeExtended/loaders/KTX2Loader.js +709 -0
  167. package/lib/ThreeExtended/math/ColorSpaces.js +59 -0
  168. package/lib/ThreeExtended/utils/BufferGeometryUtils.js +846 -0
  169. package/lib/ThreeExtended/utils/WorkerPool.js +70 -0
  170. package/lib/Utils/CameraUtils.js +554 -0
  171. package/lib/Utils/DEMUtils.js +350 -0
  172. package/lib/Utils/FeaturesUtils.js +156 -0
  173. package/lib/Utils/Gradients.js +16 -0
  174. package/lib/Utils/ThreeUtils.js +115 -0
  175. package/lib/Utils/gui/C3DTilesStyle.js +218 -0
  176. package/lib/Utils/gui/Main.js +7 -0
  177. package/lib/Utils/gui/Minimap.js +152 -0
  178. package/lib/Utils/gui/Navigation.js +245 -0
  179. package/lib/Utils/gui/Scale.js +104 -0
  180. package/lib/Utils/gui/Searchbar.js +234 -0
  181. package/lib/Utils/gui/Widget.js +80 -0
  182. package/lib/Utils/placeObjectOnGround.js +136 -0
  183. package/lib/Worker/LASLoaderWorker.js +19 -0
  184. package/lib/Worker/Potree2Worker.js +21 -0
  185. package/package.json +2 -2
@@ -0,0 +1,488 @@
1
+ import * as THREE from 'three';
2
+ import { Extent, Coordinates } from '@itowns/geographic';
3
+ import StyleOptions from "./StyleOptions.js";
4
+ function defaultExtent(crs) {
5
+ return new Extent(crs, Infinity, -Infinity, Infinity, -Infinity);
6
+ }
7
+ function _extendBuffer(feature, size) {
8
+ feature.vertices.length += size * feature.size;
9
+ if (feature.normals) {
10
+ feature.normals.length = feature.vertices.length;
11
+ }
12
+ }
13
+ function _setGeometryValues(feature, coord) {
14
+ if (feature.normals) {
15
+ coord.geodesicNormal.toArray(feature.normals, feature._pos);
16
+ }
17
+ feature._pushValues(coord.x, coord.y, coord.z);
18
+ }
19
+ const coordOut = new Coordinates('EPSG:4326', 0, 0, 0);
20
+ export const FEATURE_TYPES = {
21
+ POINT: 0,
22
+ LINE: 1,
23
+ POLYGON: 2
24
+ };
25
+
26
+ /**
27
+ * @typedef {Object} FeatureBuildingOptions
28
+ * @property {string} crs - The CRS to convert the input coordinates to.
29
+ * @property {string} [structure='2d'] - data structure type : 2d or 3d.
30
+ * If the structure is 3d, the feature have 3 dimensions by vertices positions and
31
+ * a normal for each vertices.
32
+ * @property {Extent|boolean} [filteringExtent=undefined] - Optional filter to reject
33
+ * features outside of extent. Extent filtering is file extent if filteringExtent is true.
34
+ * @property {boolean} [buildExtent] - If true the geometry will
35
+ * have an extent property containing the area covered by the geometry.
36
+ * Default value is false if `structure` parameter is set to '3d', and true otherwise.
37
+ * True if the layer does not inherit from {@link GeometryLayer}.
38
+ * @property {string} forcedExtentCrs - force feature extent crs if buildExtent is true.
39
+ * @property {function} [filter] - Filter function to remove features
40
+ * @property {boolean} [mergeFeatures=true] - If true all geometries are merged by type and multi-type.
41
+ * @property {Style} style - The style to inherit when creating
42
+ * style for all new features.
43
+ *
44
+ */
45
+
46
+ /**
47
+ * @property {Extent} extent - The 2D extent containing all the points
48
+ * composing the geometry.
49
+ * @property {Object[]} indices - Contains the indices that define the geometry.
50
+ * Objects stored in this array have two properties, an `offset` and a `count`.
51
+ * The offset is related to the overall number of vertices in the Feature.
52
+ *
53
+ * @property {Object} properties - Properties of the geometry. It can be
54
+ * anything specified in the GeoJSON under the `properties` property.
55
+ */
56
+ export class FeatureGeometry {
57
+ #currentExtent;
58
+ /**
59
+ * @param {Feature} feature geometry
60
+ */
61
+ constructor(feature) {
62
+ this.indices = [];
63
+ this.properties = {};
64
+ this.size = feature.size;
65
+ if (feature.extent) {
66
+ this.extent = defaultExtent(feature.extent.crs);
67
+ this.#currentExtent = defaultExtent(feature.extent.crs);
68
+ }
69
+ }
70
+ /**
71
+ * Add a new marker to indicate the starting of sub geometry and extends the vertices buffer.
72
+ * Then you have to push new the coordinates of sub geometry.
73
+ * The sub geometry stored in indices, see constructor for more information.
74
+ * @param {number} count - count of vertices
75
+ * @param {Feature} feature - the feature containing the geometry
76
+ */
77
+ startSubGeometry(count, feature) {
78
+ const last = this.indices.length - 1;
79
+ const extent = this.extent ? defaultExtent(this.extent.crs) : undefined;
80
+ const offset = last > -1 ? this.indices[last].offset + this.indices[last].count : feature.vertices.length / this.size;
81
+ this.indices.push({
82
+ offset,
83
+ count,
84
+ extent
85
+ });
86
+ this.#currentExtent = extent;
87
+ _extendBuffer(feature, count);
88
+ }
89
+
90
+ /**
91
+ * After you have pushed new the coordinates of sub geometry without
92
+ * `startSubGeometry`, this function close sub geometry. The sub geometry
93
+ * stored in indices, see constructor for more information.
94
+ * @param {number} count count of vertices
95
+ * @param {Feature} feature - the feature containing the geometry
96
+ */
97
+ closeSubGeometry(count, feature) {
98
+ const last = this.indices.length - 1;
99
+ const offset = last > -1 ? this.indices[last].offset + this.indices[last].count : feature.vertices.length / this.size - count;
100
+ this.indices.push({
101
+ offset,
102
+ count,
103
+ extent: this.#currentExtent
104
+ });
105
+ if (this.extent) {
106
+ this.extent.union(this.#currentExtent);
107
+ this.#currentExtent = defaultExtent(this.extent.crs);
108
+ }
109
+ }
110
+ getLastSubGeometry() {
111
+ const last = this.indices.length - 1;
112
+ return this.indices[last];
113
+ }
114
+
115
+ /**
116
+ * Push new coordinates in vertices buffer.
117
+ * @param {Feature} feature - the feature containing the geometry
118
+ * @param {Coordinates} coordIn The coordinates to push.
119
+ */
120
+ pushCoordinates(feature, coordIn) {
121
+ if (feature.isCoordinates) {
122
+ console.warn('Deprecated: change in arguments order, use pushCoordinates(feature, coordIn) instead');
123
+ this.pushCoordinates(coordIn, feature);
124
+ return;
125
+ }
126
+ coordIn.as(feature.crs, coordOut);
127
+ feature.transformToLocalSystem(coordOut);
128
+ _setGeometryValues(feature, coordOut);
129
+
130
+ // expand extent if present
131
+ if (this.#currentExtent) {
132
+ this.#currentExtent.expandByCoordinates(feature.useCrsOut ? coordOut : coordIn);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Push new values coordinates in vertices buffer without any transformation.
138
+ * No geographical conversion is made or the normal doesn't stored.
139
+ *
140
+ * @param {Feature} feature - the feature containing the geometry
141
+ * @param {Object} coordIn An object containing the coordinates values to push.
142
+ * @param {number} coordIn.x the x coordinate (in a local system).
143
+ * @param {number} coordIn.y the y coordinate (in a local system).
144
+ * @param {THREE.Vector3} [coordIn.normal] the normal on coordinates (only for `EPSG:4978` projection).
145
+ * @param {Coordinates} [coordProj] An optional argument containing the geodesic coordinates in EPSG:4326
146
+ * It allows the user to get access to the feature coordinates to set style.base_altitude.
147
+ */
148
+ pushCoordinatesValues(feature, coordIn, coordProj) {
149
+ if ((arguments.length <= 3 ? 0 : arguments.length - 3) > 0) {
150
+ console.warn('Deprecated: change in arguments, use pushCoordinatesValues(feature, {x: long, y: lat, normal}, coordProj) instead');
151
+ this.pushCoordinatesValues(feature, {
152
+ x: coordIn,
153
+ y: coordProj,
154
+ normal: arguments.length <= 3 ? undefined : arguments[3]
155
+ }, arguments.length <= 4 ? undefined : arguments[4]);
156
+ return;
157
+ }
158
+ _setGeometryValues(feature, coordIn);
159
+
160
+ // expand extent if present
161
+ if (this.#currentExtent) {
162
+ this.#currentExtent.expandByValuesCoordinates(coordIn.x, coordIn.y);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * update geometry extent with the last sub geometry extent.
168
+ */
169
+ updateExtent() {
170
+ if (this.extent) {
171
+ const last = this.indices[this.indices.length - 1];
172
+ if (last) {
173
+ this.extent.union(last.extent);
174
+ }
175
+ }
176
+ }
177
+ }
178
+ function push2DValues(value0, value1) {
179
+ this.vertices[this._pos++] = value0;
180
+ this.vertices[this._pos++] = value1;
181
+ }
182
+ function push3DValues(value0, value1) {
183
+ let value2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
184
+ this.vertices[this._pos++] = value0;
185
+ this.vertices[this._pos++] = value1;
186
+ this.vertices[this._pos++] = value2;
187
+ }
188
+
189
+ /**
190
+ *
191
+ * This class improves and simplifies the construction and conversion of geographic data structures.
192
+ * It's an intermediary structure between geomatic formats and THREE objects.
193
+ *
194
+ * **Warning**, the data (`extent` or `Coordinates`) can be stored in a local system.
195
+ * To use vertices or extent in `Feature.crs` projection,
196
+ * it's necessary to transform `Coordinates` or `Extent` by `FeatureCollection.matrixWorld`.
197
+ *
198
+ * ```js
199
+ * // To have feature extent in featureCollection.crs projection:
200
+ * feature.extent.applyMatrix4(featureCollection.matrixWorld);
201
+ *
202
+ * // To have feature vertex in feature.crs projection:
203
+ * coord.crs = feature.crs;
204
+ * coord.setFromArray(feature.vertices)
205
+ * coord.applyMatrix4(featureCollection.matrixWorld);
206
+ *```
207
+ *
208
+ * @property {string} type - Geometry type, can be `point`, `line`, or
209
+ * `polygon`.
210
+ * @property {number[]} vertices - All the vertices of the Feature.
211
+ * @property {number[]} normals - All the normals of the Feature.
212
+ * @property {number} size - the number of values of the array that should be associated with a coordinates.
213
+ * The size is 3 with altitude and 2 without altitude.
214
+ * @property {boolean} hasRawElevationData - indicates if the geographic coordinates, from original source, has an elevation,
215
+ * the coordinates has a third coordinate.
216
+ * @property {string} crs - Geographic or Geocentric coordinates system.
217
+ * @property {FeatureGeometry[]} geometries - An array containing all {@link
218
+ * FeatureGeometry}.
219
+ * @property {Extent?} extent - The extent containing all the geometries
220
+ * composing the feature.
221
+ */
222
+ class Feature {
223
+ /**
224
+ *
225
+ * @param {string} type type of Feature. It can be 'point', 'line' or 'polygon'.
226
+ * @param {FeatureCollection} collection Parent feature collection.
227
+ */
228
+ constructor(type, collection) {
229
+ if (Object.keys(FEATURE_TYPES).find(t => FEATURE_TYPES[t] === type)) {
230
+ this.type = type;
231
+ } else {
232
+ throw new Error(`Unsupported Feature type: ${type}`);
233
+ }
234
+ this.geometries = [];
235
+ this.vertices = [];
236
+ this.crs = collection.crs;
237
+ this.size = collection.size;
238
+ this.normals = collection.crs == 'EPSG:4978' ? [] : undefined;
239
+ this.hasRawElevationData = false;
240
+ this.transformToLocalSystem = collection.transformToLocalSystem.bind(collection);
241
+ if (collection.extent) {
242
+ // this.crs is final crs projection, is out projection.
243
+ // If the extent crs is the same then we use output coordinate (coordOut) to expand it.
244
+ this.extent = defaultExtent(collection.extent.crs);
245
+ this.useCrsOut = this.extent.crs == this.crs;
246
+ }
247
+ this._pos = 0;
248
+ this._pushValues = (this.size === 3 ? push3DValues : push2DValues).bind(this);
249
+ this.style = StyleOptions.setFromProperties;
250
+ }
251
+ /**
252
+ * Instance a new {@link FeatureGeometry} and push in {@link Feature}.
253
+ * @returns {FeatureGeometry} the instancied geometry.
254
+ */
255
+ bindNewGeometry() {
256
+ const geometry = new FeatureGeometry(this);
257
+ this.geometries.push(geometry);
258
+ return geometry;
259
+ }
260
+ /**
261
+ * Update {@link Extent} feature with {@link Extent} geometry
262
+ * @param {FeatureGeometry} geometry used to update Feature {@link Extent}
263
+ */
264
+ updateExtent(geometry) {
265
+ if (this.extent) {
266
+ this.extent.union(geometry.extent);
267
+ }
268
+ }
269
+
270
+ /**
271
+ * @returns {number} the count of geometry.
272
+ */
273
+ get geometryCount() {
274
+ return this.geometries.length;
275
+ }
276
+ }
277
+ export default Feature;
278
+ const doNothing = () => {};
279
+ const transformToLocalSystem3D = (coord, collection) => {
280
+ coord.geodesicNormal.applyNormalMatrix(collection.normalMatrixInverse);
281
+ return coord.applyMatrix4(collection.matrixWorldInverse);
282
+ };
283
+ const transformToLocalSystem2D = (coord, collection) => coord.applyMatrix4(collection.matrixWorldInverse);
284
+ const axisZ = new THREE.Vector3(0, 0, 1);
285
+ const alignYtoEast = new THREE.Quaternion();
286
+ /**
287
+ * An object regrouping a list of [features]{@link Feature} and the extent of this collection.
288
+ * **Warning**, the data (`extent` or `Coordinates`) can be stored in a local system.
289
+ * The local system center is the `center` property.
290
+ * To use `Feature` vertices or `FeatureCollection/Feature` extent in FeatureCollection.crs projection,
291
+ * it's necessary to transform `Coordinates` or `Extent` by `FeatureCollection.matrixWorld`.
292
+ *
293
+ * ```js
294
+ * // To have featureCollection extent in featureCollection.crs projection:
295
+ * featureCollection.extent.applyMatrix4(featureCollection.matrixWorld);
296
+ *
297
+ * // To have feature vertex in featureCollection.crs projection:
298
+ * const vertices = featureCollection.features[0].vertices;
299
+ * coord.crs = featureCollection.crs;
300
+ * coord.setFromArray(vertices)
301
+ * coord.applyMatrix4(featureCollection.matrixWorld);
302
+ *```
303
+ *
304
+ * @extends THREE.Object3D
305
+ *
306
+ * @property {Feature[]} features - The array of features composing the
307
+ * collection.
308
+ * @property {Extent?} extent - The 2D extent containing all the features
309
+ * composing the collection. The extent projection is the same local projection `FeatureCollection`.
310
+ * To transform `FeatureCollection.extent` to `FeatureCollection.crs` projection, the transformation matrix must be applied.
311
+ *
312
+ * **WARNING** if crs is `EPSG:4978` because the 3d geocentric system doesn't work with 2D `Extent`,
313
+ * The FeatureCollection.extent projection is the original projection.
314
+ * In this case, there isn't need to transform the extent.
315
+ *
316
+ * @property {string} crs - Geographic or Geocentric coordinates system.
317
+ * @property {boolean} isFeatureCollection - Used to check whether this is FeatureCollection.
318
+ * @property {number} size - The size structure, it's 3 for 3d and 2 for 2d.
319
+ * @property {Style} style - The collection style used to display the feature collection.
320
+ * @property {boolean} isInverted - This option is to be set to the
321
+ * correct value, true or false (default being false), if the computation of
322
+ * the coordinates needs to be inverted to same scheme as OSM, Google Maps
323
+ * or other system. See [this link](
324
+ * https://alastaira.wordpress.com/2011/07/06/converting-tms-tile-coordinates-to-googlebingosm-tile-coordinates)
325
+ * for more informations.
326
+ * @property {THREE.Matrix4} matrixWorldInverse - The matrix world inverse.
327
+ * @property {Coordinates} center - The local center coordinates in `EPSG:4326`.
328
+ * The local system is centred in this center.
329
+ *
330
+ */
331
+
332
+ export class FeatureCollection extends THREE.Object3D {
333
+ #transformToLocalSystem = (() => transformToLocalSystem2D)();
334
+ #setLocalSystem = (() => doNothing)();
335
+ /**
336
+ * @param {FeatureBuildingOptions|Layer} options The building options .
337
+ */
338
+ constructor(options) {
339
+ super();
340
+ this.isFeatureCollection = true;
341
+ this.crs = options.accurate || !options.source?.crs ? options.crs : options.source.crs;
342
+ this.features = [];
343
+ this.mergeFeatures = options.mergeFeatures === undefined ? true : options.mergeFeatures;
344
+ this.size = options.structure == '3d' ? 3 : 2;
345
+ this.filterExtent = options.filterExtent;
346
+ this.style = options.style;
347
+ this.isInverted = false;
348
+ this.matrixWorldInverse = new THREE.Matrix4();
349
+ this.center = new Coordinates('EPSG:4326', 0, 0);
350
+ if (this.size == 2) {
351
+ this.extent = options.buildExtent === false ? undefined : defaultExtent(options.forcedExtentCrs || this.crs);
352
+ this.#setLocalSystem = center => {
353
+ // set local system center
354
+ center.as(this.crs, this.center);
355
+
356
+ // set position to local system center
357
+ this.position.copy(center);
358
+ this.updateMatrixWorld();
359
+ this.#setLocalSystem = doNothing;
360
+ };
361
+ } else {
362
+ this.extent = options.buildExtent ? defaultExtent(options.forcedExtentCrs || this.crs) : undefined;
363
+ this.#setLocalSystem = center => {
364
+ // set local system center
365
+ center.as('EPSG:4326', this.center);
366
+ if (this.crs == 'EPSG:4978') {
367
+ // align Z axe to geodesic normal.
368
+ this.quaternion.setFromUnitVectors(axisZ, center.geodesicNormal);
369
+ // align Y axe to East
370
+ alignYtoEast.setFromAxisAngle(axisZ, THREE.MathUtils.degToRad(90 + this.center.longitude));
371
+ this.quaternion.multiply(alignYtoEast);
372
+ }
373
+
374
+ // set position to local system center
375
+ this.position.copy(center);
376
+ this.updateMatrixWorld();
377
+ this.normalMatrix.getNormalMatrix(this.matrix);
378
+ this.normalMatrixInverse = new THREE.Matrix3().copy(this.normalMatrix).invert();
379
+ this.#setLocalSystem = doNothing;
380
+ };
381
+ this.#transformToLocalSystem = transformToLocalSystem3D;
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Apply the matrix World inverse on the coordinates.
387
+ * This method is used when the coordinates is pushed
388
+ * to transform it in local system.
389
+ *
390
+ * @param {Coordinates} coordinates The coordinates
391
+ * @returns {Coordinates} The coordinates in local system
392
+ */
393
+ transformToLocalSystem(coordinates) {
394
+ this.#setLocalSystem(coordinates);
395
+ return this.#transformToLocalSystem(coordinates, this);
396
+ }
397
+
398
+ /**
399
+ * Update FeatureCollection extent with `extent` or all features extent if
400
+ * `extent` is `undefined`.
401
+ * @param {Extent} extent
402
+ */
403
+ updateExtent(extent) {
404
+ if (this.extent) {
405
+ const extents = extent ? [extent] : this.features.map(feature => feature.extent);
406
+ for (const ext of extents) {
407
+ this.extent.union(ext);
408
+ }
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Updates the global transform of the object and its descendants.
414
+ *
415
+ * @param {boolean} force The force
416
+ */
417
+ updateMatrixWorld(force) {
418
+ super.updateMatrixWorld(force);
419
+ this.matrixWorldInverse.copy(this.matrixWorld).invert();
420
+ }
421
+
422
+ /**
423
+ * Remove features that don't have {@link FeatureGeometry}.
424
+ */
425
+ removeEmptyFeature() {
426
+ this.features = this.features.filter(feature => feature.geometries.length);
427
+ }
428
+
429
+ /**
430
+ * Push the `feature` in FeatureCollection.
431
+ * @param {Feature} feature
432
+ */
433
+ pushFeature(feature) {
434
+ this.features.push(feature);
435
+ this.updateExtent(feature.extent);
436
+ }
437
+ requestFeature(type, callback) {
438
+ const feature = this.features.find(callback);
439
+ if (feature && this.mergeFeatures) {
440
+ return feature;
441
+ } else {
442
+ const newFeature = new Feature(type, this);
443
+ this.features.push(newFeature);
444
+ return newFeature;
445
+ }
446
+ }
447
+
448
+ /**
449
+ * Returns the Feature by type if `mergeFeatures` is `true` or returns the
450
+ * new instance of typed Feature.
451
+ *
452
+ * @param {string} type the type requested
453
+ * @returns {Feature}
454
+ */
455
+ requestFeatureByType(type) {
456
+ return this.requestFeature(type, feature => feature.type === type);
457
+ }
458
+
459
+ /**
460
+ * Returns the Feature by type if `mergeFeatures` is `true` or returns the
461
+ * new instance of typed Feature.
462
+ *
463
+ * @param {string} id the id requested
464
+ * @param {string} type the type requested
465
+ * @returns {Feature}
466
+ */
467
+ requestFeatureById(id, type) {
468
+ return this.requestFeature(type, feature => feature.id === id);
469
+ }
470
+ /**
471
+ * Add a new feature with references to all properties.
472
+ * It allows to have features with different styles
473
+ * without having to duplicate the geometry.
474
+ * @param {Feature} feature The feature to reference.
475
+ * @return {Feature} The new referenced feature
476
+ */
477
+ newFeatureByReference(feature) {
478
+ const ref = new Feature(feature.type, this);
479
+ ref.extent = feature.extent;
480
+ ref.geometries = feature.geometries;
481
+ ref.normals = feature.normals;
482
+ ref.size = feature.size;
483
+ ref.vertices = feature.vertices;
484
+ ref._pos = feature._pos;
485
+ this.features.push(ref);
486
+ return ref;
487
+ }
488
+ }
@@ -0,0 +1,108 @@
1
+ import * as THREE from 'three';
2
+ import { Coordinates, CRS } from '@itowns/geographic';
3
+ const coord = new Coordinates('EPSG:4326');
4
+ const indexes = new THREE.Vector2();
5
+ function biLinearInterpolation(indexes, getData) {
6
+ const j = Math.floor(indexes.x);
7
+ const i = Math.floor(indexes.y);
8
+ const u = indexes.x - j;
9
+ const v = indexes.y - i;
10
+ return (1 - u) * ((1 - v) * getData(i, j) + v * getData(i + 1, j)) + u * ((1 - v) * getData(i, j + 1) + v * getData(i + 1, j + 1));
11
+ }
12
+
13
+ /**
14
+ * An instance of `GeoidGrid` allows accessing some geoid height grid data from geographic instances (like some
15
+ * {@link Coordinates}). The geoid height grid data must contain geoid height values for a set of geographic points
16
+ * regularly dispatched on a planar surface.
17
+ *
18
+ * @property {Extent} extent The geographic extent of the geoid height grid data.
19
+ * @property {THREE.Vector2} step The distance between two consecutive points of the geoid height grid. The
20
+ * `x` value stands for the distance along the West-East direction, and the
21
+ * `y` value stands for the distance along the South-North direction.
22
+ * @property {THREE.Vector2} dimensions The planar dimensions of the geoid height grid data extent.
23
+ * @property {THREE.Vector2} dataSize The number of values in the gridded data along the West-East direction (`x`
24
+ * axis) and the South-North direction (`y` axis).
25
+ *
26
+ * @example
27
+ * // Create a set of gridded data.
28
+ * const data = [
29
+ * [1, 2, 3],
30
+ * [2, 3, 4],
31
+ * [3, 4, 5],
32
+ * ];
33
+ * // This set of data presents the following spatial distribution of geoid heights values :
34
+ * //
35
+ * // Latitudes ^
36
+ * // |
37
+ * // 41.0 | 3 4 5
38
+ * // 40.5 | 2 3 4
39
+ * // 40.0 | 1 2 3
40
+ * // |------------->
41
+ * // 1 2 3 Longitudes
42
+ *
43
+ * // Create a GeoidGrid allowing to access the gridded data.
44
+ * const geoidGrid = new GeoidGrid(
45
+ * new Extent('EPSG:4326', 1, 3, 40, 41),
46
+ * new THREE.Vector2(1, 0.5),
47
+ * (verticalIndex, horizontalIndex) => data[verticalIndex][horizontalIndex],
48
+ * );
49
+ *
50
+ * // Access a value of geoid height at some geographic coordinates.
51
+ * // The value is interpolated from the gridded data.
52
+ * const value = geoidGrid.getHeightAtCoordinates(
53
+ * new Coordinates('EPSG:4326', 1.5, 40.25)
54
+ * );
55
+ * // This should return 2.0, which is the result from the bi-linear
56
+ * // interpolation at the center of the `[[1, 2], [2, 3]]` subsection
57
+ * // of the grid data.
58
+ */
59
+ class GeoidGrid {
60
+ /**
61
+ * @param {Extent} extent The geographic extent of the geoid height grid data.
62
+ * @param {THREE.Vector2} step The distance between two consecutive points of the geoid height grid. The
63
+ * `x` value stands for the distance along the West-East direction, and the
64
+ * `y` value stands for the distance along the South-North direction.
65
+ * @param {function} getData A method that allows reading a value in the geoid height grid from its
66
+ * vertical and horizontal indexes. The lower an index, the lower the
67
+ * coordinate on the corresponding axis - 0 being the index of the minimal
68
+ * coordinate of the gridded data on a given axis. In other words :
69
+ * - `getData(0, 0)` must return the geoid height value at the SOUTH-WEST
70
+ * corner of your data extent.
71
+ * - `getData(0, j)` must return a geoid height on the southern limit of your
72
+ * data extent.
73
+ * - `getData(i, 0)` must return a geoid height on the western limit of your
74
+ * data extent.
75
+ * - if your gridded data has dimensions (rowNumber, colNumber),
76
+ * `getData(rowNumber - 1, colNumber - 1)` must return the geoid height at
77
+ * the NORTH-EAST corner of your data extent.
78
+ */
79
+ constructor(extent, step, getData) {
80
+ CRS.isGeographic(extent.crs);
81
+ this.extent = extent;
82
+ this.step = new THREE.Vector2(step.x, step.y || step.x);
83
+ this.dimensions = this.extent.planarDimensions();
84
+ this.dataSize = new THREE.Vector2().addVectors(this.step, this.dimensions).divide(this.step).round();
85
+ this.getData = getData;
86
+ }
87
+
88
+ /**
89
+ * Get the value of the geoid height at given geographic {@link Coordinates}. The geoid height value is
90
+ * bi-linearly interpolated from the gridded data accessed by the `GeoidGrid` instance.
91
+ *
92
+ * @param {Coordinates} coordinates Geographic coordinates to get the geoid height value at.
93
+ *
94
+ * @returns {number} The geoid height value at the given {@link Coordinates}, bi-interpolated from the gridded
95
+ * data accessed by the `GeoidGrid` instance.
96
+ */
97
+ getHeightAtCoordinates(coordinates) {
98
+ coordinates.as(this.extent.crs, coord);
99
+ indexes.set((this.dataSize.x - 1) * (coord.x - this.extent.west) / this.dimensions.x, (this.dataSize.y - 1) * (coord.y - this.extent.south) / this.dimensions.y);
100
+
101
+ // TODO : add management for global GeoidGrid.
102
+ if (indexes.x < 0 || indexes.x >= this.dataSize.x - 1 || indexes.y < 0 || indexes.y >= this.dataSize.y - 1) {
103
+ return 0;
104
+ }
105
+ return biLinearInterpolation(indexes, this.getData);
106
+ }
107
+ }
108
+ export default GeoidGrid;