@aguacerowx/react-native 0.0.20 → 0.0.22

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.
Files changed (195) hide show
  1. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +42 -5
  2. package/android/src/main/res/raw/fragment_shader.glsl +18 -8
  3. package/ios/FragmentUniforms.swift +2 -0
  4. package/ios/GridRenderLayer.swift +24 -4
  5. package/ios/GridRenderLayerManager.mm +12 -0
  6. package/ios/GridRenderLayerView.h +1 -7
  7. package/ios/GridRenderLayerView.m +7 -1
  8. package/ios/Shaders.metal +131 -71
  9. package/ios/compiled-shaders/Shaders-device.metallib +0 -0
  10. package/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  11. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +42 -5
  12. package/lib/commonjs/android/src/main/res/raw/fragment_shader.glsl +18 -8
  13. package/lib/commonjs/ios/FragmentUniforms.swift +2 -0
  14. package/lib/commonjs/ios/GridRenderLayer.swift +24 -4
  15. package/lib/commonjs/ios/GridRenderLayerManager.mm +12 -0
  16. package/lib/commonjs/ios/GridRenderLayerView.h +1 -7
  17. package/lib/commonjs/ios/GridRenderLayerView.m +7 -1
  18. package/lib/commonjs/ios/Shaders.metal +131 -71
  19. package/lib/commonjs/ios/compiled-shaders/Shaders-device.metallib +0 -0
  20. package/lib/commonjs/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  21. package/lib/commonjs/package.json +3 -3
  22. package/lib/commonjs/scripts/compile-shaders.js +62 -0
  23. package/lib/commonjs/scripts/compile-shaders.js.map +1 -0
  24. package/lib/commonjs/scripts/compile-shaders.sh +12 -0
  25. package/lib/commonjs/src/WeatherLayerManager.js +51 -17
  26. package/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  27. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +42 -5
  28. package/lib/module/android/src/main/res/raw/fragment_shader.glsl +18 -8
  29. package/lib/module/ios/FragmentUniforms.swift +2 -0
  30. package/lib/module/ios/GridRenderLayer.swift +24 -4
  31. package/lib/module/ios/GridRenderLayerManager.mm +12 -0
  32. package/lib/module/ios/GridRenderLayerView.h +1 -7
  33. package/lib/module/ios/GridRenderLayerView.m +7 -1
  34. package/lib/module/ios/Shaders.metal +131 -71
  35. package/lib/module/ios/compiled-shaders/Shaders-device.metallib +0 -0
  36. package/lib/module/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  37. package/lib/module/lib/commonjs/package.json +3 -3
  38. package/lib/module/lib/commonjs/scripts/compile-shaders.js +62 -0
  39. package/lib/module/lib/commonjs/scripts/compile-shaders.js.map +1 -0
  40. package/lib/module/lib/commonjs/src/WeatherLayerManager.js +51 -17
  41. package/lib/module/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  42. package/lib/module/package.json +3 -3
  43. package/lib/module/scripts/compile-shaders.js +60 -0
  44. package/lib/module/scripts/compile-shaders.js.map +1 -0
  45. package/lib/module/scripts/compile-shaders.sh +12 -0
  46. package/lib/module/src/WeatherLayerManager.js +51 -17
  47. package/lib/module/src/WeatherLayerManager.js.map +1 -1
  48. package/lib/typescript/scripts/compile-shaders.d.ts +3 -0
  49. package/lib/typescript/scripts/compile-shaders.d.ts.map +1 -0
  50. package/lib/typescript/src/WeatherLayerManager.d.ts.map +1 -1
  51. package/package.json +3 -3
  52. package/src/WeatherLayerManager.js +192 -151
  53. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/AguaceroCore.js +0 -1063
  54. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/AguaceroCore.js.map +0 -1
  55. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/coordinate_configs.js +0 -381
  56. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/coordinate_configs.js.map +0 -1
  57. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/default-colormaps.js +0 -1256
  58. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/default-colormaps.js.map +0 -1
  59. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/dictionaries.js +0 -4041
  60. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/dictionaries.js.map +0 -1
  61. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/events.js +0 -38
  62. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/events.js.map +0 -1
  63. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/fill-layer-worker.js +0 -30
  64. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/fill-layer-worker.js.map +0 -1
  65. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/getBundleId.js +0 -27
  66. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/getBundleId.js.map +0 -1
  67. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/index.js +0 -41
  68. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/index.js.map +0 -1
  69. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/map-styles.js +0 -301
  70. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/map-styles.js.map +0 -1
  71. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/unitConversions.js +0 -126
  72. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/unitConversions.js.map +0 -1
  73. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/package.json +0 -48
  74. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/AguaceroCore.js +0 -1055
  75. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/AguaceroCore.js.map +0 -1
  76. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/coordinate_configs.js +0 -381
  77. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/coordinate_configs.js.map +0 -1
  78. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/default-colormaps.js +0 -1256
  79. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/default-colormaps.js.map +0 -1
  80. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/dictionaries.js +0 -4041
  81. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/dictionaries.js.map +0 -1
  82. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/events.js +0 -38
  83. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/events.js.map +0 -1
  84. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/fill-layer-worker.js +0 -30
  85. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/fill-layer-worker.js.map +0 -1
  86. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/getBundleId.js +0 -27
  87. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/getBundleId.js.map +0 -1
  88. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/index.js +0 -41
  89. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/index.js.map +0 -1
  90. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/map-styles.js +0 -301
  91. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/map-styles.js.map +0 -1
  92. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/unitConversions.js +0 -126
  93. package/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/unitConversions.js.map +0 -1
  94. package/lib/module/lib/commonjs/android/build.gradle +0 -108
  95. package/lib/module/lib/commonjs/android/src/main/AndroidManifest.xml +0 -7
  96. package/lib/module/lib/commonjs/ios/FragmentUniforms.swift +0 -14
  97. package/lib/module/lib/commonjs/ios/GridRenderLayer.swift +0 -983
  98. package/lib/module/lib/commonjs/ios/GridRenderLayerBridge.swift +0 -30
  99. package/lib/module/lib/commonjs/ios/GridRenderLayerManager.mm +0 -146
  100. package/lib/module/lib/commonjs/ios/GridRenderLayerView.h +0 -23
  101. package/lib/module/lib/commonjs/ios/GridRenderLayerView.m +0 -199
  102. package/lib/module/lib/commonjs/ios/InspectorDataCache.swift +0 -66
  103. package/lib/module/lib/commonjs/ios/InspectorModule.m +0 -10
  104. package/lib/module/lib/commonjs/ios/InspectorModule.swift +0 -64
  105. package/lib/module/lib/commonjs/ios/Shaders.metal +0 -131
  106. package/lib/module/lib/commonjs/ios/WeatherFrameProcessorModule.m +0 -16
  107. package/lib/module/lib/commonjs/ios/WeatherFrameProcessorModule.swift +0 -104
  108. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-device.metallib +0 -0
  109. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  110. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders.metallib +0 -0
  111. package/lib/module/lib/commonjs/ios/generated/AguaceroWxReactNativeSpec-generated.mm +0 -0
  112. package/lib/module/lib/commonjs/ios/generated/AguaceroWxReactNativeSpec.h +0 -0
  113. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/AguaceroCore.js +0 -1063
  114. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/AguaceroCore.js.map +0 -1
  115. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/coordinate_configs.js +0 -381
  116. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/coordinate_configs.js.map +0 -1
  117. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/default-colormaps.js +0 -1256
  118. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/default-colormaps.js.map +0 -1
  119. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/dictionaries.js +0 -4041
  120. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/dictionaries.js.map +0 -1
  121. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/events.js +0 -38
  122. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/events.js.map +0 -1
  123. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/fill-layer-worker.js +0 -30
  124. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/fill-layer-worker.js.map +0 -1
  125. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/getBundleId.js +0 -27
  126. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/getBundleId.js.map +0 -1
  127. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/index.js +0 -41
  128. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/index.js.map +0 -1
  129. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/map-styles.js +0 -301
  130. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/map-styles.js.map +0 -1
  131. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/unitConversions.js +0 -126
  132. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/dist/unitConversions.js.map +0 -1
  133. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/package.json +0 -48
  134. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/AguaceroCore.js +0 -1059
  135. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/AguaceroCore.js.map +0 -1
  136. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/coordinate_configs.js +0 -381
  137. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/coordinate_configs.js.map +0 -1
  138. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/default-colormaps.js +0 -1256
  139. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/default-colormaps.js.map +0 -1
  140. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/dictionaries.js +0 -4041
  141. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/dictionaries.js.map +0 -1
  142. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/events.js +0 -38
  143. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/events.js.map +0 -1
  144. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/fill-layer-worker.js +0 -30
  145. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/fill-layer-worker.js.map +0 -1
  146. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/getBundleId.js +0 -27
  147. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/getBundleId.js.map +0 -1
  148. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/index.js +0 -41
  149. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/index.js.map +0 -1
  150. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/map-styles.js +0 -301
  151. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/map-styles.js.map +0 -1
  152. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/unitConversions.js +0 -126
  153. package/lib/module/lib/commonjs/node_modules/@aguacerowx/javascript-sdk/src/unitConversions.js.map +0 -1
  154. package/lib/module/lib/commonjs/scripts/compile-shaders.sh +0 -27
  155. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/AguaceroCore.js +0 -1063
  156. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/AguaceroCore.js.map +0 -1
  157. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/coordinate_configs.js +0 -381
  158. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/coordinate_configs.js.map +0 -1
  159. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/default-colormaps.js +0 -1256
  160. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/default-colormaps.js.map +0 -1
  161. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/dictionaries.js +0 -4041
  162. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/dictionaries.js.map +0 -1
  163. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/events.js +0 -38
  164. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/events.js.map +0 -1
  165. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/fill-layer-worker.js +0 -30
  166. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/fill-layer-worker.js.map +0 -1
  167. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/getBundleId.js +0 -27
  168. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/getBundleId.js.map +0 -1
  169. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/index.js +0 -41
  170. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/index.js.map +0 -1
  171. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/map-styles.js +0 -301
  172. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/map-styles.js.map +0 -1
  173. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/unitConversions.js +0 -126
  174. package/lib/module/node_modules/@aguacerowx/javascript-sdk/dist/unitConversions.js.map +0 -1
  175. package/lib/module/node_modules/@aguacerowx/javascript-sdk/package.json +0 -48
  176. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/AguaceroCore.js +0 -1047
  177. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/AguaceroCore.js.map +0 -1
  178. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/coordinate_configs.js +0 -375
  179. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/coordinate_configs.js.map +0 -1
  180. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/default-colormaps.js +0 -1250
  181. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/default-colormaps.js.map +0 -1
  182. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/dictionaries.js +0 -4035
  183. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/dictionaries.js.map +0 -1
  184. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/events.js +0 -31
  185. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/events.js.map +0 -1
  186. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/fill-layer-worker.js +0 -29
  187. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/fill-layer-worker.js.map +0 -1
  188. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/getBundleId.js +0 -21
  189. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/getBundleId.js.map +0 -1
  190. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/index.js +0 -12
  191. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/index.js.map +0 -1
  192. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/map-styles.js +0 -295
  193. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/map-styles.js.map +0 -1
  194. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/unitConversions.js +0 -119
  195. package/lib/module/node_modules/@aguacerowx/javascript-sdk/src/unitConversions.js.map +0 -1
