leaflet-city-mapper 0.0.0-stage → 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 (412) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +78 -2
  3. package/cucumber.mjs +9 -0
  4. package/dist/leaflet-city-mapper.js +2 -0
  5. package/dist/leaflet-city-mapper.js.map +7 -0
  6. package/dist/utils/CELL.js +2 -0
  7. package/dist/utils/CELL.js.map +7 -0
  8. package/dist/utils/addBridges.js +2 -0
  9. package/dist/utils/addBridges.js.map +7 -0
  10. package/dist/utils/addRasterTile.js +2 -0
  11. package/dist/utils/addRasterTile.js.map +7 -0
  12. package/dist/utils/along.js +2 -0
  13. package/dist/utils/along.js.map +7 -0
  14. package/dist/utils/atmosphere.js +2 -0
  15. package/dist/utils/atmosphere.js.map +7 -0
  16. package/dist/utils/attach.js +2 -0
  17. package/dist/utils/attach.js.map +7 -0
  18. package/dist/utils/bindSunlight.js +2 -0
  19. package/dist/utils/bindSunlight.js.map +7 -0
  20. package/dist/utils/box.js +2 -0
  21. package/dist/utils/box.js.map +7 -0
  22. package/dist/utils/bridgeElevation.js +2 -0
  23. package/dist/utils/bridgeElevation.js.map +7 -0
  24. package/dist/utils/build.js +2 -0
  25. package/dist/utils/build.js.map +7 -0
  26. package/dist/utils/cameraControls.js +2 -0
  27. package/dist/utils/cameraControls.js.map +7 -0
  28. package/dist/utils/channel.js +2 -0
  29. package/dist/utils/channel.js.map +7 -0
  30. package/dist/utils/collider.js +2 -0
  31. package/dist/utils/collider.js.map +7 -0
  32. package/dist/utils/colliders.js +2 -0
  33. package/dist/utils/colliders.js.map +7 -0
  34. package/dist/utils/computeBounds.js +2 -0
  35. package/dist/utils/computeBounds.js.map +7 -0
  36. package/dist/utils/conformModelToTerrain.js +2 -0
  37. package/dist/utils/conformModelToTerrain.js.map +7 -0
  38. package/dist/utils/createMesh.js +2 -0
  39. package/dist/utils/createMesh.js.map +7 -0
  40. package/dist/utils/createProgram.js +3 -0
  41. package/dist/utils/createProgram.js.map +7 -0
  42. package/dist/utils/decodeDirectory.js +2 -0
  43. package/dist/utils/decodeDirectory.js.map +7 -0
  44. package/dist/utils/decodeHeader.js +2 -0
  45. package/dist/utils/decodeHeader.js.map +7 -0
  46. package/dist/utils/decodeModel.js +2 -0
  47. package/dist/utils/decodeModel.js.map +7 -0
  48. package/dist/utils/decompress.js +2 -0
  49. package/dist/utils/decompress.js.map +7 -0
  50. package/dist/utils/destroyTexture.js +2 -0
  51. package/dist/utils/destroyTexture.js.map +7 -0
  52. package/dist/utils/disposeMesh.js +2 -0
  53. package/dist/utils/disposeMesh.js.map +7 -0
  54. package/dist/utils/drawGeometry.js +2 -0
  55. package/dist/utils/drawGeometry.js.map +7 -0
  56. package/dist/utils/elevationWGSL.js +24 -0
  57. package/dist/utils/elevationWGSL.js.map +7 -0
  58. package/dist/utils/emptyNode.js +2 -0
  59. package/dist/utils/emptyNode.js.map +7 -0
  60. package/dist/utils/endZoom.js +2 -0
  61. package/dist/utils/endZoom.js.map +7 -0
  62. package/dist/utils/findFeature.js +2 -0
  63. package/dist/utils/findFeature.js.map +7 -0
  64. package/dist/utils/geometry.js +1 -0
  65. package/dist/utils/geometry.js.map +7 -0
  66. package/dist/utils/getElevation.js +2 -0
  67. package/dist/utils/getElevation.js.map +7 -0
  68. package/dist/utils/getHeader.js +2 -0
  69. package/dist/utils/getHeader.js.map +7 -0
  70. package/dist/utils/getZxy.js +2 -0
  71. package/dist/utils/getZxy.js.map +7 -0
  72. package/dist/utils/glass.js +2 -0
  73. package/dist/utils/glass.js.map +7 -0
  74. package/dist/utils/headlight.js +2 -0
  75. package/dist/utils/headlight.js.map +7 -0
  76. package/dist/utils/hit.js +2 -0
  77. package/dist/utils/hit.js.map +7 -0
  78. package/dist/utils/horizontalPosition.js +2 -0
  79. package/dist/utils/horizontalPosition.js.map +7 -0
  80. package/dist/utils/horizontalRay.js +2 -0
  81. package/dist/utils/horizontalRay.js.map +7 -0
  82. package/dist/utils/hull.js +2 -0
  83. package/dist/utils/hull.js.map +7 -0
  84. package/dist/utils/initSunlight.js +2 -0
  85. package/dist/utils/initSunlight.js.map +7 -0
  86. package/dist/utils/initTerrain.js +2 -0
  87. package/dist/utils/initTerrain.js.map +7 -0
  88. package/dist/utils/initTraffic.js +40 -0
  89. package/dist/utils/initTraffic.js.map +7 -0
  90. package/dist/utils/initWalk.js +2 -0
  91. package/dist/utils/initWalk.js.map +7 -0
  92. package/dist/utils/intersectMeshes.js +2 -0
  93. package/dist/utils/intersectMeshes.js.map +7 -0
  94. package/dist/utils/isClockWise.js +2 -0
  95. package/dist/utils/isClockWise.js.map +7 -0
  96. package/dist/utils/lampPostGeometry.js +2 -0
  97. package/dist/utils/lampPostGeometry.js.map +7 -0
  98. package/dist/utils/lightGeometry.js +2 -0
  99. package/dist/utils/lightGeometry.js.map +7 -0
  100. package/dist/utils/lightGrid.js +2 -0
  101. package/dist/utils/lightGrid.js.map +7 -0
  102. package/dist/utils/limbs.js +2 -0
  103. package/dist/utils/limbs.js.map +7 -0
  104. package/dist/utils/loadModel.js +2 -0
  105. package/dist/utils/loadModel.js.map +7 -0
  106. package/dist/utils/loadSource.js +2 -0
  107. package/dist/utils/loadSource.js.map +7 -0
  108. package/dist/utils/loadTerrain.js +2 -0
  109. package/dist/utils/loadTerrain.js.map +7 -0
  110. package/dist/utils/mapCamera.js +2 -0
  111. package/dist/utils/mapCamera.js.map +7 -0
  112. package/dist/utils/materialShaders.js +211 -0
  113. package/dist/utils/materialShaders.js.map +7 -0
  114. package/dist/utils/mirror.js +2 -0
  115. package/dist/utils/mirror.js.map +7 -0
  116. package/dist/utils/moonPosition.js +2 -0
  117. package/dist/utils/moonPosition.js.map +7 -0
  118. package/dist/utils/moves.js +2 -0
  119. package/dist/utils/moves.js.map +7 -0
  120. package/dist/utils/nativeEvents.js +2 -0
  121. package/dist/utils/nativeEvents.js.map +7 -0
  122. package/dist/utils/nativeGeometry.js +2 -0
  123. package/dist/utils/nativeGeometry.js.map +7 -0
  124. package/dist/utils/nativeLayer.js +2 -0
  125. package/dist/utils/nativeLayer.js.map +7 -0
  126. package/dist/utils/nodeMatrix.js +2 -0
  127. package/dist/utils/nodeMatrix.js.map +7 -0
  128. package/dist/utils/onAdd3DLayer.js +2 -0
  129. package/dist/utils/onAdd3DLayer.js.map +7 -0
  130. package/dist/utils/onAddSun.js +2 -0
  131. package/dist/utils/onAddSun.js.map +7 -0
  132. package/dist/utils/onClick.js +2 -0
  133. package/dist/utils/onClick.js.map +7 -0
  134. package/dist/utils/onMapChange.js +2 -0
  135. package/dist/utils/onMapChange.js.map +7 -0
  136. package/dist/utils/onPMTileAdd.js +2 -0
  137. package/dist/utils/onPMTileAdd.js.map +7 -0
  138. package/dist/utils/onPMTileRemove.js +2 -0
  139. package/dist/utils/onPMTileRemove.js.map +7 -0
  140. package/dist/utils/onPointerLeave.js +2 -0
  141. package/dist/utils/onPointerLeave.js.map +7 -0
  142. package/dist/utils/onPointerMove.js +2 -0
  143. package/dist/utils/onPointerMove.js.map +7 -0
  144. package/dist/utils/onRemove3DLayer.js +2 -0
  145. package/dist/utils/onRemove3DLayer.js.map +7 -0
  146. package/dist/utils/onRemoveSun.js +2 -0
  147. package/dist/utils/onRemoveSun.js.map +7 -0
  148. package/dist/utils/onTerrainAdd.js +2 -0
  149. package/dist/utils/onTerrainAdd.js.map +7 -0
  150. package/dist/utils/onTerrainChange.js +2 -0
  151. package/dist/utils/onTerrainChange.js.map +7 -0
  152. package/dist/utils/onTerrainRemove.js +2 -0
  153. package/dist/utils/onTerrainRemove.js.map +7 -0
  154. package/dist/utils/onZoomAnim.js +2 -0
  155. package/dist/utils/onZoomAnim.js.map +7 -0
  156. package/dist/utils/paints.js +2 -0
  157. package/dist/utils/paints.js.map +7 -0
  158. package/dist/utils/parseColor.js +2 -0
  159. package/dist/utils/parseColor.js.map +7 -0
  160. package/dist/utils/parts.js +2 -0
  161. package/dist/utils/parts.js.map +7 -0
  162. package/dist/utils/projectCelestialBody.js +2 -0
  163. package/dist/utils/projectCelestialBody.js.map +7 -0
  164. package/dist/utils/pump.js +2 -0
  165. package/dist/utils/pump.js.map +7 -0
  166. package/dist/utils/rasterTiles.js +2 -0
  167. package/dist/utils/rasterTiles.js.map +7 -0
  168. package/dist/utils/raycast.js +2 -0
  169. package/dist/utils/raycast.js.map +7 -0
  170. package/dist/utils/read.js +2 -0
  171. package/dist/utils/read.js.map +7 -0
  172. package/dist/utils/readAccessor.js +2 -0
  173. package/dist/utils/readAccessor.js.map +7 -0
  174. package/dist/utils/releaseArea.js +2 -0
  175. package/dist/utils/releaseArea.js.map +7 -0
  176. package/dist/utils/removeRasterTile.js +2 -0
  177. package/dist/utils/removeRasterTile.js.map +7 -0
  178. package/dist/utils/render.js +15 -0
  179. package/dist/utils/render.js.map +7 -0
  180. package/dist/utils/renderSunlight.js +13 -0
  181. package/dist/utils/renderSunlight.js.map +7 -0
  182. package/dist/utils/renderers.js +2 -0
  183. package/dist/utils/renderers.js.map +7 -0
  184. package/dist/utils/resizeSunlight.js +2 -0
  185. package/dist/utils/resizeSunlight.js.map +7 -0
  186. package/dist/utils/roofCoverage.js +2 -0
  187. package/dist/utils/roofCoverage.js.map +7 -0
  188. package/dist/utils/routeGeometry.js +2 -0
  189. package/dist/utils/routeGeometry.js.map +7 -0
  190. package/dist/utils/scheduledTrips.js +2 -0
  191. package/dist/utils/scheduledTrips.js.map +7 -0
  192. package/dist/utils/setGeoJSONData.js +2 -0
  193. package/dist/utils/setGeoJSONData.js.map +7 -0
  194. package/dist/utils/setHighlight.js +2 -0
  195. package/dist/utils/setHighlight.js.map +7 -0
  196. package/dist/utils/setPMTileOpacity.js +2 -0
  197. package/dist/utils/setPMTileOpacity.js.map +7 -0
  198. package/dist/utils/setPMTileZIndex.js +2 -0
  199. package/dist/utils/setPMTileZIndex.js.map +7 -0
  200. package/dist/utils/setParent.js +2 -0
  201. package/dist/utils/setParent.js.map +7 -0
  202. package/dist/utils/setTerrainHeight.js +2 -0
  203. package/dist/utils/setTerrainHeight.js.map +7 -0
  204. package/dist/utils/setVertexColor.js +2 -0
  205. package/dist/utils/setVertexColor.js.map +7 -0
  206. package/dist/utils/showFeature.js +2 -0
  207. package/dist/utils/showFeature.js.map +7 -0
  208. package/dist/utils/sizes.js +2 -0
  209. package/dist/utils/sizes.js.map +7 -0
  210. package/dist/utils/skin.js +2 -0
  211. package/dist/utils/skin.js.map +7 -0
  212. package/dist/utils/solarPosition.js +2 -0
  213. package/dist/utils/solarPosition.js.map +7 -0
  214. package/dist/utils/sortMeshes.js +2 -0
  215. package/dist/utils/sortMeshes.js.map +7 -0
  216. package/dist/utils/speed.js +2 -0
  217. package/dist/utils/speed.js.map +7 -0
  218. package/dist/utils/startZoom.js +2 -0
  219. package/dist/utils/startZoom.js.map +7 -0
  220. package/dist/utils/taillight.js +2 -0
  221. package/dist/utils/taillight.js.map +7 -0
  222. package/dist/utils/terrainAtlas.js +2 -0
  223. package/dist/utils/terrainAtlas.js.map +7 -0
  224. package/dist/utils/terrainElevation.js +2 -0
  225. package/dist/utils/terrainElevation.js.map +7 -0
  226. package/dist/utils/terrainGrid.js +2 -0
  227. package/dist/utils/terrainGrid.js.map +7 -0
  228. package/dist/utils/textureSampler.js +2 -0
  229. package/dist/utils/textureSampler.js.map +7 -0
  230. package/dist/utils/tileId.js +2 -0
  231. package/dist/utils/tileId.js.map +7 -0
  232. package/dist/utils/toLanes.js +2 -0
  233. package/dist/utils/toLanes.js.map +7 -0
  234. package/dist/utils/toSRGB.js +2 -0
  235. package/dist/utils/toSRGB.js.map +7 -0
  236. package/dist/utils/tooltip.js +3 -0
  237. package/dist/utils/tooltip.js.map +7 -0
  238. package/dist/utils/traffic.js +2 -0
  239. package/dist/utils/traffic.js.map +7 -0
  240. package/dist/utils/traverse.js +2 -0
  241. package/dist/utils/traverse.js.map +7 -0
  242. package/dist/utils/treeGeometry.js +2 -0
  243. package/dist/utils/treeGeometry.js.map +7 -0
  244. package/dist/utils/triangulate.js +2 -0
  245. package/dist/utils/triangulate.js.map +7 -0
  246. package/dist/utils/tripsAt.js +2 -0
  247. package/dist/utils/tripsAt.js.map +7 -0
  248. package/dist/utils/types.js +2 -0
  249. package/dist/utils/types.js.map +7 -0
  250. package/dist/utils/underEntry.js +2 -0
  251. package/dist/utils/underEntry.js.map +7 -0
  252. package/dist/utils/update.js +2 -0
  253. package/dist/utils/update.js.map +7 -0
  254. package/dist/utils/updateArea.js +2 -0
  255. package/dist/utils/updateArea.js.map +7 -0
  256. package/dist/utils/updateCamera.js +2 -0
  257. package/dist/utils/updateCamera.js.map +7 -0
  258. package/dist/utils/updatePointLights.js +2 -0
  259. package/dist/utils/updatePointLights.js.map +7 -0
  260. package/dist/utils/updateWorldMatrix.js +2 -0
  261. package/dist/utils/updateWorldMatrix.js.map +7 -0
  262. package/dist/utils/vehicleOffsets.js +2 -0
  263. package/dist/utils/vehicleOffsets.js.map +7 -0
  264. package/dist/utils/vehicles.js +2 -0
  265. package/dist/utils/vehicles.js.map +7 -0
  266. package/dist/utils/vertexNormals.js +2 -0
  267. package/dist/utils/vertexNormals.js.map +7 -0
  268. package/dist/utils/walk.js +2 -0
  269. package/dist/utils/walk.js.map +7 -0
  270. package/dist/utils/white.js +2 -0
  271. package/dist/utils/white.js.map +7 -0
  272. package/dist/utils/worldLights.js +2 -0
  273. package/dist/utils/worldLights.js.map +7 -0
  274. package/dist/utils/wrap.js +2 -0
  275. package/dist/utils/wrap.js.map +7 -0
  276. package/package.json +43 -4
  277. package/src/index.js +397 -0
  278. package/src/utils/CELL.js +4 -0
  279. package/src/utils/addBridges.js +66 -0
  280. package/src/utils/addRasterTile.js +112 -0
  281. package/src/utils/along.js +9 -0
  282. package/src/utils/atmosphere.js +20 -0
  283. package/src/utils/attach.js +255 -0
  284. package/src/utils/bindSunlight.js +12 -0
  285. package/src/utils/box.js +1 -0
  286. package/src/utils/bridgeElevation.js +18 -0
  287. package/src/utils/build.js +20 -0
  288. package/src/utils/cameraControls.js +287 -0
  289. package/src/utils/channel.js +4 -0
  290. package/src/utils/collider.js +62 -0
  291. package/src/utils/colliders.js +2 -0
  292. package/src/utils/computeBounds.js +17 -0
  293. package/src/utils/conformModelToTerrain.js +69 -0
  294. package/src/utils/createMesh.js +31 -0
  295. package/src/utils/createProgram.js +92 -0
  296. package/src/utils/decodeDirectory.js +40 -0
  297. package/src/utils/decodeHeader.js +15 -0
  298. package/src/utils/decodeModel.js +43 -0
  299. package/src/utils/decompress.js +5 -0
  300. package/src/utils/destroyTexture.js +7 -0
  301. package/src/utils/disposeMesh.js +13 -0
  302. package/src/utils/drawGeometry.js +122 -0
  303. package/src/utils/elevationWGSL.js +27 -0
  304. package/src/utils/emptyNode.js +9 -0
  305. package/src/utils/endZoom.js +15 -0
  306. package/src/utils/findFeature.js +49 -0
  307. package/src/utils/geometry.js +2 -0
  308. package/src/utils/getElevation.js +10 -0
  309. package/src/utils/getHeader.js +9 -0
  310. package/src/utils/getZxy.js +76 -0
  311. package/src/utils/glass.js +1 -0
  312. package/src/utils/headlight.js +1 -0
  313. package/src/utils/hit.js +41 -0
  314. package/src/utils/horizontalPosition.js +16 -0
  315. package/src/utils/horizontalRay.js +12 -0
  316. package/src/utils/hull.js +1 -0
  317. package/src/utils/initSunlight.js +9 -0
  318. package/src/utils/initTerrain.js +19 -0
  319. package/src/utils/initTraffic.js +93 -0
  320. package/src/utils/initWalk.js +72 -0
  321. package/src/utils/intersectMeshes.js +121 -0
  322. package/src/utils/isClockWise.js +12 -0
  323. package/src/utils/lampPostGeometry.js +26 -0
  324. package/src/utils/lightGeometry.js +22 -0
  325. package/src/utils/lightGrid.js +50 -0
  326. package/src/utils/limbs.js +9 -0
  327. package/src/utils/loadModel.js +217 -0
  328. package/src/utils/loadSource.js +17 -0
  329. package/src/utils/loadTerrain.js +65 -0
  330. package/src/utils/mapCamera.js +432 -0
  331. package/src/utils/materialShaders.js +243 -0
  332. package/src/utils/mirror.js +6 -0
  333. package/src/utils/moonPosition.js +17 -0
  334. package/src/utils/moves.js +11 -0
  335. package/src/utils/nativeEvents.js +77 -0
  336. package/src/utils/nativeGeometry.js +131 -0
  337. package/src/utils/nativeLayer.js +317 -0
  338. package/src/utils/nodeMatrix.js +22 -0
  339. package/src/utils/onAdd3DLayer.js +31 -0
  340. package/src/utils/onAddSun.js +147 -0
  341. package/src/utils/onClick.js +13 -0
  342. package/src/utils/onMapChange.js +16 -0
  343. package/src/utils/onPMTileAdd.js +15 -0
  344. package/src/utils/onPMTileRemove.js +8 -0
  345. package/src/utils/onPointerLeave.js +11 -0
  346. package/src/utils/onPointerMove.js +15 -0
  347. package/src/utils/onRemove3DLayer.js +78 -0
  348. package/src/utils/onRemoveSun.js +3 -0
  349. package/src/utils/onTerrainAdd.js +18 -0
  350. package/src/utils/onTerrainChange.js +13 -0
  351. package/src/utils/onTerrainRemove.js +40 -0
  352. package/src/utils/onZoomAnim.js +14 -0
  353. package/src/utils/paints.js +10 -0
  354. package/src/utils/parseColor.js +42 -0
  355. package/src/utils/parts.js +16 -0
  356. package/src/utils/projectCelestialBody.js +13 -0
  357. package/src/utils/pump.js +226 -0
  358. package/src/utils/rasterTiles.js +285 -0
  359. package/src/utils/raycast.js +60 -0
  360. package/src/utils/read.js +29 -0
  361. package/src/utils/readAccessor.js +68 -0
  362. package/src/utils/releaseArea.js +34 -0
  363. package/src/utils/removeRasterTile.js +13 -0
  364. package/src/utils/render.js +406 -0
  365. package/src/utils/renderSunlight.js +170 -0
  366. package/src/utils/renderers.js +2 -0
  367. package/src/utils/resizeSunlight.js +15 -0
  368. package/src/utils/roofCoverage.js +47 -0
  369. package/src/utils/routeGeometry.js +22 -0
  370. package/src/utils/scheduledTrips.js +29 -0
  371. package/src/utils/setGeoJSONData.js +11 -0
  372. package/src/utils/setHighlight.js +13 -0
  373. package/src/utils/setPMTileOpacity.js +7 -0
  374. package/src/utils/setPMTileZIndex.js +7 -0
  375. package/src/utils/setParent.js +7 -0
  376. package/src/utils/setTerrainHeight.js +10 -0
  377. package/src/utils/setVertexColor.js +14 -0
  378. package/src/utils/showFeature.js +27 -0
  379. package/src/utils/sizes.js +1 -0
  380. package/src/utils/skin.js +2 -0
  381. package/src/utils/solarPosition.js +17 -0
  382. package/src/utils/sortMeshes.js +12 -0
  383. package/src/utils/speed.js +3 -0
  384. package/src/utils/startZoom.js +5 -0
  385. package/src/utils/taillight.js +1 -0
  386. package/src/utils/terrainAtlas.js +21 -0
  387. package/src/utils/terrainElevation.js +20 -0
  388. package/src/utils/terrainGrid.js +23 -0
  389. package/src/utils/textureSampler.js +10 -0
  390. package/src/utils/tileId.js +18 -0
  391. package/src/utils/toLanes.js +7 -0
  392. package/src/utils/toSRGB.js +1 -0
  393. package/src/utils/tooltip.js +6 -0
  394. package/src/utils/traffic.js +315 -0
  395. package/src/utils/traverse.js +6 -0
  396. package/src/utils/treeGeometry.js +45 -0
  397. package/src/utils/triangulate.js +100 -0
  398. package/src/utils/tripsAt.js +16 -0
  399. package/src/utils/types.js +8 -0
  400. package/src/utils/underEntry.js +17 -0
  401. package/src/utils/update.js +18 -0
  402. package/src/utils/updateArea.js +40 -0
  403. package/src/utils/updateCamera.js +32 -0
  404. package/src/utils/updatePointLights.js +38 -0
  405. package/src/utils/updateWorldMatrix.js +47 -0
  406. package/src/utils/vehicleOffsets.js +8 -0
  407. package/src/utils/vehicles.js +65 -0
  408. package/src/utils/vertexNormals.js +30 -0
  409. package/src/utils/walk.js +187 -0
  410. package/src/utils/white.js +1 -0
  411. package/src/utils/worldLights.js +25 -0
  412. package/src/utils/wrap.js +1 -0
