easy-three-utils 0.0.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 (166) hide show
  1. package/package.json +12 -0
  2. package/src/common/index.ts +24 -0
  3. package/src/common/useLine2.ts +87 -0
  4. package/src/common/useLoader.ts +184 -0
  5. package/src/common/useLocationCalculator.ts +145 -0
  6. package/src/common/useMark.ts +42 -0
  7. package/src/common/useTween.ts +86 -0
  8. package/src/core/basic/camera.ts +28 -0
  9. package/src/core/basic/clock.ts +11 -0
  10. package/src/core/basic/control.ts +32 -0
  11. package/src/core/basic/index.ts +35 -0
  12. package/src/core/basic/labelRenderer.ts +26 -0
  13. package/src/core/basic/light.ts +63 -0
  14. package/src/core/basic/renderer.ts +37 -0
  15. package/src/core/basic/scene.ts +11 -0
  16. package/src/core/basic/stats.ts +16 -0
  17. package/src/core/event.ts +74 -0
  18. package/src/core/index.ts +11 -0
  19. package/src/core/main.ts +389 -0
  20. package/src/draco/README.md +32 -0
  21. package/src/draco/draco_decoder.js +34 -0
  22. package/src/draco/draco_decoder.wasm +0 -0
  23. package/src/draco/draco_encoder.js +33 -0
  24. package/src/draco/draco_wasm_wrapper.js +117 -0
  25. package/src/draco/gltf/draco_decoder.js +33 -0
  26. package/src/draco/gltf/draco_decoder.wasm +0 -0
  27. package/src/draco/gltf/draco_encoder.js +33 -0
  28. package/src/draco/gltf/draco_wasm_wrapper.js +116 -0
  29. package/src/tileRenderer/base/Tile.d.ts +50 -0
  30. package/src/tileRenderer/base/TileBase.d.ts +76 -0
  31. package/src/tileRenderer/base/TileInternal.d.ts +36 -0
  32. package/src/tileRenderer/base/TilesRendererBase.d.ts +35 -0
  33. package/src/tileRenderer/base/TilesRendererBase.js +847 -0
  34. package/src/tileRenderer/base/Tileset.d.ts +66 -0
  35. package/src/tileRenderer/base/constants.d.ts +6 -0
  36. package/src/tileRenderer/base/constants.js +16 -0
  37. package/src/tileRenderer/base/loaders/B3DMLoaderBase.d.ts +18 -0
  38. package/src/tileRenderer/base/loaders/B3DMLoaderBase.js +85 -0
  39. package/src/tileRenderer/base/loaders/CMPTLoaderBase.d.ts +22 -0
  40. package/src/tileRenderer/base/loaders/CMPTLoaderBase.js +61 -0
  41. package/src/tileRenderer/base/loaders/I3DMLoaderBase.d.ts +21 -0
  42. package/src/tileRenderer/base/loaders/I3DMLoaderBase.js +130 -0
  43. package/src/tileRenderer/base/loaders/LoaderBase.d.ts +10 -0
  44. package/src/tileRenderer/base/loaders/LoaderBase.js +73 -0
  45. package/src/tileRenderer/base/loaders/PNTSLoaderBase.d.ts +17 -0
  46. package/src/tileRenderer/base/loaders/PNTSLoaderBase.js +82 -0
  47. package/src/tileRenderer/base/plugins/ImplicitTilingPlugin.js +12 -0
  48. package/src/tileRenderer/base/traverseFunctions.js +468 -0
  49. package/src/tileRenderer/gltf.js +144 -0
  50. package/src/tileRenderer/index.d.ts +41 -0
  51. package/src/tileRenderer/index.js +44 -0
  52. package/src/tileRenderer/plugins/README.md +578 -0
  53. package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.d.ts +2 -0
  54. package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.js +84 -0
  55. package/src/tileRenderer/plugins/base/SUBTREELoader.js +876 -0
  56. package/src/tileRenderer/plugins/index.d.ts +17 -0
  57. package/src/tileRenderer/plugins/index.js +17 -0
  58. package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.d.ts +9 -0
  59. package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.js +175 -0
  60. package/src/tileRenderer/plugins/three/DebugTilesPlugin.d.ts +29 -0
  61. package/src/tileRenderer/plugins/three/DebugTilesPlugin.js +677 -0
  62. package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.d.ts +18 -0
  63. package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.js +86 -0
  64. package/src/tileRenderer/plugins/three/GoogleAttributionsManager.js +62 -0
  65. package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.d.ts +5 -0
  66. package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.js +200 -0
  67. package/src/tileRenderer/plugins/three/ReorientationPlugin.d.ts +12 -0
  68. package/src/tileRenderer/plugins/three/ReorientationPlugin.js +136 -0
  69. package/src/tileRenderer/plugins/three/TileCompressionPlugin.d.ts +18 -0
  70. package/src/tileRenderer/plugins/three/TileCompressionPlugin.js +223 -0
  71. package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.d.ts +5 -0
  72. package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.js +87 -0
  73. package/src/tileRenderer/plugins/three/fade/FadeManager.js +370 -0
  74. package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.d.ts +9 -0
  75. package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.js +318 -0
  76. package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.d.ts +5 -0
  77. package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.js +27 -0
  78. package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.d.ts +30 -0
  79. package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.js +76 -0
  80. package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.d.ts +49 -0
  81. package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.js +147 -0
  82. package/src/tileRenderer/plugins/three/gltf/metadata/classes/ClassProperty.js +149 -0
  83. package/src/tileRenderer/plugins/three/gltf/metadata/classes/MeshFeatures.js +215 -0
  84. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyAttributeAccessor.js +107 -0
  85. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertySetAccessor.js +45 -0
  86. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTableAccessor.js +209 -0
  87. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTextureAccessor.js +244 -0
  88. package/src/tileRenderer/plugins/three/gltf/metadata/classes/StructuralMetadata.js +202 -0
  89. package/src/tileRenderer/plugins/three/gltf/metadata/math/Matrix2.js +55 -0
  90. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/ClassPropertyHelpers.js +495 -0
  91. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TexCoordUtilities.js +72 -0
  92. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TextureReadUtility.js +154 -0
  93. package/src/tileRenderer/plugins/three/objects/EllipsoidRegionHelper.js +186 -0
  94. package/src/tileRenderer/plugins/three/objects/SphereHelper.js +55 -0
  95. package/src/tileRenderer/r3f/README.md +238 -0
  96. package/src/tileRenderer/r3f/components/CameraControls.jsx +132 -0
  97. package/src/tileRenderer/r3f/components/CameraTransition.jsx +177 -0
  98. package/src/tileRenderer/r3f/components/CanvasDOMOverlay.jsx +54 -0
  99. package/src/tileRenderer/r3f/components/CompassGizmo.jsx +260 -0
  100. package/src/tileRenderer/r3f/components/TilesAttributionOverlay.jsx +110 -0
  101. package/src/tileRenderer/r3f/components/TilesRenderer.jsx +239 -0
  102. package/src/tileRenderer/r3f/index.jsx +6 -0
  103. package/src/tileRenderer/r3f/utilities/useForceUpdate.jsx +8 -0
  104. package/src/tileRenderer/r3f/utilities/useObjectDep.jsx +59 -0
  105. package/src/tileRenderer/r3f/utilities/useOptions.jsx +143 -0
  106. package/src/tileRenderer/three/DebugTilesRenderer.d.ts +28 -0
  107. package/src/tileRenderer/three/DebugTilesRenderer.js +58 -0
  108. package/src/tileRenderer/three/TilesGroup.d.ts +9 -0
  109. package/src/tileRenderer/three/TilesGroup.js +91 -0
  110. package/src/tileRenderer/three/TilesRenderer.d.ts +37 -0
  111. package/src/tileRenderer/three/TilesRenderer.js +1049 -0
  112. package/src/tileRenderer/three/controls/CameraTransitionManager.js +305 -0
  113. package/src/tileRenderer/three/controls/EnvironmentControls.js +1295 -0
  114. package/src/tileRenderer/three/controls/GlobeControls.js +684 -0
  115. package/src/tileRenderer/three/controls/PivotPointMesh.js +104 -0
  116. package/src/tileRenderer/three/controls/PointerTracker.js +257 -0
  117. package/src/tileRenderer/three/controls/utils.js +113 -0
  118. package/src/tileRenderer/three/loaders/B3DMLoader.d.ts +26 -0
  119. package/src/tileRenderer/three/loaders/B3DMLoader.js +85 -0
  120. package/src/tileRenderer/three/loaders/CMPTLoader.d.ts +19 -0
  121. package/src/tileRenderer/three/loaders/CMPTLoader.js +97 -0
  122. package/src/tileRenderer/three/loaders/GLTFExtensionLoader.d.ts +11 -0
  123. package/src/tileRenderer/three/loaders/GLTFExtensionLoader.js +68 -0
  124. package/src/tileRenderer/three/loaders/I3DMLoader.d.ts +26 -0
  125. package/src/tileRenderer/three/loaders/I3DMLoader.js +256 -0
  126. package/src/tileRenderer/three/loaders/PNTSLoader.d.ts +25 -0
  127. package/src/tileRenderer/three/loaders/PNTSLoader.js +202 -0
  128. package/src/tileRenderer/three/loaders/gltf/GLTFCesiumRTCExtension.js +12 -0
  129. package/src/tileRenderer/three/loaders/gltf/GLTFMeshFeaturesExtension.js +12 -0
  130. package/src/tileRenderer/three/loaders/gltf/GLTFStructuralMetadataExtension.js +12 -0
  131. package/src/tileRenderer/three/math/Ellipsoid.d.ts +31 -0
  132. package/src/tileRenderer/three/math/Ellipsoid.js +337 -0
  133. package/src/tileRenderer/three/math/EllipsoidRegion.d.ts +23 -0
  134. package/src/tileRenderer/three/math/EllipsoidRegion.js +178 -0
  135. package/src/tileRenderer/three/math/ExtendedFrustum.js +65 -0
  136. package/src/tileRenderer/three/math/GeoConstants.d.ts +4 -0
  137. package/src/tileRenderer/three/math/GeoConstants.js +5 -0
  138. package/src/tileRenderer/three/math/GeoUtils.d.ts +9 -0
  139. package/src/tileRenderer/three/math/GeoUtils.js +106 -0
  140. package/src/tileRenderer/three/math/OBB.js +179 -0
  141. package/src/tileRenderer/three/math/TileBoundingVolume.js +272 -0
  142. package/src/tileRenderer/three/plugins/CesiumIonAuthPlugin.js +12 -0
  143. package/src/tileRenderer/three/plugins/DebugTilesPlugin.js +26 -0
  144. package/src/tileRenderer/three/plugins/GoogleCloudAuthPlugin.js +12 -0
  145. package/src/tileRenderer/three/raycastTraverse.js +178 -0
  146. package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.d.ts +14 -0
  147. package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.js +21 -0
  148. package/src/tileRenderer/three/renderers/GoogleTilesRenderer.d.ts +43 -0
  149. package/src/tileRenderer/three/renderers/GoogleTilesRenderer.js +48 -0
  150. package/src/tileRenderer/three/utilities.js +54 -0
  151. package/src/tileRenderer/utilities/BatchTable.d.ts +24 -0
  152. package/src/tileRenderer/utilities/BatchTable.js +82 -0
  153. package/src/tileRenderer/utilities/BatchTableHierarchyExtension.js +127 -0
  154. package/src/tileRenderer/utilities/FeatureTable.d.ts +30 -0
  155. package/src/tileRenderer/utilities/FeatureTable.js +159 -0
  156. package/src/tileRenderer/utilities/LRUCache.d.ts +8 -0
  157. package/src/tileRenderer/utilities/LRUCache.js +385 -0
  158. package/src/tileRenderer/utilities/PriorityQueue.d.ts +16 -0
  159. package/src/tileRenderer/utilities/PriorityQueue.js +137 -0
  160. package/src/tileRenderer/utilities/arrayToString.js +7 -0
  161. package/src/tileRenderer/utilities/readMagicBytes.js +29 -0
  162. package/src/tileRenderer/utilities/rgb565torgb.js +22 -0
  163. package/src/tileRenderer/utilities/urlExtension.js +34 -0
  164. package/tsconfig.json +42 -0
  165. package/tsconfig.node.json +11 -0
  166. package/typings/three.d.ts +27 -0
