MVTTools

用于 Swift 的 MapLibre/Mapbox 矢量瓦片 (MVT) 读写库,以及一个强大的命令行工具,用于处理矢量瓦片和 GeoJSON。

特性

要求

此软件包需要 Swift 5.10 或更高版本(至少 Xcode 14),并且可以在 iOS (>= iOS 13)、macOS (>= macOS 13)、tvOS (>= tvOS 13)、watchOS (>= watchOS 6) 以及 Linux 上编译。

使用 Swift Package Manager 安装

dependencies: [
    .package(url: "https://github.com/Outdooractive/mvt-tools", from: "1.8.0"),
],
targets: [
    .target(name: "MyTarget", dependencies: [
        .product(name: "MVTTools", package: "mvt-tools"),
    ]),
]

此软件包使用 gis-tools 库,并且被 mvt-postgis 库使用,也请关注它们。

用法

请参阅 API 文档(通过 Swift Package Index)。

读取

import MVTTools

// Load
let mvtData = Data(contentsOf: URL(fileURLWithPath: "14_8716_8015.vector.mvt"))!
let tile = VectorTile(data: mvtData, x: 8716, y: 8015, z: 14, indexed: .hilbert)!

print(tile.isIndexed)
print(tile.layerNames.sorted())

let tileAsGeoJsonData: Data? = tile.toGeoJson(prettyPrinted: true)
...

let result = tile.query(at: Coordinate3D(latitude: 3.870163, longitude: 11.518585), tolerance: 100.0)
...

写入

import MVTTools

var tile = VectorTile(x: 8716, y: 8015, z: 14)!
var feature = Feature(Point(Coordinate3D(latitude: 3.870163, longitude: 11.518585)))
feature.properties = [
    "test": 1,
    "test2": 5.567,
    "test3": [1, 2, 3],
    "test4": [
        "sub1": 1,
        "sub2": 2
    ]
]

tile.setFeatures([feature], for: "test")

// Also have a look at ``VectorTile.ExportOptions``
let tileData = tile.data()
...

Playground

在 macOS 上,您可以使用 Swift Playground 来检查 MVTTools API,例如 layerNamesprojection

命令行工具

您可以通过以下方式安装命令行工具 mvt

mvt 可以处理本地磁盘上的矢量瓦片或 GeoJSON 文件,也可以处理来自 Web 服务器的文件。

GeoJSON 可以在其要素属性中包含图层名称(默认名称为 vt_layer),并且任何生成的 GeoJSON 都将自动包含此属性。 可以使用选项 --property-name (或 -P)、--disable-input-layer-property (或 -Di) 和 --disable-output-layer-property (或 -Do) 来控制。 一些命令允许使用 --layer (或 -l) 将结果限制为某些图层,该选项可以根据需要重复多次以指定多个图层。

# mvt -h
OVERVIEW: A utility for inspecting and working with vector tiles (MVT) and GeoJSON files.

A x/y/z tile coordinate is needed for encoding/decoding vector tiles (MVT).
This tile coordinate can be extracted from the file path/URL if it's either in the form '/z/x/y' or 'z_x_y'.
Tile coordinates are not necessary for GeoJSON input files.

Examples:
- Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt
- https://demotiles.maplibre.org/tiles/2/2/1.pbf

USAGE: mvt <subcommand>

OPTIONS:
  --version               Show the version.
  -h, --help              Show help information.

SUBCOMMANDS:
  dump (default)          Print the input file (mvt or GeoJSON) as pretty-printed GeoJSON to the console
  info                    Print information about the input file (mvt or GeoJSON)
  query                   Query the features in the input file (mvt or GeoJSON)
  merge                   Merge any number of vector tiles or GeoJSONs
  import                  Import some GeoJSONs into a vector tile
  export                  Export a vector tile as GeoJSON to a file

  See 'mvt help <subcommand>' for detailed help.

mvt dump

将矢量瓦片或 GeoJSON 文件打印为格式良好的 GeoJSON。

