leaflet-city-mapper 0.0.1 → 0.0.2

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 (472) hide show
  1. package/README.md +15 -13
  2. package/cucumber.mjs +4 -0
  3. package/dist/leaflet-city-mapper.js +1 -1
  4. package/dist/leaflet-city-mapper.js.map +4 -4
  5. package/dist/utils/CELL.js +2 -0
  6. package/dist/utils/CELL.js.map +7 -0
  7. package/dist/utils/addBridges.js +2 -0
  8. package/dist/utils/addBridges.js.map +7 -0
  9. package/dist/utils/addRasterTile.js +2 -0
  10. package/dist/utils/addRasterTile.js.map +7 -0
  11. package/dist/utils/along.js +2 -0
  12. package/dist/utils/along.js.map +7 -0
  13. package/dist/utils/atmosphere.js +2 -0
  14. package/dist/utils/atmosphere.js.map +7 -0
  15. package/dist/utils/attach.js +2 -0
  16. package/dist/utils/attach.js.map +7 -0
  17. package/dist/utils/bindSunlight.js +2 -0
  18. package/dist/utils/bindSunlight.js.map +7 -0
  19. package/dist/utils/box.js +2 -0
  20. package/dist/utils/box.js.map +7 -0
  21. package/dist/utils/bridgeElevation.js +2 -0
  22. package/dist/utils/bridgeElevation.js.map +7 -0
  23. package/dist/utils/build.js +2 -0
  24. package/dist/utils/build.js.map +7 -0
  25. package/dist/utils/cameraControls.js +2 -0
  26. package/dist/utils/cameraControls.js.map +7 -0
  27. package/dist/utils/channel.js +2 -0
  28. package/dist/utils/channel.js.map +7 -0
  29. package/dist/utils/collider.js +2 -0
  30. package/dist/utils/collider.js.map +7 -0
  31. package/dist/utils/colliders.js +2 -0
  32. package/dist/utils/colliders.js.map +7 -0
  33. package/dist/utils/computeBounds.js +2 -0
  34. package/dist/utils/computeBounds.js.map +7 -0
  35. package/dist/utils/conformModelToTerrain.js +2 -0
  36. package/dist/utils/conformModelToTerrain.js.map +7 -0
  37. package/dist/utils/createMesh.js +2 -0
  38. package/dist/utils/createMesh.js.map +7 -0
  39. package/dist/utils/createProgram.js +3 -0
  40. package/dist/utils/createProgram.js.map +7 -0
  41. package/dist/utils/decodeDirectory.js +2 -0
  42. package/dist/utils/decodeDirectory.js.map +7 -0
  43. package/dist/utils/decodeHeader.js +2 -0
  44. package/dist/utils/decodeHeader.js.map +7 -0
  45. package/dist/utils/decodeModel.js +2 -0
  46. package/dist/utils/decodeModel.js.map +7 -0
  47. package/dist/utils/decompress.js +2 -0
  48. package/dist/utils/decompress.js.map +7 -0
  49. package/dist/utils/destroyTexture.js +2 -0
  50. package/dist/utils/destroyTexture.js.map +7 -0
  51. package/dist/utils/disposeMesh.js +2 -0
  52. package/dist/utils/disposeMesh.js.map +7 -0
  53. package/dist/utils/drawGeometry.js +2 -0
  54. package/dist/utils/drawGeometry.js.map +7 -0
  55. package/dist/utils/elevationWGSL.js +24 -0
  56. package/dist/utils/elevationWGSL.js.map +7 -0
  57. package/dist/utils/emptyNode.js +2 -0
  58. package/dist/utils/emptyNode.js.map +7 -0
  59. package/dist/utils/endZoom.js +2 -0
  60. package/dist/utils/endZoom.js.map +7 -0
  61. package/dist/utils/findFeature.js +2 -0
  62. package/dist/utils/findFeature.js.map +7 -0
  63. package/dist/utils/geometry.js +0 -1
  64. package/dist/utils/geometry.js.map +4 -4
  65. package/dist/utils/getElevation.js +2 -0
  66. package/dist/utils/getElevation.js.map +7 -0
  67. package/dist/utils/getHeader.js +2 -0
  68. package/dist/utils/getHeader.js.map +7 -0
  69. package/dist/utils/getZxy.js +2 -0
  70. package/dist/utils/getZxy.js.map +7 -0
  71. package/dist/utils/glass.js +2 -0
  72. package/dist/utils/glass.js.map +7 -0
  73. package/dist/utils/headlight.js +2 -0
  74. package/dist/utils/headlight.js.map +7 -0
  75. package/dist/utils/hit.js +2 -0
  76. package/dist/utils/hit.js.map +7 -0
  77. package/dist/utils/horizontalPosition.js +2 -0
  78. package/dist/utils/horizontalPosition.js.map +7 -0
  79. package/dist/utils/horizontalRay.js +2 -0
  80. package/dist/utils/horizontalRay.js.map +7 -0
  81. package/dist/utils/hull.js +2 -0
  82. package/dist/utils/hull.js.map +7 -0
  83. package/dist/utils/initSunlight.js +2 -0
  84. package/dist/utils/initSunlight.js.map +7 -0
  85. package/dist/utils/initTerrain.js +2 -0
  86. package/dist/utils/initTerrain.js.map +7 -0
  87. package/dist/utils/initTraffic.js +40 -0
  88. package/dist/utils/initTraffic.js.map +7 -0
  89. package/dist/utils/initWalk.js +2 -0
  90. package/dist/utils/initWalk.js.map +7 -0
  91. package/dist/utils/intersectMeshes.js +2 -0
  92. package/dist/utils/intersectMeshes.js.map +7 -0
  93. package/dist/utils/isClockWise.js +2 -0
  94. package/dist/utils/isClockWise.js.map +7 -0
  95. package/dist/utils/lampPostGeometry.js +2 -0
  96. package/dist/utils/lampPostGeometry.js.map +7 -0
  97. package/dist/utils/lightGeometry.js +2 -0
  98. package/dist/utils/lightGeometry.js.map +7 -0
  99. package/dist/utils/lightGrid.js +2 -0
  100. package/dist/utils/lightGrid.js.map +7 -0
  101. package/dist/utils/limbs.js +2 -0
  102. package/dist/utils/limbs.js.map +7 -0
  103. package/dist/utils/loadModel.js +2 -0
  104. package/dist/utils/loadModel.js.map +7 -0
  105. package/dist/utils/loadSource.js +2 -0
  106. package/dist/utils/loadSource.js.map +7 -0
  107. package/dist/utils/loadTerrain.js +2 -0
  108. package/dist/utils/loadTerrain.js.map +7 -0
  109. package/dist/utils/mapCamera.js +2 -0
  110. package/dist/utils/mapCamera.js.map +7 -0
  111. package/dist/utils/{shaders.js → materialShaders.js} +16 -8
  112. package/dist/utils/materialShaders.js.map +7 -0
  113. package/dist/utils/mirror.js +2 -0
  114. package/dist/utils/mirror.js.map +7 -0
  115. package/dist/utils/moonPosition.js +2 -0
  116. package/dist/utils/moonPosition.js.map +7 -0
  117. package/dist/utils/moves.js +2 -0
  118. package/dist/utils/moves.js.map +7 -0
  119. package/dist/utils/nativeEvents.js +2 -0
  120. package/dist/utils/nativeEvents.js.map +7 -0
  121. package/dist/utils/nativeGeometry.js +2 -0
  122. package/dist/utils/nativeGeometry.js.map +7 -0
  123. package/dist/utils/nativeLayer.js +2 -0
  124. package/dist/utils/nativeLayer.js.map +7 -0
  125. package/dist/utils/nodeMatrix.js +2 -0
  126. package/dist/utils/nodeMatrix.js.map +7 -0
  127. package/dist/utils/onAdd3DLayer.js +2 -0
  128. package/dist/utils/onAdd3DLayer.js.map +7 -0
  129. package/dist/utils/onAddSun.js +2 -0
  130. package/dist/utils/onAddSun.js.map +7 -0
  131. package/dist/utils/onClick.js +2 -0
  132. package/dist/utils/onClick.js.map +7 -0
  133. package/dist/utils/onMapChange.js +2 -0
  134. package/dist/utils/onMapChange.js.map +7 -0
  135. package/dist/utils/onPMTileAdd.js +2 -0
  136. package/dist/utils/onPMTileAdd.js.map +7 -0
  137. package/dist/utils/onPMTileRemove.js +2 -0
  138. package/dist/utils/onPMTileRemove.js.map +7 -0
  139. package/dist/utils/onPointerLeave.js +2 -0
  140. package/dist/utils/onPointerLeave.js.map +7 -0
  141. package/dist/utils/onPointerMove.js +2 -0
  142. package/dist/utils/onPointerMove.js.map +7 -0
  143. package/dist/utils/onRemove3DLayer.js +2 -0
  144. package/dist/utils/onRemove3DLayer.js.map +7 -0
  145. package/dist/utils/onRemoveSun.js +2 -0
  146. package/dist/utils/onRemoveSun.js.map +7 -0
  147. package/dist/utils/onTerrainAdd.js +2 -0
  148. package/dist/utils/onTerrainAdd.js.map +7 -0
  149. package/dist/utils/onTerrainChange.js +2 -0
  150. package/dist/utils/onTerrainChange.js.map +7 -0
  151. package/dist/utils/onTerrainRemove.js +2 -0
  152. package/dist/utils/onTerrainRemove.js.map +7 -0
  153. package/dist/utils/onZoomAnim.js +2 -0
  154. package/dist/utils/onZoomAnim.js.map +7 -0
  155. package/dist/utils/paints.js +2 -0
  156. package/dist/utils/paints.js.map +7 -0
  157. package/dist/utils/parseColor.js +2 -0
  158. package/dist/utils/parseColor.js.map +7 -0
  159. package/dist/utils/parts.js +2 -0
  160. package/dist/utils/parts.js.map +7 -0
  161. package/dist/utils/projectCelestialBody.js +2 -0
  162. package/dist/utils/projectCelestialBody.js.map +7 -0
  163. package/dist/utils/pump.js +2 -0
  164. package/dist/utils/pump.js.map +7 -0
  165. package/dist/utils/rasterTiles.js +2 -0
  166. package/dist/utils/rasterTiles.js.map +7 -0
  167. package/dist/utils/raycast.js +2 -0
  168. package/dist/utils/raycast.js.map +7 -0
  169. package/dist/utils/read.js +2 -0
  170. package/dist/utils/read.js.map +7 -0
  171. package/dist/utils/readAccessor.js +2 -0
  172. package/dist/utils/readAccessor.js.map +7 -0
  173. package/dist/utils/releaseArea.js +2 -0
  174. package/dist/utils/releaseArea.js.map +7 -0
  175. package/dist/utils/removeRasterTile.js +2 -0
  176. package/dist/utils/removeRasterTile.js.map +7 -0
  177. package/dist/utils/render.js +15 -0
  178. package/dist/utils/render.js.map +7 -0
  179. package/dist/utils/renderSunlight.js +13 -0
  180. package/dist/utils/renderSunlight.js.map +7 -0
  181. package/dist/utils/renderers.js +2 -0
  182. package/dist/utils/renderers.js.map +7 -0
  183. package/dist/utils/resizeSunlight.js +2 -0
  184. package/dist/utils/resizeSunlight.js.map +7 -0
  185. package/dist/utils/roofCoverage.js +2 -0
  186. package/dist/utils/roofCoverage.js.map +7 -0
  187. package/dist/utils/routeGeometry.js +2 -0
  188. package/dist/utils/routeGeometry.js.map +7 -0
  189. package/dist/utils/scheduledTrips.js +2 -0
  190. package/dist/utils/scheduledTrips.js.map +7 -0
  191. package/dist/utils/setGeoJSONData.js +2 -0
  192. package/dist/utils/setGeoJSONData.js.map +7 -0
  193. package/dist/utils/setHighlight.js +2 -0
  194. package/dist/utils/setHighlight.js.map +7 -0
  195. package/dist/utils/setPMTileOpacity.js +2 -0
  196. package/dist/utils/setPMTileOpacity.js.map +7 -0
  197. package/dist/utils/setPMTileZIndex.js +2 -0
  198. package/dist/utils/setPMTileZIndex.js.map +7 -0
  199. package/dist/utils/setParent.js +2 -0
  200. package/dist/utils/setParent.js.map +7 -0
  201. package/dist/utils/setTerrainHeight.js +2 -0
  202. package/dist/utils/setTerrainHeight.js.map +7 -0
  203. package/dist/utils/setVertexColor.js +2 -0
  204. package/dist/utils/setVertexColor.js.map +7 -0
  205. package/dist/utils/showFeature.js +2 -0
  206. package/dist/utils/showFeature.js.map +7 -0
  207. package/dist/utils/sizes.js +2 -0
  208. package/dist/utils/sizes.js.map +7 -0
  209. package/dist/utils/skin.js +2 -0
  210. package/dist/utils/skin.js.map +7 -0
  211. package/dist/utils/solarPosition.js +2 -0
  212. package/dist/utils/solarPosition.js.map +7 -0
  213. package/dist/utils/sortMeshes.js +2 -0
  214. package/dist/utils/sortMeshes.js.map +7 -0
  215. package/dist/utils/speed.js +2 -0
  216. package/dist/utils/speed.js.map +7 -0
  217. package/dist/utils/startZoom.js +2 -0
  218. package/dist/utils/startZoom.js.map +7 -0
  219. package/dist/utils/taillight.js +2 -0
  220. package/dist/utils/taillight.js.map +7 -0
  221. package/dist/utils/terrainAtlas.js +2 -0
  222. package/dist/utils/terrainAtlas.js.map +7 -0
  223. package/dist/utils/terrainElevation.js +2 -0
  224. package/dist/utils/terrainElevation.js.map +7 -0
  225. package/dist/utils/terrainGrid.js +2 -0
  226. package/dist/utils/terrainGrid.js.map +7 -0
  227. package/dist/utils/textureSampler.js +2 -0
  228. package/dist/utils/textureSampler.js.map +7 -0
  229. package/dist/utils/tileId.js +2 -0
  230. package/dist/utils/tileId.js.map +7 -0
  231. package/dist/utils/toLanes.js +2 -0
  232. package/dist/utils/toLanes.js.map +7 -0
  233. package/dist/utils/toSRGB.js +2 -0
  234. package/dist/utils/toSRGB.js.map +7 -0
  235. package/dist/utils/tooltip.js +3 -0
  236. package/dist/utils/tooltip.js.map +7 -0
  237. package/dist/utils/traffic.js +1 -1
  238. package/dist/utils/traffic.js.map +3 -3
  239. package/dist/utils/traverse.js +2 -0
  240. package/dist/utils/traverse.js.map +7 -0
  241. package/dist/utils/treeGeometry.js +2 -0
  242. package/dist/utils/treeGeometry.js.map +7 -0
  243. package/dist/utils/triangulate.js +2 -0
  244. package/dist/utils/triangulate.js.map +7 -0
  245. package/dist/utils/tripsAt.js +2 -0
  246. package/dist/utils/tripsAt.js.map +7 -0
  247. package/dist/utils/types.js +2 -0
  248. package/dist/utils/types.js.map +7 -0
  249. package/dist/utils/underEntry.js +2 -0
  250. package/dist/utils/underEntry.js.map +7 -0
  251. package/dist/utils/update.js +2 -0
  252. package/dist/utils/update.js.map +7 -0
  253. package/dist/utils/updateArea.js +2 -0
  254. package/dist/utils/updateArea.js.map +7 -0
  255. package/dist/utils/updateCamera.js +2 -0
  256. package/dist/utils/updateCamera.js.map +7 -0
  257. package/dist/utils/updatePointLights.js +2 -0
  258. package/dist/utils/updatePointLights.js.map +7 -0
  259. package/dist/utils/updateWorldMatrix.js +2 -0
  260. package/dist/utils/updateWorldMatrix.js.map +7 -0
  261. package/dist/utils/vehicleOffsets.js +2 -0
  262. package/dist/utils/vehicleOffsets.js.map +7 -0
  263. package/dist/utils/vehicles.js +1 -1
  264. package/dist/utils/vehicles.js.map +3 -3
  265. package/dist/utils/vertexNormals.js +2 -0
  266. package/dist/utils/vertexNormals.js.map +7 -0
  267. package/dist/utils/walk.js +1 -1
  268. package/dist/utils/walk.js.map +3 -3
  269. package/dist/utils/white.js +2 -0
  270. package/dist/utils/white.js.map +7 -0
  271. package/dist/utils/worldLights.js +2 -0
  272. package/dist/utils/worldLights.js.map +7 -0
  273. package/dist/utils/wrap.js +2 -0
  274. package/dist/utils/wrap.js.map +7 -0
  275. package/package.json +2 -4
  276. package/src/index.js +365 -50
  277. package/src/utils/CELL.js +4 -0
  278. package/src/utils/addBridges.js +66 -0
  279. package/src/utils/addRasterTile.js +112 -0
  280. package/src/utils/along.js +9 -0
  281. package/src/utils/atmosphere.js +20 -0
  282. package/src/utils/attach.js +255 -0
  283. package/src/utils/bindSunlight.js +12 -0
  284. package/src/utils/box.js +1 -0
  285. package/src/utils/bridgeElevation.js +18 -0
  286. package/src/utils/build.js +20 -0
  287. package/src/utils/cameraControls.js +287 -0
  288. package/src/utils/channel.js +4 -0
  289. package/src/utils/collider.js +62 -0
  290. package/src/utils/colliders.js +2 -0
  291. package/src/utils/computeBounds.js +17 -0
  292. package/src/utils/conformModelToTerrain.js +69 -0
  293. package/src/utils/createMesh.js +31 -0
  294. package/src/utils/createProgram.js +92 -0
  295. package/src/utils/decodeDirectory.js +40 -0
  296. package/src/utils/decodeHeader.js +15 -0
  297. package/src/utils/decodeModel.js +43 -0
  298. package/src/utils/decompress.js +5 -0
  299. package/src/utils/destroyTexture.js +7 -0
  300. package/src/utils/disposeMesh.js +13 -0
  301. package/src/utils/drawGeometry.js +122 -0
  302. package/src/utils/elevationWGSL.js +27 -0
  303. package/src/utils/emptyNode.js +9 -0
  304. package/src/utils/endZoom.js +15 -0
  305. package/src/utils/findFeature.js +49 -0
  306. package/src/utils/geometry.js +0 -254
  307. package/src/utils/getElevation.js +10 -0
  308. package/src/utils/getHeader.js +9 -0
  309. package/src/utils/getZxy.js +76 -0
  310. package/src/utils/glass.js +1 -0
  311. package/src/utils/headlight.js +1 -0
  312. package/src/utils/hit.js +41 -0
  313. package/src/utils/horizontalPosition.js +16 -0
  314. package/src/utils/horizontalRay.js +12 -0
  315. package/src/utils/hull.js +1 -0
  316. package/src/utils/initSunlight.js +9 -0
  317. package/src/utils/initTerrain.js +19 -0
  318. package/src/utils/initTraffic.js +93 -0
  319. package/src/utils/initWalk.js +72 -0
  320. package/src/utils/{picking.js → intersectMeshes.js} +121 -119
  321. package/src/utils/isClockWise.js +12 -0
  322. package/src/utils/lampPostGeometry.js +26 -0
  323. package/src/utils/lightGeometry.js +22 -0
  324. package/src/utils/{lighting.js → lightGrid.js} +50 -51
  325. package/src/utils/limbs.js +9 -0
  326. package/src/{scene/model.js → utils/loadModel.js} +37 -24
  327. package/src/utils/loadSource.js +17 -0
  328. package/src/utils/loadTerrain.js +65 -0
  329. package/src/utils/mapCamera.js +432 -0
  330. package/src/utils/{shaders.js → materialShaders.js} +243 -237
  331. package/src/utils/mirror.js +6 -0
  332. package/src/utils/moonPosition.js +17 -0
  333. package/src/utils/moves.js +11 -0
  334. package/src/utils/nativeEvents.js +77 -0
  335. package/src/utils/nativeGeometry.js +131 -0
  336. package/src/utils/nativeLayer.js +317 -0
  337. package/src/utils/nodeMatrix.js +22 -0
  338. package/src/utils/onAdd3DLayer.js +31 -0
  339. package/src/utils/onAddSun.js +147 -0
  340. package/src/utils/onClick.js +13 -0
  341. package/src/utils/onMapChange.js +16 -0
  342. package/src/utils/onPMTileAdd.js +15 -0
  343. package/src/utils/onPMTileRemove.js +8 -0
  344. package/src/utils/onPointerLeave.js +11 -0
  345. package/src/utils/onPointerMove.js +15 -0
  346. package/src/utils/onRemove3DLayer.js +78 -0
  347. package/src/utils/onRemoveSun.js +3 -0
  348. package/src/utils/onTerrainAdd.js +18 -0
  349. package/src/utils/onTerrainChange.js +13 -0
  350. package/src/utils/onTerrainRemove.js +40 -0
  351. package/src/utils/onZoomAnim.js +14 -0
  352. package/src/utils/paints.js +10 -0
  353. package/src/utils/parseColor.js +42 -0
  354. package/src/utils/parts.js +16 -0
  355. package/src/utils/projectCelestialBody.js +13 -0
  356. package/src/{scene/sources.js → utils/pump.js} +59 -98
  357. package/src/utils/rasterTiles.js +285 -0
  358. package/src/utils/raycast.js +60 -0
  359. package/src/utils/read.js +29 -0
  360. package/src/utils/readAccessor.js +68 -0
  361. package/src/utils/releaseArea.js +34 -0
  362. package/src/utils/removeRasterTile.js +13 -0
  363. package/src/{scene → utils}/render.js +112 -173
  364. package/src/utils/renderSunlight.js +170 -0
  365. package/src/utils/renderers.js +2 -0
  366. package/src/utils/resizeSunlight.js +15 -0
  367. package/src/utils/roofCoverage.js +47 -0
  368. package/src/utils/routeGeometry.js +22 -0
  369. package/src/utils/scheduledTrips.js +29 -0
  370. package/src/utils/setGeoJSONData.js +11 -0
  371. package/src/utils/setHighlight.js +13 -0
  372. package/src/utils/setPMTileOpacity.js +7 -0
  373. package/src/utils/setPMTileZIndex.js +7 -0
  374. package/src/utils/setParent.js +7 -0
  375. package/src/utils/setTerrainHeight.js +10 -0
  376. package/src/utils/setVertexColor.js +14 -0
  377. package/src/utils/showFeature.js +27 -0
  378. package/src/utils/sizes.js +1 -0
  379. package/src/utils/skin.js +2 -0
  380. package/src/utils/solarPosition.js +17 -0
  381. package/src/utils/sortMeshes.js +12 -0
  382. package/src/utils/speed.js +3 -0
  383. package/src/utils/startZoom.js +5 -0
  384. package/src/utils/taillight.js +1 -0
  385. package/src/utils/terrainAtlas.js +21 -0
  386. package/src/utils/terrainElevation.js +20 -0
  387. package/src/utils/terrainGrid.js +23 -0
  388. package/src/utils/textureSampler.js +10 -0
  389. package/src/utils/tileId.js +18 -0
  390. package/src/utils/toLanes.js +7 -0
  391. package/src/utils/toSRGB.js +1 -0
  392. package/src/utils/tooltip.js +6 -0
  393. package/src/utils/traffic.js +310 -85
  394. package/src/utils/traverse.js +6 -0
  395. package/src/utils/treeGeometry.js +45 -0
  396. package/src/utils/triangulate.js +100 -0
  397. package/src/utils/tripsAt.js +16 -0
  398. package/src/utils/types.js +8 -0
  399. package/src/utils/{control.js → underEntry.js} +1 -2
  400. package/src/utils/update.js +18 -0
  401. package/src/utils/updateArea.js +40 -0
  402. package/src/utils/updateCamera.js +32 -0
  403. package/src/utils/updatePointLights.js +38 -0
  404. package/src/utils/updateWorldMatrix.js +47 -0
  405. package/src/utils/vehicleOffsets.js +8 -0
  406. package/src/utils/vehicles.js +65 -69
  407. package/src/utils/vertexNormals.js +30 -0
  408. package/src/utils/walk.js +181 -66
  409. package/src/utils/white.js +1 -0
  410. package/src/utils/worldLights.js +25 -0
  411. package/src/utils/wrap.js +1 -0
  412. package/dist/scene/gpu.js +0 -3
  413. package/dist/scene/gpu.js.map +0 -7
  414. package/dist/scene/lighting.js +0 -9
  415. package/dist/scene/lighting.js.map +0 -7
  416. package/dist/scene/model.js +0 -2
  417. package/dist/scene/model.js.map +0 -7
  418. package/dist/scene/picking.js +0 -2
  419. package/dist/scene/picking.js.map +0 -7
  420. package/dist/scene/pmtiles.js +0 -2
  421. package/dist/scene/pmtiles.js.map +0 -7
  422. package/dist/scene/render.js +0 -15
  423. package/dist/scene/render.js.map +0 -7
  424. package/dist/scene/sources.js +0 -2
  425. package/dist/scene/sources.js.map +0 -7
  426. package/dist/types/3d.js +0 -2
  427. package/dist/types/3d.js.map +0 -7
  428. package/dist/types/geojson.js +0 -2
  429. package/dist/types/geojson.js.map +0 -7
  430. package/dist/types/pmtiles.js +0 -2
  431. package/dist/types/pmtiles.js.map +0 -7
  432. package/dist/types/sunlight.js +0 -2
  433. package/dist/types/sunlight.js.map +0 -7
  434. package/dist/types/terrain.js +0 -24
  435. package/dist/types/terrain.js.map +0 -7
  436. package/dist/types/traffic.js +0 -41
  437. package/dist/types/traffic.js.map +0 -7
  438. package/dist/types/walk.js +0 -2
  439. package/dist/types/walk.js.map +0 -7
  440. package/dist/utils/control.js +0 -2
  441. package/dist/utils/control.js.map +0 -7
  442. package/dist/utils/lighting.js +0 -2
  443. package/dist/utils/lighting.js.map +0 -7
  444. package/dist/utils/model.js +0 -2
  445. package/dist/utils/model.js.map +0 -7
  446. package/dist/utils/picking.js +0 -2
  447. package/dist/utils/picking.js.map +0 -7
  448. package/dist/utils/pmtiles.js +0 -2
  449. package/dist/utils/pmtiles.js.map +0 -7
  450. package/dist/utils/scene.js +0 -2
  451. package/dist/utils/scene.js.map +0 -7
  452. package/dist/utils/shaders.js.map +0 -7
  453. package/dist/utils/sun.js +0 -2
  454. package/dist/utils/sun.js.map +0 -7
  455. package/dist/utils/terrain.js +0 -2
  456. package/dist/utils/terrain.js.map +0 -7
  457. package/src/scene/gpu.js +0 -438
  458. package/src/scene/lighting.js +0 -193
  459. package/src/scene/picking.js +0 -150
  460. package/src/scene/pmtiles.js +0 -94
  461. package/src/types/3d.js +0 -337
  462. package/src/types/geojson.js +0 -42
  463. package/src/types/pmtiles.js +0 -143
  464. package/src/types/sunlight.js +0 -142
  465. package/src/types/terrain.js +0 -331
  466. package/src/types/traffic.js +0 -356
  467. package/src/types/walk.js +0 -219
  468. package/src/utils/model.js +0 -178
  469. package/src/utils/pmtiles.js +0 -79
  470. package/src/utils/scene.js +0 -102
  471. package/src/utils/sun.js +0 -71
  472. package/src/utils/terrain.js +0 -78