@@ -0,0 +1,684 @@
1
+ import {
2
+ Matrix4,
3
+ Quaternion,
4
+ Vector2,
5
+ Vector3,
6
+ MathUtils,
7
+ Ray,
8
+ } from 'three';
9
+ import { DRAG, EnvironmentControls, NONE } from './EnvironmentControls.js';
10
+ import { closestRayEllipsoidSurfacePointEstimate, closestRaySpherePointFromRotation, makeRotateAroundPoint, mouseToCoords, setRaycasterFromCamera } from './utils.js';
11
+ import { Ellipsoid } from '../math/Ellipsoid.js';
12
+
13
+ const _invMatrix = new Matrix4();
14
+ const _rotMatrix = new Matrix4();
15
+ const _pos = new Vector3();
16
+ const _vec = new Vector3();
17
+ const _center = new Vector3();
18
+ const _forward = new Vector3();
19
+ const _right = new Vector3();
20
+ const _targetRight = new Vector3();
21
+ const _globalUp = new Vector3();
22
+ const _quaternion = new Quaternion();
23
+ const _zoomPointUp = new Vector3();
24
+ const _toCenter = new Vector3();
25
+ const _latLon = {};
26
+ const _ray = new Ray();
27
+ const _ellipsoid = new Ellipsoid();
28
+
29
+ const _pointer = new Vector2();
30
+ const MIN_ELEVATION = 400;
31
+
32
+ export class GlobeControls extends EnvironmentControls {
33
+
34
+ get ellipsoid() {
35
+
36
+ return this.tilesRenderer ? this.tilesRenderer.ellipsoid : null;
37
+
38
+ }
39
+
40
+ get tilesGroup() {
41
+
42
+ return this.tilesRenderer ? this.tilesRenderer.group : null;
43
+
44
+ }
45
+
46
+ constructor( scene = null, camera = null, domElement = null, tilesRenderer = null ) {
47
+
48
+ // store which mode the drag stats are in
49
+ super( scene, camera, domElement );
50
+
51
+ this.isGlobeControls = true;
52
+
53
+ this._dragMode = 0;
54
+ this._rotationMode = 0;
55
+ this.maxZoom = 0.01;
56
+ this.useFallbackPlane = false;
57
+ this.reorientOnDrag = false;
58
+
59
+ this.dragQuaternion = new Quaternion();
60
+
61
+ this.setTilesRenderer( tilesRenderer );
62
+
63
+ }
64
+
65
+ setScene( scene ) {
66
+
67
+ if ( scene === null && this.tilesRenderer !== null ) {
68
+
69
+ super.setScene( this.tilesRenderer.group );
70
+
71
+ } else {
72
+
73
+ super.setScene( scene );
74
+
75
+ }
76
+
77
+ }
78
+
79
+ getPivotPoint( target ) {
80
+
81
+ const { camera, tilesGroup, ellipsoid } = this;
82
+
83
+ // get camera values
84
+ _forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
85
+ _invMatrix.copy( tilesGroup.matrixWorld ).invert();
86
+
87
+ // set a ray in the local ellipsoid frame
88
+ _ray.origin.copy( camera.position );
89
+ _ray.direction.copy( _forward );
90
+ _ray.applyMatrix4( _invMatrix );
91
+
92
+ // get the estimated closest point
93
+ closestRayEllipsoidSurfacePointEstimate( _ray, ellipsoid, _vec );
94
+ _vec.applyMatrix4( tilesGroup.matrixWorld );
95
+
96
+ // use the closest point if no pivot was provided or it's closer
97
+ if (
98
+ super.getPivotPoint( target ) === null ||
99
+ target.distanceTo( _ray.origin ) > _vec.distanceTo( _ray.origin )
100
+ ) {
101
+
102
+ target.copy( _vec );
103
+
104
+ }
105
+
106
+ return target;
107
+
108
+ }
109
+
110
+ // get the vector to the center of the provided globe
111
+ getVectorToCenter( target ) {
112
+
113
+ const { tilesGroup, camera } = this;
114
+ return target
115
+ .setFromMatrixPosition( tilesGroup.matrixWorld )
116
+ .sub( camera.position );
117
+
118
+ }
119
+
120
+ // get the distance to the center of the globe
121
+ getDistanceToCenter() {
122
+
123
+ return this
124
+ .getVectorToCenter( _vec )
125
+ .length();
126
+
127
+ }
128
+
129
+ getUpDirection( point, target ) {
130
+
131
+ // get the "up" direction based on the wgs84 ellipsoid
132
+ const { tilesGroup, ellipsoid } = this;
133
+ _invMatrix.copy( tilesGroup.matrixWorld ).invert();
134
+ _vec.copy( point ).applyMatrix4( _invMatrix );
135
+
136
+ ellipsoid.getPositionToNormal( _vec, target );
137
+ target.transformDirection( tilesGroup.matrixWorld );
138
+
139
+ }
140
+
141
+ getCameraUpDirection( target ) {
142
+
143
+ const { tilesGroup, ellipsoid, camera } = this;
144
+ if ( camera.isOrthographicCamera ) {
145
+
146
+ this._getVirtualOrthoCameraPosition( _vec );
147
+
148
+ _invMatrix.copy( tilesGroup.matrixWorld ).invert();
149
+ _vec.applyMatrix4( _invMatrix );
150
+
151
+ ellipsoid.getPositionToNormal( _vec, target );
152
+ target.transformDirection( tilesGroup.matrixWorld );
153
+
154
+ } else {
155
+
156
+ this.getUpDirection( camera.position, target );
157
+
158
+ }
159
+
160
+ }
161
+
162
+ update( deltaTime = Math.min( this.clock.getDelta(), 64 / 1000 ) ) {
163
+
164
+ if ( ! this.enabled || ! this.tilesGroup || ! this.camera || deltaTime === 0 ) {
165
+
166
+ return;
167
+
168
+ }
169
+
170
+ const { camera, pivotMesh } = this;
171
+
172
+ // if we're outside the transition threshold then we toggle some reorientation behavior
173
+ // when adjusting the up frame while moving the camera
174
+ if ( this._isNearControls() ) {
175
+
176
+ this.scaleZoomOrientationAtEdges = this.zoomDelta < 0;
177
+
178
+ } else {
179
+
180
+ if ( this.state !== NONE && this._dragMode !== 1 && this._rotationMode !== 1 ) {
181
+
182
+ pivotMesh.visible = false;
183
+
184
+ }
185
+ this.scaleZoomOrientationAtEdges = false;
186
+
187
+ }
188
+
189
+ // fire basic controls update
190
+ super.update( deltaTime );
191
+
192
+ // update the camera planes and the ortho camera position
193
+ this.adjustCamera( camera );
194
+
195
+ }
196
+
197
+ // Updates the passed camera near and far clip planes to encapsulate the ellipsoid from the
198
+ // current position in addition to adjusting the height.
199
+ adjustCamera( camera ) {
200
+
201
+ super.adjustCamera( camera );
202
+
203
+ const { tilesGroup, ellipsoid } = this;
204
+ if ( camera.isPerspectiveCamera ) {
205
+
206
+ // adjust the clip planes
207
+ const distanceToCenter = _vec
208
+ .setFromMatrixPosition( tilesGroup.matrixWorld )
209
+ .sub( camera.position ).length();
210
+
211
+ // update the projection matrix
212
+ // interpolate from the 25% radius margin around the globe down to the surface
213
+ // so we can avoid z fighting when near value is too far at a high altitude
214
+ const largestDistance = Math.max( ...ellipsoid.radius );
215
+ const margin = 0.25 * largestDistance;
216
+ const alpha = MathUtils.clamp( ( distanceToCenter - largestDistance ) / margin, 0, 1 );
217
+ const minNear = MathUtils.lerp( 1, 1000, alpha );
218
+ camera.near = Math.max( minNear, distanceToCenter - largestDistance - margin );
219
+
220
+ // update the far plane to the horizon distance
221
+ const invMatrix = _invMatrix.copy( tilesGroup.matrixWorld ).invert();
222
+ _pos.copy( camera.position ).applyMatrix4( invMatrix );
223
+ ellipsoid.getPositionToCartographic( _pos, _latLon );
224
+
225
+ // use a minimum elevation for computing the horizon distance to avoid the far clip
226
+ // plane approaching zero as the camera goes to or below sea level.
227
+ const elevation = Math.max( ellipsoid.getPositionElevation( _pos ), MIN_ELEVATION );
228
+ const horizonDistance = ellipsoid.calculateHorizonDistance( _latLon.lat, elevation );
229
+
230
+ // extend the horizon distance by 2.5 to handle cases where geometry extends above the horizon
231
+ camera.far = horizonDistance * 2.5 + 0.1;
232
+ camera.updateProjectionMatrix();
233
+
234
+ } else {
235
+
236
+ this._getVirtualOrthoCameraPosition( camera.position, camera );
237
+ camera.updateMatrixWorld();
238
+
239
+ _invMatrix.copy( camera.matrixWorld ).invert();
240
+ _vec.setFromMatrixPosition( tilesGroup.matrixWorld ).applyMatrix4( _invMatrix );
241
+
242
+ const distanceToCenter = - _vec.z;
243
+ camera.near = distanceToCenter - Math.max( ...ellipsoid.radius ) * 1.1;
244
+ camera.far = distanceToCenter + 0.1;
245
+
246
+ // adjust the position of the ortho camera such that the near value is 0
247
+ camera.position.addScaledVector( _forward, camera.near );
248
+ camera.far -= camera.near;
249
+ camera.near = 0;
250
+
251
+ camera.updateProjectionMatrix();
252
+ camera.updateMatrixWorld();
253
+
254
+ }
255
+
256
+ }
257
+
258
+ // resets the "stuck" drag modes
259
+ resetState() {
260
+
261
+ super.resetState();
262
+ this._dragMode = 0;
263
+ this._rotationMode = 0;
264
+
265
+ }
266
+
267
+ _updatePosition( deltaTime ) {
268
+
269
+ if ( this.state !== DRAG ) {
270
+
271
+ const {
272
+ enableDamping,
273
+ tilesGroup,
274
+ dragQuaternion,
275
+ dragInertia,
276
+ camera,
277
+ } = this;
278
+
279
+ // apply inertia for movement
280
+ if ( enableDamping ) {
281
+
282
+ // ensure our w component is non-one if the xyz values are
283
+ // non zero to ensure we can animate
284
+ if (
285
+ dragQuaternion.w === 1 && (
286
+ dragQuaternion.x !== 0 ||
287
+ dragQuaternion.y !== 0 ||
288
+ dragQuaternion.z !== 0
289
+ )
290
+ ) {
291
+
292
+ dragQuaternion.w = Math.min( dragQuaternion.w, 1 - 1e-9 );
293
+
294
+ }
295
+
296
+ // construct the rotation matrix
297
+ _center.setFromMatrixPosition( tilesGroup.matrixWorld );
298
+ _quaternion.identity().slerp( dragQuaternion, dragInertia.x * deltaTime );
299
+ makeRotateAroundPoint( _center, _quaternion, _rotMatrix );
300
+
301
+ // apply the rotation
302
+ camera.matrixWorld.premultiply( _rotMatrix );
303
+ camera.matrixWorld.decompose( camera.position, camera.quaternion, _vec );
304
+
305
+ }
306
+
307
+ } else {
308
+
309
+ // save the drag mode state so we can update the pivot mesh visuals in "update"
310
+ if ( this._dragMode === 0 ) {
311
+
312
+ this._dragMode = this._isNearControls() ? 1 : - 1;
313
+
314
+ }
315
+
316
+ const {
317
+ raycaster,
318
+ camera,
319
+ pivotPoint,
320
+ pointerTracker,
321
+ domElement,
322
+ tilesGroup,
323
+ } = this;
324
+
325
+ // reuse cache variables
326
+ const pivotDir = _pos;
327
+ const newPivotDir = _targetRight;
328
+
329
+ // get the pointer and ray
330
+ pointerTracker.getCenterPoint( _pointer );
331
+ mouseToCoords( _pointer.x, _pointer.y, domElement, _pointer );
332
+ setRaycasterFromCamera( raycaster, _pointer, camera );
333
+
334
+ // transform to ellipsoid frame
335
+ _invMatrix.copy( tilesGroup.matrixWorld ).invert();
336
+ raycaster.ray.applyMatrix4( _invMatrix );
337
+
338
+ // construct an ellipsoid that matches a sphere with the radius of the globe so
339
+ // the drag position matches where the initial click was
340
+ const pivotRadius = _vec.copy( pivotPoint ).applyMatrix4( _invMatrix ).length();
341
+ _ellipsoid.radius.setScalar( pivotRadius );
342
+
343
+ // find the hit point and use the closest point on the horizon if we miss
344
+ if ( camera.isPerspectiveCamera ) {
345
+
346
+ if ( ! _ellipsoid.intersectRay( raycaster.ray, _vec ) ) {
347
+
348
+ closestRaySpherePointFromRotation( raycaster.ray, pivotRadius, _vec );
349
+
350
+ }
351
+
352
+ } else {
353
+
354
+ closestRayEllipsoidSurfacePointEstimate( raycaster.ray, _ellipsoid, _vec );
355
+
356
+ }
357
+ _vec.applyMatrix4( tilesGroup.matrixWorld );
358
+
359
+ // get the point directions
360
+ _center.setFromMatrixPosition( tilesGroup.matrixWorld );
361
+ pivotDir.subVectors( pivotPoint, _center ).normalize();
362
+ newPivotDir.subVectors( _vec, _center ).normalize();
363
+
364
+ // construct the rotation
365
+ _quaternion.setFromUnitVectors( newPivotDir, pivotDir );
366
+ makeRotateAroundPoint( _center, _quaternion, _rotMatrix );
367
+
368
+ // apply the rotation
369
+ camera.matrixWorld.premultiply( _rotMatrix );
370
+ camera.matrixWorld.decompose( camera.position, camera.quaternion, _vec );
371
+
372
+ const { dragInertia, dragQuaternion } = this;
373
+ if ( pointerTracker.getMoveDistance() / deltaTime < 2 * window.devicePixelRatio ) {
374
+
375
+ dragQuaternion.slerp( _quaternion, 0.5 );
376
+ dragInertia.set( 1 / deltaTime, 0, 0 );
377
+
378
+ } else {
379
+
380
+ dragQuaternion.copy( _quaternion );
381
+ dragInertia.set( 1 / deltaTime, 0, 0 );
382
+
383
+ }
384
+
385
+ }
386
+
387
+ this._alignCameraUp( this.up );
388
+
389
+ }
390
+
391
+ // disable rotation once we're outside the control transition
392
+ _updateRotation( ...args ) {
393
+
394
+ if ( this._rotationMode === 1 || this._isNearControls() ) {
395
+
396
+ this._rotationMode = 1;
397
+ super._updateRotation( ...args );
398
+
399
+ } else {
400
+
401
+ this.pivotMesh.visible = false;
402
+ this._rotationMode = - 1;
403
+
404
+ }
405
+
406
+ this._alignCameraUp( this.up );
407
+
408
+ }
409
+
410
+ _updateZoom() {
411
+
412
+ const { zoomDelta, ellipsoid, zoomSpeed, zoomPoint, camera, maxZoom } = this;
413
+
414
+ // used to scale the tilt transitions based on zoom intensity
415
+ const deltaAlpha = MathUtils.clamp( MathUtils.mapLinear( Math.abs( zoomDelta ), 0, 20, 0, 1 ), 0, 1 );
416
+ if ( this._isNearControls() || zoomDelta > 0 ) {
417
+
418
+ this._updateZoomDirection();
419
+
420
+ // When zooming try to tilt the camera towards the center of the planet to avoid the globe
421
+ // spinning as you zoom out from the horizon
422
+ if ( zoomDelta < 0 && ( this.zoomPointSet || this._updateZoomPoint() ) ) {
423
+
424
+ // get the forward vector and vector toward the center of the ellipsoid
425
+ _forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ).normalize();
426
+ _toCenter.copy( this.up ).multiplyScalar( - 1 );
427
+
428
+ // Calculate alpha values to use to scale the amount of tilt that occurs as the camera moves.
429
+ // Scales based on mouse position near the horizon and current tilt.
430
+ this.getUpDirection( zoomPoint, _zoomPointUp );
431
+ const upAlpha = MathUtils.clamp( MathUtils.mapLinear( - _zoomPointUp.dot( _toCenter ), 1, 0.95, 0, 1 ), 0, 1 );
432
+ const forwardAlpha = 1 - _forward.dot( _toCenter );
433
+ const cameraAlpha = camera.isOrthographicCamera ? 0.05 : 1;
434
+ const adjustedDeltaAlpha = MathUtils.clamp( deltaAlpha * 3, 0, 1 );
435
+
436
+ // apply scale
437
+ const alpha = Math.min( upAlpha * forwardAlpha * cameraAlpha * adjustedDeltaAlpha, 0.1 );
438
+ _toCenter.lerpVectors( _forward, _toCenter, alpha ).normalize();
439
+
440
+ // perform rotation
441
+ _quaternion.setFromUnitVectors( _forward, _toCenter );
442
+ makeRotateAroundPoint( zoomPoint, _quaternion, _rotMatrix );
443
+ camera.matrixWorld.premultiply( _rotMatrix );
444
+ camera.matrixWorld.decompose( camera.position, camera.quaternion, _toCenter );
445
+
446
+ // update zoom direction
447
+ this.zoomDirection.subVectors( zoomPoint, camera.position ).normalize();
448
+
449
+ }
450
+
451
+ super._updateZoom();
452
+
453
+ } else if ( camera.isPerspectiveCamera ) {
454
+
455
+ // orient the camera to focus on the earth during the zoom
456
+ const transitionDistance = this._getPerspectiveTransitionDistance();
457
+ const maxDistance = this._getMaxPerspectiveDistance();
458
+ const distanceAlpha = MathUtils.mapLinear( this.getDistanceToCenter(), transitionDistance, maxDistance, 0, 1 );
459
+ this._tiltTowardsCenter( MathUtils.lerp( 0, 0.4, distanceAlpha * deltaAlpha ) );
460
+ this._alignCameraUpToNorth( MathUtils.lerp( 0, 0.2, distanceAlpha * deltaAlpha ) );
461
+
462
+ // calculate zoom in a similar way to environment controls so
463
+ // the zoom speeds are comparable
464
+ const dist = this.getDistanceToCenter() - ellipsoid.radius.x;
465
+ const scale = zoomDelta * dist * zoomSpeed * 0.0025;
466
+ const clampedScale = Math.max( scale, Math.min( this.getDistanceToCenter() - maxDistance, 0 ) );
467
+
468
+ // zoom out directly from the globe center
469
+ this.getVectorToCenter( _vec ).normalize();
470
+ this.camera.position.addScaledVector( _vec, clampedScale );
471
+ this.camera.updateMatrixWorld();
472
+
473
+ this.zoomDelta = 0;
474
+
475
+ } else {
476
+
477
+ const transitionZoom = this._getOrthographicTransitionZoom();
478
+ const minZoom = this._getMinOrthographicZoom();
479
+ const distanceAlpha = MathUtils.mapLinear( camera.zoom, transitionZoom, minZoom, 0, 1 );
480
+ this._tiltTowardsCenter( MathUtils.lerp( 0, 0.4, distanceAlpha * deltaAlpha ) );
481
+ this._alignCameraUpToNorth( MathUtils.lerp( 0, 0.2, distanceAlpha * deltaAlpha ) );
482
+
483
+ const scale = this.zoomDelta;
484
+ const normalizedDelta = Math.pow( 0.95, Math.abs( scale * 0.05 ) );
485
+ const scaleFactor = scale > 0 ? 1 / Math.abs( normalizedDelta ) : normalizedDelta;
486
+
487
+ const maxScaleFactor = minZoom / camera.zoom;
488
+ const clampedScaleFactor = Math.max( scaleFactor * zoomSpeed, Math.min( maxScaleFactor, 1 ) );
489
+
490
+ camera.zoom = Math.min( maxZoom, camera.zoom * clampedScaleFactor );
491
+ camera.updateProjectionMatrix();
492
+
493
+ this.zoomDelta = 0;
494
+ this.zoomDirectionSet = false;
495
+
496
+ }
497
+
498
+ }
499
+
500
+ // tilt the camera to align with north
501
+ _alignCameraUpToNorth( alpha ) {
502
+
503
+ const { tilesGroup } = this;
504
+ _globalUp.set( 0, 0, 1 ).transformDirection( tilesGroup.matrixWorld );
505
+ this._alignCameraUp( _globalUp, alpha );
506
+
507
+ }
508
+
509
+ // tilt the camera to align with the provided "up" value
510
+ _alignCameraUp( up, alpha = null ) {
511
+
512
+ const { camera } = this;
513
+ _forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
514
+ _right.set( - 1, 0, 0 ).transformDirection( camera.matrixWorld );
515
+ _targetRight.crossVectors( up, _forward );
516
+
517
+ // compute the alpha based on how far away from boresight the up vector is
518
+ // so we can ease into the correct orientation
519
+ if ( alpha === null ) {
520
+
521
+ alpha = 1 - Math.abs( _forward.dot( up ) );
522
+ alpha = MathUtils.mapLinear( alpha, 0, 1, - 0.01, 1 );
523
+ alpha = MathUtils.clamp( alpha, 0, 1 ) ** 2;
524
+
525
+ }
526
+
527
+ _targetRight.lerp( _right, 1 - alpha ).normalize();
528
+
529
+ _quaternion.setFromUnitVectors( _right, _targetRight );
530
+ camera.quaternion.premultiply( _quaternion );
531
+ camera.updateMatrixWorld();
532
+
533
+ }
534
+
535
+ // tilt the camera to look at the center of the globe
536
+ _tiltTowardsCenter( alpha ) {
537
+
538
+ const {
539
+ camera,
540
+ tilesGroup,
541
+ } = this;
542
+
543
+ _forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ).normalize();
544
+ _vec.setFromMatrixPosition( tilesGroup.matrixWorld ).sub( camera.position ).normalize();
545
+ _vec.lerp( _forward, 1 - alpha ).normalize();
546
+
547
+ _quaternion.setFromUnitVectors( _forward, _vec );
548
+ camera.quaternion.premultiply( _quaternion );
549
+ camera.updateMatrixWorld();
550
+
551
+ }
552
+
553
+ // returns the perspective camera transition distance can move to based on globe size and fov
554
+ _getPerspectiveTransitionDistance() {
555
+
556
+ const { camera, ellipsoid } = this;
557
+ if ( ! camera.isPerspectiveCamera ) {
558
+
559
+ throw new Error();
560
+
561
+ }
562
+
563
+ // When the smallest fov spans 65% of the ellipsoid then we use the near controls
564
+ const ellipsoidRadius = Math.max( ...ellipsoid.radius );
565
+ const fovHoriz = 2 * Math.atan( Math.tan( MathUtils.DEG2RAD * camera.fov * 0.5 ) * camera.aspect );
566
+ const distVert = ellipsoidRadius / Math.tan( MathUtils.DEG2RAD * camera.fov * 0.5 );
567
+ const distHoriz = ellipsoidRadius / Math.tan( fovHoriz * 0.5 );
568
+ const dist = Math.max( distVert, distHoriz );
569
+
570
+ return dist;
571
+
572
+ }
573
+
574
+ // returns the max distance the perspective camera can move to based on globe size and fov
575
+ _getMaxPerspectiveDistance() {
576
+
577
+ const { camera, ellipsoid } = this;
578
+ if ( ! camera.isPerspectiveCamera ) {
579
+
580
+ throw new Error();
581
+
582
+ }
583
+
584
+ // allow for zooming out such that the ellipsoid is half the size of the largest fov
585
+ const ellipsoidRadius = Math.max( ...ellipsoid.radius );
586
+ const fovHoriz = 2 * Math.atan( Math.tan( MathUtils.DEG2RAD * camera.fov * 0.5 ) * camera.aspect );
587
+ const distVert = ellipsoidRadius / Math.tan( MathUtils.DEG2RAD * camera.fov * 0.5 );
588
+ const distHoriz = ellipsoidRadius / Math.tan( fovHoriz * 0.5 );
589
+ const dist = 2 * Math.max( distVert, distHoriz );
590
+
591
+ return dist;
592
+
593
+ }
594
+
595
+ // returns the transition threshold for orthographic zoom based on the globe size and camera settings
596
+ _getOrthographicTransitionZoom() {
597
+
598
+ const { camera, ellipsoid } = this;
599
+ if ( ! camera.isOrthographicCamera ) {
600
+
601
+ throw new Error();
602
+
603
+ }
604
+
605
+ const orthoHeight = ( camera.top - camera.bottom );
606
+ const orthoWidth = ( camera.right - camera.left );
607
+ const orthoSize = Math.max( orthoHeight, orthoWidth );
608
+ const ellipsoidRadius = Math.max( ...ellipsoid.radius );
609
+ const ellipsoidDiameter = 2 * ellipsoidRadius;
610
+ return 2 * orthoSize / ellipsoidDiameter;
611
+
612
+ }
613
+
614
+ // returns the minimum allowed orthographic zoom based on the globe size and camera settings
615
+ _getMinOrthographicZoom() {
616
+
617
+ const { camera, ellipsoid } = this;
618
+ if ( ! camera.isOrthographicCamera ) {
619
+
620
+ throw new Error();
621
+
622
+ }
623
+
624
+ const orthoHeight = ( camera.top - camera.bottom );
625
+ const orthoWidth = ( camera.right - camera.left );
626
+ const orthoSize = Math.min( orthoHeight, orthoWidth );
627
+ const ellipsoidRadius = Math.max( ...ellipsoid.radius );
628
+ const ellipsoidDiameter = 2 * ellipsoidRadius;
629
+ return 0.7 * orthoSize / ellipsoidDiameter;
630
+
631
+ }
632
+
633
+ // returns the "virtual position" of the orthographic based on where it is and
634
+ // where it's looking primarily so we can reasonably position the camera object
635
+ // in space and derive a reasonable "up" value.
636
+ _getVirtualOrthoCameraPosition( target, camera = this.camera ) {
637
+
638
+ const { tilesGroup, ellipsoid } = this;
639
+ if ( ! camera.isOrthographicCamera ) {
640
+
641
+ throw new Error();
642
+
643
+ }
644
+
645
+ _invMatrix.copy( tilesGroup.matrixWorld ).invert();
646
+
647
+ // get ray in globe coordinate frame
648
+ _ray.origin.copy( camera.position );
649
+ _ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
650
+ _ray.applyMatrix4( _invMatrix );
651
+
652
+ // get the closest point to the ray on the globe in the global coordinate frame
653
+ closestRayEllipsoidSurfacePointEstimate( _ray, ellipsoid, _pos );
654
+ _pos.applyMatrix4( tilesGroup.matrixWorld );
655
+
656
+ // get ortho camera info
657
+ const orthoHeight = ( camera.top - camera.bottom );
658
+ const orthoWidth = ( camera.right - camera.left );
659
+ const orthoSize = Math.max( orthoHeight, orthoWidth ) / camera.zoom;
660
+ _forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
661
+
662
+ // ensure we move the camera exactly along the forward vector to avoid shifting
663
+ // the camera in other directions due to floating point error
664
+ const dist = _pos.sub( camera.position ).dot( _forward );
665
+ target.copy( camera.position ).addScaledVector( _forward, dist - orthoSize * 4 );
666
+
667
+ }
668
+
669
+ _isNearControls() {
670
+
671
+ const { camera } = this;
672
+ if ( camera.isPerspectiveCamera ) {
673
+
674
+ return this.getDistanceToCenter() < this._getPerspectiveTransitionDistance();
675
+
676
+ } else {
677
+
678
+ return camera.zoom > this._getOrthographicTransitionZoom();
679
+
680
+ }
681
+
682
+ }
683
+
684
+ }