@aguacerowx/mapsgl 0.0.57 → 0.0.58
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/index.js +45 -45
- package/package.json +1 -1
- package/src/GridRenderLayer.js +1387 -1387
- package/src/MapManager.js +197 -197
- package/src/NexradSitesOverlay.js +148 -148
- package/src/NexradWeatherController.js +3 -0
- package/src/SatelliteShaderManager.js +1000 -1000
- package/src/WorkerPool.js +340 -340
- package/src/defaultBasisBaseUrl.js +11 -11
- package/src/nexrad/MapboxRadarLayer.ts +783 -783
- package/src/nexrad/PreprocessedSweepParser.ts +225 -225
- package/src/nexrad/buildRadarRayGeometry.ts +97 -97
- package/src/nexrad/level3StormRelative.ts +116 -116
- package/src/nexrad/loadNexradSites.ts +119 -119
- package/src/nexrad/nexradArchiveDiag.ts +26 -26
- package/src/nexrad/nexradCrossSectionSampleAtLatLon.ts +121 -121
- package/src/nexrad/nexradMapboxFrameOpts.ts +126 -126
- package/src/nexrad/nexradSitesDefault.json +1699 -1699
- package/src/nexrad/radarArchiveCore.bundled.js +10 -0
- package/src/nexrad/radarArchiveCore.ts +11 -0
- package/src/nexrad/radarDecode.worker.ts +25 -25
- package/src/nexrad/radarDecodeSlot.ts +195 -195
- package/src/nexrad/radarFrameGpuMatch.ts +111 -111
- package/src/satelliteDefaultColormaps.js +37 -37
- package/src/satelliteKtxWorker.js +232 -232
- package/src/satelliteShader.js +17 -17
- package/src/style-applicator.js +112 -112
- package/src/style-layer-map.js +26 -26
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Frame transforms applied in {@link MapboxRadarLayer} before GPU upload.
|
|
3
|
-
* Mouse readouts must use the **same** gate/ray ordering as the texture or samples drift from pixels.
|
|
4
|
-
*/
|
|
5
|
-
import type { DecodedRadarFrame } from './nexradArchiveCache.js';
|
|
6
|
-
|
|
7
|
-
/** Shortest distance between two headings on [0, 360), in degrees. */
|
|
8
|
-
function angularDistanceDeg(a: number, b: number): number {
|
|
9
|
-
let d = Math.abs(a - b) % 360;
|
|
10
|
-
if (d > 180) d = 360 - d;
|
|
11
|
-
return d;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* For Level-III layout products (KDP/N0H): remap incoming rays into fixed canonical azimuth bins
|
|
16
|
-
* (same as MapboxRadarLayer `sortFrameToCanonicalBins`).
|
|
17
|
-
*/
|
|
18
|
-
export function canonicalBinsRadarFrame(frame: DecodedRadarFrame): DecodedRadarFrame {
|
|
19
|
-
const nRays = frame.nRays;
|
|
20
|
-
const nGates = frame.nGates;
|
|
21
|
-
if (nRays <= 0 || nGates <= 0) return frame;
|
|
22
|
-
if (frame.rayBoundariesDeg.length < nRays + 1) return frame;
|
|
23
|
-
|
|
24
|
-
const degPerBin = 360 / nRays;
|
|
25
|
-
const bytesPerRay = nGates * 2;
|
|
26
|
-
|
|
27
|
-
const centers = new Float32Array(nRays);
|
|
28
|
-
for (let r = 0; r < nRays; r++) {
|
|
29
|
-
const lower = frame.rayBoundariesDeg[r]!;
|
|
30
|
-
const upper = frame.rayBoundariesDeg[r + 1]!;
|
|
31
|
-
const center = (lower + upper) * 0.5;
|
|
32
|
-
centers[r] = ((center % 360) + 360) % 360;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const canonicalGateData = new Uint8Array(nRays * bytesPerRay);
|
|
36
|
-
for (let i = 0; i < canonicalGateData.length; i += 2) {
|
|
37
|
-
canonicalGateData[i] = 128;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const used = new Array<boolean>(nRays).fill(false);
|
|
41
|
-
for (let bin = 0; bin < nRays; bin++) {
|
|
42
|
-
const targetDeg = ((((bin + 0.5) * degPerBin) % 360) + 360) % 360;
|
|
43
|
-
let bestR = -1;
|
|
44
|
-
let bestDist = Infinity;
|
|
45
|
-
for (let r = 0; r < nRays; r++) {
|
|
46
|
-
if (used[r]) continue;
|
|
47
|
-
const dist = angularDistanceDeg(centers[r], targetDeg);
|
|
48
|
-
if (dist < bestDist) {
|
|
49
|
-
bestDist = dist;
|
|
50
|
-
bestR = r;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (bestR >= 0) {
|
|
54
|
-
used[bestR] = true;
|
|
55
|
-
canonicalGateData.set(
|
|
56
|
-
frame.gateData.subarray(bestR * bytesPerRay, (bestR + 1) * bytesPerRay),
|
|
57
|
-
bin * bytesPerRay,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const canonicalBoundaries = new Float32Array(nRays + 1);
|
|
63
|
-
for (let i = 0; i <= nRays; i++) {
|
|
64
|
-
canonicalBoundaries[i] = i * degPerBin;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return { ...frame, gateData: canonicalGateData, rayBoundariesDeg: canonicalBoundaries };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Sort rays by ascending start azimuth — same as MapboxRadarLayer `sortFrameByAzimuth`. */
|
|
71
|
-
export function sortRadarFrameByAzimuth(frame: DecodedRadarFrame): DecodedRadarFrame {
|
|
72
|
-
const nRays = frame.nRays;
|
|
73
|
-
const nGates = frame.nGates;
|
|
74
|
-
const bytesPerRay = nGates * 2;
|
|
75
|
-
|
|
76
|
-
const rayOrder = Array.from({ length: nRays }, (_, i) => i).sort(
|
|
77
|
-
(a, b) => frame.rayBoundariesDeg[a] - frame.rayBoundariesDeg[b],
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const sortedGateData = new Uint8Array(nRays * bytesPerRay);
|
|
81
|
-
const sortedBoundaries = new Float32Array(nRays + 1);
|
|
82
|
-
|
|
83
|
-
for (let newIdx = 0; newIdx < nRays; newIdx++) {
|
|
84
|
-
const oldIdx = rayOrder[newIdx]!;
|
|
85
|
-
sortedGateData.set(
|
|
86
|
-
frame.gateData.subarray(oldIdx * bytesPerRay, (oldIdx + 1) * bytesPerRay),
|
|
87
|
-
newIdx * bytesPerRay,
|
|
88
|
-
);
|
|
89
|
-
sortedBoundaries[newIdx] = frame.rayBoundariesDeg[oldIdx]!;
|
|
90
|
-
}
|
|
91
|
-
sortedBoundaries[nRays] =
|
|
92
|
-
frame.rayBoundariesDeg[rayOrder[nRays - 1]!]! +
|
|
93
|
-
(frame.rayBoundariesDeg[rayOrder[1]!]! - frame.rayBoundariesDeg[rayOrder[0]!]!);
|
|
94
|
-
|
|
95
|
-
return { ...frame, gateData: sortedGateData, rayBoundariesDeg: sortedBoundaries };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export type GpuReadoutFrameOptions = {
|
|
99
|
-
geometryLayoutKey?: string | null;
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Match {@link MapboxRadarLayer} `uploadFrame` gate/ray ordering for CPU readout.
|
|
104
|
-
*/
|
|
105
|
-
export function prepareRadarFrameForGpuReadout(
|
|
106
|
-
frame: DecodedRadarFrame,
|
|
107
|
-
options?: GpuReadoutFrameOptions,
|
|
108
|
-
): DecodedRadarFrame {
|
|
109
|
-
const hasLayoutKey = options?.geometryLayoutKey != null && options.geometryLayoutKey !== '';
|
|
110
|
-
return hasLayoutKey ? canonicalBinsRadarFrame(frame) : sortRadarFrameByAzimuth(frame);
|
|
111
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Frame transforms applied in {@link MapboxRadarLayer} before GPU upload.
|
|
3
|
+
* Mouse readouts must use the **same** gate/ray ordering as the texture or samples drift from pixels.
|
|
4
|
+
*/
|
|
5
|
+
import type { DecodedRadarFrame } from './nexradArchiveCache.js';
|
|
6
|
+
|
|
7
|
+
/** Shortest distance between two headings on [0, 360), in degrees. */
|
|
8
|
+
function angularDistanceDeg(a: number, b: number): number {
|
|
9
|
+
let d = Math.abs(a - b) % 360;
|
|
10
|
+
if (d > 180) d = 360 - d;
|
|
11
|
+
return d;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* For Level-III layout products (KDP/N0H): remap incoming rays into fixed canonical azimuth bins
|
|
16
|
+
* (same as MapboxRadarLayer `sortFrameToCanonicalBins`).
|
|
17
|
+
*/
|
|
18
|
+
export function canonicalBinsRadarFrame(frame: DecodedRadarFrame): DecodedRadarFrame {
|
|
19
|
+
const nRays = frame.nRays;
|
|
20
|
+
const nGates = frame.nGates;
|
|
21
|
+
if (nRays <= 0 || nGates <= 0) return frame;
|
|
22
|
+
if (frame.rayBoundariesDeg.length < nRays + 1) return frame;
|
|
23
|
+
|
|
24
|
+
const degPerBin = 360 / nRays;
|
|
25
|
+
const bytesPerRay = nGates * 2;
|
|
26
|
+
|
|
27
|
+
const centers = new Float32Array(nRays);
|
|
28
|
+
for (let r = 0; r < nRays; r++) {
|
|
29
|
+
const lower = frame.rayBoundariesDeg[r]!;
|
|
30
|
+
const upper = frame.rayBoundariesDeg[r + 1]!;
|
|
31
|
+
const center = (lower + upper) * 0.5;
|
|
32
|
+
centers[r] = ((center % 360) + 360) % 360;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const canonicalGateData = new Uint8Array(nRays * bytesPerRay);
|
|
36
|
+
for (let i = 0; i < canonicalGateData.length; i += 2) {
|
|
37
|
+
canonicalGateData[i] = 128;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const used = new Array<boolean>(nRays).fill(false);
|
|
41
|
+
for (let bin = 0; bin < nRays; bin++) {
|
|
42
|
+
const targetDeg = ((((bin + 0.5) * degPerBin) % 360) + 360) % 360;
|
|
43
|
+
let bestR = -1;
|
|
44
|
+
let bestDist = Infinity;
|
|
45
|
+
for (let r = 0; r < nRays; r++) {
|
|
46
|
+
if (used[r]) continue;
|
|
47
|
+
const dist = angularDistanceDeg(centers[r], targetDeg);
|
|
48
|
+
if (dist < bestDist) {
|
|
49
|
+
bestDist = dist;
|
|
50
|
+
bestR = r;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (bestR >= 0) {
|
|
54
|
+
used[bestR] = true;
|
|
55
|
+
canonicalGateData.set(
|
|
56
|
+
frame.gateData.subarray(bestR * bytesPerRay, (bestR + 1) * bytesPerRay),
|
|
57
|
+
bin * bytesPerRay,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const canonicalBoundaries = new Float32Array(nRays + 1);
|
|
63
|
+
for (let i = 0; i <= nRays; i++) {
|
|
64
|
+
canonicalBoundaries[i] = i * degPerBin;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return { ...frame, gateData: canonicalGateData, rayBoundariesDeg: canonicalBoundaries };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Sort rays by ascending start azimuth — same as MapboxRadarLayer `sortFrameByAzimuth`. */
|
|
71
|
+
export function sortRadarFrameByAzimuth(frame: DecodedRadarFrame): DecodedRadarFrame {
|
|
72
|
+
const nRays = frame.nRays;
|
|
73
|
+
const nGates = frame.nGates;
|
|
74
|
+
const bytesPerRay = nGates * 2;
|
|
75
|
+
|
|
76
|
+
const rayOrder = Array.from({ length: nRays }, (_, i) => i).sort(
|
|
77
|
+
(a, b) => frame.rayBoundariesDeg[a] - frame.rayBoundariesDeg[b],
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const sortedGateData = new Uint8Array(nRays * bytesPerRay);
|
|
81
|
+
const sortedBoundaries = new Float32Array(nRays + 1);
|
|
82
|
+
|
|
83
|
+
for (let newIdx = 0; newIdx < nRays; newIdx++) {
|
|
84
|
+
const oldIdx = rayOrder[newIdx]!;
|
|
85
|
+
sortedGateData.set(
|
|
86
|
+
frame.gateData.subarray(oldIdx * bytesPerRay, (oldIdx + 1) * bytesPerRay),
|
|
87
|
+
newIdx * bytesPerRay,
|
|
88
|
+
);
|
|
89
|
+
sortedBoundaries[newIdx] = frame.rayBoundariesDeg[oldIdx]!;
|
|
90
|
+
}
|
|
91
|
+
sortedBoundaries[nRays] =
|
|
92
|
+
frame.rayBoundariesDeg[rayOrder[nRays - 1]!]! +
|
|
93
|
+
(frame.rayBoundariesDeg[rayOrder[1]!]! - frame.rayBoundariesDeg[rayOrder[0]!]!);
|
|
94
|
+
|
|
95
|
+
return { ...frame, gateData: sortedGateData, rayBoundariesDeg: sortedBoundaries };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export type GpuReadoutFrameOptions = {
|
|
99
|
+
geometryLayoutKey?: string | null;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Match {@link MapboxRadarLayer} `uploadFrame` gate/ray ordering for CPU readout.
|
|
104
|
+
*/
|
|
105
|
+
export function prepareRadarFrameForGpuReadout(
|
|
106
|
+
frame: DecodedRadarFrame,
|
|
107
|
+
options?: GpuReadoutFrameOptions,
|
|
108
|
+
): DecodedRadarFrame {
|
|
109
|
+
const hasLayoutKey = options?.geometryLayoutKey != null && options.geometryLayoutKey !== '';
|
|
110
|
+
return hasLayoutKey ? canonicalBinsRadarFrame(frame) : sortRadarFrameByAzimuth(frame);
|
|
111
|
+
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default GOES brightness-temperature colormaps for WebGL satellite, aligned with
|
|
3
|
-
* aguacero-frontend `src/lib/defaultColormaps.ts` (`SatelliteLongwaveIR` and `SatelliteWV`, K/°C units).
|
|
4
|
-
*
|
|
5
|
-
* Format: flat array `[norm0, '#hex', norm1, '#hex', ...]` where each **norm** is 0–100
|
|
6
|
-
* (cold → hot in texture space; see `SatelliteShaderManager._generateTextureFromColormapData` and
|
|
7
|
-
* frontend `normToKelvin` / `kelvinToNorm` in `utilityFunctions.ts`).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/** Longwave IR (C13–C16-style) — matches `SatelliteLongwaveIR.units.K.colormap` in the frontend. */
|
|
11
|
-
export const DEFAULT_SATELLITE_LONGWAVE_IR_COLORMAP = [
|
|
12
|
-
5, '#000000',
|
|
13
|
-
51, '#ffffff',
|
|
14
|
-
52, '#00ffff',
|
|
15
|
-
58, '#0033cc',
|
|
16
|
-
64, '#33ff00',
|
|
17
|
-
73, '#ffee00',
|
|
18
|
-
78, '#ff0000',
|
|
19
|
-
82, '#660000',
|
|
20
|
-
88, '#808080',
|
|
21
|
-
90, '#cc66ff',
|
|
22
|
-
96, '#9933cc',
|
|
23
|
-
100, '#9933cc',
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
/** Upper / mid / lower water vapor (C08–C10) — matches `SatelliteWV.units.K.colormap` in the frontend. */
|
|
27
|
-
export const DEFAULT_SATELLITE_WATER_VAPOR_COLORMAP = [
|
|
28
|
-
10, '#cece55',
|
|
29
|
-
20, '#ce5555',
|
|
30
|
-
30, '#262626',
|
|
31
|
-
45, '#ffffff',
|
|
32
|
-
55, '#55cece',
|
|
33
|
-
70, '#5555ce',
|
|
34
|
-
80, '#4d3366',
|
|
35
|
-
90, '#e673e6',
|
|
36
|
-
100, '#efe6eb',
|
|
37
|
-
];
|
|
1
|
+
/**
|
|
2
|
+
* Default GOES brightness-temperature colormaps for WebGL satellite, aligned with
|
|
3
|
+
* aguacero-frontend `src/lib/defaultColormaps.ts` (`SatelliteLongwaveIR` and `SatelliteWV`, K/°C units).
|
|
4
|
+
*
|
|
5
|
+
* Format: flat array `[norm0, '#hex', norm1, '#hex', ...]` where each **norm** is 0–100
|
|
6
|
+
* (cold → hot in texture space; see `SatelliteShaderManager._generateTextureFromColormapData` and
|
|
7
|
+
* frontend `normToKelvin` / `kelvinToNorm` in `utilityFunctions.ts`).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Longwave IR (C13–C16-style) — matches `SatelliteLongwaveIR.units.K.colormap` in the frontend. */
|
|
11
|
+
export const DEFAULT_SATELLITE_LONGWAVE_IR_COLORMAP = [
|
|
12
|
+
5, '#000000',
|
|
13
|
+
51, '#ffffff',
|
|
14
|
+
52, '#00ffff',
|
|
15
|
+
58, '#0033cc',
|
|
16
|
+
64, '#33ff00',
|
|
17
|
+
73, '#ffee00',
|
|
18
|
+
78, '#ff0000',
|
|
19
|
+
82, '#660000',
|
|
20
|
+
88, '#808080',
|
|
21
|
+
90, '#cc66ff',
|
|
22
|
+
96, '#9933cc',
|
|
23
|
+
100, '#9933cc',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/** Upper / mid / lower water vapor (C08–C10) — matches `SatelliteWV.units.K.colormap` in the frontend. */
|
|
27
|
+
export const DEFAULT_SATELLITE_WATER_VAPOR_COLORMAP = [
|
|
28
|
+
10, '#cece55',
|
|
29
|
+
20, '#ce5555',
|
|
30
|
+
30, '#262626',
|
|
31
|
+
45, '#ffffff',
|
|
32
|
+
55, '#55cece',
|
|
33
|
+
70, '#5555ce',
|
|
34
|
+
80, '#4d3366',
|
|
35
|
+
90, '#e673e6',
|
|
36
|
+
100, '#efe6eb',
|
|
37
|
+
];
|