gnss-js 1.26.0 → 1.28.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/dist/chunk-4KMWWCUR.js +120 -0
- package/dist/{chunk-WDUN4BWL.js → chunk-6GTS5MVI.js} +437 -118
- package/dist/{chunk-4XGKCVE3.js → chunk-O65WA6CM.js} +810 -2
- package/dist/index.cjs +1268 -19
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +24 -4
- package/dist/positioning.cjs +883 -1
- package/dist/positioning.d.cts +231 -2
- package/dist/positioning.d.ts +231 -2
- package/dist/positioning.js +18 -1
- package/dist/rinex.cjs +438 -0
- package/dist/rinex.d.cts +28 -49
- package/dist/rinex.d.ts +28 -49
- package/dist/rinex.js +7 -3
- package/dist/sp3-BAq8l39b.d.cts +70 -0
- package/dist/sp3-BAq8l39b.d.ts +70 -0
- package/package.json +1 -1
- package/dist/ionex-DaW5x9nq.d.cts +0 -23
- package/dist/ionex-DaW5x9nq.d.ts +0 -23
package/dist/rinex.cjs
CHANGED
|
@@ -40,6 +40,7 @@ __export(rinex_exports, {
|
|
|
40
40
|
stationHeaderLines: () => stationHeaderLines,
|
|
41
41
|
systemCmp: () => systemCmp,
|
|
42
42
|
systemName: () => systemName,
|
|
43
|
+
writeCrx: () => writeCrx,
|
|
43
44
|
writeModernObsBlob: () => writeModernObsBlob,
|
|
44
45
|
writeRinex2ObsBlob: () => writeRinex2ObsBlob,
|
|
45
46
|
writeRinex4ObsBlob: () => writeRinex4ObsBlob,
|
|
@@ -134,6 +135,442 @@ function crxDecompress(prev, field) {
|
|
|
134
135
|
};
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
// src/rinex/crx-writer.ts
|
|
139
|
+
var ARC_ORDER = 3;
|
|
140
|
+
function emptyData() {
|
|
141
|
+
return { u: [0, 0, 0, 0], l: [0, 0, 0, 0], order: -1 };
|
|
142
|
+
}
|
|
143
|
+
function cAtol(s) {
|
|
144
|
+
let i = 0;
|
|
145
|
+
while (i < s.length && (s[i] === " " || s[i] === " ")) i++;
|
|
146
|
+
let sign = 1;
|
|
147
|
+
if (s[i] === "+" || s[i] === "-") {
|
|
148
|
+
if (s[i] === "-") sign = -1;
|
|
149
|
+
i++;
|
|
150
|
+
}
|
|
151
|
+
let n = 0;
|
|
152
|
+
let any = false;
|
|
153
|
+
while (i < s.length && s[i] >= "0" && s[i] <= "9") {
|
|
154
|
+
n = n * 10 + (s.charCodeAt(i) - 48);
|
|
155
|
+
i++;
|
|
156
|
+
any = true;
|
|
157
|
+
}
|
|
158
|
+
return any ? sign * n : 0;
|
|
159
|
+
}
|
|
160
|
+
function strdiff(s1, s2) {
|
|
161
|
+
let ds = "";
|
|
162
|
+
const n = Math.min(s1.length, s2.length);
|
|
163
|
+
let i = 0;
|
|
164
|
+
for (; i < n; i++) {
|
|
165
|
+
if (s2[i] === s1[i]) ds += " ";
|
|
166
|
+
else if (s2[i] === " ") ds += "&";
|
|
167
|
+
else ds += s2[i];
|
|
168
|
+
}
|
|
169
|
+
if (s1.length > s2.length) {
|
|
170
|
+
for (let k = i; k < s1.length; k++) ds += s1[k] === " " ? " " : "&";
|
|
171
|
+
} else if (s2.length > s1.length) {
|
|
172
|
+
ds += s2.slice(i);
|
|
173
|
+
}
|
|
174
|
+
let end = ds.length;
|
|
175
|
+
while (end > 0 && ds[end - 1] === " ") end--;
|
|
176
|
+
return ds.slice(0, end);
|
|
177
|
+
}
|
|
178
|
+
function readValue(field14) {
|
|
179
|
+
const c = field14.padEnd(14, " ").split("");
|
|
180
|
+
const p7 = c[7];
|
|
181
|
+
c[10] = c[9];
|
|
182
|
+
c[9] = c[8];
|
|
183
|
+
let l = cAtol(c.slice(9, 14).join(""));
|
|
184
|
+
let u;
|
|
185
|
+
if (p7 === " ") {
|
|
186
|
+
u = 0;
|
|
187
|
+
} else if (p7 === "-") {
|
|
188
|
+
u = 0;
|
|
189
|
+
l = -l;
|
|
190
|
+
} else {
|
|
191
|
+
c[8] = ".";
|
|
192
|
+
u = cAtol(c.slice(0, 14).join(""));
|
|
193
|
+
if (u < 0) l = -l;
|
|
194
|
+
}
|
|
195
|
+
return { u, l };
|
|
196
|
+
}
|
|
197
|
+
function putdiff(dddu, dddl) {
|
|
198
|
+
dddu += Math.trunc(dddl / 1e5);
|
|
199
|
+
dddl %= 1e5;
|
|
200
|
+
if (dddu < 0 && dddl > 0) {
|
|
201
|
+
dddu++;
|
|
202
|
+
dddl -= 1e5;
|
|
203
|
+
} else if (dddu > 0 && dddl < 0) {
|
|
204
|
+
dddu--;
|
|
205
|
+
dddl += 1e5;
|
|
206
|
+
}
|
|
207
|
+
if (dddu === 0) return String(dddl);
|
|
208
|
+
return `${dddu}${String(Math.abs(dddl)).padStart(5, "0")}`;
|
|
209
|
+
}
|
|
210
|
+
function putClock(du, dl, cOrder) {
|
|
211
|
+
du += Math.trunc(dl / 1e8);
|
|
212
|
+
dl %= 1e8;
|
|
213
|
+
if (du < 0 && dl > 0) {
|
|
214
|
+
du++;
|
|
215
|
+
dl -= 1e8;
|
|
216
|
+
} else if (du > 0 && dl < 0) {
|
|
217
|
+
du--;
|
|
218
|
+
dl += 1e8;
|
|
219
|
+
}
|
|
220
|
+
let out = "";
|
|
221
|
+
if (cOrder === 0) out += `${ARC_ORDER}&`;
|
|
222
|
+
if (du === 0) out += String(dl);
|
|
223
|
+
else out += `${du}${String(Math.abs(dl)).padStart(8, "0")}`;
|
|
224
|
+
return out;
|
|
225
|
+
}
|
|
226
|
+
function chop(line) {
|
|
227
|
+
let end = line.length;
|
|
228
|
+
if (end > 0 && line[end - 1] === "\r") end--;
|
|
229
|
+
while (end > 0 && line[end - 1] === " ") end--;
|
|
230
|
+
return line.slice(0, end);
|
|
231
|
+
}
|
|
232
|
+
function readSat(lines, cursor, rinexVersion, ntype, ntypeGnss) {
|
|
233
|
+
let line = chop(lines[cursor.li++] ?? "");
|
|
234
|
+
let maxField;
|
|
235
|
+
let ntypeRec;
|
|
236
|
+
let firstRec;
|
|
237
|
+
let satId = "";
|
|
238
|
+
if (rinexVersion === 2) {
|
|
239
|
+
maxField = 5;
|
|
240
|
+
ntypeRec = ntype;
|
|
241
|
+
firstRec = 0;
|
|
242
|
+
} else {
|
|
243
|
+
satId = line.slice(0, 3);
|
|
244
|
+
const sys = line[0];
|
|
245
|
+
maxField = ntypeRec = ntypeGnss[sys] ?? -1;
|
|
246
|
+
if (maxField < 0) return null;
|
|
247
|
+
firstRec = 3;
|
|
248
|
+
}
|
|
249
|
+
const data = [];
|
|
250
|
+
let flag = "";
|
|
251
|
+
for (let i = 0; i < ntypeRec; i += maxField) {
|
|
252
|
+
const nfield = Math.min(ntypeRec - i, maxField);
|
|
253
|
+
const need = firstRec + 16 * nfield;
|
|
254
|
+
let body = line;
|
|
255
|
+
if (body.length < need) body = body.padEnd(need, " ");
|
|
256
|
+
for (let j = 0; j < nfield; j++) {
|
|
257
|
+
const p = firstRec + j * 16;
|
|
258
|
+
const rec = body.slice(p, p + 16);
|
|
259
|
+
const d = emptyData();
|
|
260
|
+
if (rec[10] === ".") {
|
|
261
|
+
flag += rec[14] ?? " ";
|
|
262
|
+
flag += rec[15] ?? " ";
|
|
263
|
+
const v = readValue(rec.slice(0, 14));
|
|
264
|
+
d.u[0] = v.u;
|
|
265
|
+
d.l[0] = v.l;
|
|
266
|
+
d.order = 0;
|
|
267
|
+
} else if (rec.slice(0, 14).trim() === "") {
|
|
268
|
+
flag += rec[14] ?? " ";
|
|
269
|
+
flag += rec[15] ?? " ";
|
|
270
|
+
d.order = -1;
|
|
271
|
+
} else {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
data.push(d);
|
|
275
|
+
}
|
|
276
|
+
if (i + maxField < ntypeRec) {
|
|
277
|
+
line = chop(lines[cursor.li++] ?? "");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return { sat: { data, flag, ntypeRec }, satId };
|
|
281
|
+
}
|
|
282
|
+
var MONTHS = [
|
|
283
|
+
"Jan",
|
|
284
|
+
"Feb",
|
|
285
|
+
"Mar",
|
|
286
|
+
"Apr",
|
|
287
|
+
"May",
|
|
288
|
+
"Jun",
|
|
289
|
+
"Jul",
|
|
290
|
+
"Aug",
|
|
291
|
+
"Sep",
|
|
292
|
+
"Oct",
|
|
293
|
+
"Nov",
|
|
294
|
+
"Dec"
|
|
295
|
+
];
|
|
296
|
+
function crinexDate() {
|
|
297
|
+
const d = /* @__PURE__ */ new Date();
|
|
298
|
+
const dd = String(d.getUTCDate()).padStart(2, "0");
|
|
299
|
+
const mon = MONTHS[d.getUTCMonth()];
|
|
300
|
+
const yy = String(d.getUTCFullYear() % 100).padStart(2, "0");
|
|
301
|
+
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
302
|
+
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
303
|
+
return `${dd}-${mon}-${yy} ${hh}:${mm}`;
|
|
304
|
+
}
|
|
305
|
+
function writeCrx(rinexText, opts = {}) {
|
|
306
|
+
const rawLines = rinexText.split("\n");
|
|
307
|
+
const cursor = { li: 0 };
|
|
308
|
+
const out = [];
|
|
309
|
+
const firstLine = chop(rawLines[cursor.li++] ?? "");
|
|
310
|
+
if (firstLine.slice(60, 80) !== "RINEX VERSION / TYPE" || firstLine[20] !== "O") {
|
|
311
|
+
throw new Error("writeCrx: not a RINEX observation file");
|
|
312
|
+
}
|
|
313
|
+
const rinexVersion = parseInt(firstLine, 10);
|
|
314
|
+
const rinexVersionFull = readVersionFull(firstLine);
|
|
315
|
+
if (rinexVersionFull < 0) throw new Error("writeCrx: invalid RINEX version");
|
|
316
|
+
const crxVersion = rinexVersionFull >= 402 ? "3.1" : rinexVersion === 2 ? "1.0" : "3.0";
|
|
317
|
+
out.push(
|
|
318
|
+
`${crxVersion.padEnd(20)}${"COMPACT RINEX FORMAT".padEnd(40)}${"CRINEX VERS / TYPE".padEnd(20)}`
|
|
319
|
+
);
|
|
320
|
+
const prog = (opts.prog ?? "gnss-js writeCrx").slice(0, 40);
|
|
321
|
+
const date = opts.date ?? crinexDate();
|
|
322
|
+
out.push(`${prog.padEnd(40)}${date.padEnd(20)}CRINEX PROG / DATE`);
|
|
323
|
+
out.push(firstLine);
|
|
324
|
+
let ntype = 0;
|
|
325
|
+
const ntypeGnss = {};
|
|
326
|
+
let line;
|
|
327
|
+
do {
|
|
328
|
+
line = chop(rawLines[cursor.li++] ?? "");
|
|
329
|
+
out.push(line);
|
|
330
|
+
const label = line.slice(60).trimStart();
|
|
331
|
+
if (label.startsWith("# / TYPES OF OBSERV") && line[5] !== " ") {
|
|
332
|
+
ntype = parseInt(line, 10);
|
|
333
|
+
} else if (label.startsWith("SYS / # / OBS TYPES") && line[0] !== " ") {
|
|
334
|
+
ntypeGnss[line[0]] = parseInt(line.slice(3), 10);
|
|
335
|
+
}
|
|
336
|
+
if (cursor.li >= rawLines.length) break;
|
|
337
|
+
} while (!line.slice(60).trimStart().startsWith("END OF HEADER"));
|
|
338
|
+
const v2 = rinexVersion === 2;
|
|
339
|
+
const off = v2 ? { event: 28, nsat: 29, satlst: 32, clock: 68, satOld: 32, shiftClk: 1 } : {
|
|
340
|
+
event: 31,
|
|
341
|
+
nsat: 32,
|
|
342
|
+
satlst: 41,
|
|
343
|
+
clock: 41,
|
|
344
|
+
satOld: 41,
|
|
345
|
+
shiftClk: 4,
|
|
346
|
+
psec: 57
|
|
347
|
+
};
|
|
348
|
+
let oldline = "&";
|
|
349
|
+
let nsatOld = 0;
|
|
350
|
+
let clk0 = { u: [0, 0, 0, 0], l: [0, 0, 0, 0] };
|
|
351
|
+
let dy0 = [];
|
|
352
|
+
let flag0 = [];
|
|
353
|
+
let oldpsec = "";
|
|
354
|
+
let clkOrderPrev = -1;
|
|
355
|
+
const resetArcs = () => {
|
|
356
|
+
oldline = "&";
|
|
357
|
+
nsatOld = 0;
|
|
358
|
+
clkOrderPrev = -1;
|
|
359
|
+
};
|
|
360
|
+
for (; ; ) {
|
|
361
|
+
if (cursor.li >= rawLines.length) break;
|
|
362
|
+
let epoch = rawLines[cursor.li];
|
|
363
|
+
if (epoch === void 0) break;
|
|
364
|
+
if (epoch === "" && cursor.li === rawLines.length - 1) break;
|
|
365
|
+
cursor.li++;
|
|
366
|
+
epoch = chop(epoch);
|
|
367
|
+
if (epoch === "") continue;
|
|
368
|
+
let newline;
|
|
369
|
+
if (v2) {
|
|
370
|
+
newline = epoch;
|
|
371
|
+
} else {
|
|
372
|
+
newline = epoch.length < 41 ? epoch.padEnd(41, " ") : epoch;
|
|
373
|
+
}
|
|
374
|
+
const eventFlag = parseInt(newline[off.event] ?? "0", 10) || 0;
|
|
375
|
+
if (eventFlag > 1) {
|
|
376
|
+
putEventData(rawLines, cursor, v2, newline, out, ntypeGnss, (n) => {
|
|
377
|
+
ntype = n;
|
|
378
|
+
});
|
|
379
|
+
resetArcs();
|
|
380
|
+
clk0 = { u: [0, 0, 0, 0], l: [0, 0, 0, 0] };
|
|
381
|
+
dy0 = [];
|
|
382
|
+
flag0 = [];
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
let newpsec = "";
|
|
386
|
+
if (rinexVersionFull >= 402 && newline.length === 62) {
|
|
387
|
+
const psec = newline.slice(off.psec, off.psec + 5);
|
|
388
|
+
if (/^\d{5}$/.test(psec)) newpsec = psec;
|
|
389
|
+
newline = newline.slice(0, off.psec).replace(/\s+$/, "");
|
|
390
|
+
}
|
|
391
|
+
let clkOrder = -1;
|
|
392
|
+
const clk1 = { u: [0, 0, 0, 0], l: [0, 0, 0, 0] };
|
|
393
|
+
if (newline.length > off.clock) {
|
|
394
|
+
clkOrder = readClock(
|
|
395
|
+
newline.slice(off.clock),
|
|
396
|
+
off.shiftClk,
|
|
397
|
+
clk1,
|
|
398
|
+
clkOrderPrev
|
|
399
|
+
);
|
|
400
|
+
if (clkOrder > -1) {
|
|
401
|
+
newline = newline.slice(0, off.clock).replace(/\s+$/, "");
|
|
402
|
+
if (!v2 && newline.length < 41) newline = newline.padEnd(41, " ");
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
clkOrderPrev = clkOrder;
|
|
406
|
+
const nsat = parseInt((newline.slice(off.nsat) || "0").trim(), 10) || 0;
|
|
407
|
+
if (v2 && nsat > 12) {
|
|
408
|
+
newline = readMoreSat(rawLines, cursor, nsat, newline);
|
|
409
|
+
}
|
|
410
|
+
const sats = [];
|
|
411
|
+
const satIds = [];
|
|
412
|
+
let bad = false;
|
|
413
|
+
let satlist = v2 ? newline.slice(off.satlst, off.satlst + nsat * 3) : "";
|
|
414
|
+
for (let i = 0; i < nsat; i++) {
|
|
415
|
+
const r = readSat(rawLines, cursor, rinexVersion, ntype, ntypeGnss);
|
|
416
|
+
if (!r) {
|
|
417
|
+
bad = true;
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
sats.push(r.sat);
|
|
421
|
+
satIds.push(v2 ? satlist.slice(i * 3, i * 3 + 3) : r.satId);
|
|
422
|
+
}
|
|
423
|
+
if (bad) continue;
|
|
424
|
+
if (!v2) satlist = satIds.join("");
|
|
425
|
+
const fullNew = v2 ? newline : newline.slice(0, 41) + satlist;
|
|
426
|
+
const oldSatList = v2 ? oldline.slice(off.satOld, off.satOld + nsatOld * 3) : oldline.slice(off.satOld);
|
|
427
|
+
const sattbl = [];
|
|
428
|
+
const dup = /* @__PURE__ */ new Set();
|
|
429
|
+
for (let i = 0; i < nsat; i++) {
|
|
430
|
+
const id = satIds[i];
|
|
431
|
+
if (dup.has(id)) {
|
|
432
|
+
bad = true;
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
dup.add(id);
|
|
436
|
+
let found = -1;
|
|
437
|
+
for (let j = 0; j < nsatOld; j++) {
|
|
438
|
+
if (oldSatList.slice(j * 3, j * 3 + 3) === id) {
|
|
439
|
+
found = j;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
sattbl.push(found);
|
|
444
|
+
}
|
|
445
|
+
if (bad) continue;
|
|
446
|
+
out.push(strdiff(oldline, fullNew));
|
|
447
|
+
let clockLine = "";
|
|
448
|
+
if (clkOrder > -1) {
|
|
449
|
+
if (clkOrder > 0) processClock(clk1, clk0, clkOrder);
|
|
450
|
+
clockLine += putClock(clk1.u[clkOrder], clk1.l[clkOrder], clkOrder);
|
|
451
|
+
}
|
|
452
|
+
if (newpsec.length === 5) {
|
|
453
|
+
clockLine += " " + strdiff(oldpsec, newpsec);
|
|
454
|
+
}
|
|
455
|
+
out.push(clockLine);
|
|
456
|
+
const dataLines = buildData(sats, sattbl, dy0, flag0, rinexVersion);
|
|
457
|
+
for (const dl of dataLines) out.push(dl);
|
|
458
|
+
oldline = fullNew;
|
|
459
|
+
nsatOld = nsat;
|
|
460
|
+
clk0 = clk1;
|
|
461
|
+
oldpsec = newpsec;
|
|
462
|
+
dy0 = sats.map((s) => s.data);
|
|
463
|
+
flag0 = sats.map((s) => s.flag);
|
|
464
|
+
}
|
|
465
|
+
return out.join("\n") + "\n";
|
|
466
|
+
}
|
|
467
|
+
function readClock(field, shiftClk, clk1, prevOrder) {
|
|
468
|
+
const c = field.split("");
|
|
469
|
+
if (c[2] !== ".") return -1;
|
|
470
|
+
for (let k = 0; k < shiftClk; k++) c[2 + k] = c[3 + k];
|
|
471
|
+
c[2 + shiftClk] = ".";
|
|
472
|
+
const s = c.join("");
|
|
473
|
+
const m = /(-?\d+)\.(\d+)/.exec(s);
|
|
474
|
+
if (!m) return -1;
|
|
475
|
+
clk1.u[0] = parseInt(m[1], 10);
|
|
476
|
+
clk1.l[0] = parseInt(m[2], 10);
|
|
477
|
+
if (c[0] === "-" || c[1] === "-") clk1.l[0] = -clk1.l[0];
|
|
478
|
+
return Math.min(prevOrder + 1, ARC_ORDER);
|
|
479
|
+
}
|
|
480
|
+
function processClock(clk1, clk0, clkOrder) {
|
|
481
|
+
for (let i = 0; i < clkOrder; i++) {
|
|
482
|
+
clk1.u[i + 1] = clk1.u[i] - clk0.u[i];
|
|
483
|
+
clk1.l[i + 1] = clk1.l[i] - clk0.l[i];
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function takeDiff(py1, py0) {
|
|
487
|
+
py1.order = py0.order;
|
|
488
|
+
if (py1.order < ARC_ORDER) py1.order++;
|
|
489
|
+
for (let k = 0; k < py1.order; k++) {
|
|
490
|
+
py1.u[k + 1] = py1.u[k] - py0.u[k];
|
|
491
|
+
py1.l[k + 1] = py1.l[k] - py0.l[k];
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function buildData(sats, sattbl, dy0, flag0, rinexVersion) {
|
|
495
|
+
const lines = [];
|
|
496
|
+
for (let i = 0; i < sats.length; i++) {
|
|
497
|
+
const sat = sats[i];
|
|
498
|
+
const i0 = sattbl[i];
|
|
499
|
+
const prevFlag = (i0 >= 0 ? flag0[i0] ?? "" : "").split("");
|
|
500
|
+
let line = "";
|
|
501
|
+
for (let j = 0; j < sat.ntypeRec; j++) {
|
|
502
|
+
const py1 = sat.data[j];
|
|
503
|
+
if (py1.order >= 0) {
|
|
504
|
+
if (i0 < 0 || dy0[i0]?.[j]?.order === -1) {
|
|
505
|
+
py1.order = 0;
|
|
506
|
+
line += `${ARC_ORDER}&`;
|
|
507
|
+
} else {
|
|
508
|
+
takeDiff(py1, dy0[i0][j]);
|
|
509
|
+
if (Math.abs(py1.u[py1.order]) > 1e5) {
|
|
510
|
+
py1.order = 0;
|
|
511
|
+
line += `${ARC_ORDER}&`;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
line += putdiff(py1.u[py1.order], py1.l[py1.order]);
|
|
515
|
+
} else if (i0 >= 0 && rinexVersion === 2) {
|
|
516
|
+
prevFlag[j * 2] = " ";
|
|
517
|
+
prevFlag[j * 2 + 1] = " ";
|
|
518
|
+
}
|
|
519
|
+
line += " ";
|
|
520
|
+
}
|
|
521
|
+
if (i0 < 0 && rinexVersion !== 2) {
|
|
522
|
+
for (const ch of sat.flag) line += ch === " " ? "&" : ch;
|
|
523
|
+
} else {
|
|
524
|
+
line += i0 < 0 ? strdiff("", sat.flag) : strdiff(prevFlag.join(""), sat.flag);
|
|
525
|
+
line = line.replace(/ +$/, "");
|
|
526
|
+
}
|
|
527
|
+
lines.push(line);
|
|
528
|
+
}
|
|
529
|
+
return lines;
|
|
530
|
+
}
|
|
531
|
+
function putEventData(lines, cursor, v2, epochLine, out, ntypeGnss, setNtype) {
|
|
532
|
+
if (v2) {
|
|
533
|
+
out.push("&" + epochLine.slice(1));
|
|
534
|
+
if (epochLine.length > 29) {
|
|
535
|
+
const n = parseInt(epochLine.slice(29), 10) || 0;
|
|
536
|
+
for (let i = 0; i < n; i++) {
|
|
537
|
+
const l = chop(lines[cursor.li++] ?? "");
|
|
538
|
+
out.push(l);
|
|
539
|
+
if (l.slice(60).trimStart().startsWith("# / TYPES OF OBSERV") && l[5] !== " ") {
|
|
540
|
+
setNtype(parseInt(l, 10));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
} else {
|
|
545
|
+
out.push(epochLine.replace(/\s+$/, ""));
|
|
546
|
+
const n = parseInt(epochLine.slice(32), 10) || 0;
|
|
547
|
+
for (let i = 0; i < n; i++) {
|
|
548
|
+
const l = chop(lines[cursor.li++] ?? "");
|
|
549
|
+
out.push(l);
|
|
550
|
+
if (l.slice(60).trimStart().startsWith("SYS / # / OBS TYPES") && l[0] !== " ") {
|
|
551
|
+
ntypeGnss[l[0]] = parseInt(l.slice(3), 10);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function readMoreSat(lines, cursor, n, epochLine) {
|
|
557
|
+
let result = epochLine;
|
|
558
|
+
let remaining = n;
|
|
559
|
+
while (remaining > 12) {
|
|
560
|
+
const l = lines[cursor.li++] ?? "";
|
|
561
|
+
const chopped = chop(l);
|
|
562
|
+
result += chopped[2] === " " ? chopped.slice(32) : chopped;
|
|
563
|
+
remaining -= 12;
|
|
564
|
+
}
|
|
565
|
+
return result;
|
|
566
|
+
}
|
|
567
|
+
function readVersionFull(line) {
|
|
568
|
+
if (line[5] === "2" && line[6] === " ") return 200;
|
|
569
|
+
const d = (c) => c !== void 0 && c >= "0" && c <= "9";
|
|
570
|
+
if (!d(line[5]) || line[6] !== "." || !d(line[7]) || !d(line[8])) return -1;
|
|
571
|
+
return (line.charCodeAt(5) - 48) * 100 + (line.charCodeAt(7) - 48) * 10 + (line.charCodeAt(8) - 48);
|
|
572
|
+
}
|
|
573
|
+
|
|
137
574
|
// src/rinex/format.ts
|
|
138
575
|
function padL(s, w) {
|
|
139
576
|
return s.length >= w ? s.slice(0, w) : s + " ".repeat(w - s.length);
|
|
@@ -2346,6 +2783,7 @@ function writeRinex4ObsBlob(header, epochs, obsTypes) {
|
|
|
2346
2783
|
stationHeaderLines,
|
|
2347
2784
|
systemCmp,
|
|
2348
2785
|
systemName,
|
|
2786
|
+
writeCrx,
|
|
2349
2787
|
writeModernObsBlob,
|
|
2350
2788
|
writeRinex2ObsBlob,
|
|
2351
2789
|
writeRinex4ObsBlob,
|
package/dist/rinex.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { R as RinexHeader } from './parser-JPjjFgeP.cjs';
|
|
|
2
2
|
export { E as EpochSummary, P as ParseOptions, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.cjs';
|
|
3
3
|
import { a as NavResult, N as NavHeader, E as Ephemeris, R as RinexCnavEphemeris } from './nav-DImXUdbp.cjs';
|
|
4
4
|
export { G as GlonassEphemeris, K as KeplerEphemeris, p as parseNavFile } from './nav-DImXUdbp.cjs';
|
|
5
|
-
export { I as IonexGrid, p as parseIonex } from './
|
|
5
|
+
export { I as IonexGrid, S as Sp3File, a as Sp3Sample, p as parseIonex, b as parseSp3, s as sp3Position } from './sp3-BAq8l39b.cjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Compact RINEX (Hatanaka / CRX) decompression utilities.
|
|
@@ -49,6 +49,32 @@ declare function crxDecompress(prev: DiffState | null, field: CrxField): {
|
|
|
49
49
|
result: number;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Compact RINEX (Hatanaka / CRX) *compression* — the inverse of crx.ts.
|
|
54
|
+
*
|
|
55
|
+
* This is a faithful TypeScript port of RNXCMP's `rnx2crx.c` (v4.2.0,
|
|
56
|
+
* Y. Hatanaka / GSI Japan), operating on RINEX text in and CRINEX text
|
|
57
|
+
* out. It reproduces the reference compressor byte-for-byte in the data
|
|
58
|
+
* section (the CRINEX header's PROG/DATE line carries a timestamp, so it
|
|
59
|
+
* is the only line that legitimately differs from a given run of the C
|
|
60
|
+
* tool). Validated against the `rnx2crx`/`crx2rnx` oracles on real
|
|
61
|
+
* multi-GNSS RINEX 3.03/3.04 observation files.
|
|
62
|
+
*
|
|
63
|
+
* Supports RINEX 2.x (CRINEX 1.0) and RINEX 3.x / 4.0x (CRINEX 3.0).
|
|
64
|
+
* The RINEX 4.02 pico-second epoch record (CRINEX 3.1) is handled too.
|
|
65
|
+
*/
|
|
66
|
+
interface WriteCrxOptions {
|
|
67
|
+
/** CRINEX PROG / DATE program label (≤20 chars). */
|
|
68
|
+
prog?: string;
|
|
69
|
+
/** CRINEX PROG / DATE timestamp (as `dd-MMM-yy HH:mm`). Defaults to now (UTC). */
|
|
70
|
+
date?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Compress a full RINEX observation file (text) to Compact RINEX (text).
|
|
74
|
+
* The inverse of the crx.ts decoder. Throws on structurally invalid input.
|
|
75
|
+
*/
|
|
76
|
+
declare function writeCrx(rinexText: string, opts?: WriteCrxOptions): string;
|
|
77
|
+
|
|
52
78
|
/**
|
|
53
79
|
* Shared RINEX formatting helpers.
|
|
54
80
|
*
|
|
@@ -156,53 +182,6 @@ interface Nav4Input {
|
|
|
156
182
|
*/
|
|
157
183
|
declare function writeRinexNav4(nav: Nav4Input): string;
|
|
158
184
|
|
|
159
|
-
/**
|
|
160
|
-
* SP3-c/-d precise orbit and clock parser, with Lagrange interpolation
|
|
161
|
-
* for evaluating positions between the tabulated epochs.
|
|
162
|
-
*
|
|
163
|
-
* Positions are converted to meters (SP3 tabulates km), clocks to
|
|
164
|
-
* seconds (SP3 tabulates microseconds). Missing positions (all-zero
|
|
165
|
-
* coordinates) and the 999999.999999 bad-clock sentinel become null.
|
|
166
|
-
* Epoch tags are read in the file's own time scale (GPS for IGS/MGEX
|
|
167
|
-
* products) as epoch milliseconds, matching the convention of the
|
|
168
|
-
* RINEX parsers in this library.
|
|
169
|
-
*/
|
|
170
|
-
interface Sp3Sample {
|
|
171
|
-
/** ECEF meters. */
|
|
172
|
-
x: number;
|
|
173
|
-
y: number;
|
|
174
|
-
z: number;
|
|
175
|
-
/** Satellite clock offset in seconds, or null when flagged bad. */
|
|
176
|
-
clk: number | null;
|
|
177
|
-
}
|
|
178
|
-
interface Sp3File {
|
|
179
|
-
version: string;
|
|
180
|
-
/** Epoch timestamps (ms). */
|
|
181
|
-
epochs: number[];
|
|
182
|
-
/** Tabulated interval in seconds (from the ## header line). */
|
|
183
|
-
intervalSec: number;
|
|
184
|
-
/** Time system from the %c line, e.g. 'GPS'. */
|
|
185
|
-
timeSystem: string;
|
|
186
|
-
/** prn → per-epoch samples (null where the satellite is missing). */
|
|
187
|
-
satellites: Record<string, (Sp3Sample | null)[]>;
|
|
188
|
-
}
|
|
189
|
-
declare function parseSp3(text: string): Sp3File;
|
|
190
|
-
/**
|
|
191
|
-
* Satellite position at an arbitrary time by Lagrange interpolation
|
|
192
|
-
* over the `order` nearest tabulated samples (default 9, the standard
|
|
193
|
-
* choice for 5–15 min SP3 tables; centimetre-level between nodes).
|
|
194
|
-
* Clock is interpolated linearly between the bracketing samples.
|
|
195
|
-
*
|
|
196
|
-
* Returns null outside the covered span, near data gaps, or when the
|
|
197
|
-
* satellite is absent.
|
|
198
|
-
*/
|
|
199
|
-
declare function sp3Position(sp3: Sp3File, prn: string, tMs: number, order?: number): {
|
|
200
|
-
x: number;
|
|
201
|
-
y: number;
|
|
202
|
-
z: number;
|
|
203
|
-
clk: number | null;
|
|
204
|
-
} | null;
|
|
205
|
-
|
|
206
185
|
/**
|
|
207
186
|
* RINEX 3.04 / 4.01 observation file writer.
|
|
208
187
|
*
|
|
@@ -284,4 +263,4 @@ declare function createGzipLineSink(): {
|
|
|
284
263
|
*/
|
|
285
264
|
declare function stationHeaderLines(header: RinexHeader): string[];
|
|
286
265
|
|
|
287
|
-
export { type CompactEpoch, type CrxField, type DiffState, EMPTY_WARNINGS, Ephemeris, type Nav4Input, NavHeader, NavResult, RinexCnavEphemeris, RinexHeader, type RinexWarning, type RinexWarnings,
|
|
266
|
+
export { type CompactEpoch, type CrxField, type DiffState, EMPTY_WARNINGS, Ephemeris, type Nav4Input, NavHeader, NavResult, RinexCnavEphemeris, RinexHeader, type RinexWarning, type RinexWarnings, WarningAccumulator, type WarningSeverity, type WriteCrxOptions, createGzipLineSink, crxDecompress, crxRepair, fmtD, fmtF, hdrLine, padL, padR, parseCrxDataLine, stationHeaderLines, writeCrx, writeModernObsBlob, writeRinex2ObsBlob, writeRinex4ObsBlob, writeRinexNav, writeRinexNav4, writeRinexObsBlob };
|
package/dist/rinex.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { R as RinexHeader } from './parser-JPjjFgeP.js';
|
|
|
2
2
|
export { E as EpochSummary, P as ParseOptions, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.js';
|
|
3
3
|
import { a as NavResult, N as NavHeader, E as Ephemeris, R as RinexCnavEphemeris } from './nav-DImXUdbp.js';
|
|
4
4
|
export { G as GlonassEphemeris, K as KeplerEphemeris, p as parseNavFile } from './nav-DImXUdbp.js';
|
|
5
|
-
export { I as IonexGrid, p as parseIonex } from './
|
|
5
|
+
export { I as IonexGrid, S as Sp3File, a as Sp3Sample, p as parseIonex, b as parseSp3, s as sp3Position } from './sp3-BAq8l39b.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Compact RINEX (Hatanaka / CRX) decompression utilities.
|
|
@@ -49,6 +49,32 @@ declare function crxDecompress(prev: DiffState | null, field: CrxField): {
|
|
|
49
49
|
result: number;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Compact RINEX (Hatanaka / CRX) *compression* — the inverse of crx.ts.
|
|
54
|
+
*
|
|
55
|
+
* This is a faithful TypeScript port of RNXCMP's `rnx2crx.c` (v4.2.0,
|
|
56
|
+
* Y. Hatanaka / GSI Japan), operating on RINEX text in and CRINEX text
|
|
57
|
+
* out. It reproduces the reference compressor byte-for-byte in the data
|
|
58
|
+
* section (the CRINEX header's PROG/DATE line carries a timestamp, so it
|
|
59
|
+
* is the only line that legitimately differs from a given run of the C
|
|
60
|
+
* tool). Validated against the `rnx2crx`/`crx2rnx` oracles on real
|
|
61
|
+
* multi-GNSS RINEX 3.03/3.04 observation files.
|
|
62
|
+
*
|
|
63
|
+
* Supports RINEX 2.x (CRINEX 1.0) and RINEX 3.x / 4.0x (CRINEX 3.0).
|
|
64
|
+
* The RINEX 4.02 pico-second epoch record (CRINEX 3.1) is handled too.
|
|
65
|
+
*/
|
|
66
|
+
interface WriteCrxOptions {
|
|
67
|
+
/** CRINEX PROG / DATE program label (≤20 chars). */
|
|
68
|
+
prog?: string;
|
|
69
|
+
/** CRINEX PROG / DATE timestamp (as `dd-MMM-yy HH:mm`). Defaults to now (UTC). */
|
|
70
|
+
date?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Compress a full RINEX observation file (text) to Compact RINEX (text).
|
|
74
|
+
* The inverse of the crx.ts decoder. Throws on structurally invalid input.
|
|
75
|
+
*/
|
|
76
|
+
declare function writeCrx(rinexText: string, opts?: WriteCrxOptions): string;
|
|
77
|
+
|
|
52
78
|
/**
|
|
53
79
|
* Shared RINEX formatting helpers.
|
|
54
80
|
*
|
|
@@ -156,53 +182,6 @@ interface Nav4Input {
|
|
|
156
182
|
*/
|
|
157
183
|
declare function writeRinexNav4(nav: Nav4Input): string;
|
|
158
184
|
|
|
159
|
-
/**
|
|
160
|
-
* SP3-c/-d precise orbit and clock parser, with Lagrange interpolation
|
|
161
|
-
* for evaluating positions between the tabulated epochs.
|
|
162
|
-
*
|
|
163
|
-
* Positions are converted to meters (SP3 tabulates km), clocks to
|
|
164
|
-
* seconds (SP3 tabulates microseconds). Missing positions (all-zero
|
|
165
|
-
* coordinates) and the 999999.999999 bad-clock sentinel become null.
|
|
166
|
-
* Epoch tags are read in the file's own time scale (GPS for IGS/MGEX
|
|
167
|
-
* products) as epoch milliseconds, matching the convention of the
|
|
168
|
-
* RINEX parsers in this library.
|
|
169
|
-
*/
|
|
170
|
-
interface Sp3Sample {
|
|
171
|
-
/** ECEF meters. */
|
|
172
|
-
x: number;
|
|
173
|
-
y: number;
|
|
174
|
-
z: number;
|
|
175
|
-
/** Satellite clock offset in seconds, or null when flagged bad. */
|
|
176
|
-
clk: number | null;
|
|
177
|
-
}
|
|
178
|
-
interface Sp3File {
|
|
179
|
-
version: string;
|
|
180
|
-
/** Epoch timestamps (ms). */
|
|
181
|
-
epochs: number[];
|
|
182
|
-
/** Tabulated interval in seconds (from the ## header line). */
|
|
183
|
-
intervalSec: number;
|
|
184
|
-
/** Time system from the %c line, e.g. 'GPS'. */
|
|
185
|
-
timeSystem: string;
|
|
186
|
-
/** prn → per-epoch samples (null where the satellite is missing). */
|
|
187
|
-
satellites: Record<string, (Sp3Sample | null)[]>;
|
|
188
|
-
}
|
|
189
|
-
declare function parseSp3(text: string): Sp3File;
|
|
190
|
-
/**
|
|
191
|
-
* Satellite position at an arbitrary time by Lagrange interpolation
|
|
192
|
-
* over the `order` nearest tabulated samples (default 9, the standard
|
|
193
|
-
* choice for 5–15 min SP3 tables; centimetre-level between nodes).
|
|
194
|
-
* Clock is interpolated linearly between the bracketing samples.
|
|
195
|
-
*
|
|
196
|
-
* Returns null outside the covered span, near data gaps, or when the
|
|
197
|
-
* satellite is absent.
|
|
198
|
-
*/
|
|
199
|
-
declare function sp3Position(sp3: Sp3File, prn: string, tMs: number, order?: number): {
|
|
200
|
-
x: number;
|
|
201
|
-
y: number;
|
|
202
|
-
z: number;
|
|
203
|
-
clk: number | null;
|
|
204
|
-
} | null;
|
|
205
|
-
|
|
206
185
|
/**
|
|
207
186
|
* RINEX 3.04 / 4.01 observation file writer.
|
|
208
187
|
*
|
|
@@ -284,4 +263,4 @@ declare function createGzipLineSink(): {
|
|
|
284
263
|
*/
|
|
285
264
|
declare function stationHeaderLines(header: RinexHeader): string[];
|
|
286
265
|
|
|
287
|
-
export { type CompactEpoch, type CrxField, type DiffState, EMPTY_WARNINGS, Ephemeris, type Nav4Input, NavHeader, NavResult, RinexCnavEphemeris, RinexHeader, type RinexWarning, type RinexWarnings,
|
|
266
|
+
export { type CompactEpoch, type CrxField, type DiffState, EMPTY_WARNINGS, Ephemeris, type Nav4Input, NavHeader, NavResult, RinexCnavEphemeris, RinexHeader, type RinexWarning, type RinexWarnings, WarningAccumulator, type WarningSeverity, type WriteCrxOptions, createGzipLineSink, crxDecompress, crxRepair, fmtD, fmtF, hdrLine, padL, padR, parseCrxDataLine, stationHeaderLines, writeCrx, writeModernObsBlob, writeRinex2ObsBlob, writeRinex4ObsBlob, writeRinexNav, writeRinexNav4, writeRinexObsBlob };
|
package/dist/rinex.js
CHANGED
|
@@ -9,16 +9,15 @@ import {
|
|
|
9
9
|
padR,
|
|
10
10
|
parseIonex,
|
|
11
11
|
parseNavFile,
|
|
12
|
-
parseSp3,
|
|
13
|
-
sp3Position,
|
|
14
12
|
stationHeaderLines,
|
|
13
|
+
writeCrx,
|
|
15
14
|
writeModernObsBlob,
|
|
16
15
|
writeRinex2ObsBlob,
|
|
17
16
|
writeRinex4ObsBlob,
|
|
18
17
|
writeRinexNav,
|
|
19
18
|
writeRinexNav4,
|
|
20
19
|
writeRinexObsBlob
|
|
21
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-6GTS5MVI.js";
|
|
22
21
|
import "./chunk-726LQBGM.js";
|
|
23
22
|
import "./chunk-IQ5OIMQD.js";
|
|
24
23
|
import {
|
|
@@ -30,6 +29,10 @@ import {
|
|
|
30
29
|
systemCmp,
|
|
31
30
|
systemName
|
|
32
31
|
} from "./chunk-3U5AX7PY.js";
|
|
32
|
+
import {
|
|
33
|
+
parseSp3,
|
|
34
|
+
sp3Position
|
|
35
|
+
} from "./chunk-4KMWWCUR.js";
|
|
33
36
|
import "./chunk-FIEWO4J4.js";
|
|
34
37
|
export {
|
|
35
38
|
EMPTY_WARNINGS,
|
|
@@ -52,6 +55,7 @@ export {
|
|
|
52
55
|
stationHeaderLines,
|
|
53
56
|
systemCmp,
|
|
54
57
|
systemName,
|
|
58
|
+
writeCrx,
|
|
55
59
|
writeModernObsBlob,
|
|
56
60
|
writeRinex2ObsBlob,
|
|
57
61
|
writeRinex4ObsBlob,
|