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,70 @@
1
+ /**
2
+ * @author Deepkolos / https://github.com/deepkolos
3
+ */
4
+
5
+ export class WorkerPool {
6
+ constructor() {
7
+ let pool = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 4;
8
+ this.pool = pool;
9
+ this.queue = [];
10
+ this.workers = [];
11
+ this.workersResolve = [];
12
+ this.workerStatus = 0;
13
+ }
14
+ _initWorker(workerId) {
15
+ if (!this.workers[workerId]) {
16
+ const worker = this.workerCreator();
17
+ worker.addEventListener('message', this._onMessage.bind(this, workerId));
18
+ this.workers[workerId] = worker;
19
+ }
20
+ }
21
+ _getIdleWorker() {
22
+ for (let i = 0; i < this.pool; i++) if (!(this.workerStatus & 1 << i)) return i;
23
+ return -1;
24
+ }
25
+ _onMessage(workerId, msg) {
26
+ const resolve = this.workersResolve[workerId];
27
+ resolve && resolve(msg);
28
+ if (this.queue.length) {
29
+ const {
30
+ resolve,
31
+ msg,
32
+ transfer
33
+ } = this.queue.shift();
34
+ this.workersResolve[workerId] = resolve;
35
+ this.workers[workerId].postMessage(msg, transfer);
36
+ } else {
37
+ this.workerStatus ^= 1 << workerId;
38
+ }
39
+ }
40
+ setWorkerCreator(workerCreator) {
41
+ this.workerCreator = workerCreator;
42
+ }
43
+ setWorkerLimit(pool) {
44
+ this.pool = pool;
45
+ }
46
+ postMessage(msg, transfer) {
47
+ return new Promise(resolve => {
48
+ const workerId = this._getIdleWorker();
49
+ if (workerId !== -1) {
50
+ this._initWorker(workerId);
51
+ this.workerStatus |= 1 << workerId;
52
+ this.workersResolve[workerId] = resolve;
53
+ this.workers[workerId].postMessage(msg, transfer);
54
+ } else {
55
+ this.queue.push({
56
+ resolve,
57
+ msg,
58
+ transfer
59
+ });
60
+ }
61
+ });
62
+ }
63
+ dispose() {
64
+ this.workers.forEach(worker => worker.terminate());
65
+ this.workersResolve.length = 0;
66
+ this.workers.length = 0;
67
+ this.queue.length = 0;
68
+ this.workerStatus = 0;
69
+ }
70
+ }
@@ -0,0 +1,554 @@
1
+ import * as THREE from 'three';
2
+ import TWEEN from '@tweenjs/tween.js';
3
+ import DEMUtils from "./DEMUtils.js";
4
+ import { MAIN_LOOP_EVENTS } from "../Core/MainLoop.js";
5
+ import { Coordinates, Ellipsoid } from '@itowns/geographic';
6
+ import OBB from "../Renderer/OBB.js";
7
+ import { VIEW_EVENTS } from "../Core/View.js";
8
+ THREE.Object3D.DEFAULT_UP.set(0, 0, 1);
9
+ const targetPosition = new THREE.Vector3();
10
+ const targetCoord = new Coordinates('EPSG:4326', 0, 0, 0);
11
+ const ellipsoid = new Ellipsoid();
12
+ const rigs = [];
13
+ const obb = new OBB();
14
+ const size = new THREE.Vector3();
15
+ const deferred = () => {
16
+ let resolve;
17
+ let reject;
18
+ return {
19
+ promise: new Promise((re, rej) => {
20
+ resolve = re;
21
+ reject = rej;
22
+ }),
23
+ resolve,
24
+ reject
25
+ };
26
+ };
27
+
28
+ // Wrap angle in degrees to [-180 180]
29
+ function wrapTo180(angle) {
30
+ return angle - Math.floor((angle + 180.0) / 360) * 360;
31
+ }
32
+ function tileLayer(view) {
33
+ return view.getLayers(l => l.isTiledGeometryLayer)[0];
34
+ }
35
+ export function getLookAtFromMath(view, camera) {
36
+ const direction = new THREE.Vector3(0, 0, 0.5);
37
+ direction.unproject(camera);
38
+ direction.sub(camera.position).normalize();
39
+ if (view.referenceCrs == 'EPSG:4978') {
40
+ // Intersect Ellispoid
41
+ return ellipsoid.intersection({
42
+ direction,
43
+ origin: camera.position
44
+ });
45
+ } else {
46
+ // Intersect plane
47
+ const distance = camera.position.z / direction.z;
48
+ return direction.multiplyScalar(distance).add(camera.position);
49
+ }
50
+ }
51
+ function proxyProperty(view, camera, rig, key) {
52
+ rig.proxy.position[key] = camera.position[key];
53
+ Object.defineProperty(camera.position, key, {
54
+ get: () => rig.proxy.position[key],
55
+ set: newValue => {
56
+ rig.removeProxy(view, camera);
57
+ camera.position[key] = newValue;
58
+ }
59
+ });
60
+ }
61
+
62
+ // the rig is used to manipulate the camera
63
+ // It consists of a tree of 3D objects, each element is assigned a task
64
+ //
65
+ // Transformation
66
+ //
67
+ // rig position on Coordinate (for the globe is rotation)
68
+ // |
69
+ // └── sealevel position on altitude zero
70
+ // |
71
+ // └── target position on DEM, and rotation (pitch and heading)
72
+ // |
73
+ // └── camera distance to target
74
+ //
75
+ // When all transformations are calculated,
76
+ // this.camera's transformation is applied to view.camera.camera
77
+ class CameraRig extends THREE.Object3D {
78
+ constructor() {
79
+ super();
80
+ // seaLevel is on rig's z axis, it's at altitude zero
81
+ this.seaLevel = new THREE.Object3D();
82
+ // target is on seaLevel's z axis and target.position.z is the DEM altitude
83
+ this.target = new THREE.Object3D();
84
+ this.target.rotation.order = 'ZXY';
85
+ // camera look at target
86
+ this.camera = new THREE.Camera();
87
+ this.add(this.seaLevel);
88
+ this.seaLevel.add(this.target);
89
+ this.target.add(this.camera);
90
+ // target's geographic coordinate
91
+ this.coord = new Coordinates('EPSG:4978', 0, 0);
92
+ // sea level's worldPoistion
93
+ this.targetWorldPosition = new THREE.Vector3();
94
+ this.removeAll = () => {};
95
+ this._onChangeCallback = null;
96
+ }
97
+
98
+ // apply rig.camera's transformation to camera
99
+ applyTransformToCamera(view, camera) {
100
+ if (this.proxy) {
101
+ camera.quaternion._onChange(this._onChangeCallback);
102
+ this.camera.matrixWorld.decompose(this.proxy.position, camera.quaternion, camera.scale);
103
+ camera.quaternion._onChange(() => this.removeProxy(view, camera));
104
+ } else {
105
+ this.camera.matrixWorld.decompose(camera.position, camera.quaternion, camera.scale);
106
+ }
107
+ view.dispatchEvent({
108
+ type: VIEW_EVENTS.CAMERA_MOVED,
109
+ coord: this.coord,
110
+ range: this.range,
111
+ heading: this.heading,
112
+ tilt: this.tilt
113
+ });
114
+ }
115
+ setProxy(view, camera) {
116
+ if (!this.proxy && view && camera) {
117
+ this.proxy = {
118
+ position: new THREE.Vector3()
119
+ };
120
+ Object.keys(camera.position).forEach(key => proxyProperty(view, camera, this, key));
121
+ this._onChangeCallback = camera.quaternion._onChangeCallback;
122
+ camera.quaternion._onChange(() => this.removeProxy(view, camera));
123
+ }
124
+ }
125
+ removeProxy(view, camera) {
126
+ this.stop(view);
127
+ if (this.proxy && view && camera) {
128
+ Object.keys(camera.position).forEach(key => Object.defineProperty(camera.position, key, {
129
+ value: this.proxy.position[key],
130
+ writable: true
131
+ }));
132
+ camera.quaternion._onChange(this._onChangeCallback);
133
+ this.proxy = null;
134
+ }
135
+ }
136
+ setTargetFromCoordinate(view, coord) {
137
+ // compute precise coordinate (coord) altitude and clamp it above seaLevel
138
+ coord.as(tileLayer(view).extent.crs, this.coord);
139
+ const altitude = Math.max(0, DEMUtils.getElevationValueAt(tileLayer(view), this.coord, DEMUtils.PRECISE_READ_Z) || this.coord.z);
140
+ this.coord.z = altitude;
141
+ // adjust target's position with clamped altitude
142
+ this.coord.as(view.referenceCrs).toVector3(targetPosition);
143
+ if (view.referenceCrs == 'EPSG:4978') {
144
+ // ellipsoid geocentric projection
145
+ this.lookAt(targetPosition);
146
+ this.seaLevel.position.set(0, 0, targetPosition.length() - altitude);
147
+ } else {
148
+ // planar projection
149
+ this.position.set(targetPosition.x, targetPosition.y, 0);
150
+ this.seaLevel.position.set(0, 0, 0);
151
+ }
152
+ // place camera's target
153
+ this.target.position.set(0, 0, altitude);
154
+ }
155
+
156
+ // set rig's objects transformation from camera's position and target's position
157
+ setFromPositions(view, cameraPosition) {
158
+ this.setTargetFromCoordinate(view, new Coordinates(view.referenceCrs).setFromVector3(targetPosition));
159
+ this.target.rotation.set(0, 0, 0);
160
+ this.updateMatrixWorld(true);
161
+ this.camera.position.copy(cameraPosition);
162
+ this.target.worldToLocal(this.camera.position);
163
+ const range = this.camera.position.length();
164
+ this.target.rotation.x = Math.asin(this.camera.position.z / range);
165
+ const cosPlanXY = THREE.MathUtils.clamp(this.camera.position.y / (Math.cos(this.target.rotation.x) * range), -1, 1);
166
+ this.target.rotation.z = Math.sign(-this.camera.position.x || 1) * Math.acos(cosPlanXY);
167
+ this.camera.position.set(0, range, 0);
168
+ }
169
+
170
+ // set from target's coordinate, rotation and range between target and camera
171
+ applyParams(view, params) {
172
+ if (params.coord) {
173
+ this.setTargetFromCoordinate(view, params.coord);
174
+ }
175
+ if (params.tilt != undefined) {
176
+ this.target.rotation.x = THREE.MathUtils.degToRad(params.tilt);
177
+ }
178
+ if (params.heading != undefined) {
179
+ this.target.rotation.z = THREE.MathUtils.degToRad(-wrapTo180(params.heading + 180));
180
+ }
181
+ if (params.range) {
182
+ this.camera.position.set(0, params.range, 0);
183
+ }
184
+ this.camera.rotation.set(-Math.PI * 0.5, 0, Math.PI);
185
+ this.updateMatrixWorld(true);
186
+ this.targetWorldPosition.setFromMatrixPosition(this.seaLevel.matrixWorld);
187
+ }
188
+ getParams() {
189
+ return {
190
+ coord: this.coord.clone(),
191
+ tilt: this.tilt,
192
+ heading: this.heading,
193
+ range: this.range,
194
+ targetWorldPosition: this.targetWorldPosition
195
+ };
196
+ }
197
+ setfromCamera(view, camera, pickedPosition) {
198
+ camera.updateMatrixWorld(true);
199
+ if (pickedPosition == undefined) {
200
+ pickedPosition = view.getPickingPositionFromDepth() || getLookAtFromMath(view, camera);
201
+ }
202
+ const range = pickedPosition && !isNaN(pickedPosition.x) ? camera.position.distanceTo(pickedPosition) : 100;
203
+ camera.localToWorld(targetPosition.set(0, 0, -range));
204
+ this.setFromPositions(view, camera.position);
205
+ }
206
+ copyObject3D(rig) {
207
+ this.copy(rig, false);
208
+ this.seaLevel.copy(rig.seaLevel, false);
209
+ this.target.copy(rig.target, false);
210
+ this.camera.copy(rig.camera);
211
+ return this;
212
+ }
213
+ animateCameraToLookAtTarget(view, camera, params) {
214
+ params.easing = params.easing || TWEEN.Easing.Quartic.InOut;
215
+ this.setfromCamera(view, camera);
216
+ const tweenGroup = new TWEEN.Group();
217
+ this.start = (this.start || new CameraRig()).copyObject3D(this);
218
+ this.end = (this.end || new CameraRig()).copyObject3D(this);
219
+ const time = params.time || 2500;
220
+ const factor = {
221
+ t: 0
222
+ };
223
+ const animations = [];
224
+ const def = deferred();
225
+ this.addPlaceTargetOnGround(view, camera, params.coord, factor);
226
+ this.end.applyParams(view, params);
227
+ // compute the angle along z-axis between the starting position and the end position
228
+ const difference = this.end.target.rotation.z - this.start.target.rotation.z;
229
+ // if that angle is superior to 180°, recompute the rotation as the complementary angle.
230
+ if (Math.abs(difference) > Math.PI) {
231
+ this.end.target.rotation.z = this.start.target.rotation.z + difference - Math.sign(difference) * 2 * Math.PI;
232
+ }
233
+ animations.push(new TWEEN.Tween(factor).to({
234
+ t: 1
235
+ }, time).easing(params.easing).onUpdate(d => {
236
+ // rotate to coord destination in geocentric projection
237
+ if (view.referenceCrs == 'EPSG:4978') {
238
+ this.quaternion.slerpQuaternions(this.start.quaternion, this.end.quaternion, d.t);
239
+ }
240
+ // camera rotation
241
+ this.camera.quaternion.slerpQuaternions(this.start.camera.quaternion, this.end.camera.quaternion, d.t);
242
+ // camera's target rotation
243
+ this.target.rotation.set(0, 0, 0);
244
+ this.target.rotateZ(THREE.MathUtils.lerp(this.start.target.rotation.z, this.end.target.rotation.z, d.t));
245
+ this.target.rotateX(THREE.MathUtils.lerp(this.start.target.rotation.x, this.end.target.rotation.x, d.t));
246
+ }));
247
+
248
+ // translate to coordinate destination in planar projection
249
+ if (view.referenceCrs != 'EPSG:4978') {
250
+ animations.push(new TWEEN.Tween(this.position).to(this.end.position, time).easing(params.easing));
251
+ }
252
+
253
+ // translate to altitude zero
254
+ animations.push(new TWEEN.Tween(this.seaLevel.position).to(this.end.seaLevel.position, time).easing(params.easing));
255
+
256
+ // translate camera position
257
+ animations.push(new TWEEN.Tween(this.camera.position).to(this.end.camera.position, time).easing(params.easing));
258
+ tweenGroup.add(...animations);
259
+
260
+ // update animations, transformation and view
261
+ this.animationFrameRequester = () => {
262
+ tweenGroup.update();
263
+ this.updateMatrixWorld(true);
264
+ this.applyTransformToCamera(view, camera);
265
+ this.targetWorldPosition.setFromMatrixPosition(this.seaLevel.matrixWorld);
266
+ if (params.callback) {
267
+ params.callback(this);
268
+ }
269
+ targetCoord.crs = view.referenceCrs;
270
+ targetCoord.setFromVector3(this.targetWorldPosition).as(tileLayer(view).extent.crs, this.coord);
271
+ view.notifyChange(camera);
272
+ };
273
+ this.removeAll = function (o) {
274
+ this.removeAll = () => {};
275
+ tweenGroup.removeAll();
276
+ if (this.animationFrameRequester) {
277
+ view.removeFrameRequester(MAIN_LOOP_EVENTS.BEFORE_RENDER, this.animationFrameRequester);
278
+ }
279
+ def.resolve(o !== undefined);
280
+ this.animationFrameRequester = null;
281
+ };
282
+
283
+ // Waiting last animation complete,
284
+ // we assume that the animation that completes last is the one that was started last
285
+ animations[animations.length - 1].onComplete(this.removeAll);
286
+ animations.forEach(anim => anim.start());
287
+ view.addFrameRequester(MAIN_LOOP_EVENTS.BEFORE_RENDER, this.animationFrameRequester);
288
+ view.notifyChange(camera);
289
+ return def;
290
+ }
291
+ stop(view) {
292
+ this.removePlaceTargetOnGround(view);
293
+ this.removeAll();
294
+ }
295
+
296
+ // update target position to coordinate's altitude
297
+ addPlaceTargetOnGround(view, camera, coord) {
298
+ let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
299
+ t: 1.0
300
+ };
301
+ this.removePlaceTargetOnGround(view);
302
+ if (view && camera) {
303
+ const startAltitude = this.target.position.z;
304
+ this.placeTargetOnGround = () => {
305
+ const altitude = Math.max(0, DEMUtils.getElevationValueAt(tileLayer(view), coord || this.coord, DEMUtils.PRECISE_READ_Z) || 0);
306
+ this.target.position.z = startAltitude * (1.0 - options.t) + altitude * options.t;
307
+ this.target.updateMatrixWorld(true);
308
+ this.applyTransformToCamera(view, camera);
309
+ };
310
+ this.placeTargetOnGround();
311
+ view.addFrameRequester(MAIN_LOOP_EVENTS.BEFORE_RENDER, this.placeTargetOnGround);
312
+ }
313
+ }
314
+ removePlaceTargetOnGround(view) {
315
+ if (view && this.placeTargetOnGround) {
316
+ view.removeFrameRequester(MAIN_LOOP_EVENTS.BEFORE_RENDER, this.placeTargetOnGround);
317
+ this.placeTargetOnGround = null;
318
+ }
319
+ }
320
+ get tilt() {
321
+ return THREE.MathUtils.radToDeg(this.target.rotation.x);
322
+ }
323
+ get heading() {
324
+ return -wrapTo180(THREE.MathUtils.radToDeg(this.target.rotation.z) + 180);
325
+ }
326
+ get range() {
327
+ return this.camera.position.y;
328
+ }
329
+ }
330
+ export function getRig(camera) {
331
+ rigs[camera.uuid] = rigs[camera.uuid] || new CameraRig();
332
+ return rigs[camera.uuid];
333
+ }
334
+
335
+ /**
336
+ * @module CameraUtils
337
+ */
338
+ export default {
339
+ /**
340
+ * @typedef {Object} CameraTransformOptions
341
+ * @property {Coordinate} [coord=currentCoordinate] Camera look at geographic coordinate
342
+ * @property {Number} [tilt=currentTilt] camera's tilt, in degree
343
+ * @property {Number} [heading=currentHeading] camera's heading, in degree
344
+ * @property {Number} [range=currentRange] camera distance to target coordinate, in meter
345
+ * @property {Number} [time=2500] duration of the animation, in ms
346
+ * @property {boolean} [proxy=true] use proxy to handling camera's transformation. if proxy == true, other camera's transformation stops rig's transformation
347
+ * @property {Number} [easing=TWEEN.Easing.Quartic.InOut] in and out easing animation
348
+ * @property {function} [callback] callback call each animation's frame (params are current cameraTransform and worldTargetPosition)
349
+ * @property {boolean} [stopPlaceOnGroundAtEnd=false] stop place target on the ground at animation ending
350
+ */
351
+ /**
352
+ * Default value for option to stop place target
353
+ * on the ground at animation ending.
354
+ * Default value is false.
355
+ */
356
+ defaultStopPlaceOnGroundAtEnd: false,
357
+ Easing: TWEEN.Easing,
358
+ /**
359
+ * Stop camera's animation
360
+ *
361
+ * @param {View} view The camera view
362
+ * @param {Camera} camera The camera to stop animation
363
+ */
364
+ stop(view, camera) {
365
+ getRig(camera).stop(view);
366
+ },
367
+ /**
368
+ * Gets the current parameters transform camera looking at target.
369
+ *
370
+ * @param {View} view The camera view
371
+ * @param {Camera} camera The camera to get transform
372
+ * @param {THREE.Vector3} [target] - The optional target
373
+ * @return {CameraUtils~CameraTransformOptions} The transform camera looking at target
374
+ */
375
+ getTransformCameraLookingAtTarget(view, camera, target) {
376
+ const rig = getRig(camera);
377
+ rig.setfromCamera(view, camera, target);
378
+ return rig.getParams();
379
+ },
380
+ /**
381
+ * Apply transform to camera
382
+ *
383
+ * @param {View} view The camera view
384
+ * @param {Camera} camera The camera to transform
385
+ * @param {CameraUtils~CameraTransformOptions|Extent} params The parameters
386
+ * @return {Promise} promise with resolve final CameraUtils~CameraTransformOptions
387
+ */
388
+ transformCameraToLookAtTarget(view, camera) {
389
+ let params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
390
+ if (params.isExtent) {
391
+ params = this.getCameraTransformOptionsFromExtent(view, camera, params);
392
+ }
393
+ params.proxy = params.proxy === undefined || params.proxy;
394
+ const rig = getRig(camera);
395
+ rig.stop(view);
396
+ rig.setfromCamera(view, camera);
397
+ if (params.proxy) {
398
+ rig.setProxy(view, camera);
399
+ }
400
+ rig.applyParams(view, params);
401
+ rig.addPlaceTargetOnGround(view, camera, params.coord);
402
+ rig.applyTransformToCamera(view, camera);
403
+ view.notifyChange(camera);
404
+ return Promise.resolve(rig.getParams());
405
+ },
406
+ /**
407
+ * Compute the CameraTransformOptions that allow a given camera to display a given extent in its entirety.
408
+ *
409
+ * @param {View} view The camera view
410
+ * @param {THREE.Camera} camera The camera to get the CameraTransformOptions from
411
+ * @param {Extent} extent The extent the camera must display
412
+ *
413
+ * @return {CameraUtils~CameraTransformOptions} The CameraTransformOptions allowing camera to display the extent.
414
+ */
415
+ getCameraTransformOptionsFromExtent(view, camera, extent) {
416
+ const cameraTransformOptions = {
417
+ coord: new Coordinates(extent.crs, 0, 0, 0),
418
+ heading: 0,
419
+ tilt: view.isPlanarView ? 90 : 89.9
420
+ };
421
+ let dimensions;
422
+ if (view.isGlobeView) {
423
+ extent = extent.as('EPSG:4326');
424
+ // compute extent's bounding box dimensions
425
+ obb.setFromExtent(extent);
426
+ // /!\ WARNING x and y are inverted, see issue #XXXX
427
+ obb.box3D.getSize(size);
428
+ dimensions = {
429
+ x: size.y,
430
+ y: size.x
431
+ };
432
+ } else {
433
+ extent = extent.as(view.referenceCrs);
434
+ dimensions = extent.planarDimensions();
435
+ }
436
+ extent.center(cameraTransformOptions.coord);
437
+ if (camera.isOrthographicCamera) {
438
+ // setup camera zoom
439
+ if (dimensions.x / dimensions.y > camera.aspect) {
440
+ camera.zoom = (camera.right - camera.left) / dimensions.x;
441
+ } else {
442
+ camera.zoom = (camera.top - camera.bottom) / dimensions.y;
443
+ }
444
+ camera.updateProjectionMatrix();
445
+
446
+ // setup camera placement
447
+ cameraTransformOptions.range = 1000;
448
+ } else if (camera.isPerspectiveCamera) {
449
+ // setup range for camera placement
450
+ const verticalFOV = THREE.MathUtils.degToRad(camera.fov);
451
+ if (dimensions.x / dimensions.y > camera.aspect) {
452
+ const focal = view.domElement.clientHeight * 0.5 / Math.tan(verticalFOV * 0.5);
453
+ const horizontalFOV = 2 * Math.atan(view.domElement.clientWidth * 0.5 / focal);
454
+ cameraTransformOptions.range = dimensions.x / (2 * Math.tan(horizontalFOV * 0.5));
455
+ } else {
456
+ cameraTransformOptions.range = dimensions.y / (2 * Math.tan(verticalFOV * 0.5));
457
+ }
458
+ }
459
+ return cameraTransformOptions;
460
+ },
461
+ /**
462
+ * Apply transform to camera with animation
463
+ *
464
+ * @param {View} view The camera view
465
+ * @param {Camera} camera The camera to animate
466
+ * @param {CameraUtils~CameraTransformOptions} params The parameters
467
+ * @return {Promise} promise with resolve final CameraUtils~CameraTransformOptions
468
+ */
469
+ animateCameraToLookAtTarget(view, camera) {
470
+ let params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
471
+ params.proxy = params.proxy === undefined || params.proxy;
472
+ const rig = getRig(camera);
473
+ rig.stop(view);
474
+ if (params.proxy) {
475
+ rig.setProxy(view, camera);
476
+ }
477
+ return rig.animateCameraToLookAtTarget(view, camera, params).promise.then(finished => {
478
+ const stopPlaceOnGround = params.stopPlaceOnGroundAtEnd === undefined ? this.defaultStopPlaceOnGroundAtEnd : params.stopPlaceOnGroundAtEnd;
479
+ const newTransformation = rig.getParams();
480
+ if (stopPlaceOnGround) {
481
+ rig.stop(view);
482
+ }
483
+ newTransformation.finished = finished;
484
+ return newTransformation;
485
+ });
486
+ },
487
+ /**
488
+ * chain animation transform to camera
489
+ *
490
+ * @param {View} view The camera view
491
+ * @param {Camera} camera The camera to animate
492
+ * @param {CameraUtils~CameraTransformOptions[]} params array parameters, each parameters transforms are apply to camera, in serial
493
+ * @return {Promise} promise with resolve final CameraUtils~CameraTransformOptions
494
+ */
495
+ sequenceAnimationsToLookAtTarget(view, camera) {
496
+ let params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [{}];
497
+ // convert each param to a function
498
+ const funcs = params.map(param => () => this.animateCameraToLookAtTarget(view, camera, param));
499
+
500
+ // execute Promises in serial
501
+ return (funcs => funcs.reduce((promise, func) => promise.then(result => {
502
+ const finished = result.length ? result[result.length - 1].finished : true;
503
+ if (finished) {
504
+ return func().then(Array.prototype.concat.bind(result));
505
+ } else {
506
+ return Promise.resolve([{
507
+ finished: false
508
+ }]);
509
+ }
510
+ }), Promise.resolve([])))(funcs);
511
+ },
512
+ /**
513
+ * Gets the difference camera transformation
514
+ *
515
+ * @param {CameraUtils~CameraTransformOptions} first param to compare with the second
516
+ * @param {CameraUtils~CameraTransformOptions} second param to compare with the first
517
+ * @return {object} The difference parameters
518
+ */
519
+ getDiffParams(first, second) {
520
+ if (!first || !second) {
521
+ return;
522
+ }
523
+ let diff;
524
+ if (Math.abs(first.range - second.range) / first.range > 0.001) {
525
+ diff = diff || {};
526
+ diff.range = {
527
+ previous: first.range,
528
+ new: second.range
529
+ };
530
+ }
531
+ if (Math.abs(first.tilt - second.tilt) > 0.1) {
532
+ diff = diff || {};
533
+ diff.tilt = {
534
+ previous: first.tilt,
535
+ new: second.tilt
536
+ };
537
+ }
538
+ if (Math.abs(first.heading - second.heading) > 0.1) {
539
+ diff = diff || {};
540
+ diff.heading = {
541
+ previous: first.heading,
542
+ new: second.heading
543
+ };
544
+ }
545
+ if (Math.abs(first.coord.x - second.coord.x) > 0.000001 || Math.abs(first.coord.y - second.coord.y) > 0.000001) {
546
+ diff = diff || {};
547
+ diff.coord = {
548
+ previous: first.coord,
549
+ new: second.coord
550
+ };
551
+ }
552
+ return diff;
553
+ }
554
+ };