package/src/index.js CHANGED
@@ -1,82 +1,397 @@
1
+ import './utils/mapCamera.js';
2
+
1
3
  /**
2
4
  * `new L.Layer({ source: { type, url, ...settings }, pane, attribution })`: layers with a `source`
3
- * load their type module on first use. Subclasses are unchanged.
5
+ * load their specialized utilities on first use. Native map layers also join the WebGPU scene.
4
6
  */
5
7
 
6
8
  /**
7
9
  * Router for `new L.Layer({ source: { type, url, ...settings }, pane, attribution })`.
8
- * It imports the type module on demand and turns the
9
- * layer into it; types receive flat options (`{ ...source, pane, attribution }`), so `layer.options.url` etc.
10
+ * It imports source utilities on demand and initializes the existing instance;
11
+ * types receive flat options (`{ ...source, pane, attribution }`), so `layer.options.url` etc.
10
12
  *
11
13
  * Folder layout:
12
- * - types/: one module per `source.type`, the only files imported by this router:
13
- * - 'pmtiles': raster PMTiles basemap (an L.TileLayer), draped on the terrain when present;
14
- * - '3d': shared WebGPU scene with a GLB/glTF model, PMTiles GeoJSON features, or empty;
15
- * - 'geojson': inline or URL-backed GeoJSON features rendered by the shared 3D scene;
16
- * - 'terrain': Float32 PMTiles DEM that deforms raster tiles, buildings and the camera, plus optional bridge decks;
17
- * - 'sunlight': simulation clock control, sun/moon lighting and shadows;
18
- * - 'traffic': vehicles moving along GeoJSON lanes (measured flow or timetable);
19
- * - 'walk': third-person pedestrian moved with the keyboard, the camera following behind.
20
- * - scene/: named operations for GPU resources, model/archive loading, lighting, sources, picking
21
- * and rendering. They receive the layer explicitly; types/3d.js declares its delegates, without mixins.
22
- * - utils/: computations and scene-data helpers, independent of Leaflet layers and GPU devices.
23
- * Geometry, decoders, lighting grids, terrain sampling, traffic and collisions can be tested in Node;
24
- * scene transforms/picking use browser DOMMatrix/DOMPoint, and CSS colors use a canvas.
14
+ * - Vector ('3d', 'geojson') and raster ('pmtiles') initialization lives here.
15
+ * - utils/: lazy operations for rendering, archives, geometry and specialized layers:
16
+ * terrain (Float32 DEM), sunlight (clock and lighting), traffic and walking.
17
+ * Operations receive the layer explicitly, without subclasses or prototype replacement.
25
18
  * Dataset-specific code and data (routes, timetables, API loaders) belong to the application, e.g. misc/.
26
19
  *
27
- * When `type` is omitted it is inferred from `source.url`: *.pmtiles -> 'pmtiles', anything else -> '3d'.
20
+ * When `type` is omitted, inline FeatureCollections use 'geojson'; otherwise *.pmtiles URLs use
21
+ * 'pmtiles' and other sources use '3d'.
28
22
  */
