@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,1072 @@
|
|
|
1
|
+
import {LngLat} from './lng_lat';
|
|
2
|
+
import {LngLatBounds} from './lng_lat_bounds';
|
|
3
|
+
import {MercatorCoordinate, mercatorXfromLng, mercatorYfromLat, mercatorZfromAltitude} from './mercator_coordinate';
|
|
4
|
+
import Point from '@mapbox/point-geometry';
|
|
5
|
+
import {wrap, clamp} from '../util/util';
|
|
6
|
+
import {interpolates} from '@maplibre/maplibre-gl-style-spec';
|
|
7
|
+
import {EXTENT} from '../data/extent';
|
|
8
|
+
import {vec3, vec4, mat4, mat2, vec2} from 'gl-matrix';
|
|
9
|
+
import {Aabb, Frustum} from '../util/primitives';
|
|
10
|
+
import {EdgeInsets} from './edge_insets';
|
|
11
|
+
|
|
12
|
+
import {UnwrappedTileID, OverscaledTileID, CanonicalTileID} from '../source/tile_id';
|
|
13
|
+
import type {PaddingOptions} from './edge_insets';
|
|
14
|
+
import {Terrain} from '../render/terrain';
|
|
15
|
+
|
|
16
|
+
export const MAX_VALID_LATITUDE = 85.051129;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
* A single transform, generally used for a single tile to be
|
|
21
|
+
* scaled, rotated, and zoomed.
|
|
22
|
+
*/
|
|
23
|
+
export class Transform {
|
|
24
|
+
tileSize: number;
|
|
25
|
+
tileZoom: number;
|
|
26
|
+
lngRange: [number, number];
|
|
27
|
+
latRange: [number, number];
|
|
28
|
+
scale: number;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
angle: number;
|
|
32
|
+
rotationMatrix: mat2;
|
|
33
|
+
pixelsToGLUnits: [number, number];
|
|
34
|
+
cameraToCenterDistance: number;
|
|
35
|
+
mercatorMatrix: mat4;
|
|
36
|
+
projectionMatrix: mat4;
|
|
37
|
+
modelViewProjectionMatrix: mat4;
|
|
38
|
+
invModelViewProjectionMatrix: mat4;
|
|
39
|
+
alignedModelViewProjectionMatrix: mat4;
|
|
40
|
+
fogMatrix: mat4;
|
|
41
|
+
pixelMatrix: mat4;
|
|
42
|
+
pixelMatrix3D: mat4;
|
|
43
|
+
pixelMatrixInverse: mat4;
|
|
44
|
+
glCoordMatrix: mat4;
|
|
45
|
+
labelPlaneMatrix: mat4;
|
|
46
|
+
minElevationForCurrentTile: number;
|
|
47
|
+
_fov: number;
|
|
48
|
+
_pitch: number;
|
|
49
|
+
_zoom: number;
|
|
50
|
+
_unmodified: boolean;
|
|
51
|
+
_renderWorldCopies: boolean;
|
|
52
|
+
_minZoom: number;
|
|
53
|
+
_maxZoom: number;
|
|
54
|
+
_minPitch: number;
|
|
55
|
+
_maxPitch: number;
|
|
56
|
+
_center: LngLat;
|
|
57
|
+
_elevation: number;
|
|
58
|
+
_pixelPerMeter: number;
|
|
59
|
+
_edgeInsets: EdgeInsets;
|
|
60
|
+
_constraining: boolean;
|
|
61
|
+
_posMatrixCache: {[_: string]: mat4};
|
|
62
|
+
_alignedPosMatrixCache: {[_: string]: mat4};
|
|
63
|
+
_fogMatrixCache: {[_: string]: mat4};
|
|
64
|
+
/**
|
|
65
|
+
* This value represents the distance from the camera to the far clipping plane.
|
|
66
|
+
* It is used in the calculation of the projection matrix to determine which objects are visible.
|
|
67
|
+
* farZ should be larger than nearZ.
|
|
68
|
+
*/
|
|
69
|
+
farZ: number;
|
|
70
|
+
/**
|
|
71
|
+
* This value represents the distance from the camera to the near clipping plane.
|
|
72
|
+
* It is used in the calculation of the projection matrix to determine which objects are visible.
|
|
73
|
+
* nearZ should be smaller than farZ.
|
|
74
|
+
*/
|
|
75
|
+
nearZ: number;
|
|
76
|
+
|
|
77
|
+
constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean) {
|
|
78
|
+
this.tileSize = 512; // constant
|
|
79
|
+
|
|
80
|
+
this._renderWorldCopies = renderWorldCopies === undefined ? true : !!renderWorldCopies;
|
|
81
|
+
this._minZoom = minZoom || 0;
|
|
82
|
+
this._maxZoom = maxZoom || 22;
|
|
83
|
+
|
|
84
|
+
this._minPitch = (minPitch === undefined || minPitch === null) ? 0 : minPitch;
|
|
85
|
+
this._maxPitch = (maxPitch === undefined || maxPitch === null) ? 60 : maxPitch;
|
|
86
|
+
|
|
87
|
+
this.setMaxBounds();
|
|
88
|
+
|
|
89
|
+
this.width = 0;
|
|
90
|
+
this.height = 0;
|
|
91
|
+
this._center = new LngLat(0, 0);
|
|
92
|
+
this._elevation = 0;
|
|
93
|
+
this.zoom = 0;
|
|
94
|
+
this.angle = 0;
|
|
95
|
+
this._fov = 0.6435011087932844;
|
|
96
|
+
this._pitch = 0;
|
|
97
|
+
this._unmodified = true;
|
|
98
|
+
this._edgeInsets = new EdgeInsets();
|
|
99
|
+
this._posMatrixCache = {};
|
|
100
|
+
this._alignedPosMatrixCache = {};
|
|
101
|
+
this._fogMatrixCache = {};
|
|
102
|
+
this.minElevationForCurrentTile = 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
clone(): Transform {
|
|
106
|
+
const clone = new Transform(this._minZoom, this._maxZoom, this._minPitch, this.maxPitch, this._renderWorldCopies);
|
|
107
|
+
clone.apply(this);
|
|
108
|
+
return clone;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
apply(that: Transform) {
|
|
112
|
+
this.tileSize = that.tileSize;
|
|
113
|
+
this.latRange = that.latRange;
|
|
114
|
+
this.lngRange = that.lngRange;
|
|
115
|
+
this.width = that.width;
|
|
116
|
+
this.height = that.height;
|
|
117
|
+
this._center = that._center;
|
|
118
|
+
this._elevation = that._elevation;
|
|
119
|
+
this.minElevationForCurrentTile = that.minElevationForCurrentTile;
|
|
120
|
+
this.zoom = that.zoom;
|
|
121
|
+
this.angle = that.angle;
|
|
122
|
+
this._fov = that._fov;
|
|
123
|
+
this._pitch = that._pitch;
|
|
124
|
+
this._unmodified = that._unmodified;
|
|
125
|
+
this._edgeInsets = that._edgeInsets.clone();
|
|
126
|
+
this._calcMatrices();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get minZoom(): number { return this._minZoom; }
|
|
130
|
+
set minZoom(zoom: number) {
|
|
131
|
+
if (this._minZoom === zoom) return;
|
|
132
|
+
this._minZoom = zoom;
|
|
133
|
+
this.zoom = Math.max(this.zoom, zoom);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
get maxZoom(): number { return this._maxZoom; }
|
|
137
|
+
set maxZoom(zoom: number) {
|
|
138
|
+
if (this._maxZoom === zoom) return;
|
|
139
|
+
this._maxZoom = zoom;
|
|
140
|
+
this.zoom = Math.min(this.zoom, zoom);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get minPitch(): number { return this._minPitch; }
|
|
144
|
+
set minPitch(pitch: number) {
|
|
145
|
+
if (this._minPitch === pitch) return;
|
|
146
|
+
this._minPitch = pitch;
|
|
147
|
+
this.pitch = Math.max(this.pitch, pitch);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get maxPitch(): number { return this._maxPitch; }
|
|
151
|
+
set maxPitch(pitch: number) {
|
|
152
|
+
if (this._maxPitch === pitch) return;
|
|
153
|
+
this._maxPitch = pitch;
|
|
154
|
+
this.pitch = Math.min(this.pitch, pitch);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
get renderWorldCopies(): boolean { return this._renderWorldCopies; }
|
|
158
|
+
set renderWorldCopies(renderWorldCopies: boolean) {
|
|
159
|
+
if (renderWorldCopies === undefined) {
|
|
160
|
+
renderWorldCopies = true;
|
|
161
|
+
} else if (renderWorldCopies === null) {
|
|
162
|
+
renderWorldCopies = false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
this._renderWorldCopies = renderWorldCopies;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
get worldSize(): number {
|
|
169
|
+
return this.tileSize * this.scale;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
get centerOffset(): Point {
|
|
173
|
+
return this.centerPoint._sub(this.size._div(2));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
get size(): Point {
|
|
177
|
+
return new Point(this.width, this.height);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
get bearing(): number {
|
|
181
|
+
return -this.angle / Math.PI * 180;
|
|
182
|
+
}
|
|
183
|
+
set bearing(bearing: number) {
|
|
184
|
+
const b = -wrap(bearing, -180, 180) * Math.PI / 180;
|
|
185
|
+
if (this.angle === b) return;
|
|
186
|
+
this._unmodified = false;
|
|
187
|
+
this.angle = b;
|
|
188
|
+
this._calcMatrices();
|
|
189
|
+
|
|
190
|
+
// 2x2 matrix for rotating points
|
|
191
|
+
this.rotationMatrix = mat2.create();
|
|
192
|
+
mat2.rotate(this.rotationMatrix, this.rotationMatrix, this.angle);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
get pitch(): number {
|
|
196
|
+
return this._pitch / Math.PI * 180;
|
|
197
|
+
}
|
|
198
|
+
set pitch(pitch: number) {
|
|
199
|
+
const p = clamp(pitch, this.minPitch, this.maxPitch) / 180 * Math.PI;
|
|
200
|
+
if (this._pitch === p) return;
|
|
201
|
+
this._unmodified = false;
|
|
202
|
+
this._pitch = p;
|
|
203
|
+
this._calcMatrices();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
get fov(): number {
|
|
207
|
+
return this._fov / Math.PI * 180;
|
|
208
|
+
}
|
|
209
|
+
set fov(fov: number) {
|
|
210
|
+
fov = Math.max(0.01, Math.min(60, fov));
|
|
211
|
+
if (this._fov === fov) return;
|
|
212
|
+
this._unmodified = false;
|
|
213
|
+
this._fov = fov / 180 * Math.PI;
|
|
214
|
+
this._calcMatrices();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get zoom(): number { return this._zoom; }
|
|
218
|
+
set zoom(zoom: number) {
|
|
219
|
+
const constrainedZoom = Math.min(Math.max(zoom, this.minZoom), this.maxZoom);
|
|
220
|
+
if (this._zoom === constrainedZoom) return;
|
|
221
|
+
this._unmodified = false;
|
|
222
|
+
this._zoom = constrainedZoom;
|
|
223
|
+
this.tileZoom = Math.max(0, Math.floor(constrainedZoom));
|
|
224
|
+
this.scale = this.zoomScale(constrainedZoom);
|
|
225
|
+
this._constrain();
|
|
226
|
+
this._calcMatrices();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
get center(): LngLat { return this._center; }
|
|
230
|
+
set center(center: LngLat) {
|
|
231
|
+
if (center.lat === this._center.lat && center.lng === this._center.lng) return;
|
|
232
|
+
this._unmodified = false;
|
|
233
|
+
this._center = center;
|
|
234
|
+
this._constrain();
|
|
235
|
+
this._calcMatrices();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Elevation at current center point, meters above sea level
|
|
240
|
+
*/
|
|
241
|
+
get elevation(): number { return this._elevation; }
|
|
242
|
+
set elevation(elevation: number) {
|
|
243
|
+
if (elevation === this._elevation) return;
|
|
244
|
+
this._elevation = elevation;
|
|
245
|
+
this._constrain();
|
|
246
|
+
this._calcMatrices();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
get padding(): PaddingOptions { return this._edgeInsets.toJSON(); }
|
|
250
|
+
set padding(padding: PaddingOptions) {
|
|
251
|
+
if (this._edgeInsets.equals(padding)) return;
|
|
252
|
+
this._unmodified = false;
|
|
253
|
+
//Update edge-insets in place
|
|
254
|
+
this._edgeInsets.interpolate(this._edgeInsets, padding, 1);
|
|
255
|
+
this._calcMatrices();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* The center of the screen in pixels with the top-left corner being (0,0)
|
|
260
|
+
* and +y axis pointing downwards. This accounts for padding.
|
|
261
|
+
*/
|
|
262
|
+
get centerPoint(): Point {
|
|
263
|
+
return this._edgeInsets.getCenter(this.width, this.height);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Returns if the padding params match
|
|
268
|
+
*
|
|
269
|
+
* @param padding - the padding to check against
|
|
270
|
+
* @returns true if they are equal, false otherwise
|
|
271
|
+
*/
|
|
272
|
+
isPaddingEqual(padding: PaddingOptions): boolean {
|
|
273
|
+
return this._edgeInsets.equals(padding);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Helper method to update edge-insets in place
|
|
278
|
+
*
|
|
279
|
+
* @param start - the starting padding
|
|
280
|
+
* @param target - the target padding
|
|
281
|
+
* @param t - the step/weight
|
|
282
|
+
*/
|
|
283
|
+
interpolatePadding(start: PaddingOptions, target: PaddingOptions, t: number) {
|
|
284
|
+
this._unmodified = false;
|
|
285
|
+
this._edgeInsets.interpolate(start, target, t);
|
|
286
|
+
this._constrain();
|
|
287
|
+
this._calcMatrices();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Return a zoom level that will cover all tiles the transform
|
|
292
|
+
* @param options - the options
|
|
293
|
+
* @returns zoom level An integer zoom level at which all tiles will be visible.
|
|
294
|
+
*/
|
|
295
|
+
coveringZoomLevel(options: {
|
|
296
|
+
/**
|
|
297
|
+
* Target zoom level. If true, the value will be rounded to the closest integer. Otherwise the value will be floored.
|
|
298
|
+
*/
|
|
299
|
+
roundZoom?: boolean;
|
|
300
|
+
/**
|
|
301
|
+
* Tile size, expressed in screen pixels.
|
|
302
|
+
*/
|
|
303
|
+
tileSize: number;
|
|
304
|
+
}): number {
|
|
305
|
+
const z = (options.roundZoom ? Math.round : Math.floor)(
|
|
306
|
+
this.zoom + this.scaleZoom(this.tileSize / options.tileSize)
|
|
307
|
+
);
|
|
308
|
+
// At negative zoom levels load tiles from z0 because negative tile zoom levels don't exist.
|
|
309
|
+
return Math.max(0, z);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Return any "wrapped" copies of a given tile coordinate that are visible
|
|
314
|
+
* in the current view.
|
|
315
|
+
*/
|
|
316
|
+
getVisibleUnwrappedCoordinates(tileID: CanonicalTileID) {
|
|
317
|
+
const result = [new UnwrappedTileID(0, tileID)];
|
|
318
|
+
if (this._renderWorldCopies) {
|
|
319
|
+
const utl = this.pointCoordinate(new Point(0, 0));
|
|
320
|
+
const utr = this.pointCoordinate(new Point(this.width, 0));
|
|
321
|
+
const ubl = this.pointCoordinate(new Point(this.width, this.height));
|
|
322
|
+
const ubr = this.pointCoordinate(new Point(0, this.height));
|
|
323
|
+
const w0 = Math.floor(Math.min(utl.x, utr.x, ubl.x, ubr.x));
|
|
324
|
+
const w1 = Math.floor(Math.max(utl.x, utr.x, ubl.x, ubr.x));
|
|
325
|
+
|
|
326
|
+
// Add an extra copy of the world on each side to properly render ImageSources and CanvasSources.
|
|
327
|
+
// Both sources draw outside the tile boundaries of the tile that "contains them" so we need
|
|
328
|
+
// to add extra copies on both sides in case offscreen tiles need to draw into on-screen ones.
|
|
329
|
+
const extraWorldCopy = 1;
|
|
330
|
+
|
|
331
|
+
for (let w = w0 - extraWorldCopy; w <= w1 + extraWorldCopy; w++) {
|
|
332
|
+
if (w === 0) continue;
|
|
333
|
+
result.push(new UnwrappedTileID(w, tileID));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Return all coordinates that could cover this transform for a covering
|
|
341
|
+
* zoom level.
|
|
342
|
+
* @param options - the options
|
|
343
|
+
* @returns OverscaledTileIDs
|
|
344
|
+
*/
|
|
345
|
+
coveringTiles(
|
|
346
|
+
options: {
|
|
347
|
+
tileSize: number;
|
|
348
|
+
minzoom?: number;
|
|
349
|
+
maxzoom?: number;
|
|
350
|
+
roundZoom?: boolean;
|
|
351
|
+
reparseOverscaled?: boolean;
|
|
352
|
+
renderWorldCopies?: boolean;
|
|
353
|
+
terrain?: Terrain;
|
|
354
|
+
}
|
|
355
|
+
): Array<OverscaledTileID> {
|
|
356
|
+
let z = this.coveringZoomLevel(options);
|
|
357
|
+
const actualZ = z;
|
|
358
|
+
|
|
359
|
+
if (options.minzoom !== undefined && z < options.minzoom) return [];
|
|
360
|
+
if (options.maxzoom !== undefined && z > options.maxzoom) z = options.maxzoom;
|
|
361
|
+
|
|
362
|
+
const cameraCoord = this.pointCoordinate(this.getCameraPoint());
|
|
363
|
+
const centerCoord = MercatorCoordinate.fromLngLat(this.center);
|
|
364
|
+
const numTiles = Math.pow(2, z);
|
|
365
|
+
const cameraPoint = [numTiles * cameraCoord.x, numTiles * cameraCoord.y, 0];
|
|
366
|
+
const centerPoint = [numTiles * centerCoord.x, numTiles * centerCoord.y, 0];
|
|
367
|
+
const cameraFrustum = Frustum.fromInvProjectionMatrix(this.invModelViewProjectionMatrix, this.worldSize, z);
|
|
368
|
+
|
|
369
|
+
// No change of LOD behavior for pitch lower than 60 and when there is no top padding: return only tile ids from the requested zoom level
|
|
370
|
+
let minZoom = options.minzoom || 0;
|
|
371
|
+
// Use 0.1 as an epsilon to avoid for explicit == 0.0 floating point checks
|
|
372
|
+
if (!options.terrain && this.pitch <= 60.0 && this._edgeInsets.top < 0.1)
|
|
373
|
+
minZoom = z;
|
|
374
|
+
|
|
375
|
+
// There should always be a certain number of maximum zoom level tiles surrounding the center location in 2D or in front of the camera in 3D
|
|
376
|
+
const radiusOfMaxLvlLodInTiles = options.terrain ? 2 / Math.min(this.tileSize, options.tileSize) * this.tileSize : 3;
|
|
377
|
+
|
|
378
|
+
const newRootTile = (wrap: number): any => {
|
|
379
|
+
return {
|
|
380
|
+
aabb: new Aabb([wrap * numTiles, 0, 0], [(wrap + 1) * numTiles, numTiles, 0]),
|
|
381
|
+
zoom: 0,
|
|
382
|
+
x: 0,
|
|
383
|
+
y: 0,
|
|
384
|
+
wrap,
|
|
385
|
+
fullyVisible: false
|
|
386
|
+
};
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// Do a depth-first traversal to find visible tiles and proper levels of detail
|
|
390
|
+
const stack = [];
|
|
391
|
+
const result = [];
|
|
392
|
+
const maxZoom = z;
|
|
393
|
+
const overscaledZ = options.reparseOverscaled ? actualZ : z;
|
|
394
|
+
|
|
395
|
+
if (this._renderWorldCopies) {
|
|
396
|
+
// Render copy of the globe thrice on both sides
|
|
397
|
+
for (let i = 1; i <= 3; i++) {
|
|
398
|
+
stack.push(newRootTile(-i));
|
|
399
|
+
stack.push(newRootTile(i));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
stack.push(newRootTile(0));
|
|
404
|
+
|
|
405
|
+
while (stack.length > 0) {
|
|
406
|
+
const it = stack.pop();
|
|
407
|
+
const x = it.x;
|
|
408
|
+
const y = it.y;
|
|
409
|
+
let fullyVisible = it.fullyVisible;
|
|
410
|
+
|
|
411
|
+
// Visibility of a tile is not required if any of its ancestor if fully inside the frustum
|
|
412
|
+
if (!fullyVisible) {
|
|
413
|
+
const intersectResult = it.aabb.intersects(cameraFrustum);
|
|
414
|
+
|
|
415
|
+
if (intersectResult === 0)
|
|
416
|
+
continue;
|
|
417
|
+
|
|
418
|
+
fullyVisible = intersectResult === 2;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const refPoint = options.terrain ? cameraPoint : centerPoint;
|
|
422
|
+
const distanceX = it.aabb.distanceX(refPoint);
|
|
423
|
+
const distanceY = it.aabb.distanceY(refPoint);
|
|
424
|
+
const longestDim = Math.max(Math.abs(distanceX), Math.abs(distanceY));
|
|
425
|
+
|
|
426
|
+
// We're using distance based heuristics to determine if a tile should be split into quadrants or not.
|
|
427
|
+
// radiusOfMaxLvlLodInTiles defines that there's always a certain number of maxLevel tiles next to the map center.
|
|
428
|
+
// Using the fact that a parent node in quadtree is twice the size of its children (per dimension)
|
|
429
|
+
// we can define distance thresholds for each relative level:
|
|
430
|
+
// f(k) = offset + 2 + 4 + 8 + 16 + ... + 2^k. This is the same as "offset+2^(k+1)-2"
|
|
431
|
+
const distToSplit = radiusOfMaxLvlLodInTiles + (1 << (maxZoom - it.zoom)) - 2;
|
|
432
|
+
|
|
433
|
+
// Have we reached the target depth or is the tile too far away to be any split further?
|
|
434
|
+
if (it.zoom === maxZoom || (longestDim > distToSplit && it.zoom >= minZoom)) {
|
|
435
|
+
const dz = maxZoom - it.zoom, dx = cameraPoint[0] - 0.5 - (x << dz), dy = cameraPoint[1] - 0.5 - (y << dz);
|
|
436
|
+
result.push({
|
|
437
|
+
tileID: new OverscaledTileID(it.zoom === maxZoom ? overscaledZ : it.zoom, it.wrap, it.zoom, x, y),
|
|
438
|
+
distanceSq: vec2.sqrLen([centerPoint[0] - 0.5 - x, centerPoint[1] - 0.5 - y]),
|
|
439
|
+
// this variable is currently not used, but may be important to reduce the amount of loaded tiles
|
|
440
|
+
tileDistanceToCamera: Math.sqrt(dx * dx + dy * dy)
|
|
441
|
+
});
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
for (let i = 0; i < 4; i++) {
|
|
446
|
+
const childX = (x << 1) + (i % 2);
|
|
447
|
+
const childY = (y << 1) + (i >> 1);
|
|
448
|
+
const childZ = it.zoom + 1;
|
|
449
|
+
let quadrant = it.aabb.quadrant(i);
|
|
450
|
+
if (options.terrain) {
|
|
451
|
+
const tileID = new OverscaledTileID(childZ, it.wrap, childZ, childX, childY);
|
|
452
|
+
const minMax = options.terrain.getMinMaxElevation(tileID);
|
|
453
|
+
const minElevation = minMax.minElevation ?? this.elevation;
|
|
454
|
+
const maxElevation = minMax.maxElevation ?? this.elevation;
|
|
455
|
+
quadrant = new Aabb(
|
|
456
|
+
[quadrant.min[0], quadrant.min[1], minElevation] as vec3,
|
|
457
|
+
[quadrant.max[0], quadrant.max[1], maxElevation] as vec3
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
stack.push({aabb: quadrant, zoom: childZ, x: childX, y: childY, wrap: it.wrap, fullyVisible});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return result.sort((a, b) => a.distanceSq - b.distanceSq).map(a => a.tileID);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
resize(width: number, height: number) {
|
|
468
|
+
this.width = width;
|
|
469
|
+
this.height = height;
|
|
470
|
+
|
|
471
|
+
this.pixelsToGLUnits = [2 / width, -2 / height];
|
|
472
|
+
this._constrain();
|
|
473
|
+
this._calcMatrices();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
get unmodified(): boolean { return this._unmodified; }
|
|
477
|
+
|
|
478
|
+
zoomScale(zoom: number) { return Math.pow(2, zoom); }
|
|
479
|
+
scaleZoom(scale: number) { return Math.log(scale) / Math.LN2; }
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Convert from LngLat to world coordinates (Mercator coordinates scaled by 512)
|
|
483
|
+
* @param lnglat - the lngLat
|
|
484
|
+
* @returns Point
|
|
485
|
+
*/
|
|
486
|
+
project(lnglat: LngLat) {
|
|
487
|
+
const lat = clamp(lnglat.lat, -MAX_VALID_LATITUDE, MAX_VALID_LATITUDE);
|
|
488
|
+
return new Point(
|
|
489
|
+
mercatorXfromLng(lnglat.lng) * this.worldSize,
|
|
490
|
+
mercatorYfromLat(lat) * this.worldSize);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Convert from world coordinates ([0, 512],[0, 512]) to LngLat ([-180, 180], [-90, 90])
|
|
495
|
+
* @param point - world coordinate
|
|
496
|
+
* @returns LngLat
|
|
497
|
+
*/
|
|
498
|
+
unproject(point: Point): LngLat {
|
|
499
|
+
return new MercatorCoordinate(point.x / this.worldSize, point.y / this.worldSize).toLngLat();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
get point(): Point { return this.project(this.center); }
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* get the camera position in LngLat and altitudes in meter
|
|
506
|
+
* @returns An object with lngLat & altitude.
|
|
507
|
+
*/
|
|
508
|
+
getCameraPosition(): {
|
|
509
|
+
lngLat: LngLat;
|
|
510
|
+
altitude: number;
|
|
511
|
+
} {
|
|
512
|
+
const lngLat = this.pointLocation(this.getCameraPoint());
|
|
513
|
+
const altitude = Math.cos(this._pitch) * this.cameraToCenterDistance / this._pixelPerMeter;
|
|
514
|
+
return {lngLat, altitude: altitude + this.elevation};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* This method works in combination with freezeElevation activated.
|
|
519
|
+
* freezeElevation is enabled during map-panning because during this the camera should sit in constant height.
|
|
520
|
+
* After panning finished, call this method to recalculate the zoomlevel for the current camera-height in current terrain.
|
|
521
|
+
* @param terrain - the terrain
|
|
522
|
+
*/
|
|
523
|
+
recalculateZoom(terrain: Terrain) {
|
|
524
|
+
const origElevation = this.elevation;
|
|
525
|
+
const origAltitude = Math.cos(this._pitch) * this.cameraToCenterDistance / this._pixelPerMeter;
|
|
526
|
+
|
|
527
|
+
// find position the camera is looking on
|
|
528
|
+
const center = this.pointLocation(this.centerPoint, terrain);
|
|
529
|
+
const elevation = terrain.getElevationForLngLatZoom(center, this.tileZoom);
|
|
530
|
+
const deltaElevation = this.elevation - elevation;
|
|
531
|
+
if (!deltaElevation) return;
|
|
532
|
+
|
|
533
|
+
// The camera's altitude off the ground + the ground's elevation = a constant:
|
|
534
|
+
// this means the camera stays at the same total height.
|
|
535
|
+
const requiredAltitude = origAltitude + origElevation - elevation;
|
|
536
|
+
// Since altitude = Math.cos(this._pitch) * this.cameraToCenterDistance / pixelPerMeter:
|
|
537
|
+
const requiredPixelPerMeter = Math.cos(this._pitch) * this.cameraToCenterDistance / requiredAltitude;
|
|
538
|
+
// Since pixelPerMeter = mercatorZfromAltitude(1, center.lat) * worldSize:
|
|
539
|
+
const requiredWorldSize = requiredPixelPerMeter / mercatorZfromAltitude(1, center.lat);
|
|
540
|
+
// Since worldSize = this.tileSize * scale:
|
|
541
|
+
const requiredScale = requiredWorldSize / this.tileSize;
|
|
542
|
+
const zoom = this.scaleZoom(requiredScale);
|
|
543
|
+
|
|
544
|
+
// update matrices
|
|
545
|
+
this._elevation = elevation;
|
|
546
|
+
this._center = center;
|
|
547
|
+
this.zoom = zoom;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
setLocationAtPoint(lnglat: LngLat, point: Point) {
|
|
551
|
+
const a = this.pointCoordinate(point);
|
|
552
|
+
const b = this.pointCoordinate(this.centerPoint);
|
|
553
|
+
const loc = this.locationCoordinate(lnglat);
|
|
554
|
+
const newCenter = new MercatorCoordinate(
|
|
555
|
+
loc.x - (a.x - b.x),
|
|
556
|
+
loc.y - (a.y - b.y));
|
|
557
|
+
this.center = this.coordinateLocation(newCenter);
|
|
558
|
+
if (this._renderWorldCopies) {
|
|
559
|
+
this.center = this.center.wrap();
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Given a LngLat location, return the screen point that corresponds to it
|
|
565
|
+
* @param lnglat - location
|
|
566
|
+
* @param terrain - optional terrain
|
|
567
|
+
* @returns screen point
|
|
568
|
+
*/
|
|
569
|
+
locationPoint(lnglat: LngLat, terrain?: Terrain): Point {
|
|
570
|
+
return terrain ?
|
|
571
|
+
this.coordinatePoint(this.locationCoordinate(lnglat), terrain.getElevationForLngLatZoom(lnglat, this.tileZoom), this.pixelMatrix3D) :
|
|
572
|
+
this.coordinatePoint(this.locationCoordinate(lnglat));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Given a point on screen, return its lnglat
|
|
577
|
+
* @param p - screen point
|
|
578
|
+
* @param terrain - optional terrain
|
|
579
|
+
* @returns lnglat location
|
|
580
|
+
*/
|
|
581
|
+
pointLocation(p: Point, terrain?: Terrain): LngLat {
|
|
582
|
+
return this.coordinateLocation(this.pointCoordinate(p, terrain));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Given a geographical lnglat, return an unrounded
|
|
587
|
+
* coordinate that represents it at low zoom level.
|
|
588
|
+
* @param lnglat - the location
|
|
589
|
+
* @returns The mercator coordinate
|
|
590
|
+
*/
|
|
591
|
+
locationCoordinate(lnglat: LngLat): MercatorCoordinate {
|
|
592
|
+
return MercatorCoordinate.fromLngLat(lnglat);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Given a Coordinate, return its geographical position.
|
|
597
|
+
* @param coord - mercator coordinates
|
|
598
|
+
* @returns lng and lat
|
|
599
|
+
*/
|
|
600
|
+
coordinateLocation(coord: MercatorCoordinate): LngLat {
|
|
601
|
+
return coord && coord.toLngLat();
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Given a Point, return its mercator coordinate.
|
|
606
|
+
* @param p - the point
|
|
607
|
+
* @param terrain - optional terrain
|
|
608
|
+
* @returns lnglat
|
|
609
|
+
*/
|
|
610
|
+
pointCoordinate(p: Point, terrain?: Terrain): MercatorCoordinate {
|
|
611
|
+
// get point-coordinate from terrain coordinates framebuffer
|
|
612
|
+
if (terrain) {
|
|
613
|
+
const coordinate = terrain.pointCoordinate(p);
|
|
614
|
+
if (coordinate != null) {
|
|
615
|
+
return coordinate;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// calculate point-coordinate on flat earth
|
|
620
|
+
const targetZ = 0;
|
|
621
|
+
// since we don't know the correct projected z value for the point,
|
|
622
|
+
// unproject two points to get a line and then find the point on that
|
|
623
|
+
// line with z=0
|
|
624
|
+
|
|
625
|
+
const coord0 = [p.x, p.y, 0, 1] as vec4;
|
|
626
|
+
const coord1 = [p.x, p.y, 1, 1] as vec4;
|
|
627
|
+
|
|
628
|
+
vec4.transformMat4(coord0, coord0, this.pixelMatrixInverse);
|
|
629
|
+
vec4.transformMat4(coord1, coord1, this.pixelMatrixInverse);
|
|
630
|
+
|
|
631
|
+
const w0 = coord0[3];
|
|
632
|
+
const w1 = coord1[3];
|
|
633
|
+
const x0 = coord0[0] / w0;
|
|
634
|
+
const x1 = coord1[0] / w1;
|
|
635
|
+
const y0 = coord0[1] / w0;
|
|
636
|
+
const y1 = coord1[1] / w1;
|
|
637
|
+
const z0 = coord0[2] / w0;
|
|
638
|
+
const z1 = coord1[2] / w1;
|
|
639
|
+
|
|
640
|
+
const t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0);
|
|
641
|
+
|
|
642
|
+
return new MercatorCoordinate(
|
|
643
|
+
interpolates.number(x0, x1, t) / this.worldSize,
|
|
644
|
+
interpolates.number(y0, y1, t) / this.worldSize);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Given a coordinate, return the screen point that corresponds to it
|
|
649
|
+
* @param coord - the coordinates
|
|
650
|
+
* @param elevation - the elevation
|
|
651
|
+
* @param pixelMatrix - the pixel matrix
|
|
652
|
+
* @returns screen point
|
|
653
|
+
*/
|
|
654
|
+
coordinatePoint(coord: MercatorCoordinate, elevation: number = 0, pixelMatrix = this.pixelMatrix): Point {
|
|
655
|
+
const p = [coord.x * this.worldSize, coord.y * this.worldSize, elevation, 1] as vec4;
|
|
656
|
+
vec4.transformMat4(p, p, pixelMatrix);
|
|
657
|
+
return new Point(p[0] / p[3], p[1] / p[3]);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Returns the map's geographical bounds. When the bearing or pitch is non-zero, the visible region is not
|
|
662
|
+
* an axis-aligned rectangle, and the result is the smallest bounds that encompasses the visible region.
|
|
663
|
+
* @returns Returns a {@link LngLatBounds} object describing the map's geographical bounds.
|
|
664
|
+
*/
|
|
665
|
+
getBounds(): LngLatBounds {
|
|
666
|
+
const top = Math.max(0, this.height / 2 - this.getHorizon());
|
|
667
|
+
return new LngLatBounds()
|
|
668
|
+
.extend(this.pointLocation(new Point(0, top)))
|
|
669
|
+
.extend(this.pointLocation(new Point(this.width, top)))
|
|
670
|
+
.extend(this.pointLocation(new Point(this.width, this.height)))
|
|
671
|
+
.extend(this.pointLocation(new Point(0, this.height)));
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Returns the maximum geographical bounds the map is constrained to, or `null` if none set.
|
|
676
|
+
* @returns max bounds
|
|
677
|
+
*/
|
|
678
|
+
getMaxBounds(): LngLatBounds | null {
|
|
679
|
+
if (!this.latRange || this.latRange.length !== 2 ||
|
|
680
|
+
!this.lngRange || this.lngRange.length !== 2) return null;
|
|
681
|
+
|
|
682
|
+
return new LngLatBounds([this.lngRange[0], this.latRange[0]], [this.lngRange[1], this.latRange[1]]);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Calculate pixel height of the visible horizon in relation to map-center (e.g. height/2),
|
|
687
|
+
* multiplied by a static factor to simulate the earth-radius.
|
|
688
|
+
* The calculated value is the horizontal line from the camera-height to sea-level.
|
|
689
|
+
* @returns Horizon above center in pixels.
|
|
690
|
+
*/
|
|
691
|
+
getHorizon(): number {
|
|
692
|
+
return Math.tan(Math.PI / 2 - this._pitch) * this.cameraToCenterDistance * 0.85;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Sets or clears the map's geographical constraints.
|
|
697
|
+
* @param bounds - A {@link LngLatBounds} object describing the new geographic boundaries of the map.
|
|
698
|
+
*/
|
|
699
|
+
setMaxBounds(bounds?: LngLatBounds | null) {
|
|
700
|
+
if (bounds) {
|
|
701
|
+
this.lngRange = [bounds.getWest(), bounds.getEast()];
|
|
702
|
+
this.latRange = [bounds.getSouth(), bounds.getNorth()];
|
|
703
|
+
this._constrain();
|
|
704
|
+
} else {
|
|
705
|
+
this.lngRange = null;
|
|
706
|
+
this.latRange = [-MAX_VALID_LATITUDE, MAX_VALID_LATITUDE];
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
calculateTileMatrix(unwrappedTileID: UnwrappedTileID): mat4 {
|
|
711
|
+
const canonical = unwrappedTileID.canonical;
|
|
712
|
+
const scale = this.worldSize / this.zoomScale(canonical.z);
|
|
713
|
+
const unwrappedX = canonical.x + Math.pow(2, canonical.z) * unwrappedTileID.wrap;
|
|
714
|
+
|
|
715
|
+
const worldMatrix = mat4.identity(new Float64Array(16) as any);
|
|
716
|
+
mat4.translate(worldMatrix, worldMatrix, [unwrappedX * scale, canonical.y * scale, 0]);
|
|
717
|
+
mat4.scale(worldMatrix, worldMatrix, [scale / EXTENT, scale / EXTENT, 1]);
|
|
718
|
+
return worldMatrix;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Calculate the posMatrix that, given a tile coordinate, would be used to display the tile on a map.
|
|
723
|
+
* @param unwrappedTileID - the tile ID
|
|
724
|
+
*/
|
|
725
|
+
calculatePosMatrix(unwrappedTileID: UnwrappedTileID, aligned: boolean = false): mat4 {
|
|
726
|
+
const posMatrixKey = unwrappedTileID.key;
|
|
727
|
+
const cache = aligned ? this._alignedPosMatrixCache : this._posMatrixCache;
|
|
728
|
+
if (cache[posMatrixKey]) {
|
|
729
|
+
return cache[posMatrixKey];
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
const posMatrix = this.calculateTileMatrix(unwrappedTileID);
|
|
733
|
+
mat4.multiply(posMatrix, aligned ? this.alignedModelViewProjectionMatrix : this.modelViewProjectionMatrix, posMatrix);
|
|
734
|
+
|
|
735
|
+
cache[posMatrixKey] = new Float32Array(posMatrix);
|
|
736
|
+
return cache[posMatrixKey];
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Calculate the fogMatrix that, given a tile coordinate, would be used to calculate fog on the map.
|
|
741
|
+
* @param unwrappedTileID - the tile ID
|
|
742
|
+
* @private
|
|
743
|
+
*/
|
|
744
|
+
calculateFogMatrix(unwrappedTileID: UnwrappedTileID): mat4 {
|
|
745
|
+
const posMatrixKey = unwrappedTileID.key;
|
|
746
|
+
const cache = this._fogMatrixCache;
|
|
747
|
+
if (cache[posMatrixKey]) {
|
|
748
|
+
return cache[posMatrixKey];
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const fogMatrix = this.calculateTileMatrix(unwrappedTileID);
|
|
752
|
+
mat4.multiply(fogMatrix, this.fogMatrix, fogMatrix);
|
|
753
|
+
|
|
754
|
+
cache[posMatrixKey] = new Float32Array(fogMatrix);
|
|
755
|
+
return cache[posMatrixKey];
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
customLayerMatrix(): mat4 {
|
|
759
|
+
return this.mercatorMatrix.slice() as any;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Get center lngLat and zoom to ensure that
|
|
764
|
+
* 1) everything beyond the bounds is excluded
|
|
765
|
+
* 2) a given lngLat is as near the center as possible
|
|
766
|
+
* Bounds are those set by maxBounds or North & South "Poles" and, if only 1 globe is displayed, antimeridian.
|
|
767
|
+
*/
|
|
768
|
+
getConstrained(lngLat: LngLat, zoom: number): {center: LngLat; zoom: number} {
|
|
769
|
+
zoom = clamp(+zoom, this.minZoom, this.maxZoom);
|
|
770
|
+
const result = {
|
|
771
|
+
center: new LngLat(lngLat.lng, lngLat.lat),
|
|
772
|
+
zoom
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
let lngRange = this.lngRange;
|
|
776
|
+
|
|
777
|
+
if (!this._renderWorldCopies && lngRange === null) {
|
|
778
|
+
const almost180 = 180 - 1e-10;
|
|
779
|
+
lngRange = [-almost180, almost180];
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
const worldSize = this.tileSize * this.zoomScale(result.zoom); // A world size for the requested zoom level, not the current world size
|
|
783
|
+
let minY = 0;
|
|
784
|
+
let maxY = worldSize;
|
|
785
|
+
let minX = 0;
|
|
786
|
+
let maxX = worldSize;
|
|
787
|
+
let scaleY = 0;
|
|
788
|
+
let scaleX = 0;
|
|
789
|
+
const {x: screenWidth, y: screenHeight} = this.size;
|
|
790
|
+
|
|
791
|
+
if (this.latRange) {
|
|
792
|
+
const latRange = this.latRange;
|
|
793
|
+
minY = mercatorYfromLat(latRange[1]) * worldSize;
|
|
794
|
+
maxY = mercatorYfromLat(latRange[0]) * worldSize;
|
|
795
|
+
const shouldZoomIn = maxY - minY < screenHeight;
|
|
796
|
+
if (shouldZoomIn) scaleY = screenHeight / (maxY - minY);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
if (lngRange) {
|
|
800
|
+
minX = wrap(
|
|
801
|
+
mercatorXfromLng(lngRange[0]) * worldSize,
|
|
802
|
+
0,
|
|
803
|
+
worldSize
|
|
804
|
+
);
|
|
805
|
+
maxX = wrap(
|
|
806
|
+
mercatorXfromLng(lngRange[1]) * worldSize,
|
|
807
|
+
0,
|
|
808
|
+
worldSize
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
if (maxX < minX) maxX += worldSize;
|
|
812
|
+
|
|
813
|
+
const shouldZoomIn = maxX - minX < screenWidth;
|
|
814
|
+
if (shouldZoomIn) scaleX = screenWidth / (maxX - minX);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
const {x: originalX, y: originalY} = this.project.call({worldSize}, lngLat);
|
|
818
|
+
let modifiedX, modifiedY;
|
|
819
|
+
|
|
820
|
+
const scale = Math.max(scaleX || 0, scaleY || 0);
|
|
821
|
+
|
|
822
|
+
if (scale) {
|
|
823
|
+
// zoom in to exclude all beyond the given lng/lat ranges
|
|
824
|
+
const newPoint = new Point(
|
|
825
|
+
scaleX ? (maxX + minX) / 2 : originalX,
|
|
826
|
+
scaleY ? (maxY + minY) / 2 : originalY);
|
|
827
|
+
result.center = this.unproject.call({worldSize}, newPoint).wrap();
|
|
828
|
+
result.zoom += this.scaleZoom(scale);
|
|
829
|
+
return result;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (this.latRange) {
|
|
833
|
+
const h2 = screenHeight / 2;
|
|
834
|
+
if (originalY - h2 < minY) modifiedY = minY + h2;
|
|
835
|
+
if (originalY + h2 > maxY) modifiedY = maxY - h2;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
if (lngRange) {
|
|
839
|
+
const centerX = (minX + maxX) / 2;
|
|
840
|
+
let wrappedX = originalX;
|
|
841
|
+
if (this._renderWorldCopies) {
|
|
842
|
+
wrappedX = wrap(originalX, centerX - worldSize / 2, centerX + worldSize / 2);
|
|
843
|
+
}
|
|
844
|
+
const w2 = screenWidth / 2;
|
|
845
|
+
|
|
846
|
+
if (wrappedX - w2 < minX) modifiedX = minX + w2;
|
|
847
|
+
if (wrappedX + w2 > maxX) modifiedX = maxX - w2;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// pan the map if the screen goes off the range
|
|
851
|
+
if (modifiedX !== undefined || modifiedY !== undefined) {
|
|
852
|
+
const newPoint = new Point(modifiedX ?? originalX, modifiedY ?? originalY);
|
|
853
|
+
result.center = this.unproject.call({worldSize}, newPoint).wrap();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return result;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
_constrain() {
|
|
860
|
+
if (!this.center || !this.width || !this.height || this._constraining) return;
|
|
861
|
+
this._constraining = true;
|
|
862
|
+
const unmodified = this._unmodified;
|
|
863
|
+
const {center, zoom} = this.getConstrained(this.center, this.zoom);
|
|
864
|
+
this.center = center;
|
|
865
|
+
this.zoom = zoom;
|
|
866
|
+
this._unmodified = unmodified;
|
|
867
|
+
this._constraining = false;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
_calcMatrices() {
|
|
871
|
+
if (!this.height) return;
|
|
872
|
+
|
|
873
|
+
const halfFov = this._fov / 2;
|
|
874
|
+
const offset = this.centerOffset;
|
|
875
|
+
const x = this.point.x, y = this.point.y;
|
|
876
|
+
this.cameraToCenterDistance = 0.5 / Math.tan(halfFov) * this.height;
|
|
877
|
+
this._pixelPerMeter = mercatorZfromAltitude(1, this.center.lat) * this.worldSize;
|
|
878
|
+
|
|
879
|
+
let m = mat4.identity(new Float64Array(16) as any);
|
|
880
|
+
mat4.scale(m, m, [this.width / 2, -this.height / 2, 1]);
|
|
881
|
+
mat4.translate(m, m, [1, -1, 0]);
|
|
882
|
+
this.labelPlaneMatrix = m;
|
|
883
|
+
|
|
884
|
+
m = mat4.identity(new Float64Array(16) as any);
|
|
885
|
+
mat4.scale(m, m, [1, -1, 1]);
|
|
886
|
+
mat4.translate(m, m, [-1, -1, 0]);
|
|
887
|
+
mat4.scale(m, m, [2 / this.width, 2 / this.height, 1]);
|
|
888
|
+
this.glCoordMatrix = m;
|
|
889
|
+
|
|
890
|
+
// Calculate the camera to sea-level distance in pixel in respect of terrain
|
|
891
|
+
const cameraToSeaLevelDistance = this.cameraToCenterDistance + this._elevation * this._pixelPerMeter / Math.cos(this._pitch);
|
|
892
|
+
// In case of negative minimum elevation (e.g. the dead see, under the sea maps) use a lower plane for calculation
|
|
893
|
+
const minElevation = Math.min(this.elevation, this.minElevationForCurrentTile);
|
|
894
|
+
const cameraToLowestPointDistance = cameraToSeaLevelDistance - minElevation * this._pixelPerMeter / Math.cos(this._pitch);
|
|
895
|
+
const lowestPlane = minElevation < 0 ? cameraToLowestPointDistance : cameraToSeaLevelDistance;
|
|
896
|
+
|
|
897
|
+
// Find the distance from the center point [width/2 + offset.x, height/2 + offset.y] to the
|
|
898
|
+
// center top point [width/2 + offset.x, 0] in Z units, using the law of sines.
|
|
899
|
+
// 1 Z unit is equivalent to 1 horizontal px at the center of the map
|
|
900
|
+
// (the distance between[width/2, height/2] and [width/2 + 1, height/2])
|
|
901
|
+
const groundAngle = Math.PI / 2 + this._pitch;
|
|
902
|
+
const fovAboveCenter = this._fov * (0.5 + offset.y / this.height);
|
|
903
|
+
const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * lowestPlane / Math.sin(clamp(Math.PI - groundAngle - fovAboveCenter, 0.01, Math.PI - 0.01));
|
|
904
|
+
|
|
905
|
+
// Find the distance from the center point to the horizon
|
|
906
|
+
const horizon = this.getHorizon();
|
|
907
|
+
const horizonAngle = Math.atan(horizon / this.cameraToCenterDistance);
|
|
908
|
+
const fovCenterToHorizon = 2 * horizonAngle * (0.5 + offset.y / (horizon * 2));
|
|
909
|
+
const topHalfSurfaceDistanceHorizon = Math.sin(fovCenterToHorizon) * lowestPlane / Math.sin(clamp(Math.PI - groundAngle - fovCenterToHorizon, 0.01, Math.PI - 0.01));
|
|
910
|
+
|
|
911
|
+
// Calculate z distance of the farthest fragment that should be rendered.
|
|
912
|
+
// Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
|
|
913
|
+
const topHalfMinDistance = Math.min(topHalfSurfaceDistance, topHalfSurfaceDistanceHorizon);
|
|
914
|
+
this.farZ = (Math.cos(Math.PI / 2 - this._pitch) * topHalfMinDistance + lowestPlane) * 1.01;
|
|
915
|
+
|
|
916
|
+
// The larger the value of nearZ is
|
|
917
|
+
// - the more depth precision is available for features (good)
|
|
918
|
+
// - clipping starts appearing sooner when the camera is close to 3d features (bad)
|
|
919
|
+
//
|
|
920
|
+
// Other values work for mapbox-gl-js but deck.gl was encountering precision issues
|
|
921
|
+
// when rendering custom layers. This value was experimentally chosen and
|
|
922
|
+
// seems to solve z-fighting issues in deck.gl while not clipping buildings too close to the camera.
|
|
923
|
+
this.nearZ = this.height / 50;
|
|
924
|
+
|
|
925
|
+
// matrix for conversion from location to clip space(-1 .. 1)
|
|
926
|
+
m = new Float64Array(16) as any;
|
|
927
|
+
mat4.perspective(m, this._fov, this.width / this.height, this.nearZ, this.farZ);
|
|
928
|
+
|
|
929
|
+
// Apply center of perspective offset
|
|
930
|
+
m[8] = -offset.x * 2 / this.width;
|
|
931
|
+
m[9] = offset.y * 2 / this.height;
|
|
932
|
+
this.projectionMatrix = mat4.clone(m);
|
|
933
|
+
|
|
934
|
+
mat4.scale(m, m, [1, -1, 1]);
|
|
935
|
+
mat4.translate(m, m, [0, 0, -this.cameraToCenterDistance]);
|
|
936
|
+
mat4.rotateX(m, m, this._pitch);
|
|
937
|
+
mat4.rotateZ(m, m, this.angle);
|
|
938
|
+
mat4.translate(m, m, [-x, -y, 0]);
|
|
939
|
+
|
|
940
|
+
// The mercatorMatrix can be used to transform points from mercator coordinates
|
|
941
|
+
// ([0, 0] nw, [1, 1] se) to clip space.
|
|
942
|
+
this.mercatorMatrix = mat4.scale([] as any, m, [this.worldSize, this.worldSize, this.worldSize]);
|
|
943
|
+
|
|
944
|
+
// scale vertically to meters per pixel (inverse of ground resolution):
|
|
945
|
+
mat4.scale(m, m, [1, 1, this._pixelPerMeter]);
|
|
946
|
+
|
|
947
|
+
// matrix for conversion from world space to screen coordinates in 2D
|
|
948
|
+
this.pixelMatrix = mat4.multiply(new Float64Array(16) as any, this.labelPlaneMatrix, m);
|
|
949
|
+
|
|
950
|
+
// matrix for conversion from world space to clip space (-1 .. 1)
|
|
951
|
+
mat4.translate(m, m, [0, 0, -this.elevation]); // elevate camera over terrain
|
|
952
|
+
this.modelViewProjectionMatrix = m;
|
|
953
|
+
this.invModelViewProjectionMatrix = mat4.invert([] as any, m);
|
|
954
|
+
|
|
955
|
+
// create a fog matrix, same es proj-matrix but with near clipping-plane in mapcenter
|
|
956
|
+
// needed to calculate a correct z-value for fog calculation, because projMatrix z value is not
|
|
957
|
+
this.fogMatrix = new Float64Array(16) as any;
|
|
958
|
+
mat4.perspective(this.fogMatrix, this._fov, this.width / this.height, cameraToSeaLevelDistance, this.farZ);
|
|
959
|
+
this.fogMatrix[8] = -offset.x * 2 / this.width;
|
|
960
|
+
this.fogMatrix[9] = offset.y * 2 / this.height;
|
|
961
|
+
mat4.scale(this.fogMatrix, this.fogMatrix, [1, -1, 1]);
|
|
962
|
+
mat4.translate(this.fogMatrix, this.fogMatrix, [0, 0, -this.cameraToCenterDistance]);
|
|
963
|
+
mat4.rotateX(this.fogMatrix, this.fogMatrix, this._pitch);
|
|
964
|
+
mat4.rotateZ(this.fogMatrix, this.fogMatrix, this.angle);
|
|
965
|
+
mat4.translate(this.fogMatrix, this.fogMatrix, [-x, -y, 0]);
|
|
966
|
+
mat4.scale(this.fogMatrix, this.fogMatrix, [1, 1, this._pixelPerMeter]);
|
|
967
|
+
mat4.translate(this.fogMatrix, this.fogMatrix, [0, 0, -this.elevation]); // elevate camera over terrain
|
|
968
|
+
|
|
969
|
+
// matrix for conversion from world space to screen coordinates in 3D
|
|
970
|
+
this.pixelMatrix3D = mat4.multiply(new Float64Array(16) as any, this.labelPlaneMatrix, m);
|
|
971
|
+
|
|
972
|
+
// Make a second projection matrix that is aligned to a pixel grid for rendering raster tiles.
|
|
973
|
+
// We're rounding the (floating point) x/y values to achieve to avoid rendering raster images to fractional
|
|
974
|
+
// coordinates. Additionally, we adjust by half a pixel in either direction in case that viewport dimension
|
|
975
|
+
// is an odd integer to preserve rendering to the pixel grid. We're rotating this shift based on the angle
|
|
976
|
+
// of the transformation so that 0°, 90°, 180°, and 270° rasters are crisp, and adjust the shift so that
|
|
977
|
+
// it is always <= 0.5 pixels.
|
|
978
|
+
const xShift = (this.width % 2) / 2, yShift = (this.height % 2) / 2,
|
|
979
|
+
angleCos = Math.cos(this.angle), angleSin = Math.sin(this.angle),
|
|
980
|
+
dx = x - Math.round(x) + angleCos * xShift + angleSin * yShift,
|
|
981
|
+
dy = y - Math.round(y) + angleCos * yShift + angleSin * xShift;
|
|
982
|
+
const alignedM = new Float64Array(m) as any as mat4;
|
|
983
|
+
mat4.translate(alignedM, alignedM, [dx > 0.5 ? dx - 1 : dx, dy > 0.5 ? dy - 1 : dy, 0]);
|
|
984
|
+
this.alignedModelViewProjectionMatrix = alignedM;
|
|
985
|
+
|
|
986
|
+
// inverse matrix for conversion from screen coordinates to location
|
|
987
|
+
m = mat4.invert(new Float64Array(16) as any, this.pixelMatrix);
|
|
988
|
+
if (!m) throw new Error('failed to invert matrix');
|
|
989
|
+
this.pixelMatrixInverse = m;
|
|
990
|
+
|
|
991
|
+
this._posMatrixCache = {};
|
|
992
|
+
this._alignedPosMatrixCache = {};
|
|
993
|
+
this._fogMatrixCache = {};
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
maxPitchScaleFactor() {
|
|
997
|
+
// calcMatrices hasn't run yet
|
|
998
|
+
if (!this.pixelMatrixInverse) return 1;
|
|
999
|
+
|
|
1000
|
+
const coord = this.pointCoordinate(new Point(0, 0));
|
|
1001
|
+
const p = [coord.x * this.worldSize, coord.y * this.worldSize, 0, 1] as vec4;
|
|
1002
|
+
const topPoint = vec4.transformMat4(p, p, this.pixelMatrix);
|
|
1003
|
+
return topPoint[3] / this.cameraToCenterDistance;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* The camera looks at the map from a 3D (lng, lat, altitude) location. Let's use `cameraLocation`
|
|
1008
|
+
* as the name for the location under the camera and on the surface of the earth (lng, lat, 0).
|
|
1009
|
+
* `cameraPoint` is the projected position of the `cameraLocation`.
|
|
1010
|
+
*
|
|
1011
|
+
* This point is useful to us because only fill-extrusions that are between `cameraPoint` and
|
|
1012
|
+
* the query point on the surface of the earth can extend and intersect the query.
|
|
1013
|
+
*
|
|
1014
|
+
* When the map is not pitched the `cameraPoint` is equivalent to the center of the map because
|
|
1015
|
+
* the camera is right above the center of the map.
|
|
1016
|
+
*/
|
|
1017
|
+
getCameraPoint() {
|
|
1018
|
+
const pitch = this._pitch;
|
|
1019
|
+
const yOffset = Math.tan(pitch) * (this.cameraToCenterDistance || 1);
|
|
1020
|
+
return this.centerPoint.add(new Point(0, yOffset));
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* When the map is pitched, some of the 3D features that intersect a query will not intersect
|
|
1025
|
+
* the query at the surface of the earth. Instead the feature may be closer and only intersect
|
|
1026
|
+
* the query because it extrudes into the air.
|
|
1027
|
+
* @param queryGeometry - For point queries, the line from the query point to the "camera point",
|
|
1028
|
+
* for other geometries, the envelope of the query geometry and the "camera point"
|
|
1029
|
+
* @returns a geometry that includes all of the original query as well as all possible ares of the
|
|
1030
|
+
* screen where the *base* of a visible extrusion could be.
|
|
1031
|
+
*
|
|
1032
|
+
*/
|
|
1033
|
+
getCameraQueryGeometry(queryGeometry: Array<Point>): Array<Point> {
|
|
1034
|
+
const c = this.getCameraPoint();
|
|
1035
|
+
|
|
1036
|
+
if (queryGeometry.length === 1) {
|
|
1037
|
+
return [queryGeometry[0], c];
|
|
1038
|
+
} else {
|
|
1039
|
+
let minX = c.x;
|
|
1040
|
+
let minY = c.y;
|
|
1041
|
+
let maxX = c.x;
|
|
1042
|
+
let maxY = c.y;
|
|
1043
|
+
for (const p of queryGeometry) {
|
|
1044
|
+
minX = Math.min(minX, p.x);
|
|
1045
|
+
minY = Math.min(minY, p.y);
|
|
1046
|
+
maxX = Math.max(maxX, p.x);
|
|
1047
|
+
maxY = Math.max(maxY, p.y);
|
|
1048
|
+
}
|
|
1049
|
+
return [
|
|
1050
|
+
new Point(minX, minY),
|
|
1051
|
+
new Point(maxX, minY),
|
|
1052
|
+
new Point(maxX, maxY),
|
|
1053
|
+
new Point(minX, maxY),
|
|
1054
|
+
new Point(minX, minY)
|
|
1055
|
+
];
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Return the distance to the camera in clip space from a LngLat.
|
|
1060
|
+
* This can be compared to the value from the depth buffer (terrain.depthAtPoint)
|
|
1061
|
+
* to determine whether a point is occluded.
|
|
1062
|
+
* @param lngLat - the point
|
|
1063
|
+
* @param elevation - the point's elevation
|
|
1064
|
+
* @returns depth value in clip space (between 0 and 1)
|
|
1065
|
+
*/
|
|
1066
|
+
lngLatToCameraDepth(lngLat: LngLat, elevation: number) {
|
|
1067
|
+
const coord = this.locationCoordinate(lngLat);
|
|
1068
|
+
const p = [coord.x * this.worldSize, coord.y * this.worldSize, elevation, 1] as vec4;
|
|
1069
|
+
vec4.transformMat4(p, p, this.modelViewProjectionMatrix);
|
|
1070
|
+
return (p[2] / p[3]);
|
|
1071
|
+
}
|
|
1072
|
+
}
|