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,90 +1,315 @@
1
- // Pure helpers of the 'traffic' type: lane interpolation and vehicle scheduling.
2
-
3
- /** Default urban speed (m/s) used to turn a lane's hourly `flow` into vehicles on the road. */
4
- export const speed = 8;
5
-
6
- /** Evenly spaced starting offsets (metres) for `flow` vehicles/h moving at `velocity` m/s on a `length` metres lane. */
7
- export function vehicleOffsets(length, flow, velocity = speed) {
8
- const count = Math.round(length * flow / 3600 / velocity);
9
- return Array.from({ length: count }, (_, i) => (i + 0.5) * length / count);
10
- }
11
-
12
- /** Point and unit direction at distance `s` along `points` ([x, z, y?]) with cumulative `lengths`. */
13
- export function along(points, lengths, s) {
14
- let i = 1;
15
- while (i < lengths.length - 1 && lengths[i] < s) i++;
16
- const a = points[i - 1], b = points[i], d = lengths[i] - lengths[i - 1] || 1;
17
- const t = (s - lengths[i - 1]) / d;
18
- return { x: a[0] + (b[0] - a[0]) * t, y: (a[2] ?? 0) + ((b[2] ?? 0) - (a[2] ?? 0)) * t, z: a[1] + (b[1] - a[1]) * t, dx: (b[0] - a[0]) / d, dz: (b[1] - a[1]) / d };
19
- }
20
-
21
- /**
22
- * Trips of a frequency-based timetable (like GTFS frequencies.txt) underway at `date`, in the timetable's local time.
23
- * @param {{timeZone: string, duration: number, services: Array<{from: string, to: string, every?: number, months?: number[], weekdays?: number[]}>}} timetable
24
- * `duration` and `every` are minutes; `from`/`to` are 'HH:MM' first/last departures; months are 1-12, weekdays 0 (Sunday)-6.
25
- * @returns {Array<{id: string, departure: string, progress: number}>} `progress` is 0-1 along the lane.
26
- */
27
- export function scheduledTrips(date, { timeZone, duration, services }) {
28
- const time = new Date(date);
29
- if (!Number.isFinite(time.getTime())) throw new Error('Invalid date');
30
- const clock = new Intl.DateTimeFormat('en-GB', {
31
- timeZone, year: 'numeric', month: '2-digit', day: '2-digit',
32
- hour: '2-digit', minute: '2-digit', second: '2-digit', hourCycle: 'h23',
1
+ import * as createMeshApi from './createMesh.js';
2
+ import * as disposeMesh from './disposeMesh.js';
3
+ import * as setHighlight from './setHighlight.js';
4
+ import * as showFeature from './showFeature.js';
5
+ import { update as updateScene } from './update.js';
6
+ import { along } from './along.js';
7
+ import { build } from './build.js';
8
+ import { computeBounds } from './computeBounds.js';
9
+ import { routeGeometry } from './routeGeometry.js';
10
+ import { toLanes } from './toLanes.js';
11
+ import { tripsAt } from './tripsAt.js';
12
+ import { underEntry } from './underEntry.js';
13
+ import { getElevation } from './getElevation.js';
14
+
15
+ export function trafficNow(state) {
16
+ let control = { live: true };
17
+ state.layer._map?.eachLayer(other => { if (other.control?.time) control = other.control; });
18
+ return { live: control.live, time: control.live ? new Date() : control.time };
19
+ }
20
+
21
+ export function createTrafficMesh(state, data, featureFaces, material, usage = 0) {
22
+ const result = createMeshApi.createMesh(state.layer, data, material, usage);
23
+ result.extras.featureFaces = featureFaces;
24
+ return result;
25
+ }
26
+
27
+ export function disposeTrafficObject(state, object) {
28
+ if (!object) return;
29
+ if (state.layer.highlightedFeature?.mesh === object) {
30
+ setHighlight.setHighlight(state.layer, null);
31
+ state.layer.hoveredFeature = null;
32
+ showFeature.showFeature(state.layer, null);
33
+ };
34
+ disposeMesh.disposeMesh(state.layer, object);
35
+ }
36
+
37
+ export function failTraffic(state, error) {
38
+ state.status.textContent = `Error: ${error.message}`;
39
+ state.status.setAttribute('role', 'alert');
40
+ console.error('Traffic layer', error);
41
+ }
42
+
43
+ export function groundTraffic(state) {
44
+ const { layer, lanes } = state;
45
+ const terrain = layer._map._terrain3D?._terrainReady && layer._map._terrain3D, base = layer.root.position[1];
46
+ for (const lane of lanes) lane.points.forEach((point, i) => {
47
+ const elevation = terrain && (lane.elevation ?? getElevation(terrain, lane.latlngs[i]));
48
+ point[2] = Number.isFinite(elevation) && Number.isFinite(base) ? elevation - base : 0;
33
49
  });
34
- const parts = Object.fromEntries(clock.formatToParts(time).filter(p => p.type !== 'literal').map(p => [p.type, Number(p.value)]));
35
- const minute = parts.hour * 60 + parts.minute + (parts.second + time.getUTCMilliseconds() / 1000) / 60;
36
- const weekday = new Date(Date.UTC(parts.year, parts.month - 1, parts.day)).getUTCDay();
37
- const minutes = clockTime => clockTime.split(':').reduce((hours, value) => hours * 60 + Number(value));
38
- const departures = [];
39
- for (const { from, to, every = Infinity, months, weekdays } of services) {
40
- if (months?.includes(parts.month) === false || weekdays?.includes(weekday) === false) continue;
41
- for (let departure = minutes(from); departure <= minutes(to); departure += every) departures.push(departure);
50
+ state.lanesDirty = true;
51
+ state.nextCheck = -Infinity;
52
+ }
53
+
54
+ export function prepareTraffic(state) {
55
+ const { layer, lanes } = state;
56
+ const crs = layer._map.options.crs, origin = crs.project(layer.location);
57
+ const metres = Math.cos(layer.location.lat * Math.PI / 180);
58
+ for (const lane of lanes) {
59
+ lane.points = lane.latlngs.map(([lat, lng]) => {
60
+ const point = crs.project(new L.LatLng(lat, lng));
61
+ return [(point.x - origin.x) * metres, -(point.y - origin.y) * metres, 0];
62
+ });
63
+ lane.lengths = [0];
64
+ for (let i = 1; i < lane.points.length; i++) {
65
+ lane.lengths.push(lane.lengths[i - 1] + Math.hypot(lane.points[i][0] - lane.points[i - 1][0], lane.points[i][1] - lane.points[i - 1][1]));
66
+ }
67
+ lane.length = lane.lengths.at(-1);
42
68
  }
43
- return departures.sort((a, b) => a - b).filter(departure => minute >= departure && minute < departure + duration).map(departure => ({
44
- id: `${parts.year}-${parts.month}-${parts.day}-${departure}`,
45
- departure: `${String(Math.floor(departure / 60)).padStart(2, '0')}:${String(departure % 60).padStart(2, '0')}`,
46
- progress: (minute - departure) / duration,
47
- }));
48
- }
49
-
50
- // GeoJSON (Multi)LineStrings become lanes ({latlngs, properties, elevation?}); prepare() adds `points` ([x, z, ground]),
51
- // `lengths` and `length` in layer-local metres.
52
- export const toLanes = ({ features = [] }) => features.flatMap(({ geometry, properties }) => {
53
- const lines = geometry?.type === 'LineString' ? [geometry.coordinates] : geometry?.type === 'MultiLineString' ? geometry.coordinates : [];
54
- return lines.map(line => ({ latlngs: line.map(([lng, lat]) => [lat, lng]), properties: properties ?? {}, elevation: properties?.elevation }));
55
- });
56
-
57
- // A lane with a `timetable` runs scheduled trips end to end; one with a `flow` (vehicles/h) loops evenly spaced vehicles.
58
- export const tripsAt = (time, lanes, velocity) => lanes.flatMap((lane, l) => {
59
- const { timetable, flow = 0 } = lane.properties;
60
- if (!lane.length) return [];
61
- if (timetable) return scheduledTrips(time, timetable).map(trip => ({
62
- id: `${l}-${trip.id}`, lane, distance: trip.progress * lane.length, speed: lane.length / (timetable.duration * 60),
63
- properties: { ...lane.properties, departure: trip.departure },
64
- }));
65
- const travelled = time / 1000 * velocity;
66
- return (lane.offsets ||= vehicleOffsets(lane.length, flow, velocity))
67
- .map((offset, k) => ({ id: `${l}-${k}`, lane, distance: (offset + travelled) % lane.length, speed: velocity, properties: lane.properties }));
68
- });
69
-
70
- /** Dashed lane outline, in layer-local metres. */
71
- export function routeGeometry(lanes) {
72
- const position = [], normal = [], color = [];
73
- for (const { points, lengths } of lanes) for (let i = 1; i < points.length; i++) {
74
- const a = points[i - 1], b = points[i];
75
- const dx = b[0] - a[0], dz = b[1] - a[1], length = lengths[i] - lengths[i - 1];
76
- if (!length) continue;
77
- const x = -dz / length * 2.5, z = dx / length * 2.5;
78
- for (let distance = Math.floor(lengths[i - 1] / 30) * 30; distance < lengths[i]; distance += 30) {
79
- const start = Math.max(0, (distance - lengths[i - 1]) / length);
80
- const end = Math.min(1, (distance + 18 - lengths[i - 1]) / length);
81
- if (end <= start) continue;
82
- const p = [a[0] + dx * start, a[1] + dz * start], q = [a[0] + dx * end, a[1] + dz * end], y = a[2] + 0.4;
83
- for (const point of [[p[0] - x, p[1] - z], [p[0] + x, p[1] + z], [q[0] + x, q[1] + z],
84
- [p[0] - x, p[1] - z], [q[0] + x, q[1] + z], [q[0] - x, q[1] - z]]) {
85
- position.push(point[0], y, point[1]); normal.push(0, 1, 0); color.push(0.08, 0.7, 0.85);
86
- }
69
+ groundTraffic(state);
70
+ disposeTrafficObject(state, state.route);
71
+ state.route = null;
72
+ state.tripsKey = null;
73
+ }
74
+
75
+ export function drawTrafficRoute(state) {
76
+ state.route = createTrafficMesh(state, routeGeometry(state.lanes), [], { emissive: [0.03, 0.25, 0.3] });
77
+ }
78
+
79
+ export function rebuildTrafficMesh(state) {
80
+ const { trips, model, vertices } = state;
81
+ disposeTrafficObject(state, state.mesh);
82
+ state.mesh = null;
83
+ if (!trips.length) return;
84
+ const color = trips.flatMap((trip, i) => build(model(i)).color), count = color.length / 3;
85
+ state.mesh = createTrafficMesh(state, { position: color.map(() => 0), normal: color.map(() => 0), color },
86
+ trips.map((trip, i) => ({
87
+ id: trip.id, properties: trip.properties, faceStart: i * vertices / 3, faceEnd: (i + 1) * vertices / 3,
88
+ vertexStart: i * vertices, vertexEnd: (i + 1) * vertices
89
+ })), {}, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC);
90
+ state.mesh.geometry.drawRange.count = count;
91
+ trafficBounds(state);
92
+ }
93
+
94
+ export function trafficBounds(state) {
95
+ const extent = { attributes: { position: { data: state.lanes.flatMap(lane => lane.points.flatMap(([x, z, y]) => [x - 20, y, z - 20, x + 20, y + 5, z + 20])) } } };
96
+ computeBounds(extent);
97
+ state.mesh.geometry.bounds = extent.bounds;
98
+ }
99
+
100
+ export function destroyTrafficGpu(state) {
101
+ for (const buffer of [state.gpu?.params, state.gpu?.template, state.gpu?.points, state.gpu?.vehicles]) buffer?.destroy();
102
+ state.gpu = null;
103
+ }
104
+
105
+ export function trafficStorage(device, data) {
106
+ const buffer = device.createBuffer({ size: Math.max(16, data.byteLength), usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
107
+ device.queue.writeBuffer(buffer, 0, data);
108
+ return buffer;
109
+ }
110
+
111
+ export function rebaseTraffic(state) {
112
+ const { device } = state.layer.renderer;
113
+ if (state.gpu?.device !== device) {
114
+ destroyTrafficGpu(state);
115
+ state.gpu = {
116
+ device,
117
+ pipeline: device.createComputePipeline({ layout: 'auto', compute: { module: device.createShaderModule({ code: state.shader }), entryPoint: 'main' } }),
118
+ params: device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST }),
119
+ template: trafficStorage(device, new Float32Array([...state.template.position, ...state.template.normal])),
120
+ };
121
+ state.lanesDirty = true;
122
+ }
123
+ if (state.lanesDirty) {
124
+ const data = new Float32Array(state.lanes.reduce((count, lane) => count + lane.points.length, 0) * 4);
125
+ let offset = 0;
126
+ for (const lane of state.lanes) {
127
+ lane.start = offset / 4;
128
+ lane.points.forEach((point, i) => { data.set([point[0], point[1], point[2], lane.lengths[i]], offset); offset += 4; });
129
+ }
130
+ state.gpu.points?.destroy();
131
+ state.gpu.points = trafficStorage(device, data);
132
+ state.lanesDirty = false;
133
+ }
134
+ const data = new Float32Array(state.trips.length * 4), index = new Uint32Array(data.buffer);
135
+ state.trips.forEach((trip, i) => {
136
+ index[i * 4] = trip.lane.start;
137
+ index[i * 4 + 1] = trip.lane.points.length;
138
+ data[i * 4 + 2] = trip.distance;
139
+ data[i * 4 + 3] = trip.speed;
140
+ state.mesh.extras.featureFaces[i].properties = trip.properties;
141
+ });
142
+ if (state.gpu.vehicles?.size >= data.byteLength) device.queue.writeBuffer(state.gpu.vehicles, 0, data);
143
+ else {
144
+ state.gpu.vehicles?.destroy();
145
+ state.gpu.vehicles = trafficStorage(device, data);
146
+ }
147
+ const { position, normal } = state.mesh.geometry.attributes;
148
+ state.gpu.bindGroup = device.createBindGroup({
149
+ layout: state.gpu.pipeline.getBindGroupLayout(0),
150
+ entries: [state.gpu.params, state.gpu.template, state.gpu.points, state.gpu.vehicles, position.buffer, normal.buffer]
151
+ .map((buffer, binding) => ({ binding, resource: { buffer } })),
152
+ });
153
+ }
154
+
155
+ export function moveTraffic(state, seconds) {
156
+ const { device } = state.gpu;
157
+ state.paramFloats[0] = state.elapsed = seconds;
158
+ state.paramFloats[1] = state.side;
159
+ state.paramInts[2] = state.vertices;
160
+ state.paramInts[3] = state.trips.length * state.vertices;
161
+ device.queue.writeBuffer(state.gpu.params, 0, state.params);
162
+ const encoder = device.createCommandEncoder(), pass = encoder.beginComputePass();
163
+ pass.setPipeline(state.gpu.pipeline);
164
+ pass.setBindGroup(0, state.gpu.bindGroup);
165
+ pass.dispatchWorkgroups(Math.ceil(state.paramInts[3] / 64));
166
+ pass.end();
167
+ device.queue.submit([encoder.finish()]);
168
+ state.stale = true;
169
+ }
170
+
171
+ export function locateTraffic(state, trip) {
172
+ const { points, lengths, length } = trip.lane;
173
+ let distance = trip.distance + state.elapsed * trip.speed;
174
+ distance -= length * Math.floor(distance / length);
175
+ const { x, y, z, dx, dz } = along(points, lengths, distance);
176
+ return { x: x - dz * state.side, y, z: z + dx * state.side, dx, dz };
177
+ }
178
+
179
+ export function placeTraffic(state) {
180
+ if (!state.mesh || !state.stale) return;
181
+ state.stale = false;
182
+ const { position, normal } = state.mesh.geometry.attributes;
183
+ state.trips.forEach((trip, i) => {
184
+ const { x: cx, y, z: cz, dx, dz } = locateTraffic(state, trip);
185
+ for (let k = 0, o = i * state.stride; k < state.stride; k += 3, o += 3) {
186
+ const lx = state.template.position[k], lz = state.template.position[k + 2], nx = state.template.normal[k], nz = state.template.normal[k + 2];
187
+ position.data[o] = cx - lx * dz - lz * dx;
188
+ position.data[o + 1] = y + state.template.position[k + 1];
189
+ position.data[o + 2] = cz + lx * dx - lz * dz;
190
+ normal.data[o] = -nx * dz - nz * dx;
191
+ normal.data[o + 1] = state.template.normal[k + 1];
192
+ normal.data[o + 2] = nx * dx - nz * dz;
87
193
  }
194
+ });
195
+ }
196
+
197
+ export function tickTraffic(state) {
198
+ state.frame = undefined;
199
+ if (!state.ready || !state.layer._map) return;
200
+ if (!state.layer.renderer) { state.frame = requestAnimationFrame(state.tick); return; }
201
+ if (state.mesh && !(state.mesh.geometry.attributes.position.buffer.usage & GPUBufferUsage.STORAGE)) {
202
+ state.tripsKey = null;
203
+ state.nextCheck = -Infinity;
88
204
  }
89
- return { position, normal, color };
205
+ const { live, time } = trafficNow(state), ms = time?.getTime(), valid = Number.isFinite(ms);
206
+ let changed = false;
207
+ if (!live || !valid || !(ms >= state.rebasedAt && ms < state.nextCheck)) {
208
+ let text;
209
+ try {
210
+ state.trips = valid ? tripsAt(time, state.lanes, state.velocity) : [];
211
+ text = !valid ? 'Select a valid simulation date' : !state.loaded ? 'Loading…' :
212
+ `${state.trips.length} vehicle${state.trips.length === 1 ? '' : 's'}${state.loaded.note ? ` · ${state.loaded.note}` : ''}`;
213
+ } catch (error) { return failTraffic(state, error); }
214
+ state.rebasedAt = ms;
215
+ state.nextCheck = ms + 1000;
216
+ const key = state.trips.map(trip => trip.id).join();
217
+ changed = key !== state.tripsKey || (state.outline && !state.route && state.lanes.length);
218
+ if (state.outline && !state.route && state.lanes.length) drawTrafficRoute(state);
219
+ if (key !== state.tripsKey) { rebuildTrafficMesh(state); state.tripsKey = key; }
220
+ if (state.mesh) rebaseTraffic(state);
221
+ if (state.status.textContent !== text) state.status.textContent = text;
222
+ state.status.removeAttribute('role');
223
+ }
224
+ if (state.mesh) moveTraffic(state, (ms - state.rebasedAt) / 1000);
225
+ if (state.mesh && state.lights && (!live || !(performance.now() - state.litAt < 100))) {
226
+ state.litAt = performance.now();
227
+ state.mesh.extras.lights = state.trips.flatMap(trip => {
228
+ const { x, y, z, dx, dz } = locateTraffic(state, trip);
229
+ return state.lights.map(({ position: [lx, ly, lz], ...light }) => ({ ...light, position: [x - lx * dz - lz * dx, y + ly, z + lx * dx - lz * dz] }));
230
+ });
231
+ }
232
+ if (state.mesh || changed) updateScene(state.layer);
233
+ if (live && valid) state.frame = requestAnimationFrame(state.tick);
234
+ }
235
+
236
+ export async function fetchTrafficLanes(state, time, signal) {
237
+ const href = new URL(state.url, document.baseURI).href;
238
+ if (/\.m?js(?:[?#]|$)/i.test(state.url)) return (await import(href)).default(time, state.layer, signal);
239
+ if (!state.file) {
240
+ const response = await fetch(href, { signal });
241
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
242
+ state.file = await response.json();
243
+ }
244
+ return state.file;
245
+ }
246
+
247
+ export function loadedTrafficLanes(state, signal, data) {
248
+ if (signal.aborted || !state.layer._map || data === state.loaded) return;
249
+ state.loaded = data;
250
+ state.lanes = toLanes(data);
251
+ prepareTraffic(state);
252
+ if (!state.frame) state.tick();
253
+ }
254
+
255
+ export function failedTrafficLoad(state, error) {
256
+ if (error.name !== 'AbortError') failTraffic(state, error);
257
+ }
258
+
259
+ export function loadTraffic(state) {
260
+ const { time } = trafficNow(state);
261
+ if (!Number.isFinite(time?.getTime())) return;
262
+ state.request?.abort();
263
+ const { signal } = state.request = new AbortController();
264
+ fetchTrafficLanes(state, time, signal).then(
265
+ loadedTrafficLanes.bind(null, state, signal),
266
+ failedTrafficLoad.bind(null, state),
267
+ );
268
+ }
269
+
270
+ export function updateTraffic(state, event) {
271
+ if (event?.layer === state.layer) return;
272
+ cancelAnimationFrame(state.frame);
273
+ loadTraffic(state);
274
+ state.tick();
275
+ }
276
+
277
+ export function updateTrafficTerrain(state) {
278
+ if (!state.lanes.length) return;
279
+ groundTraffic(state);
280
+ disposeTrafficObject(state, state.route);
281
+ state.route = null;
282
+ if (state.mesh) trafficBounds(state);
283
+ if (!state.frame) state.tick();
284
+ }
285
+
286
+ export function startTraffic(state) {
287
+ state.layer._map.off('simulationtimechange layerremove', state.update).on('simulationtimechange layerremove', state.update);
288
+ state.layer._map.off('terrainchange', state.terrain).on('terrainchange', state.terrain);
289
+ underEntry(state.layer, state.status);
290
+ state.update();
291
+ }
292
+
293
+ export function readyTraffic(state) {
294
+ state.ready = true;
295
+ if (state.layer._map) startTraffic(state);
296
+ }
297
+
298
+ export function addTraffic(state) {
299
+ if (state.ready) startTraffic(state);
300
+ }
301
+
302
+ export function removeTraffic(state) {
303
+ state.request?.abort();
304
+ cancelAnimationFrame(state.frame);
305
+ state.frame = undefined;
306
+ state.layer._map.off('simulationtimechange layerremove', state.update).off('terrainchange', state.terrain);
307
+ disposeTrafficObject(state, state.mesh);
308
+ disposeTrafficObject(state, state.route);
309
+ state.mesh = state.route = null;
310
+ delete state.layer._beforeRaycast;
311
+ destroyTrafficGpu(state);
312
+ state.lanes = [];
313
+ state.trips = [];
314
+ state.tripsKey = state.loaded = null;
90
315
  }
@@ -0,0 +1,6 @@
1
+ /** Depth-first walk; a truthy callback result skips that node's descendants. */
2
+
3
+ export function traverse(node, callback) {
4
+ if (callback(node)) return;
5
+ for (const child of node.children) traverse(child, callback);
6
+ }
@@ -0,0 +1,45 @@
1
+ import { parseColor } from "./parseColor.js";
2
+
3
+ /** Low-poly tree, sharing the source block's buffers, picking and terrain offset. */
4
+
5
+ export function treeGeometry(point, style, addTriangle) {
6
+ const { top, bottom = 0, trunkRadius, crownRadius, crownBottom, crownShape = 'round' } = style;
7
+ if (![trunkRadius, crownRadius, crownBottom].every(Number.isFinite) ||
8
+ trunkRadius <= 0 || crownRadius < trunkRadius || crownBottom <= bottom || crownBottom >= top ||
9
+ !['round', 'cone'].includes(crownShape)) {
10
+ throw new Error('Invalid tree dimensions or crown shape');
11
+ }
12
+ const trunk = parseColor(style.trunkColor ?? 0x72513a);
13
+ const crown = parseColor(style.color ?? 0x4f823b);
14
+ const ring = radius => Array.from({ length: 8 }, (_, i) => ({
15
+ x: point.x + Math.cos(i * Math.PI / 4) * radius,
16
+ y: point.y + Math.sin(i * Math.PI / 4) * radius,
17
+ ground: point.ground,
18
+ }));
19
+ const surface = (lowRadius, low, highRadius, high, color) => {
20
+ const lower = ring(lowRadius), upper = ring(highRadius);
21
+ for (let i = 0; i < 8; i++) {
22
+ const next = (i + 1) % 8;
23
+ const angle = (i + 0.5) * Math.PI / 4;
24
+ const slope = (lowRadius - highRadius) / (high - low);
25
+ const length = Math.hypot(1, slope);
26
+ const nx = Math.cos(angle) / length, ny = slope / length, nz = -Math.sin(angle) / length;
27
+ if (lowRadius) addTriangle(lower[i], low, lower[next], low, upper[next], high, nx, ny, nz, color);
28
+ if (highRadius) addTriangle(lower[i], low, upper[next], high, upper[i], high, nx, ny, nz, color);
29
+ }
30
+ };
31
+ surface(trunkRadius, bottom, trunkRadius, crownBottom + (top - crownBottom) * 0.25, trunk);
32
+ if (crownShape === 'cone') {
33
+ const base = ring(crownRadius);
34
+ for (let i = 0; i < 8; i++) addTriangle(point, crownBottom, base[i], crownBottom,
35
+ base[(i + 1) % 8], crownBottom, 0, -1, 0, crown);
36
+ surface(crownRadius, crownBottom, 0, top, crown);
37
+ } else {
38
+ const profile = [[0, 0], [0.35, 0.8], [0.6, 1], [0.85, 0.7], [1, 0]];
39
+ for (let i = 1; i < profile.length; i++) {
40
+ const [low, lr] = profile[i - 1], [high, hr] = profile[i];
41
+ surface(lr * crownRadius, crownBottom + low * (top - crownBottom),
42
+ hr * crownRadius, crownBottom + high * (top - crownBottom), crown);
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,100 @@
1
+ import { isClockWise } from "./isClockWise.js";
2
+
3
+ /**
4
+ * Triangulates a polygon given as `{x, y}` points.
5
+ * Rings omit the repeated closing point; winding is normalized internally.
6
+ * Vertex indices remain relative to the original inputs after duplicate/collinear
7
+ * cleanup. Hole bridges duplicate endpoints, not source vertices.
8
+ * @param {Object[]} contour Outer boundary.
9
+ * @param {Object[][]} [holes] Interior boundaries.
10
+ *
11
+ * @returns {number[][]} Triangles as indices in `[...contour, ...holes.flat()]`.
12
+ */
13
+
14
+ export function triangulate(contour, holes = []) {
15
+ const points = [contour, ...holes].flat();
16
+ if (points.some(p => !Number.isFinite(p.x) || !Number.isFinite(p.y))) throw new Error('Invalid polygon coordinates');
17
+ // Translate near the origin to avoid cancellation with geographic coordinates.
18
+ const vertices = points.map((p, index) => ({ x: p.x - contour[0].x, y: p.y - contour[0].y, index }));
19
+ const cross = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
20
+ const equal = (a, b) => a.x === b.x && a.y === b.y;
21
+ // Remove zero-area corners before connecting holes; keep original vertex indices.
22
+ const clean = ring => {
23
+ let changed = true;
24
+ while (changed && ring.length > 3) {
25
+ changed = false;
26
+ for (let i = 0; i < ring.length; i++) {
27
+ const a = ring[(i + ring.length - 1) % ring.length], b = ring[i], c = ring[(i + 1) % ring.length];
28
+ if (equal(a, b) || Math.abs(cross(a, b, c)) < 1e-10) {
29
+ ring.splice(i, 1); changed = true; break;
30
+ }
31
+ }
32
+ }
33
+ if (ring.length < 3) throw new Error('Degenerate polygon ring');
34
+ return ring;
35
+ };
36
+ let offset = 0;
37
+ const rings = [contour, ...holes].map((path, index) => {
38
+ const ring = clean(vertices.slice(offset, offset += path.length));
39
+ if (isClockWise(ring) !== Boolean(index)) ring.reverse();
40
+ return ring;
41
+ });
42
+ const inside = (point, ring) => {
43
+ let result = false;
44
+ for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
45
+ const a = ring[i], b = ring[j];
46
+ if ((a.y > point.y) !== (b.y > point.y) &&
47
+ point.x < (b.x - a.x) * (point.y - a.y) / (b.y - a.y) + a.x) result = !result;
48
+ }
49
+ return result;
50
+ };
51
+ const intersects = (a, b, c, d) => {
52
+ if (equal(a, c) || equal(a, d) || equal(b, c) || equal(b, d)) return false;
53
+ const abC = cross(a, b, c), abD = cross(a, b, d), cdA = cross(c, d, a), cdB = cross(c, d, b);
54
+ const on = (p, q, r) => Math.min(p.x, q.x) <= r.x && r.x <= Math.max(p.x, q.x) &&
55
+ Math.min(p.y, q.y) <= r.y && r.y <= Math.max(p.y, q.y);
56
+ return abC * abD < 0 && cdA * cdB < 0 ||
57
+ abC === 0 && on(a, b, c) || abD === 0 && on(a, b, d) ||
58
+ cdA === 0 && on(c, d, a) || cdB === 0 && on(c, d, b);
59
+ };
60
+ let polygon = rings[0].slice();
61
+ // A bridge must stay inside the outer boundary, outside every hole, and cross no edge.
62
+ // ponytail: quadratic ear clipping for building footprints; use spatial indexing for large rings.
63
+ for (const hole of rings.slice(1).sort((a, b) => Math.min(...a.map(p => p.x)) - Math.min(...b.map(p => p.x)))) {
64
+ let bridge, distance = Infinity;
65
+ for (let h = 0; h < hole.length; h++) for (let p = 0; p < polygon.length; p++) {
66
+ const a = hole[h], b = polygon[p], d = (a.x - b.x) ** 2 + (a.y - b.y) ** 2;
67
+ if (d >= distance) continue;
68
+ const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
69
+ if (!inside(mid, rings[0]) || rings.slice(1).some(r => inside(mid, r))) continue;
70
+ if ([polygon, ...rings.slice(1)].some(r => r.some((c, i) => intersects(a, b, c, r[(i + 1) % r.length])))) continue;
71
+ bridge = [h, p]; distance = d;
72
+ }
73
+ if (!bridge) throw new Error('Unable to connect polygon hole');
74
+ const [h, p] = bridge;
75
+ polygon = [...polygon.slice(0, p + 1), ...hole.slice(h), ...hole.slice(0, h + 1),
76
+ polygon[p], ...polygon.slice(p + 1)];
77
+ }
78
+ // Clip a convex corner only when no other vertex is inside/on its triangle.
79
+ const result = [];
80
+ while (polygon.length > 3) {
81
+ let clipped = false;
82
+ for (let i = 0; i < polygon.length; i++) {
83
+ const a = polygon[(i + polygon.length - 1) % polygon.length], b = polygon[i], c = polygon[(i + 1) % polygon.length];
84
+ if (cross(a, b, c) <= 1e-10) continue;
85
+ if (polygon.some(p => !equal(p, a) && !equal(p, b) && !equal(p, c) &&
86
+ cross(a, b, p) >= 0 && cross(b, c, p) >= 0 && cross(c, a, p) >= 0)) continue;
87
+ result.push([a.index, b.index, c.index]); polygon.splice(i, 1); clipped = true; break;
88
+ }
89
+ if (!clipped) throw new Error('Unable to triangulate polygon: invalid or self-intersecting rings');
90
+ }
91
+ if (cross(...polygon) > 1e-10) result.push(polygon.map(p => p.index));
92
+ const area = ring => Math.abs(ring.reduce((sum, p, i) => {
93
+ const q = ring[(i + 1) % ring.length]; return sum + p.x * q.y - q.x * p.y;
94
+ }, 0)) / 2;
95
+ // Reject incomplete coverage instead of silently emitting a partial roof.
96
+ const expected = area(rings[0]) - rings.slice(1).reduce((sum, ring) => sum + area(ring), 0);
97
+ const actual = result.reduce((sum, triangle) => sum + cross(...triangle.map(i => vertices[i])) / 2, 0);
98
+ if (expected <= 0 || Math.abs(actual - expected) > Math.max(1e-7, expected * 1e-8)) throw new Error('Polygon triangulation area mismatch');
99
+ return result;
100
+ }
@@ -0,0 +1,16 @@
1
+ import { vehicleOffsets } from "./vehicleOffsets.js";
2
+ import { scheduledTrips } from "./scheduledTrips.js";
3
+
4
+ // A lane with a `timetable` runs scheduled trips end to end; one with a `flow` (vehicles/h) loops evenly spaced vehicles.
5
+
6
+ export const tripsAt = (time, lanes, velocity) => lanes.flatMap((lane, l) => {
7
+ const { timetable, flow = 0 } = lane.properties;
8
+ if (!lane.length) return [];
9
+ if (timetable) return scheduledTrips(time, timetable).map(trip => ({
10
+ id: `${l}-${trip.id}`, lane, distance: trip.progress * lane.length, speed: lane.length / (timetable.duration * 60),
11
+ properties: { ...lane.properties, departure: trip.departure },
12
+ }));
13
+ const travelled = time / 1000 * velocity;
14
+ return (lane.offsets ||= vehicleOffsets(lane.length, flow, velocity))
15
+ .map((offset, k) => ({ id: `${l}-${k}`, lane, distance: (offset + travelled) % lane.length, speed: velocity, properties: lane.properties }));
16
+ });
@@ -0,0 +1,8 @@
1
+ export const types = {
2
+ 5120: Int8Array,
3
+ 5121: Uint8Array,
4
+ 5122: Int16Array,
5
+ 5123: Uint16Array,
6
+ 5125: Uint32Array,
7
+ 5126: Float32Array,
8
+ };
@@ -5,8 +5,7 @@
5
5
  export function underEntry(layer, element) {
6
6
  const map = layer._map;
7
7
  const place = () => {
8
- const input = [...map.getContainer().querySelectorAll('.leaflet-control-layers-selector')]
9
- .find(input => input.layerId === globalThis.L.Util.stamp(layer));
8
+ const input = [...map.getContainer().querySelectorAll('.leaflet-control-layers-selector')].find(input => input.layerId === L.Util.stamp(layer));
10
9
  input?.closest('label').after(element);
11
10
  return Boolean(input);
12
11
  };
@@ -0,0 +1,18 @@
1
+ import { render } from "./render.js";
2
+
3
+ /** Scene graph, shared camera and frame rendering. */
4
+ /** Content changes: render once on the next animation frame. */
5
+
6
+ export function update(backend) {
7
+ const shared = backend._shared;
8
+ if (!shared) return backend;
9
+ if (shared !== backend) {
10
+ update(shared);
11
+ return backend;
12
+ }
13
+ backend._frame ||= requestAnimationFrame(() => {
14
+ backend._frame = null;
15
+ if (backend._shared === backend && backend.renderer) render(backend);
16
+ });
17
+ return backend;
18
+ }