29
23
 
30
24
  const layerProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Layer.prototype));
31
25
 
32
- // Stand-in while the type module loads: remembers the map, renders nothing.
33
- const Pending = L.Layer.extend({
34
- onAdd() {},
35
- onRemove() {},
36
- });
37
-
38
26
  // One chain for every pending layer: they become real layers in creation order, whatever the import timing.
39
27
  let loading = Promise.resolve();
28
+ let sceneModules, sceneLoading, rasterModules;
29
+ let nativeLoading;
40
30
 
41
- // Shared registry: type modules (src/types) register here.
42
- L.Layer.types = {};
31
+ /**
32
+ * The '3d' layer type: native WebGPU scene synchronized with the map camera.
33
+ * Layers on one map share a canvas, scene and camera; each has its own root transform.
34
+ *
35
+ * @typedef {Object} Layer3DOptions Layer options; pane and attribution remain standard L.Layer options.
36
+ * @property {string} [type] '3d', 'geojson', 'pmtiles', 'terrain', 'sunlight', 'traffic' or 'walk'.
37
+ * @property {number[]} [center] Local origin [lat,lng]; defaults to the first map center.
38
+ * @property {number} [terrainOffset=0] Vertical offset in metres when terrain is enabled.
39
+ * @property {boolean} [terrainConform=false] Fit lower model geometry to local terrain elevation.
40
+ * @property {'OPAQUE'|'MASK'|'BLEND'} [alphaMode] Override every glTF material's alpha mode.
41
+ * @property {number[]} [rotation] Model Euler rotation [x,y,z] in radians, YXZ order.
42
+ * @property {number[]} [scale] Model scale [x,y,z].
43
+ * @property {string} [url] GLB/glTF model URL or PMTiles archive URL.
44
+ * @property {function(Object): (ExtrusionStyle|null)} [style] Source styling; null skips a feature.
45
+ * @property {function(PickedFeature): (Node|string)} [tooltip] Tooltip content; strings are text.
46
+ * @property {string} [ariaLabel='3D scene'] Shared canvas accessible name.
47
+ * @property {boolean} [nightLight=false] Point sources: emissive bulbs and local illumination.
48
+ * @property {boolean} [nightSparkle=false] Model: sparse luminous points at night.
49
+ *
50
+ * @typedef {Object} ExtrusionStyle
51
+ * @property {number} top Roof height in metres; must exceed bottom.
52
+ * @property {number} [bottom=0] Nonnegative base height.
53
+ * @property {number|string|Object} [color=0xd9b38c] RGB/CSS color or linear-space {h,s,l}.
54
+ * @property {number} [trunkRadius] Point tree trunk radius in metres.
55
+ * @property {number} [crownRadius] Point tree crown radius in metres.
56
+ * @property {number} [crownBottom] Point tree crown base in metres.
57
+ * @property {string} [crownShape='round'] Point tree crown shape.
58
+ * @property {number|string|Object} [trunkColor=0x72513a] Point tree bark color.
59
+ * @property {number} [lightRadius] Point light estimated ground reach in metres.
60
+ * @property {number} [lightFlux] Point light luminous flux in lumens.
61
+ *
62
+ * @typedef {Object} PickedFeature
63
+ * @property {string|number} id Source feature id or configured model URL.
64
+ * @property {Object} properties GeoJSON properties or model-level glTF extras.
65
+ * @property {Object} mesh Intersected mesh.
66
+ * @property {number[]} point Intersection [x,y,z] in shared scene metres.
67
+ * @property {Object} [model] Configured model root; absent for source polygons.
68
+ * @property {number} [vertexStart] First polygon vertex in the batched mesh.
69
+ * @property {number} [vertexEnd] Exclusive end of the polygon's vertex range.
70
+ *
71
+ * @typedef {Object} SourceArea
72
+ * @property {Object} coords Archive block {z,x,y}.
73
+ * @property {AbortController} request Cancellation prevents attaching obsolete results.
74
+ * @property {boolean} [done] Geometry built successfully, including empty blocks.
75
+ * @property {Object|null} [mesh] Batched GPU mesh.
76
+ * @property {number} [buildings] Emitted feature count.
77
+ * @property {number} [skipped] Features skipped by style.
78
+ * @property {string} [error] Failed load/build message.
79
+ *
80
+ * @param {L.Layer} backend
81
+ * @param {Layer3DOptions} [options] World origin comes from center or the first map centre.
82
+ */
83
+
84
+ L.Layer._renderers = new WeakMap();
85
+ L.Layer._nextId = 0;
43
86
 
