@sakuzu/maplibre-gl-draw 1.0.0

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 (636) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +661 -0
  3. package/README.ja.md +248 -0
  4. package/README.md +255 -0
  5. package/THIRD_PARTY_NOTICES.md +275 -0
  6. package/dist/api/api.d.ts +1259 -0
  7. package/dist/api/api.js +86 -0
  8. package/dist/api/context.d.ts +173 -0
  9. package/dist/api/context.js +193 -0
  10. package/dist/api/display-api.d.ts +1 -0
  11. package/dist/api/display-api.js +23 -0
  12. package/dist/api/event-api.d.ts +13 -0
  13. package/dist/api/event-api.js +17 -0
  14. package/dist/api/extension-api.d.ts +46 -0
  15. package/dist/api/extension-api.js +85 -0
  16. package/dist/api/feature-api.d.ts +11 -0
  17. package/dist/api/feature-api.js +101 -0
  18. package/dist/api/geometry/apply.d.ts +51 -0
  19. package/dist/api/geometry/apply.js +114 -0
  20. package/dist/api/geometry/boolean.d.ts +28 -0
  21. package/dist/api/geometry/boolean.js +65 -0
  22. package/dist/api/geometry/buffer.d.ts +11 -0
  23. package/dist/api/geometry/buffer.js +105 -0
  24. package/dist/api/geometry/split.d.ts +16 -0
  25. package/dist/api/geometry/split.js +75 -0
  26. package/dist/api/geometry/targets.d.ts +76 -0
  27. package/dist/api/geometry/targets.js +158 -0
  28. package/dist/api/geometry/types.d.ts +31 -0
  29. package/dist/api/geometry/types.js +3 -0
  30. package/dist/api/geometry-operations.d.ts +162 -0
  31. package/dist/api/geometry-operations.js +94 -0
  32. package/dist/api/group-api.d.ts +10 -0
  33. package/dist/api/group-api.js +78 -0
  34. package/dist/api/import-export/constants.d.ts +29 -0
  35. package/dist/api/import-export/constants.js +40 -0
  36. package/dist/api/import-export/embedded-file.d.ts +13 -0
  37. package/dist/api/import-export/embedded-file.js +31 -0
  38. package/dist/api/import-export/file-name.d.ts +10 -0
  39. package/dist/api/import-export/file-name.js +20 -0
  40. package/dist/api/import-export/format-detection.d.ts +12 -0
  41. package/dist/api/import-export/format-detection.js +29 -0
  42. package/dist/api/import-export/geojson-export.d.ts +19 -0
  43. package/dist/api/import-export/geojson-export.js +262 -0
  44. package/dist/api/import-export/geojson-import.d.ts +34 -0
  45. package/dist/api/import-export/geojson-import.js +538 -0
  46. package/dist/api/import-export/geometry-validation.d.ts +20 -0
  47. package/dist/api/import-export/geometry-validation.js +107 -0
  48. package/dist/api/import-export/image-import.d.ts +12 -0
  49. package/dist/api/import-export/image-import.js +53 -0
  50. package/dist/api/import-export/index.d.ts +9 -0
  51. package/dist/api/import-export/index.js +107 -0
  52. package/dist/api/import-export/native-format.d.ts +15 -0
  53. package/dist/api/import-export/native-format.js +126 -0
  54. package/dist/api/import-export/native-validation.d.ts +28 -0
  55. package/dist/api/import-export/native-validation.js +212 -0
  56. package/dist/api/import-export/own-property.d.ts +10 -0
  57. package/dist/api/import-export/own-property.js +19 -0
  58. package/dist/api/import-export/style-validation.d.ts +27 -0
  59. package/dist/api/import-export/style-validation.js +49 -0
  60. package/dist/api/import-export/types.d.ts +26 -0
  61. package/dist/api/import-export/types.js +3 -0
  62. package/dist/api/index.d.ts +15 -0
  63. package/dist/api/index.js +3 -0
  64. package/dist/api/input-api.d.ts +158 -0
  65. package/dist/api/input-api.js +144 -0
  66. package/dist/api/instance-api.d.ts +38 -0
  67. package/dist/api/instance-api.js +136 -0
  68. package/dist/api/layer-api.d.ts +12 -0
  69. package/dist/api/layer-api.js +62 -0
  70. package/dist/api/selection-api.d.ts +7 -0
  71. package/dist/api/selection-api.js +78 -0
  72. package/dist/api/snapping-api.d.ts +125 -0
  73. package/dist/api/snapping-api.js +50 -0
  74. package/dist/api/topology-api.d.ts +30 -0
  75. package/dist/api/topology-api.js +16 -0
  76. package/dist/api/tracing-api.d.ts +31 -0
  77. package/dist/api/tracing-api.js +16 -0
  78. package/dist/dispatcher/hit-test/box-strategies.d.ts +19 -0
  79. package/dist/dispatcher/hit-test/box-strategies.js +275 -0
  80. package/dist/dispatcher/hit-test/box-strategy.d.ts +59 -0
  81. package/dist/dispatcher/hit-test/box-strategy.js +37 -0
  82. package/dist/dispatcher/hit-test/globe-shape.d.ts +46 -0
  83. package/dist/dispatcher/hit-test/globe-shape.js +70 -0
  84. package/dist/dispatcher/hit-test/index.d.ts +14 -0
  85. package/dist/dispatcher/hit-test/index.js +9 -0
  86. package/dist/dispatcher/hit-test/local-frame.d.ts +77 -0
  87. package/dist/dispatcher/hit-test/local-frame.js +112 -0
  88. package/dist/dispatcher/hit-test/segment-grid.d.ts +32 -0
  89. package/dist/dispatcher/hit-test/segment-grid.js +79 -0
  90. package/dist/dispatcher/hit-test/service.d.ts +120 -0
  91. package/dist/dispatcher/hit-test/service.js +333 -0
  92. package/dist/dispatcher/hit-test/strategies/base.d.ts +136 -0
  93. package/dist/dispatcher/hit-test/strategies/base.js +66 -0
  94. package/dist/dispatcher/hit-test/strategies/circle.d.ts +10 -0
  95. package/dist/dispatcher/hit-test/strategies/circle.js +56 -0
  96. package/dist/dispatcher/hit-test/strategies/image.d.ts +22 -0
  97. package/dist/dispatcher/hit-test/strategies/image.js +115 -0
  98. package/dist/dispatcher/hit-test/strategies/index.d.ts +11 -0
  99. package/dist/dispatcher/hit-test/strategies/index.js +10 -0
  100. package/dist/dispatcher/hit-test/strategies/line.d.ts +17 -0
  101. package/dist/dispatcher/hit-test/strategies/line.js +30 -0
  102. package/dist/dispatcher/hit-test/strategies/multi.d.ts +44 -0
  103. package/dist/dispatcher/hit-test/strategies/multi.js +141 -0
  104. package/dist/dispatcher/hit-test/strategies/point.d.ts +20 -0
  105. package/dist/dispatcher/hit-test/strategies/point.js +29 -0
  106. package/dist/dispatcher/hit-test/strategies/polygon.d.ts +52 -0
  107. package/dist/dispatcher/hit-test/strategies/polygon.js +138 -0
  108. package/dist/dispatcher/hit-test/topmost.d.ts +48 -0
  109. package/dist/dispatcher/hit-test/topmost.js +157 -0
  110. package/dist/dispatcher/hit-test/visibility-lookup.d.ts +23 -0
  111. package/dist/dispatcher/hit-test/visibility-lookup.js +40 -0
  112. package/dist/dispatcher/index.d.ts +15 -0
  113. package/dist/dispatcher/index.js +3 -0
  114. package/dist/dispatcher/input-router.d.ts +1 -0
  115. package/dist/dispatcher/input-router.js +288 -0
  116. package/dist/dispatcher/normalizer.d.ts +1 -0
  117. package/dist/dispatcher/normalizer.js +513 -0
  118. package/dist/dispatcher/types.d.ts +144 -0
  119. package/dist/dispatcher/types.js +15 -0
  120. package/dist/display/chunk-set.d.ts +24 -0
  121. package/dist/display/chunk-set.js +533 -0
  122. package/dist/display/chunk.d.ts +1 -0
  123. package/dist/display/chunk.js +104 -0
  124. package/dist/display/columnar/index.d.ts +12 -0
  125. package/dist/display/columnar/index.js +13 -0
  126. package/dist/display/columnar/prepare.d.ts +42 -0
  127. package/dist/display/columnar/prepare.js +116 -0
  128. package/dist/display/columnar/source.d.ts +1 -0
  129. package/dist/display/columnar/source.js +531 -0
  130. package/dist/display/columnar/table.d.ts +1 -0
  131. package/dist/display/columnar/table.js +471 -0
  132. package/dist/display/columnar/types.d.ts +223 -0
  133. package/dist/display/columnar/types.js +3 -0
  134. package/dist/display/dataset.d.ts +2 -0
  135. package/dist/display/dataset.js +891 -0
  136. package/dist/display/index.d.ts +13 -0
  137. package/dist/display/index.js +3 -0
  138. package/dist/display/interaction.d.ts +1 -0
  139. package/dist/display/interaction.js +90 -0
  140. package/dist/display/manager.d.ts +1 -0
  141. package/dist/display/manager.js +440 -0
  142. package/dist/display/packed-rtree.d.ts +1 -0
  143. package/dist/display/packed-rtree.js +244 -0
  144. package/dist/display/partition.d.ts +1 -0
  145. package/dist/display/partition.js +226 -0
  146. package/dist/display/provider.d.ts +1 -0
  147. package/dist/display/provider.js +342 -0
  148. package/dist/display/retained.d.ts +40 -0
  149. package/dist/display/retained.js +898 -0
  150. package/dist/display/selection.d.ts +13 -0
  151. package/dist/display/selection.js +226 -0
  152. package/dist/display/source.d.ts +1 -0
  153. package/dist/display/source.js +119 -0
  154. package/dist/display/spatial.d.ts +1 -0
  155. package/dist/display/spatial.js +71 -0
  156. package/dist/display/style.d.ts +1 -0
  157. package/dist/display/style.js +126 -0
  158. package/dist/display/thinning.d.ts +65 -0
  159. package/dist/display/thinning.js +910 -0
  160. package/dist/display/triangulation.d.ts +1 -0
  161. package/dist/display/triangulation.js +0 -0
  162. package/dist/display/types.d.ts +561 -0
  163. package/dist/display/types.js +43 -0
  164. package/dist/extension/feature-handler.d.ts +182 -0
  165. package/dist/extension/feature-handler.js +3 -0
  166. package/dist/extension/index.d.ts +9 -0
  167. package/dist/extension/index.js +3 -0
  168. package/dist/extension/renderers.d.ts +208 -0
  169. package/dist/extension/renderers.js +3 -0
  170. package/dist/geometry/angle.d.ts +47 -0
  171. package/dist/geometry/angle.js +44 -0
  172. package/dist/geometry/bbox.d.ts +48 -0
  173. package/dist/geometry/bbox.js +83 -0
  174. package/dist/geometry/boolean.d.ts +162 -0
  175. package/dist/geometry/boolean.js +331 -0
  176. package/dist/geometry/buffer.d.ts +72 -0
  177. package/dist/geometry/buffer.js +218 -0
  178. package/dist/geometry/circle.d.ts +55 -0
  179. package/dist/geometry/circle.js +107 -0
  180. package/dist/geometry/coords.d.ts +97 -0
  181. package/dist/geometry/coords.js +149 -0
  182. package/dist/geometry/distance.d.ts +79 -0
  183. package/dist/geometry/distance.js +111 -0
  184. package/dist/geometry/errors.d.ts +74 -0
  185. package/dist/geometry/errors.js +104 -0
  186. package/dist/geometry/index.d.ts +28 -0
  187. package/dist/geometry/index.js +38 -0
  188. package/dist/geometry/measure.d.ts +81 -0
  189. package/dist/geometry/measure.js +236 -0
  190. package/dist/geometry/predicates.d.ts +62 -0
  191. package/dist/geometry/predicates.js +132 -0
  192. package/dist/geometry/simplify.d.ts +74 -0
  193. package/dist/geometry/simplify.js +159 -0
  194. package/dist/geometry/split.d.ts +68 -0
  195. package/dist/geometry/split.js +430 -0
  196. package/dist/geometry/types.d.ts +95 -0
  197. package/dist/geometry/types.js +3 -0
  198. package/dist/geometry/units.d.ts +35 -0
  199. package/dist/geometry/units.js +41 -0
  200. package/dist/index.d.ts +72 -0
  201. package/dist/index.js +20 -0
  202. package/dist/maplibre-gl-draw.d.ts +47 -0
  203. package/dist/maplibre-gl-draw.js +407 -0
  204. package/dist/messages.d.ts +64 -0
  205. package/dist/messages.js +36 -0
  206. package/dist/modes/cursor.d.ts +1 -0
  207. package/dist/modes/cursor.js +72 -0
  208. package/dist/modes/draw/circle.d.ts +1 -0
  209. package/dist/modes/draw/circle.js +222 -0
  210. package/dist/modes/draw/commit-layer.d.ts +26 -0
  211. package/dist/modes/draw/commit-layer.js +31 -0
  212. package/dist/modes/draw/freehand.d.ts +1 -0
  213. package/dist/modes/draw/freehand.js +264 -0
  214. package/dist/modes/draw/image.d.ts +1 -0
  215. package/dist/modes/draw/image.js +60 -0
  216. package/dist/modes/draw/index.d.ts +9 -0
  217. package/dist/modes/draw/index.js +11 -0
  218. package/dist/modes/draw/line.d.ts +1 -0
  219. package/dist/modes/draw/line.js +363 -0
  220. package/dist/modes/draw/point.d.ts +1 -0
  221. package/dist/modes/draw/point.js +87 -0
  222. package/dist/modes/draw/polygon.d.ts +1 -0
  223. package/dist/modes/draw/polygon.js +378 -0
  224. package/dist/modes/draw/trace-support.d.ts +79 -0
  225. package/dist/modes/draw/trace-support.js +161 -0
  226. package/dist/modes/handler.d.ts +285 -0
  227. package/dist/modes/handler.js +3 -0
  228. package/dist/modes/index.d.ts +7 -0
  229. package/dist/modes/index.js +3 -0
  230. package/dist/modes/manager.d.ts +15 -0
  231. package/dist/modes/manager.js +196 -0
  232. package/dist/modes/select/box-selection.d.ts +52 -0
  233. package/dist/modes/select/box-selection.js +140 -0
  234. package/dist/modes/select/click-handler.d.ts +32 -0
  235. package/dist/modes/select/click-handler.js +166 -0
  236. package/dist/modes/select/cursor-handler.d.ts +15 -0
  237. package/dist/modes/select/cursor-handler.js +59 -0
  238. package/dist/modes/select/drag/auxiliary.d.ts +26 -0
  239. package/dist/modes/select/drag/auxiliary.js +56 -0
  240. package/dist/modes/select/drag/intermediate-writes.d.ts +1 -0
  241. package/dist/modes/select/drag/intermediate-writes.js +171 -0
  242. package/dist/modes/select/drag/move.d.ts +24 -0
  243. package/dist/modes/select/drag/move.js +59 -0
  244. package/dist/modes/select/drag/operation.d.ts +30 -0
  245. package/dist/modes/select/drag/operation.js +18 -0
  246. package/dist/modes/select/drag/radius.d.ts +15 -0
  247. package/dist/modes/select/drag/radius.js +49 -0
  248. package/dist/modes/select/drag/transform.d.ts +17 -0
  249. package/dist/modes/select/drag/transform.js +155 -0
  250. package/dist/modes/select/drag/vertex.d.ts +17 -0
  251. package/dist/modes/select/drag/vertex.js +163 -0
  252. package/dist/modes/select/drag-handler.d.ts +1 -0
  253. package/dist/modes/select/drag-handler.js +254 -0
  254. package/dist/modes/select/hit-helpers.d.ts +40 -0
  255. package/dist/modes/select/hit-helpers.js +51 -0
  256. package/dist/modes/select/mode.d.ts +1 -0
  257. package/dist/modes/select/mode.js +397 -0
  258. package/dist/modes/select/shortcut-handler.d.ts +40 -0
  259. package/dist/modes/select/shortcut-handler.js +128 -0
  260. package/dist/operations/index.d.ts +9 -0
  261. package/dist/operations/index.js +3 -0
  262. package/dist/operations/layer-operations.d.ts +1 -0
  263. package/dist/operations/layer-operations.js +350 -0
  264. package/dist/operations/resize.d.ts +71 -0
  265. package/dist/operations/resize.js +252 -0
  266. package/dist/operations/rotate.d.ts +17 -0
  267. package/dist/operations/rotate.js +166 -0
  268. package/dist/operations/selection-operations.d.ts +20 -0
  269. package/dist/operations/selection-operations.js +159 -0
  270. package/dist/operations/shared-vertex.d.ts +1 -0
  271. package/dist/operations/shared-vertex.js +210 -0
  272. package/dist/operations/trace-graph.d.ts +96 -0
  273. package/dist/operations/trace-graph.js +283 -0
  274. package/dist/operations/vertex.d.ts +1 -0
  275. package/dist/operations/vertex.js +538 -0
  276. package/dist/plugins/index.d.ts +10 -0
  277. package/dist/plugins/index.js +3 -0
  278. package/dist/plugins/mutation-hooks.d.ts +28 -0
  279. package/dist/plugins/mutation-hooks.js +84 -0
  280. package/dist/plugins/plugin-context.d.ts +1 -0
  281. package/dist/plugins/plugin-context.js +367 -0
  282. package/dist/plugins/plugin-manager.d.ts +103 -0
  283. package/dist/plugins/plugin-manager.js +316 -0
  284. package/dist/plugins/plugin.d.ts +529 -0
  285. package/dist/plugins/plugin.js +3 -0
  286. package/dist/shared/config/constants.d.ts +66 -0
  287. package/dist/shared/config/constants.js +60 -0
  288. package/dist/shared/config/feature-style.d.ts +155 -0
  289. package/dist/shared/config/feature-style.js +154 -0
  290. package/dist/shared/config/index.d.ts +17 -0
  291. package/dist/shared/config/index.js +8 -0
  292. package/dist/shared/config/rendering.d.ts +107 -0
  293. package/dist/shared/config/rendering.js +33 -0
  294. package/dist/shared/config/selection-highlight.d.ts +29 -0
  295. package/dist/shared/config/selection-highlight.js +35 -0
  296. package/dist/shared/config/selection.d.ts +273 -0
  297. package/dist/shared/config/selection.js +266 -0
  298. package/dist/shared/config/topology.d.ts +33 -0
  299. package/dist/shared/config/topology.js +17 -0
  300. package/dist/shared/config/trace.d.ts +40 -0
  301. package/dist/shared/config/trace.js +17 -0
  302. package/dist/shared/math/angle.d.ts +21 -0
  303. package/dist/shared/math/angle.js +34 -0
  304. package/dist/shared/math/circle.d.ts +6 -0
  305. package/dist/shared/math/circle.js +10 -0
  306. package/dist/shared/math/constants.d.ts +48 -0
  307. package/dist/shared/math/constants.js +59 -0
  308. package/dist/shared/math/distance.d.ts +78 -0
  309. package/dist/shared/math/distance.js +147 -0
  310. package/dist/shared/math/globe-subdivision.d.ts +62 -0
  311. package/dist/shared/math/globe-subdivision.js +99 -0
  312. package/dist/shared/math/index.d.ts +17 -0
  313. package/dist/shared/math/index.js +21 -0
  314. package/dist/shared/math/intersection.d.ts +63 -0
  315. package/dist/shared/math/intersection.js +236 -0
  316. package/dist/shared/math/longitude.d.ts +20 -0
  317. package/dist/shared/math/longitude.js +31 -0
  318. package/dist/shared/math/mercator-plane.d.ts +27 -0
  319. package/dist/shared/math/mercator-plane.js +26 -0
  320. package/dist/shared/math/obb.d.ts +65 -0
  321. package/dist/shared/math/obb.js +107 -0
  322. package/dist/shared/math/rotation.d.ts +93 -0
  323. package/dist/shared/math/rotation.js +186 -0
  324. package/dist/shared/math/segment-grid.d.ts +69 -0
  325. package/dist/shared/math/segment-grid.js +159 -0
  326. package/dist/shared/math/transform.d.ts +140 -0
  327. package/dist/shared/math/transform.js +189 -0
  328. package/dist/shared/types/events.d.ts +128 -0
  329. package/dist/shared/types/events.js +3 -0
  330. package/dist/shared/types/model.d.ts +950 -0
  331. package/dist/shared/types/model.js +3 -0
  332. package/dist/shared/types/selection-box.d.ts +23 -0
  333. package/dist/shared/types/selection-box.js +3 -0
  334. package/dist/shared/types/style.d.ts +68 -0
  335. package/dist/shared/types/style.js +3 -0
  336. package/dist/shared/utils/color.d.ts +49 -0
  337. package/dist/shared/utils/color.js +180 -0
  338. package/dist/shared/utils/coordinates.d.ts +52 -0
  339. package/dist/shared/utils/coordinates.js +75 -0
  340. package/dist/shared/utils/embedded-image.d.ts +34 -0
  341. package/dist/shared/utils/embedded-image.js +161 -0
  342. package/dist/shared/utils/event-emitter.d.ts +262 -0
  343. package/dist/shared/utils/event-emitter.js +44 -0
  344. package/dist/shared/utils/feature-bbox.d.ts +8 -0
  345. package/dist/shared/utils/feature-bbox.js +207 -0
  346. package/dist/shared/utils/feature-segments.d.ts +23 -0
  347. package/dist/shared/utils/feature-segments.js +179 -0
  348. package/dist/shared/utils/id.d.ts +1 -0
  349. package/dist/shared/utils/id.js +35 -0
  350. package/dist/shared/utils/image.d.ts +34 -0
  351. package/dist/shared/utils/image.js +106 -0
  352. package/dist/shared/utils/index.d.ts +15 -0
  353. package/dist/shared/utils/index.js +24 -0
  354. package/dist/shared/utils/map.d.ts +26 -0
  355. package/dist/shared/utils/map.js +35 -0
  356. package/dist/shared/utils/name-generator.d.ts +197 -0
  357. package/dist/shared/utils/name-generator.js +337 -0
  358. package/dist/shared/utils/pixel-ratio.d.ts +111 -0
  359. package/dist/shared/utils/pixel-ratio.js +85 -0
  360. package/dist/shared/utils/property.d.ts +88 -0
  361. package/dist/shared/utils/property.js +140 -0
  362. package/dist/shared/utils/vertex-ref.d.ts +23 -0
  363. package/dist/shared/utils/vertex-ref.js +20 -0
  364. package/dist/snapping/custom-targets.d.ts +1 -0
  365. package/dist/snapping/custom-targets.js +21 -0
  366. package/dist/snapping/geometry.d.ts +1 -0
  367. package/dist/snapping/geometry.js +61 -0
  368. package/dist/snapping/index.d.ts +14 -0
  369. package/dist/snapping/index.js +4 -0
  370. package/dist/snapping/indicator.d.ts +19 -0
  371. package/dist/snapping/indicator.js +145 -0
  372. package/dist/snapping/providers/display.d.ts +72 -0
  373. package/dist/snapping/providers/display.js +268 -0
  374. package/dist/snapping/providers/guide.d.ts +69 -0
  375. package/dist/snapping/providers/guide.js +187 -0
  376. package/dist/snapping/providers/intersection.d.ts +1 -0
  377. package/dist/snapping/providers/intersection.js +92 -0
  378. package/dist/snapping/providers/shared.d.ts +39 -0
  379. package/dist/snapping/providers/shared.js +146 -0
  380. package/dist/snapping/providers/store.d.ts +1 -0
  381. package/dist/snapping/providers/store.js +132 -0
  382. package/dist/snapping/service.d.ts +1 -0
  383. package/dist/snapping/service.js +272 -0
  384. package/dist/snapping/types.d.ts +267 -0
  385. package/dist/snapping/types.js +66 -0
  386. package/dist/store/change-merger.d.ts +1 -0
  387. package/dist/store/change-merger.js +102 -0
  388. package/dist/store/draw-store.d.ts +1 -0
  389. package/dist/store/draw-store.js +396 -0
  390. package/dist/store/event-bridge.d.ts +1 -0
  391. package/dist/store/event-bridge.js +161 -0
  392. package/dist/store/index.d.ts +12 -0
  393. package/dist/store/index.js +4 -0
  394. package/dist/store/local-visibility.d.ts +21 -0
  395. package/dist/store/local-visibility.js +27 -0
  396. package/dist/store/lock.d.ts +67 -0
  397. package/dist/store/lock.js +54 -0
  398. package/dist/store/memory/change-bus.d.ts +60 -0
  399. package/dist/store/memory/change-bus.js +232 -0
  400. package/dist/store/memory/file-store.d.ts +15 -0
  401. package/dist/store/memory/file-store.js +33 -0
  402. package/dist/store/memory/frozen.d.ts +21 -0
  403. package/dist/store/memory/frozen.js +51 -0
  404. package/dist/store/memory/ui-state.d.ts +51 -0
  405. package/dist/store/memory/ui-state.js +223 -0
  406. package/dist/store/memory.d.ts +26 -0
  407. package/dist/store/memory.js +708 -0
  408. package/dist/store/spatial/index.d.ts +6 -0
  409. package/dist/store/spatial/index.js +4 -0
  410. package/dist/store/spatial/spatial-index.d.ts +90 -0
  411. package/dist/store/spatial/spatial-index.js +148 -0
  412. package/dist/store/spatial/store-spatial-index.d.ts +60 -0
  413. package/dist/store/spatial/store-spatial-index.js +125 -0
  414. package/dist/store/store.d.ts +417 -0
  415. package/dist/store/store.js +3 -0
  416. package/dist/store/types.d.ts +8 -0
  417. package/dist/store/types.js +3 -0
  418. package/dist/store/writable-layer.d.ts +35 -0
  419. package/dist/store/writable-layer.js +20 -0
  420. package/dist/view/cache/buffer.d.ts +28 -0
  421. package/dist/view/cache/buffer.js +176 -0
  422. package/dist/view/cache/earcut.d.ts +1 -0
  423. package/dist/view/cache/earcut.js +122 -0
  424. package/dist/view/cache/style-rule.d.ts +1 -0
  425. package/dist/view/cache/style-rule.js +97 -0
  426. package/dist/view/cache/terrain-fill.d.ts +30 -0
  427. package/dist/view/cache/terrain-fill.js +60 -0
  428. package/dist/view/cache/texture.d.ts +14 -0
  429. package/dist/view/cache/texture.js +292 -0
  430. package/dist/view/coordinator.d.ts +27 -0
  431. package/dist/view/coordinator.js +72 -0
  432. package/dist/view/feature-companion.d.ts +173 -0
  433. package/dist/view/feature-companion.js +108 -0
  434. package/dist/view/globe-subdivision.d.ts +78 -0
  435. package/dist/view/globe-subdivision.js +128 -0
  436. package/dist/view/index.d.ts +47 -0
  437. package/dist/view/index.js +20 -0
  438. package/dist/view/layer/attach.d.ts +20 -0
  439. package/dist/view/layer/attach.js +47 -0
  440. package/dist/view/layer/blend.d.ts +57 -0
  441. package/dist/view/layer/blend.js +14 -0
  442. package/dist/view/layer/custom-layer.d.ts +1 -0
  443. package/dist/view/layer/custom-layer.js +509 -0
  444. package/dist/view/layer/depth-state.d.ts +14 -0
  445. package/dist/view/layer/depth-state.js +44 -0
  446. package/dist/view/layer/display-list.d.ts +1 -0
  447. package/dist/view/layer/display-list.js +111 -0
  448. package/dist/view/layer/drape-planner.d.ts +139 -0
  449. package/dist/view/layer/drape-planner.js +726 -0
  450. package/dist/view/layer/frame-render.d.ts +57 -0
  451. package/dist/view/layer/frame-render.js +209 -0
  452. package/dist/view/layer/frame-state.d.ts +147 -0
  453. package/dist/view/layer/frame-state.js +484 -0
  454. package/dist/view/layer/gl-state.d.ts +77 -0
  455. package/dist/view/layer/gl-state.js +132 -0
  456. package/dist/view/layer/index.d.ts +6 -0
  457. package/dist/view/layer/index.js +5 -0
  458. package/dist/view/layer/render-scope.d.ts +30 -0
  459. package/dist/view/layer/render-scope.js +28 -0
  460. package/dist/view/layer/render.d.ts +87 -0
  461. package/dist/view/layer/render.js +187 -0
  462. package/dist/view/layer/renderers.d.ts +81 -0
  463. package/dist/view/layer/renderers.js +142 -0
  464. package/dist/view/layer/slot-manager.d.ts +26 -0
  465. package/dist/view/layer/slot-manager.js +133 -0
  466. package/dist/view/layer/slots.d.ts +33 -0
  467. package/dist/view/layer/slots.js +50 -0
  468. package/dist/view/layer/store-retained-bbox.d.ts +36 -0
  469. package/dist/view/layer/store-retained-bbox.js +188 -0
  470. package/dist/view/layer/store-retained-chunk.d.ts +97 -0
  471. package/dist/view/layer/store-retained-chunk.js +94 -0
  472. package/dist/view/layer/store-retained-classify.d.ts +34 -0
  473. package/dist/view/layer/store-retained-classify.js +88 -0
  474. package/dist/view/layer/store-retained-collect.d.ts +24 -0
  475. package/dist/view/layer/store-retained-collect.js +121 -0
  476. package/dist/view/layer/store-retained-coord-patch.d.ts +119 -0
  477. package/dist/view/layer/store-retained-coord-patch.js +168 -0
  478. package/dist/view/layer/store-retained-immediate.d.ts +63 -0
  479. package/dist/view/layer/store-retained-immediate.js +49 -0
  480. package/dist/view/layer/store-retained-invalidation.d.ts +96 -0
  481. package/dist/view/layer/store-retained-invalidation.js +192 -0
  482. package/dist/view/layer/store-retained.d.ts +198 -0
  483. package/dist/view/layer/store-retained.js +430 -0
  484. package/dist/view/layer/terrain-resolver.d.ts +1 -0
  485. package/dist/view/layer/terrain-resolver.js +174 -0
  486. package/dist/view/renderers/batch-manager.d.ts +61 -0
  487. package/dist/view/renderers/batch-manager.js +718 -0
  488. package/dist/view/renderers/draw-factors.d.ts +60 -0
  489. package/dist/view/renderers/draw-factors.js +35 -0
  490. package/dist/view/renderers/drawer.d.ts +1 -0
  491. package/dist/view/renderers/drawer.js +346 -0
  492. package/dist/view/renderers/image.d.ts +1 -0
  493. package/dist/view/renderers/image.js +255 -0
  494. package/dist/view/renderers/line/dash.d.ts +31 -0
  495. package/dist/view/renderers/line/dash.js +152 -0
  496. package/dist/view/renderers/line/line-geometry.d.ts +39 -0
  497. package/dist/view/renderers/line/line-geometry.js +460 -0
  498. package/dist/view/renderers/line/line-gl.d.ts +1 -0
  499. package/dist/view/renderers/line/line-gl.js +236 -0
  500. package/dist/view/renderers/line/line-shader.d.ts +1 -0
  501. package/dist/view/renderers/line/line-shader.js +364 -0
  502. package/dist/view/renderers/line/line-types.d.ts +43 -0
  503. package/dist/view/renderers/line/line-types.js +3 -0
  504. package/dist/view/renderers/line/line-uniforms.d.ts +1 -0
  505. package/dist/view/renderers/line/line-uniforms.js +390 -0
  506. package/dist/view/renderers/line/sdf-line.d.ts +92 -0
  507. package/dist/view/renderers/line/sdf-line.js +567 -0
  508. package/dist/view/renderers/point/billboard-depth.d.ts +10 -0
  509. package/dist/view/renderers/point/billboard-depth.js +56 -0
  510. package/dist/view/renderers/point/point-instance.d.ts +124 -0
  511. package/dist/view/renderers/point/point-instance.js +738 -0
  512. package/dist/view/renderers/point/point-sdf.d.ts +58 -0
  513. package/dist/view/renderers/point/point-sdf.js +170 -0
  514. package/dist/view/renderers/point/point-shape.d.ts +99 -0
  515. package/dist/view/renderers/point/point-shape.js +504 -0
  516. package/dist/view/renderers/point/point-style.d.ts +1 -0
  517. package/dist/view/renderers/point/point-style.js +46 -0
  518. package/dist/view/renderers/polygon/batch.d.ts +26 -0
  519. package/dist/view/renderers/polygon/batch.js +336 -0
  520. package/dist/view/renderers/polygon/earcut-input.d.ts +37 -0
  521. package/dist/view/renderers/polygon/earcut-input.js +55 -0
  522. package/dist/view/renderers/polygon/earcut-sliced.d.ts +69 -0
  523. package/dist/view/renderers/polygon/earcut-sliced.js +960 -0
  524. package/dist/view/renderers/polygon/fill.d.ts +74 -0
  525. package/dist/view/renderers/polygon/fill.js +251 -0
  526. package/dist/view/renderers/polygon/sdf-polygon.d.ts +62 -0
  527. package/dist/view/renderers/polygon/sdf-polygon.js +919 -0
  528. package/dist/view/renderers/polygon/terrain-cull.d.ts +3 -0
  529. package/dist/view/renderers/polygon/terrain-cull.js +14 -0
  530. package/dist/view/renderers/polygon/triangulator.d.ts +41 -0
  531. package/dist/view/renderers/polygon/triangulator.js +3 -0
  532. package/dist/view/renderers/retained.d.ts +43 -0
  533. package/dist/view/renderers/retained.js +3 -0
  534. package/dist/view/renderers/stroke.d.ts +121 -0
  535. package/dist/view/renderers/stroke.js +621 -0
  536. package/dist/view/shaders/frame.d.ts +8 -0
  537. package/dist/view/shaders/frame.js +37 -0
  538. package/dist/view/shaders/helpers.d.ts +238 -0
  539. package/dist/view/shaders/helpers.js +611 -0
  540. package/dist/view/shaders/initializer.d.ts +27 -0
  541. package/dist/view/shaders/initializer.js +125 -0
  542. package/dist/view/shaders/projection.d.ts +123 -0
  543. package/dist/view/shaders/projection.js +299 -0
  544. package/dist/view/shaders/quad-grid.d.ts +77 -0
  545. package/dist/view/shaders/quad-grid.js +128 -0
  546. package/dist/view/shaders/quad.d.ts +189 -0
  547. package/dist/view/shaders/quad.js +582 -0
  548. package/dist/view/shaders/retained-origin.d.ts +50 -0
  549. package/dist/view/shaders/retained-origin.js +67 -0
  550. package/dist/view/shaders/terrain-shade.d.ts +23 -0
  551. package/dist/view/shaders/terrain-shade.js +93 -0
  552. package/dist/view/style-rule.d.ts +166 -0
  553. package/dist/view/style-rule.js +300 -0
  554. package/dist/view/terrain/anchor.d.ts +135 -0
  555. package/dist/view/terrain/anchor.js +226 -0
  556. package/dist/view/terrain/context.d.ts +132 -0
  557. package/dist/view/terrain/context.js +437 -0
  558. package/dist/view/terrain/dem-atlas.d.ts +97 -0
  559. package/dist/view/terrain/dem-atlas.js +534 -0
  560. package/dist/view/terrain/detect.d.ts +126 -0
  561. package/dist/view/terrain/detect.js +198 -0
  562. package/dist/view/terrain/drape/bin-store.d.ts +179 -0
  563. package/dist/view/terrain/drape/bin-store.js +529 -0
  564. package/dist/view/terrain/drape/binning.d.ts +259 -0
  565. package/dist/view/terrain/drape/binning.js +604 -0
  566. package/dist/view/terrain/drape/edge-constrain.d.ts +37 -0
  567. package/dist/view/terrain/drape/edge-constrain.js +175 -0
  568. package/dist/view/terrain/drape/geometry.d.ts +95 -0
  569. package/dist/view/terrain/drape/geometry.js +260 -0
  570. package/dist/view/terrain/drape/mesh.d.ts +50 -0
  571. package/dist/view/terrain/drape/mesh.js +86 -0
  572. package/dist/view/terrain/drape/pass.d.ts +122 -0
  573. package/dist/view/terrain/drape/pass.js +379 -0
  574. package/dist/view/terrain/drape/quad-glyphs.d.ts +64 -0
  575. package/dist/view/terrain/drape/quad-glyphs.js +117 -0
  576. package/dist/view/terrain/drape/quad.d.ts +249 -0
  577. package/dist/view/terrain/drape/quad.js +835 -0
  578. package/dist/view/terrain/drape/renderer.d.ts +184 -0
  579. package/dist/view/terrain/drape/renderer.js +706 -0
  580. package/dist/view/terrain/drape/shared.d.ts +80 -0
  581. package/dist/view/terrain/drape/shared.js +173 -0
  582. package/dist/view/terrain/drape/stitch.d.ts +155 -0
  583. package/dist/view/terrain/drape/stitch.js +228 -0
  584. package/dist/view/terrain/ground.d.ts +72 -0
  585. package/dist/view/terrain/ground.js +151 -0
  586. package/dist/view/terrain/metrics.d.ts +180 -0
  587. package/dist/view/terrain/metrics.js +231 -0
  588. package/dist/view/terrain/occlusion.d.ts +11 -0
  589. package/dist/view/terrain/occlusion.js +129 -0
  590. package/dist/view/terrain/polygon.d.ts +86 -0
  591. package/dist/view/terrain/polygon.js +301 -0
  592. package/dist/view/terrain/shade.d.ts +48 -0
  593. package/dist/view/terrain/shade.js +45 -0
  594. package/dist/view/terrain/state.d.ts +99 -0
  595. package/dist/view/terrain/state.js +186 -0
  596. package/dist/view/terrain/tessellation.d.ts +265 -0
  597. package/dist/view/terrain/tessellation.js +924 -0
  598. package/dist/view/terrain/tiling.d.ts +56 -0
  599. package/dist/view/terrain/tiling.js +155 -0
  600. package/dist/view/terrain/upstream-terrain.d.ts +82 -0
  601. package/dist/view/terrain/upstream-terrain.js +116 -0
  602. package/dist/view/ui/auxiliary-handles.d.ts +151 -0
  603. package/dist/view/ui/auxiliary-handles.js +22 -0
  604. package/dist/view/ui/bounds.d.ts +53 -0
  605. package/dist/view/ui/bounds.js +149 -0
  606. package/dist/view/ui/box-selection.d.ts +1 -0
  607. package/dist/view/ui/box-selection.js +83 -0
  608. package/dist/view/ui/handle-test.d.ts +1 -0
  609. package/dist/view/ui/handle-test.js +437 -0
  610. package/dist/view/ui/handle-thinning.d.ts +122 -0
  611. package/dist/view/ui/handle-thinning.js +430 -0
  612. package/dist/view/ui/handles.d.ts +25 -0
  613. package/dist/view/ui/handles.js +673 -0
  614. package/dist/view/ui/helper.d.ts +19 -0
  615. package/dist/view/ui/helper.js +76 -0
  616. package/dist/view/ui/index.d.ts +15 -0
  617. package/dist/view/ui/index.js +15 -0
  618. package/dist/view/ui/selection-scope.d.ts +25 -0
  619. package/dist/view/ui/selection-scope.js +34 -0
  620. package/dist/view/ui/selection-ui/bounding-box.d.ts +44 -0
  621. package/dist/view/ui/selection-ui/bounding-box.js +240 -0
  622. package/dist/view/ui/selection-ui/extension-registry.d.ts +76 -0
  623. package/dist/view/ui/selection-ui/extension-registry.js +78 -0
  624. package/dist/view/ui/selection-ui/index.d.ts +12 -0
  625. package/dist/view/ui/selection-ui/index.js +12 -0
  626. package/dist/view/ui/selection-ui/renderer.d.ts +29 -0
  627. package/dist/view/ui/selection-ui/renderer.js +227 -0
  628. package/dist/view/ui/selection-ui/types.d.ts +55 -0
  629. package/dist/view/ui/selection-ui/types.js +3 -0
  630. package/dist/view/ui/selection-ui-drawer.d.ts +52 -0
  631. package/dist/view/ui/selection-ui-drawer.js +329 -0
  632. package/dist/view/ui/tentative.d.ts +1 -0
  633. package/dist/view/ui/tentative.js +320 -0
  634. package/dist/view/viewport.d.ts +119 -0
  635. package/dist/view/viewport.js +254 -0
  636. package/package.json +113 -0
