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
@@ -1,143 +0,0 @@
1
- import './3d.js';
2
- import { read, getHeader, getZxy } from '../scene/pmtiles.js';
3
- import { decompress } from '../utils/pmtiles.js';
4
-
5
- /** A raster TileLayer backed by the shared PMTiles reader. */
6
- L.Layer.types.pmtiles = L.TileLayer.extend({
7
- _read(offset, length, signal) { return read(this, offset, length, signal); },
8
- _decompress(data, compression) { return decompress(data, compression); },
9
- getHeader() { return getHeader(this); },
10
- getZxy(z, x, y, signal) { return getZxy(this, z, x, y, signal); },
11
-
12
- initialize(options) {
13
- L.TileLayer.prototype.initialize.call(this, options.url, options);
14
- this.url = new URL(options.url, document.baseURI).href;
15
- this._directories = new Map();
16
- this.on('tileunload', this._releaseTile, this);
17
- this.on('load tileunload', () => L.Layer.types['3d']._renderers.get(this._map)?.update());
18
- this.ready = Promise.resolve(this.options.archive || this).then(async archive => {
19
- const header = await archive.getHeader();
20
- this.options.archive = archive;
21
- this.header = header;
22
- if (this.options.maxNativeZoom === undefined) this.options.maxNativeZoom = header.maxZoom;
23
- this.fire('ready');
24
- return this;
25
- }).catch(error => {
26
- this.fire('error', { error });
27
- throw error;
28
- });
29
- },
30
-
31
- onAdd(map) {
32
- if (this.header) {
33
- L.TileLayer.prototype.onAdd.call(this, map);
34
- this._setTerrain3D(map._terrain3D);
35
- } else {
36
- this.ready = this.ready.then(layer => {
37
- if (this._map === map && map.hasLayer(this) && !this._container) {
38
- L.TileLayer.prototype.onAdd.call(this, map);
39
- this._setTerrain3D(map._terrain3D);
40
- }
41
- return layer;
42
- });
43
- }
44
- },
45
-
46
- onRemove(map) {
47
- this._setTerrain3D(null);
48
- if (this._container) L.TileLayer.prototype.onRemove.call(this, map);
49
- },
50
-
51
- setOpacity(opacity) {
52
- L.TileLayer.prototype.setOpacity.call(this, opacity);
53
- L.Layer.types['3d']._renderers.get(this._map)?.update();
54
- return this;
55
- },
56
-
57
- setZIndex(zIndex) {
58
- L.TileLayer.prototype.setZIndex.call(this, zIndex);
59
- L.Layer.types['3d']._renderers.get(this._map)?.update();
60
- return this;
61
- },
62
-
63
- createTile(coords, done) {
64
- const tile = document.createElement('img');
65
- tile.alt = '';
66
- if (this.options.crossOrigin || this.options.crossOrigin === '') {
67
- tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
68
- }
69
- if (typeof this.options.referrerPolicy === 'string') tile.referrerPolicy = this.options.referrerPolicy;
70
- tile.request = new AbortController();
71
- this.ready.then(() => {
72
- if (tile.request.signal.aborted) return;
73
- return this.options.archive.getZxy(coords.z, coords.x, coords.y, tile.request.signal);
74
- }).then(async result => {
75
- if (tile.request.signal.aborted) return;
76
- if (!result) throw new Error(`Tile ${coords.z}/${coords.x}/${coords.y} is not in the offline archive`);
77
- await new Promise((resolve, reject) => {
78
- const finish = error => {
79
- tile.request.signal.removeEventListener('abort', abort);
80
- tile.onload = tile.onerror = null;
81
- this._releaseURL(tile);
82
- if (error) reject(error);
83
- else resolve();
84
- };
85
- const abort = () => finish();
86
- tile.request.signal.addEventListener('abort', abort, { once: true });
87
- tile.objectURL = URL.createObjectURL(new Blob([result.data]));
88
- tile.onload = () => finish();
89
- tile.onerror = () => finish(new Error(`Unable to decode tile ${coords.z}/${coords.x}/${coords.y}`));
90
- tile.src = tile.objectURL;
91
- });
92
- if (tile.request.signal.aborted) return;
93
- tile.done = true;
94
- this._registerTerrainTile(coords, tile);
95
- done(null, tile);
96
- }).catch(error => {
97
- if (tile.request.signal.aborted) return;
98
- tile.error = error.message;
99
- this._tileOnError(done, tile, error);
100
- });
101
- return tile;
102
- },
103
-
104
- _abortLoading() {
105
- // Requests can still be pending while an image with no src reports complete.
106
- for (const { coords, el } of Object.values(this._tiles)) {
107
- if (coords.z !== this._tileZoom) this._releaseTile({ tile: el });
108
- }
109
- L.TileLayer.prototype._abortLoading.call(this);
110
- },
111
-
112
- _setTerrain3D(terrain) {
113
- if (this._terrain3D === terrain) return;
114
- for (const { el } of Object.values(this._tiles || {})) this._terrain3D?.removeRasterTile(el);
115
- this._terrain3D = terrain || null;
116
- if (this._terrain3D) {
117
- for (const { coords, el } of Object.values(this._tiles || {})) {
118
- if (el.done) this._registerTerrainTile(coords, el);
119
- }
120
- }
121
- },
122
-
123
- _registerTerrainTile(coords, tile) {
124
- if (!this._terrain3D) return;
125
- const terrain = this._terrain3D;
126
- terrain.addRasterTile(this, coords, tile).catch(error => {
127
- if (this._terrain3D === terrain && tile.isConnected) this.fire('tileerror', { tile, coords, error });
128
- });
129
- },
130
-
131
- _releaseURL(tile) {
132
- if (tile.objectURL) {
133
- URL.revokeObjectURL(tile.objectURL);
134
- tile.objectURL = null;
135
- }
136
- },
137
-
138
- _releaseTile({ tile }) {
139
- this._terrain3D?.removeRasterTile(tile);
140
- tile.request.abort();
141
- this._releaseURL(tile);
142
- },
143
- });
@@ -1,142 +0,0 @@
1
- import { atmosphere, moonPosition, solarPosition, projectCelestialBody } from '../utils/sun.js';
2
- import { underEntry } from '../utils/control.js';
3
-
4
- function installSunlight(map) {
5
- const L = globalThis.L;
6
- const control = new L.Control({ position: 'bottomright' });
7
- control.live = true;
8
- let date, slider, output, status, timer;
9
- const originalSky = map.getContainer().style.getPropertyValue('--leaflet-sky-background');
10
- const disc = 'position:absolute;width:18px;height:18px;border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;';
11
- const sunDisc = L.DomUtil.create('div', 'sunlight-sun');
12
- const moonDisc = L.DomUtil.create('div', 'sunlight-moon');
13
- sunDisc.style.cssText = disc + 'background:#fff3bd;box-shadow:0 0 18px 7px #ffd27699;';
14
- moonDisc.style.cssText = disc + 'background:#dce5f2;box-shadow:0 0 10px 2px #cbdcff55;';
15
- sunDisc.setAttribute('role', 'img'); sunDisc.setAttribute('aria-label', 'Sun');
16
- moonDisc.setAttribute('role', 'img'); moonDisc.setAttribute('aria-label', 'Moon');
17
- const updateSky = () => {
18
- const sun = map._sunlight, sky = map._pitchSky;
19
- if (sun) map.getContainer().style.setProperty('--leaflet-sky-background', sun.background);
20
- else if (originalSky) map.getContainer().style.setProperty('--leaflet-sky-background', originalSky);
21
- else map.getContainer().style.removeProperty('--leaflet-sky-background');
22
- const size = map.getSize(), pitch = map.getPitch() * Math.PI / 180, bearing = map.getBearing() * Math.PI / 180;
23
- for (const [disc, body] of [[sunDisc, sun], [moonDisc, sun?.moon]]) {
24
- disc.hidden = true;
25
- if (!sky || !body || body.altitude <= 0 || !sun) continue;
26
- if (disc.parentNode !== sky) sky.append(disc);
27
- const point = projectCelestialBody(body.direction, size, pitch, bearing);
28
- if (!point) continue;
29
- const { left, top } = point;
30
- disc.hidden = left < 0 || left > size.x || top < 0 || top > sky.clientHeight || sky.style.display === 'none';
31
- disc.style.left = `${left}px`; disc.style.top = `${top}px`;
32
- }
33
- };
34
- const render = () => L.Layer.types['3d']?._renderers.get(map)?.update();
35
- const update = () => {
36
- try {
37
- if (control.live) control.time = new Date();
38
- const time = control.time.toISOString();
39
- date.value = time.slice(0, 10);
40
- slider.value = String(control.time.getUTCHours() * 60 + control.time.getUTCMinutes());
41
- output.textContent = `${time.slice(11, 16)} UTC${control.live ? ' · now' : ''}`;
42
- const center = map.getCenter();
43
- const sun = map._sunlight = solarPosition(control.time, center.lat, center.lng);
44
- Object.assign(sun, atmosphere(sun.altitude));
45
- sun.moon = moonPosition(control.time, center.lat, center.lng);
46
- status.textContent = sun.altitude <= 0 ? 'Night · no direct sunlight' :
47
- sun.altitude < 3 ? 'Low sun · shadows paused' : `Sun altitude ${sun.altitude.toFixed(1)}°`;
48
- map.fire('simulationtimechange', { time: new Date(control.time), live: control.live });
49
- updateSky(); render();
50
- } catch (error) {
51
- delete map._sunlight;
52
- updateSky();
53
- render();
54
- status.textContent = `Error: ${error.message}`;
55
- console.error('Solar simulation', error);
56
- }
57
- };
58
- const selectTime = () => {
59
- control.live = false;
60
- if (!date.value || !date.validity.valid) {
61
- control.time = new Date(NaN);
62
- map.fire('simulationtimechange', { time: null, live: false });
63
- delete map._sunlight;
64
- updateSky();
65
- render();
66
- status.textContent = 'Error: choose a valid solar date';
67
- return;
68
- }
69
- control.time = new Date(`${date.value}T00:00:00Z`);
70
- control.time.setUTCMinutes(Number(slider.value));
71
- update();
72
- };
73
- control.onAdd = () => {
74
- const container = L.DomUtil.create('div', 'sunlight-control');
75
- container.style.cssText = 'color:#222;width:min(200px,calc(100vw - 60px));font:12px/1.4 sans-serif;';
76
- date = document.createElement('input');
77
- date.type = 'date';
78
- date.style.cssText = 'width:100%;box-sizing:border-box;';
79
- date.setAttribute('aria-label', 'Solar date (UTC)');
80
- slider = document.createElement('input');
81
- slider.type = 'range';
82
- slider.style.cssText = 'width:100%;box-sizing:border-box;margin:10px 0 4px;cursor:pointer;';
83
- slider.min = '0'; slider.max = '1439'; slider.step = '1';
84
- slider.setAttribute('aria-label', 'Time of day (UTC)');
85
- output = document.createElement('output');
86
- output.style.cssText = 'font-weight:bold;font-variant-numeric:tabular-nums;';
87
- output.setAttribute('aria-live', 'off');
88
- const now = document.createElement('button');
89
- now.type = 'button'; now.textContent = 'Now';
90
- now.onclick = () => { control.live = true; update(); };
91
- const timeRow = document.createElement('div');
92
- timeRow.className = 'sunlight-time';
93
- timeRow.style.cssText = 'display:flex;justify-content:space-between;align-items:center;';
94
- timeRow.append(output, now);
95
- status = document.createElement('div');
96
- status.className = 'sunlight-status';
97
- status.style.marginTop = '5px';
98
- status.setAttribute('role', 'status');
99
- const note = document.createElement('small');
100
- note.style.color = '#555';
101
- note.textContent = 'Indicative · loaded geometry only. Streetlight illumination is estimated, not measured lux.';
102
- container.append(date, slider, timeRow, status, note);
103
- slider.oninput = selectTime;
104
- date.onchange = selectTime;
105
- L.DomEvent.disableClickPropagation(container);
106
- L.DomEvent.disableScrollPropagation(container);
107
- update();
108
- timer = setInterval(() => { if (control.live) update(); }, 60000);
109
- map.on('moveend', update);
110
- map.on('move rotate pitch resize', updateSky);
111
- return container;
112
- };
113
- control.onRemove = () => {
114
- clearInterval(timer);
115
- map.fire('simulationtimechange', { time: null, live: false });
116
- map.off('moveend', update);
117
- map.off('move rotate pitch resize', updateSky);
118
- delete map._sunlight;
119
- updateSky();
120
- sunDisc.remove(); moonDisc.remove();
121
- render();
122
- };
123
- return control;
124
- }
125
-
126
- // Sun/moon clock control and sky colours; the control is created on first add (`layer.control`).
127
- L.Layer.types.sunlight = L.Layer.extend({
128
- onAdd(map) {
129
- this.control = this.control || installSunlight(map);
130
- if (!this.control._map) this.control.addTo(map);
131
- // Shown under this layer's entry in the layers control; a standalone control without one.
132
- const container = this.control.getContainer(), nested = underEntry(this, container);
133
- container.classList.toggle('leaflet-control', !nested);
134
- container.classList.toggle('leaflet-bar', !nested);
135
- Object.assign(container.style, nested
136
- ? { background: '', padding: '2px 0 6px 20px', margin: '0' }
137
- : { background: '#fff', padding: '8px', margin: '' });
138
- },
139
- onRemove() {
140
- this.control.remove();
141
- },
142
- });
@@ -1,331 +0,0 @@
1
- import { bridgeElevation, terrainElevation, terrainGrid, terrainAtlas } from '../utils/terrain.js';
2
- import { triangulate } from '../utils/geometry.js';
3
- import './3d.js';
4
- import './pmtiles.js';
5
-
6
- /**
7
- * Renders IGN Float32 DEM tiles and PMTiles raster basemaps in the shared WebGPU scene.
8
- * Source options: `url` (single-zoom Float32 PMTiles DEM); `bridges` (optional GeoJSON deck polygons with Z, see _addBridges).
9
- */
10
- L.Layer.types.terrain = L.Layer.types['3d'].extend({
11
- initialize(options = {}) {
12
- const terrainSource = options.url;
13
- const layerOptions = { ...options };
14
- delete layerOptions.url;
15
- L.Layer.types['3d'].prototype.initialize.call(this, layerOptions);
16
- this.terrainSource = terrainSource;
17
- this._terrainTiles = new Map();
18
- this._rasterTiles = new Map();
19
- this._terrainReady = false;
20
- },
21
-
22
- onAdd(map) {
23
- if (map._terrain3D && map._terrain3D !== this) throw new Error('Only one terrain layer can be active per map');
24
- map._terrain3D = this;
25
- L.Layer.types['3d'].prototype.onAdd.call(this, map);
26
- this._terrainPromise = this.root
27
- ? this._loadTerrain()
28
- : new Promise(resolve => this.once('ready', () => this._loadTerrain().then(resolve), this));
29
- map.eachLayer(layer => layer._setTerrain3D?.(this));
30
- map.fire('terrainchange');
31
- },
32
-
33
- onRemove(map) {
34
- this._terrainController?.abort();
35
- this._terrainLoading = false;
36
- this._terrainReady = false;
37
- map.eachLayer(layer => layer._setTerrain3D?.(null));
38
- for (const tile of this._rasterTiles.keys()) this.removeRasterTile(tile);
39
- if (map._terrain3D === this) delete map._terrain3D;
40
- for (const layer of Object.values(map._layers)) layer._setTerrainHeight?.();
41
- map.fire('terrainchange');
42
- this._terrainTiles.clear();
43
- this._terrainOriginElevation = 0;
44
- this._terrainPromise = null;
45
- if (this._rasterProgram) this._removeProgram(this._rasterProgram);
46
- this._rasterProgram = null;
47
- if (this._dem) this._destroyTexture(this._dem.texture);
48
- this._dem = null;
49
- for (const grid of this._terrainGrids?.values() || []) {
50
- for (const attribute of Object.values(grid)) this._destroyTexture(attribute.buffer);
51
- }
52
- this._terrainGrids = null;
53
- this._bridges = null;
54
- this._disposeMesh(this._bridgeMesh);
55
- this._bridgeMesh = null;
56
- L.Layer.types['3d'].prototype.onRemove.call(this, map);
57
- },
58
-
59
- async _loadTerrain() {
60
- if (this._terrainLoading || !this._map) return;
61
- this._terrainLoading = true;
62
- this._terrainReady = false;
63
- const controller = this._terrainController = new AbortController();
64
- try {
65
- if (!this.terrainSource) throw new Error('Terrain layer requires a PMTiles elevation archive');
66
- const archive = this._terrainArchive = new L.Layer({ source: { type: 'pmtiles', url: this.terrainSource } });
67
- await archive.ready;
68
- const header = archive.header;
69
- if (header.tileType !== 0 || header.minZoom !== header.maxZoom) {
70
- throw new Error('Expected a single-zoom Float32 PMTiles terrain archive');
71
- }
72
- this._terrainZoom = header.maxZoom;
73
- const map = this._map;
74
- const northwest = map.project([header.maxLat, header.minLon], this._terrainZoom).divideBy(256).floor();
75
- const southeast = map.project([header.minLat, header.maxLon], this._terrainZoom).divideBy(256).floor();
76
- this._terrainBounds = new L.Bounds(northwest, southeast);
77
- const tiles = [];
78
- for (let x = northwest.x; x <= southeast.x; x++) {
79
- for (let y = northwest.y; y <= southeast.y; y++) tiles.push({ z: this._terrainZoom, x, y });
80
- }
81
- let next = 0;
82
- await Promise.all(Array.from({ length: Math.min(4, tiles.length) }, async () => {
83
- while (next < tiles.length) {
84
- controller.signal.throwIfAborted();
85
- const coords = tiles[next++];
86
- const result = await archive.getZxy(coords.z, coords.x, coords.y, controller.signal);
87
- if (!result || result.data.byteLength !== 256 * 256 * 4) {
88
- throw new Error(`Missing or invalid Float32 terrain tile ${coords.z}/${coords.x}/${coords.y}`);
89
- }
90
- this._terrainTiles.set(`${coords.x}/${coords.y}`, new Float32Array(result.data));
91
- }
92
- }));
93
- const bridges = this.options.bridges && await fetch(this.options.bridges, { signal: controller.signal })
94
- .then(response => { if (!response.ok) throw new Error(`Bridges: HTTP ${response.status}`); return response.json(); });
95
- if (controller.signal.aborted || this._map !== map) return;
96
- this._terrainReady = true;
97
- this._terrainOriginElevation = this._getElevation(this.location) ?? 0;
98
- for (const layer of Object.values(map._layers)) layer._setTerrainHeight?.();
99
- if (bridges) this._addBridges(bridges);
100
- map.fire('terrainchange');
101
- this.update();
102
- this.fire('terrainready');
103
- return true;
104
- } catch (error) {
105
- if (!controller.signal.aborted) this.fire('error', { error });
106
- return false;
107
- } finally {
108
- this._terrainLoading = false;
109
- }
110
- },
111
-
112
- /** @param {L.LatLng|L.Point} location LatLng, or a pixel point at the terrain zoom. */
113
- _getElevation(location) {
114
- if (!this._map || !this._terrainReady) return null;
115
- const point = location instanceof L.Point ? location : this._map.project(location, this._terrainZoom);
116
- return bridgeElevation(point, this._bridges) ?? terrainElevation(point, this._terrainTiles);
117
- },
118
-
119
- /**
120
- * Bare-earth DEMs drop bridges: `_getElevation` returns the deck height inside these polygons (GeoJSON
121
- * Polygon/MultiPolygon with Z, e.g. IGN BD TOPO), and one mesh draws the 1.2 m thick decks.
122
- * ponytail: anything under a deck (quays, boats asking `_getElevation`) also gets the deck height.
123
- */
124
- _addBridges(geojson) {
125
- const map = this._map, crs = map.options.crs, zoom = this._terrainZoom;
126
- const origin = crs.project(this.location), metres = Math.cos(this.location.lat * Math.PI / 180);
127
- const base = this.root.position[1], position = [], normal = [], color = [];
128
- const local = ([lng, lat, z]) => {
129
- const p = crs.project(new L.LatLng(lat, lng));
130
- return [(p.x - origin.x) * metres, z - base, -(p.y - origin.y) * metres];
131
- };
132
- const push = (p, n) => { position.push(...p); normal.push(...n); color.push(0.6, 0.58, 0.54); };
133
- this._bridges = new Map();
134
- for (const { geometry } of geojson.features) {
135
- const polygons = geometry.type === 'Polygon' ? [geometry.coordinates] : geometry.type === 'MultiPolygon' ? geometry.coordinates : [];
136
- for (const polygon of polygons) {
137
- const rings = polygon.map(ring => ring.slice(0, -1)).filter(ring => ring.length >= 3);
138
- if (!rings.length) continue;
139
- const pixels = rings.flat().map(([lng, lat, z]) => { const p = map.project([lat, lng], zoom); return [p.x, p.y, z]; });
140
- const points = rings.flat().map(local);
141
- let triangles;
142
- try {
143
- const starts = rings.map((ring, r) => rings.slice(0, r).reduce((sum, previous) => sum + previous.length, 0));
144
- const [contour, ...holes] = rings.map((ring, r) => ring.map((c, i) => ({ x: pixels[starts[r] + i][0], y: pixels[starts[r] + i][1] })));
145
- triangles = triangulate(contour, holes);
146
- } catch { continue; }
147
- const bridge = {
148
- triangles: triangles.map(t => t.map(i => pixels[i])),
149
- min: [Math.min(...pixels.map(p => p[0])), Math.min(...pixels.map(p => p[1]))],
150
- max: [Math.max(...pixels.map(p => p[0])), Math.max(...pixels.map(p => p[1]))],
151
- };
152
- for (let x = Math.floor(bridge.min[0] / 64); x <= Math.floor(bridge.max[0] / 64); x++) {
153
- for (let y = Math.floor(bridge.min[1] / 64); y <= Math.floor(bridge.max[1] / 64); y++) {
154
- const key = `${x}/${y}`;
155
- this._bridges.set(key, [...this._bridges.get(key) || [], bridge]);
156
- }
157
- }
158
- const below = p => [p[0], p[1] - 1.2, p[2]];
159
- for (let [a, b, c] of triangles) {
160
- // Counter-clockwise seen from above, so double-sided shading keeps the top lit.
161
- const [pa, pb, pc] = [points[a], points[b], points[c]];
162
- if ((pb[2] - pa[2]) * (pc[0] - pa[0]) - (pb[0] - pa[0]) * (pc[2] - pa[2]) < 0) [b, c] = [c, b];
163
- for (const i of [a, b, c]) push(points[i], [0, 1, 0]);
164
- for (const i of [a, c, b]) push(below(points[i]), [0, -1, 0]);
165
- }
166
- let start = 0;
167
- for (const ring of rings) {
168
- for (let i = 0; i < ring.length; i++) {
169
- const p = points[start + i], q = points[start + (i + 1) % ring.length];
170
- 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];
171
- for (const corner of [p, q, below(q), p, below(q), below(p)]) push(corner, n);
172
- }
173
- start += ring.length;
174
- }
175
- }
176
- }
177
- if (position.length) this._bridgeMesh = this._createMesh({ position, normal, color });
178
- },
179
-
180
- async addRasterTile(layer, coords, tile) {
181
- const [ready, bitmap] = await Promise.all([this._terrainPromise, createImageBitmap(tile)]);
182
- if (!ready || !this._map || this._map._terrain3D !== this || layer._terrain3D !== this ||
183
- tile.request.signal.aborted || !tile.isConnected || this._rasterTiles.has(tile)) {
184
- bitmap.close();
185
- return;
186
- }
187
- // Match DEM pixel spacing, capped at 64 subdivisions per tile.
188
- const divisions = Math.max(1, Math.min(64, 256 / 2 ** (coords.z - this._terrainZoom)));
189
- const map = this._map, crs = map.options.crs;
190
- const origin = crs.project(this.location), metres = Math.cos(this.location.lat * Math.PI / 180);
191
- // Tile pixels map linearly to projected metres: one scaled unit grid per tile, elevation in the vertex shader.
192
- const scale = crs.scale(coords.z), terrainScale = 2 ** (this._terrainZoom - coords.z);
193
- const corner = crs.transformation.untransform(new L.Point(coords.x * 256, coords.y * 256), scale);
194
- const opposite = crs.transformation.untransform(new L.Point((coords.x + 1) * 256, (coords.y + 1) * 256), scale);
195
- const device = this.renderer.device;
196
- const texture = {
197
- device,
198
- texture: device.createTexture({
199
- size: [tile.width, tile.height],
200
- format: 'rgba8unorm',
201
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
202
- }),
203
- sampler: device.createSampler({ addressModeU: 'clamp-to-edge', addressModeV: 'clamp-to-edge' }),
204
- samplerOptions: { addressModeU: 'clamp-to-edge', addressModeV: 'clamp-to-edge' },
205
- image: tile, format: 'rgba8unorm', srgb: false, flipY: false, uploaded: tile,
206
- };
207
- device.queue.copyExternalImageToTexture({ source: bitmap }, { texture: texture.texture }, [tile.width, tile.height]);
208
- bitmap.close();
209
- if (!this._rasterProgram || this._rasterProgram.device !== device) {
210
- // DEM atlas over the archive's tile grid; invalid or missing samples become -1e9 (the shader's no-data).
211
- // ponytail: one texture, capped by maxTextureDimension2D (32×32 DEM tiles at 8192 px); split it for larger archives.
212
- const bounds = this._terrainBounds, columns = bounds.max.x - bounds.min.x + 1, rows = bounds.max.y - bounds.min.y + 1;
213
- const { elevations, low, high } = terrainAtlas(this._terrainTiles, bounds);
214
- if (this._dem) this._destroyTexture(this._dem.texture);
215
- this._dem = {
216
- texture: device.createTexture({
217
- size: [columns * 256, rows * 256],
218
- format: 'r32float',
219
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
220
- }),
221
- low: Number.isFinite(low) ? low : this._terrainOriginElevation,
222
- high: Number.isFinite(high) ? high : this._terrainOriginElevation,
223
- };
224
- device.queue.writeTexture({ texture: this._dem.texture }, elevations,
225
- { bytesPerRow: columns * 1024 }, [columns * 256, rows * 256]);
226
- this._terrainGrids = new Map();
227
- this._rasterProgram = this._createProgram({
228
- baseTexture: texture,
229
- unlit: true,
230
- alphaMode: 'BLEND',
231
- terrain: this._dem,
232
- });
233
- }
234
- let attributes = this._terrainGrids.get(divisions);
235
- if (!attributes) {
236
- attributes = terrainGrid(divisions);
237
- for (const [name, attribute] of Object.entries(attributes)) {
238
- attribute.size ||= 1;
239
- attribute.count = attribute.data.length / attribute.size;
240
- attribute.indexFormat = 'uint16';
241
- attribute.buffer = device.createBuffer({
242
- size: Math.max(4, attribute.data.byteLength),
243
- usage: name === 'index'
244
- ? GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
245
- : GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
246
- });
247
- device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
248
- }
249
- this._terrainGrids.set(divisions, attributes);
250
- }
251
- const base = this._terrainOriginElevation;
252
- const bottom = Math.min(this._dem.low, base) - base, top = Math.max(this._dem.high, base) - base;
253
- const sizeX = (opposite.x - corner.x) * metres, sizeZ = -(opposite.y - corner.y) * metres;
254
- // ponytail: ray picking sees the flat unit grid; read the DEM back if terrain must be pickable.
255
- const geometry = {
256
- device,
257
- attributes,
258
- drawRange: { start: 0, count: attributes.index.count },
259
- // Local bounds whose radius, scaled by the largest axis, still covers the displaced tile.
260
- bounds: {
261
- min: [0, bottom, 0], max: [1, top, 1], center: [0.5, (bottom + top) / 2, 0.5],
262
- radius: Math.hypot(sizeX, top - bottom, sizeZ) / 2 / Math.max(sizeX, 1, sizeZ),
263
- },
264
- };
265
- const mesh = {
266
- position: [(corner.x - origin.x) * metres, 0, -(corner.y - origin.y) * metres],
267
- rotation: [0, 0, 0],
268
- scale: [sizeX, 1, sizeZ],
269
- worldMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
270
- children: [],
271
- visible: true,
272
- device,
273
- geometry,
274
- program: this._rasterProgram,
275
- texture,
276
- // DEM pixel of the tile's corner, DEM pixels per tile, and the elevation at the layer origin.
277
- terrain: [
278
- coords.x * 256 * terrainScale - this._terrainBounds.min.x * 256,
279
- coords.y * 256 * terrainScale - this._terrainBounds.min.y * 256,
280
- 256 * terrainScale,
281
- base,
282
- ],
283
- tile,
284
- opacity: layer.options.opacity ?? 1,
285
- id: L.Layer.types['3d']._nextId++,
286
- renderOrder: -1,
287
- };
288
- this.add(mesh);
289
- this._rasterTiles.set(tile, mesh);
290
- tile._terrainVisibility = tile.style.visibility;
291
- },
292
-
293
- removeRasterTile(tile) {
294
- tile._terrainRequest?.abort();
295
- const mesh = this._rasterTiles.get(tile);
296
- if (!mesh) return;
297
- this.remove(mesh);
298
- this._destroyTexture(mesh.texture.texture);
299
- this._rasterTiles.delete(tile);
300
- tile.style.visibility = tile._terrainVisibility;
301
- delete tile._terrainVisibility;
302
- },
303
- });
304
-
305
- /**
306
- * WGSL twin of _getElevation for the vertex shader: bilinear DEM pixels, or the first valid
307
- * neighbour near no-data (stored as -1e9), else `base`. Expects `dem: texture_2d<f32>`.
308
- */
309
- L.Layer.types.terrain.elevationWGSL = `
310
- fn demSample(pixel: vec2<i32>) -> f32 {
311
- if (any(pixel < vec2<i32>(0)) || any(pixel >= vec2<i32>(textureDimensions(dem)))) { return -1e9; }
312
- return textureLoad(dem, pixel, 0).r;
313
- }
314
- fn elevation(pixel: vec2<f32>, base: f32) -> f32 {
315
- let p = pixel - vec2<f32>(0.5);
316
- let f = fract(p);
317
- let i = vec2<i32>(floor(p));
318
- let v00 = demSample(i);
319
- let v10 = demSample(i + vec2<i32>(1, 0));
320
- let v01 = demSample(i + vec2<i32>(0, 1));
321
- let v11 = demSample(i + vec2<i32>(1, 1));
322
- if (v00 > -1000.0 && v10 > -1000.0 && v01 > -1000.0 && v11 > -1000.0) {
323
- return mix(mix(v00, v10, f.x), mix(v01, v11, f.x), f.y);
324
- }
325
- if (v00 > -1000.0) { return v00; }
326
- if (v10 > -1000.0) { return v10; }
327
- if (v01 > -1000.0) { return v01; }
328
- if (v11 > -1000.0) { return v11; }
329
- return base;
330
- }
331
- `;