44
- // Core L.Layer has no initialize and init hooks get no arguments: keep the options for the hook.
45
87
  L.Layer.include({
88
+ _layerAdd(event) {
89
+ const native = !this._3d && (
90
+ this instanceof L.GridLayer ||
91
+ this instanceof L.Polyline ||
92
+ this instanceof L.CircleMarker ||
93
+ this instanceof L.Marker && !(this.options.icon instanceof L.DivIcon) ||
94
+ this instanceof L.ImageOverlay && !(this instanceof L.VideoOverlay) && !(this instanceof L.SVGOverlay)
95
+ );
96
+ if (native) {
97
+ if (this instanceof L.GridLayer || this instanceof L.ImageOverlay) {
98
+ this.options.crossOrigin ||= true;
99
+ }
100
+ if (this instanceof L.Marker) this.options.icon.options.crossOrigin ||= true;
101
+ }
102
+ layerProto._layerAdd.call(this, event);
103
+ if (!native || !event.target.hasLayer(this)) return;
104
+ this._initNativeGPU(event.target);
105
+ },
106
+ _initNativeGPU(map) {
107
+ if (this._nativeGPU) return;
108
+ if (!document.getElementById('leaflet-webgpu-targets')) {
109
+ const style = document.createElement('style');
110
+ style.id = 'leaflet-webgpu-targets';
111
+ style.textContent = '.leaflet-webgpu-target{opacity:0!important}';
112
+ document.head.append(style);
113
+ }
114
+ const state = this._nativeGPU = { source: this, map, hidden: new Set() };
115
+ state.hide = () => {
116
+ const htmlIcon = this instanceof L.Marker && this.options.icon instanceof L.DivIcon;
117
+ const targets = [htmlIcon ? null : this._icon, htmlIcon ? null : this._shadow];
118
+ for (const element of state.hidden) {
119
+ if (targets.includes(element)) continue;
120
+ element.classList.remove('leaflet-webgpu-target');
121
+ state.hidden.delete(element);
122
+ }
123
+ for (const element of targets) {
124
+ if (!element || state.hidden.has(element)) continue;
125
+ element.classList.add('leaflet-webgpu-target');
126
+ state.hidden.add(element);
127
+ }
128
+ };
129
+ state.hide();
130
+ this.once('remove', () => {
131
+ if (this._nativeGPU === state) this._nativeGPU = null;
132
+ state.dispose?.();
133
+ for (const element of state.hidden) {
134
+ element.classList.remove('leaflet-webgpu-target');
135
+ }
136
+ });
137
+
138
+ nativeLoading ||= import('./utils/nativeLayer.js');
139
+ this.ready = nativeLoading.then(({ nativeLayer }) => {
140
+ if (this._nativeGPU !== state) return this;
141
+ return nativeLayer(state);
142
+ });
143
+ this.ready.catch(error => this.fire('error', { error }));
144
+ },
145
+ _init3D(options = {}) {
146
+ const layer = this;
147
+ const ready = sceneLoading ||= Promise.all([
148
+ import('./utils/onAdd3DLayer.js'),
149
+ import('./utils/onRemove3DLayer.js'),
150
+ import('./utils/updateArea.js'),
151
+ import('./utils/onTerrainChange.js'),
152
+ ]).then(([add, remove, update, terrain]) => sceneModules = { ...add, ...remove, ...update, ...terrain });
153
+ layer._3d = true;
154
+ L.Util.setOptions(layer, { ariaLabel: '3D scene', ...options });
155
+ layer.onAdd = map => {
156
+ if (sceneModules) return sceneModules.onAdd3DLayer(layer, map);
157
+ ready.then(({ onAdd3DLayer }) => {
158
+ if (layer._map === map) onAdd3DLayer(layer, map);
159
+ }).catch(error => layer.fire('error', { error }));
160
+ };
161
+ layer.onRemove = map => {
162
+ if (sceneModules) return sceneModules.onRemove3DLayer(layer, map);
163
+ ready.then(({ onRemove3DLayer }) => onRemove3DLayer(layer, map))
164
+ .catch(error => layer.fire('error', { error }));
165
+ };
166
+ layer.getEvents = () => {
167
+ const events = {};
168
+ if (layer.url) {
169
+ events.moveend = events.zoomend = events.rotate = events.pitch = events.resize = () =>
170
+ sceneModules ? sceneModules.updateArea(layer) : ready.then(({ updateArea }) => updateArea(layer));
171
+ }
172
+ if (layer._geojson || layer.url) {
173
+ events.terrainchange = () => sceneModules
174
+ ? sceneModules.onTerrainChange(layer)
175
+ : ready.then(({ onTerrainChange }) => onTerrainChange(layer));
176
+ }
177
+ return events;
178
+ };
179
+ // ponytail: models are recognised by extension; extensionless model URLs need a .glb/.gltf suffix or query.
180
+ const isModel = !layer._geojson && /\.(glb|gltf)(?:[?#]|$)/i.test(layer.options.url);
181
+ layer.modelUrl = isModel ? layer.options.url : null;
182
+ layer.url = layer.options.url && !isModel && !layer._geojson ? new URL(layer.options.url, document.baseURI).href : null;
183
+ layer._directories = new Map();
184
+ if (layer.options.center) {
185
+ layer.location = new L.LatLng(layer.options.center[0], layer.options.center[1]);
186
+ }
187
+ /** @type {Map<string, SourceArea>} Keys are archive x/y, not screen tiles. */
188
+ layer._areas = new Map();
189
+ layer._inflight = 0;
190
+ layer._added = Promise.withResolvers();
191
+ queueMicrotask(async () => {
192
+ try {
193
+ await ready;
194
+ layer.root = (await import('./utils/emptyNode.js')).emptyNode();
195
+ layer.raycaster = { origin: [0, 0, 0], direction: [0, 0, 0] };
196
+ if (layer.url || layer._geojson) {
197
+ layer.group = layer.root;
198
+ if (layer.url) layer.header = await (await import('./utils/getHeader.js')).getHeader(layer);
199
+ }
200
+ if (layer._map) {
201
+ await (await import('./utils/attach.js')).attach(layer, layer._map);
202
+ layer._added.resolve();
203
+ }
204
+ if (layer.modelUrl) await (await import('./utils/loadModel.js')).loadModel(layer);
205
+ if (layer._shared) (await import('./utils/update.js')).update(layer);
206
+ layer.fire('ready');
207
+ } catch (error) {
208
+ layer.fire('error', { error });
209
+ }
210
+ });
211
+ },
212
+ _initRaster(options) {
213
+ const layer = this;
214
+ const [{ read }, { getHeader }, { getZxy }, { onPMTileAdd }, { onPMTileRemove },
215
+ { getRasterTileSize, updateRasterTiles }, { setPMTileOpacity }, { setPMTileZIndex }, { emptyNode }] = rasterModules;
216
+ layer._read = (offset, length, signal) => read(layer, offset, length, signal);
217
+ layer.getHeader = () => getHeader(layer);
218
+ layer.getZxy = (z, x, y, signal) => getZxy(layer, z, x, y, signal);
219
+ layer.getTileSize = () => getRasterTileSize();
220
+ layer.isLoading = () => layer._loadingTiles > 0;
221
+ layer.setOpacity = opacity => setPMTileOpacity(layer, opacity);
222
+ layer.setZIndex = zIndex => setPMTileZIndex(layer, zIndex);
223
+ layer.onAdd = map => onPMTileAdd(layer, map);
224
+ layer.onRemove = map => onPMTileRemove(layer, map);
225
+ const update = () => updateRasterTiles(layer);
226
+ layer.getEvents = () => ({
227
+ moveend: update,
228
+ zoomend: update,
229
+ rotate: update,
230
+ pitch: update,
231
+ resize: update,
232
+ });
233
+ options = { ariaLabel: 'PMTiles raster', maxZoom: 18, opacity: 1, zIndex: 0, ...options };
234
+ L.Util.setOptions(layer, options);
235
+ layer.root = emptyNode();
236
+ layer._areas = new Map();
237
+ layer._rasterTiles = new Map();
238
+ layer._loadingTiles = 0;
239
+ layer._added = Promise.withResolvers();
240
+ layer.url = new URL(options.url, document.baseURI).href;
241
+ layer._directories = new Map();
242
+ layer.ready = Promise.resolve(layer.options.archive || layer).then(async archive => {
243
+ const header = await archive.getHeader();
244
+ layer.options.archive = archive;
245
+ layer.header = header;
246
+ if (layer.options.maxNativeZoom === undefined) {
247
+ layer.options.maxNativeZoom = header.maxZoom;
248
+ }
249
+ layer.options.maxZoom = Math.max(layer.options.minZoom || 0, layer.options.maxZoom);
250
+ layer.fire('ready');
251
+ return layer;
252
+ }).catch(error => {
253
+ layer.fire('error', { error });
254
+ throw error;
255
+ });
256
+ },
46
257
  initialize(options = {}) {
47
258
  if (Object.getPrototypeOf(this) !== L.Layer.prototype || !options.source) {
48
259
  if (layerProto.initialize) return layerProto.initialize.apply(this, arguments);
49
260
  L.Util.setOptions(this, options);
50
261
  return;
51
262
  }
52
- const layer = this;
53
- const { source: { type = /\.pmtiles(?:[?#]|$)/i.test(options.source.url) ? 'pmtiles' : '3d', ...source }, ...core } = options;
263
+ const {
264
+ source: {
265
+ type = options.source.data?.type === 'FeatureCollection'
266
+ ? 'geojson'
267
+ : /\.pmtiles(?:[?#]|$)/i.test(options.source.url) ? 'pmtiles' : '3d',
268
+ ...source
269
+ },
270
+ ...core
271
+ } = options;
54
272
  const settings = { ...source, ...core };
55
- // A stand-in created by the entry point before this module loaded may already be on a map.
56
- const map = layer._map;
57
- map?.removeLayer(layer);
58
- delete layer.onAdd;
59
- delete layer.onRemove;
60
- if (L.Layer.types[type]) {
61
- Object.setPrototypeOf(layer, L.Layer.types[type].prototype);
62
- layer.options = Object.create(L.Layer.types[type].prototype.options);
63
- L.Layer.types[type].prototype.initialize.call(layer, settings);
64
- map?.addLayer(layer);
273
+ L.Util.setOptions(this, core);
274
+ this._type = type;
275
+ if (type === '3d') {
276
+ this._init3D(settings);
277
+ return;
278
+ }
279
+ if (type === 'pmtiles' && rasterModules) {
280
+ this._initRaster(settings);
65
281
  return;
66
282
  }
67
- Object.setPrototypeOf(layer, Pending.prototype);
68
- L.Util.setOptions(layer, core);
69
- map?.addLayer(layer);
283
+ this.onAdd = () => {};
284
+ this.onRemove = () => {};
70
285
  // ponytail: type methods (setOpacity, add, ...) exist only once `ready` resolves.
71
- loading = loading.catch(() => {}).then(() => import(`./types/${type}.js`));
72
- const pending = layer.ready = loading.then(() => {
73
- const map = layer._map;
74
- map?.removeLayer(layer);
75
- Object.setPrototypeOf(layer, L.Layer.types[type].prototype);
76
- layer.options = Object.create(L.Layer.types[type].prototype.options);
77
- L.Layer.types[type].prototype.initialize.call(layer, settings);
78
- map?.addLayer(layer);
79
- return layer.ready === pending ? layer : layer.ready;
286
+ loading = loading.catch(() => {}).then(async () => {
287
+ switch (type) {
288
+ case 'geojson': {
289
+ const { setGeoJSONData } = await import('./utils/setGeoJSONData.js');
290
+ return (layer, options) => {
291
+ layer._geojson = true;
292
+ layer.setData = data => setGeoJSONData(layer, data);
293
+ layer._init3D(options);
294
+ };
295
+ }
296
+ case 'pmtiles': {
297
+ rasterModules = await Promise.all([
298
+ import('./utils/read.js'),
299
+ import('./utils/getHeader.js'),
300
+ import('./utils/getZxy.js'),
301
+ import('./utils/onPMTileAdd.js'),
302
+ import('./utils/onPMTileRemove.js'),
303
+ import('./utils/rasterTiles.js'),
304
+ import('./utils/setPMTileOpacity.js'),
305
+ import('./utils/setPMTileZIndex.js'),
306
+ import('./utils/emptyNode.js'),
307
+ ]);
308
+ return (layer, options) => layer._initRaster(options);
309
+ }
310
+ case 'terrain':
311
+ return (await import('./utils/initTerrain.js')).initTerrain;
312
+ case 'sunlight':
313
+ return (await import('./utils/initSunlight.js')).initSunlight;
314
+ case 'traffic':
315
+ return (await import('./utils/initTraffic.js')).initTraffic;
316
+ case 'walk':
317
+ return (await import('./utils/initWalk.js')).initWalk;
318
+ default:
319
+ throw new Error(`Unknown layer type: ${type}`);
320
+ }
321
+ });
322
+ const ready = this.ready = loading.then(initialize => {
323
+ const map = this._map;
324
+ map?.removeLayer(this);
325
+ delete this.onAdd;
326
+ delete this.onRemove;
327
+ initialize(this, settings);
328
+ map?.addLayer(this);
329
+ return this.ready === ready ? this : this.ready;
80
330
  });
331
+ ready.catch(error => this.fire('error', { error }));
81
332
  },
333
+ });
334
+
335
+ L.Layer.addInitHook(function () {
336
+ if (this instanceof L.Polyline || this instanceof L.CircleMarker) {
337
+ const refresh = () => this._nativeGPU?.refresh?.();
338
+ this.beforeAdd = this.onAdd = this.onRemove = this._updateBounds = () => {};
339
+ this.getEvents = () => ({});
340
+ // Leaflet mutators call this renderer contract, but no SVG/Canvas renderer is created.
341
+ this._renderer = {
342
+ options: { tolerance: 0 },
343
+ _updatePath: refresh,
344
+ _updateStyle: refresh,
345
+ _bringToFront: () => this._nativeGPU?.reorder?.(true),
346
+ _bringToBack: () => this._nativeGPU?.reorder?.(false),
347
+ };
348
+ if (this instanceof L.Polyline) {
349
+ const closest = this.closestLayerPoint;
350
+ this.closestLayerPoint = function (point) {
351
+ this._project();
352
+ this._parts = this._rings;
353
+ return closest.call(this, point);
354
+ };
355
+ }
356
+ if (this instanceof L.Circle) {
357
+ const getBounds = this.getBounds;
358
+ this.getBounds = function () {
359
+ this._project();
360
+ return getBounds.call(this);
361
+ };
362
+ }
363
+ } else if (this instanceof L.GridLayer) {
364
+ const initialize = this._initContainer;
365
+ this._initContainer = function () {
366
+ initialize.call(this);
367
+ this._container.remove();
368
+ };
369
+ this._updateOpacity = function () {
370
+ if (!this._map) return;
371
+ const now = Date.now();
372
+ let fading = false, prune = false;
373
+ for (const tile of Object.values(this._tiles || {})) {
374
+ if (!tile.current || !tile.loaded) continue;
375
+ tile._gpuOpacity = this._map._fadeAnimated ? Math.min(1, (now - tile.loaded) / 200) : 1;
376
+ if (tile._gpuOpacity < 1) fading = true;
377
+ else if (!tile.active) {
378
+ this._onOpaqueTile(tile);
379
+ tile.active = true;
380
+ prune = true;
381
+ }
382
+ }
383
+ if (prune && !this._noPrune) this._pruneTiles();
384
+ this._nativeGPU?.refresh?.();
385
+ cancelAnimationFrame(this._fadeFrame);
386
+ if (fading) this._fadeFrame = requestAnimationFrame(() => this._updateOpacity());
387
+ };
388
+ } else if (this instanceof L.ImageOverlay && !(this instanceof L.VideoOverlay) && !(this instanceof L.SVGOverlay)) {
389
+ this.onAdd = function () {
390
+ if (!this._image) this._initImage();
391
+ if (this._image.complete && this._image.naturalWidth) queueMicrotask(() => this.fire('load'));
392
+ };
393
+ this.onRemove = () => {};
394
+ this.getEvents = () => ({});
395
+ this._reset = () => this._nativeGPU?.refresh?.();
396
+ }
82
397
  });
@@ -0,0 +1,4 @@
1
+ // Walls (non-horizontal triangles) of a mesh in world space, bucketed by 8 m cells; `origin` is the world translation
2
+ // at build time, since layer roots only move vertically with the terrain afterwards.
3
+
4
+ export const CELL = 8;
@@ -0,0 +1,66 @@
1
+ import { createMesh } from './createMesh.js';
2
+ import { triangulate } from './triangulate.js';
3
+
4
+ /**
5
+ * Bare-earth DEMs drop bridges: `getElevation` returns the deck height inside these polygons (GeoJSON
6
+ * Polygon/MultiPolygon with Z, e.g. IGN BD TOPO), and one mesh draws the 1.2 m thick decks.
7
+ * ponytail: anything under a deck (quays, boats asking `getElevation`) also gets the deck height.
8
+ */
9
+
10
+ export function addBridges(backend, geojson) {
11
+ const map = backend._map, crs = map.options.crs, zoom = backend._terrainZoom;
12
+ const origin = crs.project(backend.location), metres = Math.cos(backend.location.lat * Math.PI / 180);
13
+ const base = backend.root.position[1], position = [], normal = [], color = [];
14
+ const local = ([lng, lat, z]) => {
15
+ const p = crs.project(new L.LatLng(lat, lng));
16
+ return [(p.x - origin.x) * metres, z - base, -(p.y - origin.y) * metres];
17
+ };
18
+ const push = (p, n) => { position.push(...p); normal.push(...n); color.push(0.6, 0.58, 0.54); };
19
+ backend._bridges = new Map();
20
+ for (const { geometry } of geojson.features) {
21
+ const polygons = geometry.type === 'Polygon' ? [geometry.coordinates] : geometry.type === 'MultiPolygon' ? geometry.coordinates : [];
22
+ for (const polygon of polygons) {
23
+ const rings = polygon.map(ring => ring.slice(0, -1)).filter(ring => ring.length >= 3);
24
+ if (!rings.length) continue;
25
+ const pixels = rings.flat().map(([lng, lat, z]) => { const p = map.project([lat, lng], zoom); return [p.x, p.y, z]; });
26
+ const points = rings.flat().map(local);
27
+ let triangles;
28
+ try {
29
+ const starts = rings.map((ring, r) => rings.slice(0, r).reduce((sum, previous) => sum + previous.length, 0));
30
+ const [contour, ...holes] = rings.map((ring, r) => ring.map((c, i) => ({ x: pixels[starts[r] + i][0], y: pixels[starts[r] + i][1] })));
31
+ triangles = triangulate(contour, holes);
32
+ } catch { continue; }
33
+ const bridge = {
34
+ triangles: triangles.map(t => t.map(i => pixels[i])),
35
+ min: [Math.min(...pixels.map(p => p[0])), Math.min(...pixels.map(p => p[1]))],
36
+ max: [Math.max(...pixels.map(p => p[0])), Math.max(...pixels.map(p => p[1]))],
37
+ };
38
+ for (let x = Math.floor(bridge.min[0] / 64); x <= Math.floor(bridge.max[0] / 64); x++) {
39
+ for (let y = Math.floor(bridge.min[1] / 64); y <= Math.floor(bridge.max[1] / 64); y++) {
40
+ const key = `${x}/${y}`;
41
+ backend._bridges.set(key, [...backend._bridges.get(key) || [], bridge]);
42
+ }
43
+ }
44
+ const below = p => [p[0], p[1] - 1.2, p[2]];
45
+ for (let [a, b, c] of triangles) {
46
+ // Counter-clockwise seen from above, so double-sided shading keeps the top lit.
47
+ const [pa, pb, pc] = [points[a], points[b], points[c]];
48
+ if ((pb[2] - pa[2]) * (pc[0] - pa[0]) - (pb[0] - pa[0]) * (pc[2] - pa[2]) < 0) [b, c] = [c, b];
49
+ for (const i of [a, b, c]) push(points[i], [0, 1, 0]);
50
+ for (const i of [a, c, b]) push(below(points[i]), [0, -1, 0]);
51
+ }
52
+ let start = 0;
53
+ for (const ring of rings) {
54
+ for (let i = 0; i < ring.length; i++) {
55
+ const p = points[start + i], q = points[start + (i + 1) % ring.length];
56
+ const length = Math.hypot(q[0] - p[0], q[2] - p[2]) || 1, n = [(q[2] - p[2]) / length, 0, -(q[0] - p[0]) / length];
57
+ for (const corner of [p, q, below(q), p, below(q), below(p)]) push(corner, n);
58
+ }
59
+ start += ring.length;
60
+ }
61
+ }
62
+ }
63
+ if (position.length) {
64
+ backend._bridgeMesh = createMesh(backend, { position, normal, color });
65
+ }
66
+ }
@@ -0,0 +1,112 @@
1
+ import { createProgram } from './createProgram.js';
2
+ import { destroyTexture } from './destroyTexture.js';
3
+ import { terrainAtlas } from './terrainAtlas.js';
4
+ import { terrainGrid } from './terrainGrid.js';
5
+ import { setParent } from './setParent.js';
6
+ import { update } from './update.js';
7
+
8
+ export async function addRasterTile(backend, layer, coords, tile) {
9
+ const ready = await backend._terrainPromise;
10
+ if (!ready || !backend._map || backend._map._terrain3D !== backend || layer._terrain3D !== backend ||
11
+ tile.request.signal.aborted || !layer._rasterTiles.has(`${coords.z}/${coords.x}/${coords.y}`) ||
12
+ backend._rasterTiles.has(tile)) {
13
+ return;
14
+ }
15
+ // Match DEM pixel spacing, capped at 64 subdivisions per tile.
16
+ const divisions = Math.max(1, Math.min(64, 256 / 2 ** (coords.z - backend._terrainZoom)));
17
+ const map = backend._map, crs = map.options.crs;
18
+ const origin = crs.project(backend.location), metres = Math.cos(backend.location.lat * Math.PI / 180);
19
+ // Tile pixels map linearly to projected metres: one scaled unit grid per tile, elevation in the vertex shader.
20
+ const scale = crs.scale(coords.z), terrainScale = 2 ** (backend._terrainZoom - coords.z);
21
+ const corner = crs.transformation.untransform(new L.Point(coords.x * 256, coords.y * 256), scale);
22
+ const opposite = crs.transformation.untransform(new L.Point((coords.x + 1) * 256, (coords.y + 1) * 256), scale);
23
+ const device = backend.renderer.device;
24
+ const texture = tile.texture;
25
+ if (!backend._rasterProgram || backend._rasterProgram.device !== device) {
26
+ // DEM atlas over the archive's tile grid; invalid or missing samples become -1e9 (the shader's no-data).
27
+ // ponytail: one texture, capped by maxTextureDimension2D (32×32 DEM tiles at 8192 px); split it for larger archives.
28
+ const bounds = backend._terrainBounds, columns = bounds.max.x - bounds.min.x + 1, rows = bounds.max.y - bounds.min.y + 1;
29
+ const { elevations, low, high } = terrainAtlas(backend._terrainTiles, bounds);
30
+ if (backend._dem) destroyTexture(backend, backend._dem.texture);
31
+ backend._dem = {
32
+ texture: device.createTexture({
33
+ size: [columns * 256, rows * 256],
34
+ format: 'r32float',
35
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
36
+ }),
37
+ low: Number.isFinite(low) ? low : backend._terrainOriginElevation,
38
+ high: Number.isFinite(high) ? high : backend._terrainOriginElevation,
39
+ };
40
+ device.queue.writeTexture({ texture: backend._dem.texture }, elevations,
41
+ { bytesPerRow: columns * 1024 }, [columns * 256, rows * 256]);
42
+ backend._terrainGrids = new Map();
43
+ backend._rasterProgram = createProgram(backend, {
44
+ baseTexture: texture,
45
+ unlit: true,
46
+ terrain: backend._dem,
47
+ alphaMode: 'BLEND',
48
+ depthWrite: true,
49
+ });
50
+ }
51
+ let attributes = backend._terrainGrids.get(divisions);
52
+ if (!attributes) {
53
+ attributes = terrainGrid(divisions);
54
+ for (const [name, attribute] of Object.entries(attributes)) {
55
+ attribute.size ||= 1;
56
+ attribute.count = attribute.data.length / attribute.size;
57
+ attribute.indexFormat = 'uint16';
58
+ attribute.buffer = device.createBuffer({
59
+ size: Math.max(4, attribute.data.byteLength),
60
+ usage: name === 'index'
61
+ ? GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
62
+ : GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
63
+ });
64
+ device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
65
+ }
66
+ backend._terrainGrids.set(divisions, attributes);
67
+ }
68
+ const base = backend._terrainOriginElevation;
69
+ const bottom = Math.min(backend._dem.low, base) - base, top = Math.max(backend._dem.high, base) - base;
70
+ const sizeX = (opposite.x - corner.x) * metres, sizeZ = -(opposite.y - corner.y) * metres;
71
+ // ponytail: ray picking sees the flat unit grid; read the DEM back if terrain must be pickable.
72
+ const geometry = {
73
+ device,
74
+ attributes,
75
+ drawRange: { start: 0, count: attributes.index.count },
76
+ // Local bounds whose radius, scaled by the largest axis, still covers the displaced tile.
77
+ bounds: {
78
+ min: [0, bottom, 0], max: [1, top, 1], center: [0.5, (bottom + top) / 2, 0.5],
79
+ radius: Math.hypot(sizeX, top - bottom, sizeZ) / 2 / Math.max(sizeX, 1, sizeZ),
80
+ },
81
+ };
82
+ const mesh = {
83
+ position: [(corner.x - origin.x) * metres, 0, -(corner.y - origin.y) * metres],
84
+ rotation: [0, 0, 0],
85
+ scale: [sizeX, 1, sizeZ],
86
+ worldMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
87
+ children: [],
88
+ visible: true,
89
+ device,
90
+ geometry,
91
+ program: backend._rasterProgram,
92
+ texture,
93
+ // DEM pixel of the tile's corner, DEM pixels per tile, and the elevation at the layer origin.
94
+ terrain: [
95
+ coords.x * 256 * terrainScale - backend._terrainBounds.min.x * 256,
96
+ coords.y * 256 * terrainScale - backend._terrainBounds.min.y * 256,
97
+ 256 * terrainScale,
98
+ base,
99
+ ],
100
+ tile,
101
+ opacity: layer.options.opacity ?? 1,
102
+ id: L.Layer._nextId++,
103
+ renderOrder: layer.options.zIndex || 0,
104
+ fadeDuration: 250,
105
+ fadeStart: tile.loadedAt,
106
+ ground: true,
107
+ };
108
+ tile.mesh.visible = false;
109
+ setParent(mesh, backend.root);
110
+ update(backend);
111
+ backend._rasterTiles.set(tile, mesh);
112
+ }
@@ -0,0 +1,9 @@
1
+ /** Point and unit direction at distance `s` along `points` ([x, z, y?]) with cumulative `lengths`. */
2
+
3
+ export function along(points, lengths, s) {
4
+ let i = 1;
5
+ while (i < lengths.length - 1 && lengths[i] < s) i++;
6
+ const a = points[i - 1], b = points[i], d = lengths[i] - lengths[i - 1] || 1;
7
+ const t = (s - lengths[i - 1]) / d;
8
+ return { x: a[0] + (b[0] - a[0]) * t, y: (a[2] ?? 0) + ((b[2] ?? 0) - (a[2] ?? 0)) * t, z: a[1] + (b[1] - a[1]) * t, dx: (b[0] - a[0]) / d, dz: (b[1] - a[1]) / d };
9
+ }
@@ -0,0 +1,20 @@
1
+
2
+ export function atmosphere(altitude) {
3
+ if (!Number.isFinite(altitude)) {
4
+ throw new Error('Invalid solar altitude');
5
+ }
6
+ const stops = [
7
+ [-18, [3, 7, 20], [17, 28, 54], [0.025, 0.04, 0.09]],
8
+ [-6, [37, 53, 84], [182, 106, 86], [0.12, 0.10, 0.14]],
9
+ [0, [101, 131, 171], [246, 170, 115], [0.38, 0.24, 0.18]],
10
+ [10, [74, 147, 208], [197, 221, 237], [0.80, 0.75, 0.68]],
11
+ [25, [53, 144, 213], [223, 238, 250], [1, 1, 1]],
12
+ ];
13
+ const upper = stops.findIndex(stop => stop[0] >= altitude);
14
+ const b = stops[upper < 0 ? stops.length - 1 : upper],
15
+ a = stops[Math.max(0, upper - 1)];
16
+ const t = a === b || upper < 0 ? 1 : (altitude - a[0]) / (b[0] - a[0]);
17
+ const mix = index => a[index].map((value, i) => value + (b[index][i] - value) * t);
18
+ const rgb = values => `rgb(${values.map(Math.round).join(', ')})`;
19
+ return { background: `linear-gradient(${rgb(mix(1))}, ${rgb(mix(2))})`, tint: mix(3) };
20
+ }