@@ -0,0 +1,129 @@
1
+ // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * Deciding whether a symbol is occluded by the terrain (whether to ghost it)
5
+ *
6
+ * Points, icons and billboard labels are drawn without a depth test. A billboard's front/back
7
+ * order is decided by the depth of its single center point, so enabling depth makes the whole
8
+ * thing disappear as soon as it sinks a few meters into the ground (confirmed by measurement).
9
+ * On the other hand, a symbol behind a mountain stays clearly visible, which is misread as
10
+ * "being in front". So what is occluded is drawn faintly (a CesiumJS-style ghost).
11
+ *
12
+ * The test runs on the CPU. The segment drawn from the camera to the anchor is sampled, and if
13
+ * the ground elevation along the way rises above the segment it is occluded. Fetching a single
14
+ * elevation takes about 0.4us, so 24 samples along the segment cost about 10us per anchor,
15
+ * which is enough. Solving it on the GPU would mean ray marching in the fragment shader, whose
16
+ * cost per symbol is far larger.
17
+ *
18
+ * Reading the depth buffer (MapLibre's `terrain.depthAtPoint`) is not an option: `readPixels`
19
+ * runs for every single point, which inserts a synchronous wait and stalls rendering once per
20
+ * symbol.
21
+ */
22
+ import { drawnLongitude } from './anchor.js';
23
+ import { groundElevationMeters } from './ground.js';
24
+ import { mercatorX, mercatorY } from './tessellation.js';
25
+ /**
26
+ * Opacity of an occluded symbol
27
+ *
28
+ * @internal
29
+ */
30
+ export const TERRAIN_GHOST_OPACITY = 0.35;
31
+ /** Upper bound on the number of samples along the segment */
32
+ const MAX_SAMPLES = 24;
33
+ /** Lower bound on the number of samples along the segment */
34
+ const MIN_SAMPLES = 6;
35
+ /**
36
+ * Margin discarded on the camera side
37
+ *
38
+ * The ground directly below the camera almost always rises above the segment (the camera is
39
+ * above the ground, but the line of sight points downward, so it grazes the ground just past
40
+ * the starting point). Looking there would make everything occluded, so the first few percent
41
+ * on the start side are skipped.
42
+ */
43
+ const NEAR_SKIP = 0.08;
44
+ /**
45
+ * Margin discarded on the anchor side (counted in terrain mesh nodes)
46
+ *
47
+ * The anchor sits on top of the ground, so the ground just in front of it is necessarily at
48
+ * the same height. To keep it from hiding itself, two nodes' worth is skipped.
49
+ */
50
+ const SELF_SKIP_NODES = 2;
51
+ /**
52
+ * Converts a Mercator y back into a latitude
53
+ */
54
+ function inverseMercatorY(y) {
55
+ return (Math.atan(Math.sinh(Math.PI * (1 - 2 * y))) * 180) / Math.PI;
56
+ }
57
+ /**
58
+ * Whether an anchor is occluded by the terrain
59
+ *
60
+ * Always false (not occluded) when the terrain is disabled or the camera position cannot be
61
+ * obtained. This matches the appearance before the terrain was introduced exactly.
62
+ *
63
+ * @internal
64
+ */
65
+ export function isAnchorOccluded(context, lng, lat) {
66
+ const frame = context.anchorFrame;
67
+ const terrain = frame.terrain;
68
+ const camera = frame.cameraMercator;
69
+ if (!terrain || !camera)
70
+ return false;
71
+ const scale = frame.elevationScale;
72
+ if (!(scale > 0))
73
+ return false;
74
+ const cached = context.occlusionCache.get(`${lng},${lat}`);
75
+ if (cached !== undefined)
76
+ return cached;
77
+ const result = computeOccluded(lng, lat, scale, camera, terrain, context);
78
+ context.occlusionCache.set(`${lng},${lat}`, result);
79
+ return result;
80
+ }
81
+ /**
82
+ * Returns the opacity for a symbol at a point: 0.35 when the terrain hides it from the camera,
83
+ * 1 otherwise.
84
+ *
85
+ * @param context The terrain state of the draw instance
86
+ * @param lng The longitude in degrees
87
+ * @param lat The latitude in degrees
88
+ * @returns 0.35 or 1. Always 1 when the terrain is disabled
89
+ */
90
+ export function anchorGhostOpacity(context, lng, lat) {
91
+ return isAnchorOccluded(context, lng, lat) ? TERRAIN_GHOST_OPACITY : 1;
92
+ }
93
+ function computeOccluded(lng, lat, scale, camera, terrain, context) {
94
+ const frame = context.anchorFrame;
95
+ // The elevation of the ground maplibre draws (ground.ts), on the copy of the world the
96
+ // anchor is drawn on
97
+ const elevationAt = (sampleLng, sampleLat) => groundElevationMeters(frame.elevationQuery, terrain, context.coverage, drawnLongitude(context, sampleLng), sampleLat, frame.tileZoom);
98
+ const ax = mercatorX(lng);
99
+ const ay = mercatorY(lat);
100
+ const az = elevationAt(lng, lat) * scale;
101
+ const [cx, cy, cz] = camera;
102
+ const dx = ax - cx;
103
+ const dy = ay - cy;
104
+ const dz = az - cz;
105
+ const horizontal = Math.hypot(dx, dy);
106
+ if (!(horizontal > 0))
107
+ return false;
108
+ // The sample spacing matches the node spacing of the terrain mesh (sampling any finer only
109
+ // goes beyond the resolution of the bilinear interpolation and adds no information)
110
+ const node = context.renderState.stepGrid > 0 ? context.renderState.stepGrid : horizontal / 16;
111
+ const samples = Math.min(MAX_SAMPLES, Math.max(MIN_SAMPLES, Math.ceil(horizontal / node)));
112
+ // The ground just in front of the anchor is the anchor's own ground, so it is skipped
113
+ const selfSkip = Math.min(0.5, (SELF_SKIP_NODES * node) / horizontal);
114
+ const tEnd = 1 - selfSkip;
115
+ if (!(tEnd > NEAR_SKIP))
116
+ return false;
117
+ for (let i = 0; i < samples; i++) {
118
+ const t = NEAR_SKIP + ((tEnd - NEAR_SKIP) * (i + 0.5)) / samples;
119
+ const px = cx + dx * t;
120
+ const py = cy + dy * t;
121
+ const pz = cz + dz * t;
122
+ const sampleLng = px * 360 - 180;
123
+ const sampleLat = inverseMercatorY(py);
124
+ const surface = elevationAt(sampleLng, sampleLat) * scale;
125
+ if (surface > pz)
126
+ return true;
127
+ }
128
+ return false;
129
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The injection point for terrain subdivision of polygons
3
+ *
4
+ * Called from the polygon renderers (polygon/sdf-polygon.ts and polygon/batch.ts). When the
5
+ * terrain is disabled, `getTerrainTessellationStep(context)` returns null and the caller does
6
+ * nothing. Rendering without terrain therefore does not change by a single byte.
7
+ */
8
+ import type { Coordinate } from '../../store/types.js';
9
+ import type { TerrainContext } from './context.js';
10
+ import { type MercatorRect, type TessellationStep } from './tessellation.js';
11
+ /**
12
+ * Returns the subdivision step of the terrain mesh for the current frame.
13
+ *
14
+ * @param context The terrain state of the draw instance
15
+ * @returns The step, or `null` when the terrain is disabled
16
+ */
17
+ export declare function getTerrainTessellationStep(context: TerrainContext): TessellationStep | null;
18
+ /**
19
+ * Decides the effective step for a single feature
20
+ *
21
+ * The step is decided by the screen (the zoom), but for a large feature the grid can reach
22
+ * hundreds of thousands of cells. Cutting off once the upper bound is reached produces the
23
+ * distorted result "only the first triangles are fine and the rest stay coarse", and only part
24
+ * of the polygon sits on the terrain. So instead of cutting off, the step is coarsened by a
25
+ * power of 2 and the whole feature is subdivided uniformly. It is a power of 2 so that the
26
+ * coarse grid is a subset of the fine grid (the fill and the outline are subdivided at the
27
+ * same points).
28
+ */
29
+ export declare function polygonTessellationStep(base: TessellationStep, flatCoords: readonly number[]): TessellationStep;
30
+ /**
31
+ * The number of grid cells the bounding box covers (an estimate, from a flat coordinate array)
32
+ *
33
+ * Outside the range (region) nothing is subdivided, so that part is not counted.
34
+ */
35
+ export declare function boundingCells(flatCoords: readonly number[], grid: number, region?: MercatorRect | null): number;
36
+ /**
37
+ * The number of grid cells the bounding box covers (an estimate, from rings)
38
+ *
39
+ * Every feature is scanned in order to estimate the total amount of the batch, so the count is
40
+ * made without building an array for flattening.
41
+ */
42
+ export declare function ringBoundingCells(ring: readonly Coordinate[], grid: number, region?: MercatorRect | null): number;
43
+ /**
44
+ * Whether the bounding box of a flat coordinate array intersects the range
45
+ */
46
+ export declare function flatCoordsIntersect(flatCoords: readonly number[], region: MercatorRect): boolean;
47
+ /**
48
+ * Whether the bounding box of an array of rings intersects the range
49
+ */
50
+ export declare function ringsIntersect(rings: readonly Coordinate[][], region: MercatorRect): boolean;
51
+ /**
52
+ * Decides the coarsening factor applied to the whole batch (a power of 2)
53
+ *
54
+ * A per-feature upper bound cannot hold back a batch with thousands of features (a
55
+ * dataset). The total number of cells is estimated before construction, and if
56
+ * it exceeds the budget the whole batch is coarsened uniformly. Applying a different factor
57
+ * per feature would put neighboring features on different grids and make them disagree at the
58
+ * boundary, so there is one factor per batch.
59
+ *
60
+ * @param totalCells The sum of the bounding box cell counts of all features
61
+ */
62
+ export declare function batchTessellationFactor(totalCells: number): number;
63
+ /**
64
+ * Subdivides the fill of a single feature and returns the step actually used
65
+ *
66
+ * When the step was too fine to finish subdividing (the vertex budget ran out, or a single
67
+ * triangle sweeps too many cells), emitting it as is produces a mixture where "part of it
68
+ * follows the terrain while the rest are flat triangles breaking through the terrain". This is
69
+ * what is behind the wedge-shaped breakage sticking out of the terrain, so it is coarsened and
70
+ * subdivided again. Subdividing the outline with the returned step as well guarantees that the
71
+ * fill and the outline lie on the same grid.
72
+ *
73
+ * @returns The subdivision result and the step that produced it
74
+ */
75
+ export declare function tessellatePolygonFill(context: TerrainContext, featureId: string | undefined, partIndex: number, flatCoords: number[], indices: number[], base: TessellationStep): {
76
+ flatCoords: number[];
77
+ indices: number[];
78
+ step: TessellationStep;
79
+ };
80
+ /**
81
+ * Subdivides the rings of the outline
82
+ *
83
+ * It uses the same grid as the fill, so the edge of the fill and the vertices of the outline
84
+ * still agree after subdivision.
85
+ */
86
+ export declare function tessellateRings(rings: Coordinate[][], step: TessellationStep): Coordinate[][];
@@ -0,0 +1,301 @@
1
+ // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ import { TERRAIN_MAX_BATCH_SUBDIVISION_CELLS, TERRAIN_MAX_COARSEN_STEPS, TERRAIN_MAX_SUBDIVISION_POINTS, TERRAIN_MAX_TILED_SUBDIVISION_POINTS, } from './metrics.js';
4
+ import { getTerrainRenderState } from './state.js';
5
+ import { cellsInRegion, densifyRings, mercatorX, mercatorY, rectsIntersect, subdivideTriangles, } from './tessellation.js';
6
+ import { tilingSignature } from './tiling.js';
7
+ /**
8
+ * Returns the subdivision step of the terrain mesh for the current frame.
9
+ *
10
+ * @param context The terrain state of the draw instance
11
+ * @returns The step, or `null` when the terrain is disabled
12
+ */
13
+ export function getTerrainTessellationStep(context) {
14
+ const terrain = getTerrainRenderState(context);
15
+ if (!terrain.active || !(terrain.stepGrid > 0))
16
+ return null;
17
+ const tiling = terrain.tessellationTiling;
18
+ return {
19
+ grid: terrain.stepGrid,
20
+ // When subdividing to match the tile's actual mesh, the amount is capped by the view, so
21
+ // the upper bound is set high (falling back to coarsening midway makes the fill drop out
22
+ // on ridges)
23
+ maxPoints: tiling ? TERRAIN_MAX_TILED_SUBDIVISION_POINTS : TERRAIN_MAX_SUBDIVISION_POINTS,
24
+ region: terrain.tessellationRegion,
25
+ tiling,
26
+ };
27
+ }
28
+ /**
29
+ * Decides the effective step for a single feature
30
+ *
31
+ * The step is decided by the screen (the zoom), but for a large feature the grid can reach
32
+ * hundreds of thousands of cells. Cutting off once the upper bound is reached produces the
33
+ * distorted result "only the first triangles are fine and the rest stay coarse", and only part
34
+ * of the polygon sits on the terrain. So instead of cutting off, the step is coarsened by a
35
+ * power of 2 and the whole feature is subdivided uniformly. It is a power of 2 so that the
36
+ * coarse grid is a subset of the fine grid (the fill and the outline are subdivided at the
37
+ * same points).
38
+ */
39
+ export function polygonTessellationStep(base, flatCoords) {
40
+ // When subdividing to match the tile's actual mesh, no coarsening is applied. Coarsening
41
+ // would make the step coarser than the tile's mesh, and our own chord would dive below the
42
+ // ridge and be carved away. The amount is capped by the number of tiles, so no brake is
43
+ // needed in the first place.
44
+ if (base.tiling)
45
+ return base;
46
+ const cells = boundingCells(flatCoords, base.grid, base.region);
47
+ if (!(cells > base.maxPoints))
48
+ return base;
49
+ // Coarsened by a power of 2 (the coarse grid still lies on a subset of the terrain mesh
50
+ // nodes)
51
+ const factor = 2 ** Math.ceil(Math.log2(Math.sqrt(cells / base.maxPoints)));
52
+ return coarsen(base, factor);
53
+ }
54
+ /**
55
+ * The number of grid cells the bounding box covers (an estimate, from a flat coordinate array)
56
+ *
57
+ * Outside the range (region) nothing is subdivided, so that part is not counted.
58
+ */
59
+ export function boundingCells(flatCoords, grid, region) {
60
+ if (flatCoords.length < 2 || !(grid > 0))
61
+ return 0;
62
+ let minX = Number.POSITIVE_INFINITY;
63
+ let maxX = Number.NEGATIVE_INFINITY;
64
+ let minY = Number.POSITIVE_INFINITY;
65
+ let maxY = Number.NEGATIVE_INFINITY;
66
+ for (let i = 0; i < flatCoords.length; i += 2) {
67
+ const x = flatCoords[i];
68
+ const y = flatCoords[i + 1];
69
+ if (x < minX)
70
+ minX = x;
71
+ if (x > maxX)
72
+ maxX = x;
73
+ if (y < minY)
74
+ minY = y;
75
+ if (y > maxY)
76
+ maxY = y;
77
+ }
78
+ return cellsFromBounds(minX, maxX, minY, maxY, grid, region);
79
+ }
80
+ /**
81
+ * The number of grid cells the bounding box covers (an estimate, from rings)
82
+ *
83
+ * Every feature is scanned in order to estimate the total amount of the batch, so the count is
84
+ * made without building an array for flattening.
85
+ */
86
+ export function ringBoundingCells(ring, grid, region) {
87
+ if (ring.length === 0 || !(grid > 0))
88
+ return 0;
89
+ let minX = Number.POSITIVE_INFINITY;
90
+ let maxX = Number.NEGATIVE_INFINITY;
91
+ let minY = Number.POSITIVE_INFINITY;
92
+ let maxY = Number.NEGATIVE_INFINITY;
93
+ for (const [x, y] of ring) {
94
+ if (x < minX)
95
+ minX = x;
96
+ if (x > maxX)
97
+ maxX = x;
98
+ if (y < minY)
99
+ minY = y;
100
+ if (y > maxY)
101
+ maxY = y;
102
+ }
103
+ return cellsFromBounds(minX, maxX, minY, maxY, grid, region);
104
+ }
105
+ /**
106
+ * The fingerprint of the conditions that decide this feature's subdivision
107
+ *
108
+ * It is decided by the tile configuration covering it (which cell has which step), the
109
+ * coarsening factor and the relationship with the range. The elevation is not included,
110
+ * because the shader looks the elevation up every frame, so there is no need to subdivide
111
+ * again when the DEM arrives.
112
+ */
113
+ function fillSignature(step, flatCoords) {
114
+ if (flatCoords.length < 2)
115
+ return 'empty';
116
+ let minLng = Number.POSITIVE_INFINITY;
117
+ let maxLng = Number.NEGATIVE_INFINITY;
118
+ let minLat = Number.POSITIVE_INFINITY;
119
+ let maxLat = Number.NEGATIVE_INFINITY;
120
+ for (let i = 0; i < flatCoords.length; i += 2) {
121
+ const lng = flatCoords[i];
122
+ const lat = flatCoords[i + 1];
123
+ if (lng < minLng)
124
+ minLng = lng;
125
+ if (lng > maxLng)
126
+ maxLng = lng;
127
+ if (lat < minLat)
128
+ minLat = lat;
129
+ if (lat > maxLat)
130
+ maxLat = lat;
131
+ }
132
+ return tilingSignature(step.tiling ?? null, step.region ?? null, step.coarsen && step.coarsen > 1 ? step.coarsen : 1, step.grid, mercatorX(minLng),
133
+ // Mercator y decreases as the latitude increases
134
+ mercatorY(maxLat), mercatorX(maxLng), mercatorY(minLat));
135
+ }
136
+ /**
137
+ * Whether the bounding box of a flat coordinate array intersects the range
138
+ */
139
+ export function flatCoordsIntersect(flatCoords, region) {
140
+ if (flatCoords.length < 2)
141
+ return false;
142
+ let minLng = Number.POSITIVE_INFINITY;
143
+ let maxLng = Number.NEGATIVE_INFINITY;
144
+ let minLat = Number.POSITIVE_INFINITY;
145
+ let maxLat = Number.NEGATIVE_INFINITY;
146
+ for (let i = 0; i < flatCoords.length; i += 2) {
147
+ const lng = flatCoords[i];
148
+ const lat = flatCoords[i + 1];
149
+ if (lng < minLng)
150
+ minLng = lng;
151
+ if (lng > maxLng)
152
+ maxLng = lng;
153
+ if (lat < minLat)
154
+ minLat = lat;
155
+ if (lat > maxLat)
156
+ maxLat = lat;
157
+ }
158
+ // Mercator y decreases as the latitude increases
159
+ return rectsIntersect(mercatorX(minLng), mercatorY(maxLat), mercatorX(maxLng), mercatorY(minLat), region);
160
+ }
161
+ /**
162
+ * Whether the bounding box of an array of rings intersects the range
163
+ */
164
+ export function ringsIntersect(rings, region) {
165
+ let minLng = Number.POSITIVE_INFINITY;
166
+ let maxLng = Number.NEGATIVE_INFINITY;
167
+ let minLat = Number.POSITIVE_INFINITY;
168
+ let maxLat = Number.NEGATIVE_INFINITY;
169
+ for (const ring of rings) {
170
+ for (const [lng, lat] of ring) {
171
+ if (lng < minLng)
172
+ minLng = lng;
173
+ if (lng > maxLng)
174
+ maxLng = lng;
175
+ if (lat < minLat)
176
+ minLat = lat;
177
+ if (lat > maxLat)
178
+ maxLat = lat;
179
+ }
180
+ }
181
+ if (minLng > maxLng)
182
+ return false;
183
+ return rectsIntersect(mercatorX(minLng), mercatorY(maxLat), mercatorX(maxLng), mercatorY(minLat), region);
184
+ }
185
+ /**
186
+ * Converts a longitude/latitude bounding box into a number of Mercator cells (an estimate is
187
+ * enough)
188
+ */
189
+ function cellsFromBounds(minX, maxX, minY, maxY, grid, region) {
190
+ // Mercator y decreases as the latitude increases, so top and bottom are swapped
191
+ return cellsInRegion(mercatorX(minX), mercatorY(maxY), mercatorX(maxX), mercatorY(minY), grid, region);
192
+ }
193
+ /**
194
+ * Coarsens the step by a power of 2
195
+ */
196
+ function coarsen(step, factor) {
197
+ if (!(factor > 1))
198
+ return step;
199
+ if (step.tiling) {
200
+ // When matching the tile's actual mesh, the factor is raised rather than the step
201
+ // (being a power of 2, the subdivision points keep lying on a subset of the nodes)
202
+ return { ...step, coarsen: (step.coarsen ?? 1) * factor };
203
+ }
204
+ return { grid: step.grid * factor, maxPoints: step.maxPoints, region: step.region };
205
+ }
206
+ /**
207
+ * Decides the coarsening factor applied to the whole batch (a power of 2)
208
+ *
209
+ * A per-feature upper bound cannot hold back a batch with thousands of features (a
210
+ * dataset). The total number of cells is estimated before construction, and if
211
+ * it exceeds the budget the whole batch is coarsened uniformly. Applying a different factor
212
+ * per feature would put neighboring features on different grids and make them disagree at the
213
+ * boundary, so there is one factor per batch.
214
+ *
215
+ * @param totalCells The sum of the bounding box cell counts of all features
216
+ */
217
+ export function batchTessellationFactor(totalCells) {
218
+ if (!(totalCells > TERRAIN_MAX_BATCH_SUBDIVISION_CELLS))
219
+ return 1;
220
+ const steps = Math.ceil(Math.log2(Math.sqrt(totalCells / TERRAIN_MAX_BATCH_SUBDIVISION_CELLS)));
221
+ return 2 ** Math.min(steps, TERRAIN_MAX_COARSEN_STEPS);
222
+ }
223
+ /**
224
+ * Subdivides the fill of a single feature and returns the step actually used
225
+ *
226
+ * When the step was too fine to finish subdividing (the vertex budget ran out, or a single
227
+ * triangle sweeps too many cells), emitting it as is produces a mixture where "part of it
228
+ * follows the terrain while the rest are flat triangles breaking through the terrain". This is
229
+ * what is behind the wedge-shaped breakage sticking out of the terrain, so it is coarsened and
230
+ * subdivided again. Subdividing the outline with the returned step as well guarantees that the
231
+ * fill and the outline lie on the same grid.
232
+ *
233
+ * @returns The subdivision result and the step that produced it
234
+ */
235
+ export function tessellatePolygonFill(context, featureId, partIndex, flatCoords, indices, base) {
236
+ // Features outside the range are left alone. Since it is already decided that they will not
237
+ // be subdivided, even building the vertex pool (registering every coordinate into a Map) is
238
+ // expensive. With 8,172 administrative boundaries and 1.1 million vertices in total, this
239
+ // early exit decides most of the construction time (measured: 3.9 s -> 0.5 s).
240
+ if (base.region && !flatCoordsIntersect(flatCoords, base.region)) {
241
+ return { flatCoords, indices, step: base };
242
+ }
243
+ // The subdivision cache belongs to the draw instance whose context is passed. Back when it
244
+ // was shared globally, triangles subdivided with a different step were returned whenever
245
+ // the generation happened to coincide with another instance's.
246
+ const fillCache = context.fillCache;
247
+ // The fingerprint of the conditions that decide this feature's subdivision (the covering
248
+ // tile configuration, the coarsening and the relationship with the range). As long as the
249
+ // conditions are the same it can be reused even when the range moves or a chunk is re-baked
250
+ const signature = fillSignature(base, flatCoords);
251
+ if (featureId) {
252
+ const cached = fillCache.get(featureId, partIndex, signature, indices);
253
+ if (cached) {
254
+ return {
255
+ flatCoords: cached.flatCoords,
256
+ indices: cached.indices,
257
+ step: {
258
+ grid: cached.grid,
259
+ maxPoints: base.maxPoints,
260
+ region: base.region,
261
+ tiling: cached.grid === base.grid ? base.tiling : null,
262
+ },
263
+ };
264
+ }
265
+ }
266
+ let step = polygonTessellationStep(base, flatCoords);
267
+ let result = subdivideTriangles(flatCoords, indices, step);
268
+ let coarsened = 0;
269
+ while (result.overflowed && coarsened < TERRAIN_MAX_COARSEN_STEPS) {
270
+ // The required factor is derived from the amount of the overflow, rounded up to a power
271
+ // of 2 and applied in one go (trying factor 2 at a time would mean redoing it up to the
272
+ // upper bound every time for a huge feature)
273
+ const wanted = Math.max(2, 2 ** Math.ceil(Math.log2(result.overflowFactor)));
274
+ const remaining = 2 ** (TERRAIN_MAX_COARSEN_STEPS - coarsened);
275
+ const factor = Math.min(wanted, remaining);
276
+ coarsened += Math.round(Math.log2(factor));
277
+ step = coarsen(step, factor);
278
+ result = subdivideTriangles(flatCoords, indices, step);
279
+ }
280
+ if (featureId) {
281
+ fillCache.set(featureId, partIndex, signature, indices, result.flatCoords, result.indices, step.grid);
282
+ }
283
+ return { flatCoords: result.flatCoords, indices: result.indices, step };
284
+ }
285
+ /**
286
+ * Subdivides the rings of the outline
287
+ *
288
+ * It uses the same grid as the fill, so the edge of the fill and the vertices of the outline
289
+ * still agree after subdivision.
290
+ */
291
+ export function tessellateRings(rings, step) {
292
+ // Outside the range nothing is subdivided (the same test as the fill; if the two disagree
293
+ // they drift apart)
294
+ if (step.region && !ringsIntersect(rings, step.region))
295
+ return rings;
296
+ // The coarsening applied to the fill is applied to the outline too. Forgetting it would
297
+ // subdivide only the outline on the finest grid and make the number of points jump (both
298
+ // construction and rendering get heavier)
299
+ const coarsen = step.coarsen && step.coarsen > 1 ? step.coarsen : 1;
300
+ return densifyRings(rings, coarsen > 1 ? { ...step, grid: step.grid * coarsen } : step);
301
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Formula for terrain shading (an aid to reading the map)
3
+ *
4
+ * There are two paths that put a polygon fill onto the ground surface: analytic drape
5
+ * (filling as pixels of the ground surface, `drape/renderer.ts` and `drape/quad.ts`) and
6
+ * vertex displacement (the path in `shaders/helpers.ts` that lifts the vertices of a
7
+ * feature and fills them). So that both produce the same pixels, the formula that derives
8
+ * the brightness factor from the gradient is kept here in a single place, and only the way
9
+ * the samples are taken is adapted to each path. If each path had its own formula, the
10
+ * brightness of the fill would jump where the bands switch over.
11
+ *
12
+ * Shading does not change the hue; it is applied to the brightness only. It is not 3D
13
+ * lighting that illuminates symbols with an arbitrary light, it is also distinct from
14
+ * vertical exaggeration of the terrain (which follows the map's own factor), and it does not
15
+ * change the dimensions of the relief at all.
16
+ */
17
+ /**
18
+ * Light source for the shading
19
+ *
20
+ * It is a pair of a unit vector in the map coordinate system (east, north, up) and a
21
+ * strength.
22
+ */
23
+ export interface TerrainShadeLight {
24
+ /** Unit vector in the map coordinate system (east, north, up) */
25
+ readonly direction: readonly [number, number, number];
26
+ /** Strength of the shading (0 means no shading) */
27
+ readonly strength: number;
28
+ }
29
+ /**
30
+ * GLSL that derives the brightness factor from the gradient
31
+ *
32
+ * The caller must declare `u_light_dir` (map coordinate system, east / north / up) and
33
+ * `u_shade_strength`. The unit of the gradient is meters per meter (eastward and
34
+ * northward), and every path converts its samples to this unit before passing them in.
35
+ */
36
+ export declare const TERRAIN_SHADE_CORE_GLSL = "\nfloat terrainShadeFromGradient(float dzdEast, float dzdNorth) {\n if (u_shade_strength <= 0.0) return 1.0;\n vec3 normal = normalize(vec3(-dzdEast, -dzdNorth, 1.0));\n float lambert = dot(normal, u_light_dir);\n // The value on level ground (the normal pointing straight up). It is normalized to\n // 1.0 here, so no shading is applied on flat places (the name flat cannot be used\n // because it is a reserved word in GLSL)\n float level = max(u_light_dir.z, 1e-3);\n float factor = 1.0 + u_shade_strength * (lambert - level) / level;\n return clamp(factor, 1.0 - u_shade_strength, 1.0 + u_shade_strength * 0.5);\n}\n";
37
+ /**
38
+ * CPU mirror of `terrainShadeFromGradient`
39
+ *
40
+ * The GLSL is the authority for the implementation, but the formula itself is placed here
41
+ * as a pure function so that it can be verified (the same practice as `drapeShadeWindow`).
42
+ * Given the same samples, every path arrives at this value.
43
+ *
44
+ * @param dzdEast Eastward gradient (meters per meter)
45
+ * @param dzdNorth Northward gradient (meters per meter)
46
+ * @param light The light source
47
+ */
48
+ export declare function terrainShadeFactor(dzdEast: number, dzdNorth: number, light: TerrainShadeLight): number;
@@ -0,0 +1,45 @@
1
+ // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * GLSL that derives the brightness factor from the gradient
5
+ *
6
+ * The caller must declare `u_light_dir` (map coordinate system, east / north / up) and
7
+ * `u_shade_strength`. The unit of the gradient is meters per meter (eastward and
8
+ * northward), and every path converts its samples to this unit before passing them in.
9
+ */
10
+ export const TERRAIN_SHADE_CORE_GLSL = `
11
+ float terrainShadeFromGradient(float dzdEast, float dzdNorth) {
12
+ if (u_shade_strength <= 0.0) return 1.0;
13
+ vec3 normal = normalize(vec3(-dzdEast, -dzdNorth, 1.0));
14
+ float lambert = dot(normal, u_light_dir);
15
+ // The value on level ground (the normal pointing straight up). It is normalized to
16
+ // 1.0 here, so no shading is applied on flat places (the name flat cannot be used
17
+ // because it is a reserved word in GLSL)
18
+ float level = max(u_light_dir.z, 1e-3);
19
+ float factor = 1.0 + u_shade_strength * (lambert - level) / level;
20
+ return clamp(factor, 1.0 - u_shade_strength, 1.0 + u_shade_strength * 0.5);
21
+ }
22
+ `;
23
+ /**
24
+ * CPU mirror of `terrainShadeFromGradient`
25
+ *
26
+ * The GLSL is the authority for the implementation, but the formula itself is placed here
27
+ * as a pure function so that it can be verified (the same practice as `drapeShadeWindow`).
28
+ * Given the same samples, every path arrives at this value.
29
+ *
30
+ * @param dzdEast Eastward gradient (meters per meter)
31
+ * @param dzdNorth Northward gradient (meters per meter)
32
+ * @param light The light source
33
+ */
34
+ export function terrainShadeFactor(dzdEast, dzdNorth, light) {
35
+ const strength = light.strength;
36
+ if (strength <= 0)
37
+ return 1;
38
+ const length = Math.hypot(dzdEast, dzdNorth, 1);
39
+ const normal = [-dzdEast / length, -dzdNorth / length, 1 / length];
40
+ const dir = light.direction;
41
+ const lambert = normal[0] * dir[0] + normal[1] * dir[1] + normal[2] * dir[2];
42
+ const level = Math.max(dir[2], 1e-3);
43
+ const factor = 1 + (strength * (lambert - level)) / level;
44
+ return Math.min(Math.max(factor, 1 - strength), 1 + strength * 0.5);
45
+ }