@itowns/geographic 2.44.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,459 @@
1
+ import * as THREE from 'three';
2
+ import proj4 from 'proj4';
3
+ import Coordinates from "./Coordinates.js";
4
+ const DEG2RAD = THREE.MathUtils.DEG2RAD;
5
+ const matrix = new THREE.Matrix4();
6
+ const north = new THREE.Vector3();
7
+ const east = new THREE.Vector3();
8
+ const axis = new THREE.Vector3().set(0, 0, 1);
9
+ const coord = new Coordinates('EPSG:4326', 0, 0, 0);
10
+ const euler = new THREE.Euler();
11
+ const quat = new THREE.Quaternion();
12
+ function quaternionIdentity(coordinates) {
13
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
14
+ return coordinates ? target.set(0, 0, 0, 1) : quaternionIdentity;
15
+ }
16
+
17
+ /**
18
+ * The OrientationUtils module provides methods to compute the quaternion that
19
+ * models a rotation defined with various conventions, including between different
20
+ * CRS.
21
+ * The local <a href="https://en.wikipedia.org/wiki/Local_tangent_plane_coordinates#Local_east,_north,_up_(ENU)_coordinates">
22
+ * East/North/Up frame (ENU)</a> is used as a pivot frame when computing the rotation between two distinct CRS.
23
+ * If the origin of the frame is undefined, CRS-related methods precompute and return a function
24
+ * that can be applied efficiently to many points of origin.
25
+ * Otherwise, the target quaternion is returned at the provided origin coordinates.
26
+ *
27
+ * @example
28
+ * // Compute the rotation around the point of origin from a frame aligned with Lambert93 axes (epsg:2154),
29
+ * // to the geocentric frame (epsg:4978)
30
+ * quat_crs2crs = OrientationUtils.quaternionFromCRSToCRS("EPSG:2154", "EPSG:4978")(origin);
31
+ * // Compute the rotation of a sensor platform defined by its attitude
32
+ * quat_attitude = OrientationUtils.quaternionFromAttitude(attitude);
33
+ * // Compute the rotation from the sensor platform frame to the geocentric frame
34
+ * quat = quat_crs2crs.multiply(quat_attitude);
35
+ *
36
+ * @module OrientationUtils
37
+ */
38
+ export default {
39
+ /**
40
+ * @typedef {Object} Attitude
41
+ * Properties are either defined as (omega, phi, kappa) or as (roll, pitch,
42
+ * heading) or all `undefined`.
43
+ *
44
+ * @property {number} omega - angle in degrees
45
+ * @property {number} phi - angle in degrees
46
+ * @property {number} kappa - angle in degrees
47
+ * @property {number} roll - angle in degrees
48
+ * @property {number} pitch - angle in degrees
49
+ * @property {number} heading - angle in degrees
50
+ */
51
+
52
+ /**
53
+ * The transform from the platform frame to the local East, North, Up (ENU)
54
+ * frame is `RotationZ(heading).RotationX(pitch).RotationY(roll)`
55
+ *
56
+ * @param {number} [roll=0] - angle in degrees
57
+ * @param {number} [pitch=0] - angle in degrees
58
+ * @param {number} [heading=0] - angle in degrees
59
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] - output Quaternion
60
+ *
61
+ * @return {THREE.Quaternion} target quaternion
62
+ */
63
+ quaternionFromRollPitchHeading() {
64
+ let roll = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
65
+ let pitch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
66
+ let heading = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
67
+ let target = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : new THREE.Quaternion();
68
+ roll *= DEG2RAD;
69
+ pitch *= DEG2RAD;
70
+ heading *= DEG2RAD;
71
+ // return this.setFromEuler(euler.set(pitch, roll, heading , 'ZXY')).conjugate();
72
+ return target.setFromEuler(euler.set(-pitch, -roll, -heading, 'YXZ')); // optimized version of above
73
+ },
74
+ /**
75
+ * From
76
+ * [DocMicMac](https://github.com/micmacIGN/Documentation/raw/master/DocMicMac.pdf),
77
+ * the transform from the platform frame to the local East, North, Up (ENU)
78
+ * frame is:
79
+ *
80
+ * ```
81
+ * RotationX(omega).RotationY(phi).RotationZ(kappa).RotationX(PI)
82
+ * RotationX(PI) <=> Quaternion(1,0,0,0) : converts between the 2 conventions for the camera local frame:
83
+ * X right, Y bottom, Z front : convention in photogrammetry and computer vision
84
+ * X right, Y top, Z back : convention in webGL, threejs
85
+ * ```
86
+ *
87
+ * @param {number} [omega=0] - angle in degrees
88
+ * @param {number} [phi=0] - angle in degrees
89
+ * @param {number} [kappa=0] - angle in degrees
90
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
91
+ *
92
+ * @return {THREE.Quaternion} target quaternion
93
+ */
94
+ quaternionFromOmegaPhiKappa() {
95
+ let omega = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
96
+ let phi = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
97
+ let kappa = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
98
+ let target = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : new THREE.Quaternion();
99
+ omega *= DEG2RAD;
100
+ phi *= DEG2RAD;
101
+ kappa *= DEG2RAD;
102
+ target.setFromEuler(euler.set(omega, phi, kappa, 'XYZ'));
103
+ target.set(target.w, target.z, -target.y, -target.x); // <=> target.multiply(new THREE.Quaternion(1, 0, 0, 0));
104
+ return target;
105
+ },
106
+ /**
107
+ * Set the quaternion according to the rotation from the platform frame to
108
+ * the local frame.
109
+ *
110
+ * @param {Attitude} attitude - Attitude
111
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
112
+ *
113
+ * @return {THREE.Quaternion} target quaternion
114
+ */
115
+ quaternionFromAttitude(attitude) {
116
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
117
+ if (attitude.roll !== undefined || attitude.pitch !== undefined || attitude.heading !== undefined) {
118
+ return this.quaternionFromRollPitchHeading(attitude.roll, attitude.pitch, attitude.heading, target);
119
+ }
120
+ if (attitude.omega !== undefined || attitude.phi !== undefined || attitude.kappa !== undefined) {
121
+ return this.quaternionFromOmegaPhiKappa(attitude.omega, attitude.phi, attitude.kappa, target);
122
+ }
123
+ return target.set(0, 0, 0, 1);
124
+ },
125
+ /**
126
+ * @typedef {Function|THREE.Quaternion} FunctionOrQuaternion - Either a
127
+ * THREE.Quaternion or a function that accepts arguments `(coordinates,
128
+ * target)` and returns the quaternion that models a rotation around the
129
+ * point of origin. If target is not provided, a new quaternion is created
130
+ * and returned instead.
131
+ *
132
+ * @property {Coordinates} coordinates the origin of the local East North Up
133
+ * (ENU) frame
134
+ * @property {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion.
135
+ */
136
+
137
+ /**
138
+ * A Projection object models a Coordinate Reference System (CRS).
139
+ * Such an object is usually created with proj4 using `proj4.defs(crs);`
140
+ *
141
+ * @typedef {Object} Projection
142
+ *
143
+ * @property {string} projName
144
+ */
145
+
146
+ /**
147
+ * Set the quaternion according to the rotation from the local East North Up (ENU)
148
+ * frame to the geocentric frame. The up direction of the ENU frame is
149
+ * provided by the normalized geodetic normal of the provided coordinates
150
+ * (geodeticNormal property).
151
+ *
152
+ * @param {Coordinates} [coordinates] the origin of the local East North Up
153
+ * (ENU) frame
154
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
155
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
156
+ */
157
+ quaternionFromEnuToGeocent(coordinates) {
158
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
159
+ if (coordinates) {
160
+ return this.quaternionFromEnuToGeocent()(coordinates, target);
161
+ }
162
+ return function (coordinates) {
163
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
164
+ const up = coordinates.geodesicNormal;
165
+ if (up.x == 0 && up.y == 0) {
166
+ return target.set(0, 0, 0, 1);
167
+ }
168
+ // this is an optimized version of matrix.lookAt(up, new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, 1));
169
+ east.set(-up.y, up.x, 0).normalize();
170
+ north.crossVectors(up, east);
171
+ matrix.makeBasis(east, north, up);
172
+ return target.setFromRotationMatrix(matrix);
173
+ };
174
+ },
175
+ /**
176
+ * Set the quaternion according to the rotation from a geocentric frame
177
+ * to the local East North Up (ENU) frame. The up direction of the ENU frame is
178
+ * provided by the normalized geodetic normal of the provided coordinates
179
+ * (geodeticNormal property).
180
+ *
181
+ * @param {Coordinates} [coordinates] the origin of the local East North Up
182
+ * (ENU) frame
183
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
184
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
185
+ */
186
+ quaternionFromGeocentToEnu(coordinates) {
187
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
188
+ if (coordinates) {
189
+ return this.quaternionFromGeocentToEnu()(coordinates, target);
190
+ }
191
+ const toGeocent = this.quaternionFromEnuToGeocent();
192
+ return function (coordinates) {
193
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
194
+ return toGeocent(coordinates, target).conjugate();
195
+ };
196
+ },
197
+ /**
198
+ * Computes the rotation from a Lambert Conformal Conic (LCC) frame to the local East North Up (ENU) frame.
199
+ * The quaternion accounts for the
200
+ * <a href="https://geodesie.ign.fr/contenu/fichiers/documentation/algorithmes/alg0060.pdf">meridian convergence</a>
201
+ * between the ENU and LCC frames.
202
+ * This is a generally small rotation around Z.
203
+ *
204
+ * @param {Object} proj the lcc projection (may be parsed using proj4)
205
+ * @param {number} proj.lat0 - the latitude of origin
206
+ * @param {number} proj.long0 - the longitude of the central meridian
207
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
208
+ * (ENU) frame
209
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
210
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
211
+ */
212
+ quaternionFromLCCToEnu(proj, coordinates) {
213
+ let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new THREE.Quaternion();
214
+ if (coordinates) {
215
+ return this.quaternionFromLCCToEnu(proj)(coordinates, target);
216
+ }
217
+ const sinlat0 = Math.sin(proj.lat0);
218
+ return function (coordinates) {
219
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
220
+ const long = coordinates.as(coord.crs, coord).longitude * DEG2RAD;
221
+ return target.setFromAxisAngle(axis, sinlat0 * (proj.long0 - long));
222
+ };
223
+ },
224
+ /**
225
+ * Computes the rotation from the local East North Up (ENU) frame to a Lambert Conformal Conic (LCC) frame.
226
+ * The quaternion accounts for the
227
+ * <a href="https://geodesie.ign.fr/contenu/fichiers/documentation/algorithmes/alg0060.pdf">meridian convergence</a>
228
+ * between the ENU and LCC frames.
229
+ * This is a generally small rotation around Z.
230
+ *
231
+ * @param {Object} proj the lcc projection (may be parsed using proj4)
232
+ * @param {number} proj.lat0 - the latitude of origin
233
+ * @param {number} proj.long0 - the longitude of the central meridian
234
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
235
+ * (ENU) frame
236
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
237
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
238
+ */
239
+ quaternionFromEnuToLCC(proj, coordinates) {
240
+ let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new THREE.Quaternion();
241
+ if (coordinates) {
242
+ return this.quaternionFromEnuToLCC(proj)(coordinates, target);
243
+ }
244
+ const fromLCC = this.quaternionFromLCCToEnu(proj);
245
+ return function (coordinates) {
246
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
247
+ return fromLCC(coordinates, target).conjugate();
248
+ };
249
+ },
250
+ /**
251
+ * Computes the rotation from a Transverse Mercator frame (TMerc) to the local East North Up (ENU) frame.
252
+ * The quaternion accounts for the
253
+ * <a href="https://geodesie.ign.fr/contenu/fichiers/documentation/algorithmes/alg0061.pdf">meridian convergence</a>
254
+ * between the ENU and TMerc frames.
255
+ * This is a generally small rotation around Z.
256
+ *
257
+ * @param {Object} proj the tmerc projection (may be parsed using proj4)
258
+ * @param {number} proj.e - the excentricity of the ellipsoid (supersedes {proj.a} and {proj.b})
259
+ * @param {number} proj.a - the semimajor radius of the ellipsoid axis
260
+ * @param {number} proj.b - the semiminor radius of the ellipsoid axis
261
+ * @param {number} proj.long0 - the longitude of the central meridian
262
+ *
263
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
264
+ * (ENU) frame
265
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
266
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
267
+ */
268
+ quaternionFromTMercToEnu(proj, coordinates) {
269
+ let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new THREE.Quaternion();
270
+ if (coordinates) {
271
+ return this.quaternionFromTMercToEnu(proj)(coordinates, target);
272
+ }
273
+ const a2 = proj.a * proj.a;
274
+ const b2 = proj.b * proj.b;
275
+ const e2 = proj.e * proj.e;
276
+ const eta0 = proj.e ? e2 / (1 - e2) : a2 / b2 - 1;
277
+ return function (coordinates) {
278
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
279
+ coordinates.as(coord.crs, coord);
280
+ const long = coord.longitude * DEG2RAD;
281
+ const lat = coord.latitude * DEG2RAD;
282
+ const dlong = proj.long0 - long;
283
+ const coslat = Math.cos(lat);
284
+ const sinlat = Math.sin(lat);
285
+ const tanlat = sinlat / coslat;
286
+ const coslat2 = coslat * coslat;
287
+ const dl2 = dlong * dlong * coslat2;
288
+ const eta2 = eta0 * coslat2;
289
+ const gamma = dlong * sinlat * (1 + dl2 / 3 * (1 + 3 * eta2 + 2 * eta2 * eta2) + dl2 * dl2 * (2 - tanlat) / 15);
290
+ return target.setFromAxisAngle(axis, gamma);
291
+ };
292
+ },
293
+ /**
294
+ * Computes the rotation from the local East North Up (ENU) to a Transverse Mercator frame.
295
+ * The quaternion accounts for the
296
+ * <a href="https://geodesie.ign.fr/contenu/fichiers/documentation/algorithmes/alg0061.pdf">meridian convergence</a>
297
+ * between the ENU and TMerc frames.
298
+ * This is a generally small rotation around Z.
299
+ *
300
+ * @param {Object} proj the tmerc projection (may be parsed using proj4)
301
+ * @param {number} proj.e - the excentricity of the ellipsoid (supersedes
302
+ * {proj.a} and {proj.b})
303
+ * @param {number} proj.a - the semimajor radius of the ellipsoid axis
304
+ * @param {number} proj.b - the semiminor radius of the ellipsoid axis
305
+ * @param {number} proj.long0 - the longitude of the central meridian
306
+ *
307
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
308
+ * (ENU) frame
309
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
310
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
311
+ */
312
+ quaternionFromEnuToTMerc(proj, coordinates) {
313
+ let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new THREE.Quaternion();
314
+ if (coordinates) {
315
+ return this.quaternionFromEnuToTMerc(proj)(coordinates, target);
316
+ }
317
+ const fromTMerc = this.quaternionFromTMercToEnu(proj);
318
+ return function (coordinates) {
319
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
320
+ return fromTMerc(coordinates, target).conjugate();
321
+ };
322
+ },
323
+ /**
324
+ * Computes the rotation from a LongLat frame to the local East North Up (ENU) frame.
325
+ * The identity quaternion (0,0,0,1) is returned, as longlat and ENU frame are assumed to be aligned.
326
+ *
327
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
328
+ * (ENU) frame
329
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
330
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
331
+ */
332
+ quaternionFromLongLatToEnu(coordinates) {
333
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
334
+ return quaternionIdentity(coordinates, target);
335
+ },
336
+ /**
337
+ * Computes the rotation from the local East North Up (ENU) frame to a LongLat frame.
338
+ * The identity quaternion (0,0,0,1) is returned, as longlat and ENU frame are assumed to be aligned.
339
+ *
340
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
341
+ * (ENU) frame
342
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
343
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
344
+ */
345
+ quaternionFromEnuToLongLat(coordinates) {
346
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
347
+ return quaternionIdentity(coordinates, target);
348
+ },
349
+ /**
350
+ * Warns for an unimplemented projection, sets the quaternion to the
351
+ * identity (0,0,0,1).
352
+ *
353
+ * @param {Projection} proj - the unimplemented projection (may be parsed
354
+ * using proj4)
355
+ *
356
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
357
+ * (ENU) frame
358
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
359
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
360
+ */
361
+ quaternionUnimplemented(proj, coordinates) {
362
+ let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new THREE.Quaternion();
363
+ console.warn('This quaternion function is not implemented for projections of type', proj.projName);
364
+ return quaternionIdentity(coordinates, target);
365
+ },
366
+ /**
367
+ * Compute the quaternion that models the rotation from the local East North
368
+ * Up (ENU) frame to the frame of the given crs.
369
+ *
370
+ * @param {string|Projection} crsOrProj - the CRS of the target frame or its
371
+ * proj4-compatible object.
372
+ *
373
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
374
+ * (ENU) frame
375
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
376
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
377
+ */
378
+ quaternionFromEnuToCRS(crsOrProj, coordinates) {
379
+ let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new THREE.Quaternion();
380
+ if (coordinates) {
381
+ return this.quaternionFromEnuToCRS(crsOrProj)(coordinates, target);
382
+ }
383
+ const proj = crsOrProj.projName ? crsOrProj : proj4.defs(crsOrProj);
384
+ switch (proj.projName) {
385
+ case 'geocent':
386
+ return this.quaternionFromEnuToGeocent();
387
+ case 'lcc':
388
+ return this.quaternionFromEnuToLCC(proj);
389
+ case 'tmerc':
390
+ return this.quaternionFromEnuToTMerc(proj);
391
+ case 'longlat':
392
+ return this.quaternionFromEnuToLongLat();
393
+ default:
394
+ return this.quaternionUnimplemented(proj);
395
+ }
396
+ },
397
+ /**
398
+ * Compute the quaternion that models the rotation from the frame of the
399
+ * given crs to the local East North Up (ENU) frame.
400
+ *
401
+ * @param {string|Projection} crsOrProj - the CRS of the source frame or its
402
+ * proj4-compatible object.
403
+ *
404
+ * @param {Coordinates} [coordinates] coordinates the origin of the local East North Up
405
+ * (ENU) frame
406
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
407
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
408
+ */
409
+ quaternionFromCRSToEnu(crsOrProj, coordinates) {
410
+ let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new THREE.Quaternion();
411
+ if (coordinates) {
412
+ return this.quaternionFromCRSToEnu(crsOrProj)(coordinates, target);
413
+ }
414
+ const proj = crsOrProj.projName ? crsOrProj : proj4.defs(crsOrProj);
415
+ switch (proj.projName) {
416
+ case 'geocent':
417
+ return this.quaternionFromGeocentToEnu();
418
+ case 'lcc':
419
+ return this.quaternionFromLCCToEnu(proj);
420
+ case 'tmerc':
421
+ return this.quaternionFromTMercToEnu(proj);
422
+ case 'longlat':
423
+ return this.quaternionFromLongLatToEnu();
424
+ default:
425
+ return this.quaternionUnimplemented(proj);
426
+ }
427
+ },
428
+ /**
429
+ * Return the function that computes the quaternion that represents a
430
+ * rotation of coordinates between two CRS frames.
431
+ *
432
+ * @param {string} crsIn - the CRS of the input frame.
433
+ * @param {string} crsOut - the CRS of the output frame.
434
+ * @param {Coordinates} [coordinates] coordinates - the origin of the local East North Up
435
+ * (ENU) frame
436
+ * @param {THREE.Quaternion} [target=new THREE.Quaternion()] output Quaternion
437
+ * @return {FunctionOrQuaternion} The target quaternion if coordinates is defined, otherwise, a function to compute it from coordinates.
438
+ */
439
+ quaternionFromCRSToCRS(crsIn, crsOut, coordinates) {
440
+ let target = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : new THREE.Quaternion();
441
+ if (coordinates) {
442
+ return this.quaternionFromCRSToCRS(crsIn, crsOut)(coordinates, target);
443
+ }
444
+ if (crsIn == crsOut) {
445
+ return function (origin) {
446
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
447
+ return target.set(0, 0, 0, 1);
448
+ };
449
+ }
450
+
451
+ // get rotations from the local East/North/Up (ENU) frame to both CRS.
452
+ const fromCrs = this.quaternionFromCRSToEnu(crsIn);
453
+ const toCrs = this.quaternionFromEnuToCRS(crsOut);
454
+ return function (origin) {
455
+ let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Quaternion();
456
+ return toCrs(origin, target).multiply(fromCrs(origin, quat));
457
+ };
458
+ }
459
+ };
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@itowns/geographic",
3
+ "version": "2.44.2",
4
+ "description": "Geodesy",
5
+ "type": "module",
6
+ "main": "lib/Main.js",
7
+ "exports": {
8
+ ".": "./lib/Main.js"
9
+ },
10
+ "scripts": {
11
+ "build": "",
12
+ "lint": "eslint \"src/**/*.{js,ts,tsx}\" \"test/**/*.js\"",
13
+ "transpile": "cross-env BABEL_DISABLE_CACHE=1 babel src --out-dir lib --extensions .js,.ts",
14
+ "test-unit": "npm run base-test-unit test/unit",
15
+ "base-test-unit": "cross-env BABEL_DISABLE_CACHE=1 mocha --import=../../config/babel-register/register.mjs",
16
+ "test-with-coverage": "c8 -n src -r html cross-env npm run test-unit",
17
+ "test-with-coverage_lcov": "c8 -n src --reporter=lcov cross-env npm run test-unit",
18
+ "watch": "npm run transpile -- --watch",
19
+ "publish-latest": "npm publish --access public --tag=latest --provenance",
20
+ "prerelease-next": "npm version prerelease --preid next",
21
+ "publish-next": "npm publish --access public --tag=next --provenance"
22
+ },
23
+ "files": [
24
+ "*.md",
25
+ "src",
26
+ "lib"
27
+ ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/iTowns/itowns.git"
31
+ },
32
+ "license": "(CECILL-B OR MIT)",
33
+ "bugs": {
34
+ "url": "https://github.com/itowns/itowns/issues"
35
+ },
36
+ "peerDependencies": {
37
+ "proj4": "^2.12.1",
38
+ "three": "^0.170.0"
39
+ },
40
+ "homepage": "https://itowns.github.io/"
41
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Generated On: 2016-02-25
3
+ * Class: CoordStars
4
+ * Description: get coord of stars like earth...
5
+ */
6
+ import Coordinates from 'Coordinates';
7
+
8
+ const CoordStars = {
9
+
10
+ getSunPosition() {
11
+ const m = Math;
12
+ const PI = m.PI;
13
+ const sin = m.sin;
14
+ const cos = m.cos;
15
+ const tan = m.tan;
16
+ const asin = m.asin;
17
+ const atan = m.atan2;
18
+
19
+ const rad = PI / 180;
20
+ const dayMs = 1000 * 60 * 60 * 24;
21
+ const J1970 = 2440588;
22
+ const J2000 = 2451545;
23
+ const e = rad * 23.4397; // obliquity of the Earth
24
+
25
+ function toJulian(date) {
26
+ return date.valueOf() / dayMs - 0.5 + J1970;
27
+ }
28
+
29
+ function toDays(date) {
30
+ return toJulian(date) - J2000;
31
+ }
32
+
33
+ function getRightAscension(l, b) {
34
+ return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l));
35
+ }
36
+
37
+ function getDeclination(l, b) {
38
+ return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l));
39
+ }
40
+
41
+ function getAzimuth(H, phi, dec) {
42
+ return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi));
43
+ }
44
+
45
+ function getAltitude(H, phi, dec) {
46
+ return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H));
47
+ }
48
+
49
+ function getSiderealTime(d, lw) {
50
+ return rad * (280.16 + 360.9856235 * d) - lw;
51
+ }
52
+
53
+ function getSolarMeanAnomaly(d) {
54
+ return rad * (357.5291 + 0.98560028 * d);
55
+ }
56
+
57
+ function getEquationOfCenter(M) {
58
+ return rad * (1.9148 * sin(M) + 0.0200 * sin(2 * M) + 0.0003 * sin(3 * M));
59
+ }
60
+
61
+ function getEclipticLongitude(M, C) {
62
+ const P = rad * 102.9372; // perihelion of the Earth
63
+ return M + C + P + PI;
64
+ }
65
+
66
+ return function getSunPosition(date, lat, lon) {
67
+ const lw = rad * -lon;
68
+ const phi = rad * lat;
69
+ const d = toDays(date);
70
+ const M = getSolarMeanAnomaly(d);
71
+ const C = getEquationOfCenter(M);
72
+ const L = getEclipticLongitude(M, C);
73
+ const D = getDeclination(L, 0);
74
+ const A = getRightAscension(L, 0);
75
+ const t = getSiderealTime(d, lw);
76
+ const H = t - A;
77
+
78
+ return {
79
+ EclipticLongitude: L,
80
+ declinaison: D,
81
+ ascension: A,
82
+ H,
83
+ SiderealTime: t,
84
+ altitude: getAltitude(H, phi, D),
85
+ azimuth: getAzimuth(H, phi, D) + PI / 2, // + PI// - PI/2 // origin: north !!! not like original Mourner code but more classical ref
86
+ };
87
+ };
88
+ },
89
+
90
+ // Return scene coordinate ({x,y,z}) of sun
91
+ getSunPositionInScene(date, lat, lon) {
92
+ const sun = CoordStars.getSunPosition()(date, lat, lon);
93
+ const dayMilliSec = 24 * 3600000;
94
+ const longitude = sun.ascension + ((date % dayMilliSec) / dayMilliSec) * -360 + 180; // cause midday
95
+ const coSunCarto = new Coordinates('EPSG:4326', longitude, lat, 50000000)
96
+ .as('EPSG:4978').toVector3();
97
+
98
+ return coSunCarto;
99
+ },
100
+
101
+
102
+ };
103
+
104
+ export default CoordStars;