@@ -0,0 +1,17 @@
1
+ /** Cache local AABB and center for ray picking and transparent mesh sorting. */
2
+
3
+ export function computeBounds(geometry) {
4
+ const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity], data = geometry.attributes.position.data;
5
+ for (let i = 0; i < data.length; i++) {
6
+ min[i % 3] = Math.min(min[i % 3], data[i]);
7
+ max[i % 3] = Math.max(max[i % 3], data[i]);
8
+ }
9
+ const center = min.map((v, i) => (v + max[i]) / 2);
10
+ let radius = 0;
11
+ for (let i = 0; i < data.length; i += 3) {
12
+ radius = Math.max(radius, Math.hypot(
13
+ data[i] - center[0], data[i + 1] - center[1], data[i + 2] - center[2]
14
+ ));
15
+ }
16
+ geometry.bounds = { min, max, center, radius };
17
+ }
@@ -0,0 +1,69 @@
1
+ import { computeBounds } from './computeBounds.js';
2
+ import { getElevation } from './getElevation.js';
3
+ import { update } from './update.js';
4
+ import { updateWorldMatrix } from './updateWorldMatrix.js';
5
+ import { vertexNormals } from './vertexNormals.js';
6
+
7
+ const HEIGHT = 8;
8
+
9
+ export function conformModelToTerrain(layer, terrain) {
10
+ if (!layer.model) return;
11
+ const meshes = [];
12
+ const visit = node => {
13
+ if (node.geometry?.attributes.position) meshes.push(node);
14
+ for (const child of node.children) visit(child);
15
+ };
16
+ visit(layer.model);
17
+ if (!terrain?._terrainReady || !layer.options.terrainConform) {
18
+ for (const mesh of meshes) {
19
+ const positions = mesh.geometry._terrainBasePositions;
20
+ if (!positions) continue;
21
+ const geometry = mesh.geometry, position = geometry.attributes.position;
22
+ position.data.set(positions);
23
+ mesh.device.queue.writeBuffer(position.buffer, 0, positions);
24
+ const normals = geometry._terrainBaseNormals;
25
+ if (normals) {
26
+ geometry.attributes.normal.data.set(normals);
27
+ mesh.device.queue.writeBuffer(geometry.attributes.normal.buffer, 0, normals);
28
+ }
29
+ computeBounds(geometry);
30
+ }
31
+ return;
32
+ }
33
+
34
+ updateWorldMatrix(layer.root);
35
+ const map = layer._map, crs = map.options.crs;
36
+ const origin = crs.project(layer._shared._sceneOrigin);
37
+ const metres = Math.cos(layer._shared._sceneOrigin.lat * Math.PI / 180);
38
+ const pixelScale = crs.scale(terrain._terrainZoom);
39
+
40
+ for (const mesh of meshes) {
41
+ const geometry = mesh.geometry, attribute = geometry.attributes.position;
42
+ geometry._terrainBasePositions ||= attribute.data.slice();
43
+ const normal = geometry.attributes.normal;
44
+ geometry._terrainBaseNormals ||= normal.data.slice();
45
+ attribute.data.set(geometry._terrainBasePositions);
46
+ const world = mesh.worldMatrix, inverse = new DOMMatrix(world).inverse().toFloat64Array();
47
+ for (let i = 0; i < attribute.data.length; i += 3) {
48
+ const x = attribute.data[i], y = attribute.data[i + 1], z = attribute.data[i + 2];
49
+ const worldY = world[1] * x + world[5] * y + world[9] * z + world[13];
50
+ const weight = Math.max(0, Math.min(1, 1 - (worldY - layer.root.position[1]) / HEIGHT));
51
+ if (!weight) continue;
52
+ const worldX = world[0] * x + world[4] * y + world[8] * z + world[12];
53
+ const worldZ = world[2] * x + world[6] * y + world[10] * z + world[14];
54
+ const point = crs.transformation.transform(new L.Point(
55
+ origin.x + worldX / metres, origin.y - worldZ / metres), pixelScale);
56
+ const elevation = getElevation(terrain, point);
57
+ if (!Number.isFinite(elevation)) continue;
58
+ const offset = (elevation - worldY) * weight;
59
+ attribute.data[i] += inverse[4] * offset;
60
+ attribute.data[i + 1] += inverse[5] * offset;
61
+ attribute.data[i + 2] += inverse[6] * offset;
62
+ }
63
+ mesh.device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
64
+ normal.data.set(vertexNormals(attribute.data, geometry.attributes.index?.data));
65
+ mesh.device.queue.writeBuffer(normal.buffer, 0, normal.data);
66
+ computeBounds(geometry);
67
+ }
68
+ update(layer);
69
+ }
@@ -0,0 +1,31 @@
1
+ import { emptyNode } from './emptyNode.js';
2
+ import { createProgram } from './createProgram.js';
3
+ import { setParent } from './setParent.js';
4
+ import { update } from './update.js';
5
+
6
+ /**
7
+ * Add a non-indexed, vertex-coloured mesh from flat vec3 arrays `{ position, normal, color }` in layer-local metres.
8
+ * `usage` adds GPUBufferUsage flags to the vertex buffers (e.g. STORAGE for compute passes).
9
+ * A supplied `program` shares compiled shaders and pipelines across compatible meshes.
10
+ */
11
+
12
+ export function createMesh(backend, data, material = {}, usage = 0, program) {
13
+ const { device } = backend.renderer, attributes = {};
14
+ for (const [name, values] of Object.entries(data)) {
15
+ const array = new Float32Array(values);
16
+ const size = name === 'uv' ? 2 : 3;
17
+ const buffer = device.createBuffer({ size: Math.max(4, array.byteLength), usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | usage });
18
+ device.queue.writeBuffer(buffer, 0, array);
19
+ attributes[name] = { size, data: array, count: array.length / size, buffer };
20
+ }
21
+ const mesh = {
22
+ ...emptyNode(),
23
+ device,
24
+ geometry: { device, attributes, drawRange: { start: 0, count: attributes.position.count } },
25
+ program: program || createProgram(backend, { vertexColors: true, doubleSided: true, ...material }),
26
+ id: L.Layer._nextId++, renderOrder: 0, extras: {},
27
+ };
28
+ setParent(mesh, backend.root);
29
+ update(backend);
30
+ return mesh;
31
+ }
@@ -0,0 +1,92 @@
1
+ import { materialShaders } from './materialShaders.js';
2
+ import { elevationWGSL } from './elevationWGSL.js';
3
+
4
+
5
+ export function createProgram(backend, material = {}) {
6
+ const shaders = materialShaders(
7
+ material,
8
+ !!backend.options.nightSparkle,
9
+ material.terrain ? elevationWGSL : ''
10
+ );
11
+ const vertex = backend.renderer.device.createShaderModule({ code: shaders.vertex });
12
+ const fragment = backend.renderer.device.createShaderModule({ code: shaders.fragment });
13
+ Promise.all([
14
+ vertex.getCompilationInfo(),
15
+ fragment.getCompilationInfo()
16
+ ]).then(infos => {
17
+ const errors = infos.flatMap(info => info.messages).filter(message => message.type === 'error');
18
+ if (errors.length) {
19
+ backend.fire('error', {
20
+ error: new Error(`Unable to compile Layer3D WGSL: ${errors.map(error => error.message).join('\n')}`),
21
+ });
22
+ }
23
+ }).catch(error => backend.fire('error', { error }));
24
+ const vertexBuffers = [
25
+ { arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }] },
26
+ { arrayStride: 12, attributes: [{ shaderLocation: 1, offset: 0, format: 'float32x3' }] },
27
+ material.vertexColors ? { arrayStride: 12, attributes: [{ shaderLocation: 2, offset: 0, format: 'float32x3' }] } : null,
28
+ shaders.textured ? { arrayStride: 8, attributes: [{ shaderLocation: 3, offset: 0, format: 'float32x2' }] } : null,
29
+ ];
30
+ const bindGroupEntries = [{
31
+ binding: 0,
32
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
33
+ buffer: { type: 'uniform', hasDynamicOffset: true },
34
+ }, {
35
+ binding: 1,
36
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
37
+ buffer: { type: 'uniform' },
38
+ }];
39
+ if (shaders.hasTerrain) {
40
+ bindGroupEntries.push({
41
+ binding: 2,
42
+ visibility: GPUShaderStage.VERTEX,
43
+ texture: { sampleType: 'unfilterable-float', viewDimension: '2d' },
44
+ });
45
+ }
46
+ for (const texture of shaders.bindings) {
47
+ bindGroupEntries.push({
48
+ binding: texture.texture,
49
+ visibility: GPUShaderStage.FRAGMENT,
50
+ texture: { sampleType: 'float', viewDimension: '2d' },
51
+ });
52
+ bindGroupEntries.push({
53
+ binding: texture.sampler,
54
+ visibility: GPUShaderStage.FRAGMENT,
55
+ sampler: { type: 'filtering' },
56
+ });
57
+ }
58
+ const bindGroupLayout = backend.renderer.device.createBindGroupLayout({ entries: bindGroupEntries });
59
+ const pipelineLayout = backend.renderer.device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout, backend.renderer.sunlight.layout] });
60
+ return {
61
+ device: backend.renderer.device,
62
+ vertex,
63
+ fragment,
64
+ bindings: shaders.bindings,
65
+ vertexBuffers,
66
+ bindGroupLayout,
67
+ pipelineLayout,
68
+ pipelineCache: new Map(),
69
+ cullMode: material.doubleSided ? 'none' : 'back',
70
+ transparent: material.alphaMode === 'BLEND',
71
+ depthWrite: material.depthWrite ?? material.alphaMode !== 'BLEND',
72
+ depthTest: material.depthTest !== false,
73
+ terrain: material.terrain,
74
+ nightLight: Boolean(material.nightLight),
75
+ nightSparkle: !!backend.options.nightSparkle,
76
+ uniforms: {
77
+ baseColor: { value: material.color || [1, 1, 1] },
78
+ metallic: { value: material.metallic ?? 0 },
79
+ roughness: { value: material.roughness ?? 0.85 },
80
+ opacity: { value: material.opacity ?? 1 },
81
+ alphaCutoff: { value: material.alphaCutoff ?? 0.5 },
82
+ occlusionStrength: { value: material.occlusionStrength ?? 1 },
83
+ emissive: { value: material.emissive || [0, 0, 0] },
84
+ ...(material.baseTexture ? { baseTexture: { value: material.baseTexture } } : {}),
85
+ ...(material.metalTexture ? { metalTexture: { value: material.metalTexture } } : {}),
86
+ ...(material.emissiveTexture ? { emissiveTexture: { value: material.emissiveTexture } } : {}),
87
+ ...(material.occlusionTexture ? { occlusionTexture: { value: material.occlusionTexture } } : {}),
88
+ ...(material.roofTexture ? { roofTexture: { value: null } } : {}),
89
+ },
90
+ _layerMaterial: material,
91
+ };
92
+ }
@@ -0,0 +1,40 @@
1
+ /** Decode delta/varint directory columns, rejecting malformed entries. */
2
+
3
+ export function decodeDirectory(data) {
4
+ const bytes = new Uint8Array(data);
5
+ let cursor = 0;
6
+ const varint = () => {
7
+ let value = 0;
8
+ for (let factor = 1; factor <= 2 ** 49; factor *= 128) {
9
+ if (cursor >= bytes.length) throw new Error('Truncated PMTiles directory');
10
+ const byte = bytes[cursor++];
11
+ value += (byte & 127) * factor;
12
+ if (!Number.isSafeInteger(value)) throw new Error('Invalid PMTiles directory integer');
13
+ if (byte < 128) return value;
14
+ }
15
+ throw new Error('Invalid PMTiles directory integer');
16
+ };
17
+ const count = varint();
18
+ if (count > (bytes.length - cursor) / 4) throw new Error('Invalid PMTiles directory count');
19
+ const entries = [];
20
+ let tileId = 0;
21
+ for (let i = 0; i < count; i++) {
22
+ tileId += varint();
23
+ if (!Number.isSafeInteger(tileId) || (i && tileId <= entries[i - 1].tileId)) {
24
+ throw new Error('Invalid PMTiles directory tile IDs');
25
+ }
26
+ entries.push({ tileId });
27
+ }
28
+ for (const entry of entries) entry.runLength = varint();
29
+ for (const entry of entries) {
30
+ entry.length = varint();
31
+ if (!entry.length) throw new Error('Invalid PMTiles directory length');
32
+ }
33
+ entries.forEach((entry, i) => {
34
+ const value = varint();
35
+ if (!value && !i) throw new Error('Invalid PMTiles directory offset');
36
+ entry.offset = value ? value - 1 : entries[i - 1].offset + entries[i - 1].length;
37
+ });
38
+ if (cursor !== bytes.length) throw new Error('Trailing PMTiles directory data');
39
+ return entries;
40
+ }
@@ -0,0 +1,15 @@
1
+ /** Decode the PMTiles v3 header. */
2
+
3
+ export function decodeHeader(data) {
4
+ if (data.byteLength < 127 || new TextDecoder().decode(new Uint8Array(data, 0, 7)) !== 'PMTiles' ||
5
+ new Uint8Array(data)[7] !== 3) throw new Error('Expected a PMTiles v3 archive');
6
+ const view = new DataView(data);
7
+ const header = {};
8
+ ['rootDirectoryOffset', 'rootDirectoryLength', 'jsonMetadataOffset', 'jsonMetadataLength', 'leafDirectoryOffset', 'leafDirectoryLength', 'tileDataOffset', 'tileDataLength', 'numAddressedTiles', 'numTileEntries', 'numTileContents'].forEach((name, i) => { header[name] = Number(view.getBigUint64(8 + i * 8, true)); });
9
+ ['clustered', 'internalCompression', 'tileCompression', 'tileType', 'minZoom', 'maxZoom'].forEach((name, i) => { header[name] = view.getUint8(96 + i); });
10
+ ['minLon', 'minLat', 'maxLon', 'maxLat'].forEach((name, i) => { header[name] = view.getInt32(102 + i * 4, true) / 1e7; });
11
+ header.centerZoom = view.getUint8(118);
12
+ header.centerLon = view.getInt32(119, true) / 1e7;
13
+ header.centerLat = view.getInt32(123, true) / 1e7;
14
+ return header;
15
+ }
@@ -0,0 +1,43 @@
1
+ /** Decode a static glTF JSON document or GLB v2 container. */
2
+
3
+ export function decodeModel(data) {
4
+ const view = new DataView(data), decoder = new TextDecoder();
5
+ let description;
6
+ if (view.getUint32(0, true) === 0x46546c67) {
7
+ // Decode GLB v2 chunks; unknown types are skipped.
8
+ if (view.getUint32(4, true) !== 2 || view.getUint32(8, true) !== data.byteLength) {
9
+ throw new Error('Invalid GLB header');
10
+ }
11
+ let binary;
12
+ for (let offset = 12; offset < data.byteLength;) {
13
+ if (offset + 8 > data.byteLength) {
14
+ throw new Error('Truncated GLB chunk');
15
+ }
16
+ const length = view.getUint32(offset, true), type = view.getUint32(offset + 4, true);
17
+ offset += 8;
18
+ if (offset + length > data.byteLength) {
19
+ throw new Error('Truncated GLB data');
20
+ }
21
+ const chunk = data.slice(offset, offset + length);
22
+ if (type === 0x4e4f534a) {
23
+ description = JSON.parse(decoder.decode(chunk));
24
+ }
25
+ if (type === 0x004e4942) {
26
+ binary = chunk;
27
+ }
28
+ offset += length;
29
+ }
30
+ if (!description) {
31
+ throw new Error('Missing GLB JSON');
32
+ }
33
+ if (binary) {
34
+ description.buffers[0].binary = binary;
35
+ }
36
+ } else {
37
+ description = JSON.parse(decoder.decode(data));
38
+ }
39
+ if (description.skins?.length || description.animations?.length || description.extensionsRequired?.length || description.meshes?.some(mesh => mesh.primitives.some(primitive => primitive.targets || (primitive.mode !== undefined && primitive.mode !== 4)))) {
40
+ throw new Error('Layer3D supports static triangle glTF models without required extensions');
41
+ }
42
+ return description;
43
+ }
@@ -0,0 +1,5 @@
1
+ export async function decompress(data, compression) {
2
+ if (compression === 1) return data;
3
+ if (compression !== 2) throw new Error(`Unsupported PMTiles compression: ${compression}`);
4
+ return new Response(new Blob([data]).stream().pipeThrough(new DecompressionStream('gzip'))).arrayBuffer();
5
+ }
@@ -0,0 +1,7 @@
1
+
2
+ export function destroyTexture(layer, texture) {
3
+ layer.renderer.device.queue.onSubmittedWorkDone().then(() => texture.destroy(), error => {
4
+ layer.fire('error', { error });
5
+ texture.destroy();
6
+ });
7
+ }
@@ -0,0 +1,13 @@
1
+ import { setParent } from './setParent.js';
2
+ import { update } from './update.js';
3
+
4
+ export function disposeMesh(backend, mesh) {
5
+ if (!mesh) {
6
+ return;
7
+ }
8
+ setParent(mesh, null);
9
+ update(backend);
10
+ for (const attribute of Object.values(mesh.geometry.attributes)) {
11
+ attribute.buffer.destroy();
12
+ }
13
+ }
@@ -0,0 +1,122 @@
1
+ /** Upload retained CPU data and draw one mesh in the active WebGPU render pass. */
2
+
3
+ export function drawGeometry(backend, mesh, pass, cullMode, frontFace) {
4
+ const { geometry, program } = mesh;
5
+ const device = backend.renderer.device;
6
+ const pipelineKey = `${cullMode}:${frontFace}`;
7
+ let pipeline = program.pipelineCache.get(pipelineKey);
8
+ if (!pipeline) {
9
+ pipeline = device.createRenderPipeline({
10
+ layout: program.pipelineLayout,
11
+ vertex: {
12
+ module: program.vertex,
13
+ entryPoint: 'vertexMain',
14
+ buffers: program.vertexBuffers,
15
+ },
16
+ fragment: {
17
+ module: program.fragment,
18
+ entryPoint: 'fragmentMain',
19
+ targets: [{
20
+ format: backend.renderer.format,
21
+ blend: program.transparent ? {
22
+ color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
23
+ alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
24
+ } : undefined,
25
+ writeMask: GPUColorWrite.ALL,
26
+ }],
27
+ },
28
+ primitive: { topology: 'triangle-list', cullMode, frontFace },
29
+ depthStencil: {
30
+ format: 'depth24plus',
31
+ depthWriteEnabled: program.depthWrite,
32
+ depthCompare: program.depthTest === false ? 'always' : 'less-equal',
33
+ },
34
+ });
35
+ program.pipelineCache.set(pipelineKey, pipeline);
36
+ }
37
+
38
+ const uniforms = program.uniforms;
39
+ const renderer = backend.renderer;
40
+ const offset = renderer.uniformSlot++ * 256;
41
+ const data = renderer.uniformData, base = offset / 4;
42
+ data.set(mesh.worldMatrix, base);
43
+ data.set(uniforms.baseColor.value, base + 16);
44
+ data[base + 19] = 1;
45
+ data[base + 20] = uniforms.metallic.value;
46
+ data[base + 21] = uniforms.roughness.value;
47
+ data[base + 22] = uniforms.opacity.value * (mesh.ground ? mesh._appearance ?? 1 : 1);
48
+ data[base + 23] = uniforms.alphaCutoff.value;
49
+ data.set(uniforms.emissive.value, base + 24);
50
+ data[base + 27] = uniforms.occlusionStrength.value;
51
+ data[base + 28] = mesh.terrain?.[0] ?? 0;
52
+ data[base + 29] = mesh.terrain?.[1] ?? 0;
53
+ data[base + 30] = mesh.terrain?.[2] ?? 0;
54
+ data[base + 31] = mesh.terrain?.[3] ?? 0;
55
+ data[base + 32] = mesh.highlight?.[0] ?? 0;
56
+ data[base + 33] = mesh.highlight?.[1] ?? 0;
57
+ data[base + 34] = program.nightSparkle ? data[55] : 0;
58
+ data[base + 35] = mesh.ground ? 1 : mesh._appearance ?? 1;
59
+
60
+ const textures = mesh._textures ||= [];
61
+ textures.length = 0;
62
+ for (const binding of program.bindings) {
63
+ const texture = uniforms[binding.name]?.value;
64
+ if (!texture) throw new Error(`Missing Layer3D texture: ${binding.name}`);
65
+ if (texture.uploaded !== texture.image) {
66
+ device.queue.copyExternalImageToTexture(
67
+ { source: texture.image, flipY: Boolean(texture.flipY) },
68
+ { texture: texture.texture },
69
+ [texture.image.width, texture.image.height]
70
+ );
71
+ texture.uploaded = texture.image;
72
+ }
73
+ textures.push(texture);
74
+ }
75
+ let bindingsChanged = !mesh.bindGroup || mesh.boundBuffer !== renderer.uniformBuffer ||
76
+ textures.length !== mesh.boundTextures.length;
77
+ for (let i = 0; !bindingsChanged && i < textures.length; i++) {
78
+ if (textures[i].texture !== mesh.boundTextures[i][0] ||
79
+ textures[i].sampler !== mesh.boundTextures[i][1]) bindingsChanged = true;
80
+ }
81
+ if (bindingsChanged) {
82
+ const entries = [
83
+ { binding: 0, resource: { buffer: renderer.uniformBuffer, size: 144 } },
84
+ { binding: 1, resource: { buffer: renderer.uniformBuffer, size: 240 } },
85
+ ];
86
+ if (program.terrain) entries.push({ binding: 2, resource: program.terrain.texture.createView() });
87
+ mesh.boundBuffer = renderer.uniformBuffer;
88
+ const boundTextures = mesh.boundTextures ||= [];
89
+ boundTextures.length = textures.length;
90
+ for (let i = 0; i < textures.length; i++) {
91
+ const binding = program.bindings[i], texture = textures[i];
92
+ entries.push({ binding: binding.texture, resource: texture.texture.createView() });
93
+ entries.push({ binding: binding.sampler, resource: texture.sampler });
94
+ boundTextures[i] ||= [];
95
+ boundTextures[i][0] = texture.texture;
96
+ boundTextures[i][1] = texture.sampler;
97
+ }
98
+ mesh.bindGroup = device.createBindGroup({
99
+ layout: program.bindGroupLayout,
100
+ entries,
101
+ });
102
+ }
103
+ pass.setPipeline(pipeline);
104
+ pass.setBindGroup(0, mesh.bindGroup, [offset]);
105
+ pass.setVertexBuffer(0, geometry.attributes.position.buffer);
106
+ pass.setVertexBuffer(1, geometry.attributes.normal.buffer);
107
+ if (geometry.attributes.color) pass.setVertexBuffer(2, geometry.attributes.color.buffer);
108
+ if (geometry.attributes.uv) pass.setVertexBuffer(3, geometry.attributes.uv.buffer);
109
+ for (const attribute of Object.values(geometry.attributes)) {
110
+ if (!attribute.needsUpdate) continue;
111
+ device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
112
+ attribute.needsUpdate = false;
113
+ geometry.bounds = null;
114
+ }
115
+ const index = geometry.attributes.index;
116
+ if (index) {
117
+ pass.setIndexBuffer(index.buffer, index.indexFormat);
118
+ pass.drawIndexed(geometry.drawRange.count, 1, geometry.drawRange.start, 0, 0);
119
+ } else {
120
+ pass.draw(geometry.drawRange.count, 1, geometry.drawRange.start, 0);
121
+ }
122
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * WGSL twin of getElevation for the vertex shader: bilinear DEM pixels, or the first valid
3
+ * neighbour near no-data (stored as -1e9), else `base`. Expects `dem: texture_2d<f32>`.
4
+ */
5
+ export const elevationWGSL = `
6
+ fn demSample(pixel: vec2<i32>) -> f32 {
7
+ if (any(pixel < vec2<i32>(0)) || any(pixel >= vec2<i32>(textureDimensions(dem)))) { return -1e9; }
8
+ return textureLoad(dem, pixel, 0).r;
9
+ }
10
+ fn elevation(pixel: vec2<f32>, base: f32) -> f32 {
11
+ let p = pixel - vec2<f32>(0.5);
12
+ let f = fract(p);
13
+ let i = vec2<i32>(floor(p));
14
+ let v00 = demSample(i);
15
+ let v10 = demSample(i + vec2<i32>(1, 0));
16
+ let v01 = demSample(i + vec2<i32>(0, 1));
17
+ let v11 = demSample(i + vec2<i32>(1, 1));
18
+ if (v00 > -1000.0 && v10 > -1000.0 && v01 > -1000.0 && v11 > -1000.0) {
19
+ return mix(mix(v00, v10, f.x), mix(v01, v11, f.x), f.y);
20
+ }
21
+ if (v00 > -1000.0) { return v00; }
22
+ if (v10 > -1000.0) { return v10; }
23
+ if (v01 > -1000.0) { return v01; }
24
+ if (v11 > -1000.0) { return v11; }
25
+ return base;
26
+ }
27
+ `;
@@ -0,0 +1,9 @@
1
+ /** A fresh, empty scene-graph node. */
2
+ export const emptyNode = () => ({
3
+ position: [0, 0, 0],
4
+ rotation: [0, 0, 0],
5
+ scale: [1, 1, 1],
6
+ worldMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
7
+ children: [],
8
+ visible: true,
9
+ });
@@ -0,0 +1,15 @@
1
+ import { update } from "./update.js";
2
+
3
+ /** Stop using the outgoing level after zoomend; the next redraw uses current tiles. */
4
+
5
+ export function endZoom() {
6
+ const backend = this;
7
+ for (const animation of backend._zoomTransitions?.keys() || []) animation.finish();
8
+ backend._zoomTransitions = null;
9
+ backend._zoomView = null;
10
+ delete backend._map._cameraView;
11
+ backend._map.getContainer().classList.remove('leaflet-camera-zoom');
12
+ backend._map._updateCameraOverlays();
13
+ backend._zoomLevel = null;
14
+ update(backend);
15
+ }
@@ -0,0 +1,49 @@
1
+ import { raycast } from './raycast.js';
2
+
3
+ /**
4
+ * Translate a geometry hit into a configured model or batched source feature.
5
+ * Sorted half-open face ranges permit binary search without a feature per triangle.
6
+ * @returns {PickedFeature|null}
7
+ */
8
+
9
+ export function findFeature(backend, event) {
10
+ if (!backend.root || !backend.camera) {
11
+ return null;
12
+ }
13
+ for (const hit of raycast(backend, event, backend.root.children, Boolean(backend.model))) {
14
+ if (backend.model) {
15
+ let object = hit.object;
16
+ while (object && object !== backend.model) {
17
+ object = object.parent;
18
+ }
19
+ if (object === backend.model) {
20
+ return {
21
+ id: backend.model.id, properties: backend.model.extras,
22
+ model: backend.model, mesh: hit.object, point: hit.point
23
+ };
24
+ }
25
+ }
26
+ const ranges = hit.object.extras?.featureFaces;
27
+ if (!ranges) {
28
+ continue;
29
+ }
30
+ let low = 0,
31
+ high = ranges.length - 1;
32
+ while (low <= high) {
33
+ const middle = (low + high) >> 1;
34
+ const range = ranges[middle];
35
+ if (hit.faceIndex < range.faceStart) {
36
+ high = middle - 1;
37
+ } else if (hit.faceIndex >= range.faceEnd) {
38
+ low = middle + 1;
39
+ } else {
40
+ return {
41
+ ...range,
42
+ mesh: hit.object,
43
+ point: hit.point
44
+ };
45
+ }
46
+ }
47
+ }
48
+ return null;
49
+ }
@@ -0,0 +1,2 @@
1
+
2
+
@@ -0,0 +1,10 @@
1
+ import { bridgeElevation } from './bridgeElevation.js';
2
+ import { terrainElevation } from './terrainElevation.js';
3
+
4
+ /** @param {L.LatLng|L.Point} location LatLng, or a pixel point at the terrain zoom. */
5
+
6
+ export function getElevation(backend, location) {
7
+ if (!backend._map || !backend._terrainReady) return null;
8
+ const point = location instanceof L.Point ? location : backend._map.project(location, backend._terrainZoom);
9
+ return bridgeElevation(point, backend._bridges) ?? terrainElevation(point, backend._terrainTiles);
10
+ }
@@ -0,0 +1,9 @@
1
+ import { decodeHeader } from './decodeHeader.js';
2
+ import { read } from './read.js';
3
+
4
+ /** Cache header initialization; failures remain visible to all callers. */
5
+
6
+ export function getHeader(backend) {
7
+ if (backend.options.archive && backend.options.archive !== backend) return backend.options.archive.getHeader();
8
+ return backend._header ||= read(backend, 0, 127).then(decodeHeader);
9
+ }
@@ -0,0 +1,76 @@
1
+ import { decodeDirectory } from './decodeDirectory.js';
2
+ import { decompress } from './decompress.js';
3
+ import { tileId } from './tileId.js';
4
+ import { read } from './read.js';
5
+ import { getHeader } from './getHeader.js';
6
+
7
+ /** Nearest directory entry at/before the Hilbert ID, then follow leaf pointers. */
8
+
9
+ export async function getZxy(backend, z, x, y, signal) {
10
+ if (backend.options.archive && backend.options.archive !== backend && backend.options.archive.getZxy) {
11
+ return backend.options.archive.getZxy(z, x, y, signal);
12
+ }
13
+ const id = tileId(z, x, y);
14
+ signal?.throwIfAborted();
15
+ const header = await getHeader(backend);
16
+ signal?.throwIfAborted();
17
+ if (z < header.minZoom || z > header.maxZoom) {
18
+ return;
19
+ }
20
+ let offset = header.rootDirectoryOffset, length = header.rootDirectoryLength;
21
+ const visited = new Set();
22
+ for (let depth = 0; depth < 4; depth++) {
23
+ if (visited.has(offset)) {
24
+ throw new Error('Cyclic PMTiles directory');
25
+ }
26
+ visited.add(offset);
27
+ const key = `${offset}:${length}`;
28
+ if (!backend._directories.has(key)) {
29
+ if (backend._directories.size >= 32) {
30
+ backend._directories.delete(backend._directories.keys().next().value);
31
+ }
32
+ const pending = read(backend, offset, length)
33
+ .then(data => decompress(data, header.internalCompression))
34
+ .then(decodeDirectory)
35
+ .catch(error => {
36
+ if (backend._directories.get(key) === pending) {
37
+ backend._directories.delete(key);
38
+ }
39
+ throw error;
40
+ });
41
+ backend._directories.set(key, pending);
42
+ }
43
+ const entries = await backend._directories.get(key);
44
+ signal?.throwIfAborted();
45
+ let low = 0, high = entries.length - 1;
46
+ while (low <= high) {
47
+ const mid = (low + high) >> 1;
48
+ if (entries[mid].tileId <= id) {
49
+ low = mid + 1;
50
+ } else {
51
+ high = mid - 1;
52
+ }
53
+ }
54
+ const entry = entries[high];
55
+ if (!entry) {
56
+ return;
57
+ }
58
+ if (entry.runLength) {
59
+ if (id - entry.tileId >= entry.runLength) {
60
+ return;
61
+ }
62
+ if (entry.offset + entry.length > header.tileDataLength) {
63
+ throw new Error('PMTiles tile outside data section');
64
+ }
65
+ const data = await decompress(await read(backend, header.tileDataOffset + entry.offset, entry.length, signal), header.tileCompression);
66
+ signal?.throwIfAborted();
67
+ return { data };
68
+ }
69
+ if (entry.offset + entry.length > header.leafDirectoryLength) {
70
+ throw new Error('PMTiles directory outside leaf section');
71
+ }
72
+ offset = header.leafDirectoryOffset + entry.offset;
73
+ length = entry.length;
74
+ }
75
+ throw new Error('PMTiles directory depth exceeds four levels');
76
+ }