@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.
- package/LICENSE.txt +116 -0
- package/README.md +174 -0
- package/build/banner.ts +12 -0
- package/build/bump-version-changelog.js +26 -0
- package/build/check-bundle-size.js +77 -0
- package/build/generate-dist-package.js +26 -0
- package/build/generate-doc-images.ts +78 -0
- package/build/generate-docs.ts +190 -0
- package/build/generate-shaders.ts +68 -0
- package/build/generate-struct-arrays.ts +438 -0
- package/build/generate-style-code.ts +283 -0
- package/build/readme.md +56 -0
- package/build/release-notes.js +45 -0
- package/build/rollup/bundle_prelude.js +29 -0
- package/build/rollup/maplibregl.js +22 -0
- package/build/rollup_plugins.ts +58 -0
- package/dist/LICENSE.txt +116 -0
- package/dist/maplibre-gl.css +1 -0
- package/dist/maplibre-gl.d.ts +13304 -0
- package/dist/maplibre-gl.js +59 -0
- package/dist/maplibre-gl.js.map +1 -0
- package/dist/package.json +1 -0
- package/package.json +192 -0
- package/src/css/maplibre-gl.css +854 -0
- package/src/css/svg/maplibregl-ctrl-attrib.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-compass.svg +4 -0
- package/src/css/svg/maplibregl-ctrl-fullscreen.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-geolocate.svg +5 -0
- package/src/css/svg/maplibregl-ctrl-logo.svg +11 -0
- package/src/css/svg/maplibregl-ctrl-shrink.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-terrain.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-zoom-in.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-zoom-out.svg +3 -0
- package/src/data/array_types.g.ts +1130 -0
- package/src/data/bucket/circle_attributes.ts +8 -0
- package/src/data/bucket/circle_bucket.ts +197 -0
- package/src/data/bucket/fill_attributes.ts +8 -0
- package/src/data/bucket/fill_bucket.test.ts +95 -0
- package/src/data/bucket/fill_bucket.ts +228 -0
- package/src/data/bucket/fill_extrusion_attributes.ts +13 -0
- package/src/data/bucket/fill_extrusion_bucket.ts +305 -0
- package/src/data/bucket/heatmap_bucket.ts +12 -0
- package/src/data/bucket/line_attributes.ts +8 -0
- package/src/data/bucket/line_attributes_ext.ts +8 -0
- package/src/data/bucket/line_bucket.test.ts +142 -0
- package/src/data/bucket/line_bucket.ts +592 -0
- package/src/data/bucket/pattern_attributes.ts +9 -0
- package/src/data/bucket/pattern_bucket_features.ts +57 -0
- package/src/data/bucket/symbol_attributes.ts +122 -0
- package/src/data/bucket/symbol_bucket.test.ts +243 -0
- package/src/data/bucket/symbol_bucket.ts +975 -0
- package/src/data/bucket.ts +123 -0
- package/src/data/dem_data.test.ts +237 -0
- package/src/data/dem_data.ts +171 -0
- package/src/data/evaluation_feature.ts +18 -0
- package/src/data/extent.ts +13 -0
- package/src/data/feature_index.ts +337 -0
- package/src/data/feature_position_map.test.ts +33 -0
- package/src/data/feature_position_map.ts +126 -0
- package/src/data/index_array_type.ts +9 -0
- package/src/data/load_geometry.test.ts +49 -0
- package/src/data/load_geometry.ts +44 -0
- package/src/data/pos3d_attributes.ts +5 -0
- package/src/data/pos_attributes.ts +5 -0
- package/src/data/program_configuration.ts +735 -0
- package/src/data/raster_bounds_attributes.ts +6 -0
- package/src/data/segment.ts +89 -0
- package/src/geo/edge_insets.test.ts +83 -0
- package/src/geo/edge_insets.ts +146 -0
- package/src/geo/lng_lat.test.ts +65 -0
- package/src/geo/lng_lat.ts +169 -0
- package/src/geo/lng_lat_bounds.test.ts +357 -0
- package/src/geo/lng_lat_bounds.ts +356 -0
- package/src/geo/mercator_coordinate.test.ts +34 -0
- package/src/geo/mercator_coordinate.ts +157 -0
- package/src/geo/projection/projection.ts +72 -0
- package/src/geo/transform.test.ts +509 -0
- package/src/geo/transform.ts +1072 -0
- package/src/gl/color_mode.ts +31 -0
- package/src/gl/context.ts +321 -0
- package/src/gl/cull_face_mode.ts +22 -0
- package/src/gl/depth_mode.ts +26 -0
- package/src/gl/framebuffer.ts +48 -0
- package/src/gl/index_buffer.ts +55 -0
- package/src/gl/render_pool.test.ts +69 -0
- package/src/gl/render_pool.ts +93 -0
- package/src/gl/state.test.ts +125 -0
- package/src/gl/stencil_mode.ts +27 -0
- package/src/gl/types.ts +59 -0
- package/src/gl/value.ts +534 -0
- package/src/gl/vertex_buffer.test.ts +57 -0
- package/src/gl/vertex_buffer.ts +111 -0
- package/src/gl/webgl2.ts +12 -0
- package/src/index.test.ts +121 -0
- package/src/index.ts +250 -0
- package/src/render/draw_background.ts +53 -0
- package/src/render/draw_circle.ts +113 -0
- package/src/render/draw_collision_debug.ts +168 -0
- package/src/render/draw_custom.test.ts +73 -0
- package/src/render/draw_custom.ts +45 -0
- package/src/render/draw_debug.test.ts +122 -0
- package/src/render/draw_debug.ts +148 -0
- package/src/render/draw_fill.test.ts +137 -0
- package/src/render/draw_fill.ts +128 -0
- package/src/render/draw_fill_extrusion.ts +97 -0
- package/src/render/draw_heatmap.ts +228 -0
- package/src/render/draw_hillshade.ts +119 -0
- package/src/render/draw_line.ts +125 -0
- package/src/render/draw_raster.ts +133 -0
- package/src/render/draw_sky.ts +44 -0
- package/src/render/draw_symbol.test.ts +223 -0
- package/src/render/draw_symbol.ts +499 -0
- package/src/render/draw_terrain.ts +99 -0
- package/src/render/glyph_atlas.ts +83 -0
- package/src/render/glyph_manager.test.ts +147 -0
- package/src/render/glyph_manager.ts +198 -0
- package/src/render/image_atlas.ts +159 -0
- package/src/render/image_manager.ts +337 -0
- package/src/render/line_atlas.test.ts +38 -0
- package/src/render/line_atlas.ts +214 -0
- package/src/render/mesh.ts +25 -0
- package/src/render/painter.test.ts +51 -0
- package/src/render/painter.ts +666 -0
- package/src/render/program/background_program.ts +100 -0
- package/src/render/program/circle_program.ts +61 -0
- package/src/render/program/clipping_mask_program.ts +19 -0
- package/src/render/program/collision_program.ts +47 -0
- package/src/render/program/debug_program.ts +29 -0
- package/src/render/program/fill_extrusion_program.ts +120 -0
- package/src/render/program/fill_program.ts +121 -0
- package/src/render/program/heatmap_program.ts +76 -0
- package/src/render/program/hillshade_program.ts +116 -0
- package/src/render/program/line_program.ts +207 -0
- package/src/render/program/pattern.ts +102 -0
- package/src/render/program/program_uniforms.ts +46 -0
- package/src/render/program/raster_program.ts +88 -0
- package/src/render/program/sky_program.ts +28 -0
- package/src/render/program/symbol_program.ts +266 -0
- package/src/render/program/terrain_program.ts +116 -0
- package/src/render/program.ts +233 -0
- package/src/render/render_to_texture.test.ts +151 -0
- package/src/render/render_to_texture.ts +197 -0
- package/src/render/terrain.test.ts +322 -0
- package/src/render/terrain.ts +464 -0
- package/src/render/texture.ts +114 -0
- package/src/render/uniform_binding.test.ts +122 -0
- package/src/render/uniform_binding.ts +157 -0
- package/src/render/update_pattern_positions_in_program.test.ts +74 -0
- package/src/render/update_pattern_positions_in_program.ts +50 -0
- package/src/render/vertex_array_object.ts +163 -0
- package/src/shaders/README.md +42 -0
- package/src/shaders/_prelude.fragment.glsl +19 -0
- package/src/shaders/_prelude.fragment.glsl.g.ts +2 -0
- package/src/shaders/_prelude.vertex.glsl +148 -0
- package/src/shaders/_prelude.vertex.glsl.g.ts +2 -0
- package/src/shaders/background.fragment.glsl +10 -0
- package/src/shaders/background.fragment.glsl.g.ts +2 -0
- package/src/shaders/background.vertex.glsl +7 -0
- package/src/shaders/background.vertex.glsl.g.ts +2 -0
- package/src/shaders/background_pattern.fragment.glsl +28 -0
- package/src/shaders/background_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/background_pattern.vertex.glsl +19 -0
- package/src/shaders/background_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/circle.fragment.glsl +34 -0
- package/src/shaders/circle.fragment.glsl.g.ts +2 -0
- package/src/shaders/circle.vertex.glsl +68 -0
- package/src/shaders/circle.vertex.glsl.g.ts +2 -0
- package/src/shaders/clipping_mask.fragment.glsl +3 -0
- package/src/shaders/clipping_mask.fragment.glsl.g.ts +2 -0
- package/src/shaders/clipping_mask.vertex.glsl +7 -0
- package/src/shaders/clipping_mask.vertex.glsl.g.ts +2 -0
- package/src/shaders/collision_box.fragment.glsl +20 -0
- package/src/shaders/collision_box.fragment.glsl.g.ts +2 -0
- package/src/shaders/collision_box.vertex.glsl +27 -0
- package/src/shaders/collision_box.vertex.glsl.g.ts +2 -0
- package/src/shaders/collision_circle.fragment.glsl +17 -0
- package/src/shaders/collision_circle.fragment.glsl.g.ts +2 -0
- package/src/shaders/collision_circle.vertex.glsl +59 -0
- package/src/shaders/collision_circle.vertex.glsl.g.ts +2 -0
- package/src/shaders/debug.fragment.glsl +9 -0
- package/src/shaders/debug.fragment.glsl.g.ts +2 -0
- package/src/shaders/debug.vertex.glsl +12 -0
- package/src/shaders/debug.vertex.glsl.g.ts +2 -0
- package/src/shaders/encode_attribute.test.ts +11 -0
- package/src/shaders/encode_attribute.ts +13 -0
- package/src/shaders/fill.fragment.glsl +13 -0
- package/src/shaders/fill.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill.vertex.glsl +13 -0
- package/src/shaders/fill.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion.fragment.glsl +9 -0
- package/src/shaders/fill_extrusion.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion.vertex.glsl +84 -0
- package/src/shaders/fill_extrusion.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion_pattern.fragment.glsl +47 -0
- package/src/shaders/fill_extrusion_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion_pattern.vertex.glsl +96 -0
- package/src/shaders/fill_extrusion_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_outline.fragment.glsl +17 -0
- package/src/shaders/fill_outline.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_outline.vertex.glsl +17 -0
- package/src/shaders/fill_outline.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_outline_pattern.fragment.glsl +43 -0
- package/src/shaders/fill_outline_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_outline_pattern.vertex.glsl +44 -0
- package/src/shaders/fill_outline_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_pattern.fragment.glsl +39 -0
- package/src/shaders/fill_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_pattern.vertex.glsl +39 -0
- package/src/shaders/fill_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/heatmap.fragment.glsl +22 -0
- package/src/shaders/heatmap.fragment.glsl.g.ts +2 -0
- package/src/shaders/heatmap.vertex.glsl +54 -0
- package/src/shaders/heatmap.vertex.glsl.g.ts +2 -0
- package/src/shaders/heatmap_texture.fragment.glsl +15 -0
- package/src/shaders/heatmap_texture.fragment.glsl.g.ts +2 -0
- package/src/shaders/heatmap_texture.vertex.glsl +11 -0
- package/src/shaders/heatmap_texture.vertex.glsl.g.ts +2 -0
- package/src/shaders/hillshade.fragment.glsl +52 -0
- package/src/shaders/hillshade.fragment.glsl.g.ts +2 -0
- package/src/shaders/hillshade.vertex.glsl +11 -0
- package/src/shaders/hillshade.vertex.glsl.g.ts +2 -0
- package/src/shaders/hillshade_prepare.fragment.glsl +77 -0
- package/src/shaders/hillshade_prepare.fragment.glsl.g.ts +2 -0
- package/src/shaders/hillshade_prepare.vertex.glsl +15 -0
- package/src/shaders/hillshade_prepare.vertex.glsl.g.ts +2 -0
- package/src/shaders/line.fragment.glsl +30 -0
- package/src/shaders/line.fragment.glsl.g.ts +2 -0
- package/src/shaders/line.vertex.glsl +89 -0
- package/src/shaders/line.vertex.glsl.g.ts +2 -0
- package/src/shaders/line_gradient.fragment.glsl +34 -0
- package/src/shaders/line_gradient.fragment.glsl.g.ts +2 -0
- package/src/shaders/line_gradient.vertex.glsl +92 -0
- package/src/shaders/line_gradient.vertex.glsl.g.ts +2 -0
- package/src/shaders/line_pattern.fragment.glsl +77 -0
- package/src/shaders/line_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/line_pattern.vertex.glsl +103 -0
- package/src/shaders/line_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/line_sdf.fragment.glsl +45 -0
- package/src/shaders/line_sdf.fragment.glsl.g.ts +2 -0
- package/src/shaders/line_sdf.vertex.glsl +101 -0
- package/src/shaders/line_sdf.vertex.glsl.g.ts +2 -0
- package/src/shaders/raster.fragment.glsl +53 -0
- package/src/shaders/raster.fragment.glsl.g.ts +2 -0
- package/src/shaders/raster.vertex.glsl +21 -0
- package/src/shaders/raster.vertex.glsl.g.ts +2 -0
- package/src/shaders/shaders.ts +197 -0
- package/src/shaders/sky.fragment.glsl +17 -0
- package/src/shaders/sky.fragment.glsl.g.ts +2 -0
- package/src/shaders/sky.vertex.glsl +5 -0
- package/src/shaders/sky.vertex.glsl.g.ts +2 -0
- package/src/shaders/symbol_icon.fragment.glsl +17 -0
- package/src/shaders/symbol_icon.fragment.glsl.g.ts +2 -0
- package/src/shaders/symbol_icon.vertex.glsl +117 -0
- package/src/shaders/symbol_icon.vertex.glsl.g.ts +2 -0
- package/src/shaders/symbol_sdf.fragment.glsl +58 -0
- package/src/shaders/symbol_sdf.fragment.glsl.g.ts +2 -0
- package/src/shaders/symbol_sdf.vertex.glsl +142 -0
- package/src/shaders/symbol_sdf.vertex.glsl.g.ts +2 -0
- package/src/shaders/symbol_text_and_icon.fragment.glsl +68 -0
- package/src/shaders/symbol_text_and_icon.fragment.glsl.g.ts +2 -0
- package/src/shaders/symbol_text_and_icon.vertex.glsl +140 -0
- package/src/shaders/symbol_text_and_icon.vertex.glsl.g.ts +2 -0
- package/src/shaders/terrain.fragment.glsl +32 -0
- package/src/shaders/terrain.fragment.glsl.g.ts +2 -0
- package/src/shaders/terrain.vertex.glsl +17 -0
- package/src/shaders/terrain.vertex.glsl.g.ts +2 -0
- package/src/shaders/terrain_coords.fragment.glsl +11 -0
- package/src/shaders/terrain_coords.fragment.glsl.g.ts +2 -0
- package/src/shaders/terrain_coords.vertex.glsl +13 -0
- package/src/shaders/terrain_coords.vertex.glsl.g.ts +2 -0
- package/src/shaders/terrain_depth.fragment.glsl +15 -0
- package/src/shaders/terrain_depth.fragment.glsl.g.ts +2 -0
- package/src/shaders/terrain_depth.vertex.glsl +13 -0
- package/src/shaders/terrain_depth.vertex.glsl.g.ts +2 -0
- package/src/source/canvas_source.test.ts +210 -0
- package/src/source/canvas_source.ts +227 -0
- package/src/source/geojson_source.test.ts +492 -0
- package/src/source/geojson_source.ts +431 -0
- package/src/source/geojson_source_diff.test.ts +364 -0
- package/src/source/geojson_source_diff.ts +172 -0
- package/src/source/geojson_worker_source.test.ts +399 -0
- package/src/source/geojson_worker_source.ts +303 -0
- package/src/source/geojson_wrapper.test.ts +32 -0
- package/src/source/geojson_wrapper.ts +81 -0
- package/src/source/image_source.test.ts +235 -0
- package/src/source/image_source.ts +338 -0
- package/src/source/load_tilejson.ts +47 -0
- package/src/source/pixels_to_tile_units.ts +25 -0
- package/src/source/protocol_crud.ts +48 -0
- package/src/source/query_features.test.ts +31 -0
- package/src/source/query_features.ts +252 -0
- package/src/source/raster_dem_tile_source.test.ts +158 -0
- package/src/source/raster_dem_tile_source.ts +166 -0
- package/src/source/raster_dem_tile_worker_source.test.ts +36 -0
- package/src/source/raster_dem_tile_worker_source.ts +38 -0
- package/src/source/raster_tile_source.test.ts +206 -0
- package/src/source/raster_tile_source.ts +227 -0
- package/src/source/rtl_text_plugin_main_thread.test.ts +170 -0
- package/src/source/rtl_text_plugin_main_thread.ts +89 -0
- package/src/source/rtl_text_plugin_status.ts +33 -0
- package/src/source/rtl_text_plugin_worker.ts +49 -0
- package/src/source/source.test.ts +41 -0
- package/src/source/source.ts +186 -0
- package/src/source/source_cache.test.ts +2069 -0
- package/src/source/source_cache.ts +1102 -0
- package/src/source/source_state.ts +157 -0
- package/src/source/terrain_source_cache.test.ts +105 -0
- package/src/source/terrain_source_cache.ts +204 -0
- package/src/source/tile.test.ts +290 -0
- package/src/source/tile.ts +478 -0
- package/src/source/tile_bounds.ts +34 -0
- package/src/source/tile_cache.test.ts +130 -0
- package/src/source/tile_cache.ts +208 -0
- package/src/source/tile_id.test.ts +112 -0
- package/src/source/tile_id.ts +221 -0
- package/src/source/vector_tile_source.test.ts +401 -0
- package/src/source/vector_tile_source.ts +283 -0
- package/src/source/vector_tile_worker_source.test.ts +396 -0
- package/src/source/vector_tile_worker_source.ts +199 -0
- package/src/source/video_source.test.ts +124 -0
- package/src/source/video_source.ts +204 -0
- package/src/source/worker.test.ts +233 -0
- package/src/source/worker.ts +301 -0
- package/src/source/worker_source.ts +117 -0
- package/src/source/worker_tile.test.ts +226 -0
- package/src/source/worker_tile.ts +208 -0
- package/src/style/create_style_layer.ts +39 -0
- package/src/style/evaluation_parameters.ts +62 -0
- package/src/style/format_section_override.test.ts +62 -0
- package/src/style/format_section_override.ts +50 -0
- package/src/style/light.test.ts +86 -0
- package/src/style/light.ts +135 -0
- package/src/style/load_glyph_range.test.ts +40 -0
- package/src/style/load_glyph_range.ts +32 -0
- package/src/style/load_sprite.test.ts +227 -0
- package/src/style/load_sprite.ts +71 -0
- package/src/style/parse_glyph_pbf.ts +42 -0
- package/src/style/pauseable_placement.ts +138 -0
- package/src/style/properties.ts +726 -0
- package/src/style/query_utils.test.ts +107 -0
- package/src/style/query_utils.ts +70 -0
- package/src/style/sky.ts +127 -0
- package/src/style/style.test.ts +2654 -0
- package/src/style/style.ts +1814 -0
- package/src/style/style_glyph.ts +25 -0
- package/src/style/style_image.ts +188 -0
- package/src/style/style_layer/background_style_layer.ts +17 -0
- package/src/style/style_layer/background_style_layer_properties.g.ts +40 -0
- package/src/style/style_layer/circle_style_layer.ts +98 -0
- package/src/style/style_layer/circle_style_layer_properties.g.ts +76 -0
- package/src/style/style_layer/custom_style_layer.ts +233 -0
- package/src/style/style_layer/fill_extrusion_style_layer.ts +224 -0
- package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +55 -0
- package/src/style/style_layer/fill_style_layer.test.ts +37 -0
- package/src/style/style_layer/fill_style_layer.ts +65 -0
- package/src/style/style_layer/fill_style_layer_properties.g.ts +64 -0
- package/src/style/style_layer/heatmap_style_layer.ts +74 -0
- package/src/style/style_layer/heatmap_style_layer_properties.g.ts +46 -0
- package/src/style/style_layer/hillshade_style_layer.ts +21 -0
- package/src/style/style_layer/hillshade_style_layer_properties.g.ts +49 -0
- package/src/style/style_layer/line_style_layer.test.ts +50 -0
- package/src/style/style_layer/line_style_layer.ts +131 -0
- package/src/style/style_layer/line_style_layer_properties.g.ts +88 -0
- package/src/style/style_layer/overlap_mode.test.ts +57 -0
- package/src/style/style_layer/overlap_mode.ts +25 -0
- package/src/style/style_layer/raster_style_layer.ts +17 -0
- package/src/style/style_layer/raster_style_layer_properties.g.ts +55 -0
- package/src/style/style_layer/symbol_style_layer.ts +195 -0
- package/src/style/style_layer/symbol_style_layer_properties.g.ts +218 -0
- package/src/style/style_layer/typed_style_layer.ts +9 -0
- package/src/style/style_layer/variable_text_anchor.test.ts +117 -0
- package/src/style/style_layer/variable_text_anchor.ts +163 -0
- package/src/style/style_layer.test.ts +372 -0
- package/src/style/style_layer.ts +287 -0
- package/src/style/style_layer_index.test.ts +99 -0
- package/src/style/style_layer_index.ts +78 -0
- package/src/style/validate_style.ts +53 -0
- package/src/style/zoom_history.ts +40 -0
- package/src/symbol/anchor.test.ts +14 -0
- package/src/symbol/anchor.ts +22 -0
- package/src/symbol/check_max_angle.test.ts +54 -0
- package/src/symbol/check_max_angle.ts +76 -0
- package/src/symbol/clip_line.test.ts +154 -0
- package/src/symbol/clip_line.ts +66 -0
- package/src/symbol/collision_feature.test.ts +98 -0
- package/src/symbol/collision_feature.ts +114 -0
- package/src/symbol/collision_index.test.ts +19 -0
- package/src/symbol/collision_index.ts +618 -0
- package/src/symbol/cross_tile_symbol_index.test.ts +260 -0
- package/src/symbol/cross_tile_symbol_index.ts +367 -0
- package/src/symbol/get_anchors.test.ts +113 -0
- package/src/symbol/get_anchors.ts +167 -0
- package/src/symbol/grid_index.test.ts +75 -0
- package/src/symbol/grid_index.ts +414 -0
- package/src/symbol/merge_lines.test.ts +30 -0
- package/src/symbol/merge_lines.ts +80 -0
- package/src/symbol/one_em.ts +3 -0
- package/src/symbol/opacity_state.ts +23 -0
- package/src/symbol/path_interpolator.test.ts +134 -0
- package/src/symbol/path_interpolator.ts +55 -0
- package/src/symbol/placement.ts +1371 -0
- package/src/symbol/projection.test.ts +171 -0
- package/src/symbol/projection.ts +833 -0
- package/src/symbol/quads.test.ts +157 -0
- package/src/symbol/quads.ts +349 -0
- package/src/symbol/shaping.test.ts +360 -0
- package/src/symbol/shaping.ts +911 -0
- package/src/symbol/symbol_layout.ts +739 -0
- package/src/symbol/symbol_size.ts +129 -0
- package/src/symbol/symbol_style_layer.test.ts +103 -0
- package/src/symbol/transform_text.ts +27 -0
- package/src/ui/anchor.ts +27 -0
- package/src/ui/camera.test.ts +2301 -0
- package/src/ui/camera.ts +1520 -0
- package/src/ui/control/attribution_control.test.ts +543 -0
- package/src/ui/control/attribution_control.ts +209 -0
- package/src/ui/control/control.ts +67 -0
- package/src/ui/control/fullscreen_control.test.ts +114 -0
- package/src/ui/control/fullscreen_control.ts +189 -0
- package/src/ui/control/geolocate_control.test.ts +619 -0
- package/src/ui/control/geolocate_control.ts +725 -0
- package/src/ui/control/logo_control.test.ts +88 -0
- package/src/ui/control/logo_control.ts +86 -0
- package/src/ui/control/navigation_control.test.ts +238 -0
- package/src/ui/control/navigation_control.ts +294 -0
- package/src/ui/control/scale_control.test.ts +52 -0
- package/src/ui/control/scale_control.ts +152 -0
- package/src/ui/control/terrain_control.test.ts +58 -0
- package/src/ui/control/terrain_control.ts +74 -0
- package/src/ui/default_locale.ts +25 -0
- package/src/ui/events.ts +758 -0
- package/src/ui/handler/box_zoom.test.ts +163 -0
- package/src/ui/handler/box_zoom.ts +171 -0
- package/src/ui/handler/click_zoom.ts +55 -0
- package/src/ui/handler/cooperative_gestures.test.ts +338 -0
- package/src/ui/handler/cooperative_gestures.ts +111 -0
- package/src/ui/handler/dblclick_zoom.test.ts +151 -0
- package/src/ui/handler/drag_handler.ts +174 -0
- package/src/ui/handler/drag_move_state_manager.ts +115 -0
- package/src/ui/handler/drag_pan.test.ts +487 -0
- package/src/ui/handler/drag_rotate.test.ts +859 -0
- package/src/ui/handler/handler_util.ts +10 -0
- package/src/ui/handler/keyboard.test.ts +235 -0
- package/src/ui/handler/keyboard.ts +212 -0
- package/src/ui/handler/map_event.test.ts +158 -0
- package/src/ui/handler/map_event.ts +161 -0
- package/src/ui/handler/mouse.ts +92 -0
- package/src/ui/handler/mouse_handler_interface.test.ts +111 -0
- package/src/ui/handler/mouse_rotate.test.ts +62 -0
- package/src/ui/handler/one_finger_touch_drag.ts +45 -0
- package/src/ui/handler/one_finger_touch_drag_handler_interface.test.ts +77 -0
- package/src/ui/handler/scroll_zoom.test.ts +382 -0
- package/src/ui/handler/scroll_zoom.ts +379 -0
- package/src/ui/handler/shim/dblclick_zoom.ts +64 -0
- package/src/ui/handler/shim/drag_pan.ts +104 -0
- package/src/ui/handler/shim/drag_rotate.ts +76 -0
- package/src/ui/handler/shim/two_fingers_touch.ts +112 -0
- package/src/ui/handler/tap_drag_zoom.test.ts +113 -0
- package/src/ui/handler/tap_drag_zoom.ts +112 -0
- package/src/ui/handler/tap_recognizer.ts +138 -0
- package/src/ui/handler/tap_zoom.ts +98 -0
- package/src/ui/handler/touch_pan.ts +115 -0
- package/src/ui/handler/transform-provider.ts +44 -0
- package/src/ui/handler/two_fingers_touch.test.ts +283 -0
- package/src/ui/handler/two_fingers_touch.ts +336 -0
- package/src/ui/handler_inertia.ts +157 -0
- package/src/ui/handler_manager.ts +637 -0
- package/src/ui/hash.test.ts +404 -0
- package/src/ui/hash.ts +153 -0
- package/src/ui/map.ts +3393 -0
- package/src/ui/map_tests/map_animation.test.ts +61 -0
- package/src/ui/map_tests/map_basic.test.ts +223 -0
- package/src/ui/map_tests/map_bounds.test.ts +123 -0
- package/src/ui/map_tests/map_calculate_camera_options.test.ts +113 -0
- package/src/ui/map_tests/map_canvas.test.ts +59 -0
- package/src/ui/map_tests/map_control.test.ts +61 -0
- package/src/ui/map_tests/map_disable_handlers.test.ts +38 -0
- package/src/ui/map_tests/map_events.test.ts +1001 -0
- package/src/ui/map_tests/map_feature_state.test.ts +421 -0
- package/src/ui/map_tests/map_images.test.ts +175 -0
- package/src/ui/map_tests/map_is_moving.test.ts +164 -0
- package/src/ui/map_tests/map_is_rotating.test.ts +62 -0
- package/src/ui/map_tests/map_is_zooming.test.ts +86 -0
- package/src/ui/map_tests/map_layer.test.ts +457 -0
- package/src/ui/map_tests/map_options.test.ts +64 -0
- package/src/ui/map_tests/map_pitch.test.ts +90 -0
- package/src/ui/map_tests/map_pixel_ratio.test.ts +75 -0
- package/src/ui/map_tests/map_query_rendered_features.test.ts +93 -0
- package/src/ui/map_tests/map_render.test.ts +90 -0
- package/src/ui/map_tests/map_request_render_frame.test.ts +51 -0
- package/src/ui/map_tests/map_resize.test.ts +120 -0
- package/src/ui/map_tests/map_style.test.ts +541 -0
- package/src/ui/map_tests/map_terrian.test.ts +104 -0
- package/src/ui/map_tests/map_webgl.test.ts +72 -0
- package/src/ui/map_tests/map_world_copies.test.ts +103 -0
- package/src/ui/map_tests/map_zoom.test.ts +95 -0
- package/src/ui/marker.test.ts +1149 -0
- package/src/ui/marker.ts +880 -0
- package/src/ui/popup.test.ts +827 -0
- package/src/ui/popup.ts +717 -0
- package/src/util/abort_error.ts +21 -0
- package/src/util/actor.test.ts +218 -0
- package/src/util/actor.ts +241 -0
- package/src/util/actor_messages.ts +149 -0
- package/src/util/ajax.test.ts +237 -0
- package/src/util/ajax.ts +297 -0
- package/src/util/browser.test.ts +23 -0
- package/src/util/browser.ts +63 -0
- package/src/util/color_ramp.test.ts +105 -0
- package/src/util/color_ramp.ts +56 -0
- package/src/util/config.ts +29 -0
- package/src/util/dictionary_coder.ts +23 -0
- package/src/util/dispatcher.test.ts +76 -0
- package/src/util/dispatcher.ts +78 -0
- package/src/util/dom.ts +135 -0
- package/src/util/evented.test.ts +231 -0
- package/src/util/evented.ts +178 -0
- package/src/util/find_pole_of_inaccessibility.test.ts +21 -0
- package/src/util/find_pole_of_inaccessibility.ts +130 -0
- package/src/util/geolocation_support.test.ts +43 -0
- package/src/util/geolocation_support.ts +23 -0
- package/src/util/global_worker_pool.ts +65 -0
- package/src/util/image.ts +150 -0
- package/src/util/image_request.test.ts +408 -0
- package/src/util/image_request.ts +246 -0
- package/src/util/intersection_tests.ts +206 -0
- package/src/util/is_char_in_unicode_block.test.ts +15 -0
- package/src/util/is_char_in_unicode_block.ts +345 -0
- package/src/util/offscreen_canvas_distorted.test.ts +13 -0
- package/src/util/offscreen_canvas_distorted.ts +39 -0
- package/src/util/offscreen_canvas_supported.ts +11 -0
- package/src/util/performance.ts +117 -0
- package/src/util/primitives.test.ts +140 -0
- package/src/util/primitives.ts +143 -0
- package/src/util/request_manager.ts +42 -0
- package/src/util/resolve_tokens.test.ts +45 -0
- package/src/util/resolve_tokens.ts +17 -0
- package/src/util/script_detection.test.ts +138 -0
- package/src/util/script_detection.ts +376 -0
- package/src/util/smart_wrap.test.ts +97 -0
- package/src/util/smart_wrap.ts +58 -0
- package/src/util/struct_array.test.ts +101 -0
- package/src/util/struct_array.ts +246 -0
- package/src/util/style.test.ts +34 -0
- package/src/util/style.ts +28 -0
- package/src/util/task_queue.test.ts +114 -0
- package/src/util/task_queue.ts +64 -0
- package/src/util/test/util.ts +185 -0
- package/src/util/throttle.test.ts +42 -0
- package/src/util/throttle.ts +28 -0
- package/src/util/throttled_invoker.ts +41 -0
- package/src/util/transferable_grid_index.test.ts +56 -0
- package/src/util/transferable_grid_index.ts +214 -0
- package/src/util/util.test.ts +414 -0
- package/src/util/util.ts +724 -0
- package/src/util/vectortile_to_geojson.ts +72 -0
- package/src/util/verticalize_punctuation.ts +110 -0
- package/src/util/web_worker.ts +16 -0
- package/src/util/web_worker_transfer.test.ts +153 -0
- package/src/util/web_worker_transfer.ts +254 -0
- package/src/util/webp_supported.ts +63 -0
- package/src/util/worker_pool.test.ts +43 -0
- package/src/util/worker_pool.ts +58 -0
- package/src/util/world_bounds.test.ts +59 -0
- 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
|
+
}
|