@scoova/mgl 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 (565) hide show
  1. package/LICENSE.txt +116 -0
  2. package/README.md +174 -0
  3. package/build/banner.ts +12 -0
  4. package/build/bump-version-changelog.js +26 -0
  5. package/build/check-bundle-size.js +77 -0
  6. package/build/generate-dist-package.js +26 -0
  7. package/build/generate-doc-images.ts +78 -0
  8. package/build/generate-docs.ts +190 -0
  9. package/build/generate-shaders.ts +68 -0
  10. package/build/generate-struct-arrays.ts +438 -0
  11. package/build/generate-style-code.ts +283 -0
  12. package/build/readme.md +56 -0
  13. package/build/release-notes.js +45 -0
  14. package/build/rollup/bundle_prelude.js +29 -0
  15. package/build/rollup/maplibregl.js +22 -0
  16. package/build/rollup_plugins.ts +58 -0
  17. package/dist/LICENSE.txt +116 -0
  18. package/dist/maplibre-gl.css +1 -0
  19. package/dist/maplibre-gl.d.ts +13304 -0
  20. package/dist/maplibre-gl.js +59 -0
  21. package/dist/maplibre-gl.js.map +1 -0
  22. package/dist/package.json +1 -0
  23. package/package.json +192 -0
  24. package/src/css/maplibre-gl.css +854 -0
  25. package/src/css/svg/maplibregl-ctrl-attrib.svg +3 -0
  26. package/src/css/svg/maplibregl-ctrl-compass.svg +4 -0
  27. package/src/css/svg/maplibregl-ctrl-fullscreen.svg +3 -0
  28. package/src/css/svg/maplibregl-ctrl-geolocate.svg +5 -0
  29. package/src/css/svg/maplibregl-ctrl-logo.svg +11 -0
  30. package/src/css/svg/maplibregl-ctrl-shrink.svg +3 -0
  31. package/src/css/svg/maplibregl-ctrl-terrain.svg +3 -0
  32. package/src/css/svg/maplibregl-ctrl-zoom-in.svg +3 -0
  33. package/src/css/svg/maplibregl-ctrl-zoom-out.svg +3 -0
  34. package/src/data/array_types.g.ts +1130 -0
  35. package/src/data/bucket/circle_attributes.ts +8 -0
  36. package/src/data/bucket/circle_bucket.ts +197 -0
  37. package/src/data/bucket/fill_attributes.ts +8 -0
  38. package/src/data/bucket/fill_bucket.test.ts +95 -0
  39. package/src/data/bucket/fill_bucket.ts +228 -0
  40. package/src/data/bucket/fill_extrusion_attributes.ts +13 -0
  41. package/src/data/bucket/fill_extrusion_bucket.ts +305 -0
  42. package/src/data/bucket/heatmap_bucket.ts +12 -0
  43. package/src/data/bucket/line_attributes.ts +8 -0
  44. package/src/data/bucket/line_attributes_ext.ts +8 -0
  45. package/src/data/bucket/line_bucket.test.ts +142 -0
  46. package/src/data/bucket/line_bucket.ts +592 -0
  47. package/src/data/bucket/pattern_attributes.ts +9 -0
  48. package/src/data/bucket/pattern_bucket_features.ts +57 -0
  49. package/src/data/bucket/symbol_attributes.ts +122 -0
  50. package/src/data/bucket/symbol_bucket.test.ts +243 -0
  51. package/src/data/bucket/symbol_bucket.ts +975 -0
  52. package/src/data/bucket.ts +123 -0
  53. package/src/data/dem_data.test.ts +237 -0
  54. package/src/data/dem_data.ts +171 -0
  55. package/src/data/evaluation_feature.ts +18 -0
  56. package/src/data/extent.ts +13 -0
  57. package/src/data/feature_index.ts +337 -0
  58. package/src/data/feature_position_map.test.ts +33 -0
  59. package/src/data/feature_position_map.ts +126 -0
  60. package/src/data/index_array_type.ts +9 -0
  61. package/src/data/load_geometry.test.ts +49 -0
  62. package/src/data/load_geometry.ts +44 -0
  63. package/src/data/pos3d_attributes.ts +5 -0
  64. package/src/data/pos_attributes.ts +5 -0
  65. package/src/data/program_configuration.ts +735 -0
  66. package/src/data/raster_bounds_attributes.ts +6 -0
  67. package/src/data/segment.ts +89 -0
  68. package/src/geo/edge_insets.test.ts +83 -0
  69. package/src/geo/edge_insets.ts +146 -0
  70. package/src/geo/lng_lat.test.ts +65 -0
  71. package/src/geo/lng_lat.ts +169 -0
  72. package/src/geo/lng_lat_bounds.test.ts +357 -0
  73. package/src/geo/lng_lat_bounds.ts +356 -0
  74. package/src/geo/mercator_coordinate.test.ts +34 -0
  75. package/src/geo/mercator_coordinate.ts +157 -0
  76. package/src/geo/projection/projection.ts +72 -0
  77. package/src/geo/transform.test.ts +509 -0
  78. package/src/geo/transform.ts +1072 -0
  79. package/src/gl/color_mode.ts +31 -0
  80. package/src/gl/context.ts +321 -0
  81. package/src/gl/cull_face_mode.ts +22 -0
  82. package/src/gl/depth_mode.ts +26 -0
  83. package/src/gl/framebuffer.ts +48 -0
  84. package/src/gl/index_buffer.ts +55 -0
  85. package/src/gl/render_pool.test.ts +69 -0
  86. package/src/gl/render_pool.ts +93 -0
  87. package/src/gl/state.test.ts +125 -0
  88. package/src/gl/stencil_mode.ts +27 -0
  89. package/src/gl/types.ts +59 -0
  90. package/src/gl/value.ts +534 -0
  91. package/src/gl/vertex_buffer.test.ts +57 -0
  92. package/src/gl/vertex_buffer.ts +111 -0
  93. package/src/gl/webgl2.ts +12 -0
  94. package/src/index.test.ts +121 -0
  95. package/src/index.ts +250 -0
  96. package/src/render/draw_background.ts +53 -0
  97. package/src/render/draw_circle.ts +113 -0
  98. package/src/render/draw_collision_debug.ts +168 -0
  99. package/src/render/draw_custom.test.ts +73 -0
  100. package/src/render/draw_custom.ts +45 -0
  101. package/src/render/draw_debug.test.ts +122 -0
  102. package/src/render/draw_debug.ts +148 -0
  103. package/src/render/draw_fill.test.ts +137 -0
  104. package/src/render/draw_fill.ts +128 -0
  105. package/src/render/draw_fill_extrusion.ts +97 -0
  106. package/src/render/draw_heatmap.ts +228 -0
  107. package/src/render/draw_hillshade.ts +119 -0
  108. package/src/render/draw_line.ts +125 -0
  109. package/src/render/draw_raster.ts +133 -0
  110. package/src/render/draw_sky.ts +44 -0
  111. package/src/render/draw_symbol.test.ts +223 -0
  112. package/src/render/draw_symbol.ts +499 -0
  113. package/src/render/draw_terrain.ts +99 -0
  114. package/src/render/glyph_atlas.ts +83 -0
  115. package/src/render/glyph_manager.test.ts +147 -0
  116. package/src/render/glyph_manager.ts +198 -0
  117. package/src/render/image_atlas.ts +159 -0
  118. package/src/render/image_manager.ts +337 -0
  119. package/src/render/line_atlas.test.ts +38 -0
  120. package/src/render/line_atlas.ts +214 -0
  121. package/src/render/mesh.ts +25 -0
  122. package/src/render/painter.test.ts +51 -0
  123. package/src/render/painter.ts +666 -0
  124. package/src/render/program/background_program.ts +100 -0
  125. package/src/render/program/circle_program.ts +61 -0
  126. package/src/render/program/clipping_mask_program.ts +19 -0
  127. package/src/render/program/collision_program.ts +47 -0
  128. package/src/render/program/debug_program.ts +29 -0
  129. package/src/render/program/fill_extrusion_program.ts +120 -0
  130. package/src/render/program/fill_program.ts +121 -0
  131. package/src/render/program/heatmap_program.ts +76 -0
  132. package/src/render/program/hillshade_program.ts +116 -0
  133. package/src/render/program/line_program.ts +207 -0
  134. package/src/render/program/pattern.ts +102 -0
  135. package/src/render/program/program_uniforms.ts +46 -0
  136. package/src/render/program/raster_program.ts +88 -0
  137. package/src/render/program/sky_program.ts +28 -0
  138. package/src/render/program/symbol_program.ts +266 -0
  139. package/src/render/program/terrain_program.ts +116 -0
  140. package/src/render/program.ts +233 -0
  141. package/src/render/render_to_texture.test.ts +151 -0
  142. package/src/render/render_to_texture.ts +197 -0
  143. package/src/render/terrain.test.ts +322 -0
  144. package/src/render/terrain.ts +464 -0
  145. package/src/render/texture.ts +114 -0
  146. package/src/render/uniform_binding.test.ts +122 -0
  147. package/src/render/uniform_binding.ts +157 -0
  148. package/src/render/update_pattern_positions_in_program.test.ts +74 -0
  149. package/src/render/update_pattern_positions_in_program.ts +50 -0
  150. package/src/render/vertex_array_object.ts +163 -0
  151. package/src/shaders/README.md +42 -0
  152. package/src/shaders/_prelude.fragment.glsl +19 -0
  153. package/src/shaders/_prelude.fragment.glsl.g.ts +2 -0
  154. package/src/shaders/_prelude.vertex.glsl +148 -0
  155. package/src/shaders/_prelude.vertex.glsl.g.ts +2 -0
  156. package/src/shaders/background.fragment.glsl +10 -0
  157. package/src/shaders/background.fragment.glsl.g.ts +2 -0
  158. package/src/shaders/background.vertex.glsl +7 -0
  159. package/src/shaders/background.vertex.glsl.g.ts +2 -0
  160. package/src/shaders/background_pattern.fragment.glsl +28 -0
  161. package/src/shaders/background_pattern.fragment.glsl.g.ts +2 -0
  162. package/src/shaders/background_pattern.vertex.glsl +19 -0
  163. package/src/shaders/background_pattern.vertex.glsl.g.ts +2 -0
  164. package/src/shaders/circle.fragment.glsl +34 -0
  165. package/src/shaders/circle.fragment.glsl.g.ts +2 -0
  166. package/src/shaders/circle.vertex.glsl +68 -0
  167. package/src/shaders/circle.vertex.glsl.g.ts +2 -0
  168. package/src/shaders/clipping_mask.fragment.glsl +3 -0
  169. package/src/shaders/clipping_mask.fragment.glsl.g.ts +2 -0
  170. package/src/shaders/clipping_mask.vertex.glsl +7 -0
  171. package/src/shaders/clipping_mask.vertex.glsl.g.ts +2 -0
  172. package/src/shaders/collision_box.fragment.glsl +20 -0
  173. package/src/shaders/collision_box.fragment.glsl.g.ts +2 -0
  174. package/src/shaders/collision_box.vertex.glsl +27 -0
  175. package/src/shaders/collision_box.vertex.glsl.g.ts +2 -0
  176. package/src/shaders/collision_circle.fragment.glsl +17 -0
  177. package/src/shaders/collision_circle.fragment.glsl.g.ts +2 -0
  178. package/src/shaders/collision_circle.vertex.glsl +59 -0
  179. package/src/shaders/collision_circle.vertex.glsl.g.ts +2 -0
  180. package/src/shaders/debug.fragment.glsl +9 -0
  181. package/src/shaders/debug.fragment.glsl.g.ts +2 -0
  182. package/src/shaders/debug.vertex.glsl +12 -0
  183. package/src/shaders/debug.vertex.glsl.g.ts +2 -0
  184. package/src/shaders/encode_attribute.test.ts +11 -0
  185. package/src/shaders/encode_attribute.ts +13 -0
  186. package/src/shaders/fill.fragment.glsl +13 -0
  187. package/src/shaders/fill.fragment.glsl.g.ts +2 -0
  188. package/src/shaders/fill.vertex.glsl +13 -0
  189. package/src/shaders/fill.vertex.glsl.g.ts +2 -0
  190. package/src/shaders/fill_extrusion.fragment.glsl +9 -0
  191. package/src/shaders/fill_extrusion.fragment.glsl.g.ts +2 -0
  192. package/src/shaders/fill_extrusion.vertex.glsl +84 -0
  193. package/src/shaders/fill_extrusion.vertex.glsl.g.ts +2 -0
  194. package/src/shaders/fill_extrusion_pattern.fragment.glsl +47 -0
  195. package/src/shaders/fill_extrusion_pattern.fragment.glsl.g.ts +2 -0
  196. package/src/shaders/fill_extrusion_pattern.vertex.glsl +96 -0
  197. package/src/shaders/fill_extrusion_pattern.vertex.glsl.g.ts +2 -0
  198. package/src/shaders/fill_outline.fragment.glsl +17 -0
  199. package/src/shaders/fill_outline.fragment.glsl.g.ts +2 -0
  200. package/src/shaders/fill_outline.vertex.glsl +17 -0
  201. package/src/shaders/fill_outline.vertex.glsl.g.ts +2 -0
  202. package/src/shaders/fill_outline_pattern.fragment.glsl +43 -0
  203. package/src/shaders/fill_outline_pattern.fragment.glsl.g.ts +2 -0
  204. package/src/shaders/fill_outline_pattern.vertex.glsl +44 -0
  205. package/src/shaders/fill_outline_pattern.vertex.glsl.g.ts +2 -0
  206. package/src/shaders/fill_pattern.fragment.glsl +39 -0
  207. package/src/shaders/fill_pattern.fragment.glsl.g.ts +2 -0
  208. package/src/shaders/fill_pattern.vertex.glsl +39 -0
  209. package/src/shaders/fill_pattern.vertex.glsl.g.ts +2 -0
  210. package/src/shaders/heatmap.fragment.glsl +22 -0
  211. package/src/shaders/heatmap.fragment.glsl.g.ts +2 -0
  212. package/src/shaders/heatmap.vertex.glsl +54 -0
  213. package/src/shaders/heatmap.vertex.glsl.g.ts +2 -0
  214. package/src/shaders/heatmap_texture.fragment.glsl +15 -0
  215. package/src/shaders/heatmap_texture.fragment.glsl.g.ts +2 -0
  216. package/src/shaders/heatmap_texture.vertex.glsl +11 -0
  217. package/src/shaders/heatmap_texture.vertex.glsl.g.ts +2 -0
  218. package/src/shaders/hillshade.fragment.glsl +52 -0
  219. package/src/shaders/hillshade.fragment.glsl.g.ts +2 -0
  220. package/src/shaders/hillshade.vertex.glsl +11 -0
  221. package/src/shaders/hillshade.vertex.glsl.g.ts +2 -0
  222. package/src/shaders/hillshade_prepare.fragment.glsl +77 -0
  223. package/src/shaders/hillshade_prepare.fragment.glsl.g.ts +2 -0
  224. package/src/shaders/hillshade_prepare.vertex.glsl +15 -0
  225. package/src/shaders/hillshade_prepare.vertex.glsl.g.ts +2 -0
  226. package/src/shaders/line.fragment.glsl +30 -0
  227. package/src/shaders/line.fragment.glsl.g.ts +2 -0
  228. package/src/shaders/line.vertex.glsl +89 -0
  229. package/src/shaders/line.vertex.glsl.g.ts +2 -0
  230. package/src/shaders/line_gradient.fragment.glsl +34 -0
  231. package/src/shaders/line_gradient.fragment.glsl.g.ts +2 -0
  232. package/src/shaders/line_gradient.vertex.glsl +92 -0
  233. package/src/shaders/line_gradient.vertex.glsl.g.ts +2 -0
  234. package/src/shaders/line_pattern.fragment.glsl +77 -0
  235. package/src/shaders/line_pattern.fragment.glsl.g.ts +2 -0
  236. package/src/shaders/line_pattern.vertex.glsl +103 -0
  237. package/src/shaders/line_pattern.vertex.glsl.g.ts +2 -0
  238. package/src/shaders/line_sdf.fragment.glsl +45 -0
  239. package/src/shaders/line_sdf.fragment.glsl.g.ts +2 -0
  240. package/src/shaders/line_sdf.vertex.glsl +101 -0
  241. package/src/shaders/line_sdf.vertex.glsl.g.ts +2 -0
  242. package/src/shaders/raster.fragment.glsl +53 -0
  243. package/src/shaders/raster.fragment.glsl.g.ts +2 -0
  244. package/src/shaders/raster.vertex.glsl +21 -0
  245. package/src/shaders/raster.vertex.glsl.g.ts +2 -0
  246. package/src/shaders/shaders.ts +197 -0
  247. package/src/shaders/sky.fragment.glsl +17 -0
  248. package/src/shaders/sky.fragment.glsl.g.ts +2 -0
  249. package/src/shaders/sky.vertex.glsl +5 -0
  250. package/src/shaders/sky.vertex.glsl.g.ts +2 -0
  251. package/src/shaders/symbol_icon.fragment.glsl +17 -0
  252. package/src/shaders/symbol_icon.fragment.glsl.g.ts +2 -0
  253. package/src/shaders/symbol_icon.vertex.glsl +117 -0
  254. package/src/shaders/symbol_icon.vertex.glsl.g.ts +2 -0
  255. package/src/shaders/symbol_sdf.fragment.glsl +58 -0
  256. package/src/shaders/symbol_sdf.fragment.glsl.g.ts +2 -0
  257. package/src/shaders/symbol_sdf.vertex.glsl +142 -0
  258. package/src/shaders/symbol_sdf.vertex.glsl.g.ts +2 -0
  259. package/src/shaders/symbol_text_and_icon.fragment.glsl +68 -0
  260. package/src/shaders/symbol_text_and_icon.fragment.glsl.g.ts +2 -0
  261. package/src/shaders/symbol_text_and_icon.vertex.glsl +140 -0
  262. package/src/shaders/symbol_text_and_icon.vertex.glsl.g.ts +2 -0
  263. package/src/shaders/terrain.fragment.glsl +32 -0
  264. package/src/shaders/terrain.fragment.glsl.g.ts +2 -0
  265. package/src/shaders/terrain.vertex.glsl +17 -0
  266. package/src/shaders/terrain.vertex.glsl.g.ts +2 -0
  267. package/src/shaders/terrain_coords.fragment.glsl +11 -0
  268. package/src/shaders/terrain_coords.fragment.glsl.g.ts +2 -0
  269. package/src/shaders/terrain_coords.vertex.glsl +13 -0
  270. package/src/shaders/terrain_coords.vertex.glsl.g.ts +2 -0
  271. package/src/shaders/terrain_depth.fragment.glsl +15 -0
  272. package/src/shaders/terrain_depth.fragment.glsl.g.ts +2 -0
  273. package/src/shaders/terrain_depth.vertex.glsl +13 -0
  274. package/src/shaders/terrain_depth.vertex.glsl.g.ts +2 -0
  275. package/src/source/canvas_source.test.ts +210 -0
  276. package/src/source/canvas_source.ts +227 -0
  277. package/src/source/geojson_source.test.ts +492 -0
  278. package/src/source/geojson_source.ts +431 -0
  279. package/src/source/geojson_source_diff.test.ts +364 -0
  280. package/src/source/geojson_source_diff.ts +172 -0
  281. package/src/source/geojson_worker_source.test.ts +399 -0
  282. package/src/source/geojson_worker_source.ts +303 -0
  283. package/src/source/geojson_wrapper.test.ts +32 -0
  284. package/src/source/geojson_wrapper.ts +81 -0
  285. package/src/source/image_source.test.ts +235 -0
  286. package/src/source/image_source.ts +338 -0
  287. package/src/source/load_tilejson.ts +47 -0
  288. package/src/source/pixels_to_tile_units.ts +25 -0
  289. package/src/source/protocol_crud.ts +48 -0
  290. package/src/source/query_features.test.ts +31 -0
  291. package/src/source/query_features.ts +252 -0
  292. package/src/source/raster_dem_tile_source.test.ts +158 -0
  293. package/src/source/raster_dem_tile_source.ts +166 -0
  294. package/src/source/raster_dem_tile_worker_source.test.ts +36 -0
  295. package/src/source/raster_dem_tile_worker_source.ts +38 -0
  296. package/src/source/raster_tile_source.test.ts +206 -0
  297. package/src/source/raster_tile_source.ts +227 -0
  298. package/src/source/rtl_text_plugin_main_thread.test.ts +170 -0
  299. package/src/source/rtl_text_plugin_main_thread.ts +89 -0
  300. package/src/source/rtl_text_plugin_status.ts +33 -0
  301. package/src/source/rtl_text_plugin_worker.ts +49 -0
  302. package/src/source/source.test.ts +41 -0
  303. package/src/source/source.ts +186 -0
  304. package/src/source/source_cache.test.ts +2069 -0
  305. package/src/source/source_cache.ts +1102 -0
  306. package/src/source/source_state.ts +157 -0
  307. package/src/source/terrain_source_cache.test.ts +105 -0
  308. package/src/source/terrain_source_cache.ts +204 -0
  309. package/src/source/tile.test.ts +290 -0
  310. package/src/source/tile.ts +478 -0
  311. package/src/source/tile_bounds.ts +34 -0
  312. package/src/source/tile_cache.test.ts +130 -0
  313. package/src/source/tile_cache.ts +208 -0
  314. package/src/source/tile_id.test.ts +112 -0
  315. package/src/source/tile_id.ts +221 -0
  316. package/src/source/vector_tile_source.test.ts +401 -0
  317. package/src/source/vector_tile_source.ts +283 -0
  318. package/src/source/vector_tile_worker_source.test.ts +396 -0
  319. package/src/source/vector_tile_worker_source.ts +199 -0
  320. package/src/source/video_source.test.ts +124 -0
  321. package/src/source/video_source.ts +204 -0
  322. package/src/source/worker.test.ts +233 -0
  323. package/src/source/worker.ts +301 -0
  324. package/src/source/worker_source.ts +117 -0
  325. package/src/source/worker_tile.test.ts +226 -0
  326. package/src/source/worker_tile.ts +208 -0
  327. package/src/style/create_style_layer.ts +39 -0
  328. package/src/style/evaluation_parameters.ts +62 -0
  329. package/src/style/format_section_override.test.ts +62 -0
  330. package/src/style/format_section_override.ts +50 -0
  331. package/src/style/light.test.ts +86 -0
  332. package/src/style/light.ts +135 -0
  333. package/src/style/load_glyph_range.test.ts +40 -0
  334. package/src/style/load_glyph_range.ts +32 -0
  335. package/src/style/load_sprite.test.ts +227 -0
  336. package/src/style/load_sprite.ts +71 -0
  337. package/src/style/parse_glyph_pbf.ts +42 -0
  338. package/src/style/pauseable_placement.ts +138 -0
  339. package/src/style/properties.ts +726 -0
  340. package/src/style/query_utils.test.ts +107 -0
  341. package/src/style/query_utils.ts +70 -0
  342. package/src/style/sky.ts +127 -0
  343. package/src/style/style.test.ts +2654 -0
  344. package/src/style/style.ts +1814 -0
  345. package/src/style/style_glyph.ts +25 -0
  346. package/src/style/style_image.ts +188 -0
  347. package/src/style/style_layer/background_style_layer.ts +17 -0
  348. package/src/style/style_layer/background_style_layer_properties.g.ts +40 -0
  349. package/src/style/style_layer/circle_style_layer.ts +98 -0
  350. package/src/style/style_layer/circle_style_layer_properties.g.ts +76 -0
  351. package/src/style/style_layer/custom_style_layer.ts +233 -0
  352. package/src/style/style_layer/fill_extrusion_style_layer.ts +224 -0
  353. package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +55 -0
  354. package/src/style/style_layer/fill_style_layer.test.ts +37 -0
  355. package/src/style/style_layer/fill_style_layer.ts +65 -0
  356. package/src/style/style_layer/fill_style_layer_properties.g.ts +64 -0
  357. package/src/style/style_layer/heatmap_style_layer.ts +74 -0
  358. package/src/style/style_layer/heatmap_style_layer_properties.g.ts +46 -0
  359. package/src/style/style_layer/hillshade_style_layer.ts +21 -0
  360. package/src/style/style_layer/hillshade_style_layer_properties.g.ts +49 -0
  361. package/src/style/style_layer/line_style_layer.test.ts +50 -0
  362. package/src/style/style_layer/line_style_layer.ts +131 -0
  363. package/src/style/style_layer/line_style_layer_properties.g.ts +88 -0
  364. package/src/style/style_layer/overlap_mode.test.ts +57 -0
  365. package/src/style/style_layer/overlap_mode.ts +25 -0
  366. package/src/style/style_layer/raster_style_layer.ts +17 -0
  367. package/src/style/style_layer/raster_style_layer_properties.g.ts +55 -0
  368. package/src/style/style_layer/symbol_style_layer.ts +195 -0
  369. package/src/style/style_layer/symbol_style_layer_properties.g.ts +218 -0
  370. package/src/style/style_layer/typed_style_layer.ts +9 -0
  371. package/src/style/style_layer/variable_text_anchor.test.ts +117 -0
  372. package/src/style/style_layer/variable_text_anchor.ts +163 -0
  373. package/src/style/style_layer.test.ts +372 -0
  374. package/src/style/style_layer.ts +287 -0
  375. package/src/style/style_layer_index.test.ts +99 -0
  376. package/src/style/style_layer_index.ts +78 -0
  377. package/src/style/validate_style.ts +53 -0
  378. package/src/style/zoom_history.ts +40 -0
  379. package/src/symbol/anchor.test.ts +14 -0
  380. package/src/symbol/anchor.ts +22 -0
  381. package/src/symbol/check_max_angle.test.ts +54 -0
  382. package/src/symbol/check_max_angle.ts +76 -0
  383. package/src/symbol/clip_line.test.ts +154 -0
  384. package/src/symbol/clip_line.ts +66 -0
  385. package/src/symbol/collision_feature.test.ts +98 -0
  386. package/src/symbol/collision_feature.ts +114 -0
  387. package/src/symbol/collision_index.test.ts +19 -0
  388. package/src/symbol/collision_index.ts +618 -0
  389. package/src/symbol/cross_tile_symbol_index.test.ts +260 -0
  390. package/src/symbol/cross_tile_symbol_index.ts +367 -0
  391. package/src/symbol/get_anchors.test.ts +113 -0
  392. package/src/symbol/get_anchors.ts +167 -0
  393. package/src/symbol/grid_index.test.ts +75 -0
  394. package/src/symbol/grid_index.ts +414 -0
  395. package/src/symbol/merge_lines.test.ts +30 -0
  396. package/src/symbol/merge_lines.ts +80 -0
  397. package/src/symbol/one_em.ts +3 -0
  398. package/src/symbol/opacity_state.ts +23 -0
  399. package/src/symbol/path_interpolator.test.ts +134 -0
  400. package/src/symbol/path_interpolator.ts +55 -0
  401. package/src/symbol/placement.ts +1371 -0
  402. package/src/symbol/projection.test.ts +171 -0
  403. package/src/symbol/projection.ts +833 -0
  404. package/src/symbol/quads.test.ts +157 -0
  405. package/src/symbol/quads.ts +349 -0
  406. package/src/symbol/shaping.test.ts +360 -0
  407. package/src/symbol/shaping.ts +911 -0
  408. package/src/symbol/symbol_layout.ts +739 -0
  409. package/src/symbol/symbol_size.ts +129 -0
  410. package/src/symbol/symbol_style_layer.test.ts +103 -0
  411. package/src/symbol/transform_text.ts +27 -0
  412. package/src/ui/anchor.ts +27 -0
  413. package/src/ui/camera.test.ts +2301 -0
  414. package/src/ui/camera.ts +1520 -0
  415. package/src/ui/control/attribution_control.test.ts +543 -0
  416. package/src/ui/control/attribution_control.ts +209 -0
  417. package/src/ui/control/control.ts +67 -0
  418. package/src/ui/control/fullscreen_control.test.ts +114 -0
  419. package/src/ui/control/fullscreen_control.ts +189 -0
  420. package/src/ui/control/geolocate_control.test.ts +619 -0
  421. package/src/ui/control/geolocate_control.ts +725 -0
  422. package/src/ui/control/logo_control.test.ts +88 -0
  423. package/src/ui/control/logo_control.ts +86 -0
  424. package/src/ui/control/navigation_control.test.ts +238 -0
  425. package/src/ui/control/navigation_control.ts +294 -0
  426. package/src/ui/control/scale_control.test.ts +52 -0
  427. package/src/ui/control/scale_control.ts +152 -0
  428. package/src/ui/control/terrain_control.test.ts +58 -0
  429. package/src/ui/control/terrain_control.ts +74 -0
  430. package/src/ui/default_locale.ts +25 -0
  431. package/src/ui/events.ts +758 -0
  432. package/src/ui/handler/box_zoom.test.ts +163 -0
  433. package/src/ui/handler/box_zoom.ts +171 -0
  434. package/src/ui/handler/click_zoom.ts +55 -0
  435. package/src/ui/handler/cooperative_gestures.test.ts +338 -0
  436. package/src/ui/handler/cooperative_gestures.ts +111 -0
  437. package/src/ui/handler/dblclick_zoom.test.ts +151 -0
  438. package/src/ui/handler/drag_handler.ts +174 -0
  439. package/src/ui/handler/drag_move_state_manager.ts +115 -0
  440. package/src/ui/handler/drag_pan.test.ts +487 -0
  441. package/src/ui/handler/drag_rotate.test.ts +859 -0
  442. package/src/ui/handler/handler_util.ts +10 -0
  443. package/src/ui/handler/keyboard.test.ts +235 -0
  444. package/src/ui/handler/keyboard.ts +212 -0
  445. package/src/ui/handler/map_event.test.ts +158 -0
  446. package/src/ui/handler/map_event.ts +161 -0
  447. package/src/ui/handler/mouse.ts +92 -0
  448. package/src/ui/handler/mouse_handler_interface.test.ts +111 -0
  449. package/src/ui/handler/mouse_rotate.test.ts +62 -0
  450. package/src/ui/handler/one_finger_touch_drag.ts +45 -0
  451. package/src/ui/handler/one_finger_touch_drag_handler_interface.test.ts +77 -0
  452. package/src/ui/handler/scroll_zoom.test.ts +382 -0
  453. package/src/ui/handler/scroll_zoom.ts +379 -0
  454. package/src/ui/handler/shim/dblclick_zoom.ts +64 -0
  455. package/src/ui/handler/shim/drag_pan.ts +104 -0
  456. package/src/ui/handler/shim/drag_rotate.ts +76 -0
  457. package/src/ui/handler/shim/two_fingers_touch.ts +112 -0
  458. package/src/ui/handler/tap_drag_zoom.test.ts +113 -0
  459. package/src/ui/handler/tap_drag_zoom.ts +112 -0
  460. package/src/ui/handler/tap_recognizer.ts +138 -0
  461. package/src/ui/handler/tap_zoom.ts +98 -0
  462. package/src/ui/handler/touch_pan.ts +115 -0
  463. package/src/ui/handler/transform-provider.ts +44 -0
  464. package/src/ui/handler/two_fingers_touch.test.ts +283 -0
  465. package/src/ui/handler/two_fingers_touch.ts +336 -0
  466. package/src/ui/handler_inertia.ts +157 -0
  467. package/src/ui/handler_manager.ts +637 -0
  468. package/src/ui/hash.test.ts +404 -0
  469. package/src/ui/hash.ts +153 -0
  470. package/src/ui/map.ts +3393 -0
  471. package/src/ui/map_tests/map_animation.test.ts +61 -0
  472. package/src/ui/map_tests/map_basic.test.ts +223 -0
  473. package/src/ui/map_tests/map_bounds.test.ts +123 -0
  474. package/src/ui/map_tests/map_calculate_camera_options.test.ts +113 -0
  475. package/src/ui/map_tests/map_canvas.test.ts +59 -0
  476. package/src/ui/map_tests/map_control.test.ts +61 -0
  477. package/src/ui/map_tests/map_disable_handlers.test.ts +38 -0
  478. package/src/ui/map_tests/map_events.test.ts +1001 -0
  479. package/src/ui/map_tests/map_feature_state.test.ts +421 -0
  480. package/src/ui/map_tests/map_images.test.ts +175 -0
  481. package/src/ui/map_tests/map_is_moving.test.ts +164 -0
  482. package/src/ui/map_tests/map_is_rotating.test.ts +62 -0
  483. package/src/ui/map_tests/map_is_zooming.test.ts +86 -0
  484. package/src/ui/map_tests/map_layer.test.ts +457 -0
  485. package/src/ui/map_tests/map_options.test.ts +64 -0
  486. package/src/ui/map_tests/map_pitch.test.ts +90 -0
  487. package/src/ui/map_tests/map_pixel_ratio.test.ts +75 -0
  488. package/src/ui/map_tests/map_query_rendered_features.test.ts +93 -0
  489. package/src/ui/map_tests/map_render.test.ts +90 -0
  490. package/src/ui/map_tests/map_request_render_frame.test.ts +51 -0
  491. package/src/ui/map_tests/map_resize.test.ts +120 -0
  492. package/src/ui/map_tests/map_style.test.ts +541 -0
  493. package/src/ui/map_tests/map_terrian.test.ts +104 -0
  494. package/src/ui/map_tests/map_webgl.test.ts +72 -0
  495. package/src/ui/map_tests/map_world_copies.test.ts +103 -0
  496. package/src/ui/map_tests/map_zoom.test.ts +95 -0
  497. package/src/ui/marker.test.ts +1149 -0
  498. package/src/ui/marker.ts +880 -0
  499. package/src/ui/popup.test.ts +827 -0
  500. package/src/ui/popup.ts +717 -0
  501. package/src/util/abort_error.ts +21 -0
  502. package/src/util/actor.test.ts +218 -0
  503. package/src/util/actor.ts +241 -0
  504. package/src/util/actor_messages.ts +149 -0
  505. package/src/util/ajax.test.ts +237 -0
  506. package/src/util/ajax.ts +297 -0
  507. package/src/util/browser.test.ts +23 -0
  508. package/src/util/browser.ts +63 -0
  509. package/src/util/color_ramp.test.ts +105 -0
  510. package/src/util/color_ramp.ts +56 -0
  511. package/src/util/config.ts +29 -0
  512. package/src/util/dictionary_coder.ts +23 -0
  513. package/src/util/dispatcher.test.ts +76 -0
  514. package/src/util/dispatcher.ts +78 -0
  515. package/src/util/dom.ts +135 -0
  516. package/src/util/evented.test.ts +231 -0
  517. package/src/util/evented.ts +178 -0
  518. package/src/util/find_pole_of_inaccessibility.test.ts +21 -0
  519. package/src/util/find_pole_of_inaccessibility.ts +130 -0
  520. package/src/util/geolocation_support.test.ts +43 -0
  521. package/src/util/geolocation_support.ts +23 -0
  522. package/src/util/global_worker_pool.ts +65 -0
  523. package/src/util/image.ts +150 -0
  524. package/src/util/image_request.test.ts +408 -0
  525. package/src/util/image_request.ts +246 -0
  526. package/src/util/intersection_tests.ts +206 -0
  527. package/src/util/is_char_in_unicode_block.test.ts +15 -0
  528. package/src/util/is_char_in_unicode_block.ts +345 -0
  529. package/src/util/offscreen_canvas_distorted.test.ts +13 -0
  530. package/src/util/offscreen_canvas_distorted.ts +39 -0
  531. package/src/util/offscreen_canvas_supported.ts +11 -0
  532. package/src/util/performance.ts +117 -0
  533. package/src/util/primitives.test.ts +140 -0
  534. package/src/util/primitives.ts +143 -0
  535. package/src/util/request_manager.ts +42 -0
  536. package/src/util/resolve_tokens.test.ts +45 -0
  537. package/src/util/resolve_tokens.ts +17 -0
  538. package/src/util/script_detection.test.ts +138 -0
  539. package/src/util/script_detection.ts +376 -0
  540. package/src/util/smart_wrap.test.ts +97 -0
  541. package/src/util/smart_wrap.ts +58 -0
  542. package/src/util/struct_array.test.ts +101 -0
  543. package/src/util/struct_array.ts +246 -0
  544. package/src/util/style.test.ts +34 -0
  545. package/src/util/style.ts +28 -0
  546. package/src/util/task_queue.test.ts +114 -0
  547. package/src/util/task_queue.ts +64 -0
  548. package/src/util/test/util.ts +185 -0
  549. package/src/util/throttle.test.ts +42 -0
  550. package/src/util/throttle.ts +28 -0
  551. package/src/util/throttled_invoker.ts +41 -0
  552. package/src/util/transferable_grid_index.test.ts +56 -0
  553. package/src/util/transferable_grid_index.ts +214 -0
  554. package/src/util/util.test.ts +414 -0
  555. package/src/util/util.ts +724 -0
  556. package/src/util/vectortile_to_geojson.ts +72 -0
  557. package/src/util/verticalize_punctuation.ts +110 -0
  558. package/src/util/web_worker.ts +16 -0
  559. package/src/util/web_worker_transfer.test.ts +153 -0
  560. package/src/util/web_worker_transfer.ts +254 -0
  561. package/src/util/webp_supported.ts +63 -0
  562. package/src/util/worker_pool.test.ts +43 -0
  563. package/src/util/worker_pool.ts +58 -0
  564. package/src/util/world_bounds.test.ts +59 -0
  565. package/src/util/world_bounds.ts +46 -0
