@npm9912/v-map 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -0
  3. package/dist/cjs/_commonjsHelpers-B83fTs8d.js +36 -0
  4. package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
  5. package/dist/cjs/cesium-provider-BiFFyAl9.js +2598 -0
  6. package/dist/cjs/deck-provider-Ctq3Q8a1.js +47824 -0
  7. package/dist/cjs/geotiff-CEwvF9cG.js +47 -0
  8. package/dist/cjs/geotiff-source-RaNzzWkC.js +1522 -0
  9. package/dist/cjs/index-B1oGO1g-.js +10658 -0
  10. package/dist/cjs/index-B8LHqjyg.js +1765 -0
  11. package/dist/cjs/index-BIL4VsgP.js +310 -0
  12. package/dist/cjs/index-Blku2QY8.js +167 -0
  13. package/dist/cjs/index-CJvvX4yx.js +21 -0
  14. package/dist/cjs/index-CbVT-Con.js +699 -0
  15. package/dist/cjs/index-ISOEpMC3.js +20478 -0
  16. package/dist/cjs/index-JSwBbvGA.js +1621 -0
  17. package/dist/cjs/index.browser-DQhD8Jwl.js +6873 -0
  18. package/dist/cjs/index.cjs.js +2 -0
  19. package/dist/cjs/layer-extension-B_olS0rc.js +65 -0
  20. package/dist/cjs/leaflet-provider-DOqfs7g5.js +1815 -0
  21. package/dist/cjs/loader.cjs.js +13 -0
  22. package/dist/cjs/main-dist-7TykwFci.js +2655 -0
  23. package/dist/cjs/messages-D7h4m8Tx.js +186 -0
  24. package/dist/cjs/openlayers-provider-Dfeg6L4n.js +1604 -0
  25. package/dist/cjs/polygon-layer-B9PrN7vr.js +1300 -0
  26. package/dist/cjs/scenegraph-layer-DwNoxQdi.js +2530 -0
  27. package/dist/cjs/styleconfig-CVRqArk-.js +23 -0
  28. package/dist/cjs/v-map-builder.cjs.entry.js +3786 -0
  29. package/dist/cjs/v-map-layer-geojson_12.cjs.entry.js +40894 -0
  30. package/dist/cjs/v-map-layer-helper-iAzxAg9I.js +285 -0
  31. package/dist/cjs/v-map-layer-terrain-geotiff.cjs.entry.js +258 -0
  32. package/dist/cjs/v-map-layercontrol.cjs.entry.js +247 -0
  33. package/dist/cjs/v-map.cjs.js +25 -0
  34. package/dist/cjs/v-map.v-map-layer-osm.v-map-layergroup-BsXp3BoL.js +582 -0
  35. package/dist/cjs/v-map_3.cjs.entry.js +12 -0
  36. package/dist/collection/collection-manifest.json +30 -0
  37. package/dist/collection/components/v-map/v-map.css +3 -0
  38. package/dist/collection/components/v-map/v-map.js +467 -0
  39. package/dist/collection/components/v-map/v-map.test.js +33 -0
  40. package/dist/collection/components/v-map-builder/v-map-builder.css +1 -0
  41. package/dist/collection/components/v-map-builder/v-map-builder.js +913 -0
  42. package/dist/collection/components/v-map-builder/v-map-builder.test.js +56 -0
  43. package/dist/collection/components/v-map-layer-geojson/v-map-layer-geojson.js +862 -0
  44. package/dist/collection/components/v-map-layer-geojson/v-map-layer-geojson.test.js +42 -0
  45. package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.css +4 -0
  46. package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.js +500 -0
  47. package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.test.js +38 -0
  48. package/dist/collection/components/v-map-layer-google/v-map-layer-google.css +1 -0
  49. package/dist/collection/components/v-map-layer-google/v-map-layer-google.js +442 -0
  50. package/dist/collection/components/v-map-layer-osm/error-api.test.js +108 -0
  51. package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.css +4 -0
  52. package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.js +311 -0
  53. package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.test.js +36 -0
  54. package/dist/collection/components/v-map-layer-scatterplot/v-map-layer-scatterplot.css +1 -0
  55. package/dist/collection/components/v-map-layer-scatterplot/v-map-layer-scatterplot.js +305 -0
  56. package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.css +3 -0
  57. package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.js +548 -0
  58. package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.test.js +36 -0
  59. package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.css +3 -0
  60. package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.js +735 -0
  61. package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.test.js +42 -0
  62. package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.css +3 -0
  63. package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.js +449 -0
  64. package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.test.js +50 -0
  65. package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.css +1 -0
  66. package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.js +448 -0
  67. package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.test.js +39 -0
  68. package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.css +1 -0
  69. package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.js +489 -0
  70. package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.test.js +43 -0
  71. package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.css +1 -0
  72. package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.js +811 -0
  73. package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.test.js +34 -0
  74. package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.css +1 -0
  75. package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.js +453 -0
  76. package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.test.js +36 -0
  77. package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.css +1 -0
  78. package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.js +331 -0
  79. package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.test.js +28 -0
  80. package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.css +74 -0
  81. package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.js +277 -0
  82. package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.test.js +134 -0
  83. package/dist/collection/components/v-map-layergroup/v-map-layergroup.css +4 -0
  84. package/dist/collection/components/v-map-layergroup/v-map-layergroup.js +212 -0
  85. package/dist/collection/components/v-map-layergroup/v-map-layergroup.test.js +39 -0
  86. package/dist/collection/components/v-map-style/v-map-style.css +38 -0
  87. package/dist/collection/components/v-map-style/v-map-style.js +492 -0
  88. package/dist/collection/components/v-map-style/v-map-style.unit.js +62 -0
  89. package/dist/collection/index.js +1 -0
  90. package/dist/collection/layer/v-map-layer-helper.js +281 -0
  91. package/dist/collection/layer/v-map-layer-helper.unit.js +234 -0
  92. package/dist/collection/lib/cesium-loader.js +58 -0
  93. package/dist/collection/lib/ensure-importmap.js +12 -0
  94. package/dist/collection/lib/ensure-importmap.unit.js +57 -0
  95. package/dist/collection/lib/versions.gen.js +6 -0
  96. package/dist/collection/lib/vstyle.js +8 -0
  97. package/dist/collection/map-provider/cesium/CesiumGeoTIFFTerrainProvider.js +285 -0
  98. package/dist/collection/map-provider/cesium/CesiumLayerGroups.js +159 -0
  99. package/dist/collection/map-provider/cesium/GeoTIFFImageryProvider.js +192 -0
  100. package/dist/collection/map-provider/cesium/GeoTIFFImageryProvider.test.js +57 -0
  101. package/dist/collection/map-provider/cesium/cesium-provider.js +1408 -0
  102. package/dist/collection/map-provider/cesium/i-layer.js +1 -0
  103. package/dist/collection/map-provider/cesium/layer-manager.js +467 -0
  104. package/dist/collection/map-provider/deck/DeckGLGeoTIFFLayer.js +483 -0
  105. package/dist/collection/map-provider/deck/DeckGLGeoTIFFTerrainLayer.js +410 -0
  106. package/dist/collection/map-provider/deck/LayerGroupWithModel.js +169 -0
  107. package/dist/collection/map-provider/deck/LayerGroups.js +192 -0
  108. package/dist/collection/map-provider/deck/LayerModel.js +1 -0
  109. package/dist/collection/map-provider/deck/RenderableGroup.js +1 -0
  110. package/dist/collection/map-provider/deck/deck-provider.js +1563 -0
  111. package/dist/collection/map-provider/geotiff/geotiff-source.js +172 -0
  112. package/dist/collection/map-provider/geotiff/utils/AABB2D.js +24 -0
  113. package/dist/collection/map-provider/geotiff/utils/BVHNode2D.js +166 -0
  114. package/dist/collection/map-provider/geotiff/utils/GeoTIFFTileProcessor.js +484 -0
  115. package/dist/collection/map-provider/geotiff/utils/Triangle.js +1 -0
  116. package/dist/collection/map-provider/geotiff/utils/Triangulation.js +321 -0
  117. package/dist/collection/map-provider/geotiff/utils/colormap-utils.js +190 -0
  118. package/dist/collection/map-provider/geotiff/utils/normalization-utils.js +122 -0
  119. package/dist/collection/map-provider/geotiff/utils/sampling-utils.js +108 -0
  120. package/dist/collection/map-provider/leaflet/GeoTIFFGridLayer.js +147 -0
  121. package/dist/collection/map-provider/leaflet/WCSGridLayer.js +124 -0
  122. package/dist/collection/map-provider/leaflet/google-map-tiles-layer.js +352 -0
  123. package/dist/collection/map-provider/leaflet/leaflet-helpers.js +94 -0
  124. package/dist/collection/map-provider/leaflet/leaflet-provider.js +1095 -0
  125. package/dist/collection/map-provider/ol/CustomGeoTiff.js +145 -0
  126. package/dist/collection/map-provider/ol/openlayers-helper.js +26 -0
  127. package/dist/collection/map-provider/ol/openlayers-provider.js +1427 -0
  128. package/dist/collection/map-provider/provider-factory.js +44 -0
  129. package/dist/collection/map-provider/provider-factory.unit.js +66 -0
  130. package/dist/collection/testing/browser-test-utils.js +49 -0
  131. package/dist/collection/testing/e2e-testing.js +122 -0
  132. package/dist/collection/testing/e2e-utils.js +70 -0
  133. package/dist/collection/testing/geotiff-test-server.js +100 -0
  134. package/dist/collection/testing/mocks/geostyler-lyrx-parser.js +12 -0
  135. package/dist/collection/testing/mocks/geostyler-mapbox-parser.js +12 -0
  136. package/dist/collection/testing/mocks/geostyler-qgis-parser.js +12 -0
  137. package/dist/collection/testing/mocks/geostyler-sld-parser.js +13 -0
  138. package/dist/collection/testing/mocks/geostyler-style.js +5 -0
  139. package/dist/collection/testing/setupTests.browser.js +1 -0
  140. package/dist/collection/testing/setupTests.stencil.js +20 -0
  141. package/dist/collection/testing/setupTests.vitest.js +59 -0
  142. package/dist/collection/testing/stencil-testing-wrapper.js +43 -0
  143. package/dist/collection/testing/styleMock.js +1 -0
  144. package/dist/collection/types/color.js +1 -0
  145. package/dist/collection/types/cssmode.js +1 -0
  146. package/dist/collection/types/flavour.js +1 -0
  147. package/dist/collection/types/layerconfig.js +1 -0
  148. package/dist/collection/types/lonlat.js +1 -0
  149. package/dist/collection/types/mapinitoptions.js +1 -0
  150. package/dist/collection/types/mapprovider.js +1 -0
  151. package/dist/collection/types/provideroptions.js +1 -0
  152. package/dist/collection/types/styleconfig.js +19 -0
  153. package/dist/collection/types/styling.js +13 -0
  154. package/dist/collection/types/styling.unit.js +37 -0
  155. package/dist/collection/types/vmaplayer.js +1 -0
  156. package/dist/collection/utils/async-mutex.js +28 -0
  157. package/dist/collection/utils/diff.js +142 -0
  158. package/dist/collection/utils/diff.unit.js +59 -0
  159. package/dist/collection/utils/dom-env.js +43 -0
  160. package/dist/collection/utils/dom-env.unit.js +92 -0
  161. package/dist/collection/utils/events.js +8 -0
  162. package/dist/collection/utils/logger.js +183 -0
  163. package/dist/collection/utils/logger.unit.js +98 -0
  164. package/dist/collection/utils/messages.js +12 -0
  165. package/dist/collection/utils/spatial-utils.js +27 -0
  166. package/dist/collection/utils/spatial-utils.unit.js +24 -0
  167. package/dist/components/_commonjsHelpers.js +1 -0
  168. package/dist/components/cesium-provider.js +1 -0
  169. package/dist/components/deck-provider.js +1 -0
  170. package/dist/components/events.js +1 -0
  171. package/dist/components/geotiff-source.js +1 -0
  172. package/dist/components/geotiff.js +4 -0
  173. package/dist/components/index.browser.js +15 -0
  174. package/dist/components/index.d.ts +35 -0
  175. package/dist/components/index.js +1 -0
  176. package/dist/components/index2.js +1 -0
  177. package/dist/components/index3.js +1 -0
  178. package/dist/components/index4.js +1 -0
  179. package/dist/components/index5.js +1 -0
  180. package/dist/components/index6.js +1 -0
  181. package/dist/components/index7.js +1 -0
  182. package/dist/components/index8.js +7 -0
  183. package/dist/components/layer-extension.js +1 -0
  184. package/dist/components/leaflet-provider.js +1 -0
  185. package/dist/components/main-dist.js +1 -0
  186. package/dist/components/messages.js +1 -0
  187. package/dist/components/openlayers-provider.js +1 -0
  188. package/dist/components/polygon-layer.js +1 -0
  189. package/dist/components/scenegraph-layer.js +1 -0
  190. package/dist/components/styleconfig.js +1 -0
  191. package/dist/components/styling.js +1 -0
  192. package/dist/components/v-map-builder.d.ts +11 -0
  193. package/dist/components/v-map-builder.js +2 -0
  194. package/dist/components/v-map-layer-geojson.d.ts +11 -0
  195. package/dist/components/v-map-layer-geojson.js +1 -0
  196. package/dist/components/v-map-layer-geojson2.js +1 -0
  197. package/dist/components/v-map-layer-geotiff.d.ts +11 -0
  198. package/dist/components/v-map-layer-geotiff.js +1 -0
  199. package/dist/components/v-map-layer-geotiff2.js +1 -0
  200. package/dist/components/v-map-layer-google.d.ts +11 -0
  201. package/dist/components/v-map-layer-google.js +1 -0
  202. package/dist/components/v-map-layer-google2.js +1 -0
  203. package/dist/components/v-map-layer-helper.js +1 -0
  204. package/dist/components/v-map-layer-osm.d.ts +11 -0
  205. package/dist/components/v-map-layer-osm.js +1 -0
  206. package/dist/components/v-map-layer-osm2.js +1 -0
  207. package/dist/components/v-map-layer-scatterplot.d.ts +11 -0
  208. package/dist/components/v-map-layer-scatterplot.js +1 -0
  209. package/dist/components/v-map-layer-scatterplot2.js +1 -0
  210. package/dist/components/v-map-layer-terrain-geotiff.d.ts +11 -0
  211. package/dist/components/v-map-layer-terrain-geotiff.js +1 -0
  212. package/dist/components/v-map-layer-terrain.d.ts +11 -0
  213. package/dist/components/v-map-layer-terrain.js +1 -0
  214. package/dist/components/v-map-layer-terrain2.js +1 -0
  215. package/dist/components/v-map-layer-tile3d.d.ts +11 -0
  216. package/dist/components/v-map-layer-tile3d.js +1 -0
  217. package/dist/components/v-map-layer-tile3d2.js +1 -0
  218. package/dist/components/v-map-layer-wcs.d.ts +11 -0
  219. package/dist/components/v-map-layer-wcs.js +1 -0
  220. package/dist/components/v-map-layer-wcs2.js +1 -0
  221. package/dist/components/v-map-layer-wfs.d.ts +11 -0
  222. package/dist/components/v-map-layer-wfs.js +1 -0
  223. package/dist/components/v-map-layer-wfs2.js +1 -0
  224. package/dist/components/v-map-layer-wkt.d.ts +11 -0
  225. package/dist/components/v-map-layer-wkt.js +1 -0
  226. package/dist/components/v-map-layer-wkt2.js +1 -0
  227. package/dist/components/v-map-layer-wms.d.ts +11 -0
  228. package/dist/components/v-map-layer-wms.js +1 -0
  229. package/dist/components/v-map-layer-wms2.js +1 -0
  230. package/dist/components/v-map-layer-xyz.d.ts +11 -0
  231. package/dist/components/v-map-layer-xyz.js +1 -0
  232. package/dist/components/v-map-layer-xyz2.js +1 -0
  233. package/dist/components/v-map-layercontrol.d.ts +11 -0
  234. package/dist/components/v-map-layercontrol.js +1 -0
  235. package/dist/components/v-map-layergroup.d.ts +11 -0
  236. package/dist/components/v-map-layergroup.js +1 -0
  237. package/dist/components/v-map-layergroup2.js +1 -0
  238. package/dist/components/v-map-style.d.ts +11 -0
  239. package/dist/components/v-map-style.js +1 -0
  240. package/dist/components/v-map-style2.js +10 -0
  241. package/dist/components/v-map.d.ts +11 -0
  242. package/dist/components/v-map.js +1 -0
  243. package/dist/components/v-map2.js +1 -0
  244. package/dist/esm/_commonjsHelpers-E-ZsRS8r.js +32 -0
  245. package/dist/esm/app-globals-DQuL1Twl.js +3 -0
  246. package/dist/esm/cesium-provider-BJfAup3w.js +2596 -0
  247. package/dist/esm/deck-provider-C7U9VDEq.js +47709 -0
  248. package/dist/esm/geotiff-BEWxTIfH.js +45 -0
  249. package/dist/esm/geotiff-source-esnDnC-u.js +1516 -0
  250. package/dist/esm/index-B1zwA4IC.js +685 -0
  251. package/dist/esm/index-BBpiaTpT.js +165 -0
  252. package/dist/esm/index-BIEmlzCf.js +1697 -0
  253. package/dist/esm/index-BUHa4Jj0.js +307 -0
  254. package/dist/esm/index-DbSdn93t.js +20461 -0
  255. package/dist/esm/index-RpJarvr_.js +10656 -0
  256. package/dist/esm/index-jN06TXUp.js +14 -0
  257. package/dist/esm/index-jzneDarq.js +1613 -0
  258. package/dist/esm/index.browser-DhQAXuA7.js +6860 -0
  259. package/dist/esm/index.js +1 -0
  260. package/dist/esm/layer-extension-CZXK5goK.js +63 -0
  261. package/dist/esm/leaflet-provider-Q41TB6ku.js +1794 -0
  262. package/dist/esm/loader.js +11 -0
  263. package/dist/esm/main-dist-CwnA7_Xn.js +2652 -0
  264. package/dist/esm/messages-CMKJzsgL.js +180 -0
  265. package/dist/esm/openlayers-provider-CMsDsQTQ.js +1602 -0
  266. package/dist/esm/polygon-layer-ByhxGhWC.js +1295 -0
  267. package/dist/esm/scenegraph-layer-09K_B6DT.js +2526 -0
  268. package/dist/esm/styleconfig-B-bAcABs.js +21 -0
  269. package/dist/esm/v-map-builder.entry.js +3784 -0
  270. package/dist/esm/v-map-layer-geojson_12.entry.js +40881 -0
  271. package/dist/esm/v-map-layer-helper-Dys44Cgo.js +283 -0
  272. package/dist/esm/v-map-layer-terrain-geotiff.entry.js +256 -0
  273. package/dist/esm/v-map-layercontrol.entry.js +245 -0
  274. package/dist/esm/v-map.js +21 -0
  275. package/dist/esm/v-map.v-map-layer-osm.v-map-layergroup-B4pFHuSf.js +572 -0
  276. package/dist/esm/v-map_3.entry.js +4 -0
  277. package/dist/index.cjs.js +1 -0
  278. package/dist/index.js +1 -0
  279. package/dist/types/cesium-augment.d.ts +5 -0
  280. package/dist/types/components/v-map/v-map.d.ts +70 -0
  281. package/dist/types/components/v-map/v-map.test.d.ts +1 -0
  282. package/dist/types/components/v-map-builder/v-map-builder.d.ts +48 -0
  283. package/dist/types/components/v-map-builder/v-map-builder.test.d.ts +1 -0
  284. package/dist/types/components/v-map-layer-geojson/v-map-layer-geojson.d.ts +129 -0
  285. package/dist/types/components/v-map-layer-geojson/v-map-layer-geojson.test.d.ts +1 -0
  286. package/dist/types/components/v-map-layer-geotiff/v-map-layer-geotiff.d.ts +74 -0
  287. package/dist/types/components/v-map-layer-geotiff/v-map-layer-geotiff.test.d.ts +1 -0
  288. package/dist/types/components/v-map-layer-google/v-map-layer-google.d.ts +78 -0
  289. package/dist/types/components/v-map-layer-osm/error-api.test.d.ts +1 -0
  290. package/dist/types/components/v-map-layer-osm/v-map-layer-osm.d.ts +50 -0
  291. package/dist/types/components/v-map-layer-osm/v-map-layer-osm.test.d.ts +1 -0
  292. package/dist/types/components/v-map-layer-scatterplot/v-map-layer-scatterplot.d.ts +54 -0
  293. package/dist/types/components/v-map-layer-terrain/v-map-layer-terrain.d.ts +74 -0
  294. package/dist/types/components/v-map-layer-terrain/v-map-layer-terrain.test.d.ts +1 -0
  295. package/dist/types/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.d.ts +117 -0
  296. package/dist/types/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.test.d.ts +1 -0
  297. package/dist/types/components/v-map-layer-tile3d/v-map-layer-tile3d.d.ts +69 -0
  298. package/dist/types/components/v-map-layer-tile3d/v-map-layer-tile3d.test.d.ts +1 -0
  299. package/dist/types/components/v-map-layer-wcs/v-map-layer-wcs.d.ts +47 -0
  300. package/dist/types/components/v-map-layer-wcs/v-map-layer-wcs.test.d.ts +1 -0
  301. package/dist/types/components/v-map-layer-wfs/v-map-layer-wfs.d.ts +59 -0
  302. package/dist/types/components/v-map-layer-wfs/v-map-layer-wfs.test.d.ts +1 -0
  303. package/dist/types/components/v-map-layer-wkt/v-map-layer-wkt.d.ts +132 -0
  304. package/dist/types/components/v-map-layer-wkt/v-map-layer-wkt.test.d.ts +1 -0
  305. package/dist/types/components/v-map-layer-wms/v-map-layer-wms.d.ts +76 -0
  306. package/dist/types/components/v-map-layer-wms/v-map-layer-wms.test.d.ts +1 -0
  307. package/dist/types/components/v-map-layer-xyz/v-map-layer-xyz.d.ts +59 -0
  308. package/dist/types/components/v-map-layer-xyz/v-map-layer-xyz.test.d.ts +1 -0
  309. package/dist/types/components/v-map-layercontrol/v-map-layercontrol.d.ts +44 -0
  310. package/dist/types/components/v-map-layercontrol/v-map-layercontrol.test.d.ts +1 -0
  311. package/dist/types/components/v-map-layergroup/v-map-layergroup.d.ts +31 -0
  312. package/dist/types/components/v-map-layergroup/v-map-layergroup.test.d.ts +1 -0
  313. package/dist/types/components/v-map-style/v-map-style.d.ts +75 -0
  314. package/dist/types/components/v-map-style/v-map-style.unit.d.ts +1 -0
  315. package/dist/types/components.d.ts +2391 -0
  316. package/dist/types/globals.d.ts +16 -0
  317. package/dist/types/index.d.ts +10 -0
  318. package/dist/types/layer/v-map-layer-helper.d.ts +45 -0
  319. package/dist/types/layer/v-map-layer-helper.unit.d.ts +1 -0
  320. package/dist/types/leaflet-augment.d.ts +15 -0
  321. package/dist/types/lib/cesium-loader.d.ts +3 -0
  322. package/dist/types/lib/ensure-importmap.d.ts +3 -0
  323. package/dist/types/lib/ensure-importmap.unit.d.ts +1 -0
  324. package/dist/types/lib/versions.gen.d.ts +5 -0
  325. package/dist/types/lib/vstyle.d.ts +44 -0
  326. package/dist/types/map-provider/cesium/CesiumGeoTIFFTerrainProvider.d.ts +92 -0
  327. package/dist/types/map-provider/cesium/CesiumLayerGroups.d.ts +64 -0
  328. package/dist/types/map-provider/cesium/GeoTIFFImageryProvider.d.ts +75 -0
  329. package/dist/types/map-provider/cesium/GeoTIFFImageryProvider.test.d.ts +1 -0
  330. package/dist/types/map-provider/cesium/cesium-provider.d.ts +87 -0
  331. package/dist/types/map-provider/cesium/i-layer.d.ts +11 -0
  332. package/dist/types/map-provider/cesium/layer-manager.d.ts +31 -0
  333. package/dist/types/map-provider/deck/DeckGLGeoTIFFLayer.d.ts +91 -0
  334. package/dist/types/map-provider/deck/DeckGLGeoTIFFTerrainLayer.d.ts +82 -0
  335. package/dist/types/map-provider/deck/LayerGroupWithModel.d.ts +55 -0
  336. package/dist/types/map-provider/deck/LayerGroups.d.ts +63 -0
  337. package/dist/types/map-provider/deck/LayerModel.d.ts +8 -0
  338. package/dist/types/map-provider/deck/RenderableGroup.d.ts +20 -0
  339. package/dist/types/map-provider/deck/deck-provider.d.ts +92 -0
  340. package/dist/types/map-provider/geotiff/geotiff-source.d.ts +30 -0
  341. package/dist/types/map-provider/geotiff/utils/AABB2D.d.ts +28 -0
  342. package/dist/types/map-provider/geotiff/utils/BVHNode2D.d.ts +36 -0
  343. package/dist/types/map-provider/geotiff/utils/GeoTIFFTileProcessor.d.ts +116 -0
  344. package/dist/types/map-provider/geotiff/utils/Triangle.d.ts +5 -0
  345. package/dist/types/map-provider/geotiff/utils/Triangulation.d.ts +94 -0
  346. package/dist/types/map-provider/geotiff/utils/colormap-utils.d.ts +47 -0
  347. package/dist/types/map-provider/geotiff/utils/normalization-utils.d.ts +39 -0
  348. package/dist/types/map-provider/geotiff/utils/sampling-utils.d.ts +13 -0
  349. package/dist/types/map-provider/leaflet/GeoTIFFGridLayer.d.ts +34 -0
  350. package/dist/types/map-provider/leaflet/WCSGridLayer.d.ts +38 -0
  351. package/dist/types/map-provider/leaflet/google-map-tiles-layer.d.ts +73 -0
  352. package/dist/types/map-provider/leaflet/leaflet-helpers.d.ts +6 -0
  353. package/dist/types/map-provider/leaflet/leaflet-provider.d.ts +73 -0
  354. package/dist/types/map-provider/ol/CustomGeoTiff.d.ts +14 -0
  355. package/dist/types/map-provider/ol/openlayers-helper.d.ts +2 -0
  356. package/dist/types/map-provider/ol/openlayers-provider.d.ts +80 -0
  357. package/dist/types/map-provider/provider-factory.d.ts +12 -0
  358. package/dist/types/map-provider/provider-factory.unit.d.ts +1 -0
  359. package/dist/types/namespaces.d.ts +3 -0
  360. package/dist/types/ol-augment.d.ts +3 -0
  361. package/dist/types/ol-override.d.ts +7 -0
  362. package/dist/types/ol.d.ts +10 -0
  363. package/dist/types/stencil-public-runtime.d.ts +1860 -0
  364. package/dist/types/testing/browser-test-utils.d.ts +6 -0
  365. package/dist/types/testing/e2e-testing.d.ts +5 -0
  366. package/dist/types/testing/e2e-utils.d.ts +4 -0
  367. package/dist/types/testing/geotiff-test-server.d.ts +5 -0
  368. package/dist/types/testing/mocks/geostyler-lyrx-parser.d.ts +11 -0
  369. package/dist/types/testing/mocks/geostyler-mapbox-parser.d.ts +11 -0
  370. package/dist/types/testing/mocks/geostyler-qgis-parser.d.ts +11 -0
  371. package/dist/types/testing/mocks/geostyler-sld-parser.d.ts +11 -0
  372. package/dist/types/testing/mocks/geostyler-style.d.ts +5 -0
  373. package/dist/types/testing/setupTests.browser.d.ts +1 -0
  374. package/dist/types/testing/setupTests.stencil.d.ts +1 -0
  375. package/dist/types/testing/setupTests.vitest.d.ts +1 -0
  376. package/dist/types/testing/stencil-testing-wrapper.d.ts +3 -0
  377. package/dist/types/types/color.d.ts +1 -0
  378. package/dist/types/types/cssmode.d.ts +1 -0
  379. package/dist/types/types/flavour.d.ts +1 -0
  380. package/dist/types/types/layerconfig.d.ts +207 -0
  381. package/dist/types/types/lonlat.d.ts +1 -0
  382. package/dist/types/types/mapinitoptions.d.ts +4 -0
  383. package/dist/types/types/mapprovider.d.ts +46 -0
  384. package/dist/types/types/provideroptions.d.ts +8 -0
  385. package/dist/types/types/styleconfig.d.ts +27 -0
  386. package/dist/types/types/styling.d.ts +24 -0
  387. package/dist/types/types/styling.unit.d.ts +1 -0
  388. package/dist/types/types/vmaplayer.d.ts +10 -0
  389. package/dist/types/utils/async-mutex.d.ts +7 -0
  390. package/dist/types/utils/diff.d.ts +64 -0
  391. package/dist/types/utils/diff.unit.d.ts +1 -0
  392. package/dist/types/utils/dom-env.d.ts +5 -0
  393. package/dist/types/utils/dom-env.unit.d.ts +1 -0
  394. package/dist/types/utils/events.d.ts +29 -0
  395. package/dist/types/utils/logger.d.ts +47 -0
  396. package/dist/types/utils/logger.unit.d.ts +1 -0
  397. package/dist/types/utils/messages.d.ts +12 -0
  398. package/dist/types/utils/spatial-utils.d.ts +6 -0
  399. package/dist/types/utils/spatial-utils.unit.d.ts +1 -0
  400. package/dist/types/versions.d.ts +7 -0
  401. package/dist/v-map/index.esm.js +0 -0
  402. package/dist/v-map/p--vVleK-M.js +1 -0
  403. package/dist/v-map/p-09d10db0.entry.js +1 -0
  404. package/dist/v-map/p-5eba6058.entry.js +10 -0
  405. package/dist/v-map/p-6b102336.entry.js +1 -0
  406. package/dist/v-map/p-B-bAcABs.js +1 -0
  407. package/dist/v-map/p-BBpiaTpT.js +1 -0
  408. package/dist/v-map/p-BdijL4Av.js +1 -0
  409. package/dist/v-map/p-Be3r33VF.js +4 -0
  410. package/dist/v-map/p-BeFu0ap4.js +1 -0
  411. package/dist/v-map/p-BxFJezdK.js +1 -0
  412. package/dist/v-map/p-CMKJzsgL.js +1 -0
  413. package/dist/v-map/p-CXfA_q8m.js +1 -0
  414. package/dist/v-map/p-CZqY0yW4.js +1 -0
  415. package/dist/v-map/p-CafTHT9i.js +1 -0
  416. package/dist/v-map/p-DCTHyf58.js +1 -0
  417. package/dist/v-map/p-DQuL1Twl.js +1 -0
  418. package/dist/v-map/p-DR9McdNX.js +1 -0
  419. package/dist/v-map/p-Dckgonw8.js +1 -0
  420. package/dist/v-map/p-DhQAXuA7.js +15 -0
  421. package/dist/v-map/p-DmICdG34.js +7 -0
  422. package/dist/v-map/p-DrOQ9V4h.js +1 -0
  423. package/dist/v-map/p-DvHXtWUg.js +1 -0
  424. package/dist/v-map/p-E-ZsRS8r.js +1 -0
  425. package/dist/v-map/p-MyTSFnEk.js +1 -0
  426. package/dist/v-map/p-RpJarvr_.js +1 -0
  427. package/dist/v-map/p-WaMDUuAz.js +1 -0
  428. package/dist/v-map/p-aa410e64.entry.js +2 -0
  429. package/dist/v-map/p-c21c93fe.entry.js +1 -0
  430. package/dist/v-map/p-jzneDarq.js +2 -0
  431. package/dist/v-map/p-uiIP-taz.js +1 -0
  432. package/dist/v-map/v-map.esm.js +1 -0
  433. package/loader/cdn.js +1 -0
  434. package/loader/index.cjs.js +1 -0
  435. package/loader/index.d.ts +24 -0
  436. package/loader/index.es2017.js +1 -0
  437. package/loader/index.js +2 -0
  438. package/package.json +193 -0
