这是用户在 2024-3-25 23:35 为 https://maplibre.org/maplibre-native/docs/book/design/android-map-rendering-data-flow.html 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

Android Map Rendering Data Flow
Android地图渲染数据流


Figure 5: Simplified data flow diagram of initializing a map in Android
图 5:Android 中初始化地图的简化数据流程图

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.
图 5 显示了初始化地图的简化数据流程图。该数据流程图的设备部分基于Android平台。

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.
在地图初始化请求到达 MapLibre Native Core 之前,该请求会初始化平台或设备运行时中的一组对等组件。特别是对于 Android,我们有使用 Android Native Development Kit 用 C++ 编写的部分和用 Java 编写的部分。

A map initialization starts with initializing a map in an Android View. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. In this diagram this is denoted as a Map View inside the device runtime. This view is also responsible for initiating a Device Map Renderer which subsequently initializes a GL Thread worker. This thread is a render loop that takes UI events from the Android View and passes it downstream to get the rendered map.
地图初始化从初始化 Android 视图中的地图开始。视图占据屏幕上的一个矩形区域,负责绘图和事件处理。在此图中,这表示为设备运行时内的地图视图。该视图还负责启动设备映射渲染器,随后初始化 GL 线程工作线程。该线程是一个渲染循环,它从 Android 视图获取 UI 事件并将其传递到下游以获取渲染的地图。

On the native C++ side of the device code, we see a peer Map View component. This one is a wrapper class between the Android Map View and 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 Native renderer.
在设备代码的本机 C++ 端,我们看到一个对等地图视图组件。这是 Android 地图视图和通用地图组件之间的包装类。对于 Android,这维护了从 Java 运行时建立的 JNI 方法契约。本文档之前谈到的渲染线程是以MapRenderer 的形式出现的。这是一个将渲染事件从设备运行时传递到 MapLibre Native 渲染器的 Actor。


Figure 6: Workflow of rendering tiles
图 6:渲染图块的工作流程

Before the frame-by-frame map rendering 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 are essential for every aspect of rendering such as resizing the viewport, setting initial map camera, changes in map camera due to tilt, zoom, and movement. Each of these operations manifest into a set of Transforms that gets applied to the to-be-rendered map tile or already rendered map tile. The Transform class noted in the diagram however does not represent a single or multitude of transformations. A Map View like other components inside MapLibre works as a state machine. The Transform class maintains the current set of global transforms applied 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 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.
在使用 MapLibre Native 渲染器开始逐帧地图渲染之前,通用地图组件会被初始化。渲染地图图块的每一帧或初始化地图视图需要一组变换。通过变换,完成旋转、倾斜、投影等基本突变。变换对于渲染的各个方面都至关重要,例如调整视口大小、设置初始地图相机、由于倾斜、缩放和移动而导致的地图相机变化。这些操作中的每一个都体现为一组应用于要渲染的地图图块或已渲染的地图图块的变换。然而,图中标注的 Transform 类并不代表单个或多个转换。地图视图与 MapLibre 中的其他组件一样,充当状态机。 Transform 类维护应用于地图的当前全局变换集。为了简化更改相机方向、缩放或俯仰的过程,地图视图将更新 Transform 类的状态。 Transform 类将使用观察者将转换事件发送到 MapLibre Native 渲染器。这个整体变换指令(例如将摄像机位置从 A 点更改为 B 点)将转换为渲染器组件推导的一组变换。

Along initializing the Transform state, the Map View will also initialize the Style sub-component. The Style component here also follows a state machine-esque behaviour. It holds the current state of used Styles for the Map View along with layers, glyphs, and sources. A change in style or initialization of style translates to re-loading the Glyph Atlas, Sources, and Layers. A Glyph Atlas is a combined image all glyphs. The renderer slices the necessary glyph by bounding boxes whenever necessary. Different sources are loaded differently. For Tilesets, the tile data is loaded but not rendered right away. For client provided data sources such as GeoJSON, the data is loaded from the file source or code. Then these sources are organized into layers dictated by the style and the layers are sent for rendering through the actors.
在初始化 Transform 状态的同时,Map View 还将初始化 Style 子组件。这里的 Style 组件也遵循状态机式的行为。它保存地图视图使用的样式以及图层、字形和源的当前状态。样式的更改或样式的初始化会转化为重新加载字形图集、源和图层。字形图集是所有字形的组合图像。渲染器在必要时通过边界框来切片必要的字形。不同的源加载方式不同。对于图块集,图块数据会被加载但不会立即渲染。对于客户端提供的数据源(例如 GeoJSON),数据是从文件源或代码加载的。然后,这些源被组织成由样式决定的层,并且这些层被发送以通过参与者进行渲染。