@@ -0,0 +1,833 @@
1
+ import Point from '@mapbox/point-geometry';
2
+
3
+ import {mat4, vec4} from 'gl-matrix';
4
+ import * as symbolSize from './symbol_size';
5
+ import {addDynamicAttributes} from '../data/bucket/symbol_bucket';
6
+
7
+ import type {Painter} from '../render/painter';
8
+ import type {Transform} from '../geo/transform';
9
+ import type {SymbolBucket} from '../data/bucket/symbol_bucket';
10
+ import type {
11
+ GlyphOffsetArray,
12
+ SymbolLineVertexArray,
13
+ SymbolDynamicLayoutArray
14
+ } from '../data/array_types.g';
15
+ import {WritingMode} from '../symbol/shaping';
16
+ import {findLineIntersection} from '../util/util';
17
+ import {UnwrappedTileID} from '../source/tile_id';
18
+ import {Projection} from '../geo/projection/projection';
19
+
20
+ export {
21
+ updateLineLabels,
22
+ hideGlyphs,
23
+ getLabelPlaneMatrix,
24
+ getGlCoordMatrix,
25
+ project,
26
+ getPerspectiveRatio,
27
+ placeFirstAndLastGlyph,
28
+ placeGlyphAlongLine,
29
+ xyTransformMat4,
30
+ projectLineVertexToViewport as projectVertexToViewport,
31
+ projectTileCoordinatesToViewport,
32
+ findOffsetIntersectionPoint,
33
+ transformToOffsetNormal,
34
+ };
35
+
36
+ /**
37
+ * The result of projecting a point to the screen, with some additional information about the projection.
38
+ */
39
+ export type PointProjection = {
40
+ /**
41
+ * The projected point.
42
+ */
43
+ point: Point;
44
+ /**
45
+ * The original W component of the projection.
46
+ */
47
+ signedDistanceFromCamera: number;
48
+ /**
49
+ * For complex projections (such as globe), true if the point is occluded by the projection, such as by being on the backfacing side of the globe.
50
+ */
51
+ isOccluded: boolean;
52
+ };
53
+
54
+ /*
55
+ * # Overview of coordinate spaces
56
+ *
57
+ * ## Tile coordinate spaces
58
+ * Each label has an anchor. Some labels have corresponding line geometries.
59
+ * The points for both anchors and lines are stored in tile units. Each tile has it's own
60
+ * coordinate space going from (0, 0) at the top left to (EXTENT, EXTENT) at the bottom right.
61
+ *
62
+ * ## Clip space (GL coordinate space)
63
+ * At the end of everything, the vertex shader needs to produce a position in clip space,
64
+ * which is (-1, 1) at the top left and (1, -1) in the bottom right.
65
+ * In the depth buffer, values are between 0 (near plane) to 1 (far plane).
66
+ *
67
+ * ## Map pixel coordinate spaces
68
+ * Each tile has a pixel coordinate space. It's just the tile units scaled so that one unit is
69
+ * whatever counts as 1 pixel at the current zoom.
70
+ * This space is used for pitch-alignment=map, rotation-alignment=map
71
+ *
72
+ * ## Rotated map pixel coordinate spaces
73
+ * Like the above, but rotated so axis of the space are aligned with the viewport instead of the tile.
74
+ * This space is used for pitch-alignment=map, rotation-alignment=viewport
75
+ *
76
+ * ## Viewport pixel coordinate space
77
+ * (0, 0) is at the top left of the canvas and (pixelWidth, pixelHeight) is at the bottom right corner
78
+ * of the canvas. This space is used for pitch-alignment=viewport
79
+ *
80
+ *
81
+ * # Vertex projection
82
+ * It goes roughly like this:
83
+ * 1. project the anchor and line from tile units into the correct label coordinate space
84
+ * - map pixel space pitch-alignment=map rotation-alignment=map
85
+ * - rotated map pixel space pitch-alignment=map rotation-alignment=viewport
86
+ * - viewport pixel space pitch-alignment=viewport rotation-alignment=*
87
+ * 2. if the label follows a line, find the point along the line that is the correct distance from the anchor.
88
+ * 3. add the glyph's corner offset to the point from step 3
89
+ * 4. convert from the label coordinate space to clip space
90
+ *
91
+ * For horizontal labels we want to do step 1 in the shader for performance reasons (no cpu work).
92
+ * This is what `u_label_plane_matrix` is used for.
93
+ * For labels aligned with lines we have to steps 1 and 2 on the cpu since we need access to the line geometry.
94
+ * This is what `updateLineLabels(...)` does.
95
+ * Since the conversion is handled on the cpu we just set `u_label_plane_matrix` to an identity matrix.
96
+ *
97
+ * Steps 3 and 4 are done in the shaders for all labels.
98
+ */
99
+
100
+ /*
101
+ * Returns a matrix for converting from tile units to the correct label coordinate space.
102
+ */
103
+ function getLabelPlaneMatrix(posMatrix: mat4,
104
+ pitchWithMap: boolean,
105
+ rotateWithMap: boolean,
106
+ transform: Transform,
107
+ pixelsToTileUnits: number) {
108
+ const m = mat4.create();
109
+ if (pitchWithMap) {
110
+ mat4.scale(m, m, [1 / pixelsToTileUnits, 1 / pixelsToTileUnits, 1]);
111
+ if (!rotateWithMap) {
112
+ mat4.rotateZ(m, m, transform.angle);
113
+ }
114
+ } else {
115
+ mat4.multiply(m, transform.labelPlaneMatrix, posMatrix);
116
+ }
117
+ return m;
118
+ }
119
+
120
+ /*
121
+ * Returns a matrix for converting from the correct label coordinate space to clip space.
122
+ */
123
+ function getGlCoordMatrix(posMatrix: mat4,
124
+ pitchWithMap: boolean,
125
+ rotateWithMap: boolean,
126
+ transform: Transform,
127
+ pixelsToTileUnits: number) {
128
+ if (pitchWithMap) {
129
+ const m = mat4.clone(posMatrix);
130
+ mat4.scale(m, m, [pixelsToTileUnits, pixelsToTileUnits, 1]);
131
+ if (!rotateWithMap) {
132
+ mat4.rotateZ(m, m, -transform.angle);
133
+ }
134
+ return m;
135
+ } else {
136
+ return transform.glCoordMatrix;
137
+ }
138
+ }
139
+
140
+ function project(x: number, y: number, matrix: mat4, getElevation?: (x: number, y: number) => number): PointProjection {
141
+ let pos;
142
+ if (getElevation) { // slow because of handle z-index
143
+ pos = [x, y, getElevation(x, y), 1] as vec4;
144
+ vec4.transformMat4(pos, pos, matrix);
145
+ } else { // fast because of ignore z-index
146
+ pos = [x, y, 0, 1] as vec4;
147
+ xyTransformMat4(pos, pos, matrix);
148
+ }
149
+ const w = pos[3];
150
+ return {
151
+ point: new Point(pos[0] / w, pos[1] / w),
152
+ signedDistanceFromCamera: w,
153
+ isOccluded: false
154
+ };
155
+ }
156
+
157
+ function getPerspectiveRatio(cameraToCenterDistance: number, signedDistanceFromCamera: number): number {
158
+ return 0.5 + 0.5 * (cameraToCenterDistance / signedDistanceFromCamera);
159
+ }
160
+
161
+ function isVisible(p: Point,
162
+ clippingBuffer: [number, number]) {
163
+ const inPaddedViewport = (
164
+ p.x >= -clippingBuffer[0] &&
165
+ p.x <= clippingBuffer[0] &&
166
+ p.y >= -clippingBuffer[1] &&
167
+ p.y <= clippingBuffer[1]);
168
+ return inPaddedViewport;
169
+ }
170
+
171
+ /*
172
+ * Update the `dynamicLayoutVertexBuffer` for the buffer with the correct glyph positions for the current map view.
173
+ * This is only run on labels that are aligned with lines. Horizontal labels are handled entirely in the shader.
174
+ */
175
+ function updateLineLabels(bucket: SymbolBucket,
176
+ posMatrix: mat4,
177
+ painter: Painter,
178
+ isText: boolean,
179
+ labelPlaneMatrix: mat4,
180
+ glCoordMatrix: mat4,
181
+ pitchWithMap: boolean,
182
+ keepUpright: boolean,
183
+ rotateToLine: boolean,
184
+ projection: Projection,
185
+ unwrappedTileID: UnwrappedTileID,
186
+ viewportWidth: number,
187
+ viewportHeight: number,
188
+ translation: [number, number],
189
+ getElevation: (x: number, y: number) => number) {
190
+
191
+ const sizeData = isText ? bucket.textSizeData : bucket.iconSizeData;
192
+ const partiallyEvaluatedSize = symbolSize.evaluateSizeForZoom(sizeData, painter.transform.zoom);
193
+
194
+ const clippingBuffer: [number, number] = [256 / painter.width * 2 + 1, 256 / painter.height * 2 + 1];
195
+
196
+ const dynamicLayoutVertexArray = isText ?
197
+ bucket.text.dynamicLayoutVertexArray :
198
+ bucket.icon.dynamicLayoutVertexArray;
199
+ dynamicLayoutVertexArray.clear();
200
+
201
+ const lineVertexArray = bucket.lineVertexArray;
202
+ const placedSymbols = isText ? bucket.text.placedSymbolArray : bucket.icon.placedSymbolArray;
203
+
204
+ const aspectRatio = painter.transform.width / painter.transform.height;
205
+
206
+ let useVertical = false;
207
+
208
+ for (let s = 0; s < placedSymbols.length; s++) {
209
+ const symbol = placedSymbols.get(s);
210
+
211
+ // Don't do calculations for vertical glyphs unless the previous symbol was horizontal
212
+ // and we determined that vertical glyphs were necessary.
213
+ // Also don't do calculations for symbols that are collided and fully faded out
214
+ if (symbol.hidden || symbol.writingMode === WritingMode.vertical && !useVertical) {
215
+ hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray);
216
+ continue;
217
+ }
218
+ // Awkward... but we're counting on the paired "vertical" symbol coming immediately after its horizontal counterpart
219
+ useVertical = false;
220
+
221
+ const anchorPos = project(symbol.anchorX, symbol.anchorY, posMatrix, getElevation);
222
+
223
+ // Don't bother calculating the correct point for invisible labels.
224
+ if (!isVisible(anchorPos.point, clippingBuffer)) {
225
+ hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray);
226
+ continue;
227
+ }
228
+
229
+ const cameraToAnchorDistance = anchorPos.signedDistanceFromCamera;
230
+ const perspectiveRatio = getPerspectiveRatio(painter.transform.cameraToCenterDistance, cameraToAnchorDistance);
231
+
232
+ const fontSize = symbolSize.evaluateSizeForFeature(sizeData, partiallyEvaluatedSize, symbol);
233
+ const pitchScaledFontSize = pitchWithMap ? fontSize / perspectiveRatio : fontSize * perspectiveRatio;
234
+
235
+ const tileAnchorPoint = new Point(symbol.anchorX, symbol.anchorY);
236
+ const projectionCache: ProjectionCache = {projections: {}, offsets: {}, cachedAnchorPoint: undefined, anyProjectionOccluded: false};
237
+
238
+ const projectionContext: SymbolProjectionContext = {
239
+ getElevation,
240
+ labelPlaneMatrix,
241
+ lineVertexArray,
242
+ pitchWithMap,
243
+ projectionCache,
244
+ projection,
245
+ tileAnchorPoint,
246
+ unwrappedTileID,
247
+ width: viewportWidth,
248
+ height: viewportHeight,
249
+ translation
250
+ };
251
+
252
+ const placeUnflipped: any = placeGlyphsAlongLine(projectionContext, symbol, pitchScaledFontSize, false /*unflipped*/, keepUpright, posMatrix, glCoordMatrix,
253
+ bucket.glyphOffsetArray, dynamicLayoutVertexArray, aspectRatio, rotateToLine);
254
+
255
+ useVertical = placeUnflipped.useVertical;
256
+
257
+ if (placeUnflipped.notEnoughRoom || useVertical ||
258
+ (placeUnflipped.needsFlipping &&
259
+ (placeGlyphsAlongLine(projectionContext, symbol, pitchScaledFontSize, true /*flipped*/, keepUpright, posMatrix, glCoordMatrix,
260
+ bucket.glyphOffsetArray, dynamicLayoutVertexArray, aspectRatio, rotateToLine) as any).notEnoughRoom)) {
261
+ hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray);
262
+ }
263
+ }
264
+
265
+ if (isText) {
266
+ bucket.text.dynamicLayoutVertexBuffer.updateData(dynamicLayoutVertexArray);
267
+ } else {
268
+ bucket.icon.dynamicLayoutVertexBuffer.updateData(dynamicLayoutVertexArray);
269
+ }
270
+ }
271
+
272
+ type FirstAndLastGlyphPlacement = {
273
+ first: PlacedGlyph;
274
+ last: PlacedGlyph;
275
+ } | null;
276
+
277
+ /*
278
+ * Place the first and last glyph of a line label, projected to the label plane.
279
+ * This function is called both during collision detection (to determine the label's size)
280
+ * and during line label rendering (to make sure the label fits on the line geometry with
281
+ * the current camera position, which may differ from the position used during collision detection).
282
+ *
283
+ * Calling this function has the effect of populating the "projectionCache" with all projected
284
+ * vertex locations the label will need, making future calls to placeGlyphAlongLine (for all the
285
+ * intermediate glyphs) much cheaper.
286
+ *
287
+ * Returns null if the label can't fit on the geometry
288
+ */
289
+ function placeFirstAndLastGlyph(
290
+ fontScale: number,
291
+ glyphOffsetArray: GlyphOffsetArray,
292
+ lineOffsetX: number,
293
+ lineOffsetY: number,
294
+ flip: boolean,
295
+ symbol: any,
296
+ rotateToLine: boolean,
297
+ projectionContext: SymbolProjectionContext): FirstAndLastGlyphPlacement {
298
+ const glyphEndIndex = symbol.glyphStartIndex + symbol.numGlyphs;
299
+ const lineStartIndex = symbol.lineStartIndex;
300
+ const lineEndIndex = symbol.lineStartIndex + symbol.lineLength;
301
+
302
+ const firstGlyphOffset = glyphOffsetArray.getoffsetX(symbol.glyphStartIndex);
303
+ const lastGlyphOffset = glyphOffsetArray.getoffsetX(glyphEndIndex - 1);
304
+
305
+ const firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, symbol.segment,
306
+ lineStartIndex, lineEndIndex, projectionContext, rotateToLine);
307
+ if (!firstPlacedGlyph)
308
+ return null;
309
+
310
+ const lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, symbol.segment,
311
+ lineStartIndex, lineEndIndex, projectionContext, rotateToLine);
312
+ if (!lastPlacedGlyph)
313
+ return null;
314
+
315
+ if (projectionContext.projectionCache.anyProjectionOccluded) {
316
+ return null;
317
+ }
318
+
319
+ return {first: firstPlacedGlyph, last: lastPlacedGlyph};
320
+ }
321
+
322
+ function requiresOrientationChange(writingMode, firstPoint, lastPoint, aspectRatio) {
323
+ if (writingMode === WritingMode.horizontal) {
324
+ // On top of choosing whether to flip, choose whether to render this version of the glyphs or the alternate
325
+ // vertical glyphs. We can't just filter out vertical glyphs in the horizontal range because the horizontal
326
+ // and vertical versions can have slightly different projections which could lead to angles where both or
327
+ // neither showed.
328
+ const rise = Math.abs(lastPoint.y - firstPoint.y);
329
+ const run = Math.abs(lastPoint.x - firstPoint.x) * aspectRatio;
330
+ if (rise > run) {
331
+ return {useVertical: true};
332
+ }
333
+ }
334
+
335
+ if (writingMode === WritingMode.vertical ? firstPoint.y < lastPoint.y : firstPoint.x > lastPoint.x) {
336
+ // Includes "horizontalOnly" case for labels without vertical glyphs
337
+ return {needsFlipping: true};
338
+ }
339
+
340
+ return null;
341
+ }
342
+
343
+ /*
344
+ * Place first and last glyph along the line projected to label plane, and if they fit
345
+ * iterate through all the intermediate glyphs, calculating their label plane positions
346
+ * from the projected line.
347
+ *
348
+ * Finally, add resulting glyph position calculations to dynamicLayoutVertexArray for
349
+ * upload to the GPU
350
+ */
351
+ function placeGlyphsAlongLine(projectionContext: SymbolProjectionContext, symbol, fontSize, flip, keepUpright, posMatrix, glCoordMatrix, glyphOffsetArray, dynamicLayoutVertexArray, aspectRatio, rotateToLine) {
352
+ const fontScale = fontSize / 24;
353
+ const lineOffsetX = symbol.lineOffsetX * fontScale;
354
+ const lineOffsetY = symbol.lineOffsetY * fontScale;
355
+
356
+ let placedGlyphs;
357
+ if (symbol.numGlyphs > 1) {
358
+ const glyphEndIndex = symbol.glyphStartIndex + symbol.numGlyphs;
359
+ const lineStartIndex = symbol.lineStartIndex;
360
+ const lineEndIndex = symbol.lineStartIndex + symbol.lineLength;
361
+
362
+ // Place the first and the last glyph in the label first, so we can figure out
363
+ // the overall orientation of the label and determine whether it needs to be flipped in keepUpright mode
364
+ const firstAndLastGlyph = placeFirstAndLastGlyph(fontScale, glyphOffsetArray, lineOffsetX, lineOffsetY, flip, symbol, rotateToLine, projectionContext);
365
+ if (!firstAndLastGlyph) {
366
+ return {notEnoughRoom: true};
367
+ }
368
+ const firstPoint = project(firstAndLastGlyph.first.point.x, firstAndLastGlyph.first.point.y, glCoordMatrix, projectionContext.getElevation).point;
369
+ const lastPoint = project(firstAndLastGlyph.last.point.x, firstAndLastGlyph.last.point.y, glCoordMatrix, projectionContext.getElevation).point;
370
+
371
+ if (keepUpright && !flip) {
372
+ const orientationChange = requiresOrientationChange(symbol.writingMode, firstPoint, lastPoint, aspectRatio);
373
+ if (orientationChange) {
374
+ return orientationChange;
375
+ }
376
+ }
377
+
378
+ placedGlyphs = [firstAndLastGlyph.first];
379
+ for (let glyphIndex = symbol.glyphStartIndex + 1; glyphIndex < glyphEndIndex - 1; glyphIndex++) {
380
+ // Since first and last glyph fit on the line, we're sure that the rest of the glyphs can be placed
381
+ placedGlyphs.push(placeGlyphAlongLine(fontScale * glyphOffsetArray.getoffsetX(glyphIndex), lineOffsetX, lineOffsetY, flip, symbol.segment,
382
+ lineStartIndex, lineEndIndex, projectionContext, rotateToLine));
383
+ }
384
+ placedGlyphs.push(firstAndLastGlyph.last);
385
+ } else {
386
+ // Only a single glyph to place
387
+ // So, determine whether to flip based on projected angle of the line segment it's on
388
+ if (keepUpright && !flip) {
389
+ const a = project(projectionContext.tileAnchorPoint.x, projectionContext.tileAnchorPoint.y, posMatrix, projectionContext.getElevation).point;
390
+ const tileVertexIndex = (symbol.lineStartIndex + symbol.segment + 1);
391
+ const tileSegmentEnd = new Point(projectionContext.lineVertexArray.getx(tileVertexIndex), projectionContext.lineVertexArray.gety(tileVertexIndex));
392
+ const projectedVertex = project(tileSegmentEnd.x, tileSegmentEnd.y, posMatrix, projectionContext.getElevation);
393
+ // We know the anchor will be in the viewport, but the end of the line segment may be
394
+ // behind the plane of the camera, in which case we can use a point at any arbitrary (closer)
395
+ // point on the segment.
396
+ const b = (projectedVertex.signedDistanceFromCamera > 0) ?
397
+ projectedVertex.point :
398
+ projectTruncatedLineSegmentToLabelPlane(projectionContext.tileAnchorPoint, tileSegmentEnd, a, 1, posMatrix, projectionContext);
399
+
400
+ const orientationChange = requiresOrientationChange(symbol.writingMode, a, b, aspectRatio);
401
+ if (orientationChange) {
402
+ return orientationChange;
403
+ }
404
+ }
405
+ const singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetArray.getoffsetX(symbol.glyphStartIndex), lineOffsetX, lineOffsetY, flip, symbol.segment,
406
+ symbol.lineStartIndex, symbol.lineStartIndex + symbol.lineLength, projectionContext, rotateToLine);
407
+ if (!singleGlyph || projectionContext.projectionCache.anyProjectionOccluded)
408
+ return {notEnoughRoom: true};
409
+
410
+ placedGlyphs = [singleGlyph];
411
+ }
412
+
413
+ for (const glyph of placedGlyphs) {
414
+ addDynamicAttributes(dynamicLayoutVertexArray, glyph.point, glyph.angle);
415
+ }
416
+ return {};
417
+ }
418
+
419
+ /**
420
+ * Takes a line and direction from `previousTilePoint` to `currentTilePoint`,
421
+ * projects it to *label plane*,
422
+ * and returns a projected point along this projected line that is `minimumLength` distance away from `previousProjectedPoint`.
423
+ * @param previousTilePoint - Line start point, in tile coordinates.
424
+ * @param currentTilePoint - Line end point, in tile coordinates.
425
+ * @param previousProjectedPoint - Projection of `previousTilePoint` into *label plane*.
426
+ * @param minimumLength - Distance in the projected space along the line for the returned point.
427
+ * @param projectionMatrix - Matrix to use during projection.
428
+ * @param projectionContext - Projection context, used only for terrain's `getElevation`.
429
+ */
430
+ function projectTruncatedLineSegmentToLabelPlane(previousTilePoint: Point, currentTilePoint: Point, previousProjectedPoint: Point, minimumLength: number, projectionMatrix: mat4, projectionContext: SymbolProjectionContext) {
431
+ return _projectTruncatedLineSegment(previousTilePoint, currentTilePoint, previousProjectedPoint, minimumLength, projectionMatrix, projectionContext);
432
+ }
433
+
434
+ /**
435
+ * Takes a line and direction from `previousTilePoint` to `currentTilePoint`,
436
+ * projects it to *viewport*,
437
+ * and returns a projected point along this projected line that is `minimumLength` distance away from `previousProjectedPoint`.
438
+ * @param previousTilePoint - Line start point, in tile coordinates.
439
+ * @param currentTilePoint - Line end point, in tile coordinates.
440
+ * @param previousProjectedPoint - Projection of `previousTilePoint` into *viewport*.
441
+ * @param minimumLength - Distance in the projected space along the line for the returned point.
442
+ * @param projectionContext - Projection context, used for terrain's `getElevation`, and either the `labelPlaneMatrix` or the map's special projection (mostly for globe).
443
+ */
444
+ function projectTruncatedLineSegmentToViewport(previousTilePoint: Point, currentTilePoint: Point, previousProjectedPoint: Point, minimumLength: number, projectionContext: SymbolProjectionContext) {
445
+ return _projectTruncatedLineSegment(previousTilePoint, currentTilePoint, previousProjectedPoint, minimumLength, undefined, projectionContext);
446
+ }
447
+
448
+ /**
449
+ * Do not use directly, use {@link projectTruncatedLineSegmentToLabelPlane} or {@link projectTruncatedLineSegmentToViewport} instead,
450
+ * depending on the target space.
451
+ *
452
+ * Projects a "virtual" vertex along a line segment.
453
+ * If `projectionMatrix` is not undefined, does a simple projection using this matrix.
454
+ * Otherwise, either projects to label plane using the `labelPlaneMatrix`
455
+ * or projects to viewport using the special map projection (mostly for globe) by calling {@link projectTileCoordinatesToViewport}.
456
+ */
457
+ function _projectTruncatedLineSegment(previousTilePoint: Point, currentTilePoint: Point, previousProjectedPoint: Point, minimumLength: number, projectionMatrix: mat4 | undefined, projectionContext: SymbolProjectionContext) {
458
+ // We are assuming "previousTilePoint" won't project to a point within one unit of the camera plane
459
+ // If it did, that would mean our label extended all the way out from within the viewport to a (very distant)
460
+ // point near the plane of the camera. We wouldn't be able to render the label anyway once it crossed the
461
+ // plane of the camera.
462
+ const unitVertexToBeProjected = previousTilePoint.add(previousTilePoint.sub(currentTilePoint)._unit());
463
+ const projectedUnitVertex = projectionMatrix !== undefined ?
464
+ project(unitVertexToBeProjected.x, unitVertexToBeProjected.y, projectionMatrix, projectionContext.getElevation).point :
465
+ projectTileCoordinatesToViewport(unitVertexToBeProjected.x, unitVertexToBeProjected.y, projectionContext).point;
466
+ const projectedUnitSegment = previousProjectedPoint.sub(projectedUnitVertex);
467
+ return previousProjectedPoint.add(projectedUnitSegment._mult(minimumLength / projectedUnitSegment.mag()));
468
+ }
469
+
470
+ type IndexToPointCache = { [lineIndex: number]: Point };
471
+
472
+ /**
473
+ * @internal
474
+ * We calculate label-plane projected points for line vertices as we place glyphs along the line
475
+ * Since we will use the same vertices for potentially many glyphs, cache the results for this bucket
476
+ * over the course of the render. Each vertex location also potentially has one offset equivalent
477
+ * for us to hold onto. The vertex indices are per-symbol-bucket.
478
+ */
479
+ type ProjectionCache = {
480
+ /**
481
+ * tile-unit vertices projected into label-plane units
482
+ */
483
+ projections: IndexToPointCache;
484
+ /**
485
+ * label-plane vertices which have been shifted to follow an offset line
486
+ */
487
+ offsets: IndexToPointCache;
488
+ /**
489
+ * Cached projected anchor point.
490
+ */
491
+ cachedAnchorPoint: Point | undefined;
492
+ /**
493
+ * Was any projected point occluded by the map itself (eg. occluded by the planet when using globe projection).
494
+ *
495
+ * Viewport-pitched line-following texts where *any* of the line points is hidden behind the planet curve becomes entirely hidden.
496
+ * This is perhaps not the most ideal behavior, but it works, it is simple and planetary-scale texts such as this seem to be a rare edge case.
497
+ */
498
+ anyProjectionOccluded: boolean;
499
+ };
500
+
501
+ /**
502
+ * @internal
503
+ * Arguments necessary to project a vertex to the label plane
504
+ */
505
+ export type SymbolProjectionContext = {
506
+ /**
507
+ * Used to cache results, save cost if projecting the same vertex multiple times
508
+ */
509
+ projectionCache: ProjectionCache;
510
+ /**
511
+ * The array of tile-unit vertices transferred from worker
512
+ */
513
+ lineVertexArray: SymbolLineVertexArray;
514
+ /**
515
+ * Label plane projection matrix
516
+ */
517
+ labelPlaneMatrix: mat4;
518
+ /**
519
+ * Function to get elevation at a point
520
+ * @param x - the x coordinate
521
+ * @param y - the y coordinate
522
+ */
523
+ getElevation: (x: number, y: number) => number;
524
+ /**
525
+ * Only for creating synthetic vertices if vertex would otherwise project behind plane of camera,
526
+ * but still convenient to pass it inside this type.
527
+ */
528
+ tileAnchorPoint: Point;
529
+ /**
530
+ * True when line glyphs are projected onto the map, instead of onto the viewport.
531
+ */
532
+ pitchWithMap: boolean;
533
+ projection: Projection;
534
+ unwrappedTileID: UnwrappedTileID;
535
+ /**
536
+ * Viewport width.
537
+ */
538
+ width: number;
539
+ /**
540
+ * Viewport height.
541
+ */
542
+ height: number;
543
+ /**
544
+ * Translation in tile units, computed using text-translate and text-translate-anchor paint style properties.
545
+ */
546
+ translation: [number, number];
547
+ };
548
+
549
+ /**
550
+ * Only for creating synthetic vertices if vertex would otherwise project behind plane of camera
551
+ */
552
+ export type ProjectionSyntheticVertexArgs = {
553
+ distanceFromAnchor: number;
554
+ previousVertex: Point;
555
+ direction: number;
556
+ absOffsetX: number;
557
+ };
558
+
559
+ /**
560
+ * Transform a vertex from tile coordinates to label plane coordinates
561
+ * @param index - index of vertex to project
562
+ * @param projectionContext - necessary data to project a vertex
563
+ * @returns the vertex projected to the label plane
564
+ */
565
+ function projectLineVertexToViewport(index: number, projectionContext: SymbolProjectionContext, syntheticVertexArgs: ProjectionSyntheticVertexArgs): Point {
566
+ const cache = projectionContext.projectionCache;
567
+
568
+ if (cache.projections[index]) {
569
+ return cache.projections[index];
570
+ }
571
+ const currentVertex = new Point(
572
+ projectionContext.lineVertexArray.getx(index),
573
+ projectionContext.lineVertexArray.gety(index));
574
+
575
+ const projection = projectTileCoordinatesToViewport(currentVertex.x, currentVertex.y, projectionContext);
576
+
577
+ if (projection.signedDistanceFromCamera > 0) {
578
+ cache.projections[index] = projection.point;
579
+ cache.anyProjectionOccluded = cache.anyProjectionOccluded || projection.isOccluded;
580
+ return projection.point;
581
+ }
582
+
583
+ // The vertex is behind the plane of the camera, so we can't project it
584
+ // Instead, we'll create a vertex along the line that's far enough to include the glyph
585
+ const previousLineVertexIndex = index - syntheticVertexArgs.direction;
586
+ const previousTilePoint = syntheticVertexArgs.distanceFromAnchor === 0 ?
587
+ projectionContext.tileAnchorPoint :
588
+ new Point(projectionContext.lineVertexArray.getx(previousLineVertexIndex), projectionContext.lineVertexArray.gety(previousLineVertexIndex));
589
+
590
+ // Don't cache because the new vertex might not be far enough out for future glyphs on the same segment
591
+ const minimumLength = syntheticVertexArgs.absOffsetX - syntheticVertexArgs.distanceFromAnchor + 1;
592
+ return projectTruncatedLineSegmentToViewport(previousTilePoint, currentVertex, syntheticVertexArgs.previousVertex, minimumLength, projectionContext);
593
+ }
594
+
595
+ function projectTileCoordinatesToViewport(x: number, y: number, projectionContext: SymbolProjectionContext): PointProjection {
596
+ const translatedX = x + projectionContext.translation[0];
597
+ const translatedY = y + projectionContext.translation[1];
598
+ let projection;
599
+ if (!projectionContext.pitchWithMap && projectionContext.projection.useSpecialProjectionForSymbols) {
600
+ projection = projectionContext.projection.projectTileCoordinates(translatedX, translatedY, projectionContext.unwrappedTileID, projectionContext.getElevation);
601
+ projection.point.x = (projection.point.x * 0.5 + 0.5) * projectionContext.width;
602
+ projection.point.y = (-projection.point.y * 0.5 + 0.5) * projectionContext.height;
603
+ } else {
604
+ projection = project(translatedX, translatedY, projectionContext.labelPlaneMatrix, projectionContext.getElevation);
605
+ projection.isOccluded = false;
606
+ }
607
+ return projection;
608
+ }
609
+
610
+ /**
611
+ * Calculate the normal vector for a line segment
612
+ * @param segmentVector - will be mutated as a tiny optimization
613
+ * @param offset - magnitude of resulting vector
614
+ * @param direction - direction of line traversal
615
+ * @returns a normal vector from the segment, with magnitude equal to offset amount
616
+ */
617
+ function transformToOffsetNormal(segmentVector: Point, offset: number, direction: number): Point {
618
+ return segmentVector._unit()._perp()._mult(offset * direction);
619
+ }
620
+
621
+ /**
622
+ * Construct offset line segments for the current segment and the next segment, then extend/shrink
623
+ * the segments until they intersect. If the segments are parallel, then they will touch with no modification.
624
+ *
625
+ * @param index - Index of the current vertex
626
+ * @param prevToCurrentOffsetNormal - Normal vector of the line segment from the previous vertex to the current vertex
627
+ * @param currentVertex - Current (non-offset) vertex projected to the label plane
628
+ * @param lineStartIndex - Beginning index for the line this label is on
629
+ * @param lineEndIndex - End index for the line this label is on
630
+ * @param offsetPreviousVertex - The previous vertex projected to the label plane, and then offset along the previous segments normal
631
+ * @param lineOffsetY - Magnitude of the offset
632
+ * @param projectionContext - Necessary data for tile-to-label-plane projection
633
+ * @returns The point at which the current and next line segments intersect, once offset and extended/shrunk to their meeting point
634
+ */
635
+ function findOffsetIntersectionPoint(
636
+ index: number,
637
+ prevToCurrentOffsetNormal: Point,
638
+ currentVertex: Point,
639
+ lineStartIndex: number,
640
+ lineEndIndex: number,
641
+ offsetPreviousVertex: Point,
642
+ lineOffsetY: number,
643
+ projectionContext: SymbolProjectionContext,
644
+ syntheticVertexArgs: ProjectionSyntheticVertexArgs) {
645
+ if (projectionContext.projectionCache.offsets[index]) {
646
+ return projectionContext.projectionCache.offsets[index];
647
+ }
648
+
649
+ const offsetCurrentVertex = currentVertex.add(prevToCurrentOffsetNormal);
650
+
651
+ if (index + syntheticVertexArgs.direction < lineStartIndex || index + syntheticVertexArgs.direction >= lineEndIndex) {
652
+ // This is the end of the line, no intersection to calculate
653
+ projectionContext.projectionCache.offsets[index] = offsetCurrentVertex;
654
+ return offsetCurrentVertex;
655
+ }
656
+ // Offset the vertices for the next segment
657
+ const nextVertex = projectLineVertexToViewport(index + syntheticVertexArgs.direction, projectionContext, syntheticVertexArgs);
658
+ const currentToNextOffsetNormal = transformToOffsetNormal(nextVertex.sub(currentVertex), lineOffsetY, syntheticVertexArgs.direction);
659
+ const offsetNextSegmentBegin = currentVertex.add(currentToNextOffsetNormal);
660
+ const offsetNextSegmentEnd = nextVertex.add(currentToNextOffsetNormal);
661
+
662
+ // find the intersection of these two lines
663
+ // if the lines are parallel, offsetCurrent/offsetNextBegin will touch
664
+ projectionContext.projectionCache.offsets[index] = findLineIntersection(offsetPreviousVertex, offsetCurrentVertex, offsetNextSegmentBegin, offsetNextSegmentEnd) || offsetCurrentVertex;
665
+
666
+ return projectionContext.projectionCache.offsets[index];
667
+ }
668
+
669
+ /**
670
+ * Placed Glyph type
671
+ */
672
+ type PlacedGlyph = {
673
+ /**
674
+ * The point at which the glyph should be placed, in label plane coordinates
675
+ */
676
+ point: Point;
677
+ /**
678
+ * The angle at which the glyph should be placed
679
+ */
680
+ angle: number;
681
+ /**
682
+ * The label-plane path used to reach this glyph: used only for collision detection
683
+ */
684
+ path: Array<Point>;
685
+ };
686
+
687
+ /*
688
+ * Place a single glyph along its line, projected into the label plane, by iterating outward
689
+ * from the anchor point until the distance traversed in the label plane equals the glyph's
690
+ * offsetX. Returns null if the glyph can't fit on the line geometry.
691
+ */
692
+ function placeGlyphAlongLine(
693
+ offsetX: number,
694
+ lineOffsetX: number,
695
+ lineOffsetY: number,
696
+ flip: boolean,
697
+ anchorSegment: number,
698
+ lineStartIndex: number,
699
+ lineEndIndex: number,
700
+ projectionContext: SymbolProjectionContext,
701
+ rotateToLine: boolean): PlacedGlyph | null {
702
+
703
+ const combinedOffsetX = flip ?
704
+ offsetX - lineOffsetX :
705
+ offsetX + lineOffsetX;
706
+
707
+ let direction = combinedOffsetX > 0 ? 1 : -1;
708
+
709
+ let angle = 0;
710
+ if (flip) {
711
+ // The label needs to be flipped to keep text upright.
712
+ // Iterate in the reverse direction.
713
+ direction *= -1;
714
+ angle = Math.PI;
715
+ }
716
+
717
+ if (direction < 0) angle += Math.PI;
718
+
719
+ let currentIndex = direction > 0 ?
720
+ lineStartIndex + anchorSegment :
721
+ lineStartIndex + anchorSegment + 1;
722
+
723
+ // Project anchor point to proper label plane and cache it
724
+ let anchorPoint: Point;
725
+
726
+ if (projectionContext.projectionCache.cachedAnchorPoint) {
727
+ anchorPoint = projectionContext.projectionCache.cachedAnchorPoint;
728
+ } else {
729
+ anchorPoint = projectTileCoordinatesToViewport(projectionContext.tileAnchorPoint.x, projectionContext.tileAnchorPoint.y, projectionContext).point;
730
+ projectionContext.projectionCache.cachedAnchorPoint = anchorPoint;
731
+ }
732
+
733
+ let currentVertex = anchorPoint;
734
+ let previousVertex = anchorPoint;
735
+
736
+ // offsetPrev and intersectionPoint are analogous to previousVertex and currentVertex
737
+ // but if there's a line offset they are calculated in parallel as projection happens
738
+ let offsetIntersectionPoint: Point;
739
+ let offsetPreviousVertex: Point;
740
+
741
+ let distanceFromAnchor = 0;
742
+ let currentSegmentDistance = 0;
743
+ const absOffsetX = Math.abs(combinedOffsetX);
744
+ const pathVertices: Array<Point> = [];
745
+
746
+ let currentLineSegment: Point;
747
+ while (distanceFromAnchor + currentSegmentDistance <= absOffsetX) {
748
+ currentIndex += direction;
749
+
750
+ // offset does not fit on the projected line
751
+ if (currentIndex < lineStartIndex || currentIndex >= lineEndIndex)
752
+ return null;
753
+
754
+ // accumulate values from last iteration
755
+ distanceFromAnchor += currentSegmentDistance;
756
+ previousVertex = currentVertex;
757
+ offsetPreviousVertex = offsetIntersectionPoint;
758
+
759
+ const syntheticVertexArgs: ProjectionSyntheticVertexArgs = {
760
+ absOffsetX,
761
+ direction,
762
+ distanceFromAnchor,
763
+ previousVertex
764
+ };
765
+
766
+ // find next vertex in viewport space
767
+ currentVertex = projectLineVertexToViewport(currentIndex, projectionContext, syntheticVertexArgs);
768
+ if (lineOffsetY === 0) {
769
+ // Store vertices for collision detection and update current segment geometry
770
+ pathVertices.push(previousVertex);
771
+ currentLineSegment = currentVertex.sub(previousVertex);
772
+ } else {
773
+ // Calculate the offset for this section
774
+ let prevToCurrentOffsetNormal;
775
+ const prevToCurrent = currentVertex.sub(previousVertex);
776
+ if (prevToCurrent.mag() === 0) {
777
+ // We are starting with our anchor point directly on the vertex, so look one vertex ahead
778
+ // to calculate a normal
779
+ const nextVertex = projectLineVertexToViewport(currentIndex + direction, projectionContext, syntheticVertexArgs);
780
+ prevToCurrentOffsetNormal = transformToOffsetNormal(nextVertex.sub(currentVertex), lineOffsetY, direction);
781
+ } else {
782
+ prevToCurrentOffsetNormal = transformToOffsetNormal(prevToCurrent, lineOffsetY, direction);
783
+ }
784
+ // Initialize offsetPrev on our first iteration, after that it will be pre-calculated
785
+ if (!offsetPreviousVertex)
786
+ offsetPreviousVertex = previousVertex.add(prevToCurrentOffsetNormal);
787
+
788
+ offsetIntersectionPoint = findOffsetIntersectionPoint(currentIndex, prevToCurrentOffsetNormal, currentVertex, lineStartIndex, lineEndIndex, offsetPreviousVertex, lineOffsetY, projectionContext, syntheticVertexArgs);
789
+
790
+ pathVertices.push(offsetPreviousVertex);
791
+ currentLineSegment = offsetIntersectionPoint.sub(offsetPreviousVertex);
792
+ }
793
+ currentSegmentDistance = currentLineSegment.mag();
794
+ }
795
+
796
+ // The point is on the current segment. Interpolate to find it.
797
+ const segmentInterpolationT = (absOffsetX - distanceFromAnchor) / currentSegmentDistance;
798
+ const p = currentLineSegment._mult(segmentInterpolationT)._add(offsetPreviousVertex || previousVertex);
799
+
800
+ const segmentAngle = angle + Math.atan2(currentVertex.y - previousVertex.y, currentVertex.x - previousVertex.x);
801
+
802
+ pathVertices.push(p);
803
+
804
+ return {
805
+ point: p,
806
+ angle: rotateToLine ? segmentAngle : 0.0,
807
+ path: pathVertices
808
+ };
809
+ }
810
+
811
+ const hiddenGlyphAttributes = new Float32Array([-Infinity, -Infinity, 0, -Infinity, -Infinity, 0, -Infinity, -Infinity, 0, -Infinity, -Infinity, 0]);
812
+
813
+ // Hide them by moving them offscreen. We still need to add them to the buffer
814
+ // because the dynamic buffer is paired with a static buffer that doesn't get updated.
815
+ function hideGlyphs(num: number, dynamicLayoutVertexArray: SymbolDynamicLayoutArray) {
816
+ for (let i = 0; i < num; i++) {
817
+ const offset = dynamicLayoutVertexArray.length;
818
+ dynamicLayoutVertexArray.resize(offset + 4);
819
+ // Since all hidden glyphs have the same attributes, we can build up the array faster with a single call to Float32Array.set
820
+ // for each set of four vertices, instead of calling addDynamicAttributes for each vertex.
821
+ dynamicLayoutVertexArray.float32.set(hiddenGlyphAttributes, offset * 3);
822
+ }
823
+ }
824
+
825
+ // For line label layout, we're not using z output and our w input is always 1
826
+ // This custom matrix transformation ignores those components to make projection faster
827
+ function xyTransformMat4(out: vec4, a: vec4, m: mat4) {
828
+ const x = a[0], y = a[1];
829
+ out[0] = m[0] * x + m[4] * y + m[12];
830
+ out[1] = m[1] * x + m[5] * y + m[13];
831
+ out[3] = m[3] * x + m[7] * y + m[15];
832
+ return out;
833
+ }