gnss-js 1.1.0 → 1.2.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.
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/frames/index.ts
21
+ var frames_exports = {};
22
+ __export(frames_exports, {
23
+ REFERENCE_FRAMES: () => REFERENCE_FRAMES,
24
+ applyHelmert: () => applyHelmert,
25
+ dateToEpoch: () => dateToEpoch,
26
+ transformFrame: () => transformFrame
27
+ });
28
+ module.exports = __toCommonJS(frames_exports);
29
+ var H = (t, d, r, tDot, dDot, rDot, epoch) => ({ t, d, r, tDot, dDot, rDot, epoch });
30
+ var Z = [0, 0, 0];
31
+ var FROM_ITRF2020 = {
32
+ ITRF2014: H([-1.4, -0.9, 1.4], -0.42, Z, [0, -0.1, 0.2], 0, Z, 2015),
33
+ ITRF2008: H([0.2, 1, 3.3], -0.29, Z, [0, -0.1, 0.1], 0.03, Z, 2015),
34
+ ITRF2005: H([2.7, 0.1, -1.4], 0.65, Z, [0.3, -0.1, 0.1], 0.03, Z, 2015),
35
+ ITRF2000: H([-0.2, 0.8, -34.2], 2.25, Z, [0.1, 0, -1.7], 0.11, Z, 2015),
36
+ ITRF97: H(
37
+ [6.5, -3.9, -77.9],
38
+ 3.98,
39
+ [0, 0, 0.36],
40
+ [0.1, -0.6, -3.1],
41
+ 0.12,
42
+ [0, 0, 0.02],
43
+ 2015
44
+ ),
45
+ ITRF96: H(
46
+ [6.5, -3.9, -77.9],
47
+ 3.98,
48
+ [0, 0, 0.36],
49
+ [0.1, -0.6, -3.1],
50
+ 0.12,
51
+ [0, 0, 0.02],
52
+ 2015
53
+ ),
54
+ ITRF94: H(
55
+ [6.5, -3.9, -77.9],
56
+ 3.98,
57
+ [0, 0, 0.36],
58
+ [0.1, -0.6, -3.1],
59
+ 0.12,
60
+ [0, 0, 0.02],
61
+ 2015
62
+ ),
63
+ ITRF93: H(
64
+ [-65.8, 1.9, -71.3],
65
+ 4.47,
66
+ [-3.36, -4.33, 0.75],
67
+ [-2.8, -0.2, -2.3],
68
+ 0.12,
69
+ [-0.11, -0.19, 0.07],
70
+ 2015
71
+ ),
72
+ ITRF92: H(
73
+ [14.5, -1.9, -85.9],
74
+ 3.27,
75
+ [0, 0, 0.36],
76
+ [0.1, -0.6, -3.1],
77
+ 0.12,
78
+ [0, 0, 0.02],
79
+ 2015
80
+ ),
81
+ ITRF91: H(
82
+ [26.5, 12.1, -91.9],
83
+ 4.67,
84
+ [0, 0, 0.36],
85
+ [0.1, -0.6, -3.1],
86
+ 0.12,
87
+ [0, 0, 0.02],
88
+ 2015
89
+ ),
90
+ ITRF90: H(
91
+ [24.5, 8.1, -107.9],
92
+ 4.97,
93
+ [0, 0, 0.36],
94
+ [0.1, -0.6, -3.1],
95
+ 0.12,
96
+ [0, 0, 0.02],
97
+ 2015
98
+ ),
99
+ ITRF89: H(
100
+ [29.5, 32.1, -145.9],
101
+ 8.37,
102
+ [0, 0, 0.36],
103
+ [0.1, -0.6, -3.1],
104
+ 0.12,
105
+ [0, 0, 0.02],
106
+ 2015
107
+ ),
108
+ ITRF88: H(
109
+ [24.5, -3.9, -169.9],
110
+ 11.47,
111
+ [0.1, 0, 0.36],
112
+ [0.1, -0.6, -3.1],
113
+ 0.12,
114
+ [0, 0, 0.02],
115
+ 2015
116
+ ),
117
+ /** ITRF2020 → ETRF2020, EPSG:10572 (epoch-1989 variant) */
118
+ ETRF2020: H(Z, 0, Z, Z, 0, [0.086, 0.519, -0.753], 1989)
119
+ };
120
+ var ITRF2014_TO_ETRF2014 = H(Z, 0, Z, Z, 0, [0.085, 0.531, -0.77], 1989);
121
+ var ITRF2014_TO_ETRF2000 = H(
122
+ [54.7, 52.2, -74.1],
123
+ 2.12,
124
+ [1.701, 10.29, -16.632],
125
+ [0.1, 0.1, -1.9],
126
+ 0.11,
127
+ [0.081, 0.49, -0.792],
128
+ 2010
129
+ );
130
+ var ITRF2014_TO_NAD83_2011 = H(
131
+ [1005.3, -1909.21, -541.57],
132
+ 0.36891,
133
+ [-26.78138, 0.42027, -10.93206],
134
+ [0.79, -0.6, -1.44],
135
+ -0.07201,
136
+ [-0.06667, 0.75744, 0.05133],
137
+ 2010
138
+ );
139
+ var MAS_TO_RAD = Math.PI / (180 * 3600 * 1e3);
140
+ function applyHelmert(xyz, p, epoch, inverse = false) {
141
+ const dt = epoch - p.epoch;
142
+ const sign = inverse ? -1 : 1;
143
+ const tx = sign * (p.t[0] + p.tDot[0] * dt) / 1e3;
144
+ const ty = sign * (p.t[1] + p.tDot[1] * dt) / 1e3;
145
+ const tz = sign * (p.t[2] + p.tDot[2] * dt) / 1e3;
146
+ const d = sign * (p.d + p.dDot * dt) * 1e-9;
147
+ const rx = sign * (p.r[0] + p.rDot[0] * dt) * MAS_TO_RAD;
148
+ const ry = sign * (p.r[1] + p.rDot[1] * dt) * MAS_TO_RAD;
149
+ const rz = sign * (p.r[2] + p.rDot[2] * dt) * MAS_TO_RAD;
150
+ const [x, y, z] = xyz;
151
+ return [
152
+ x + tx + d * x - rz * y + ry * z,
153
+ y + ty + rz * x + d * y - rx * z,
154
+ z + tz - ry * x + rx * y + d * z
155
+ ];
156
+ }
157
+ var EDGES = [
158
+ ...Object.entries(FROM_ITRF2020).map(([to, p]) => ({
159
+ from: "ITRF2020",
160
+ to,
161
+ p
162
+ })),
163
+ { from: "ITRF2014", to: "ETRF2014", p: ITRF2014_TO_ETRF2014 },
164
+ { from: "ITRF2014", to: "ETRF2000", p: ITRF2014_TO_ETRF2000 },
165
+ { from: "ITRF2014", to: "NAD83(2011)", p: ITRF2014_TO_NAD83_2011 }
166
+ ];
167
+ var REFERENCE_FRAMES = [
168
+ "WGS84",
169
+ "ITRF2020",
170
+ "ITRF2014",
171
+ "ITRF2008",
172
+ "ITRF2005",
173
+ "ITRF2000",
174
+ "ITRF97",
175
+ "ITRF96",
176
+ "ITRF94",
177
+ "ITRF93",
178
+ "ITRF92",
179
+ "ITRF91",
180
+ "ITRF90",
181
+ "ITRF89",
182
+ "ITRF88",
183
+ "ETRF2020",
184
+ "ETRF2014",
185
+ "ETRF2000",
186
+ "NAD83(2011)"
187
+ ];
188
+ function resolveAlias(f) {
189
+ return f === "WGS84" ? "ITRF2020" : f;
190
+ }
191
+ function findPath(from, to) {
192
+ if (from === to) return [];
193
+ const queue = [from];
194
+ const cameFrom = /* @__PURE__ */ new Map();
195
+ const seen = /* @__PURE__ */ new Set([from]);
196
+ while (queue.length > 0) {
197
+ const cur = queue.shift();
198
+ for (const edge of EDGES) {
199
+ let next = null;
200
+ let inverse = false;
201
+ if (edge.from === cur) {
202
+ next = edge.to;
203
+ } else if (edge.to === cur) {
204
+ next = edge.from;
205
+ inverse = true;
206
+ }
207
+ if (next === null || seen.has(next)) continue;
208
+ seen.add(next);
209
+ cameFrom.set(next, { prev: cur, edge, inverse });
210
+ if (next === to) {
211
+ const path = [];
212
+ let node = to;
213
+ while (node !== from) {
214
+ const step = cameFrom.get(node);
215
+ path.unshift({ edge: step.edge, inverse: step.inverse });
216
+ node = step.prev;
217
+ }
218
+ return path;
219
+ }
220
+ queue.push(next);
221
+ }
222
+ }
223
+ return null;
224
+ }
225
+ function transformFrame(xyz, from, to, epoch) {
226
+ const src = resolveAlias(from);
227
+ const dst = resolveAlias(to);
228
+ const path = findPath(src, dst);
229
+ if (!path) {
230
+ throw new Error(`No transformation path from ${from} to ${to}`);
231
+ }
232
+ let out = [xyz[0], xyz[1], xyz[2]];
233
+ for (const { edge, inverse } of path) {
234
+ out = applyHelmert(out, edge.p, epoch, inverse);
235
+ }
236
+ return out;
237
+ }
238
+ function dateToEpoch(date) {
239
+ const year = date.getUTCFullYear();
240
+ const start = Date.UTC(year, 0, 1);
241
+ const end = Date.UTC(year + 1, 0, 1);
242
+ return year + (date.getTime() - start) / (end - start);
243
+ }
244
+ // Annotate the CommonJS export names for ESM import in node:
245
+ 0 && (module.exports = {
246
+ REFERENCE_FRAMES,
247
+ applyHelmert,
248
+ dateToEpoch,
249
+ transformFrame
250
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Terrestrial reference frame transformations.
3
+ *
4
+ * Time-dependent 14-parameter Helmert transformations between ITRF
5
+ * realizations, the ETRS89 realizations (ETRF2000/2014/2020), and
6
+ * NAD83(2011). All parameters are taken verbatim from authoritative
7
+ * sources — IERS/IGN for ITRF↔ITRF, EPSG registry entries for the
8
+ * rest — never re-derived. Each parameter set cites its source.
9
+ *
10
+ * Conventions: parameters are stored in the IERS "Position Vector"
11
+ * convention (rotations describe the rotation of the position vector,
12
+ * CRS source→target: Xs = X + T + D·X + R·X with
13
+ * R·X = (−R3·y + R2·z, R3·x − R1·z, −R2·x + R1·y) ).
14
+ * EPSG entries published in the opposite "Coordinate Frame rotation"
15
+ * convention (NAD83) have their rotations negated at definition time.
16
+ *
17
+ * WGS84 note: the current WGS84 realization (G2296) is aligned to
18
+ * ITRF2020 at the few-cm level; this module treats 'WGS84' as an alias
19
+ * of ITRF2020, which is the standard GNSS practice.
20
+ */
21
+ type ReferenceFrame = 'ITRF2020' | 'ITRF2014' | 'ITRF2008' | 'ITRF2005' | 'ITRF2000' | 'ITRF97' | 'ITRF96' | 'ITRF94' | 'ITRF93' | 'ITRF92' | 'ITRF91' | 'ITRF90' | 'ITRF89' | 'ITRF88' | 'ETRF2020' | 'ETRF2014' | 'ETRF2000' | 'NAD83(2011)' | 'WGS84';
22
+ /**
23
+ * 14-parameter Helmert set (Position Vector convention).
24
+ * Units: translations mm (rates mm/yr), scale ppb (ppb/yr),
25
+ * rotations mas (mas/yr); epoch in decimal years.
26
+ */
27
+ interface Helmert14 {
28
+ t: [number, number, number];
29
+ d: number;
30
+ r: [number, number, number];
31
+ tDot: [number, number, number];
32
+ dDot: number;
33
+ rDot: [number, number, number];
34
+ epoch: number;
35
+ }
36
+ /**
37
+ * Apply a time-dependent Helmert transformation (Position Vector
38
+ * convention) to geocentric coordinates, evaluated at `epoch`
39
+ * (decimal years). Pass `inverse` to go target → source.
40
+ */
41
+ declare function applyHelmert(xyz: readonly [number, number, number], p: Helmert14, epoch: number, inverse?: boolean): [number, number, number];
42
+ /** Frames supported by transformFrame (WGS84 is an ITRF2020 alias). */
43
+ declare const REFERENCE_FRAMES: ReferenceFrame[];
44
+ /**
45
+ * Transform geocentric coordinates between reference frames at a given
46
+ * coordinate epoch (decimal years, e.g. 2010.5).
47
+ *
48
+ * The epoch is the epoch of the coordinates themselves — the same
49
+ * physical location is expressed in both frames at that instant; no
50
+ * intra-plate velocity propagation is applied.
51
+ */
52
+ declare function transformFrame(xyz: readonly [number, number, number], from: ReferenceFrame, to: ReferenceFrame, epoch: number): [number, number, number];
53
+ /** Convert a Date to the decimal-year epoch used by transformFrame. */
54
+ declare function dateToEpoch(date: Date): number;
55
+
56
+ export { type Helmert14, REFERENCE_FRAMES, type ReferenceFrame, applyHelmert, dateToEpoch, transformFrame };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Terrestrial reference frame transformations.
3
+ *
4
+ * Time-dependent 14-parameter Helmert transformations between ITRF
5
+ * realizations, the ETRS89 realizations (ETRF2000/2014/2020), and
6
+ * NAD83(2011). All parameters are taken verbatim from authoritative
7
+ * sources — IERS/IGN for ITRF↔ITRF, EPSG registry entries for the
8
+ * rest — never re-derived. Each parameter set cites its source.
9
+ *
10
+ * Conventions: parameters are stored in the IERS "Position Vector"
11
+ * convention (rotations describe the rotation of the position vector,
12
+ * CRS source→target: Xs = X + T + D·X + R·X with
13
+ * R·X = (−R3·y + R2·z, R3·x − R1·z, −R2·x + R1·y) ).
14
+ * EPSG entries published in the opposite "Coordinate Frame rotation"
15
+ * convention (NAD83) have their rotations negated at definition time.
16
+ *
17
+ * WGS84 note: the current WGS84 realization (G2296) is aligned to
18
+ * ITRF2020 at the few-cm level; this module treats 'WGS84' as an alias
19
+ * of ITRF2020, which is the standard GNSS practice.
20
+ */
21
+ type ReferenceFrame = 'ITRF2020' | 'ITRF2014' | 'ITRF2008' | 'ITRF2005' | 'ITRF2000' | 'ITRF97' | 'ITRF96' | 'ITRF94' | 'ITRF93' | 'ITRF92' | 'ITRF91' | 'ITRF90' | 'ITRF89' | 'ITRF88' | 'ETRF2020' | 'ETRF2014' | 'ETRF2000' | 'NAD83(2011)' | 'WGS84';
22
+ /**
23
+ * 14-parameter Helmert set (Position Vector convention).
24
+ * Units: translations mm (rates mm/yr), scale ppb (ppb/yr),
25
+ * rotations mas (mas/yr); epoch in decimal years.
26
+ */
27
+ interface Helmert14 {
28
+ t: [number, number, number];
29
+ d: number;
30
+ r: [number, number, number];
31
+ tDot: [number, number, number];
32
+ dDot: number;
33
+ rDot: [number, number, number];
34
+ epoch: number;
35
+ }
36
+ /**
37
+ * Apply a time-dependent Helmert transformation (Position Vector
38
+ * convention) to geocentric coordinates, evaluated at `epoch`
39
+ * (decimal years). Pass `inverse` to go target → source.
40
+ */
41
+ declare function applyHelmert(xyz: readonly [number, number, number], p: Helmert14, epoch: number, inverse?: boolean): [number, number, number];
42
+ /** Frames supported by transformFrame (WGS84 is an ITRF2020 alias). */
43
+ declare const REFERENCE_FRAMES: ReferenceFrame[];
44
+ /**
45
+ * Transform geocentric coordinates between reference frames at a given
46
+ * coordinate epoch (decimal years, e.g. 2010.5).
47
+ *
48
+ * The epoch is the epoch of the coordinates themselves — the same
49
+ * physical location is expressed in both frames at that instant; no
50
+ * intra-plate velocity propagation is applied.
51
+ */
52
+ declare function transformFrame(xyz: readonly [number, number, number], from: ReferenceFrame, to: ReferenceFrame, epoch: number): [number, number, number];
53
+ /** Convert a Date to the decimal-year epoch used by transformFrame. */
54
+ declare function dateToEpoch(date: Date): number;
55
+
56
+ export { type Helmert14, REFERENCE_FRAMES, type ReferenceFrame, applyHelmert, dateToEpoch, transformFrame };
package/dist/frames.js ADDED
@@ -0,0 +1,222 @@
1
+ // src/frames/index.ts
2
+ var H = (t, d, r, tDot, dDot, rDot, epoch) => ({ t, d, r, tDot, dDot, rDot, epoch });
3
+ var Z = [0, 0, 0];
4
+ var FROM_ITRF2020 = {
5
+ ITRF2014: H([-1.4, -0.9, 1.4], -0.42, Z, [0, -0.1, 0.2], 0, Z, 2015),
6
+ ITRF2008: H([0.2, 1, 3.3], -0.29, Z, [0, -0.1, 0.1], 0.03, Z, 2015),
7
+ ITRF2005: H([2.7, 0.1, -1.4], 0.65, Z, [0.3, -0.1, 0.1], 0.03, Z, 2015),
8
+ ITRF2000: H([-0.2, 0.8, -34.2], 2.25, Z, [0.1, 0, -1.7], 0.11, Z, 2015),
9
+ ITRF97: H(
10
+ [6.5, -3.9, -77.9],
11
+ 3.98,
12
+ [0, 0, 0.36],
13
+ [0.1, -0.6, -3.1],
14
+ 0.12,
15
+ [0, 0, 0.02],
16
+ 2015
17
+ ),
18
+ ITRF96: H(
19
+ [6.5, -3.9, -77.9],
20
+ 3.98,
21
+ [0, 0, 0.36],
22
+ [0.1, -0.6, -3.1],
23
+ 0.12,
24
+ [0, 0, 0.02],
25
+ 2015
26
+ ),
27
+ ITRF94: H(
28
+ [6.5, -3.9, -77.9],
29
+ 3.98,
30
+ [0, 0, 0.36],
31
+ [0.1, -0.6, -3.1],
32
+ 0.12,
33
+ [0, 0, 0.02],
34
+ 2015
35
+ ),
36
+ ITRF93: H(
37
+ [-65.8, 1.9, -71.3],
38
+ 4.47,
39
+ [-3.36, -4.33, 0.75],
40
+ [-2.8, -0.2, -2.3],
41
+ 0.12,
42
+ [-0.11, -0.19, 0.07],
43
+ 2015
44
+ ),
45
+ ITRF92: H(
46
+ [14.5, -1.9, -85.9],
47
+ 3.27,
48
+ [0, 0, 0.36],
49
+ [0.1, -0.6, -3.1],
50
+ 0.12,
51
+ [0, 0, 0.02],
52
+ 2015
53
+ ),
54
+ ITRF91: H(
55
+ [26.5, 12.1, -91.9],
56
+ 4.67,
57
+ [0, 0, 0.36],
58
+ [0.1, -0.6, -3.1],
59
+ 0.12,
60
+ [0, 0, 0.02],
61
+ 2015
62
+ ),
63
+ ITRF90: H(
64
+ [24.5, 8.1, -107.9],
65
+ 4.97,
66
+ [0, 0, 0.36],
67
+ [0.1, -0.6, -3.1],
68
+ 0.12,
69
+ [0, 0, 0.02],
70
+ 2015
71
+ ),
72
+ ITRF89: H(
73
+ [29.5, 32.1, -145.9],
74
+ 8.37,
75
+ [0, 0, 0.36],
76
+ [0.1, -0.6, -3.1],
77
+ 0.12,
78
+ [0, 0, 0.02],
79
+ 2015
80
+ ),
81
+ ITRF88: H(
82
+ [24.5, -3.9, -169.9],
83
+ 11.47,
84
+ [0.1, 0, 0.36],
85
+ [0.1, -0.6, -3.1],
86
+ 0.12,
87
+ [0, 0, 0.02],
88
+ 2015
89
+ ),
90
+ /** ITRF2020 → ETRF2020, EPSG:10572 (epoch-1989 variant) */
91
+ ETRF2020: H(Z, 0, Z, Z, 0, [0.086, 0.519, -0.753], 1989)
92
+ };
93
+ var ITRF2014_TO_ETRF2014 = H(Z, 0, Z, Z, 0, [0.085, 0.531, -0.77], 1989);
94
+ var ITRF2014_TO_ETRF2000 = H(
95
+ [54.7, 52.2, -74.1],
96
+ 2.12,
97
+ [1.701, 10.29, -16.632],
98
+ [0.1, 0.1, -1.9],
99
+ 0.11,
100
+ [0.081, 0.49, -0.792],
101
+ 2010
102
+ );
103
+ var ITRF2014_TO_NAD83_2011 = H(
104
+ [1005.3, -1909.21, -541.57],
105
+ 0.36891,
106
+ [-26.78138, 0.42027, -10.93206],
107
+ [0.79, -0.6, -1.44],
108
+ -0.07201,
109
+ [-0.06667, 0.75744, 0.05133],
110
+ 2010
111
+ );
112
+ var MAS_TO_RAD = Math.PI / (180 * 3600 * 1e3);
113
+ function applyHelmert(xyz, p, epoch, inverse = false) {
114
+ const dt = epoch - p.epoch;
115
+ const sign = inverse ? -1 : 1;
116
+ const tx = sign * (p.t[0] + p.tDot[0] * dt) / 1e3;
117
+ const ty = sign * (p.t[1] + p.tDot[1] * dt) / 1e3;
118
+ const tz = sign * (p.t[2] + p.tDot[2] * dt) / 1e3;
119
+ const d = sign * (p.d + p.dDot * dt) * 1e-9;
120
+ const rx = sign * (p.r[0] + p.rDot[0] * dt) * MAS_TO_RAD;
121
+ const ry = sign * (p.r[1] + p.rDot[1] * dt) * MAS_TO_RAD;
122
+ const rz = sign * (p.r[2] + p.rDot[2] * dt) * MAS_TO_RAD;
123
+ const [x, y, z] = xyz;
124
+ return [
125
+ x + tx + d * x - rz * y + ry * z,
126
+ y + ty + rz * x + d * y - rx * z,
127
+ z + tz - ry * x + rx * y + d * z
128
+ ];
129
+ }
130
+ var EDGES = [
131
+ ...Object.entries(FROM_ITRF2020).map(([to, p]) => ({
132
+ from: "ITRF2020",
133
+ to,
134
+ p
135
+ })),
136
+ { from: "ITRF2014", to: "ETRF2014", p: ITRF2014_TO_ETRF2014 },
137
+ { from: "ITRF2014", to: "ETRF2000", p: ITRF2014_TO_ETRF2000 },
138
+ { from: "ITRF2014", to: "NAD83(2011)", p: ITRF2014_TO_NAD83_2011 }
139
+ ];
140
+ var REFERENCE_FRAMES = [
141
+ "WGS84",
142
+ "ITRF2020",
143
+ "ITRF2014",
144
+ "ITRF2008",
145
+ "ITRF2005",
146
+ "ITRF2000",
147
+ "ITRF97",
148
+ "ITRF96",
149
+ "ITRF94",
150
+ "ITRF93",
151
+ "ITRF92",
152
+ "ITRF91",
153
+ "ITRF90",
154
+ "ITRF89",
155
+ "ITRF88",
156
+ "ETRF2020",
157
+ "ETRF2014",
158
+ "ETRF2000",
159
+ "NAD83(2011)"
160
+ ];
161
+ function resolveAlias(f) {
162
+ return f === "WGS84" ? "ITRF2020" : f;
163
+ }
164
+ function findPath(from, to) {
165
+ if (from === to) return [];
166
+ const queue = [from];
167
+ const cameFrom = /* @__PURE__ */ new Map();
168
+ const seen = /* @__PURE__ */ new Set([from]);
169
+ while (queue.length > 0) {
170
+ const cur = queue.shift();
171
+ for (const edge of EDGES) {
172
+ let next = null;
173
+ let inverse = false;
174
+ if (edge.from === cur) {
175
+ next = edge.to;
176
+ } else if (edge.to === cur) {
177
+ next = edge.from;
178
+ inverse = true;
179
+ }
180
+ if (next === null || seen.has(next)) continue;
181
+ seen.add(next);
182
+ cameFrom.set(next, { prev: cur, edge, inverse });
183
+ if (next === to) {
184
+ const path = [];
185
+ let node = to;
186
+ while (node !== from) {
187
+ const step = cameFrom.get(node);
188
+ path.unshift({ edge: step.edge, inverse: step.inverse });
189
+ node = step.prev;
190
+ }
191
+ return path;
192
+ }
193
+ queue.push(next);
194
+ }
195
+ }
196
+ return null;
197
+ }
198
+ function transformFrame(xyz, from, to, epoch) {
199
+ const src = resolveAlias(from);
200
+ const dst = resolveAlias(to);
201
+ const path = findPath(src, dst);
202
+ if (!path) {
203
+ throw new Error(`No transformation path from ${from} to ${to}`);
204
+ }
205
+ let out = [xyz[0], xyz[1], xyz[2]];
206
+ for (const { edge, inverse } of path) {
207
+ out = applyHelmert(out, edge.p, epoch, inverse);
208
+ }
209
+ return out;
210
+ }
211
+ function dateToEpoch(date) {
212
+ const year = date.getUTCFullYear();
213
+ const start = Date.UTC(year, 0, 1);
214
+ const end = Date.UTC(year + 1, 0, 1);
215
+ return year + (date.getTime() - start) / (end - start);
216
+ }
217
+ export {
218
+ REFERENCE_FRAMES,
219
+ applyHelmert,
220
+ dateToEpoch,
221
+ transformFrame
222
+ };
package/dist/index.cjs CHANGED
@@ -4201,7 +4201,8 @@ function selectEphemeris(ephemerides, prn, timeMs) {
4201
4201
  }
4202
4202
  function computeSatPosition(eph, timeMs) {
4203
4203
  if (eph.system === "R" || eph.system === "S") {
4204
- return glonassPosition(eph, timeMs / 1e3);
4204
+ const leapMs = getGpsLeap(new Date(timeMs)) * 1e3;
4205
+ return glonassPosition(eph, (timeMs - leapMs) / 1e3);
4205
4206
  }
4206
4207
  const GPS_EPOCH2 = START_GPS_TIME.getTime();
4207
4208
  const gpsSeconds = (timeMs - GPS_EPOCH2) / 1e3;
@@ -4374,7 +4375,7 @@ function ephInfoToEphemeris(info) {
4374
4375
  };
4375
4376
  }
4376
4377
  function computeLiveSkyPositions(ephemerides, rxPos, cn0Map) {
4377
- const now = Date.now();
4378
+ const now = Date.now() + getGpsLeap(/* @__PURE__ */ new Date()) * 1e3;
4378
4379
  const result = [];
4379
4380
  const [rxX, rxY, rxZ] = rxPos;
4380
4381
  const [rxLat, rxLon] = ecefToGeodetic(rxX, rxY, rxZ);