The key philosophy of rendering tiles is tiles are rendered layer by layer. A collection of tiles is called a tile set. To optimize tile rendering, MapLibre Native 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 loads the tileset to be rendered first. In a rendering request, if the tileset is already loaded, MapLibre Native will use a cached tile set.
渲染图块的关键原理是图块是逐层渲染的。图块的集合称为图块集。为了优化图块渲染,MapLibre Native 仅渲染脏图块。脏图块是在视口中渲染的图块,由于用户交互而发生了变化。为了启动此过程,MapLibre Native 首先加载要渲染的图块集。在渲染请求中,如果瓦片集已加载,MapLibre Native 将使用缓存的瓦片集。

The next decision to make here is which tiles are to be rendered on the viewport. To deduce this, MapLibre Native translates the device viewport coordinates1 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 cover, there are no dirty tiles. If the tile cover somehow has a single or all new tiles to be rendered in the viewport, the existing tiles displayed in the viewport are deduced to be dirty. And only these tiles are replaced instead of a complete re-render.
这里要做的下一个决定是在视口上渲染哪些图块。为了推断这一点,MapLibre Native 将设备视口坐标 1 转换为图块覆盖物。图块覆盖加载将渲染到当前视口的所有图块。如果视口已经具有推导的图块覆盖所需渲染的所有图块,则不存在脏图块。如果图块覆盖物以某种方式具有要在视口中渲染的单个或所有新图块,则视口中显示的现有图块被推断为脏的。并且仅替换这些图块,而不是完全重新渲染。

Moving to the render flow now. The render flow is depicted in Figure 7. The diagram introduces a new component block named a Tile Renderer. These diagrams might look verbose but in reality, they are a simplified version of the actual code flow.
现在转向渲染流程。渲染流程如图 7 所示。该图引入了一个名为 Tile Renderer 的新组件块。这些图表可能看起来很冗长,但实际上,它们是实际代码流的简化版本。

The render workflow stays the same as the initialization workflow up to reaching the Render Orchestrator. This time instead of initializing the render orchestrator, the flow uses the render orchestrator to create a Render Tree. A render tree is a tree of to-be-rendered items in order. This includes rendering items from layers, sources, line atlas, and pattern atlas. A render orchestrator does not render anything by itself. It orchestrates render items for the renderer.
渲染工作流程与初始化工作流程保持相同,直到到达渲染协调器。这次,该流程没有初始化渲染协调器,而是使用渲染协调器来创建渲染树。渲染树是按顺序排列的待渲染项的树。这包括渲染来自图层、源、线图集和图案图集的项目。渲染协调器本身不会渲染任何内容。它为渲染器编排渲染项。

In the render loop ran by the Renderer, each render request ends in creating a new render tree, and the render function. The render function uses a glyph manager for fetching glyphs and font stacks that contains said glyphs. Sources and Layers are translated to RenderSource and RenderLayer objects.
在渲染器运行的渲染循环中,每个渲染请求最终都会创建一个新的渲染树和渲染函数。渲染函数使用字形管理器来获取字形和包含所述字形的字体堆栈。 Sources 和 Layers 被转换为 RenderSource 和 RenderLayer 对象。

For the sake of restating, a layer is composed of a set of sources.
重申一下,层由一组源组成。


Figure 7: Simplified data flow diagram of rendering map tiles
图7:渲染地图图块的简化数据流图

A RenderSource is produced from a single source that has an internal update method. This method produces the tile pyramid to render for said source if the source is a TileSource. For brevity, this document only talks about tile sources. There are other types such as GeoJSON sources. They work in a similar manner as the tile source.
RenderSource 由具有内部更新方法的单个源生成。如果源是 TileSource,则此方法会生成要为所述源渲染的图块金字塔。为了简洁起见,本文档仅讨论图块源。还有其他类型,例如 GeoJSON 源。它们的工作方式与图块源类似。


1

Viewport coordinates are derived from the coordinate system of the device screen. Anything rendered inside a unit cube of local space is translated to screen space of actual pixels. The tiles are rendered in a local space before rendered back to screen. We will see more about that in Coordinate System section.


1 视口坐标源自设备屏幕的坐标系。在本地空间的单位立方体内渲染的任何内容都会转换为实际像素的屏幕空间。这些图块在渲染回屏幕之前先在本地空间中渲染。我们将在坐标系部分看到更多相关内容。