@aguacerowx/react-native 0.0.21 → 0.0.23

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 (100) hide show
  1. package/aguacerowx-react-native.podspec +5 -20
  2. package/android/build/.transforms/42e9b8fa82d77a1c205db5bf0d0ed519/transformed/classes/classes_dex/classes.dex +0 -0
  3. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.dex +0 -0
  4. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayer.dex +0 -0
  5. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  6. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  7. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  8. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  9. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  10. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +18 -8
  11. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  12. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  13. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  14. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  15. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  16. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  17. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +8 -1
  18. package/android/src/main/res/raw/fragment_shader.glsl +18 -8
  19. package/ios/FragmentUniforms.swift +1 -0
  20. package/ios/GridRenderLayer.swift +117 -109
  21. package/ios/GridRenderLayerBridge.swift +11 -3
  22. package/ios/GridRenderLayerView.h +15 -1
  23. package/ios/GridRenderLayerView.m +65 -28
  24. package/ios/Shaders.metal +25 -13
  25. package/ios/compiled-shaders/Shaders-device.metallib +0 -0
  26. package/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  27. package/lib/commonjs/aguacerowx-react-native.podspec +5 -20
  28. package/lib/commonjs/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  29. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  30. package/lib/commonjs/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  31. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  32. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  33. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +18 -8
  34. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  35. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  36. package/lib/commonjs/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  37. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  38. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  39. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  40. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +8 -1
  41. package/lib/commonjs/android/src/main/res/raw/fragment_shader.glsl +18 -8
  42. package/lib/commonjs/ios/FragmentUniforms.swift +1 -0
  43. package/lib/commonjs/ios/GridRenderLayer.swift +117 -109
  44. package/lib/commonjs/ios/GridRenderLayerBridge.swift +11 -3
  45. package/lib/commonjs/ios/GridRenderLayerView.h +15 -1
  46. package/lib/commonjs/ios/GridRenderLayerView.m +65 -28
  47. package/lib/commonjs/ios/Shaders.metal +25 -13
  48. package/lib/commonjs/ios/compiled-shaders/Shaders-device.metallib +0 -0
  49. package/lib/commonjs/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  50. package/lib/commonjs/package.json +2 -2
  51. package/lib/commonjs/scripts/compile-shaders.js.map +1 -1
  52. package/lib/commonjs/src/WeatherLayerManager.js +50 -5
  53. package/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  54. package/lib/module/aguacerowx-react-native.podspec +5 -20
  55. package/lib/module/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  56. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  57. package/lib/module/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  58. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  59. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  60. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +18 -8
  61. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  62. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  63. package/lib/module/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  64. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  65. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  66. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  67. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +8 -1
  68. package/lib/module/android/src/main/res/raw/fragment_shader.glsl +18 -8
  69. package/lib/module/ios/FragmentUniforms.swift +1 -0
  70. package/lib/module/ios/GridRenderLayer.swift +117 -109
  71. package/lib/module/ios/GridRenderLayerBridge.swift +11 -3
  72. package/lib/module/ios/GridRenderLayerView.h +15 -1
  73. package/lib/module/ios/GridRenderLayerView.m +65 -28
  74. package/lib/module/ios/Shaders.metal +25 -13
  75. package/lib/module/ios/compiled-shaders/Shaders-device.metallib +0 -0
  76. package/lib/module/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  77. package/lib/module/lib/commonjs/aguacerowx-react-native.podspec +5 -20
  78. package/lib/module/lib/commonjs/ios/FragmentUniforms.swift +1 -0
  79. package/lib/module/lib/commonjs/ios/GridRenderLayer.swift +117 -109
  80. package/lib/module/lib/commonjs/ios/GridRenderLayerBridge.swift +11 -3
  81. package/lib/module/lib/commonjs/ios/GridRenderLayerView.h +15 -1
  82. package/lib/module/lib/commonjs/ios/GridRenderLayerView.m +65 -28
  83. package/lib/module/lib/commonjs/ios/Shaders.metal +25 -13
  84. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-device.metallib +0 -0
  85. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  86. package/lib/module/lib/commonjs/package.json +2 -2
  87. package/lib/module/lib/commonjs/scripts/compile-shaders.js.map +1 -1
  88. package/lib/module/lib/commonjs/src/WeatherLayerManager.js +50 -5
  89. package/lib/module/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  90. package/lib/module/package.json +2 -2
  91. package/lib/module/scripts/compile-shaders.js.map +1 -1
  92. package/lib/module/src/WeatherLayerManager.js +50 -5
  93. package/lib/module/src/WeatherLayerManager.js.map +1 -1
  94. package/lib/typescript/src/WeatherLayerManager.d.ts.map +1 -1
  95. package/package.json +2 -2
  96. package/src/WeatherLayerManager.js +208 -165
  97. package/ios/compiled-shaders/Shaders.metallib +0 -0
  98. package/lib/commonjs/ios/compiled-shaders/Shaders.metallib +0 -0
  99. package/lib/module/ios/compiled-shaders/Shaders.metallib +0 -0
  100. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders.metallib +0 -0