@@ -1,1047 +0,0 @@
1
- // AguaceroCore.js - The Headless "Engine"
2
-
3
- // --- Non-UI Imports ---
4
- import { EventEmitter } from './events.js';
5
- import { COORDINATE_CONFIGS } from './coordinate_configs.js';
6
- import { getUnitConversionFunction } from './unitConversions.js';
7
- import { DICTIONARIES, MODEL_CONFIGS } from './dictionaries.js';
8
- import { DEFAULT_COLORMAPS } from './default-colormaps.js';
9
- import proj4 from 'proj4';
10
- import { getBundleId } from './getBundleId';
11
-
12
- // --- Non-UI Helper Functions ---
13
- function hrdpsObliqueTransform(rotated_lon, rotated_lat) {
14
- const o_lat_p = 53.91148;
15
- const o_lon_p = 245.305142;
16
- const DEG_TO_RAD = Math.PI / 180.0;
17
- const RAD_TO_DEG = 180.0 / Math.PI;
18
- const o_lat_p_rad = o_lat_p * DEG_TO_RAD;
19
- const rot_lon_rad = rotated_lon * DEG_TO_RAD;
20
- const rot_lat_rad = rotated_lat * DEG_TO_RAD;
21
- const sin_rot_lat = Math.sin(rot_lat_rad);
22
- const cos_rot_lat = Math.cos(rot_lat_rad);
23
- const sin_rot_lon = Math.sin(rot_lon_rad);
24
- const cos_rot_lon = Math.cos(rot_lon_rad);
25
- const sin_o_lat_p = Math.sin(o_lat_p_rad);
26
- const cos_o_lat_p = Math.cos(o_lat_p_rad);
27
- const sin_lat = cos_o_lat_p * sin_rot_lat + sin_o_lat_p * cos_rot_lat * cos_rot_lon;
28
- let lat = Math.asin(sin_lat) * RAD_TO_DEG;
29
- const sin_lon_num = cos_rot_lat * sin_rot_lon;
30
- const sin_lon_den = -sin_o_lat_p * sin_rot_lat + cos_o_lat_p * cos_rot_lat * cos_rot_lon;
31
- let lon = Math.atan2(sin_lon_num, sin_lon_den) * RAD_TO_DEG + o_lon_p;
32
- if (lon > 180) lon -= 360;else if (lon < -180) lon += 360;
33
- return [lon, lat];
34
- }
35
- function findLatestModelRun(modelsData, modelName) {
36
- const model = modelsData?.[modelName];
37
- if (!model) return null;
38
- const availableDates = Object.keys(model).sort((a, b) => b.localeCompare(a));
39
- for (const date of availableDates) {
40
- const runs = model[date];
41
- if (!runs) continue;
42
- const availableRuns = Object.keys(runs).sort((a, b) => b.localeCompare(a));
43
- if (availableRuns.length > 0) return {
44
- date: date,
45
- run: availableRuns[0]
46
- };
47
- }
48
- return null;
49
- }
50
- export class AguaceroCore extends EventEmitter {
51
- constructor(options = {}) {
52
- super();
53
- this.isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
54
- this.apiKey = options.apiKey;
55
- this.bundleId = getBundleId();
56
- this.baseGridUrl = 'https://d3dc62msmxkrd7.cloudfront.net';
57
- if (!this.isReactNative) {
58
- this.worker = this.createWorker();
59
- this.workerRequestId = 0;
60
- this.workerResolvers = new Map();
61
- this.worker.addEventListener('message', this._handleWorkerMessage.bind(this));
62
- this.resultQueue = [];
63
- this.isProcessingQueue = false;
64
- } else {
65
- this.worker = null;
66
- }
67
- this.statusUrl = 'https://d3dc62msmxkrd7.cloudfront.net/model-status';
68
- this.modelStatus = null;
69
- this.mrmsStatus = null;
70
- this.dataCache = new Map();
71
- this.abortControllers = new Map();
72
- this.isPlaying = false;
73
- this.playIntervalId = null;
74
- this.playbackSpeed = options.playbackSpeed || 500;
75
- this.customColormaps = options.customColormaps || {};
76
- const userLayerOptions = options.layerOptions || {};
77
- const initialVariable = userLayerOptions.variable || null;
78
- this.state = {
79
- model: userLayerOptions.model || 'gfs',
80
- isMRMS: false,
81
- mrmsTimestamp: null,
82
- variable: initialVariable,
83
- date: null,
84
- run: null,
85
- forecastHour: 0,
86
- visible: true,
87
- opacity: userLayerOptions.opacity ?? 1,
88
- units: options.initialUnit || 'imperial',
89
- shaderSmoothingEnabled: options.shaderSmoothingEnabled ?? true
90
- };
91
- this.autoRefreshEnabled = options.autoRefresh ?? false;
92
- this.autoRefreshIntervalSeconds = options.autoRefreshInterval ?? 60;
93
- this.autoRefreshIntervalId = null;
94
- }
95
- async setState(newState) {
96
- Object.assign(this.state, newState);
97
- this._emitStateChange();
98
- }
99
- _emitStateChange() {
100
- const {
101
- colormap,
102
- baseUnit
103
- } = this._getColormapForVariable(this.state.variable);
104
- const toUnit = this._getTargetUnit(baseUnit, this.state.units);
105
- const displayColormap = this._convertColormapUnits(colormap, baseUnit, toUnit);
106
- let availableTimestamps = [];
107
- if (this.state.isMRMS && this.state.variable && this.mrmsStatus) {
108
- const timestamps = this.mrmsStatus[this.state.variable] || [];
109
- availableTimestamps = [...timestamps].reverse();
110
- }
111
- const eventPayload = {
112
- ...this.state,
113
- availableModels: this.modelStatus ? Object.keys(this.modelStatus).sort() : [],
114
- availableRuns: this.modelStatus?.[this.state.model] || {},
115
- availableHours: this.state.isMRMS ? [] : this.modelStatus?.[this.state.model]?.[this.state.date]?.[this.state.run] || [],
116
- availableVariables: this.getAvailableVariables(this.state.isMRMS ? 'mrms' : this.state.model),
117
- // We need to confirm this line is working as expected.
118
- availableMRMSVariables: this.getAvailableVariables('mrms'),
119
- availableTimestamps: availableTimestamps,
120
- isPlaying: this.isPlaying,
121
- colormap: displayColormap,
122
- colormapBaseUnit: toUnit
123
- };
124
- this.emit('state:change', eventPayload);
125
- }
126
- async initialize(options = {}) {
127
- await this.fetchModelStatus(true);
128
- await this.fetchMRMSStatus(true);
129
- const latestRun = findLatestModelRun(this.modelStatus, this.state.model);
130
- let initialState = this.state;
131
- if (latestRun && !this.state.isMRMS) {
132
- initialState = {
133
- ...this.state,
134
- ...latestRun,
135
- forecastHour: 0
136
- };
137
- const availableVariables = this.getAvailableVariables(initialState.model);
138
- if (availableVariables && availableVariables.length > 0) {
139
- initialState.variable = availableVariables[0];
140
- }
141
- }
142
- await this.setState(initialState);
143
- if (options.autoRefresh ?? this.autoRefreshEnabled) {
144
- this.startAutoRefresh(options.refreshInterval ?? this.autoRefreshIntervalSeconds);
145
- }
146
- }
147
- destroy() {
148
- this.pause();
149
- this.stopAutoRefresh();
150
- this.dataCache.clear();
151
- if (this.worker) {
152
- this.worker.terminate();
153
- }
154
- this.callbacks = {};
155
- console.log(`AguaceroCore has been destroyed.`);
156
- }
157
-
158
- // --- Public API Methods ---
159
-
160
- play() {
161
- if (this.isPlaying) return;
162
- this.isPlaying = true;
163
- clearInterval(this.playIntervalId);
164
- this.playIntervalId = setInterval(() => {
165
- this.step(1);
166
- }, this.playbackSpeed);
167
- this.emit('playback:start', {
168
- speed: this.playbackSpeed
169
- });
170
- this._emitStateChange(); // Notify UI that isPlaying is now true
171
- }
172
- pause() {
173
- if (!this.isPlaying) return;
174
- this.isPlaying = false;
175
- clearInterval(this.playIntervalId);
176
- this.playIntervalId = null;
177
- this.emit('playback:stop');
178
- this._emitStateChange(); // Notify UI that isPlaying is now false
179
- }
180
- togglePlay() {
181
- this.isPlaying ? this.pause() : this.play();
182
- }
183
- step(direction = 1) {
184
- // --- THIS IS THE CORRECTED MRMS LOGIC ---
185
- if (this.state.isMRMS) {
186
- const {
187
- variable,
188
- mrmsTimestamp
189
- } = this.state;
190
- if (!this.mrmsStatus || !this.mrmsStatus[variable]) {
191
- console.warn('[Core.step] MRMS status or variable not available.');
192
- return;
193
- }
194
-
195
- // CRITICAL FIX: The UI and state emissions use a REVERSED array (newest first).
196
- // The step logic MUST use the same reversed array for indexes to match.
197
- const availableTimestamps = [...(this.mrmsStatus[variable] || [])].reverse();
198
- if (availableTimestamps.length === 0) return;
199
- const currentIndex = availableTimestamps.indexOf(mrmsTimestamp);
200
- if (currentIndex === -1) {
201
- // If not found, reset to the first (newest) frame
202
- this.setState({
203
- mrmsTimestamp: availableTimestamps[0]
204
- });
205
- return;
206
- }
207
- const maxIndex = availableTimestamps.length - 1;
208
- let nextIndex = currentIndex + direction;
209
-
210
- // Loop animation
211
- if (nextIndex > maxIndex) nextIndex = 0;
212
- if (nextIndex < 0) nextIndex = maxIndex;
213
- const newTimestamp = availableTimestamps[nextIndex];
214
- this.setState({
215
- mrmsTimestamp: newTimestamp
216
- });
217
- } else {
218
- const {
219
- model,
220
- date,
221
- run,
222
- forecastHour
223
- } = this.state;
224
- const forecastHours = this.modelStatus?.[model]?.[date]?.[run];
225
- if (!forecastHours || forecastHours.length === 0) return;
226
- const currentIndex = forecastHours.indexOf(forecastHour);
227
- if (currentIndex === -1) return;
228
- const maxIndex = forecastHours.length - 1;
229
- let nextIndex = currentIndex + direction;
230
- if (nextIndex > maxIndex) nextIndex = 0;
231
- if (nextIndex < 0) nextIndex = maxIndex;
232
- const newHour = forecastHours[nextIndex];
233
- this.setState({
234
- forecastHour: newHour
235
- });
236
- }
237
- }
238
- setPlaybackSpeed(speed) {
239
- if (speed > 0) {
240
- this.playbackSpeed = speed;
241
- if (this.isPlaying) this.play();
242
- }
243
- }
244
- async setShaderSmoothing(enabled) {
245
- if (typeof enabled !== 'boolean' || enabled === this.state.shaderSmoothingEnabled) return;
246
- await this.setState({
247
- shaderSmoothingEnabled: enabled
248
- });
249
- }
250
- async setOpacity(newOpacity) {
251
- const clampedOpacity = Math.max(0, Math.min(1, newOpacity));
252
- if (clampedOpacity === this.state.opacity) return;
253
- await this.setState({
254
- opacity: clampedOpacity
255
- });
256
- }
257
- async setVariable(variable) {
258
- await this.setState({
259
- variable
260
- });
261
- }
262
- async setModel(modelName) {
263
- if (modelName === this.state.model || !this.modelStatus?.[modelName]) return;
264
- const latestRun = findLatestModelRun(this.modelStatus, modelName);
265
- if (latestRun) {
266
- await this.setState({
267
- model: modelName,
268
- date: latestRun.date,
269
- run: latestRun.run,
270
- forecastHour: 0
271
- });
272
- }
273
- }
274
- async setRun(runString) {
275
- const [date, run] = runString.split(':');
276
- if (date !== this.state.date || run !== this.state.run) {
277
- await this.setState({
278
- date,
279
- run,
280
- forecastHour: 0
281
- });
282
- }
283
- }
284
- async setUnits(newUnits) {
285
- if (newUnits === this.state.units || !['metric', 'imperial'].includes(newUnits)) return;
286
- await this.setState({
287
- units: newUnits
288
- });
289
- }
290
- async setMRMSVariable(variable) {
291
- const sortedTimestamps = [...(this.mrmsStatus[variable] || [])].sort((a, b) => b - a);
292
- const initialTimestamp = sortedTimestamps.length > 0 ? sortedTimestamps[0] : null;
293
- await this.setState({
294
- variable,
295
- isMRMS: true,
296
- mrmsTimestamp: initialTimestamp
297
- });
298
- }
299
- async setMRMSTimestamp(timestamp) {
300
- if (!this.state.isMRMS) return;
301
- await this.setState({
302
- mrmsTimestamp: timestamp
303
- });
304
- }
305
- async switchMode(options) {
306
- const {
307
- mode,
308
- variable,
309
- model,
310
- forecastHour,
311
- mrmsTimestamp
312
- } = options;
313
- if (!mode || !variable) {
314
- console.error("switchMode requires 'mode' ('mrms' | 'model') and 'variable' properties.");
315
- return;
316
- }
317
- if (mode === 'model' && !model) {
318
- console.error("switchMode with mode 'model' requires a 'model' property.");
319
- return;
320
- }
321
- let targetState = {};
322
- if (mode === 'mrms') {
323
- let finalTimestamp = mrmsTimestamp;
324
- if (finalTimestamp === undefined) {
325
- const sortedTimestamps = [...(this.mrmsStatus[variable] || [])].sort((a, b) => b - a);
326
- finalTimestamp = sortedTimestamps.length > 0 ? sortedTimestamps[0] : null;
327
- }
328
- targetState = {
329
- isMRMS: true,
330
- variable: variable,
331
- mrmsTimestamp: finalTimestamp,
332
- model: this.state.model,
333
- date: null,
334
- run: null,
335
- forecastHour: 0
336
- };
337
- } else if (mode === 'model') {
338
- const latestRun = findLatestModelRun(this.modelStatus, model);
339
- if (!latestRun) {
340
- console.error(`Could not find a valid run for model: ${model}`);
341
- return;
342
- }
343
- targetState = {
344
- isMRMS: false,
345
- model: model,
346
- variable: variable,
347
- date: latestRun.date,
348
- run: latestRun.run,
349
- forecastHour: forecastHour !== undefined ? forecastHour : 0,
350
- mrmsTimestamp: null
351
- };
352
- } else {
353
- console.error(`Invalid mode specified in switchMode: '${mode}'`);
354
- return;
355
- }
356
- await this.setState(targetState);
357
- }
358
-
359
- // --- Data and Calculation Methods ---
360
-
361
- _reconstructData(decompressedDeltas, encoding) {
362
- const expectedLength = encoding.length;
363
- const reconstructedData = new Int8Array(expectedLength);
364
- if (decompressedDeltas.length > 0 && expectedLength > 0) {
365
- // First value is absolute
366
- reconstructedData[0] = decompressedDeltas[0] > 127 ? decompressedDeltas[0] - 256 : decompressedDeltas[0];
367
-
368
- // Subsequent values are deltas from the previous one
369
- for (let i = 1; i < expectedLength; i++) {
370
- const delta = decompressedDeltas[i] > 127 ? decompressedDeltas[i] - 256 : decompressedDeltas[i];
371
- reconstructedData[i] = reconstructedData[i - 1] + delta;
372
- }
373
- }
374
- // Return as a Uint8Array, which is what the rest of the code expects
375
- return new Uint8Array(reconstructedData.buffer);
376
- }
377
- async _loadGridData(state) {
378
- if (this.isReactNative) {
379
- console.warn(`[AguaceroCore] _loadGridData was called in React Native. This is a bypass. Data loading is handled natively.`);
380
- return null;
381
- }
382
- const {
383
- model,
384
- date,
385
- run,
386
- forecastHour,
387
- variable,
388
- isMRMS,
389
- mrmsTimestamp
390
- } = state;
391
- let effectiveSmoothing = 0;
392
- const customVariableSettings = this.customColormaps[variable];
393
- if (customVariableSettings && typeof customVariableSettings.smoothing === 'number') {
394
- effectiveSmoothing = customVariableSettings.smoothing;
395
- }
396
- let resourcePath;
397
- let dataUrlIdentifier;
398
- if (isMRMS) {
399
- if (!mrmsTimestamp) return null;
400
- const mrmsDate = new Date(mrmsTimestamp * 1000);
401
- const y = mrmsDate.getUTCFullYear(),
402
- m = (mrmsDate.getUTCMonth() + 1).toString().padStart(2, '0'),
403
- d = mrmsDate.getUTCDate().toString().padStart(2, '0');
404
- dataUrlIdentifier = `mrms-${mrmsTimestamp}-${variable}-${effectiveSmoothing}`;
405
- resourcePath = `/grids/mrms/${y}${m}${d}/${mrmsTimestamp}/0/${variable}/${effectiveSmoothing}`;
406
- } else {
407
- dataUrlIdentifier = `${model}-${date}-${run}-${forecastHour}-${variable}-${effectiveSmoothing}`;
408
- resourcePath = `/grids/${model}/${date}/${run}/${forecastHour}/${variable}/${effectiveSmoothing}`;
409
- }
410
- if (this.dataCache.has(dataUrlIdentifier)) {
411
- return this.dataCache.get(dataUrlIdentifier);
412
- }
413
-
414
- // --- EDITED ---
415
- // If we are in React Native, this function should NOT do any work.
416
- // The native WeatherFrameProcessorModule is now responsible for all data loading.
417
- // This function might still be called by a "cache miss" fallback, but it
418
- // should not fetch data from JS anymore. We return null so the fallback knows
419
- // that the native module is the only source of truth for new data.
420
- if (this.isReactNative) {
421
- console.warn(`_loadGridData was called in React Native for ${dataUrlIdentifier}. This should be handled by the native module. Returning null.`);
422
- return null;
423
- }
424
- const abortController = new AbortController();
425
- this.abortControllers.set(dataUrlIdentifier, abortController);
426
- const loadPromise = (async () => {
427
- if (!this.apiKey) {
428
- throw new Error('API key is not configured.');
429
- }
430
- try {
431
- const baseUrl = `${this.baseGridUrl}${resourcePath}`;
432
- const urlWithApiKeyParam = `${baseUrl}?apiKey=${this.apiKey}`;
433
- const headers = {
434
- 'x-api-key': this.apiKey
435
- };
436
- if (this.bundleId && this.isReactNative) {
437
- headers['x-app-identifier'] = this.bundleId;
438
- }
439
- const response = await fetch(urlWithApiKeyParam, {
440
- headers: headers,
441
- signal: abortController.signal
442
- });
443
- if (!response.ok) {
444
- throw new Error(`Failed to fetch grid data: ${response.status} ${response.statusText}`);
445
- }
446
- const {
447
- data: b64Data,
448
- encoding
449
- } = await response.json();
450
- const compressedData = Uint8Array.from(atob(b64Data), c => c.charCodeAt(0));
451
-
452
- // This path is now ONLY for the web worker
453
- const requestId = this.workerRequestId++;
454
- const workerPromise = new Promise((resolve, reject) => {
455
- this.workerResolvers.set(requestId, {
456
- resolve,
457
- reject
458
- });
459
- });
460
- this.worker.postMessage({
461
- requestId,
462
- compressedData,
463
- encoding
464
- }, [compressedData.buffer]);
465
- const result = await workerPromise;
466
- const finalData = result.data;
467
- const transformedData = new Uint8Array(finalData.length);
468
- for (let i = 0; i < finalData.length; i++) {
469
- const signedValue = finalData[i] > 127 ? finalData[i] - 256 : finalData[i];
470
- transformedData[i] = signedValue + 128;
471
- }
472
- this.abortControllers.delete(dataUrlIdentifier);
473
- return {
474
- data: transformedData,
475
- encoding
476
- };
477
- } catch (error) {
478
- if (error.name === 'AbortError') {
479
- console.log(`Request cancelled for ${resourcePath}`);
480
- } else {
481
- console.error(`Failed to load data for path ${resourcePath}:`, error);
482
- }
483
- this.dataCache.delete(dataUrlIdentifier);
484
- this.abortControllers.delete(dataUrlIdentifier);
485
- return null;
486
- }
487
- })();
488
- this.dataCache.set(dataUrlIdentifier, loadPromise);
489
- return loadPromise;
490
- }
491
- cancelAllRequests() {
492
- // Abort all in-flight requests
493
- this.abortControllers.forEach((controller, key) => {
494
- controller.abort();
495
- });
496
-
497
- // Clear both maps
498
- this.abortControllers.clear();
499
- this.dataCache.clear();
500
- console.log('All pending requests cancelled');
501
- }
502
- async getValueAtLngLat(lng, lat) {
503
- const {
504
- variable,
505
- isMRMS,
506
- mrmsTimestamp,
507
- model,
508
- date,
509
- run,
510
- forecastHour,
511
- units
512
- } = this.state;
513
- if (!variable) return null;
514
- const gridIndices = this._getGridIndexFromLngLat(lng, lat);
515
- if (!gridIndices) return null;
516
- const {
517
- i,
518
- j
519
- } = gridIndices;
520
- const gridModel = isMRMS ? 'mrms' : model;
521
- const normalizedGridModel = this._normalizeModelName(gridModel);
522
- const {
523
- nx
524
- } = COORDINATE_CONFIGS[normalizedGridModel].grid_params;
525
- const customSettings = this.customColormaps[variable];
526
- const effectiveSmoothing = customSettings && typeof customSettings.smoothing === 'number' ? customSettings.smoothing : 0;
527
- const dataUrlIdentifier = isMRMS ? `mrms-${mrmsTimestamp}-${variable}-${effectiveSmoothing}` : `${model}-${date}-${run}-${forecastHour}-${variable}-${effectiveSmoothing}`;
528
- const gridDataPromise = this.dataCache.get(dataUrlIdentifier);
529
- if (!gridDataPromise) return null;
530
- try {
531
- const gridData = await gridDataPromise;
532
- if (!gridData || !gridData.data) return null;
533
- const index1D = j * nx + i;
534
- const byteValue = gridData.data[index1D];
535
- const signedQuantizedValue = byteValue - 128;
536
-
537
- // --- START OF FIX ---
538
- // You were missing 'scale_type' in this destructuring assignment.
539
- const {
540
- scale,
541
- offset,
542
- missing_quantized,
543
- scale_type
544
- } = gridData.encoding;
545
- // --- END OF FIX ---
546
-
547
- if (signedQuantizedValue === missing_quantized) return null;
548
- const intermediateValue = signedQuantizedValue * scale + offset;
549
-
550
- // Step 2: Apply non-linear scaling if specified
551
- let nativeValue = intermediateValue;
552
- if (scale_type === 'sqrt') {
553
- // Square the value while preserving its sign
554
- nativeValue = intermediateValue < 0 ? -(intermediateValue * intermediateValue) : intermediateValue * intermediateValue;
555
- }
556
- const {
557
- colormap,
558
- baseUnit
559
- } = this._getColormapForVariable(variable);
560
-
561
- // If the value is outside the colormap's bounds, return null.
562
- if (colormap && colormap.length >= 2) {
563
- const minBound = colormap[0];
564
- const maxBound = colormap[colormap.length - 2];
565
- if (nativeValue < minBound || nativeValue > maxBound) {
566
- return null;
567
- }
568
- }
569
- let dataNativeUnit = baseUnit || (DICTIONARIES.fld[variable] || {}).defaultUnit || 'none';
570
- const displayUnit = this._getTargetUnit(dataNativeUnit, units);
571
- const conversionFunc = getUnitConversionFunction(dataNativeUnit, displayUnit);
572
- let displayValue = conversionFunc ? conversionFunc(nativeValue) : nativeValue;
573
-
574
- // --- START: ADDED CODE ---
575
-
576
- // Create a variable to hold the precipitation type, if any.
577
- let precipType = null;
578
-
579
- // Check if the current variable is one of the special ptype variables.
580
- if (variable === 'ptypeRefl' || variable === 'ptypeRate') {
581
- const value = nativeValue; // Use the raw, unconverted value for ptype logic
582
-
583
- if (value >= 100 && value < 200) {
584
- displayValue -= 100;
585
- precipType = 'Snow';
586
- } else if (value >= 200 && value < 300) {
587
- displayValue -= 200;
588
- precipType = 'Frzg Rain'; // Abbreviated for tooltips
589
- } else if (value >= 300 && value < 400) {
590
- displayValue -= 300;
591
- precipType = 'Ice Pellets';
592
- } else {
593
- precipType = 'Rain';
594
- }
595
- }
596
-
597
- // Return the final payload, now including the precipType.
598
- return {
599
- lngLat: {
600
- lng,
601
- lat
602
- },
603
- variable: {
604
- code: variable,
605
- name: this.getVariableDisplayName(variable)
606
- },
607
- value: displayValue,
608
- unit: displayUnit,
609
- precipType: precipType // NEW: Add this to the return object
610
- };
611
- } catch (error) {
612
- return null;
613
- }
614
- }
615
- getAvailableVariables(modelName = null) {
616
- const model = modelName || this.state.model;
617
- return MODEL_CONFIGS[model]?.vars || [];
618
- }
619
- getVariableDisplayName(variableCode) {
620
- const varInfo = DICTIONARIES.fld[variableCode];
621
- return varInfo?.displayName || varInfo?.name || variableCode;
622
- }
623
- _getColormapForVariable(variable) {
624
- if (!variable) return {
625
- colormap: [],
626
- baseUnit: ''
627
- };
628
- if (this.customColormaps[variable] && this.customColormaps[variable].colormap) {
629
- return {
630
- colormap: this.customColormaps[variable].colormap,
631
- baseUnit: this.customColormaps[variable].baseUnit || ''
632
- };
633
- }
634
- const colormapKey = DICTIONARIES.variable_cmap[variable] || variable;
635
- const customColormap = this.customColormaps[colormapKey];
636
- if (customColormap && customColormap.colormap) {
637
- return {
638
- colormap: customColormap.colormap,
639
- baseUnit: customColormap.baseUnit || ''
640
- };
641
- }
642
- const defaultColormapData = DEFAULT_COLORMAPS[colormapKey];
643
- if (defaultColormapData && defaultColormapData.units) {
644
- // ✅ Get defaultUnit from the field dictionary
645
- const fieldInfo = DICTIONARIES.fld[variable] || {};
646
- const baseUnit = fieldInfo.defaultUnit || Object.keys(defaultColormapData.units)[0];
647
- const unitData = defaultColormapData.units[baseUnit];
648
- if (unitData && unitData.colormap) {
649
- return {
650
- colormap: unitData.colormap,
651
- baseUnit: baseUnit
652
- };
653
- }
654
- }
655
- return {
656
- colormap: [],
657
- baseUnit: ''
658
- };
659
- }
660
- _convertColormapUnits(colormap, fromUnits, toUnits) {
661
- if (fromUnits === toUnits) return colormap;
662
- const conversionFunc = getUnitConversionFunction(fromUnits, toUnits);
663
- if (!conversionFunc) return colormap;
664
- const newColormap = [];
665
- for (let i = 0; i < colormap.length; i += 2) {
666
- newColormap.push(conversionFunc(colormap[i]), colormap[i + 1]);
667
- }
668
- return newColormap;
669
- }
670
- _normalizeModelName(modelName) {
671
- const mapping = {
672
- 'hrrr': ['mpashn', 'mpasrt', 'mpasht', 'hrrrsub', 'rrfs', 'namnest', 'mpasrn', 'mpasrn3', 'mpasht2'],
673
- 'arw': ['arw2', 'fv3', 'href'],
674
- 'rtma': ['nbm'],
675
- 'ecmwf': ['ecmwfaifs'],
676
- 'gfs': ['arpege', 'graphcastgfs']
677
- };
678
- for (const [normalized, aliases] of Object.entries(mapping)) {
679
- if (aliases.includes(modelName)) return normalized;
680
- }
681
- return modelName;
682
- }
683
- _getGridCornersAndDef(model) {
684
- const normalizedModel = this._normalizeModelName(model);
685
- const gridDef = {
686
- ...COORDINATE_CONFIGS[normalizedModel],
687
- modelName: model
688
- };
689
- if (!gridDef) return null;
690
- const {
691
- nx,
692
- ny
693
- } = gridDef.grid_params;
694
- const gridType = gridDef.type;
695
- let corners;
696
- if (gridType === 'latlon') {
697
- let {
698
- lon_first,
699
- lat_first,
700
- lat_last,
701
- lon_last,
702
- dx_degrees,
703
- dy_degrees
704
- } = gridDef.grid_params;
705
- corners = {
706
- lon_tl: lon_first,
707
- lat_tl: lat_first,
708
- lon_tr: lon_last !== undefined ? lon_last : lon_first + (nx - 1) * dx_degrees,
709
- lat_tr: lat_first,
710
- lon_bl: lon_first,
711
- lat_bl: lat_last !== undefined ? lat_last : lat_first + (ny - 1) * dy_degrees,
712
- lon_br: lon_last !== undefined ? lon_last : lon_first + (nx - 1) * dx_degrees,
713
- lat_br: lat_last !== undefined ? lat_last : lat_first + (ny - 1) * dy_degrees
714
- };
715
- } else if (gridType === 'rotated_latlon') {
716
- const [lon_tl, lat_tl] = hrdpsObliqueTransform(gridDef.grid_params.lon_first, gridDef.grid_params.lat_first);
717
- const [lon_tr, lat_tr] = hrdpsObliqueTransform(gridDef.grid_params.lon_first + (nx - 1) * gridDef.grid_params.dx_degrees, gridDef.grid_params.lat_first);
718
- const [lon_bl, lat_bl] = hrdpsObliqueTransform(gridDef.grid_params.lon_first, gridDef.grid_params.lat_first + (ny - 1) * gridDef.grid_params.dy_degrees);
719
- const [lon_br, lat_br] = hrdpsObliqueTransform(gridDef.grid_params.lon_first + (nx - 1) * gridDef.grid_params.dx_degrees, gridDef.grid_params.lat_first + (ny - 1) * gridDef.grid_params.dy_degrees);
720
- corners = {
721
- lon_tl,
722
- lat_tl,
723
- lon_tr,
724
- lat_tr,
725
- lon_bl,
726
- lat_bl,
727
- lon_br,
728
- lat_br
729
- };
730
- } else if (gridType === 'lambert_conformal_conic' || gridType === 'polar_ stereographic') {
731
- let projString = Object.entries(gridDef.proj_params).map(([k, v]) => `+${k}=${v}`).join(' ');
732
- if (gridType === 'polar_stereographic') projString += ' +lat_0=90';
733
- const {
734
- x_origin,
735
- y_origin,
736
- dx,
737
- dy
738
- } = gridDef.grid_params;
739
- const [lon_tl, lat_tl] = proj4(projString, 'EPSG:4326', [x_origin, y_origin]);
740
- const [lon_tr, lat_tr] = proj4(projString, 'EPSG:4326', [x_origin + (nx - 1) * dx, y_origin]);
741
- const [lon_bl, lat_bl] = proj4(projString, 'EPSG:4326', [x_origin, y_origin + (ny - 1) * dy]);
742
- const [lon_br, lat_br] = proj4(projString, 'EPSG:4326', [x_origin + (nx - 1) * dx, y_origin + (ny - 1) * dy]);
743
- corners = {
744
- lon_tl,
745
- lat_tl,
746
- lon_tr,
747
- lat_tr,
748
- lon_bl,
749
- lat_bl,
750
- lon_br,
751
- lat_br
752
- };
753
- } else {
754
- return null;
755
- }
756
- return {
757
- corners,
758
- gridDef
759
- };
760
- }
761
- _getTargetUnit(defaultUnit, system) {
762
- if (system === 'metric') {
763
- if (['°F', '°C', 'fahrenheit', 'celsius'].includes(defaultUnit)) return '°C';
764
- if (['kts', 'mph', 'm/s'].includes(defaultUnit)) return 'km/h';
765
- if (['in', 'mm', 'cm'].includes(defaultUnit)) return 'mm';
766
- }
767
- if (system === 'imperial') {
768
- if (['°F', '°C', 'fahrenheit', 'celsius'].includes(defaultUnit)) return '°F';
769
- if (['kts', 'mph', 'm/s'].includes(defaultUnit)) return 'mph';
770
- if (['in', 'mm', 'cm'].includes(defaultUnit)) return 'in';
771
- }
772
- return defaultUnit;
773
- }
774
- _getGridIndexFromLngLat(lng, lat) {
775
- const gridModel = this.state.isMRMS ? 'mrms' : this.state.model;
776
- const normalizedGridModel = this._normalizeModelName(gridModel);
777
- const gridDef = COORDINATE_CONFIGS[normalizedGridModel];
778
- if (!gridDef) return null;
779
- const {
780
- nx,
781
- ny
782
- } = gridDef.grid_params;
783
- const pixelCoords = this.latLonToGridPixel(lat, lng, gridDef, gridModel);
784
- if (!pixelCoords || !isFinite(pixelCoords.x) || !isFinite(pixelCoords.y) || pixelCoords.x < 0 || pixelCoords.y < 0) return null;
785
- const i = Math.round(pixelCoords.x);
786
- const j = Math.round(pixelCoords.y);
787
- if (i >= 0 && i < nx && j >= 0 && j < ny) return {
788
- i,
789
- j
790
- };
791
- return null;
792
- }
793
- latLonToProjected(lat, lon, gridDef) {
794
- if (!isFinite(lat) || !isFinite(lon)) throw new Error(`Invalid coordinates: lat=${lat}, lon=${lon}`);
795
- const gridType = gridDef.type;
796
- if (gridType === 'latlon') return {
797
- x: lon,
798
- y: lat
799
- };
800
- let projString = Object.entries(gridDef.proj_params).map(([k, v]) => `+${k}=${v}`).join(' ');
801
- if (gridType === 'polar_stereographic') projString += ' +lat_0=90';
802
- const projected = proj4('EPSG:4326', projString, [lon, lat]);
803
- return {
804
- x: projected[0],
805
- y: projected[1]
806
- };
807
- }
808
- latLonToGridPixel(lat, lon, gridDef, modelName) {
809
- if (!gridDef) return null;
810
- if (modelName === 'rgem' && gridDef.type === 'polar_stereographic') return this.latLonToGridPixelPolarStereographic(lat, lon, gridDef);
811
- const projected = this.latLonToProjected(lat, lon, gridDef);
812
- let x, y;
813
- const gridOrigin = {
814
- x: gridDef.grid_params.lon_first,
815
- y: gridDef.grid_params.lat_first
816
- };
817
- const gridPixelSize = {
818
- x: gridDef.grid_params.dx_degrees,
819
- y: gridDef.grid_params.dy_degrees
820
- };
821
- if (gridDef.type === 'latlon' || gridDef.type === 'rotated_latlon') {
822
- let adjustedLon = projected.x;
823
- if (modelName === 'mrms') {
824
- if (adjustedLon < 0) adjustedLon += 360;
825
- x = (adjustedLon - gridOrigin.x) / gridPixelSize.x;
826
- y = (gridOrigin.y - projected.y) / gridPixelSize.y;
827
- } else {
828
- const isGFSType = gridDef.grid_params && gridDef.grid_params.lon_first === 0.0 && Math.abs(gridDef.grid_params.lat_first) === 90.0;
829
- const isECMWFType = gridDef.grid_params && gridDef.grid_params.lon_first === 180.0 && gridDef.grid_params.lat_first === 90.0;
830
- const isGEMType = modelName === 'gem' || gridDef.grid_params.lon_first === 180.0 && gridDef.grid_params.lat_first === -90.0 && gridDef.grid_params.lon_last === 179.85;
831
- if (isGEMType) {
832
- while (adjustedLon < gridOrigin.x) adjustedLon += 360;
833
- x = (adjustedLon - gridOrigin.x) / gridPixelSize.x;
834
- y = (projected.y - gridOrigin.y) / gridPixelSize.y;
835
- return {
836
- x,
837
- y
838
- };
839
- }
840
- let isFlippedGrid = isECMWFType ? true : gridDef.grid_params.lat_first < (gridDef.grid_params.lat_last || (gridDef.grid_params.ny - 1) * gridDef.grid_params.dy_degrees);
841
- if (isGFSType) adjustedLon = projected.x + 180;else if (isECMWFType) {
842
- if (adjustedLon < gridOrigin.x) adjustedLon += 360;
843
- } else if (['arome1', 'arome25', 'arpegeeu', 'iconeu', 'icond2'].includes(modelName)) {
844
- while (adjustedLon < 0) adjustedLon += 360;
845
- while (adjustedLon >= 360) adjustedLon -= 360;
846
- x = adjustedLon >= gridOrigin.x ? (adjustedLon - gridOrigin.x) / gridPixelSize.x : (adjustedLon + 360 - gridOrigin.x) / gridPixelSize.x;
847
- if (['arome1', 'arome25', 'arpegeeu'].includes(modelName)) y = (gridOrigin.y - projected.y) / Math.abs(gridPixelSize.y);else if (['iconeu', 'icond2'].includes(modelName)) y = (projected.y - gridOrigin.y) / gridPixelSize.y;
848
- return {
849
- x,
850
- y
851
- };
852
- } else {
853
- const lonFirst = gridOrigin.x;
854
- if (lonFirst > 180 && adjustedLon < 0) adjustedLon += 360;else if (lonFirst < 0 && adjustedLon > 180) adjustedLon -= 360;
855
- }
856
- x = (adjustedLon - gridOrigin.x) / gridPixelSize.x;
857
- if (isFlippedGrid) {
858
- if (isECMWFType) y = (gridOrigin.y - projected.y) / Math.abs(gridPixelSize.y);else {
859
- const maxLat = gridDef.grid_params.lat_last || (gridDef.grid_params.ny - 1) * gridDef.grid_params.dy_degrees;
860
- y = (maxLat - projected.y) / Math.abs(gridPixelSize.y);
861
- }
862
- } else y = (projected.y - gridOrigin.y) / gridPixelSize.y;
863
- }
864
- } else {
865
- const projOrigin = {
866
- x: gridDef.grid_params.x_origin,
867
- y: gridDef.grid_params.y_origin
868
- };
869
- const projPixelSize = {
870
- x: gridDef.grid_params.dx,
871
- y: gridDef.grid_params.dy
872
- };
873
- x = (projected.x - projOrigin.x) / projPixelSize.x;
874
- y = (projOrigin.y - projected.y) / Math.abs(projPixelSize.y);
875
- }
876
- return {
877
- x,
878
- y
879
- };
880
- }
881
- latLonToGridPixelPolarStereographic(lat, lon, gridDef) {
882
- try {
883
- const projParams = gridDef.proj_params;
884
- let projectionString = `+proj=${projParams.proj}`;
885
- Object.keys(projParams).forEach(key => {
886
- if (key !== 'proj') projectionString += ` +${key}=${projParams[key]}`;
887
- });
888
- projectionString += ' +lat_0=90 +no_defs';
889
- const {
890
- nx,
891
- ny,
892
- dx,
893
- dy,
894
- x_origin,
895
- y_origin
896
- } = gridDef.grid_params;
897
- const x_min = x_origin;
898
- const x_max = x_origin + (nx - 1) * dx;
899
- const y_max = y_origin;
900
- const y_min = y_origin + (ny - 1) * dy;
901
- const [proj_x, proj_y] = proj4('EPSG:4326', projectionString, [lon, lat]);
902
- if (!isFinite(proj_x) || !isFinite(proj_y)) return {
903
- x: -1,
904
- y: -1
905
- };
906
- const t_x = (proj_x - x_min) / (x_max - x_min);
907
- const t_y = (proj_y - y_max) / (y_min - y_max);
908
- const x = t_x * (nx - 1);
909
- const y = t_y * (ny - 1);
910
- return {
911
- x,
912
- y
913
- };
914
- } catch (error) {
915
- console.warn(`[GridAccessor] RGEM polar stereographic conversion failed for ${lat}, ${lon}:`, error);
916
- return {
917
- x: -1,
918
- y: -1
919
- };
920
- }
921
- }
922
-
923
- // --- Worker and Status Methods ---
924
-
925
- createWorker() {
926
- if (this.isReactNative) return null;
927
- const workerCode = `
928
- import { decompress } from 'https://cdn.skypack.dev/fzstd@0.1.1';
929
-
930
- function _reconstructData(decompressedDeltas, encoding) {
931
- const expectedLength = encoding.length;
932
- const reconstructedData = new Int8Array(expectedLength);
933
- if (decompressedDeltas.length > 0 && expectedLength > 0) {
934
- reconstructedData[0] = decompressedDeltas[0] > 127 ? decompressedDeltas[0] - 256 : decompressedDeltas[0];
935
- for (let i = 1; i < expectedLength; i++) {
936
- const delta = decompressedDeltas[i] > 127 ? decompressedDeltas[i] - 256 : decompressedDeltas[i];
937
- reconstructedData[i] = reconstructedData[i - 1] + delta;
938
- }
939
- }
940
- return new Uint8Array(reconstructedData.buffer);
941
- }
942
-
943
- self.onmessage = async (e) => {
944
- const { requestId, compressedData, encoding } = e.data;
945
- try {
946
- const decompressedDeltas = await decompress(compressedData);
947
- const finalData = _reconstructData(decompressedDeltas, encoding);
948
- self.postMessage({ success: true, requestId: requestId, decompressedData: finalData, encoding: encoding }, [finalData.buffer]);
949
- } catch (error) {
950
- self.postMessage({ success: false, requestId: requestId, error: error.message });
951
- }
952
- };
953
- `;
954
- const blob = new Blob([workerCode], {
955
- type: 'application/javascript'
956
- });
957
- return new Worker(URL.createObjectURL(blob), {
958
- type: 'module'
959
- });
960
- }
961
- _processResultQueue() {
962
- while (this.resultQueue.length > 0) {
963
- const {
964
- success,
965
- requestId,
966
- decompressedData,
967
- encoding,
968
- error
969
- } = this.resultQueue.shift();
970
- if (this.workerResolvers.has(requestId)) {
971
- const {
972
- resolve,
973
- reject
974
- } = this.workerResolvers.get(requestId);
975
- if (success) {
976
- resolve({
977
- data: decompressedData
978
- }); // Return as { data: ... }
979
- } else {
980
- reject(new Error(error));
981
- }
982
- this.workerResolvers.delete(requestId);
983
- }
984
- }
985
- this.isProcessingQueue = false;
986
- }
987
- _handleWorkerMessage(e) {
988
- if (this.isReactNative) return;
989
- const {
990
- success,
991
- requestId,
992
- decompressedData,
993
- encoding,
994
- error
995
- } = e.data;
996
- this.resultQueue.push({
997
- success,
998
- requestId,
999
- decompressedData,
1000
- encoding,
1001
- error
1002
- });
1003
- if (!this.isProcessingQueue) {
1004
- this.isProcessingQueue = true;
1005
- requestAnimationFrame(() => this._processResultQueue());
1006
- }
1007
- }
1008
- async fetchModelStatus(force = false) {
1009
- if (!this.modelStatus || force) {
1010
- try {
1011
- const response = await fetch(this.statusUrl);
1012
- if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
1013
- this.modelStatus = (await response.json()).models;
1014
- } catch (error) {
1015
- this.modelStatus = null;
1016
- }
1017
- }
1018
- return this.modelStatus;
1019
- }
1020
- async fetchMRMSStatus(force = false) {
1021
- const mrmsStatusUrl = 'https://h3dfvh5pq6euq36ymlpz4zqiha0obqju.lambda-url.us-east-2.on.aws';
1022
- if (!this.mrmsStatus || force) {
1023
- try {
1024
- const response = await fetch(mrmsStatusUrl);
1025
- if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
1026
- this.mrmsStatus = await response.json();
1027
- } catch (error) {
1028
- this.mrmsStatus = null;
1029
- }
1030
- }
1031
- return this.mrmsStatus;
1032
- }
1033
- startAutoRefresh(intervalSeconds) {
1034
- this.stopAutoRefresh();
1035
- this.autoRefreshIntervalId = setInterval(async () => {
1036
- await this.fetchModelStatus(true);
1037
- this._emitStateChange();
1038
- }, (intervalSeconds || 60) * 1000);
1039
- }
1040
- stopAutoRefresh() {
1041
- if (this.autoRefreshIntervalId) {
1042
- clearInterval(this.autoRefreshIntervalId);
1043
- this.autoRefreshIntervalId = null;
1044
- }
1045
- }
1046
- }
1047
- //# sourceMappingURL=AguaceroCore.js.map