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
@@ -0,0 +1,131 @@
1
+ import { triangulate } from './triangulate.js';
2
+
3
+ /** Leaflet paths become flat triangles; pixel-sized strokes are rebuilt on zoom. */
4
+ export function nativeGeometry(source, map, point) {
5
+ const fill = [], stroke = [], options = source.options;
6
+ const triangle = (target, a, b, c) => target.push(...point(a), ...point(b), ...point(c));
7
+ const disk = (center, radius, target, radiusY = radius) => {
8
+ if (!(radius > 0) || !(radiusY > 0)) return;
9
+ const count = Math.max(12, Math.min(128, Math.ceil(Math.PI * Math.sqrt(radius))));
10
+ for (let i = 0; i < count; i++) {
11
+ const at = index => new L.Point(center.x + radius * Math.cos(index * 2 * Math.PI / count),
12
+ center.y + radiusY * Math.sin(index * 2 * Math.PI / count));
13
+ triangle(target, center, at(i), at(i + 1));
14
+ }
15
+ };
16
+ const width = Number(options.weight) || 0;
17
+ const dash = (Array.isArray(options.dashArray) ? options.dashArray :
18
+ String(options.dashArray || '').trim().split(/[ ,]+/)).map(Number);
19
+ if (dash.some(value => !Number.isFinite(value) || value < 0)) throw new Error('Invalid Leaflet dashArray');
20
+ if (dash.every(value => value === 0)) dash.length = 0;
21
+ if (dash.length % 2) dash.push(...dash);
22
+ const line = (points, closed) => {
23
+ if (!options.stroke || width <= 0 || points.length < 2) return;
24
+ const radius = width / 2;
25
+ const segment = (a, b, startCap, endCap) => {
26
+ const length = a.distanceTo(b);
27
+ if (!length) return;
28
+ const direction = b.subtract(a).divideBy(length);
29
+ const normal = new L.Point(-direction.y * radius, direction.x * radius);
30
+ if (options.lineCap === 'square') {
31
+ if (startCap) a = a.subtract(direction.multiplyBy(radius));
32
+ if (endCap) b = b.add(direction.multiplyBy(radius));
33
+ }
34
+ triangle(stroke, a.add(normal), a.subtract(normal), b.add(normal));
35
+ triangle(stroke, b.add(normal), a.subtract(normal), b.subtract(normal));
36
+ if (options.lineCap === 'round') {
37
+ if (startCap) disk(a, radius, stroke);
38
+ if (endCap) disk(b, radius, stroke);
39
+ }
40
+ };
41
+ let distance = Number(options.dashOffset) || 0;
42
+ const period = dash.reduce((sum, value) => sum + value, 0);
43
+ for (let i = 0; i < points.length - (closed ? 0 : 1); i++) {
44
+ const a = points[i], b = points[(i + 1) % points.length], length = a.distanceTo(b);
45
+ if (!dash.length) {
46
+ segment(a, b, !closed && i === 0, !closed && i === points.length - 2);
47
+ if (closed || i > 0) {
48
+ if (options.lineJoin === 'round') disk(a, radius, stroke);
49
+ else {
50
+ const previous = a.subtract(points[(i + points.length - 1) % points.length]);
51
+ const previousLength = Math.hypot(previous.x, previous.y);
52
+ if (previousLength && length) {
53
+ const incoming = previous.divideBy(previousLength);
54
+ const outgoing = b.subtract(a).divideBy(length);
55
+ const side = incoming.x * outgoing.y - incoming.y * outgoing.x > 0 ? -1 : 1;
56
+ const n1 = new L.Point(-incoming.y * side, incoming.x * side);
57
+ const n2 = new L.Point(-outgoing.y * side, outgoing.x * side);
58
+ const from = a.add(n1.multiplyBy(radius)), to = a.add(n2.multiplyBy(radius));
59
+ const denominator = 1 + n1.x * n2.x + n1.y * n2.y;
60
+ const miter = denominator > 0 ? n1.add(n2).multiplyBy(radius / denominator) : null;
61
+ triangle(stroke, from, a, to);
62
+ if (options.lineJoin === 'miter' && miter && Math.hypot(miter.x, miter.y) <= radius * 4) {
63
+ triangle(stroke, from, a.add(miter), to);
64
+ }
65
+ }
66
+ }
67
+ }
68
+ } else {
69
+ let offset = 0;
70
+ while (offset < length) {
71
+ let phase = ((distance + offset) % period + period) % period, index = 0;
72
+ while (phase >= dash[index]) phase -= dash[index++];
73
+ const end = Math.min(length, offset + dash[index] - phase);
74
+ if (index % 2 === 0) {
75
+ const delta = b.subtract(a).divideBy(length);
76
+ segment(a.add(delta.multiplyBy(offset)), a.add(delta.multiplyBy(end)), true, true);
77
+ }
78
+ offset = end;
79
+ }
80
+ }
81
+ distance += length;
82
+ }
83
+ };
84
+ if (source instanceof L.CircleMarker) {
85
+ const center = map.project(source.getLatLng());
86
+ let radius = source.getRadius(), radiusY = radius;
87
+ if (source instanceof L.Circle) {
88
+ source._project();
89
+ const projected = source._point.add(map.getPixelOrigin());
90
+ center.x = projected.x;
91
+ center.y = projected.y;
92
+ radius = source._radius;
93
+ radiusY = source._radiusY || radius;
94
+ }
95
+ if (options.fill) disk(center, radius, fill, radiusY);
96
+ const count = Math.max(12, Math.min(128, Math.ceil(Math.PI * Math.sqrt(Math.max(radius, radiusY)))));
97
+ const at = (index, offset = 0) => {
98
+ const angle = index * Math.PI * 2 / count;
99
+ return new L.Point(center.x + Math.max(0, radius + offset) * Math.cos(angle),
100
+ center.y + Math.max(0, radiusY + offset) * Math.sin(angle));
101
+ };
102
+ if (dash.length) line(Array.from({ length: count }, (_, index) => at(index)), true);
103
+ else if (options.stroke && width > 0) {
104
+ for (let i = 0; i < count; i++) {
105
+ triangle(stroke, at(i, width / 2), at(i, -width / 2), at(i + 1, width / 2));
106
+ triangle(stroke, at(i + 1, width / 2), at(i, -width / 2), at(i + 1, -width / 2));
107
+ }
108
+ }
109
+ } else {
110
+ const closed = source instanceof L.Polygon;
111
+ const polygon = rings => {
112
+ const projected = rings.map(ring => ring.map(latlng => map.project(latlng)));
113
+ if (closed && options.fill && projected[0]?.length >= 3) {
114
+ const valid = projected.filter(ring => ring.length >= 3);
115
+ const vertices = valid.flat();
116
+ for (const indices of triangulate(valid[0], valid.slice(1))) {
117
+ triangle(fill, vertices[indices[0]], vertices[indices[1]], vertices[indices[2]]);
118
+ }
119
+ }
120
+ for (const ring of projected) line(ring, closed);
121
+ };
122
+ const visit = coordinates => {
123
+ if (!coordinates.length) return;
124
+ if (coordinates[0] instanceof L.LatLng) polygon([coordinates]);
125
+ else if (closed && coordinates[0][0] instanceof L.LatLng) polygon(coordinates);
126
+ else for (const child of coordinates) visit(child);
127
+ };
128
+ visit(source.getLatLngs());
129
+ }
130
+ return { fill, stroke };
131
+ }
@@ -0,0 +1,317 @@
1
+ import { createMesh } from './createMesh.js';
2
+ import { destroyTexture } from './destroyTexture.js';
3
+ import { disposeMesh } from './disposeMesh.js';
4
+ import { nativeGeometry } from './nativeGeometry.js';
5
+ import { nativeEvents } from './nativeEvents.js';
6
+ import { parseColor } from './parseColor.js';
7
+ import { update } from './update.js';
8
+
9
+ /** Render from coordinates and detached raster sources; only accessible marker controls remain DOM. */
10
+ export async function nativeLayer(state) {
11
+ const { source, map } = state;
12
+ const backend = state.backend = new L.Layer({ source: { type: '3d' } });
13
+ const meshes = state.meshes = new Map(), textures = new Map(), methods = new Map();
14
+ const images = new Set();
15
+ map._nativeGPUOrder ||= 0;
16
+ map._nativeGPUBack ||= 0;
17
+ let dirty = true, viewDirty = true, failed = false, order = ++map._nativeGPUOrder, rasterProgram;
18
+ const marker = source instanceof L.Marker;
19
+ const paneOrder = Number(getComputedStyle(source.getPane()).zIndex) || 0;
20
+ const current = () => source._nativeGPU === state && map.hasLayer(source);
21
+ const refresh = () => {
22
+ dirty = true;
23
+ viewDirty = true;
24
+ failed = false;
25
+ state.hide();
26
+ const activeImages = [source._icon, source._shadow, source._image];
27
+ for (const image of images) {
28
+ if (activeImages.includes(image)) continue;
29
+ image.removeEventListener('load', refresh);
30
+ image.removeEventListener('error', imageError);
31
+ images.delete(image);
32
+ }
33
+ for (const image of activeImages) {
34
+ if (!(image instanceof HTMLImageElement) || images.has(image)) continue;
35
+ images.add(image);
36
+ image.addEventListener('load', refresh);
37
+ image.addEventListener('error', imageError);
38
+ }
39
+ if (backend._shared) update(backend);
40
+ };
41
+ const imageError = () => source.fire('error', { error: new Error('Unable to load native layer image') });
42
+ state.refresh = refresh;
43
+ state.reorder = front => {
44
+ order = front ? ++map._nativeGPUOrder : --map._nativeGPUBack;
45
+ refresh();
46
+ };
47
+ const view = () => {
48
+ viewDirty = true;
49
+ if (backend._shared) update(backend);
50
+ };
51
+ const events = 'load tileload tileunload move drag';
52
+ source.on(events, refresh);
53
+ // Panning and camera changes never retriangulate paths or re-upload tile geometry.
54
+ map.on('zoomend', refresh);
55
+ if (marker) map.on('move zoom rotate pitch resize viewreset', view);
56
+ const removeEvents = nativeEvents(state);
57
+ for (const name of ['setLatLng', 'setLatLngs', 'addLatLng', 'setRadius', 'setStyle', 'redraw',
58
+ 'setIcon', 'setUrl', 'setBounds', 'setOpacity', 'setZIndex', 'setZIndexOffset', 'bringToFront', 'bringToBack']) {
59
+ if (typeof source[name] !== 'function') continue;
60
+ const own = Object.getOwnPropertyDescriptor(source, name), original = source[name];
61
+ methods.set(name, own);
62
+ source[name] = function (...args) {
63
+ const result = original.apply(this, args);
64
+ if ((name === 'bringToFront' || name === 'bringToBack') && this instanceof L.GridLayer) {
65
+ const indices = Object.values(map._layers).filter(layer => layer !== this &&
66
+ layer instanceof L.GridLayer && layer.getPane() === this.getPane()).map(layer => layer.options.zIndex || 0);
67
+ const edge = name === 'bringToFront' ? Math.max(...indices) + 1 : Math.min(...indices) - 1;
68
+ if (Number.isFinite(edge)) this.setZIndex(edge);
69
+ }
70
+ if (name === 'bringToFront') order = ++map._nativeGPUOrder;
71
+ if (name === 'bringToBack') order = --map._nativeGPUBack;
72
+ refresh();
73
+ return result;
74
+ };
75
+ }
76
+ state.dispose = () => {
77
+ source.off(events, refresh);
78
+ map.off('zoomend', refresh);
79
+ if (marker) map.off('move zoom rotate pitch resize viewreset', view);
80
+ removeEvents();
81
+ state.refresh = state.reorder = null;
82
+ for (const [name, descriptor] of methods) {
83
+ if (descriptor) Object.defineProperty(source, name, descriptor);
84
+ else delete source[name];
85
+ }
86
+ for (const mesh of meshes.values()) disposeMesh(backend, mesh);
87
+ meshes.clear();
88
+ for (const texture of textures.values()) destroyTexture(backend, texture.texture);
89
+ textures.clear();
90
+ for (const image of images) {
91
+ image.removeEventListener('load', refresh);
92
+ image.removeEventListener('error', imageError);
93
+ }
94
+ backend._beforeRender = null;
95
+ backend.remove();
96
+ };
97
+ const ready = new Promise((resolve, reject) => {
98
+ backend.once('ready', resolve);
99
+ backend.once('error', ({ error }) => reject(error));
100
+ });
101
+ backend.on('error', ({ error }) => source.fire('error', { error }));
102
+ refresh();
103
+ backend.addTo(map);
104
+ await ready.catch(error => {
105
+ state.dispose();
106
+ throw error;
107
+ });
108
+ if (!current()) return source;
109
+
110
+ const local = latlng => {
111
+ const crs = map.options.crs, origin = crs.project(backend.location), p = crs.project(latlng);
112
+ const metres = Math.cos(backend.location.lat * Math.PI / 180);
113
+ return [(p.x - origin.x) * metres, 0, -(p.y - origin.y) * metres];
114
+ };
115
+ const pixel = p => local(map.unproject(p));
116
+ const styleMesh = (mesh, color, opacity) => {
117
+ mesh.program.uniforms.baseColor.value = color;
118
+ mesh.program.uniforms.opacity.value = opacity;
119
+ if (source instanceof L.GridLayer) mesh.opacity = opacity;
120
+ const zIndex = marker ? source._zIndex + (source._cameraZIndexOffset || 0) : source.options.zIndex;
121
+ mesh.renderOrder = paneOrder * 1e6 + (zIndex || 0) * 1000 + order;
122
+ mesh._nativeSource = source;
123
+ mesh._nativeUsed = true;
124
+ };
125
+ const put = (key, position, color, opacity, texture, uv) => {
126
+ if (!position.length) return;
127
+ let mesh = meshes.get(key);
128
+ const data = {
129
+ position, normal: position.map((_, index) => index % 3 === 1 ? 1 : 0),
130
+ ...(uv ? { uv } : {}),
131
+ };
132
+ if (!mesh || mesh.geometry.attributes.position.data.length !== position.length ||
133
+ mesh.program.uniforms.baseTexture?.value !== texture) {
134
+ if (mesh) disposeMesh(backend, mesh);
135
+ mesh = createMesh(backend, data, {
136
+ vertexColors: false, color, opacity, unlit: true, alphaMode: 'BLEND',
137
+ ...(texture ? { baseTexture: texture } : {}),
138
+ }, 0, source instanceof L.GridLayer ? rasterProgram : undefined);
139
+ if (source instanceof L.GridLayer) {
140
+ rasterProgram ||= mesh.program;
141
+ mesh.texture = texture;
142
+ }
143
+ meshes.set(key, mesh);
144
+ } else {
145
+ const attribute = mesh.geometry.attributes.position;
146
+ attribute.data.set(position);
147
+ attribute.needsUpdate = true;
148
+ mesh.geometry.bounds = null;
149
+ }
150
+ styleMesh(mesh, color, opacity);
151
+ return mesh;
152
+ };
153
+ const textureFor = (key, image) => {
154
+ if (!(image instanceof HTMLImageElement) && !(image instanceof HTMLCanvasElement)) {
155
+ throw new Error('WebGPU native raster layers require image or canvas tiles');
156
+ }
157
+ let texture = textures.get(key);
158
+ const url = image.currentSrc || image.src;
159
+ if (!texture || texture.image !== image || texture.url !== url) {
160
+ if (texture) {
161
+ const mesh = meshes.get(key);
162
+ if (mesh) disposeMesh(backend, mesh);
163
+ meshes.delete(key);
164
+ destroyTexture(backend, texture.texture);
165
+ textures.delete(key);
166
+ }
167
+ const width = image.naturalWidth || image.width, height = image.naturalHeight || image.height;
168
+ if (!width || !height) return;
169
+ const { device } = backend.renderer;
170
+ texture = {
171
+ device, image, url, format: 'rgba8unorm', uploaded: null,
172
+ texture: device.createTexture({
173
+ size: [width, height], format: 'rgba8unorm',
174
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
175
+ }),
176
+ sampler: device.createSampler({ minFilter: 'linear', magFilter: 'linear' }),
177
+ };
178
+ textures.set(key, texture);
179
+ if (image instanceof HTMLCanvasElement) {
180
+ texture.pending = true;
181
+ // Snapshot asynchronously: copying a GPU-backed 2D canvas directly forces a blocking readback in Chromium.
182
+ createImageBitmap(image).then(bitmap => {
183
+ try {
184
+ if (!current() || textures.get(key) !== texture) return;
185
+ device.queue.copyExternalImageToTexture({ source: bitmap }, { texture: texture.texture }, [width, height]);
186
+ texture.uploaded = image;
187
+ texture.pending = false;
188
+ refresh();
189
+ } finally {
190
+ bitmap.close();
191
+ }
192
+ }).catch(error => {
193
+ failed = true;
194
+ source.fire('error', { error });
195
+ });
196
+ } else {
197
+ // CORS/security failures reject ready or emit error on the owning native layer.
198
+ try {
199
+ device.queue.copyExternalImageToTexture({ source: image }, { texture: texture.texture }, [width, height]);
200
+ } catch (error) {
201
+ texture.texture.destroy();
202
+ textures.delete(key);
203
+ throw error;
204
+ }
205
+ texture.uploaded = image;
206
+ }
207
+ }
208
+ texture.used = true;
209
+ return texture.uploaded === image ? texture : undefined;
210
+ };
211
+ const quad = (key, image, corners, opacity) => {
212
+ const texture = textureFor(key, image);
213
+ if (!texture) return;
214
+ const indices = [0, 2, 1, 1, 2, 3];
215
+ return put(key, indices.flatMap(i => corners[i]), [1, 1, 1], opacity, texture,
216
+ indices.flatMap(i => [[0, 0], [1, 0], [0, 1], [1, 1]][i]));
217
+ };
218
+ const boundsQuad = bounds => [
219
+ bounds.getNorthWest(), bounds.getNorthEast(), bounds.getSouthWest(), bounds.getSouthEast(),
220
+ ].map(local);
221
+ const synchronize = () => {
222
+ if (!current() || !backend.renderer || failed) return;
223
+ if (!dirty && (!marker || !viewDirty)) return;
224
+ dirty = false;
225
+ viewDirty = false;
226
+ for (const mesh of meshes.values()) mesh._nativeUsed = false;
227
+ for (const texture of textures.values()) texture.used = false;
228
+ if (source instanceof L.GridLayer) {
229
+ for (const [key, tile] of Object.entries(source._tiles || {})) {
230
+ if (!tile.loaded || tile.el instanceof HTMLImageElement && !tile.el.naturalWidth) continue;
231
+ const opacity = (source.options.opacity ?? 1) * (tile._gpuOpacity ?? 1);
232
+ const retained = textures.get(key);
233
+ let mesh = meshes.get(key);
234
+ if (mesh && retained?.image === tile.el && retained.url === (tile.el.currentSrc || tile.el.src)) {
235
+ retained.used = true;
236
+ styleMesh(mesh, [1, 1, 1], opacity);
237
+ } else {
238
+ const [nw, se] = source._tileCoordsToNwSe(tile.coords);
239
+ mesh = quad(key, tile.el, boundsQuad(new L.LatLngBounds(nw, se)), opacity);
240
+ }
241
+ if (mesh) mesh.renderOrder += tile.coords.z / 100;
242
+ }
243
+ } else if (source instanceof L.ImageOverlay) {
244
+ if (source._image?.complete && source._image.naturalWidth) {
245
+ quad('image', source._image, boundsQuad(source.getBounds()), source.options.opacity ?? 1);
246
+ }
247
+ } else if (marker) {
248
+ for (const [key, image] of [['shadow', source._shadow], ['icon', source._icon]]) {
249
+ if (!(image instanceof HTMLImageElement) || !image.complete || !image.naturalWidth) continue;
250
+ const world = new DOMPoint(...local(source.getLatLng()), 1)
251
+ .matrixTransform(new DOMMatrix(backend.root.worldMatrix));
252
+ const clip = world.matrixTransform(new DOMMatrix(backend.camera.projectionViewMatrix));
253
+ const inverse = new DOMMatrix(backend.camera.projectionViewMatrix).inverse();
254
+ const toLocal = new DOMMatrix(backend.root.worldMatrix).inverse();
255
+ const options = source.options.icon.options, size = map.getSize();
256
+ const dimensions = options[key === 'shadow' ? 'shadowSize' : 'iconSize'] ||
257
+ [image.naturalWidth, image.naturalHeight];
258
+ const width = dimensions.x ?? dimensions[0], height = dimensions.y ?? dimensions[1];
259
+ const anchor = (key === 'shadow' && options.shadowAnchor) ||
260
+ options.iconAnchor || [Math.floor(width / 2), Math.floor(height / 2)];
261
+ const center = new L.Point((clip.x / clip.w + 1) * size.x / 2, (1 - clip.y / clip.w) * size.y / 2);
262
+ const left = center.x - (anchor.x ?? anchor[0]), top = center.y - (anchor.y ?? anchor[1]);
263
+ const corners = [[left, top], [left + width, top],
264
+ [left, top + height], [left + width, top + height]].map(([x, y]) => {
265
+ const offset = source._cameraIconPoint(x - center.x, y - center.y);
266
+ x = center.x + offset.x; y = center.y + offset.y;
267
+ const p = new DOMPoint(x / size.x * 2 - 1,
268
+ 1 - y / size.y * 2, clip.z / clip.w, 1).matrixTransform(inverse);
269
+ const result = new DOMPoint(p.x / p.w, p.y / p.w, p.z / p.w, 1).matrixTransform(toLocal);
270
+ return [result.x, result.y, result.z];
271
+ });
272
+ const mesh = quad(key, image, corners, source.options.opacity ?? 1);
273
+ if (key === 'shadow' && mesh) mesh.renderOrder -= 100 * 1e6;
274
+ }
275
+ } else {
276
+ const { fill, stroke } = nativeGeometry(source, map, pixel);
277
+ for (const [key, positions, color, opacity] of [
278
+ ['fill', fill, source.options.fillColor || source.options.color, source.options.fillOpacity],
279
+ ['stroke', stroke, source.options.color, source.options.opacity],
280
+ ]) {
281
+ if (!positions.length) continue;
282
+ const { r, g, b } = parseColor(color);
283
+ put(key, positions, [r, g, b], opacity ?? 1);
284
+ }
285
+ }
286
+ for (const [key, mesh] of meshes) {
287
+ if (mesh._nativeUsed) continue;
288
+ disposeMesh(backend, mesh);
289
+ meshes.delete(key);
290
+ const texture = textures.get(key);
291
+ if (texture) destroyTexture(backend, texture.texture);
292
+ textures.delete(key);
293
+ }
294
+ for (const [key, texture] of textures) {
295
+ if (texture.used) continue;
296
+ destroyTexture(backend, texture.texture);
297
+ textures.delete(key);
298
+ }
299
+ };
300
+ backend._beforeRender = () => {
301
+ try {
302
+ synchronize();
303
+ } catch (error) {
304
+ failed = true;
305
+ source.fire('error', { error });
306
+ }
307
+ };
308
+ // ponytail: tessellate pixel-width strokes on zoomend; use shader extrusion for continuous zoom at scale.
309
+ try {
310
+ synchronize();
311
+ } catch (error) {
312
+ state.dispose();
313
+ throw error;
314
+ }
315
+ update(backend);
316
+ return source;
317
+ }
@@ -0,0 +1,22 @@
1
+ /** glTF quaternion/translation/scale to a column-major matrix. */
2
+
3
+ export function nodeMatrix(spec) {
4
+ if (spec.matrix) return Array.from(spec.matrix);
5
+ // glTF stores quaternions [x,y,z,w]; convert directly to a scaled column-major matrix.
6
+ const [x, y, z, w] = spec.rotation || [0, 0, 0, 1], [sx, sy, sz] = spec.scale || [1, 1, 1];
7
+ return [
8
+ (1 - 2 * (y * y + z * z)) * sx,
9
+ 2 * (x * y + z * w) * sx,
10
+ 2 * (x * z - y * w) * sx,
11
+ 0,
12
+ 2 * (x * y - z * w) * sy,
13
+ (1 - 2 * (x * x + z * z)) * sy,
14
+ 2 * (y * z + x * w) * sy, 0,
15
+ 2 * (x * z + y * w) * sz,
16
+ 2 * (y * z - x * w) * sz,
17
+ (1 - 2 * (x * x + y * y)) * sz,
18
+ 0,
19
+ ...(spec.translation || [0, 0, 0]),
20
+ 1,
21
+ ];
22
+ }
@@ -0,0 +1,31 @@
1
+ import * as attach from './attach.js';
2
+ import * as onClick from './onClick.js';
3
+ import * as onPointerLeave from './onPointerLeave.js';
4
+ import * as onPointerMove from './onPointerMove.js';
5
+
6
+ /** Attach interaction immediately; initialization may finish before or after onAdd. */
7
+ export function onAdd3DLayer(backend, map) {
8
+ if (!backend.location) {
9
+ const center = map.getCenter();
10
+ backend.location = new L.LatLng(center.lat, center.lng);
11
+ }
12
+ if (backend.url || backend._geojson || backend.options.tooltip || backend.modelUrl) {
13
+ backend.container = map.getContainer();
14
+ backend._pointerEvents ||= {
15
+ mousemove: event => onPointerMove.onPointerMove(backend, event),
16
+ click: event => onClick.onClick(backend, event),
17
+ mouseleave: () => onPointerLeave.onPointerLeave(backend),
18
+ };
19
+ if (backend.options.tooltip) {
20
+ backend._tooltip = L.DomUtil.create('div', 'leaflet-3d-tooltip', backend.container);
21
+ backend._tooltip.hidden = true;
22
+ backend._tooltip.setAttribute('role', 'tooltip');
23
+ backend._tooltip.setAttribute('aria-live', 'polite');
24
+ backend._tooltip.style.cssText = 'position:absolute;z-index:600;max-width:220px;padding:10px 12px;border:1px solid #6b5140;border-radius:6px;background:#fffaf0;box-shadow:0 3px 12px #0005;color:#30251d;font:13px/1.45 sans-serif;pointer-events:none';
25
+ }
26
+ L.DomEvent.on(backend.container, backend._pointerEvents);
27
+ }
28
+ if (backend.root) {
29
+ attach.attach(backend, map).then(() => backend._added.resolve(), error => backend.fire('error', { error }));
30
+ }
31
+ }
@@ -0,0 +1,147 @@
1
+ import { underEntry } from './underEntry.js';
2
+ import { update as updateScene } from "./update.js";
3
+ import { atmosphere } from './atmosphere.js';
4
+ import { moonPosition } from './moonPosition.js';
5
+ import { projectCelestialBody } from './projectCelestialBody.js';
6
+ import { solarPosition } from './solarPosition.js';
7
+
8
+ export function onAddSun(layer, map) {
9
+ if (!layer.control) {
10
+ const control = new L.Control({ position: 'bottomright' });
11
+ control.live = true;
12
+ let date, slider, output, status, timer;
13
+ const originalSky = map.getContainer().style.getPropertyValue('--leaflet-sky-background');
14
+ const disc = 'position:absolute;width:18px;height:18px;border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;';
15
+ const sunDisc = L.DomUtil.create('div', 'sunlight-sun');
16
+ const moonDisc = L.DomUtil.create('div', 'sunlight-moon');
17
+ sunDisc.style.cssText = disc + 'background:#fff3bd;box-shadow:0 0 18px 7px #ffd27699;';
18
+ moonDisc.style.cssText = disc + 'background:#dce5f2;box-shadow:0 0 10px 2px #cbdcff55;';
19
+ sunDisc.setAttribute('role', 'img'); sunDisc.setAttribute('aria-label', 'Sun');
20
+ moonDisc.setAttribute('role', 'img'); moonDisc.setAttribute('aria-label', 'Moon');
21
+ const updateSky = () => {
22
+ const sun = map._sunlight, sky = map._pitchSky;
23
+ if (sun) map.getContainer().style.setProperty('--leaflet-sky-background', sun.background);
24
+ else if (originalSky) map.getContainer().style.setProperty('--leaflet-sky-background', originalSky);
25
+ else map.getContainer().style.removeProperty('--leaflet-sky-background');
26
+ const size = map.getSize(), pitch = map.getPitch() * Math.PI / 180, bearing = map.getBearing() * Math.PI / 180;
27
+ for (const [disc, body] of [[sunDisc, sun], [moonDisc, sun?.moon]]) {
28
+ disc.hidden = true;
29
+ if (!sky || !body || body.altitude <= 0 || !sun) continue;
30
+ if (disc.parentNode !== sky) sky.append(disc);
31
+ const point = projectCelestialBody(body.direction, size, pitch, bearing);
32
+ if (!point) continue;
33
+ const { left, top } = point;
34
+ disc.hidden = left < 0 || left > size.x || top < 0 || top > sky.clientHeight || sky.style.display === 'none';
35
+ disc.style.left = `${left}px`; disc.style.top = `${top}px`;
36
+ }
37
+ };
38
+ const render = () => {
39
+ const renderer = L.Layer._renderers.get(map);
40
+ if (renderer) updateScene(renderer);
41
+ };
42
+ const update = () => {
43
+ try {
44
+ if (control.live) control.time = new Date();
45
+ const time = control.time.toISOString();
46
+ date.value = time.slice(0, 10);
47
+ slider.value = String(control.time.getUTCHours() * 60 + control.time.getUTCMinutes());
48
+ output.textContent = `${time.slice(11, 16)} UTC${control.live ? ' · now' : ''}`;
49
+ const center = map.getCenter();
50
+ const sun = map._sunlight = solarPosition(control.time, center.lat, center.lng);
51
+ Object.assign(sun, atmosphere(sun.altitude));
52
+ sun.moon = moonPosition(control.time, center.lat, center.lng);
53
+ status.textContent = sun.altitude <= 0
54
+ ? 'Night · no direct sunlight'
55
+ : sun.altitude < 3
56
+ ? 'Low sun · shadows paused'
57
+ : `Sun altitude ${sun.altitude.toFixed(1)}°`;
58
+ map.fire('simulationtimechange', { time: new Date(control.time), live: control.live });
59
+ updateSky();
60
+ render();
61
+ } catch (error) {
62
+ delete map._sunlight;
63
+ updateSky();
64
+ render();
65
+ status.textContent = `Error: ${error.message}`;
66
+ console.error('Solar simulation', error);
67
+ }
68
+ };
69
+ control.onAdd = () => {
70
+ const container = L.DomUtil.create('div', 'sunlight-control');
71
+ container.style.cssText = 'color:#222;width:min(200px,calc(100vw - 60px));font:12px/1.4 sans-serif;';
72
+ date = document.createElement('input');
73
+ date.type = 'date';
74
+ date.style.cssText = 'width:100%;box-sizing:border-box;';
75
+ date.setAttribute('aria-label', 'Solar date (UTC)');
76
+ slider = document.createElement('input');
77
+ slider.type = 'range';
78
+ slider.style.cssText = 'width:100%;box-sizing:border-box;margin:10px 0 4px;cursor:pointer;';
79
+ slider.min = '0'; slider.max = '1439'; slider.step = '1';
80
+ slider.setAttribute('aria-label', 'Time of day (UTC)');
81
+ output = document.createElement('output');
82
+ output.style.cssText = 'font-weight:bold;font-variant-numeric:tabular-nums;';
83
+ output.setAttribute('aria-live', 'off');
84
+ const now = document.createElement('button');
85
+ now.type = 'button'; now.textContent = 'Now';
86
+ now.onclick = () => { control.live = true; update(); };
87
+ const timeRow = document.createElement('div');
88
+ timeRow.className = 'sunlight-time';
89
+ timeRow.style.cssText = 'display:flex;justify-content:space-between;align-items:center;';
90
+ timeRow.append(output, now);
91
+ status = document.createElement('div');
92
+ status.className = 'sunlight-status';
93
+ status.style.marginTop = '5px';
94
+ status.setAttribute('role', 'status');
95
+ const note = document.createElement('small');
96
+ note.style.color = '#555';
97
+ note.textContent = 'Indicative · loaded geometry only. Streetlight illumination is estimated, not measured lux.';
98
+ container.append(date, slider, timeRow, status, note);
99
+ date.onchange = slider.oninput = () => {
100
+ control.live = false;
101
+ if (!date.value || !date.validity.valid) {
102
+ control.time = new Date(NaN);
103
+ map.fire('simulationtimechange', { time: null, live: false });
104
+ delete map._sunlight;
105
+ updateSky();
106
+ render();
107
+ status.textContent = 'Error: choose a valid solar date';
108
+ return;
109
+ }
110
+ control.time = new Date(`${date.value}T00:00:00Z`);
111
+ control.time.setUTCMinutes(Number(slider.value));
112
+ update();
113
+ };
114
+ L.DomEvent.disableClickPropagation(container);
115
+ L.DomEvent.disableScrollPropagation(container);
116
+ update();
117
+ timer = setInterval(() => { if (control.live) update(); }, 60000);
118
+ map.on('moveend', update);
119
+ map.on('move rotate pitch resize', updateSky);
120
+ return container;
121
+ };
122
+ control.onRemove = () => {
123
+ clearInterval(timer);
124
+ map.fire('simulationtimechange', { time: null, live: false });
125
+ map.off('moveend', update);
126
+ map.off('move rotate pitch resize', updateSky);
127
+ delete map._sunlight;
128
+ updateSky();
129
+ sunDisc.remove(); moonDisc.remove();
130
+ render();
131
+ };
132
+ layer.control = control;
133
+ }
134
+ if (!layer.control._map) {
135
+ layer.control.addTo(map);
136
+ }
137
+ // Shown under this layer's entry in the layers control; a standalone control without one.
138
+ const container = layer.control.getContainer(), nested = underEntry(layer, container);
139
+ container.classList.toggle('leaflet-control', !nested);
140
+ container.classList.toggle('leaflet-bar', !nested);
141
+ Object.assign(
142
+ container.style,
143
+ nested
144
+ ? { background: '', padding: '2px 0 6px 20px', margin: '0' }
145
+ : { background: '#fff', padding: '8px', margin: '' }
146
+ );
147
+ }
@@ -0,0 +1,13 @@
1
+ import { findFeature } from './findFeature.js';
2
+ import { setHighlight } from './setHighlight.js';
3
+ import { showFeature } from './showFeature.js';
4
+
5
+ /** Emit click without moving the map or pinning the tooltip. */
6
+
7
+ export function onClick(layer, event) {
8
+ const feature = findFeature(layer, event);
9
+ layer.hoveredFeature = feature;
10
+ setHighlight(layer, feature);
11
+ showFeature(layer, feature, event);
12
+ layer.fire('featureclick', { feature, originalEvent: event });
13
+ }