@@ -61,7 +61,8 @@ public class GridRenderLayer: NSObject {
61
61
  textureSize: SIMD2<Float>(0.0, 0.0),
62
62
  smoothing: 1,
63
63
  scaleType: 0,
64
- isPtype: 0 // ADD THIS
64
+ isPtype: 0,
65
+ isMRMS: 0
65
66
  )
66
67
  private var isVisible = false
67
68
  private var pendingActiveFrameKey: String?
@@ -75,15 +76,13 @@ public class GridRenderLayer: NSObject {
75
76
  let nx: Float
76
77
  let ny: Float
77
78
  let filePath: String
78
- let originalScale: Float // ADD THIS
79
- let originalOffset: Float // ADD THIS
79
+ let originalScale: Float
80
+ let originalOffset: Float
80
81
  }
81
82
  private var frameCache: [String: FrameMetadata] = [:]
82
- private let highPriorityTextureQueue = DispatchQueue(label: "com.aguacero.texture-processing-high-priority", qos: .userInitiated)
83
+ private let frameProcessingQueue = DispatchQueue(label: "com.aguacero.frame-processing", qos: .userInitiated, attributes: .concurrent)
84
+ private let semaphore = DispatchSemaphore(value: 8)
83
85
 
84
- // The concurrent queue for background preloading all other frames.
85
- private let backgroundTextureQueue = DispatchQueue(label: "com.aguacero.texture-processing-background", qos: .utility, attributes: .concurrent)
86
- // MARK: - Initializer
87
86
  private struct VertexInfo {
88
87
  var mercX: Float
89
88
  var mercY: Float
@@ -125,6 +124,13 @@ public class GridRenderLayer: NSObject {
125
124
  // ADD THIS: Force the map to repaint to show the smoothing change immediately.
126
125
  NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
127
126
  }
127
+
128
+ @objc(setIsMRMSWithIsMRMS:)
129
+ public func setIsMRMS(isMRMS: Bool) {
130
+ self.uniforms.isMRMS = isMRMS ? 1 : 0
131
+ print("🟢 [GridRenderLayer] Set isMRMS: \(isMRMS)")
132
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
133
+ }
128
134
 
129
135
  // ADD THIS METHOD
130
136
  @objc(setVariableWithVariable:)
@@ -182,11 +188,10 @@ public class GridRenderLayer: NSObject {
182
188
  self.colormapTexture = texture
183
189
  }
184
190
 
185
- @objc(clearGpuCache) // Explicitly name the Obj-C selector
191
+ @objc(clearGpuCache)
186
192
  public func clearGpuCache() {
187
- backgroundTextureQueue.async {
188
- self.frameCache.removeAll()
189
- print("🟢 [GridRenderLayer] GPU frame cache cleared.")
193
+ frameProcessingQueue.async { [weak self] in
194
+ self?.frameCache.removeAll()
190
195
  }
191
196
  }
192
197
 
@@ -219,42 +224,39 @@ public class GridRenderLayer: NSObject {
219
224
  }
220
225
 
221
226
  private func updateInspectorCache(filePath: String, nx: Int, ny: Int, scale: Float, offset: Float, missing: Float, scaleType: Int) {
222
- highPriorityTextureQueue.async {
223
-
224
- guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else {
225
- print("❌ [Inspector] FATAL: Failed to read file data from path.")
226
- self.inspectorCache.clear()
227
- return
228
- }
229
- print("💡 [Inspector] 2. Successfully read \(fileData.count) bytes from file.")
230
-
231
- guard let decompressedDeltas = self.decompressZstd(data: fileData) else {
232
- print("❌ [Inspector] FATAL: Failed to decompress Zstd data.")
233
- self.inspectorCache.clear()
234
- return
235
- }
236
- print("💡 [Inspector] 3. Successfully decompressed data.")
237
-
238
- let reconstructedData = self.reconstructData(decompressedDeltas: decompressedDeltas)
239
- print("💡 [Inspector] 4. Reconstructed data with \(reconstructedData.count) bytes.")
240
-
241
- self.inspectorCache.update(
242
- data: reconstructedData,
243
- nx: nx,
244
- ny: ny,
245
- scale: scale,
246
- offset: offset,
247
- missing: missing,
248
- scaleType: scaleType
249
- )
250
-
251
- print("💡 [Inspector] 5. ✅ Cache updated successfully with scaleType=\(scaleType)")
227
+ // This is now called from frameProcessingQueue, so we can do the work synchronously
228
+ guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else {
229
+ print("❌ [Inspector] FATAL: Failed to read file data from path.")
230
+ self.inspectorCache.clear()
231
+ return
232
+ }
233
+ print("💡 [Inspector] 2. Successfully read \(fileData.count) bytes from file.")
234
+
235
+ guard let decompressedDeltas = self.decompressZstd(data: fileData) else {
236
+ print("❌ [Inspector] FATAL: Failed to decompress Zstd data.")
237
+ self.inspectorCache.clear()
238
+ return
252
239
  }
240
+ print("💡 [Inspector] 3. Successfully decompressed data.")
241
+
242
+ let reconstructedData = self.reconstructData(decompressedDeltas: decompressedDeltas)
243
+ print("💡 [Inspector] 4. Reconstructed data with \(reconstructedData.count) bytes.")
244
+
245
+ self.inspectorCache.update(
246
+ data: reconstructedData,
247
+ nx: nx,
248
+ ny: ny,
249
+ scale: scale,
250
+ offset: offset,
251
+ missing: missing,
252
+ scaleType: scaleType
253
+ )
254
+
255
+ print("💡 [Inspector] 5. ✅ Cache updated successfully with scaleType=\(scaleType)")
253
256
  }
254
257
 
255
258
  @objc(setActiveFrameWithCacheKey:)
256
259
  public func setActiveFrame(cacheKey: String) {
257
- // First, check if the frame is already in the cache.
258
260
  if let frame = frameCache[cacheKey] {
259
261
  print("⚡️ [GridRenderLayer] Cache HIT for key: \(cacheKey). Swapping texture.")
260
262
 
@@ -266,42 +268,51 @@ public class GridRenderLayer: NSObject {
266
268
  self.uniforms.scaleType = Int32(frame.scaleType)
267
269
 
268
270
  self.isVisible = true
269
- self.pendingActiveFrameKey = nil // Clear any pending key
271
+ self.pendingActiveFrameKey = nil
270
272
  NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
271
273
 
272
- // --- ADD THIS ---
273
- // Now that the frame is active, update the inspector cache with its data.
274
- self.updateInspectorCache(
275
- filePath: frame.filePath,
276
- nx: Int(frame.nx),
277
- ny: Int(frame.ny),
278
- scale: frame.scale,
279
- offset: frame.offset,
280
- missing: frame.missing,
281
- scaleType: frame.scaleType
282
- )
274
+ // Update inspector cache on background thread since we already have the frame data
275
+ frameProcessingQueue.async { [weak self] in
276
+ self?.updateInspectorCache(
277
+ filePath: frame.filePath,
278
+ nx: Int(frame.nx),
279
+ ny: Int(frame.ny),
280
+ scale: frame.scale,
281
+ offset: frame.offset,
282
+ missing: frame.missing,
283
+ scaleType: frame.scaleType
284
+ )
285
+ }
283
286
 
284
287
  } else {
285
- // --- FIX: If it's a miss, store the key and wait for it to be primed. ---
286
288
  print("⚠️ [GridRenderLayer] setActiveFrame cache MISS for key: \(cacheKey). Will apply when primed.")
287
289
  self.pendingActiveFrameKey = cacheKey
288
- self.isVisible = false // Hide the layer until the frame is ready
290
+ self.isVisible = false
289
291
  }
290
292
  }
291
-
292
293
  @objc(primeGpuCacheWithFrameInfo:)
293
294
  public func primeGpuCache(frameInfo: [String: [String: Any]]) {
294
295
  let group = DispatchGroup()
295
296
 
296
297
  if (frameInfo.count > 1) {
297
- print("🟡 [GridRenderLayer] Starting to prime \(frameInfo.count) textures concurrently...")
298
+ print("🟡 [GridRenderLayer] Starting to prime \(frameInfo.count) textures with concurrent processing...")
298
299
  }
299
300
 
300
301
  for (cacheKey, info) in frameInfo {
301
302
  group.enter()
302
303
 
303
- backgroundTextureQueue.async {
304
- defer { group.leave() }
304
+ frameProcessingQueue.async { [weak self] in
305
+ guard let self = self else {
306
+ group.leave()
307
+ return
308
+ }
309
+
310
+ self.semaphore.wait()
311
+ defer {
312
+ self.semaphore.signal()
313
+ group.leave()
314
+ }
315
+
305
316
  if self.frameCache[cacheKey] != nil { return }
306
317
 
307
318
  guard let filePath = info["filePath"] as? String,
@@ -311,16 +322,25 @@ public class GridRenderLayer: NSObject {
311
322
  let offset = info["offset"] as? NSNumber,
312
323
  let missing = info["missing"] as? NSNumber,
313
324
  let scaleTypeStr = info["scaleType"] as? String,
314
- let originalScale = info["originalScale"] as? NSNumber, // ADD THIS
315
- let originalOffset = info["originalOffset"] as? NSNumber, // ADD THIS
316
- let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
317
- let finalTextureBytes = self.processRawData(fileData: fileData)
325
+ let originalScale = info["originalScale"] as? NSNumber,
326
+ let originalOffset = info["originalOffset"] as? NSNumber
318
327
  else {
319
328
  print("❌ [GridRenderLayer] Skipping prime for \(cacheKey), missing data.")
320
329
  return
321
330
  }
322
331
 
323
- DispatchQueue.main.sync {
332
+ // Process data OFF the main thread
333
+ guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
334
+ let finalTextureBytes = self.processRawData(fileData: fileData)
335
+ else {
336
+ print("❌ [GridRenderLayer] Failed to process data for \(cacheKey)")
337
+ return
338
+ }
339
+
340
+ // Create texture on main thread
341
+ DispatchQueue.main.async { [weak self] in
342
+ guard let self = self else { return }
343
+
324
344
  if let texture = self.createTextureFromBytes(bytes: finalTextureBytes, nx: nx.intValue, ny: ny.intValue) {
325
345
  let metadata = FrameMetadata(
326
346
  texture: texture,
@@ -331,11 +351,10 @@ public class GridRenderLayer: NSObject {
331
351
  nx: nx.floatValue,
332
352
  ny: ny.floatValue,
333
353
  filePath: filePath,
334
- originalScale: originalScale.floatValue, // ADD THIS
335
- originalOffset: originalOffset.floatValue // ADD THIS
354
+ originalScale: originalScale.floatValue,
355
+ originalOffset: originalOffset.floatValue
336
356
  )
337
357
  self.frameCache[cacheKey] = metadata
338
- print(" ✅ [GridRenderLayer] Primed and cached frame for key: \(cacheKey)")
339
358
 
340
359
  if let pendingKey = self.pendingActiveFrameKey, pendingKey == cacheKey {
341
360
  print("👍 [GridRenderLayer] The pending frame is now ready. Activating it.")
@@ -348,7 +367,7 @@ public class GridRenderLayer: NSObject {
348
367
 
349
368
  group.notify(queue: .main) {
350
369
  if (frameInfo.count > 1) {
351
- print("🎉 [GridRenderLayer] All \(frameInfo.count) frames have been processed and cached to the GPU.")
370
+ print("🎉 [GridRenderLayer] All \(frameInfo.count) frames have been processed and cached.")
352
371
  }
353
372
  }
354
373
  }
@@ -356,19 +375,20 @@ public class GridRenderLayer: NSObject {
356
375
  @objc public func updateDataTexture(data: String, nx: NSNumber, ny: NSNumber, scale: NSNumber, offset: NSNumber, missing: NSNumber, scaleType: String) {
357
376
  print("🚀 [GridRenderLayer] FAST LANE: updateDataTexture called for initial frame...")
358
377
 
359
- let filePath = data // Assuming 'data' is always the file path for this method.
378
+ let filePath = data
360
379
 
361
- // USE THE HIGH-PRIORITY QUEUE
362
- highPriorityTextureQueue.async {
363
- guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else { return }
380
+ frameProcessingQueue.async { [weak self] in
381
+ guard let self = self else { return }
364
382
 
365
- guard let finalTextureBytes = self.processRawData(fileData: fileData) else {
383
+ guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
384
+ let finalTextureBytes = self.processRawData(fileData: fileData)
385
+ else {
366
386
  print("❌ [GridRenderLayer] FAST LANE: Failed to process initial frame data.")
367
387
  return
368
388
  }
369
389
 
370
- DispatchQueue.main.async {
371
- guard let texture = self.createTextureFromBytes(bytes: finalTextureBytes, nx: nx.intValue, ny: ny.intValue) else {
390
+ DispatchQueue.main.async { [weak self] in
391
+ guard let self = self, let texture = self.createTextureFromBytes(bytes: finalTextureBytes, nx: nx.intValue, ny: ny.intValue) else {
372
392
  return
373
393
  }
374
394
 
@@ -383,8 +403,6 @@ public class GridRenderLayer: NSObject {
383
403
  print("✅ [GridRenderLayer] FAST LANE: Initial frame processed and displayed.")
384
404
  NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
385
405
 
386
- // --- ADD THIS ---
387
- // Update the inspector cache for the initial frame.
388
406
  self.updateInspectorCache(
389
407
  filePath: filePath,
390
408
  nx: nx.intValue,
@@ -399,9 +417,6 @@ public class GridRenderLayer: NSObject {
399
417
  }
400
418
 
401
419
  @objc public func updateGeometry(corners: [String: Any], gridDef: [String: Any]) {
402
- print("🟢 [GridRenderLayer] updateGeometry called")
403
- print(" device: \(self.device != nil)")
404
-
405
420
  guard self.device != nil else {
406
421
  print("⚠️ [GridRenderLayer] Device not ready yet, storing geometry for later")
407
422
  pendingGeometryUpdate = (corners: corners, gridDef: gridDef)
@@ -423,8 +438,6 @@ public class GridRenderLayer: NSObject {
423
438
  return
424
439
  }
425
440
 
426
- print(" ✅ Generated \(vertices.count/4) vertices, \(indices.count/3) triangles")
427
-
428
441
  self.indexCount = indices.count
429
442
 
430
443
  DispatchQueue.main.async {
@@ -438,7 +451,6 @@ public class GridRenderLayer: NSObject {
438
451
  print(" indexBuffer: \(self.indexBuffer != nil)")
439
452
  print(" indexCount: \(self.indexCount)")
440
453
 
441
- // TRIGGER A REPAINT - ADD THIS:
442
454
  NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
443
455
  }
444
456
  }
@@ -610,11 +622,11 @@ public class GridRenderLayer: NSObject {
610
622
 
611
623
  private func lccToLonLat(i: Double, j: Double, gridDef: [String: Any]) -> (lon: Double, lat: Double)? {
612
624
  guard let projParams = gridDef["proj_params"] as? [String: Any],
613
- let lat_0 = projParams["lat_0"] as? Double, // latitude of origin
614
- let lon_0 = projParams["lon_0"] as? Double, // longitude of origin
615
- let lat_1 = projParams["lat_1"] as? Double, // first standard parallel
616
- let lat_2 = projParams["lat_2"] as? Double, // second standard parallel (HRRR uses two!)
617
- let r_earth = projParams["R"] as? Double else {
625
+ let lat_0 = (projParams["lat_0"] as? NSNumber)?.doubleValue,
626
+ let lon_0 = (projParams["lon_0"] as? NSNumber)?.doubleValue,
627
+ let lat_1 = (projParams["lat_1"] as? NSNumber)?.doubleValue,
628
+ let lat_2 = (projParams["lat_2"] as? NSNumber)?.doubleValue,
629
+ let r_earth = (projParams["R"] as? NSNumber)?.doubleValue else {
618
630
  print("❌ [LCC Geometry] Failed to extract LCC parameters.")
619
631
  return nil
620
632
  }
@@ -628,10 +640,9 @@ public class GridRenderLayer: NSObject {
628
640
  let lat0_rad = lat_0 * toRad
629
641
  let lon0_rad = lon_0 * toRad
630
642
 
631
- // Calculate cone constant (n) using two standard parallels
632
643
  let n: Double
633
644
  if abs(lat_1 - lat_2) < 1e-10 {
634
- n = sin(lat1_rad) // Single parallel case
645
+ n = sin(lat1_rad)
635
646
  } else {
636
647
  n = log(cos(lat1_rad) / cos(lat2_rad)) / log(tan(π/4.0 + lat2_rad/2.0) / tan(π/4.0 + lat1_rad/2.0))
637
648
  }
@@ -639,7 +650,6 @@ public class GridRenderLayer: NSObject {
639
650
  let F = cos(lat1_rad) * pow(tan(π/4.0 + lat1_rad/2.0), n) / n
640
651
  let rho_0 = r_earth * F * pow(tan(π/4.0 + lat0_rad/2.0), -n)
641
652
 
642
- // i, j are the x, y projection coordinates
643
653
  let x = i
644
654
  let y = j
645
655
 
@@ -665,11 +675,16 @@ public class GridRenderLayer: NSObject {
665
675
 
666
676
  private func generateGeometryData(gridDef: [String: Any], vertices: inout [Float], indices: inout [UInt16]) {
667
677
  guard let gridParams = gridDef["grid_params"] as? [String: Any] else {
678
+ print("❌ [generateGeometryData] No grid_params found")
668
679
  return
669
680
  }
670
681
 
671
- // GFS Global Grid Path
672
- if isGFSType(gridParams: gridParams) {
682
+ // Check grid type
683
+ let isGFS = isGFSType(gridParams: gridParams)
684
+ let isLCC = isLCCType(gridDef: gridDef)
685
+
686
+ if isGFS {
687
+ // GFS path remains unchanged
673
688
  let subdivisions = 120
674
689
  let verticesPerRow = (subdivisions * 3) + 1
675
690
  let TILE_SIZE: Double = 512.0
@@ -701,12 +716,16 @@ public class GridRenderLayer: NSObject {
701
716
  }
702
717
  return
703
718
  }
704
- if isLCCType(gridDef: gridDef) {
719
+
720
+ if isLCC {
721
+ print("🗺️ [generateGeometryData] Using LCC projection path")
705
722
  generateLCCGeometry(gridDef: gridDef, vertices: &vertices, indices: &indices)
706
723
  return
707
724
  }
708
725
 
709
- // Generic Grid Path (MRMS, etc.)
726
+ // Generic Grid Path (MRMS, regional models, etc.)
727
+ print("🗺️ [generateGeometryData] Using generic regional grid path")
728
+
710
729
  let nx = gridParams["nx"] as? Int ?? 0
711
730
  let ny = gridParams["ny"] as? Int ?? 0
712
731
  let lon_first = gridParams["lon_first"] as? Double ?? 0.0
@@ -715,6 +734,7 @@ public class GridRenderLayer: NSObject {
715
734
  let dy = gridParams["dy_degrees"] as? Double ?? 0.0
716
735
  let lon_last = gridParams["lon_last"] as? Double ?? (lon_first + Double(nx - 1) * dx)
717
736
  let lat_last = gridParams["lat_last"] as? Double ?? (lat_first + Double(ny - 1) * dy)
737
+
718
738
  let lat_span = lat_last - lat_first
719
739
  let isSouthToNorth = lat_span > 0
720
740
 
@@ -727,14 +747,12 @@ public class GridRenderLayer: NSObject {
727
747
  let verticesPerRow = subdivisions_x + 1
728
748
  let TILE_SIZE: Double = 512.0
729
749
 
730
- // 🔑 FIX: Only create ONE world copy for regional data, THREE for global data
731
- let worldCopies = (data_lon_range > 300) ? [-1, 0, 1] : [0] // Only wrap if nearly global
750
+ let worldCopies = (data_lon_range > 300) ? [-1, 0, 1] : [0]
732
751
 
733
752
  for world_copy in worldCopies {
734
753
  let vertexStartIndex = UInt16(vertices.count / 4)
735
754
  let lon_offset = Double(world_copy) * 360.0
736
755
 
737
- // Generate vertices for this world copy
738
756
  for row in 0...subdivisions_y {
739
757
  for col in 0...subdivisions_x {
740
758
  let v_interp = Float(row) / Float(subdivisions_y)
@@ -759,7 +777,6 @@ public class GridRenderLayer: NSObject {
759
777
  }
760
778
  }
761
779
 
762
- // Generate indices (same as before)
763
780
  for row in 0..<UInt16(subdivisions_y) {
764
781
  for col in 0..<UInt16(subdivisions_x) {
765
782
  let tl = vertexStartIndex + row * UInt16(verticesPerRow) + col
@@ -925,9 +942,6 @@ internal func internalRenderingWillStart(_ metalDevice: MTLDevice, colorPixelFor
925
942
  return
926
943
  }
927
944
 
928
- print("✅ [GridRenderLayer] Past guards, about to render!")
929
- print(" 🎨 About to draw \(indexCount) indices (\(indexCount/3) triangles)")
930
-
931
945
  let needsLinear = (uniforms.smoothing != 0)
932
946
  if isDataSamplerLinear != needsLinear {
933
947
  let samplerDesc = MTLSamplerDescriptor()
@@ -956,9 +970,6 @@ internal func internalRenderingWillStart(_ metalDevice: MTLDevice, colorPixelFor
956
970
  SIMD4<Float>(floatArray[12], floatArray[13], floatArray[14], floatArray[15])
957
971
  )
958
972
 
959
- print(" 📐 MVP matrix after scaling: \(mvp)")
960
- print(" 📍 Zoom: \(zoom), Scale factor: \(scale)")
961
-
962
973
  // Add depth state
963
974
  let depthStencilDescriptor = MTLDepthStencilDescriptor()
964
975
  depthStencilDescriptor.depthCompareFunction = .always
@@ -977,12 +988,9 @@ internal func internalRenderingWillStart(_ metalDevice: MTLDevice, colorPixelFor
977
988
  encoder.setFragmentSamplerState(dataSamplerState, index: 0)
978
989
  encoder.setFragmentSamplerState(colormapSamplerState, index: 1)
979
990
 
980
- print(" 🎨 Drawing indexed primitives now...")
981
991
  encoder.drawIndexedPrimitives(type: .triangle, indexCount: indexCount, indexType: .uint16, indexBuffer: indices, indexBufferOffset: 0)
982
- print(" ✅ Draw call completed")
983
992
 
984
993
  encoder.endEncoding()
985
- print(" ✅ Encoder ended")
986
994
  }
987
995
 
988
996
  internal func internalRenderingWillEnd() {
@@ -10,8 +10,6 @@ import Foundation
10
10
  belowLayerId: String?
11
11
  ) -> Bool {
12
12
  let position: LayerPosition? = belowLayerId.map { .below($0) }
13
-
14
- // Create a CustomLayer object
15
13
  var customLayer = CustomLayer(id: layerId, renderer: layerHost)
16
14
 
17
15
  do {
@@ -23,8 +21,18 @@ import Foundation
23
21
  return false
24
22
  }
25
23
  }
26
-
24
+
27
25
  @objc public static func triggerRepaint(on mapView: MapView) {
28
26
  mapView.mapboxMap.triggerRepaint()
29
27
  }
28
+
29
+ // ADD THIS NEW METHOD
30
+ @objc public static func layerExists(in mapView: MapView, layerId: String) -> Bool {
31
+ do {
32
+ _ = try mapView.mapboxMap.layer(withId: layerId)
33
+ return true
34
+ } catch {
35
+ return false
36
+ }
37
+ }
30
38
  }
@@ -1,17 +1,31 @@
1
1
  #import <UIKit/UIKit.h>
2
+ #import <React/RCTComponent.h>
3
+
2
4
  @class GridRenderLayer;
3
5
  @class MapView;
6
+
4
7
  NS_ASSUME_NONNULL_BEGIN
8
+
5
9
  @interface GridRenderLayerView : UIView
10
+
6
11
  @property (nonatomic, strong) GridRenderLayer *layerInstance;
7
12
  @property (nonatomic, weak) MapView *mapView;
8
13
  @property (nonatomic, strong) NSString *layerId;
9
14
  @property (nonatomic, strong, nullable) NSString *belowID;
15
+
10
16
  // Property setters for React Native
11
17
  - (void)setOpacity:(float)opacity;
12
18
  - (void)setDataRange:(NSArray *)dataRange;
13
19
  - (void)setSmoothing:(BOOL)smoothing;
14
20
  - (void)setBelowID:(NSString *)belowID;
15
- - (void)setVariable:(NSString *)variable; // ADD THIS LINE
21
+ - (void)setVariable:(NSString *)variable;
22
+
23
+ // ADD THESE METHOD DECLARATIONS
24
+ - (void)waitForStyleLoadAndAddLayer;
25
+ - (void)pollForLayerExistence;
26
+ - (void)findMapViewAndAddLayerInView:(UIView *)view;
27
+ - (void)addLayerToMap;
28
+
16
29
  @end
30
+
17
31
  NS_ASSUME_NONNULL_END
@@ -69,11 +69,28 @@
69
69
 
70
70
  - (void)didMoveToWindow {
71
71
  [super didMoveToWindow];
72
+ RCTLogInfo(@"🔵 [GridRenderLayerView] didMoveToWindow called, window=%@, isLayerAdded=%d", self.window ? @"YES" : @"NO", self.isLayerAdded);
72
73
  if (self.window && !self.isLayerAdded) {
74
+ [self findMapViewAndAddLayerInView:self.window];
75
+ }
76
+ }
77
+
78
+ - (void)layoutSubviews {
79
+ [super layoutSubviews];
80
+
81
+ static dispatch_once_t onceToken;
82
+ dispatch_once(&onceToken, ^{
83
+ RCTLogInfo(@"🔵 [GridRenderLayerView] layoutSubviews called (first time)");
73
84
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
74
- [self findMapViewAndAddLayerInView:self.window]; // Start from window, not superview
85
+ if (!self.isLayerAdded) {
86
+ RCTLogInfo(@"🔍 [GridRenderLayerView] Attempting to find map from layoutSubviews");
87
+ UIView *searchRoot = self.window ? self.window : self.superview;
88
+ if (searchRoot) {
89
+ [self findMapViewAndAddLayerInView:searchRoot];
90
+ }
91
+ }
75
92
  });
76
- }
93
+ });
77
94
  }
78
95
 
79
96
  - (void)findMapViewAndAddLayerInView:(UIView *)view {
@@ -81,13 +98,13 @@
81
98
  return;
82
99
  }
83
100
 
101
+ RCTLogInfo(@"🔍 [GridRenderLayerView] Searching for MapView from: %@", NSStringFromClass([view class]));
102
+
84
103
  NSString *className = NSStringFromClass([view class]);
85
104
 
86
- // Check if this is RNMBXMapView - the wrapper
87
105
  if ([className isEqualToString:@"RNMBXMapView"]) {
88
106
  RCTLogInfo(@"✅ [GridRenderLayerView] Found RNMBXMapView!");
89
107
 
90
- // The first subview should be MapboxMaps.MapView
91
108
  if (view.subviews.count > 0) {
92
109
  UIView *firstSubview = view.subviews[0];
93
110
  NSString *subviewClass = NSStringFromClass([firstSubview class]);
@@ -96,7 +113,7 @@
96
113
  if ([subviewClass containsString:@"MapboxMaps.MapView"] || [subviewClass isEqualToString:@"MapView"]) {
97
114
  RCTLogInfo(@"✅ [GridRenderLayerView] Found actual MapboxMaps.MapView!");
98
115
  self.mapView = (MapView *)firstSubview;
99
- [self addLayerToMap];
116
+ [self waitForStyleLoadAndAddLayer];
100
117
  return;
101
118
  }
102
119
  }
@@ -105,7 +122,6 @@
105
122
  return;
106
123
  }
107
124
 
108
- // Recursively search all subviews
109
125
  for (UIView *subview in view.subviews) {
110
126
  [self findMapViewAndAddLayerInView:subview];
111
127
  if (self.isLayerAdded) {
@@ -114,14 +130,42 @@
114
130
  }
115
131
  }
116
132
 
117
- - (void)logViewHierarchy:(UIView *)view depth:(int)depth {
118
- NSString *indent = [@"" stringByPaddingToLength:depth * 2 withString:@" " startingAtIndex:0];
119
- NSString *className = NSStringFromClass([view class]);
120
- RCTLogInfo(@"%@└─ %@", indent, className);
133
+ - (void)waitForStyleLoadAndAddLayer {
134
+ if (!self.mapView) {
135
+ return;
136
+ }
121
137
 
122
- for (UIView *subview in view.subviews) {
123
- [self logViewHierarchy:subview depth:depth + 1];
138
+ NSString *targetLayer = self.belowID ?: @"AML_-_terrain";
139
+
140
+ // Check if the target layer already exists
141
+ if ([GridRenderLayerBridge layerExistsIn:self.mapView layerId:targetLayer]) {
142
+ RCTLogInfo(@"✅ [GridRenderLayerView] Target layer '%@' already exists, adding immediately", targetLayer);
143
+ [self addLayerToMap];
144
+ return;
145
+ }
146
+
147
+ // If not, start polling
148
+ RCTLogInfo(@"⏳ [GridRenderLayerView] Waiting for layer '%@' to exist...", targetLayer);
149
+ [self pollForLayerExistence];
150
+ }
151
+
152
+ - (void)pollForLayerExistence {
153
+ if (self.isLayerAdded || !self.mapView) {
154
+ return;
155
+ }
156
+
157
+ NSString *targetLayer = self.belowID ?: @"AML_-_terrain";
158
+
159
+ if ([GridRenderLayerBridge layerExistsIn:self.mapView layerId:targetLayer]) {
160
+ RCTLogInfo(@"✅ [GridRenderLayerView] Target layer '%@' now exists!", targetLayer);
161
+ [self addLayerToMap];
162
+ return;
124
163
  }
164
+
165
+ // Try again in 100ms
166
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
167
+ [self pollForLayerExistence];
168
+ });
125
169
  }
126
170
 
127
171
  - (void)addLayerToMap {
@@ -138,20 +182,6 @@
138
182
  return;
139
183
  }
140
184
 
141
- // Get the mapboxMap property using runtime
142
- Ivar mapboxMapIvar = class_getInstanceVariable([self.mapView class], "mapboxMap");
143
- if (!mapboxMapIvar) {
144
- RCTLogError(@"❌ [GridRenderLayerView] Could not find mapboxMap ivar");
145
- return;
146
- }
147
-
148
- id mapboxMap = object_getIvar(self.mapView, mapboxMapIvar);
149
- if (!mapboxMap) {
150
- RCTLogError(@"❌ [GridRenderLayerView] mapboxMap is nil");
151
- return;
152
- }
153
-
154
- // Use the Swift bridge to add the layer
155
185
  BOOL success = [GridRenderLayerBridge addCustomLayerTo:self.mapView
156
186
  layerHost:customLayer
157
187
  layerId:self.layerId
@@ -167,9 +197,7 @@
167
197
  usingBlock:^(NSNotification *note) {
168
198
  RCTLogInfo(@"🔄 [GridRenderLayerView] Received repaint notification");
169
199
  if (self.mapView) {
170
- RCTLogInfo(@" ✅ Calling Swift bridge triggerRepaint");
171
200
  [GridRenderLayerBridge triggerRepaintOn:self.mapView];
172
- RCTLogInfo(@" ✅ Called triggerRepaint via Swift bridge");
173
201
  }
174
202
  }];
175
203
  } else {
@@ -177,6 +205,15 @@
177
205
  }
178
206
  }
179
207
 
208
+ - (void)logViewHierarchy:(UIView *)view depth:(int)depth {
209
+ NSString *indent = [@"" stringByPaddingToLength:depth * 2 withString:@" " startingAtIndex:0];
210
+ NSString *className = NSStringFromClass([view class]);
211
+ RCTLogInfo(@"%@└─ %@", indent, className);
212
+
213
+ for (UIView *subview in view.subviews) {
214
+ [self logViewHierarchy:subview depth:depth + 1];
215
+ }
216
+ }
180
217
  - (void)removeFromSuperview {
181
218
  if (self.mapView && self.isLayerAdded) {
182
219
  id mapboxMap = [self.mapView valueForKey:@"mapboxMap"];