@spacexr/geodesy 0.1.0
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.
- package/CHANGELOG.md +18 -0
- package/LICENSE +201 -0
- package/README.md +199 -0
- package/dist/chunk-RJFTT4KI.js +227 -0
- package/dist/chunk-RJFTT4KI.js.map +1 -0
- package/dist/chunk-WYCQOUE7.js +488 -0
- package/dist/chunk-WYCQOUE7.js.map +1 -0
- package/dist/ellipsoid.d.ts +150 -0
- package/dist/ellipsoid.js +3 -0
- package/dist/ellipsoid.js.map +1 -0
- package/dist/geodetic-system-DRpWY8qG.d.ts +257 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/system.d.ts +2 -0
- package/dist/system.js +4 -0
- package/dist/system.js.map +1 -0
- package/package.json +89 -0
- package/src/angles.ts +48 -0
- package/src/ellipsoid.ts +261 -0
- package/src/geodetic-system.ts +548 -0
- package/src/index.ts +4 -0
- package/src/types.ts +46 -0
package/src/ellipsoid.ts
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Immutable oblate ellipsoid of revolution.
|
|
3
|
+
*
|
|
4
|
+
* Axis lengths are expressed in metres. The semi-major axis lies in the
|
|
5
|
+
* equatorial plane and the semi-minor axis follows the polar axis. Instances
|
|
6
|
+
* validate their dimensions and precompute the coefficients required by
|
|
7
|
+
* geodetic conversions.
|
|
8
|
+
*/
|
|
9
|
+
export class Ellipsoid {
|
|
10
|
+
/** WGS 84 reference ellipsoid used by EPSG:4978 and EPSG:4979. */
|
|
11
|
+
public static readonly WGS84 = Ellipsoid.fromSemiMajorAxisAndInverseFlattening("WGS84", 6378137, 298.257223563);
|
|
12
|
+
|
|
13
|
+
/** Geodetic Reference System 1980 ellipsoid. */
|
|
14
|
+
public static readonly GRS80 = Ellipsoid.fromSemiMajorAxisAndInverseFlattening("GRS80", 6378137, 298.257222101);
|
|
15
|
+
|
|
16
|
+
/** Geodetic Reference System 1967 ellipsoid. */
|
|
17
|
+
public static readonly GRS67 = Ellipsoid.fromSemiMajorAxisAndInverseFlattening("GRS67", 6378160, 298.25);
|
|
18
|
+
|
|
19
|
+
/** Australian National Spheroid. */
|
|
20
|
+
public static readonly ANS = Ellipsoid.fromSemiMajorAxisAndInverseFlattening("ANS", 6378160, 298.25);
|
|
21
|
+
|
|
22
|
+
/** World Geodetic System 1972 ellipsoid. */
|
|
23
|
+
public static readonly WGS72 = Ellipsoid.fromSemiMajorAxisAndInverseFlattening("WGS72", 6378135, 298.26);
|
|
24
|
+
|
|
25
|
+
/** Clarke 1858 ellipsoid. */
|
|
26
|
+
public static readonly Clarke1858 = Ellipsoid.fromSemiMajorAxisAndInverseFlattening("Clarke1858", 6378293.645, 294.26);
|
|
27
|
+
|
|
28
|
+
/** Clarke 1880 ellipsoid. */
|
|
29
|
+
public static readonly Clarke1880 = Ellipsoid.fromSemiMajorAxisAndInverseFlattening("Clarke1880", 6378249.145, 293.465);
|
|
30
|
+
|
|
31
|
+
private constructor(
|
|
32
|
+
private readonly identifier: string,
|
|
33
|
+
private readonly major: number,
|
|
34
|
+
private readonly minor: number,
|
|
35
|
+
) {
|
|
36
|
+
if (identifier.trim().length === 0) throw new RangeError("Ellipsoid name must not be empty.");
|
|
37
|
+
if (!Number.isFinite(major) || major <= 0) throw new RangeError("Semi-major axis must be a positive finite number.");
|
|
38
|
+
if (!Number.isFinite(minor) || minor <= 0) throw new RangeError("Semi-minor axis must be a positive finite number.");
|
|
39
|
+
if (minor > major)
|
|
40
|
+
throw new RangeError("An oblate ellipsoid requires the semi-minor axis to be no greater than the semi-major axis.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Creates an ellipsoid from its semi-major axis and inverse flattening.
|
|
45
|
+
*
|
|
46
|
+
* `Infinity` represents a sphere.
|
|
47
|
+
*
|
|
48
|
+
* @param name - Stable human-readable ellipsoid name.
|
|
49
|
+
* @param semiMajorAxis - Equatorial semi-major axis in metres.
|
|
50
|
+
* @param inverseFlattening - Reciprocal flattening, or `Infinity` for a sphere.
|
|
51
|
+
* @returns A validated immutable ellipsoid.
|
|
52
|
+
*/
|
|
53
|
+
public static fromSemiMajorAxisAndInverseFlattening(name: string, semiMajorAxis: number, inverseFlattening: number): Ellipsoid {
|
|
54
|
+
if (inverseFlattening !== Number.POSITIVE_INFINITY && (!Number.isFinite(inverseFlattening) || inverseFlattening <= 1)) {
|
|
55
|
+
throw new RangeError("Inverse flattening must be greater than one, or Infinity for a sphere.");
|
|
56
|
+
}
|
|
57
|
+
const flattening = inverseFlattening === Number.POSITIVE_INFINITY ? 0 : 1 / inverseFlattening;
|
|
58
|
+
return new Ellipsoid(name, semiMajorAxis, semiMajorAxis * (1 - flattening));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Creates an ellipsoid from its semi-major axis and flattening.
|
|
63
|
+
*
|
|
64
|
+
* @param name - Stable human-readable ellipsoid name.
|
|
65
|
+
* @param semiMajorAxis - Equatorial semi-major axis in metres.
|
|
66
|
+
* @param flattening - Flattening in the interval `[0, 1)`.
|
|
67
|
+
* @returns A validated immutable ellipsoid.
|
|
68
|
+
*/
|
|
69
|
+
public static fromSemiMajorAxisAndFlattening(name: string, semiMajorAxis: number, flattening: number): Ellipsoid {
|
|
70
|
+
if (!Number.isFinite(flattening) || flattening < 0 || flattening >= 1) {
|
|
71
|
+
throw new RangeError("Flattening must be a finite number in the interval [0, 1).");
|
|
72
|
+
}
|
|
73
|
+
return new Ellipsoid(name, semiMajorAxis, semiMajorAxis * (1 - flattening));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Creates an ellipsoid from its semi-major and semi-minor axes.
|
|
78
|
+
*
|
|
79
|
+
* @param name - Stable human-readable ellipsoid name.
|
|
80
|
+
* @param semiMajorAxis - Equatorial semi-major axis in metres.
|
|
81
|
+
* @param semiMinorAxis - Polar semi-minor axis in metres.
|
|
82
|
+
* @returns A validated immutable ellipsoid.
|
|
83
|
+
*/
|
|
84
|
+
public static fromAxes(name: string, semiMajorAxis: number, semiMinorAxis: number): Ellipsoid {
|
|
85
|
+
return new Ellipsoid(name, semiMajorAxis, semiMinorAxis);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates a spherical reference surface.
|
|
90
|
+
*
|
|
91
|
+
* @param name - Stable human-readable sphere name.
|
|
92
|
+
* @param radius - Radius in metres.
|
|
93
|
+
* @returns An ellipsoid with zero flattening.
|
|
94
|
+
*/
|
|
95
|
+
public static sphere(name: string, radius: number): Ellipsoid {
|
|
96
|
+
return new Ellipsoid(name, radius, radius);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Stable human-readable identifier. */
|
|
100
|
+
public get name(): string {
|
|
101
|
+
return this.identifier;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Equatorial semi-major axis in metres. */
|
|
105
|
+
public get semiMajorAxis(): number {
|
|
106
|
+
return this.major;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Polar semi-minor axis in metres. */
|
|
110
|
+
public get semiMinorAxis(): number {
|
|
111
|
+
return this.minor;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Largest ellipsoid radius in metres. */
|
|
115
|
+
public get maximumRadius(): number {
|
|
116
|
+
return this.major;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Smallest ellipsoid radius in metres. */
|
|
120
|
+
public get minimumRadius(): number {
|
|
121
|
+
return this.minor;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Ellipsoid flattening `(a - b) / a`. */
|
|
125
|
+
public get flattening(): number {
|
|
126
|
+
return (this.major - this.minor) / this.major;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Reciprocal flattening, or `Infinity` for a sphere. */
|
|
130
|
+
public get inverseFlattening(): number {
|
|
131
|
+
const flattening = this.flattening;
|
|
132
|
+
return flattening === 0 ? Number.POSITIVE_INFINITY : 1 / flattening;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** First eccentricity squared `e^2`. */
|
|
136
|
+
public get squaredEccentricity(): number {
|
|
137
|
+
return 1 - (this.minor * this.minor) / (this.major * this.major);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Compatibility alias for {@link squaredEccentricity}. */
|
|
141
|
+
public get sqrEccentricity(): number {
|
|
142
|
+
return this.squaredEccentricity;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** First eccentricity `e`. */
|
|
146
|
+
public get eccentricity(): number {
|
|
147
|
+
return Math.sqrt(this.squaredEccentricity);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Second eccentricity squared `e'^2`. */
|
|
151
|
+
public get secondSquaredEccentricity(): number {
|
|
152
|
+
return (this.major * this.major - this.minor * this.minor) / (this.minor * this.minor);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Linear eccentricity in metres. */
|
|
156
|
+
public get linearEccentricity(): number {
|
|
157
|
+
return Math.sqrt(this.major * this.major - this.minor * this.minor);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Precomputed coefficient `1 - e^2`. */
|
|
161
|
+
public get oneMinusSquaredEccentricity(): number {
|
|
162
|
+
return 1 - this.squaredEccentricity;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Compatibility alias for {@link oneMinusSquaredEccentricity}. */
|
|
166
|
+
public get oneMinusSqrEccentricity(): number {
|
|
167
|
+
return this.oneMinusSquaredEccentricity;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Semi-latus rectum in metres. */
|
|
171
|
+
public get semiLatusRectum(): number {
|
|
172
|
+
return this.major * this.oneMinusSquaredEccentricity;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Returns the prime-vertical radius of curvature at a geodetic latitude.
|
|
177
|
+
*
|
|
178
|
+
* @param latitudeRadians - Geodetic latitude in radians.
|
|
179
|
+
* @returns Prime-vertical radius in metres.
|
|
180
|
+
*/
|
|
181
|
+
public primeVerticalRadius(latitudeRadians: number): number {
|
|
182
|
+
const sine = Math.sin(latitudeRadians);
|
|
183
|
+
return this.major / Math.sqrt(1 - this.squaredEccentricity * sine * sine);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Returns the meridional radius of curvature at a geodetic latitude.
|
|
188
|
+
*
|
|
189
|
+
* @param latitudeRadians - Geodetic latitude in radians.
|
|
190
|
+
* @returns Meridional radius in metres.
|
|
191
|
+
*/
|
|
192
|
+
public meridionalRadius(latitudeRadians: number): number {
|
|
193
|
+
const sine = Math.sin(latitudeRadians);
|
|
194
|
+
const denominator = 1 - this.squaredEccentricity * sine * sine;
|
|
195
|
+
return (this.major * this.oneMinusSquaredEccentricity) / Math.pow(denominator, 1.5);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Returns the geocentric surface radius at a latitude.
|
|
200
|
+
*
|
|
201
|
+
* @param latitudeRadians - Geocentric latitude in radians.
|
|
202
|
+
* @returns Distance from the ellipsoid centre to its surface in metres.
|
|
203
|
+
*/
|
|
204
|
+
public radiusAtLatitude(latitudeRadians: number): number {
|
|
205
|
+
const cosine = Math.cos(latitudeRadians);
|
|
206
|
+
const sine = Math.sin(latitudeRadians);
|
|
207
|
+
const majorSquared = this.major * this.major;
|
|
208
|
+
const minorSquared = this.minor * this.minor;
|
|
209
|
+
return Math.sqrt(
|
|
210
|
+
((majorSquared * cosine) ** 2 + (minorSquared * sine) ** 2) / ((this.major * cosine) ** 2 + (this.minor * sine) ** 2),
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Intersects a normalized geocentric direction with the ellipsoid surface.
|
|
216
|
+
*
|
|
217
|
+
* @param x - ECEF X component of a normalized direction.
|
|
218
|
+
* @param y - ECEF Y component of a normalized direction.
|
|
219
|
+
* @param z - ECEF Z component of a normalized direction.
|
|
220
|
+
* @returns Distance from the centre to the surface in metres.
|
|
221
|
+
*/
|
|
222
|
+
public radiusAtPosition(x: number, y: number, z: number): number {
|
|
223
|
+
const norm = Math.hypot(x, y, z);
|
|
224
|
+
if (Math.abs(norm - 1) > 1e-12) throw new RangeError("Direction passed to radiusAtPosition must be normalized.");
|
|
225
|
+
const denominator = (x * x + y * y) / (this.major * this.major) + (z * z) / (this.minor * this.minor);
|
|
226
|
+
return 1 / Math.sqrt(denominator);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Tests geometric equality independently from the ellipsoid name.
|
|
231
|
+
*
|
|
232
|
+
* @param other - Ellipsoid to compare.
|
|
233
|
+
* @returns `true` when both axes are exactly equal.
|
|
234
|
+
*/
|
|
235
|
+
public equals(other: Ellipsoid): boolean {
|
|
236
|
+
return other.major === this.major && other.minor === this.minor;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Creates a uniformly scaled ellipsoid.
|
|
241
|
+
*
|
|
242
|
+
* @param scale - Positive uniform scale applied to both axes.
|
|
243
|
+
* @param name - Name assigned to the scaled instance.
|
|
244
|
+
* @returns A new ellipsoid with unchanged flattening.
|
|
245
|
+
*/
|
|
246
|
+
public scaled(scale: number, name = `${this.name} x ${scale}`): Ellipsoid {
|
|
247
|
+
if (!Number.isFinite(scale) || scale <= 0) throw new RangeError("Ellipsoid scale must be a positive finite number.");
|
|
248
|
+
return new Ellipsoid(name, this.major * scale, this.minor * scale);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Compatibility alias for {@link scaled}.
|
|
253
|
+
*
|
|
254
|
+
* @param name - Name assigned to the cloned instance.
|
|
255
|
+
* @param scale - Positive uniform scale applied to both axes.
|
|
256
|
+
* @returns A new ellipsoid.
|
|
257
|
+
*/
|
|
258
|
+
public clone(name: string, scale = 1): Ellipsoid {
|
|
259
|
+
return this.scaled(scale, name);
|
|
260
|
+
}
|
|
261
|
+
}
|