@@ -0,0 +1,1522 @@
1
+ 'use strict';
2
+
3
+ var messages = require('./messages-D7h4m8Tx.js');
4
+
5
+ /**
6
+ * ColorMap utilities for GeoTIFF visualization
7
+ * Extracted for testability
8
+ */
9
+ /**
10
+ * Predefined color maps
11
+ */
12
+ const PREDEFINED_COLORMAPS = {
13
+ grayscale: [
14
+ { value: 0.0, color: [0, 0, 0] },
15
+ { value: 1.0, color: [255, 255, 255] },
16
+ ],
17
+ viridis: [
18
+ { value: 0.0, color: [68, 1, 84] },
19
+ { value: 0.25, color: [59, 82, 139] },
20
+ { value: 0.5, color: [33, 145, 140] },
21
+ { value: 0.75, color: [94, 201, 98] },
22
+ { value: 1.0, color: [253, 231, 37] },
23
+ ],
24
+ terrain: [
25
+ { value: 0.0, color: [0, 128, 0] }, // dark green (low)
26
+ { value: 0.25, color: [139, 195, 74] }, // light green
27
+ { value: 0.5, color: [255, 235, 59] }, // yellow
28
+ { value: 0.75, color: [255, 152, 0] }, // orange
29
+ { value: 1.0, color: [255, 255, 255] }, // white (high)
30
+ ],
31
+ turbo: [
32
+ { value: 0.0, color: [48, 18, 59] },
33
+ { value: 0.2, color: [33, 102, 172] },
34
+ { value: 0.4, color: [68, 190, 112] },
35
+ { value: 0.6, color: [253, 231, 37] },
36
+ { value: 0.8, color: [234, 51, 35] },
37
+ { value: 1.0, color: [122, 4, 3] },
38
+ ],
39
+ rainbow: [
40
+ { value: 0.0, color: [148, 0, 211] }, // violet
41
+ { value: 0.2, color: [0, 0, 255] }, // blue
42
+ { value: 0.4, color: [0, 255, 0] }, // green
43
+ { value: 0.6, color: [255, 255, 0] }, // yellow
44
+ { value: 0.8, color: [255, 127, 0] }, // orange
45
+ { value: 1.0, color: [255, 0, 0] }, // red
46
+ ],
47
+ };
48
+ /**
49
+ * Parse a hex color string to RGB array
50
+ * @param hexColor - Hex color string (e.g., "#FF0000" or "#F00")
51
+ * @returns RGB array [r, g, b] with values 0-255
52
+ */
53
+ function parseHexColor(hexColor) {
54
+ let hex = hexColor.trim();
55
+ if (hex.startsWith('#')) {
56
+ hex = hex.slice(1);
57
+ }
58
+ // Handle shorthand hex (#RGB -> #RRGGBB)
59
+ if (hex.length === 3) {
60
+ hex = hex
61
+ .split('')
62
+ .map(c => c + c)
63
+ .join('');
64
+ }
65
+ if (hex.length !== 6) {
66
+ messages.warn(`Invalid hex color: ${hexColor}, using black`);
67
+ return [0, 0, 0];
68
+ }
69
+ const r = parseInt(hex.slice(0, 2), 16);
70
+ const g = parseInt(hex.slice(2, 4), 16);
71
+ const b = parseInt(hex.slice(4, 6), 16);
72
+ if (isNaN(r) || isNaN(g) || isNaN(b)) {
73
+ messages.warn(`Invalid hex color: ${hexColor}, using black`);
74
+ return [0, 0, 0];
75
+ }
76
+ return [r, g, b];
77
+ }
78
+ /**
79
+ * Convert GeoStyler ColorMap to internal ColorStop array
80
+ * @param geoStylerColorMap - GeoStyler ColorMap object
81
+ * @param valueRange - Optional value range [min, max] for normalization
82
+ * @returns Object with ColorStop array and computed range
83
+ */
84
+ function convertGeoStylerColorMap(geoStylerColorMap, valueRange) {
85
+ const entries = geoStylerColorMap.colorMapEntries || [];
86
+ if (entries.length === 0) {
87
+ messages.warn('GeoStyler ColorMap has no entries, using grayscale');
88
+ return { stops: PREDEFINED_COLORMAPS.grayscale };
89
+ }
90
+ // Extract quantity values for normalization
91
+ const quantities = entries
92
+ .map(e => e.quantity)
93
+ .filter((q) => typeof q === 'number');
94
+ let minVal;
95
+ let maxVal;
96
+ if (valueRange) {
97
+ [minVal, maxVal] = valueRange;
98
+ }
99
+ else if (quantities.length > 0) {
100
+ minVal = Math.min(...quantities);
101
+ maxVal = Math.max(...quantities);
102
+ }
103
+ else {
104
+ // No quantities and no valueRange - assume normalized 0-1
105
+ minVal = 0;
106
+ maxVal = 1;
107
+ }
108
+ // Avoid division by zero
109
+ if (maxVal === minVal) {
110
+ maxVal = minVal + 1;
111
+ }
112
+ const stops = entries.map(entry => {
113
+ const quantity = typeof entry.quantity === 'number' ? entry.quantity : 0;
114
+ const normalizedValue = (quantity - minVal) / (maxVal - minVal);
115
+ // Parse color (handle both string and Expression<string>)
116
+ const colorStr = typeof entry.color === 'string' ? entry.color : String(entry.color);
117
+ const color = parseHexColor(colorStr);
118
+ return {
119
+ value: Math.max(0, Math.min(1, normalizedValue)), // Clamp to [0, 1]
120
+ color,
121
+ };
122
+ });
123
+ // Sort by value for binary search
124
+ stops.sort((a, b) => a.value - b.value);
125
+ return {
126
+ stops,
127
+ computedRange: valueRange ? undefined : [minVal, maxVal],
128
+ };
129
+ }
130
+ /**
131
+ * Apply colormap to a normalized value using interpolation
132
+ * @param normalizedValue - Value between 0 and 1
133
+ * @param colorStops - Array of color stops (must be sorted by value)
134
+ * @returns RGB color [r, g, b]
135
+ */
136
+ function applyColorMap(normalizedValue, colorStops) {
137
+ const v = Math.max(0, Math.min(1, normalizedValue));
138
+ if (colorStops.length === 0) {
139
+ return [0, 0, 0]; // Black fallback
140
+ }
141
+ if (colorStops.length === 1) {
142
+ return colorStops[0].color;
143
+ }
144
+ // Binary search for surrounding color stops
145
+ let left = 0;
146
+ let right = colorStops.length - 1;
147
+ // Handle edge cases
148
+ if (v <= colorStops[left].value) {
149
+ return colorStops[left].color;
150
+ }
151
+ if (v >= colorStops[right].value) {
152
+ return colorStops[right].color;
153
+ }
154
+ // Binary search
155
+ while (right - left > 1) {
156
+ const mid = Math.floor((left + right) / 2);
157
+ if (colorStops[mid].value <= v) {
158
+ left = mid;
159
+ }
160
+ else {
161
+ right = mid;
162
+ }
163
+ }
164
+ // Interpolate between left and right
165
+ const lower = colorStops[left];
166
+ const upper = colorStops[right];
167
+ const ratio = (v - lower.value) / (upper.value - lower.value);
168
+ const r = Math.round(lower.color[0] + ratio * (upper.color[0] - lower.color[0]));
169
+ const g = Math.round(lower.color[1] + ratio * (upper.color[1] - lower.color[1]));
170
+ const b = Math.round(lower.color[2] + ratio * (upper.color[2] - lower.color[2]));
171
+ return [r, g, b];
172
+ }
173
+ /**
174
+ * Get ColorStop array from ColorMapName or GeoStyler ColorMap
175
+ * @param colorMap - Predefined name or GeoStyler ColorMap
176
+ * @param valueRange - Optional value range for GeoStyler ColorMap
177
+ * @returns ColorStop array and computed range (if applicable)
178
+ */
179
+ function getColorStops(colorMap, valueRange) {
180
+ if (typeof colorMap === 'string') {
181
+ // Predefined colormap name
182
+ const stops = PREDEFINED_COLORMAPS[colorMap];
183
+ if (!stops) {
184
+ messages.warn(`Unknown colormap: ${colorMap}, using grayscale`);
185
+ return { stops: PREDEFINED_COLORMAPS.grayscale };
186
+ }
187
+ return { stops };
188
+ }
189
+ else {
190
+ // GeoStyler ColorMap
191
+ return convertGeoStylerColorMap(colorMap, valueRange);
192
+ }
193
+ }
194
+
195
+ class AABB2D {
196
+ min;
197
+ max;
198
+ constructor(min, max) {
199
+ this.min = min;
200
+ this.max = max;
201
+ }
202
+ contains(point) {
203
+ return (point.x >= this.min.x &&
204
+ point.x <= this.max.x &&
205
+ point.y >= this.min.y &&
206
+ point.y <= this.max.y);
207
+ }
208
+ static fromTriangle(triangle) {
209
+ const minX = Math.min(triangle.a.x, triangle.b.x, triangle.c.x);
210
+ const minY = Math.min(triangle.a.y, triangle.b.y, triangle.c.y);
211
+ const maxX = Math.max(triangle.a.x, triangle.b.x, triangle.c.x);
212
+ const maxY = Math.max(triangle.a.y, triangle.b.y, triangle.c.y);
213
+ return new AABB2D({ x: minX, y: minY }, { x: maxX, y: maxY });
214
+ }
215
+ static union(a, b) {
216
+ return new AABB2D({ x: Math.min(a.min.x, b.min.x), y: Math.min(a.min.y, b.min.y) }, { x: Math.max(a.max.x, b.max.x), y: Math.max(a.max.y, b.max.y) });
217
+ }
218
+ }
219
+
220
+ class BVHNode2D {
221
+ bbox;
222
+ triangles;
223
+ left;
224
+ right;
225
+ constructor(bbox, triangles = [], left = null, right = null) {
226
+ this.bbox = bbox;
227
+ this.triangles = triangles;
228
+ this.left = left;
229
+ this.right = right;
230
+ }
231
+ static build(triangles, depth = 0, maxDepth = 10) {
232
+ if (triangles.length <= 2 || depth >= maxDepth) {
233
+ let bbox = AABB2D.fromTriangle(triangles[0]);
234
+ for (let i = 1; i < triangles.length; i++) {
235
+ bbox = AABB2D.union(bbox, AABB2D.fromTriangle(triangles[i]));
236
+ }
237
+ return new BVHNode2D(bbox, triangles);
238
+ }
239
+ const centroids = triangles.map(t => ({
240
+ x: (t.a.x + t.b.x + t.c.x) / 3,
241
+ y: (t.a.y + t.b.y + t.c.y) / 3,
242
+ }));
243
+ const { min, max } = centroids.reduce((acc, c) => ({
244
+ min: { x: Math.min(acc.min.x, c.x), y: Math.min(acc.min.y, c.y) },
245
+ max: { x: Math.max(acc.max.x, c.x), y: Math.max(acc.max.y, c.y) },
246
+ }), { min: centroids[0], max: centroids[0] });
247
+ const axis = max.x - min.x > max.y - min.y ? 'x' : 'y';
248
+ centroids.sort((a, b) => a[axis] - b[axis]);
249
+ const mid = Math.floor(centroids.length / 2);
250
+ const leftTriangles = [];
251
+ const rightTriangles = [];
252
+ for (let i = 0; i < triangles.length; i++) {
253
+ (i < mid ? leftTriangles : rightTriangles).push(triangles[i]);
254
+ }
255
+ const left = BVHNode2D.build(leftTriangles, depth + 1, maxDepth);
256
+ const right = BVHNode2D.build(rightTriangles, depth + 1, maxDepth);
257
+ const bbox = AABB2D.union(left.bbox, right.bbox);
258
+ return new BVHNode2D(bbox, [], left, right);
259
+ }
260
+ /**
261
+ * Finds the triangle containing the given point.
262
+ * @param point The point to test.
263
+ * @returns The containing triangle or `null`.
264
+ */
265
+ findContainingTriangle(point) {
266
+ if (!this.bbox.contains(point)) {
267
+ return null;
268
+ }
269
+ if (this.triangles.length > 0) {
270
+ for (const triangle of this.triangles) {
271
+ if (BVHNode2D.punktInDreieck2D(point, triangle)) {
272
+ return triangle;
273
+ }
274
+ }
275
+ return null;
276
+ }
277
+ return (this.left?.findContainingTriangle(point) ||
278
+ this.right?.findContainingTriangle(point) ||
279
+ null);
280
+ }
281
+ static punktInDreieck2D(p, triangle) {
282
+ const { a, b, c } = triangle;
283
+ const v0 = { x: c.x - a.x, y: c.y - a.y };
284
+ const v1 = { x: b.x - a.x, y: b.y - a.y };
285
+ const v2 = { x: p.x - a.x, y: p.y - a.y };
286
+ const dot00 = v0.x * v0.x + v0.y * v0.y;
287
+ const dot01 = v0.x * v1.x + v0.y * v1.y;
288
+ const dot02 = v0.x * v2.x + v0.y * v2.y;
289
+ const dot11 = v1.x * v1.x + v1.y * v1.y;
290
+ const dot12 = v1.x * v2.x + v1.y * v2.y;
291
+ const invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
292
+ const u = (dot11 * dot02 - dot01 * dot12) * invDenom;
293
+ const v = (dot00 * dot12 - dot01 * dot02) * invDenom;
294
+ return u >= 0 && v >= 0 && u + v <= 1;
295
+ //return u >= 0 && v >= 0 && u + v < 1;
296
+ }
297
+ static toTriangle2D(triangle) {
298
+ return {
299
+ a: { x: triangle.target[0][0], y: triangle.target[0][1] },
300
+ b: { x: triangle.target[1][0], y: triangle.target[1][1] },
301
+ c: { x: triangle.target[2][0], y: triangle.target[2][1] },
302
+ triangle: triangle,
303
+ transform: null,
304
+ };
305
+ }
306
+ /**
307
+ * Returns a string representation of the BVH tree structure
308
+ * @param indent - Internal parameter for recursive formatting
309
+ * @returns Formatted string showing tree structure
310
+ */
311
+ toString(indent = '') {
312
+ const isLeaf = this.triangles.length > 0;
313
+ const nodeType = isLeaf ? 'LEAF' : 'NODE';
314
+ const bboxStr = `[${this.bbox.min.x.toFixed(2)}, ${this.bbox.min.y.toFixed(2)}, ${this.bbox.max.x.toFixed(2)}, ${this.bbox.max.y.toFixed(2)}]`;
315
+ let result = `${indent}${nodeType} bbox=${bboxStr}`;
316
+ if (isLeaf) {
317
+ const triArray = this.triangles.map(t2D => t2D.a.x.toFixed(2) +
318
+ ',' +
319
+ t2D.a.y.toFixed(2) +
320
+ ' ' +
321
+ t2D.b.x.toFixed(2) +
322
+ ',' +
323
+ t2D.b.y.toFixed(2) +
324
+ ' ' +
325
+ t2D.c.x.toFixed(2) +
326
+ ',' +
327
+ t2D.c.y.toFixed(2));
328
+ const triArrayStr = triArray.toString();
329
+ result += ` triangles=${this.triangles.length} - ${triArrayStr}`;
330
+ }
331
+ else {
332
+ result += '\n';
333
+ if (this.left) {
334
+ result += `${indent}├─ left:\n${this.left.toString(indent + '│ ')}`;
335
+ }
336
+ if (this.right) {
337
+ result += `${indent}└─ right:\n${this.right.toString(indent + ' ')}`;
338
+ }
339
+ }
340
+ return result;
341
+ }
342
+ /**
343
+ * Get statistics about the BVH tree
344
+ * @returns Object with tree statistics
345
+ */
346
+ getStats() {
347
+ const stats = {
348
+ depth: 1,
349
+ nodeCount: 1,
350
+ leafCount: 0,
351
+ triangleCount: this.triangles.length,
352
+ minTrianglesPerLeaf: Infinity,
353
+ maxTrianglesPerLeaf: 0,
354
+ };
355
+ if (this.triangles.length > 0) {
356
+ // This is a leaf
357
+ stats.leafCount = 1;
358
+ stats.minTrianglesPerLeaf = this.triangles.length;
359
+ stats.maxTrianglesPerLeaf = this.triangles.length;
360
+ }
361
+ else {
362
+ // This is an internal node
363
+ if (this.left) {
364
+ const leftStats = this.left.getStats();
365
+ stats.depth = Math.max(stats.depth, leftStats.depth + 1);
366
+ stats.nodeCount += leftStats.nodeCount;
367
+ stats.leafCount += leftStats.leafCount;
368
+ stats.triangleCount += leftStats.triangleCount;
369
+ stats.minTrianglesPerLeaf = Math.min(stats.minTrianglesPerLeaf, leftStats.minTrianglesPerLeaf);
370
+ stats.maxTrianglesPerLeaf = Math.max(stats.maxTrianglesPerLeaf, leftStats.maxTrianglesPerLeaf);
371
+ }
372
+ if (this.right) {
373
+ const rightStats = this.right.getStats();
374
+ stats.depth = Math.max(stats.depth, rightStats.depth + 1);
375
+ stats.nodeCount += rightStats.nodeCount;
376
+ stats.leafCount += rightStats.leafCount;
377
+ stats.triangleCount += rightStats.triangleCount;
378
+ stats.minTrianglesPerLeaf = Math.min(stats.minTrianglesPerLeaf, rightStats.minTrianglesPerLeaf);
379
+ stats.maxTrianglesPerLeaf = Math.max(stats.maxTrianglesPerLeaf, rightStats.maxTrianglesPerLeaf);
380
+ }
381
+ }
382
+ return stats;
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Triangulation for raster reprojection
388
+ *
389
+ * Based on OpenLayers' triangulation approach for efficient raster reprojection.
390
+ * Instead of transforming every pixel, we:
391
+ * 1. Divide the target extent into triangles
392
+ * 2. Transform only triangle vertices with proj4
393
+ * 3. Use affine transformation to map pixels within each triangle
394
+ *
395
+ * This reduces proj4 calls from ~65,536 per tile to ~50-200 per tile.
396
+ */
397
+ function calculateBounds(sourceRef, resolution, targetExtent, transformFn, step = 10) {
398
+ const [west, south, east, north] = targetExtent;
399
+ let minX = Infinity;
400
+ let minY = Infinity;
401
+ let maxX = -Infinity;
402
+ let maxY = -Infinity;
403
+ let minXTarget = [0, 0];
404
+ let minYTarget = [0, 0];
405
+ let maxXTarget = [0, 0];
406
+ let maxYTarget = [0, 0];
407
+ // Funktion zum Abtasten einer Kante
408
+ const sampleEdge = (start, end, steps) => {
409
+ for (let i = 0; i <= steps; i++) {
410
+ const t = i / steps;
411
+ const x = start[0] + (end[0] - start[0]) * t;
412
+ const y = start[1] + (end[1] - start[1]) * t;
413
+ const target = [x, y];
414
+ const [xSrc, ySrc] = transformFn(target);
415
+ if (xSrc < minX) {
416
+ minX = xSrc;
417
+ minXTarget = target;
418
+ }
419
+ if (ySrc < minY) {
420
+ minY = ySrc;
421
+ minYTarget = target;
422
+ }
423
+ if (xSrc > maxX) {
424
+ maxX = xSrc;
425
+ maxXTarget = target;
426
+ }
427
+ if (ySrc > maxY) {
428
+ maxY = ySrc;
429
+ maxYTarget = target;
430
+ }
431
+ }
432
+ };
433
+ // Abtasten aller vier Kanten
434
+ sampleEdge([west, north], [east, north], step); // Top edge
435
+ sampleEdge([east, north], [east, south], step); // Right edge
436
+ sampleEdge([east, south], [west, south], step); // Bottom edge
437
+ sampleEdge([west, south], [west, north], step); // Left edge
438
+ if (sourceRef != null && resolution != null) {
439
+ const minXPix = Math.floor((minX - sourceRef[0]) / resolution);
440
+ minX = sourceRef[0] + minXPix * resolution;
441
+ const minYPix = Math.floor((minY - sourceRef[1]) / resolution);
442
+ minY = sourceRef[1] + minYPix * resolution;
443
+ const maxXPix = Math.ceil((maxX - sourceRef[0]) / resolution);
444
+ maxX = sourceRef[0] + maxXPix * resolution;
445
+ const maxYPix = Math.ceil((maxY - sourceRef[1]) / resolution);
446
+ maxY = sourceRef[1] + maxYPix * resolution;
447
+ }
448
+ return {
449
+ source: {
450
+ minX,
451
+ minY,
452
+ maxX,
453
+ maxY,
454
+ },
455
+ target: {
456
+ minX: minXTarget[0],
457
+ minY: minYTarget[1],
458
+ maxX: maxXTarget[0],
459
+ maxY: maxYTarget[1],
460
+ },
461
+ };
462
+ }
463
+ const MAX_SUBDIVISION = 10;
464
+ /**
465
+ * Class for triangulation of the given target extent
466
+ * Used for determining source data and the reprojection itself
467
+ */
468
+ class Triangulation {
469
+ triangles_ = [];
470
+ transformFn_;
471
+ errorThresholdSquared_;
472
+ bvh_ = null;
473
+ bounds;
474
+ /**
475
+ * @param transformFn - Function that transforms [x, y] from target to source projection
476
+ * @param targetExtent - [west, south, east, north] in target projection
477
+ * @param errorThreshold - Maximum allowed error in pixels (default: 0.5)
478
+ */
479
+ constructor(transformFn, targetExtent, errorThreshold = 0.5, sourceRef = null, resolution = null, step = 10) {
480
+ this.transformFn_ = transformFn;
481
+ this.errorThresholdSquared_ = errorThreshold * errorThreshold;
482
+ const [west, south, east, north] = targetExtent;
483
+ // Transform the four corners
484
+ const a = [west, north]; // top-left
485
+ const b = [east, north]; // top-right
486
+ const c = [east, south]; // bottom-right
487
+ const d = [west, south]; // bottom-left
488
+ const extBounds = calculateBounds(sourceRef, resolution, targetExtent, this.transformFn_, step);
489
+ // const aSrc = this.transformFn_(a);
490
+ // const bSrc = this.transformFn_(b);
491
+ // const cSrc = this.transformFn_(c);
492
+ // const dSrc = this.transformFn_(d);
493
+ const aSrc = [
494
+ extBounds.source.minX,
495
+ extBounds.source.maxY,
496
+ ]; // top-left
497
+ const bSrc = [
498
+ extBounds.source.maxX,
499
+ extBounds.source.maxY,
500
+ ]; // top-right
501
+ const cSrc = [
502
+ extBounds.source.maxX,
503
+ extBounds.source.minY,
504
+ ]; // bottom-right
505
+ const dSrc = [
506
+ extBounds.source.minX,
507
+ extBounds.source.minY,
508
+ ]; // bottom-left
509
+ this.bounds = extBounds.source;
510
+ this.addQuad_(a, b, c, d, aSrc, bSrc, cSrc, dSrc, MAX_SUBDIVISION);
511
+ }
512
+ getBounds() {
513
+ return this.bounds;
514
+ }
515
+ /**
516
+ * Recursively subdivide a quadrilateral if needed
517
+ */
518
+ addQuad_(a, b, c, d, aSrc, bSrc, cSrc, dSrc, maxSubdivision) {
519
+ let needsSubdivision = false;
520
+ // Check if we need to subdivide based on error threshold
521
+ if (maxSubdivision > 0) {
522
+ // Calculate midpoints of all edges (linear interpolation in target space)
523
+ const abTarget = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
524
+ const bcTarget = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2];
525
+ const cdTarget = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2];
526
+ const daTarget = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2];
527
+ // Transform midpoints to source space
528
+ const abSrc = this.transformFn_(abTarget);
529
+ const bcSrc = this.transformFn_(bcTarget);
530
+ const cdSrc = this.transformFn_(cdTarget);
531
+ const daSrc = this.transformFn_(daTarget);
532
+ // Calculate expected midpoints (linear interpolation in source space)
533
+ const abExpected = [
534
+ (aSrc[0] + bSrc[0]) / 2,
535
+ (aSrc[1] + bSrc[1]) / 2,
536
+ ];
537
+ const bcExpected = [
538
+ (bSrc[0] + cSrc[0]) / 2,
539
+ (bSrc[1] + cSrc[1]) / 2,
540
+ ];
541
+ const cdExpected = [
542
+ (cSrc[0] + dSrc[0]) / 2,
543
+ (cSrc[1] + dSrc[1]) / 2,
544
+ ];
545
+ const daExpected = [
546
+ (dSrc[0] + aSrc[0]) / 2,
547
+ (dSrc[1] + aSrc[1]) / 2,
548
+ ];
549
+ // Calculate squared errors
550
+ const abError = this.getSquaredError_(abSrc, abExpected);
551
+ const bcError = this.getSquaredError_(bcSrc, bcExpected);
552
+ const cdError = this.getSquaredError_(cdSrc, cdExpected);
553
+ const daError = this.getSquaredError_(daSrc, daExpected);
554
+ // Check if any edge exceeds error threshold
555
+ if (abError > this.errorThresholdSquared_ ||
556
+ bcError > this.errorThresholdSquared_ ||
557
+ cdError > this.errorThresholdSquared_ ||
558
+ daError > this.errorThresholdSquared_) {
559
+ needsSubdivision = true;
560
+ }
561
+ }
562
+ if (needsSubdivision) {
563
+ // Subdivide into 4 smaller quads
564
+ // Calculate center point
565
+ const eTarget = [
566
+ (a[0] + b[0] + c[0] + d[0]) / 4,
567
+ (a[1] + b[1] + c[1] + d[1]) / 4,
568
+ ];
569
+ const eSrc = this.transformFn_(eTarget);
570
+ // Calculate edge midpoints
571
+ const abTarget = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
572
+ const bcTarget = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2];
573
+ const cdTarget = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2];
574
+ const daTarget = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2];
575
+ const abSrc = this.transformFn_(abTarget);
576
+ const bcSrc = this.transformFn_(bcTarget);
577
+ const cdSrc = this.transformFn_(cdTarget);
578
+ const daSrc = this.transformFn_(daTarget);
579
+ const newMaxSubdivision = maxSubdivision - 1;
580
+ // Recursively add 4 sub-quads
581
+ this.addQuad_(a, abTarget, eTarget, daTarget, aSrc, abSrc, eSrc, daSrc, newMaxSubdivision);
582
+ this.addQuad_(abTarget, b, bcTarget, eTarget, abSrc, bSrc, bcSrc, eSrc, newMaxSubdivision);
583
+ this.addQuad_(eTarget, bcTarget, c, cdTarget, eSrc, bcSrc, cSrc, cdSrc, newMaxSubdivision);
584
+ this.addQuad_(daTarget, eTarget, cdTarget, d, daSrc, eSrc, cdSrc, dSrc, newMaxSubdivision);
585
+ }
586
+ else {
587
+ // No subdivision needed - add two triangles for this quad
588
+ // Triangle 1: a-b-d
589
+ this.addTriangle_(a, b, d, aSrc, bSrc, dSrc);
590
+ // Triangle 2: b-c-d
591
+ this.addTriangle_(b, c, d, bSrc, cSrc, dSrc);
592
+ }
593
+ }
594
+ /**
595
+ * Add a single triangle
596
+ */
597
+ addTriangle_(a, b, c, aSrc, bSrc, cSrc) {
598
+ // Check for non-finite coordinates
599
+ if (!isFinite(aSrc[0]) ||
600
+ !isFinite(aSrc[1]) ||
601
+ !isFinite(bSrc[0]) ||
602
+ !isFinite(bSrc[1]) ||
603
+ !isFinite(cSrc[0]) ||
604
+ !isFinite(cSrc[1])) {
605
+ return; // Skip invalid triangles
606
+ }
607
+ this.triangles_.push({
608
+ source: [aSrc, bSrc, cSrc],
609
+ target: [a, b, c],
610
+ });
611
+ }
612
+ /**
613
+ * Calculate squared error between two points
614
+ */
615
+ getSquaredError_(actual, expected) {
616
+ const dx = actual[0] - expected[0];
617
+ const dy = actual[1] - expected[1];
618
+ return dx * dx + dy * dy;
619
+ }
620
+ /**
621
+ * Get all triangles
622
+ */
623
+ getTriangles() {
624
+ return this.triangles_;
625
+ }
626
+ /**
627
+ * Calculate the bounding extent of all source coordinates
628
+ */
629
+ calculateSourceExtent() {
630
+ if (this.triangles_.length === 0) {
631
+ return null;
632
+ }
633
+ let minX = Infinity;
634
+ let minY = Infinity;
635
+ let maxX = -Infinity;
636
+ let maxY = -Infinity;
637
+ for (const triangle of this.triangles_) {
638
+ for (const [x, y] of triangle.source) {
639
+ if (x < minX)
640
+ minX = x;
641
+ if (x > maxX)
642
+ maxX = x;
643
+ if (y < minY)
644
+ minY = y;
645
+ if (y > maxY)
646
+ maxY = y;
647
+ }
648
+ }
649
+ return [minX, minY, maxX, maxY];
650
+ }
651
+ buildBVH() {
652
+ const triangles2D = this.triangles_.map(BVHNode2D.toTriangle2D);
653
+ this.bvh_ = BVHNode2D.build(triangles2D);
654
+ }
655
+ findSourceTriangleForTargetPoint(point, extraTri = null) {
656
+ if (!this.bvh_)
657
+ this.buildBVH();
658
+ const point2D = { x: point[0], y: point[1] };
659
+ if (extraTri?.tri &&
660
+ BVHNode2D.punktInDreieck2D(point2D, BVHNode2D.toTriangle2D(extraTri.tri))) {
661
+ return extraTri;
662
+ }
663
+ const result = this.bvh_.findContainingTriangle(point2D);
664
+ if (result && !result.transform) {
665
+ result.transform = this.calculateAffineTransform(result.triangle);
666
+ }
667
+ return result
668
+ ? { tri: result.triangle, transform: result.transform }
669
+ : null;
670
+ }
671
+ /**
672
+ * Calculate affine transformation matrix for a triangle
673
+ * Maps from target triangle to source triangle
674
+ */
675
+ calculateAffineTransform(triangle) {
676
+ const [[x0t, y0t], [x1t, y1t], [x2t, y2t]] = triangle.target;
677
+ const [[x0s, y0s], [x1s, y1s], [x2s, y2s]] = triangle.source;
678
+ // Solve for affine transformation: [xs, ys] = [a*xt + b*yt + c, d*xt + e*yt + f]
679
+ // Using the three triangle vertices
680
+ const det = (x1t - x0t) * (y2t - y0t) - (x2t - x0t) * (y1t - y0t);
681
+ if (Math.abs(det) < 1e-10) {
682
+ // Degenerate triangle - return identity-like transform
683
+ return { a: 1, b: 0, c: x0s, d: 0, e: 1, f: y0s };
684
+ }
685
+ const a = ((x1s - x0s) * (y2t - y0t) - (x2s - x0s) * (y1t - y0t)) / det;
686
+ const b = ((x2s - x0s) * (x1t - x0t) - (x1s - x0s) * (x2t - x0t)) / det;
687
+ const c = x0s - a * x0t - b * y0t;
688
+ const d = ((y1s - y0s) * (y2t - y0t) - (y2s - y0s) * (y1t - y0t)) / det;
689
+ const e = ((y2s - y0s) * (x1t - x0t) - (y1s - y0s) * (x2t - x0t)) / det;
690
+ const f = y0s - d * x0t - e * y0t;
691
+ return { a, b, c, d, e, f };
692
+ }
693
+ // ============================================================================
694
+ // REPROJECTION METHODS
695
+ // ============================================================================
696
+ /**
697
+ * Apply affine transformation to a point
698
+ */
699
+ applyAffineTransform(x, y, transform) {
700
+ return [
701
+ transform.a * x + transform.b * y + transform.c,
702
+ transform.d * x + transform.e * y + transform.f,
703
+ ];
704
+ }
705
+ }
706
+
707
+ /**
708
+ * Normalization utilities for raster data
709
+ * Handles conversion of different TypedArray types to normalized 0-255 range
710
+ */
711
+ /**
712
+ * Normalize a raw value to 0-255 range based on array type
713
+ * @param rawValue - The raw value from the raster
714
+ * @param arrayType - The TypedArray type name
715
+ * @returns Normalized value 0-255
716
+ */
717
+ function normalizeValue(rawValue, arrayType) {
718
+ switch (arrayType) {
719
+ case 'Uint8Array':
720
+ return rawValue; // Already 0-255
721
+ case 'Uint16Array':
722
+ // 0-65535 → 0-255
723
+ return Math.round((rawValue / 65535) * 255);
724
+ case 'Int16Array':
725
+ // -32768-32767 → 0-255
726
+ return Math.round(((rawValue + 32768) / 65535) * 255);
727
+ case 'Uint32Array':
728
+ // 0-4294967295 → 0-255
729
+ return Math.round((rawValue / 4294967295) * 255);
730
+ case 'Int32Array':
731
+ // -2147483648-2147483647 → 0-255
732
+ return Math.round(((rawValue + 2147483648) / 4294967295) * 255);
733
+ case 'Float32Array':
734
+ case 'Float64Array':
735
+ // Assume 0.0-1.0 range for Float arrays (common for normalized data)
736
+ // Clamp to [0, 1] first
737
+ const clamped = Math.max(0, Math.min(1, rawValue));
738
+ return Math.round(clamped * 255);
739
+ default:
740
+ messages.warn(`Unknown array type: ${arrayType}, treating as Uint8`);
741
+ return rawValue;
742
+ }
743
+ }
744
+ /**
745
+ * Normalize a raw value to 0-1 range for colormap application
746
+ * @param rawValue - The raw value from the raster
747
+ * @param valueRange - Optional [min, max] range. If not provided, assumes normalized data.
748
+ * @returns Normalized value 0-1
749
+ */
750
+ function normalizeToColorMapRange(rawValue, valueRange) {
751
+ {
752
+ // Assume already normalized or single-value range
753
+ return Math.max(0, Math.min(1, rawValue));
754
+ }
755
+ }
756
+
757
+ /**
758
+ * Nearest-Neighbor Sampling with window-based reading and multi-band support
759
+ * Returns [R, G, B, A] values (0-255)
760
+ */
761
+ function sampleNearest(x, y, rasterBands, arrayType, width, height, offsetX, offsetY, colorStops) {
762
+ const px = Math.round(x) - offsetX;
763
+ const py = Math.round(y) - offsetY;
764
+ if (px < 0 || px >= width || py < 0 || py >= height) {
765
+ return null;
766
+ }
767
+ const idx = py * width + px;
768
+ const bandCount = rasterBands.length;
769
+ if (bandCount === 1) {
770
+ // Grayscale - apply colormap if specified
771
+ const rawValue = rasterBands[0][idx];
772
+ if (colorStops) {
773
+ // Apply colormap (only for Float types or when colorStops provided)
774
+ const normalizedValue = normalizeToColorMapRange(rawValue);
775
+ const [r, g, b] = applyColorMap(normalizedValue, colorStops);
776
+ return [r, g, b, 255];
777
+ }
778
+ else {
779
+ // Regular grayscale normalization
780
+ const gray = normalizeValue(rawValue, arrayType);
781
+ return [gray, gray, gray, 255];
782
+ }
783
+ }
784
+ else if (bandCount === 3) {
785
+ // RGB
786
+ const r = normalizeValue(rasterBands[0][idx], arrayType);
787
+ const g = normalizeValue(rasterBands[1][idx], arrayType);
788
+ const b = normalizeValue(rasterBands[2][idx], arrayType);
789
+ return [r, g, b, 255];
790
+ }
791
+ else if (bandCount >= 4) {
792
+ // RGBA
793
+ const r = normalizeValue(rasterBands[0][idx], arrayType);
794
+ const g = normalizeValue(rasterBands[1][idx], arrayType);
795
+ const b = normalizeValue(rasterBands[2][idx], arrayType);
796
+ const a = normalizeValue(rasterBands[3][idx], arrayType);
797
+ return [r, g, b, a];
798
+ }
799
+ return null;
800
+ }
801
+ /**
802
+ * Bilinear Interpolation with window-based reading and multi-band support
803
+ * Returns [R, G, B, A] values (0-255)
804
+ */
805
+ function sampleBilinear(x, y, rasterBands, arrayType, width, height, offsetX, offsetY, colorStops) {
806
+ const localX = x - offsetX;
807
+ const localY = y - offsetY;
808
+ // Bounds-Check
809
+ if (localX < 0 ||
810
+ localX >= width - 1 ||
811
+ localY < 0 ||
812
+ localY >= height - 1) {
813
+ return null;
814
+ }
815
+ // Bilineare Interpolation
816
+ const x0 = Math.floor(localX);
817
+ const x1 = Math.ceil(localX);
818
+ const y0 = Math.floor(localY);
819
+ const y1 = Math.ceil(localY);
820
+ const fx = localX - x0;
821
+ const fy = localY - y0;
822
+ const bandCount = rasterBands.length;
823
+ const result = [0, 0, 0, 255];
824
+ if (bandCount === 1) {
825
+ // Grayscale - interpolate first, then apply colormap
826
+ const band = rasterBands[0];
827
+ const v00 = band[y0 * width + x0];
828
+ const v10 = band[y0 * width + x1];
829
+ const v01 = band[y1 * width + x0];
830
+ const v11 = band[y1 * width + x1];
831
+ const v0 = v00 * (1 - fx) + v10 * fx;
832
+ const v1 = v01 * (1 - fx) + v11 * fx;
833
+ const interpolated = v0 * (1 - fy) + v1 * fy;
834
+ if (colorStops) {
835
+ // Apply colormap (only for Float types or when colorStops provided)
836
+ const normalizedValue = normalizeToColorMapRange(interpolated);
837
+ const [r, g, b] = applyColorMap(normalizedValue, colorStops);
838
+ return [r, g, b, 255];
839
+ }
840
+ else {
841
+ // Regular grayscale normalization
842
+ const gray = normalizeValue(interpolated, arrayType);
843
+ return [gray, gray, gray, 255];
844
+ }
845
+ }
846
+ else {
847
+ // RGB/RGBA - interpolate each band
848
+ const bandsToProcess = Math.min(bandCount, 4);
849
+ for (let b = 0; b < bandsToProcess; b++) {
850
+ const band = rasterBands[b];
851
+ const v00 = band[y0 * width + x0];
852
+ const v10 = band[y0 * width + x1];
853
+ const v01 = band[y1 * width + x0];
854
+ const v11 = band[y1 * width + x1];
855
+ const v0 = v00 * (1 - fx) + v10 * fx;
856
+ const v1 = v01 * (1 - fx) + v11 * fx;
857
+ const interpolated = v0 * (1 - fy) + v1 * fy;
858
+ result[b] = normalizeValue(interpolated, arrayType);
859
+ }
860
+ }
861
+ return result;
862
+ }
863
+
864
+ /**
865
+ * Processes GeoTIFF tiles with triangulation-based reprojection
866
+ *
867
+ * This class encapsulates the tile rendering logic using triangulation
868
+ * for efficient reprojection from arbitrary source projections to Web Mercator.
869
+ */
870
+ class GeoTIFFTileProcessor {
871
+ // Configuration
872
+ config;
873
+ worldSize = 40075016.686; // Earth circumference in meters (Web Mercator)
874
+ // Global triangulation for the entire image (created once)
875
+ globalTriangulation;
876
+ constructor(config) {
877
+ this.config = config;
878
+ if (config.worldSize) {
879
+ this.worldSize = config.worldSize;
880
+ }
881
+ }
882
+ /**
883
+ * Create global triangulation for the entire GeoTIFF image
884
+ * This is called once to avoid recreating triangulation for every tile
885
+ */
886
+ createGlobalTriangulation() {
887
+ const startTime = performance.now();
888
+ const [srcWest, srcSouth, srcEast, srcNorth] = this.config.sourceBounds;
889
+ // Transform source corners to target projection (Mercator)
890
+ const transformFnToProj = (coord) => {
891
+ return this.config.transformSourceMapToViewFn(coord);
892
+ };
893
+ const { source: bounds } = calculateBounds(null, null, [srcWest, srcSouth, srcEast, srcNorth], transformFnToProj);
894
+ const mercatorBounds = [
895
+ bounds.minX,
896
+ bounds.minY,
897
+ bounds.maxX,
898
+ bounds.maxY,
899
+ ];
900
+ messages.log('Creating global triangulation for bounds:', {
901
+ source: this.config.sourceBounds,
902
+ mercator: mercatorBounds,
903
+ });
904
+ // Inverse transformation: from target (Mercator) back to source
905
+ const inverseTransformFn = (coord) => {
906
+ return this.config.transformViewToSourceMapFn(coord);
907
+ };
908
+ // Use adaptive error threshold based on pixel resolution
909
+ const errorThreshold = this.config.resolution / 2.0;
910
+ const step = Math.min(10, Math.max(this.config.imageWidth, this.config.imageHeight) / 256);
911
+ this.globalTriangulation = new Triangulation(inverseTransformFn, mercatorBounds, errorThreshold, this.config.sourceRef, this.config.resolution, step);
912
+ // Force indexing
913
+ this.globalTriangulation.findSourceTriangleForTargetPoint([0, 0]);
914
+ const triangles = this.globalTriangulation.getTriangles();
915
+ messages.log(`Global triangulation created: ${triangles.length} triangles in ${(performance.now() - startTime).toFixed(2)}ms`);
916
+ }
917
+ /**
918
+ * Get the global triangulation (may be undefined if not created yet)
919
+ */
920
+ getGlobalTriangulation() {
921
+ return this.globalTriangulation;
922
+ }
923
+ /**
924
+ * Normalize terrain samples so mesh generation does not create spikes
925
+ * for nodata or otherwise invalid height values.
926
+ */
927
+ sanitizeElevationValue(value) {
928
+ if (!Number.isFinite(value)) {
929
+ return 0;
930
+ }
931
+ if (this.config.noDataValue !== undefined &&
932
+ value === this.config.noDataValue) {
933
+ return 0;
934
+ }
935
+ return value;
936
+ }
937
+ /**
938
+ * Calculate tile size in meters for a given zoom level
939
+ */
940
+ getTileSizeInMeter(z) {
941
+ return this.worldSize / Math.pow(2, z);
942
+ }
943
+ /**
944
+ * Convert tile coordinates to View projection bounds
945
+ * For Web Mercator (deck.gl/Leaflet/Cesium): returns bounds in meters
946
+ * Note: This assumes Web Mercator tiling scheme. Override for other projections.
947
+ */
948
+ getTileBounds(x, y, z) {
949
+ const tileSize = this.getTileSizeInMeter(z);
950
+ const west = -this.worldSize / 2 + x * tileSize;
951
+ const north = this.worldSize / 2 - y * tileSize;
952
+ const east = west + tileSize;
953
+ const south = north - tileSize;
954
+ return [west, south, east, north];
955
+ }
956
+ /**
957
+ * Select best overview image based on zoom level
958
+ */
959
+ selectOverviewImage(z, tileSize) {
960
+ const baseResolution = this.config.baseImage.getResolution()[0];
961
+ if (!this.config.overviewImages ||
962
+ this.config.overviewImages.length === 0) {
963
+ return {
964
+ bestImage: this.config.baseImage,
965
+ bestResolution: baseResolution,
966
+ imageLevel: 0,
967
+ };
968
+ }
969
+ const tileSizeInMeter = this.getTileSizeInMeter(z);
970
+ const tileResolution = tileSizeInMeter / tileSize;
971
+ // Check base image and all overviews
972
+ const allImages = [this.config.baseImage, ...this.config.overviewImages];
973
+ const maxResImage = allImages[this.config.overviewImages.length];
974
+ const maxResolution = baseResolution * Math.pow(2, this.config.overviewImages.length);
975
+ let imageLevel = this.config.overviewImages.length;
976
+ let bestResolution = maxResolution;
977
+ let bestImage = maxResImage;
978
+ let levelCounter = 0;
979
+ let resolution = baseResolution;
980
+ for (const img of allImages) {
981
+ const ratio = tileResolution / (resolution * 2.0);
982
+ if (ratio <= 1.0) {
983
+ bestImage = img;
984
+ bestResolution = resolution;
985
+ imageLevel = levelCounter;
986
+ break;
987
+ }
988
+ levelCounter++;
989
+ resolution = resolution * 2;
990
+ }
991
+ return { bestImage, bestResolution, imageLevel };
992
+ }
993
+ /**
994
+ * Calculate source bounds for a tile after transformation
995
+ * @param viewBounds - Tile bounds in View projection
996
+ */
997
+ calculateTileSourceBounds(viewBounds) {
998
+ const [viewWest, viewSouth, viewEast, viewNorth] = viewBounds;
999
+ const { source: bounds } = calculateBounds(this.config.sourceRef, this.config.resolution, [viewWest, viewSouth, viewEast, viewNorth], this.config.transformViewToSourceMapFn);
1000
+ // Transform tile corners from View to Source projection
1001
+ const sw = this.config.transformViewToSourceMapFn([viewWest, viewSouth]);
1002
+ const ne = this.config.transformViewToSourceMapFn([viewEast, viewNorth]);
1003
+ const nw = this.config.transformViewToSourceMapFn([viewWest, viewNorth]);
1004
+ const se = this.config.transformViewToSourceMapFn([viewEast, viewSouth]);
1005
+ // Calculate bounding box from transformed corners
1006
+ const tileSrcWest = Math.min(bounds.minX, sw[0], ne[0], nw[0], se[0]);
1007
+ const tileSrcEast = Math.max(bounds.maxX, sw[0], ne[0], nw[0], se[0]);
1008
+ const tileSrcSouth = Math.min(bounds.minY, sw[1], ne[1], nw[1], se[1]);
1009
+ const tileSrcNorth = Math.max(bounds.maxY, sw[1], ne[1], nw[1], se[1]);
1010
+ return { tileSrcWest, tileSrcEast, tileSrcSouth, tileSrcNorth };
1011
+ }
1012
+ /**
1013
+ * Calculate pixel window for reading from GeoTIFF
1014
+ */
1015
+ calculateReadWindow(tileSrcBounds, ovWidth, ovHeight) {
1016
+ const [srcWest, srcSouth, srcEast, srcNorth] = this.config.sourceBounds;
1017
+ const srcWidth = srcEast - srcWest;
1018
+ const srcHeight = srcNorth - srcSouth;
1019
+ const { tileSrcWest, tileSrcEast, tileSrcSouth, tileSrcNorth } = tileSrcBounds;
1020
+ // Calculate pixel window for this tile area
1021
+ const pixelXMin = Math.floor(((tileSrcWest - srcWest) / srcWidth) * ovWidth);
1022
+ const pixelXMax = Math.ceil(((tileSrcEast - srcWest) / srcWidth) * ovWidth);
1023
+ const pixelYMin = Math.floor(((srcNorth - tileSrcNorth) / srcHeight) * ovHeight);
1024
+ const pixelYMax = Math.ceil(((srcNorth - tileSrcSouth) / srcHeight) * ovHeight);
1025
+ // Bounds check with 2-pixel padding
1026
+ const readXMin = Math.min(ovWidth, Math.max(0, pixelXMin - 2));
1027
+ const readXMax = Math.max(0, Math.min(ovWidth, pixelXMax + 2));
1028
+ const readYMin = Math.min(ovHeight, Math.max(0, pixelYMin - 2));
1029
+ const readYMax = Math.max(0, Math.min(ovHeight, pixelYMax + 2));
1030
+ const readWidth = readXMax - readXMin;
1031
+ const readHeight = readYMax - readYMin;
1032
+ if (readWidth <= 0 || readHeight <= 0) {
1033
+ messages.warn('Invalid read window for tile', {
1034
+ readXMin,
1035
+ readXMax,
1036
+ readYMin,
1037
+ readYMax,
1038
+ ovWidth,
1039
+ ovHeight,
1040
+ });
1041
+ return null;
1042
+ }
1043
+ return {
1044
+ readXMin,
1045
+ readXMax,
1046
+ readYMin,
1047
+ readYMax,
1048
+ readWidth,
1049
+ readHeight,
1050
+ };
1051
+ }
1052
+ /**
1053
+ * Load and convert raster data from GeoTIFF image
1054
+ */
1055
+ async loadAndConvertRasterData(image, readWindow) {
1056
+ const { readXMin, readYMin, readXMax, readYMax } = readWindow;
1057
+ let rasters = null;
1058
+ let lasterr = null;
1059
+ for (let i = 0; i <= 2; i++) {
1060
+ try {
1061
+ // Read only the needed area from GeoTIFF (COG-optimized!)
1062
+ rasters = await image.readRasters({
1063
+ window: [readXMin, readYMin, readXMax, readYMax],
1064
+ });
1065
+ }
1066
+ catch (err) {
1067
+ // warn('Error - readRasters - read window: ', readWindow);
1068
+ lasterr = err;
1069
+ }
1070
+ if (rasters != null) {
1071
+ lasterr = null;
1072
+ break;
1073
+ }
1074
+ }
1075
+ if (lasterr != null) {
1076
+ messages.log(lasterr);
1077
+ messages.warn('Error - readRasters - read window: ', readWindow);
1078
+ throw lasterr;
1079
+ }
1080
+ // Convert to TypedArray array and detect type
1081
+ const rasterBands = [];
1082
+ let arrayType = '';
1083
+ for (let i = 0; i < rasters.length; i++) {
1084
+ const raster = rasters[i];
1085
+ if (typeof raster === 'number') {
1086
+ messages.warn('Unexpected number in rasters array');
1087
+ continue;
1088
+ }
1089
+ rasterBands.push(raster);
1090
+ if (i === 0) {
1091
+ arrayType = raster.constructor.name;
1092
+ }
1093
+ }
1094
+ return { rasterBands, arrayType };
1095
+ }
1096
+ /**
1097
+ * Render tile pixels using triangulation-based reprojection
1098
+ */
1099
+ renderTilePixels(params) {
1100
+ const { sampleSize, mercatorBounds, triangulation, rasterBands, arrayType, readWindow, ovWidth, ovHeight, resampleMethod, colorStops, } = params;
1101
+ const [mercWest, mercSouth, mercEast, mercNorth] = mercatorBounds;
1102
+ const [srcWest, srcSouth, srcEast, srcNorth] = this.config.sourceBounds;
1103
+ const srcWidth = srcEast - srcWest;
1104
+ const srcHeight = srcNorth - srcSouth;
1105
+ const outputData = new Uint8ClampedArray(sampleSize * sampleSize * 4); // RGBA
1106
+ let tri = null;
1107
+ for (let py = 0; py < sampleSize; py++) {
1108
+ for (let px = 0; px < sampleSize; px++) {
1109
+ const idx = (py * sampleSize + px) * 4; // RGBA index
1110
+ // Pixel position in Mercator
1111
+ const mercX = mercWest + (px / sampleSize) * (mercEast - mercWest);
1112
+ const mercY = mercNorth - (py / sampleSize) * (mercNorth - mercSouth);
1113
+ // Find triangle containing this pixel
1114
+ const targetPoint = [mercX, mercY];
1115
+ tri = triangulation.findSourceTriangleForTargetPoint(targetPoint, tri);
1116
+ if (tri) {
1117
+ // Transform using affine transformation
1118
+ const [srcX, srcY] = triangulation.applyAffineTransform(mercX, mercY, tri.transform);
1119
+ // Check if point is within source bounds
1120
+ if (srcX < srcWest ||
1121
+ srcX > srcEast ||
1122
+ srcY < srcSouth ||
1123
+ srcY > srcNorth) {
1124
+ // Outside bounds - transparent
1125
+ outputData[idx] = 0;
1126
+ outputData[idx + 1] = 0;
1127
+ outputData[idx + 2] = 0;
1128
+ outputData[idx + 3] = 0;
1129
+ }
1130
+ else {
1131
+ // Convert source coordinates to pixel coordinates (in overview image)
1132
+ const imgX = ((srcX - srcWest) / srcWidth) * ovWidth;
1133
+ const imgY = ((srcNorth - srcY) / srcHeight) * ovHeight;
1134
+ // Sample pixel from source raster
1135
+ const rgba = resampleMethod === 'near'
1136
+ ? sampleNearest(imgX, imgY, rasterBands, arrayType, readWindow.readWidth, readWindow.readHeight, readWindow.readXMin, readWindow.readYMin, colorStops)
1137
+ : sampleBilinear(imgX, imgY, rasterBands, arrayType, readWindow.readWidth, readWindow.readHeight, readWindow.readXMin, readWindow.readYMin, colorStops);
1138
+ if (rgba) {
1139
+ outputData[idx] = rgba[0];
1140
+ outputData[idx + 1] = rgba[1];
1141
+ outputData[idx + 2] = rgba[2];
1142
+ outputData[idx + 3] = rgba[3];
1143
+ }
1144
+ else {
1145
+ // No data
1146
+ outputData[idx] = 0;
1147
+ outputData[idx + 1] = 0;
1148
+ outputData[idx + 2] = 0;
1149
+ outputData[idx + 3] = 0;
1150
+ }
1151
+ }
1152
+ }
1153
+ else {
1154
+ // Pixel not in any triangle (should not happen)
1155
+ outputData[idx] = 0;
1156
+ outputData[idx + 1] = 0;
1157
+ outputData[idx + 2] = 0;
1158
+ outputData[idx + 3] = 0;
1159
+ }
1160
+ }
1161
+ }
1162
+ return outputData;
1163
+ }
1164
+ /**
1165
+ * Check if tile intersects with GeoTIFF source bounds
1166
+ * @param viewBounds - Tile bounds in View projection (e.g., Web Mercator for deck.gl/Leaflet/Cesium)
1167
+ */
1168
+ tileIntersectsSource(viewBounds) {
1169
+ const [viewWest, viewSouth, viewEast, viewNorth] = viewBounds;
1170
+ const [srcWest, srcSouth, srcEast, srcNorth] = this.config.sourceBounds;
1171
+ // Transform tile corners from View to Source projection
1172
+ const sw = this.config.transformViewToSourceMapFn([viewWest, viewSouth]);
1173
+ const ne = this.config.transformViewToSourceMapFn([viewEast, viewNorth]);
1174
+ const nw = this.config.transformViewToSourceMapFn([viewWest, viewNorth]);
1175
+ const se = this.config.transformViewToSourceMapFn([viewEast, viewSouth]);
1176
+ // Calculate bounding box of transformed tile in source projection
1177
+ const tileMinX = Math.min(sw[0], ne[0], nw[0], se[0]);
1178
+ const tileMaxX = Math.max(sw[0], ne[0], nw[0], se[0]);
1179
+ const tileMinY = Math.min(sw[1], ne[1], nw[1], se[1]);
1180
+ const tileMaxY = Math.max(sw[1], ne[1], nw[1], se[1]);
1181
+ // Check for intersection
1182
+ const intersects = tileMaxX >= srcWest &&
1183
+ tileMinX <= srcEast &&
1184
+ tileMaxY >= srcSouth &&
1185
+ tileMinY <= srcNorth;
1186
+ return intersects;
1187
+ }
1188
+ /**
1189
+ * Generate tile data with triangulation-based reprojection
1190
+ *
1191
+ * This is the main method that orchestrates the entire tile rendering process.
1192
+ */
1193
+ async getTileData(params) {
1194
+ const { x, y, z, tileSize, resolution, resampleMethod, colorStops } = params;
1195
+ // 1. Calculate View projection bounds for the tile
1196
+ const viewBounds = this.getTileBounds(x, y, z);
1197
+ messages.log(`v-map - geotiff - getTileData(${x},${y},${z}): viewBounds=[${viewBounds.map(v => v.toFixed(0)).join(',')}], sourceBounds=[${this.config.sourceBounds.map(v => v.toFixed(0)).join(',')}], toProjection=${this.config.toProjection}`);
1198
+ // 2. Early exit: Check if tile intersects with source bounds
1199
+ if (!this.tileIntersectsSource(viewBounds)) {
1200
+ // Tile is completely outside source bounds - return transparent tile
1201
+ messages.log(`v-map - geotiff - getTileData(${x},${y},${z}): no intersection, returning transparent`);
1202
+ const sampleSize = Math.ceil(tileSize * resolution);
1203
+ return new Uint8ClampedArray(sampleSize * sampleSize * 4);
1204
+ }
1205
+ // 3. Calculate sampling resolution
1206
+ const sampleSize = Math.ceil(tileSize * resolution);
1207
+ // 4. Get or create triangulation
1208
+ let triangulation;
1209
+ if (!this.globalTriangulation) {
1210
+ messages.warn('Global triangulation not available, creating fallback for tile');
1211
+ triangulation = new Triangulation(this.config.transformViewToSourceMapFn, viewBounds, 0.5);
1212
+ }
1213
+ else {
1214
+ triangulation = this.globalTriangulation;
1215
+ }
1216
+ // 5. Calculate source bounds for this tile
1217
+ const tileSrcBounds = this.calculateTileSourceBounds(viewBounds);
1218
+ // 6. Select best overview image based on zoom
1219
+ const { bestImage, bestResolution, imageLevel } = this.selectOverviewImage(z, tileSize);
1220
+ const ovWidth = bestImage.getWidth();
1221
+ const ovHeight = bestImage.getHeight();
1222
+ // 7. Calculate pixel window for reading
1223
+ const readWindow = this.calculateReadWindow(tileSrcBounds, ovWidth, ovHeight);
1224
+ if (!readWindow) {
1225
+ return new Uint8ClampedArray(sampleSize * sampleSize * 4);
1226
+ }
1227
+ // 8. Load and convert raster data
1228
+ const { rasterBands, arrayType } = await this.loadAndConvertRasterData(bestImage, readWindow);
1229
+ const bandCount = rasterBands.length;
1230
+ messages.log(`Read window: [${readWindow.readXMin}, ${readWindow.readYMin}, ${readWindow.readXMax}, ${readWindow.readYMax}] (${readWindow.readWidth}x${readWindow.readHeight} pixels), ${bandCount} bands, type: ${arrayType}, imageLevel: ${imageLevel}, resolution: ${bestResolution}`);
1231
+ // 9. Render tile pixels
1232
+ const outputData = this.renderTilePixels({
1233
+ sampleSize,
1234
+ mercatorBounds: viewBounds, // Pass View bounds (kept name for backward compat)
1235
+ triangulation,
1236
+ rasterBands,
1237
+ arrayType,
1238
+ readWindow,
1239
+ ovWidth,
1240
+ ovHeight,
1241
+ resampleMethod,
1242
+ colorStops,
1243
+ });
1244
+ return outputData;
1245
+ }
1246
+ /**
1247
+ * Get raw elevation values for a tile as Float32Array.
1248
+ *
1249
+ * Returns a (tileSize+1) × (tileSize+1) float array suitable for Martini
1250
+ * terrain mesh generation. Border pixels are backfilled for Martini compatibility.
1251
+ * Band 0 of the GeoTIFF is used as the elevation source.
1252
+ */
1253
+ async getElevationData(params) {
1254
+ const { x, y, z, tileSize } = params;
1255
+ const gridSize = tileSize + 1; // Martini requires (2^n + 1)^2 grid
1256
+ const viewBounds = this.getTileBounds(x, y, z);
1257
+ if (!this.tileIntersectsSource(viewBounds)) {
1258
+ return new Float32Array(gridSize * gridSize);
1259
+ }
1260
+ let triangulation;
1261
+ if (!this.globalTriangulation) {
1262
+ messages.warn('Global triangulation not available, creating fallback for elevation tile');
1263
+ triangulation = new Triangulation(this.config.transformViewToSourceMapFn, viewBounds, 0.5);
1264
+ }
1265
+ else {
1266
+ triangulation = this.globalTriangulation;
1267
+ }
1268
+ const tileSrcBounds = this.calculateTileSourceBounds(viewBounds);
1269
+ const { bestImage } = this.selectOverviewImage(z, tileSize);
1270
+ const ovWidth = bestImage.getWidth();
1271
+ const ovHeight = bestImage.getHeight();
1272
+ const readWindow = this.calculateReadWindow(tileSrcBounds, ovWidth, ovHeight);
1273
+ if (!readWindow) {
1274
+ return new Float32Array(gridSize * gridSize);
1275
+ }
1276
+ const { rasterBands } = await this.loadAndConvertRasterData(bestImage, readWindow);
1277
+ const [mercWest, mercSouth, mercEast, mercNorth] = viewBounds;
1278
+ const [srcWest, srcSouth, srcEast, srcNorth] = this.config.sourceBounds;
1279
+ const srcWidth = srcEast - srcWest;
1280
+ const srcHeight = srcNorth - srcSouth;
1281
+ const output = new Float32Array(gridSize * gridSize);
1282
+ let tri = null;
1283
+ for (let py = 0; py < tileSize; py++) {
1284
+ for (let px = 0; px < tileSize; px++) {
1285
+ const mercX = mercWest + (px / tileSize) * (mercEast - mercWest);
1286
+ const mercY = mercNorth - (py / tileSize) * (mercNorth - mercSouth);
1287
+ const targetPoint = [mercX, mercY];
1288
+ tri = triangulation.findSourceTriangleForTargetPoint(targetPoint, tri);
1289
+ if (tri) {
1290
+ const [srcX, srcY] = triangulation.applyAffineTransform(mercX, mercY, tri.transform);
1291
+ if (srcX >= srcWest && srcX <= srcEast && srcY >= srcSouth && srcY <= srcNorth) {
1292
+ const imgX = ((srcX - srcWest) / srcWidth) * ovWidth;
1293
+ const imgY = ((srcNorth - srcY) / srcHeight) * ovHeight;
1294
+ const sampleX = Math.round(imgX) - readWindow.readXMin;
1295
+ const sampleY = Math.round(imgY) - readWindow.readYMin;
1296
+ if (sampleX >= 0 && sampleX < readWindow.readWidth &&
1297
+ sampleY >= 0 && sampleY < readWindow.readHeight) {
1298
+ const sampleValue = Number(rasterBands[0][sampleY * readWindow.readWidth + sampleX]);
1299
+ output[py * gridSize + px] =
1300
+ this.sanitizeElevationValue(sampleValue);
1301
+ }
1302
+ }
1303
+ }
1304
+ }
1305
+ }
1306
+ // Backfill right border column (Martini requirement)
1307
+ for (let row = 0; row < tileSize; row++) {
1308
+ output[row * gridSize + tileSize] = output[row * gridSize + tileSize - 1];
1309
+ }
1310
+ // Backfill bottom border row (Martini requirement)
1311
+ for (let col = 0; col <= tileSize; col++) {
1312
+ output[tileSize * gridSize + col] = output[(tileSize - 1) * gridSize + col];
1313
+ }
1314
+ return output;
1315
+ }
1316
+ }
1317
+ async function getTileProcessorConfig(tiffSource, viewProjection) {
1318
+ const { default: proj4 } = await Promise.resolve().then(function () { return require('./index-B1oGO1g-.js'); });
1319
+ // Transform from View projection to Source projection
1320
+ const transformViewToSourceMapFn = (coord) => {
1321
+ const result = proj4(viewProjection, tiffSource.fromProjection, coord);
1322
+ return [Number(result[0]), Number(result[1])];
1323
+ };
1324
+ // Inverse: Transform from Source projection to View projection
1325
+ const transformSourceMapToViewFn = (coord) => {
1326
+ const result = proj4(tiffSource.fromProjection, viewProjection, coord);
1327
+ return [Number(result[0]), Number(result[1])];
1328
+ };
1329
+ const config = {
1330
+ transformViewToSourceMapFn,
1331
+ transformSourceMapToViewFn,
1332
+ sourceBounds: tiffSource.sourceBounds,
1333
+ sourceRef: tiffSource.sourceRef,
1334
+ resolution: tiffSource.resolution,
1335
+ imageWidth: tiffSource.width,
1336
+ imageHeight: tiffSource.height,
1337
+ fromProjection: tiffSource.fromProjection,
1338
+ toProjection: viewProjection,
1339
+ baseImage: tiffSource.baseImage,
1340
+ overviewImages: tiffSource.overviewImages ?? [],
1341
+ noDataValue: tiffSource.noDataValue,
1342
+ };
1343
+ return config;
1344
+ }
1345
+
1346
+ //const DEFAULT_TO_PROJECTION = 'EPSG:3857';
1347
+ async function loadGeoTIFFSource(url, options, deps) {
1348
+ const { geotiff, proj4, geokeysToProj4 } = deps;
1349
+ const { fromUrl } = geotiff;
1350
+ const { toProj4 } = geokeysToProj4;
1351
+ let tiff = null;
1352
+ let lasterr = null;
1353
+ for (let i = 0; i <= 2; i++) {
1354
+ try {
1355
+ tiff = await fromUrl(url, {
1356
+ allowFullFile: true,
1357
+ blockSize: 1024 * 1024, // 1MB blocks to reduce HTTP range-request count for non-COG files
1358
+ cacheSize: 100,
1359
+ });
1360
+ }
1361
+ catch (err) {
1362
+ lasterr = err;
1363
+ }
1364
+ if (tiff != null) {
1365
+ lasterr = null;
1366
+ break;
1367
+ }
1368
+ }
1369
+ if (lasterr != null) {
1370
+ messages.log(lasterr);
1371
+ messages.warn('Error - loadGeoTIFFSource - fromUrl: ', url);
1372
+ throw lasterr;
1373
+ }
1374
+ const baseImage = await tiff.getImage(0);
1375
+ const imageCount = await tiff.getImageCount();
1376
+ const overviewImages = [];
1377
+ for (let i = 1; i < imageCount; i++) {
1378
+ overviewImages.push(await tiff.getImage(i));
1379
+ }
1380
+ const width = baseImage.getWidth();
1381
+ const height = baseImage.getHeight();
1382
+ const samplesPerPixel = Math.max(1, baseImage.getSamplesPerPixel?.() ?? 1);
1383
+ let fromProjection = options.forceProjection && options.projection
1384
+ ? options.projection
1385
+ : options.projection ?? 'EPSG:4326';
1386
+ let proj4String = null;
1387
+ if (!options.forceProjection) {
1388
+ const geoKeys = typeof baseImage.getGeoKeys === 'function'
1389
+ ? baseImage.getGeoKeys() ?? null
1390
+ : null;
1391
+ if (geoKeys) {
1392
+ try {
1393
+ const projParams = toProj4(geoKeys);
1394
+ const epsg = geoKeys.ProjectedCSTypeGeoKey ?? geoKeys.GeographicTypeGeoKey;
1395
+ if (epsg) {
1396
+ fromProjection = `EPSG:${epsg}`;
1397
+ }
1398
+ if (projParams?.proj4) {
1399
+ proj4String = projParams.proj4;
1400
+ const numericCode = String(epsg);
1401
+ if (epsg && !proj4.defs(fromProjection)) {
1402
+ proj4.defs(fromProjection, projParams.proj4);
1403
+ }
1404
+ if (epsg && !proj4.defs(numericCode)) {
1405
+ proj4.defs(numericCode, projParams.proj4);
1406
+ }
1407
+ }
1408
+ }
1409
+ catch (err) {
1410
+ messages.warn('v-map - geotiff - failed to parse GeoKeys', err);
1411
+ }
1412
+ }
1413
+ }
1414
+ if (!proj4String) {
1415
+ switch (fromProjection) {
1416
+ case 'EPSG:4326':
1417
+ proj4String = '+proj=longlat +datum=WGS84 +no_defs';
1418
+ break;
1419
+ case 'EPSG:3857':
1420
+ proj4String =
1421
+ '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs';
1422
+ break;
1423
+ case 'EPSG:32632':
1424
+ proj4String = '+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs';
1425
+ break;
1426
+ }
1427
+ }
1428
+ if (!fromProjection || fromProjection.trim() === '') {
1429
+ fromProjection = 'EPSG:4326';
1430
+ }
1431
+ if (proj4String && !proj4.defs(fromProjection)) {
1432
+ proj4.defs(fromProjection, proj4String);
1433
+ }
1434
+ const sourceBounds = baseImage.getBoundingBox();
1435
+ const sourceRef = [sourceBounds[0], sourceBounds[1]];
1436
+ const resolution = baseImage.getResolution()[0];
1437
+ const rawNoData = options.nodata !== undefined && options.nodata !== null
1438
+ ? Number(options.nodata)
1439
+ : typeof baseImage.getGDALNoData === 'function'
1440
+ ? baseImage.getGDALNoData()
1441
+ : undefined;
1442
+ const noDataValue = rawNoData !== undefined && rawNoData !== null
1443
+ ? Number(rawNoData)
1444
+ : undefined;
1445
+ const clampLon = (lon) => Math.max(-180, Math.min(180, Number.isFinite(lon) ? lon : 0));
1446
+ const clampLat = (lat) => Math.max(-90, Math.min(90, Number.isFinite(lat) ? lat : 0));
1447
+ let transformToWgs84;
1448
+ if (!fromProjection || fromProjection === 'EPSG:4326') {
1449
+ transformToWgs84 = coord => coord;
1450
+ }
1451
+ else {
1452
+ transformToWgs84 = (coord) => {
1453
+ try {
1454
+ const result = proj4(fromProjection, 'EPSG:4326', coord);
1455
+ return [Number(result[0]), Number(result[1])];
1456
+ }
1457
+ catch (err) {
1458
+ messages.warn('v-map - geotiff - transform to WGS84 failed, falling back', err);
1459
+ return coord;
1460
+ }
1461
+ };
1462
+ }
1463
+ const [minX, minY, maxX, maxY] = sourceBounds;
1464
+ const corners = [
1465
+ transformToWgs84([minX, minY]),
1466
+ transformToWgs84([maxX, minY]),
1467
+ transformToWgs84([maxX, maxY]),
1468
+ transformToWgs84([minX, maxY]),
1469
+ ];
1470
+ const west = clampLon(Math.min(...corners.map(c => c[0])));
1471
+ const east = clampLon(Math.max(...corners.map(c => c[0])));
1472
+ const south = clampLat(Math.min(...corners.map(c => c[1])));
1473
+ const north = clampLat(Math.max(...corners.map(c => c[1])));
1474
+ messages.log('v-map - geotiff - loaded source', {
1475
+ url,
1476
+ width,
1477
+ height,
1478
+ samplesPerPixel,
1479
+ fromProjection,
1480
+ bounds: sourceBounds,
1481
+ });
1482
+ return {
1483
+ tiff,
1484
+ baseImage,
1485
+ overviewImages,
1486
+ width,
1487
+ height,
1488
+ samplesPerPixel,
1489
+ fromProjection,
1490
+ //toProjection: DEFAULT_TO_PROJECTION,
1491
+ sourceBounds,
1492
+ sourceRef,
1493
+ resolution,
1494
+ proj4,
1495
+ noDataValue,
1496
+ wgs84Bounds: [west, south, east, north],
1497
+ transformToWgs84,
1498
+ };
1499
+ }
1500
+ async function getGeoTIFFSource(url, projection, forceProjection, nodata) {
1501
+ const [geotiffModule, { default: proj4 }, geokeysModule] = await Promise.all([
1502
+ Promise.resolve().then(function () { return require('./geotiff-CEwvF9cG.js'); }).then(function (n) { return n.geotiff; }),
1503
+ Promise.resolve().then(function () { return require('./index-B1oGO1g-.js'); }),
1504
+ Promise.resolve().then(function () { return require('./main-dist-7TykwFci.js'); }).then(function (n) { return n.mainDist; }),
1505
+ ]);
1506
+ const source = await loadGeoTIFFSource(url, {
1507
+ projection: projection,
1508
+ forceProjection: forceProjection,
1509
+ nodata: nodata,
1510
+ }, {
1511
+ geotiff: geotiffModule,
1512
+ proj4,
1513
+ geokeysToProj4: geokeysModule,
1514
+ });
1515
+ return source;
1516
+ }
1517
+
1518
+ exports.GeoTIFFTileProcessor = GeoTIFFTileProcessor;
1519
+ exports.getColorStops = getColorStops;
1520
+ exports.getGeoTIFFSource = getGeoTIFFSource;
1521
+ exports.getTileProcessorConfig = getTileProcessorConfig;
1522
+ exports.loadGeoTIFFSource = loadGeoTIFFSource;