mvt dump Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt
{
  "type" : "FeatureCollection",
  "features" : [
    {
      "bbox" : [
        11.516327261924731,
        3.8807821163834175,
        11.516590118408191,
        3.8815421167424793
      ],
      "properties" : {
        "oneway" : 1,
        "vt_layer" : "tunnel",
        "class" : "motorway"
      },
      "geometry" : {
        "coordinates" : [
          ...
        ],
        "type" : "LineString"
      },
      "id" : 1,
      "type" : "Feature"
    },
    ...
}

mvt info

打印有关矢量瓦片/GeoJSON 的一些信息

示例 1:打印有关位于喀麦隆雅温得的 zoom 14 级别的 MVTTools 测试矢量瓦片的信息。

mvt info Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt

 Name               | Features | Points | LineStrings | Polygons | Unknown | Version
--------------------+----------+--------+-------------+----------+---------+--------
 area_label         | 55       | 55     | 0           | 0        | 0       | 2
 barrier_line       | 4219     | 0      | 4219        | 0        | 0       | 2
 bridge             | 14       | 0      | 14          | 0        | 0       | 2
 building           | 5414     | 0      | 0           | 5414     | 0       | 2
 building_label     | 413      | 413    | 0           | 0        | 0       | 2
 ...
 road               | 502      | 1      | 497         | 4        | 0       | 2
 road_label         | 309      | 0      | 309         | 0        | 0       | 2

示例 2:检查 zoom 2 级别的 MapLibre 矢量瓦片,其范围显示了从挪威到印度的区域。

mvt info https://demotiles.maplibre.org/tiles/2/2/1.pbf

 Name      | Features | Points | LineStrings | Polygons | Unknown | Version
-----------+----------+--------+-------------+----------+---------+--------
 centroids | 104      | 104    | 0           | 0        | 0       | 2
 countries | 113      | 0      | 0           | 113      | 0       | 2
 geolines  | 4        | 0      | 4           | 0        | 0       | 2

示例 3:打印有关每个图层的属性的信息。

mvt info Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt

 Name               | area | class | group | layer | ldir | len | name | name_de | name_en | name_es | name_fr | network | oneway | ref | reflen | scalerank | type
--------------------+------+-------+-------+-------+------+-----+------+---------+---------+---------+---------+---------+--------+-----+--------+-----------+-----
 airport_label      | 0    | 0     | 0     | 0     | 0    | 0   | 0    | 0       | 0       | 0       | 0       | 0       | 0      | 0   | 0      | 0         | 0
 area_label         | 55   | 55    | 0     | 0     | 0    | 0   | 55   | 55      | 55      | 55      | 55      | 0       | 0      | 0   | 0      | 0         | 0
 barrier_line       | 0    | 4219  | 0     | 0     | 0    | 0   | 0    | 0       | 0       | 0       | 0       | 0       | 0      | 0   | 0      | 0         | 0
 bridge             | 0    | 14    | 0     | 13    | 0    | 0   | 0    | 0       | 0       | 0       | 0       | 0       | 14     | 0   | 0      | 0         | 0
...

示例 4:打印有关特定属性的信息。

mvt info -p class Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt

 Name  | cemetery | driveway | fence | hedge | hospital | industrial | main | major_rail | mini_roundabout | minor_rail | motorway | park | parking | path | pitch | rail | school | service | street | street_limited | wetland | wood
-------+----------+----------+-------+-------+----------+------------+------+------------+-----------------+------------+----------+------+---------+------+-------+------+--------+---------+--------+----------------+---------+-----
 class | 4        | 36       | 3895  | 324   | 9        | 2          | 113  | 21         | 1               | 13         | 30       | 95   | 59      | 46   | 21    | 2    | 59     | 187     | 376    | 4              | 4       | 12

mvt query

示例 1:使用搜索词查询矢量瓦片或 GeoJSON 文件。

mvt query Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt "École"
{
  "features" : [
    {
      "bbox" : [
        11.537318229675295,
        3.8732409490233337,
        11.537318229675295,
        3.8732409490233337
      ],
      "geometry" : {
        "coordinates" : [
          11.537318229675295,
          3.8732409490233337
        ],
        "type" : "Point"
      },
      "id" : 51,
      "layer" : "building_label",
      "properties" : {
        "area" : 173.97920227050781,
        "name" : "École Maternelle",
        "name_de" : "École Maternelle",
        "name_en" : "École Maternelle",
        "name_es" : "École Maternelle",
        "name_fr" : "École Maternelle"
      },
      "type" : "Feature"
    },
    ...
}

示例 2:使用 latitude,longitude,radius 查询瓦片。

mvt query Tests/MVTToolsTests/TestData/14_8716_8015.geojson "3.87324,11.53731,1000"
{
  "features" : [
    {
      "bbox" : [
        11.529276967048643,
        3.8803432426251487,
        11.530832648277283,
        3.8823074685255259
      ],
      "geometry" : {
        "coordinates" : [
          ...
        ],
        "type" : "LineString"
      },
      "id" : 48,
      "layer" : "road",
      "properties" : {
        "class" : "driveway",
        "oneway" : 0
      },
      "type" : "Feature"
    },
    ...
}

示例 3:查询瓦片中的要素属性。

mvt query -p Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt ".area > 40000 and .class == 'hospital'"

{
  "features" : [
    {
      "bbox" : [
        11.510410308837876,
        3.871287406415171,
        11.510410308837876,
        3.871287406415171
      ],
      "geometry" : {
        "coordinates" : [
          11.510410308837876,
          3.871287406415171
        ],
        "type" : "Point"
      },
      "id" : 2,
      "properties" : {
        "area" : 48364.9375,
        "class" : "hospital",
        "name" : "Hopital Central de Yaoundé",
        "name_de" : "Hopital Central de Yaoundé",
        "name_en" : "Hopital Central de Yaoundé",
        "name_es" : "Hopital Central de Yaoundé",
        "name_fr" : "Hopital Central de Yaoundé",
        "vt_layer" : "area_label"
      },
      "type" : "Feature"
    }
  ],
  "type" : "FeatureCollection"
}

查询语言非常松散地模仿 jq 查询语言。 输出将包含查询返回 true 的所有要素。

这是一个概述。 示例

"properties": {
  "foo": {"bar": 1},
  "some": ["a", "b"],
  "value": 1,
  "string": "Some name"
}

通过在属性名称前放置 . 来检索值。 如果属性名称是数字或包含非字母字符,则必须用引号引起来。 可以通过简单地在点后使用数组索引或将其括在方括号中来访问数组中的元素。

.foo       // true, property "foo" exists
.foo.bar   // true, property "foo" is a dictionary containing "bar"
."foo"."bar" // true, same as above but quoted
.'foo'.'bar' // true, same as above but quoted
.foo.x     // false, "foo" doesn't contain "x"
."foo.bar" // false, property "foo.bar" doesn't exist
.foo.[0]   // false, "foo" is not an array
.some.[0]  // true, "some" is an array and has an element at index "0"
.some.0    // true, same as above but without brackets
.some."0"  // false, "0" is a string key but "some" is not a dictionary

可以这样表达比较

.value == "bar" // false
.value == 1  // true
.value != 1  // false
.value > 1   // false
.value >= 1  // true
.value < 1   // false
.value <= 1  // true
.string =~ /[Ss]ome/ // true
.string =~ /some/    // false
.string =~ /some/i   // true, case insensitive regexp
.string =~ "^Some"   // true, can also use quotes

条件(从左到右评估)

.foo.bar == 1 and .value == 1 // true
.foo == 1 or .bar == 2        // false
.foo == 1 or .value == 1      // true
.foo not          // false, true if foo does not exist
.foo and .bar not // true, foo and bar don't exist together
.foo or .bar not  // false, true if neither foo nor bar exist
.foo.bar not      // false, true if "bar" in dictionary "foo" doesn't exist

其他

near(latitude,longitude,tolerance) // true if the feature is within "tolerance" around the coordinate

一些完整的例子

// Can use single quotes for strings
mvt query -p 14_8716_8015.vector.mvt ".area > 20000 and .class == 'hospital'"

// ... or double quotes, but they must be escaped
mvt query -p 14_8716_8015.vector.mvt ".area > 20000 and .class == \"hospital\""

// No need to quote the query if it doesn't conflict with your shell
// Print all features that have an "area" property
mvt query -p 14_8716_8015.vector.mvt .area
// Features which don't have "area" and "name" properties
mvt query -p 14_8716_8015.vector.mvt .area and .name not

// Case insensitive regular expression
vt query -p 14_8716_8015.vector.mvt ".name =~ /hopital/i"

// Case sensitive regular expression
mvt query -p 14_8716_8015.vector.mvt ".name =~ /Recherches?/"
// Can also use quotes instead of slashes
mvt query -p 14_8716_8015.vector.mvt ".name =~ 'Recherches?'"

// Features around a coordinate
mvt query -p 14_8716_8015.vector.mvt "near(3.87324,11.53731,1000)"
// With other conditions
mvt query -p 14_8716_8015.vector.mvt ".name =~ /^lac/i and near(3.87324,11.53731,10000)"

mvt merge

合并两个或多个矢量瓦片或 GeoJSON 文件,可以以任意组合。

# All vector tiles:
mvt merge --output merged.mvt path/to/first.mvt path/to/second.mvt

# All GeoJSON files:
mvt merge --output merged.geojson path/to/first.geojson path/to/second.geojson

# Merge GeoJSON files into a vector tile:
mvt merge --output merged.mvt --output-format mvt path/to/first.geojson path/to/second.geojson

# Merge vector tiles into a GeoJSOn file:
mvt merge --output merged.geojson --output-format geojson path/to/first.mvt path/to/second.mvt

mvt export

将矢量瓦片作为 GeoJSON 写入文件。

mvt export --output dumped.geojson --pretty-print Tests/MVTToolsTests/TestData/14_8716_8015.vector.mvt

mvt import

从 GeoJSON 创建矢量瓦片。

mvt import new.mvt -x 8716 -y 8015 -z 14 Tests/MVTToolsTests/TestData/14_8716_8015.geojson

贡献

创建 issue打开 pull request

依赖项(用于开发)

brew install protobuf swift-protobuf swiftlint

TODO 和未来的改进

链接

许可证

MIT

作者

Thomas Rasch, Outdooractive