Rename MapLibre GL Native -> MapLibre Native (#1075)
This commit is contained in:
@@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "MapLibre GL Native Core"
|
||||
PROJECT_NAME = "MapLibre Native Core"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# MapLibre GL Native Core Documentation
|
||||
# MapLibre Native Core Documentation
|
||||
|
||||
This is the documentation of the public C++ API of MapLibre GL Native Core. You would normally only use this API if you are a contributor to one of the platform specific APIs. If you want to intergrate use MapLibre GL Native in your project, you are better served by [documentation specific to your platform](https://maplibre.org/projects/maplibre-native/), unless you are interested in the internals of MapLibre GL Native.
|
||||
This is the documentation of the public C++ API of MapLibre Native Core. You would normally only use this API if you are a contributor to one of the platform specific APIs. If you want to intergrate use MapLibre Native in your project, you are better served by [documentation specific to your platform](https://maplibre.org/projects/maplibre-native/), unless you are interested in the internals of MapLibre Native.
|
||||
|
||||
The source code can be found [on GitHub](https://github.com/maplibre/maplibre-gl-native) (the `include` directory contains the public API).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Doxygen documentation
|
||||
|
||||
This directory contains the files needed to generate the documentation of MapLibre GL Native Core using [Doxygen](https://www.doxygen.nl).
|
||||
This directory contains the files needed to generate the documentation of MapLibre Native Core using [Doxygen](https://www.doxygen.nl).
|
||||
|
||||
[Doxygen Awesome](https://jothepro.github.io/doxygen-awesome-css/index.html) is used as a theme and is included as a submodule. To update, simply check out a new version of the submodule.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# MapLibre GL Native Docs
|
||||
# MapLibre Native Docs
|
||||
|
||||
## Build Locally
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ authors = ["MapLibre Contributors"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "MapLibre GL Native Documentation"
|
||||
title = "MapLibre Native Documentation"
|
||||
|
||||
[output.html]
|
||||
additional-css = ["diff.css"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# MapLibre GL Native Documentation
|
||||
# MapLibre Native Documentation
|
||||
|
||||
[Introduction](./introduction.md)
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
- [Android Map Rendering Data Flow](design/android-map-rendering-data-flow.md)
|
||||
- [Geometry Tile Worker](design/geometry-tile-worker.md)
|
||||
|
||||
- [MapLibre GL Native for Android](./android/README.md)
|
||||
- [MapLibre Native for Android](./android/README.md)
|
||||
- [Quickstart](./android/getting-started-guide.md)
|
||||
@@ -1,3 +1,3 @@
|
||||
# MapLibre GL Native for Android
|
||||
# MapLibre Native for Android
|
||||
|
||||
MapLibre GL Native for Android is a library for embedding interactive map views with scalable, customizable vector maps onto Android devices.
|
||||
MapLibre Native for Android is a library for embedding interactive map views with scalable, customizable vector maps onto Android devices.
|
||||
@@ -11,7 +11,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
2. Add the library as a dependency into your module Gradle file (usually `<project>/<app-module>/build.gradle`). Replace `<version>` with the latest MapLibre GL Native version (e.g.: `org.maplibre.gl:android-sdk:10.0.2`). Visit [https://mvnrepository.com/artifact/org.maplibre.gl/android-sdk](https://mvnrepository.com/artifact/org.maplibre.gl/android-sdk) to view the version history of MapLibre GL Native for android.
|
||||
2. Add the library as a dependency into your module Gradle file (usually `<project>/<app-module>/build.gradle`). Replace `<version>` with the latest MapLibre Native version (e.g.: `org.maplibre.gl:android-sdk:10.0.2`). Visit [https://mvnrepository.com/artifact/org.maplibre.gl/android-sdk](https://mvnrepository.com/artifact/org.maplibre.gl/android-sdk) to view the version history of MapLibre Native for android.
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Design
|
||||
|
||||
This section is dedicated to documenting current state of MapLibre GL Native. [Architectural Problems and Recommendations](./archictural-problems-and-recommendations.md) section notes recommendations for future improvements from an architectural perspective.
|
||||
This section is dedicated to documenting current state of MapLibre Native. [Architectural Problems and Recommendations](./archictural-problems-and-recommendations.md) section notes recommendations for future improvements from an architectural perspective.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Figure 5 shows a simplified data flow diagram of initializing a map. The
|
||||
device section of this data flow diagram is based on Android platform.
|
||||
|
||||
Before the map initialization request makes it to MapLibre GL Native
|
||||
Before the map initialization request makes it to MapLibre Native
|
||||
Core, the request initializes a set of peer components in the platform
|
||||
or device runtime. Especially for Android, we have parts written in C++
|
||||
using *Android Native Development Kit* and parts written in Java.
|
||||
@@ -25,13 +25,13 @@ the generic Map Component. For Android, this maintains the JNI method
|
||||
contract established from the Java runtime. The render thread this
|
||||
document talked about before is seen in the form of *MapRenderer*. This
|
||||
is an Actor that passes the rendering events from the device runtime to
|
||||
*MapLibre GL Native* renderer.
|
||||
*MapLibre Native* renderer.
|
||||
|
||||

|
||||
*Figure 6: Workflow of rendering tiles*
|
||||
|
||||
Before the frame-by-frame map rendering
|
||||
starts with *MapLibre GL Native* renderer, the generic map component
|
||||
starts with *MapLibre Native* renderer, the generic map component
|
||||
gets initialized. Rendering each frame of a map tile or initializing the
|
||||
map view requires a set of *Transforms.* Through transform basic
|
||||
mutations like rotation, tilt, projection is accomplished. Transforms
|
||||
@@ -46,7 +46,7 @@ like other components inside MapLibre works as a state machine. The
|
||||
to the map. To simplify to change the camera orientation, zoom, or pitch
|
||||
a Map View will update the state of the Transform class. And the
|
||||
Transform class will use observers to send a transform event to
|
||||
*MapLibre GL Native* renderer. This overall transform directive, such as
|
||||
*MapLibre Native* renderer. This overall transform directive, such as
|
||||
change camera location from point A to point B will translate to a set
|
||||
of transformations deduced by the *Renderer* component.
|
||||
|
||||
@@ -70,10 +70,10 @@ rendering, MapLibre Native GL only renders *dirty* tiles. A dirty tile
|
||||
is a tile rendered in the viewport that has changed due to user
|
||||
interaction. To initiate this process, MapLibre Native GL loads the
|
||||
tileset to be rendered first. In a rendering request, if the tileset is
|
||||
already loaded, MapLibre GL Native will use a cached tile set.
|
||||
already loaded, MapLibre Native will use a cached tile set.
|
||||
|
||||
The next decision to make here is which tiles are to be rendered on the
|
||||
viewport. To deduce this, MapLibre GL Native translates the device
|
||||
viewport. To deduce this, MapLibre Native translates the device
|
||||
viewport coordinates[^20] to a tile cover. A tile cover loads all the
|
||||
tiles that will rendered to current viewport. If the viewport already
|
||||
has all the tiles that is needed to be rendered by the deduced tile
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Up until now, this document focused solely on the state of MapLibre GL
|
||||
Native at the time of writing. This section speaks of possible future
|
||||
improvements for MapLibre GL Native from an architectural point of view.
|
||||
improvements for MapLibre Native from an architectural point of view.
|
||||
Before that, let's look into the architectural challenges MapLibre GL
|
||||
Native is facing[^18]:
|
||||
|
||||
@@ -21,37 +21,37 @@ Native does not have a clear separation between the following:
|
||||
|
||||
The current rendering loop is only implemented for OpenGL. In 2018,
|
||||
Apple deprecated OpenGL for both iOS 12 and macOS in favour of Metal.
|
||||
Metal is Apple's own 3D graphics API. MapLibre GL Native's sole
|
||||
Metal is Apple's own 3D graphics API. MapLibre Native's sole
|
||||
dependency on OpenGL ES puts it in a risk of deprecation for iOS
|
||||
customers.
|
||||
|
||||
## Lack of support for other map projections except Web Mercator
|
||||
|
||||
MapLibre GL Native supports Web Mercator (EPSG:3857) as its only
|
||||
MapLibre Native supports Web Mercator (EPSG:3857) as its only
|
||||
supported projection. This fulfills most of the web and device map
|
||||
needs. At the time of writing, modern map renderers such as Google Maps
|
||||
and Mapbox GL offers 3D globe, conic, and rectangular projections too.
|
||||
At the time of writing, MapLibre GL Native renderer component does not
|
||||
At the time of writing, MapLibre Native renderer component does not
|
||||
have an architectural separation for supporting multiple projections and
|
||||
coordinate reference systems.
|
||||
|
||||
## Inconsistency among platforms
|
||||
|
||||
Each MapLibre GL Native platform has a Map View and Map Renderer
|
||||
Each MapLibre Native platform has a Map View and Map Renderer
|
||||
component. The inconsistency introduced due to differences in
|
||||
concurrency model and programming language is unavoidable. But from an
|
||||
abstractions point of view there are inconsistencies that can be
|
||||
mitigated:
|
||||
|
||||
1. Map Configuration is modeled inside MapLibre GL Native Core, the
|
||||
1. Map Configuration is modeled inside MapLibre Native Core, the
|
||||
shared cross platform codebase. Each platform creates its own
|
||||
configuration class and creates a shadow native object. The native
|
||||
configuration object is consistent across platforms but the platform
|
||||
specific configuration is not.
|
||||
|
||||
2. MapLibre GL Native has a sister repository named MapLibre GL JS. At
|
||||
2. MapLibre Native has a sister repository named MapLibre GL JS. At
|
||||
the time of writing, MapLibre GL JS does not share any code with
|
||||
MapLibre GL Native except shaders, the style specification, and
|
||||
MapLibre Native except shaders, the style specification, and
|
||||
render test fixtures. This creates a feature inconsistency across
|
||||
web and device experience for customers. The rendering architecture
|
||||
is also different between Web and Mobile. MapLibre GL JS currently
|
||||
@@ -66,11 +66,11 @@ mitigated:
|
||||
ChromeOS, macOS, and Windows 10. Technically, it can be used with
|
||||
Android and iOS but these platforms do not provide out of the box
|
||||
support for it. This also has created a divergent experience for
|
||||
customers when it comes to using MapLibre GL Native.
|
||||
customers when it comes to using MapLibre Native.
|
||||
|
||||
## Lack of documentation
|
||||
|
||||
Last but not the least, MapLibre GL Native suffers from a general lack
|
||||
Last but not the least, MapLibre Native suffers from a general lack
|
||||
of documentation. This includes current state of the code architecture,
|
||||
continuous integration and development, testing strategy, and a roadmap
|
||||
for future improvement. This document intends to address the first.
|
||||
@@ -81,9 +81,9 @@ This document proposes the following component architecture for MapLibre
|
||||
GL Native to address the architectural shortcomings.
|
||||
|
||||

|
||||
*Figure 4: Proposed Architecture of MapLibre GL Native*
|
||||
*Figure 4: Proposed Architecture of MapLibre Native*
|
||||
|
||||
Proposed architecture of MapLibre GL Native in Figure 4 addresses the
|
||||
Proposed architecture of MapLibre Native in Figure 4 addresses the
|
||||
aforementioned problems by:
|
||||
|
||||
#### Modular Rendering
|
||||
@@ -112,7 +112,7 @@ native device coordinates.
|
||||
|
||||
One example of introducing new component is supporting 3D maps in the
|
||||
future. This could mean rendering map tiles on a spherical globe instead
|
||||
of a flat 3D plane. At the time of writing MapLibre GL Native supports
|
||||
of a flat 3D plane. At the time of writing MapLibre Native supports
|
||||
2.5D extrusion for buildings and terrain tiles. Supporting confidential
|
||||
datums like *GCJ-02* can also be achieved through this.
|
||||
|
||||
@@ -132,7 +132,7 @@ interoperability with Rust, this document proposes the following to be
|
||||
done in sequence:
|
||||
|
||||
1. At first, this document proposes to implement ***Modularized
|
||||
Rendering*** in C++ for MapLibre GL Native. This document also
|
||||
Rendering*** in C++ for MapLibre Native. This document also
|
||||
proposes that Unified Rendering Interface will keep the door open
|
||||
for a *WebGPU* backed renderer in MapLibre Rust. This will address
|
||||
the divergence of web and native platforms in the future. The Rust
|
||||
@@ -146,7 +146,7 @@ done in sequence:
|
||||
|
||||
3. Finally, this document proposes to migrate Unified Rendering
|
||||
Interface and its implementations to Rust. This will completely
|
||||
transform MapLibre GL Native from a C++ ecosystem to a Rust
|
||||
transform MapLibre Native from a C++ ecosystem to a Rust
|
||||
ecosystem.
|
||||
|
||||
Following the above steps will merge towards a single MapLibre
|
||||
@@ -155,7 +155,7 @@ implementation for web and native.
|
||||
____________________________
|
||||
|
||||
[^18]: This document deliberately does not speak of problems regarding
|
||||
build and infrastructure of MapLibre GL Native. They will be handled
|
||||
build and infrastructure of MapLibre Native. They will be handled
|
||||
in individual design PR requests / documents.
|
||||
|
||||
[^19]: Rust Foreign Function Interface allows interop bindings and code
|
||||
|
||||
@@ -24,7 +24,7 @@ which we all live in and make map tiles for. This document uses the word
|
||||
*World* to denote the world MapLibre Native GL renders. The word *world*
|
||||
in rendering terms mean the *world* to render. It could be a set of
|
||||
cones and boxes, a modeled city, anything composed of 3D objects.
|
||||
MapLibre GL Native renders map tiles in a range of zoom levels on a 3D
|
||||
MapLibre Native renders map tiles in a range of zoom levels on a 3D
|
||||
plane. Map tiles are already produced from a WGS84 ellipsoid. Therefore,
|
||||
when this document uses the word *World,* it means the 3D plane
|
||||
containing a set of map tiles to be rendered, not the *Earth*.
|
||||
@@ -57,7 +57,7 @@ a bit. To render anything through a GPU:
|
||||
4. Finally, the *World Space* is transformed to device screen by
|
||||
applying viewport transform matrix.
|
||||
|
||||
Going forward, scoping our discussion only to MapLibre GL Native, we
|
||||
Going forward, scoping our discussion only to MapLibre Native, we
|
||||
will talk mostly about two categories of coordinate systems:
|
||||
|
||||
1. World Coordinates
|
||||
@@ -98,7 +98,7 @@ Projections are used to translate WGS84 coordinates to a plane. To be
|
||||
specific, projections are used to translate a location on the ellipsoid
|
||||
to a two-dimensional square. EPSG:3857[^11] or projected
|
||||
*Pseudo-Mercator Coordinate System* is such a coordinate system.
|
||||
EPSG:3857 is used by MapLibre GL Native as a default coordinate system
|
||||
EPSG:3857 is used by MapLibre Native as a default coordinate system
|
||||
to display maps. This system takes WGS84 coordinates and projects them
|
||||
into sphere. This stretches out the landmass in the hemispheres but
|
||||
mathematically makes it simpler to project a location back to a 2D
|
||||
@@ -179,7 +179,7 @@ tile's X, Y, and Z.
|
||||
To reach our goal of translating a location to a coordinate inside a
|
||||
tile, we need to know what is the *extent* of the tile. MapLibre GL
|
||||
Native follows Mapbox Vector Tile (MVT) spec. Following said spec,
|
||||
MapLibre GL Native internally normalizes each tile to an *extent* of
|
||||
MapLibre Native internally normalizes each tile to an *extent* of
|
||||
8192. Tile extent describes the width and height of the tile in integer
|
||||
coordinates. This means a tile coordinate can have higher precision than
|
||||
a pixel. Because normally a tile has a height and width of 512 pixels.
|
||||
@@ -219,9 +219,9 @@ positioned on the top left.
|
||||
|
||||
## Device Coordinates
|
||||
|
||||
World space for MapLibre GL Native contains a plane in 3D with all the
|
||||
World space for MapLibre Native contains a plane in 3D with all the
|
||||
tiles for any specific zoom level. Map tiles are hierarchical in nature.
|
||||
As in they have different zoom levels. MapLibre GL Native internally
|
||||
As in they have different zoom levels. MapLibre Native internally
|
||||
stores a tree object that mimics a tile pyramid. However, it does not
|
||||
create a hierarchy of 3D planes where each plane mimics one zoom level.
|
||||
It reuses the same 3D plane to re-render the tiles in the requested zoom
|
||||
@@ -232,7 +232,7 @@ world space starts with *View Matrix*, as defined in the world space.
|
||||
The key part here is the *camera*. A *view matrix* is a matrix that
|
||||
scales, rotates, and translates[^14] the world space from the view of
|
||||
the camera. To add the perspective of the camera, we apply the
|
||||
*Projection Matrix*. In MapLibre GL Native, a camera initialization
|
||||
*Projection Matrix*. In MapLibre Native, a camera initialization
|
||||
requires map center, bearing, and pitch.
|
||||
|
||||
*Initializing the map with a center (lon, lat) does not translate or
|
||||
@@ -250,7 +250,7 @@ Once a tile is built, the GPU can quickly draw the same tile with different
|
||||
bearing, pan, pitch, and zoom parameters[^15].
|
||||
|
||||
If we keep following Figure 2, we see we need to also add a projection
|
||||
matrix. And MapLibre GL Native uses a *perspective projection*.
|
||||
matrix. And MapLibre Native uses a *perspective projection*.
|
||||
Perspective projection matrix introduces the sense of depth perspective
|
||||
through the camera. As in objects further from the camera will look
|
||||
smaller and objects closer to the camera will look bigger. This
|
||||
@@ -271,7 +271,7 @@ pitch: 45 degrees
|
||||
tile: 585/783/11
|
||||
```
|
||||
|
||||
On top of this, MapLibre GL Native uses a field of view of 36.87 degrees
|
||||
On top of this, MapLibre Native uses a field of view of 36.87 degrees
|
||||
or 0.6435011087932844 radians. This is somewhat arbitrary. The altitude
|
||||
of the camera used to be defined as 1.5 screen heights above the ground.
|
||||
The ground is the 3D plane that paints the map tiles. The field of view
|
||||
@@ -322,7 +322,7 @@ with perspective component *w*.
|
||||
```
|
||||
|
||||
Doing this will take us into *clip space.* Clip coordinates contain all
|
||||
the tile coordinates we wish to render in MapLibre GL Native but only in
|
||||
the tile coordinates we wish to render in MapLibre Native but only in
|
||||
a normalized coordinate space of `[-1.0, 1.0]`.
|
||||
|
||||
All that is left now is to translate this to viewport coordinates.
|
||||
@@ -351,7 +351,7 @@ _________________________
|
||||
|
||||
[^11]: There are other coordinate systems such as EPSG:54001 that uses
|
||||
equirectangles over squares to project the WGS84 coordinates. This
|
||||
document focuses on EPSG:3857 because MapLibre GL Native uses it by
|
||||
document focuses on EPSG:3857 because MapLibre Native uses it by
|
||||
default.
|
||||
|
||||
[^12]: This document scopes out the trigonometric proof of this
|
||||
@@ -369,7 +369,7 @@ _________________________
|
||||
so order of operation matters.
|
||||
|
||||
[^15]: The piece of code we run on GPU is called a shader. We will see
|
||||
more how shaders influence MapLibre GL Native rendering later in the
|
||||
more how shaders influence MapLibre Native rendering later in the
|
||||
document.
|
||||
|
||||
[^16]: Matrix and examples produced from Chris Loers work hosted in:
|
||||
|
||||
@@ -77,7 +77,7 @@ implementation evaluates both inputs because they are expressions too.
|
||||
Expressions can be nested.
|
||||
|
||||
**Although it looks like JavaScript, for MapLibre Native GL**, **the
|
||||
parser for any expression is written in MapLibre GL Native Core**. Each
|
||||
parser for any expression is written in MapLibre Native Core**. Each
|
||||
platform such as iOS, Android has their own Expression class which
|
||||
provides builders to build an expression and add it to a layer. When an
|
||||
expression is added to a layer, the rendering part of the code picks it
|
||||
@@ -146,8 +146,8 @@ fillLayer.setProperties(
|
||||
);
|
||||
```
|
||||
|
||||
**To render the built expression, MapLibre GL Native uses expression
|
||||
parsers.** **Expression parsers are written in MapLibre GL Native Core
|
||||
**To render the built expression, MapLibre Native uses expression
|
||||
parsers.** **Expression parsers are written in MapLibre Native Core
|
||||
(in C++).** Each expression outputs an *EvaluationResult* class.
|
||||
Resolving an *EvaluationResult* can be deferred. As in, the result of an
|
||||
expression can be computed only when its necessary to be computed in
|
||||
|
||||
@@ -85,7 +85,7 @@ map, style with source and layers, and observers.*
|
||||
|
||||
### Layer
|
||||
|
||||
*Layer* is an overloaded terminology in the MapLibre GL Native's
|
||||
*Layer* is an overloaded terminology in the MapLibre Native's
|
||||
context. *Layer* can mean any of the following:
|
||||
|
||||
1. From the point of view of data that needs to be rendered on map,
|
||||
@@ -129,8 +129,8 @@ When it does, we will dive more into *glyph* rendering.
|
||||
|
||||
### Actor Framework
|
||||
|
||||
MapLibre GL Native is used in mobile platforms. To be performant in
|
||||
underpowered environments, MapLibre GL Native tries to leverage message
|
||||
MapLibre Native is used in mobile platforms. To be performant in
|
||||
underpowered environments, MapLibre Native tries to leverage message
|
||||
passing across threads to render frames asynchronously. The threading
|
||||
architecture in implementation realizes this using the Actor
|
||||
interface[^6]. In reality the messages are raw pointers. This ranges
|
||||
@@ -147,10 +147,10 @@ rendering events that render layers, sources, and subsequently tiles. An
|
||||
|
||||
A *Map Renderer* translates geospatial features in a vector or raster
|
||||
tile to rendered or rasterized map tiles shown in a *slippy map.*
|
||||
MapLibre GL Native uses a *Renderer* component to translate map tiles
|
||||
MapLibre Native uses a *Renderer* component to translate map tiles
|
||||
fetched from a tile server to a rendered map.
|
||||
|
||||
MapLibre GL Native uses a pool of *workers*. These workers are
|
||||
MapLibre Native uses a pool of *workers*. These workers are
|
||||
responsible for background tile generation. A render thread continuously
|
||||
renders the current state of the map with available tiles at the time of
|
||||
rendering. In Javascript and iOS, the render thread is the same as the
|
||||
@@ -168,7 +168,7 @@ Android uses a *GLSurfaceView* with a *GLThread* where the iOS SDK uses
|
||||
|
||||
### Tile Worker
|
||||
|
||||
We have noted early in this document that MapLibre GL Native uses message
|
||||
We have noted early in this document that MapLibre Native uses message
|
||||
passing to communicate with the renderer. These messages are *immutable*
|
||||
by design and the render loops checks for these in each iteration. To
|
||||
simplify, there is only one thread allocated for rendering loop,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Introduction
|
||||
|
||||
*[MapLibre GL Native](https://github.com/maplibre/maplibre-gl-native)* is a community led fork of *Mapbox GL Native*. It's a C++ library that powers
|
||||
*[MapLibre Native](https://github.com/maplibre/maplibre-gl-native)* is a community led fork of *Mapbox GL Native*. It's a C++ library that powers
|
||||
vector maps in native applications on multiple platforms by taking stylesheets that conform to the *MapLibre Style Specification,* a fork of the
|
||||
Mapbox Style Specification. Since it is derived from Mapbox's original work it also uses *Mapbox Vector Tile Specification* as its choice of vector tile format.
|
||||
|
||||
Reference in New Issue
Block a user