Skip to content

Commit

Permalink
Code reorganization
Browse files Browse the repository at this point in the history
  • Loading branch information
trasch committed Jun 3, 2024
1 parent 0fe7aa4 commit 47c805c
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 628 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ feature.properties = [

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

// Also have a look at ``VectorTileExportOptions``
// Also have a look at ``VectorTile.ExportOptions``
let tileData = tile.data()
...
```
Expand Down
2 changes: 1 addition & 1 deletion Sources/MVTCLI/CLI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct CLI: AsyncParsableCommand {
static var configuration = CommandConfiguration(
commandName: "mvt",
abstract: "A utility for inspecting and working with vector tiles.",
version: "1.4.0",
version: "1.5.0",
subcommands: [Dump.self, Info.self, Merge.self, Query.self, Export.self, Import.self],
defaultSubcommand: Dump.self)

Expand Down
11 changes: 6 additions & 5 deletions Sources/MVTCLI/Import.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ extension CLI {
tile.addGeoJson(geoJson: otherGeoJSON, layerName: layer)
}

let exportOptions = VectorTileExportOptions(
bufferSize: .extent(512),
compression: .level(9),
simplifyFeatures: .no)
tile.write(to: url, options: exportOptions)
tile.write(
to: url,
options: .init(
bufferSize: .extent(512),
compression: .level(9),
simplifyFeatures: .no))
}

}
Expand Down
11 changes: 6 additions & 5 deletions Sources/MVTCLI/Merge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ extension CLI {
tile.merge(otherTile)
}

let exportOptions = VectorTileExportOptions(
bufferSize: .extent(512),
compression: .level(9),
simplifyFeatures: .no)
tile.write(to: outputUrl, options: exportOptions)
tile.write(
to: outputUrl,
options: .init(
bufferSize: .extent(512),
compression: .level(9),
simplifyFeatures: .no))
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,37 @@ import Logging

// MARK: Reading vector tiles

extension VectorTile {
enum MVTDecoder {

static func vectorTile(from data: Data) -> VectorTile_Tile? {
var data = data
static func vectorTile(from mvtData: Data) -> VectorTile_Tile? {
var data = mvtData
if data.isGzipped {
data = (try? data.gunzipped()) ?? data
}

return try? VectorTile_Tile(serializedData: data)
}

static func loadTileFrom(
data: Data,
static func layers(
from mvtData: Data,
x: Int,
y: Int,
z: Int,
projection: Projection = .epsg4326,
layerWhitelist: Set<String>?,
logger: Logger?)
-> [String: LayerContainer]?
-> [String: VectorTile.LayerContainer]?
{
if data.isGzipped {
if mvtData.isGzipped {
(logger ?? VectorTile.logger)?.info("\(z)/\(x)/\(y): Input data is gzipped")
}

guard let tile = vectorTile(from: data) else {
guard let tile = vectorTile(from: mvtData) else {
(logger ?? VectorTile.logger)?.warning("\(z)/\(x)/\(y): Failed to create a vector tile from data")
return nil
}

var layers: [String: LayerContainer] = [:]
var layers: [String: VectorTile.LayerContainer] = [:]

var lastExtent = 0
var projectionFunction: ((_ x: Int, _ y: Int) -> Coordinate3D) = passThroughFromTile
Expand Down Expand Up @@ -73,7 +73,7 @@ extension VectorTile {
layerBoundingBox = boundingBoxes.reduce(boundingBoxes[0], +)
}

layers[name] = LayerContainer(
layers[name] = VectorTile.LayerContainer(
features: layerFeatures,
boundingBox: layerBoundingBox)

Expand Down Expand Up @@ -269,7 +269,7 @@ extension VectorTile {
commandCount = Int(commandInteger >> 3)

// ClosePath has no parameter
if commandId == VectorTile.commandIdClosePath {
if commandId == MVTDecoder.commandIdClosePath {
guard featureType != .point,
commandCount == 1,
coordinates.count > 1
Expand All @@ -291,10 +291,10 @@ extension VectorTile {
let dx: UInt32 = geometryIntegers[index]
let dy: UInt32 = geometryIntegers[index + 1]

x += VectorTile.zigZagDecode(Int(dx))
y += VectorTile.zigZagDecode(Int(dy))
x += MVTDecoder.zigZagDecode(Int(dx))
y += MVTDecoder.zigZagDecode(Int(dy))

if commandId == VectorTile.commandIdMoveTo,
if commandId == MVTDecoder.commandIdMoveTo,
!coordinates.isEmpty
{
result.append(coordinates)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import Gzip

// MARK: Writing vector tiles

extension VectorTile {
enum MVTEncoder {

static func tileDataFor(
layers: [String: LayerContainer],
static func mvtDataFor(
layers: [String: VectorTile.LayerContainer],
x: Int,
y: Int,
z: Int,
projection: Projection = .epsg4326,
options: VectorTileExportOptions)
options: VectorTile.ExportOptions)
-> Data?
{
var tile = VectorTile_Tile()
Expand Down Expand Up @@ -303,7 +303,7 @@ extension VectorTile {

// Encode points
if featureType == .point {
commandId = VectorTile.commandIdMoveTo
commandId = MVTEncoder.commandIdMoveTo
commandCount = UInt32(multiCoordinates.count)
commandInteger = (commandId & 0x7) | (commandCount << 3)
geometryIntegers.append(commandInteger)
Expand All @@ -312,8 +312,8 @@ extension VectorTile {
guard let moveToCoordinate = coordinates.first else { continue }

let (x, y) = projectionFunction(moveToCoordinate)
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(y) - dy)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(y) - dy)))
dx = x
dy = y
}
Expand All @@ -329,50 +329,50 @@ extension VectorTile {
let moveToCoordinate = coordinates.first
else { continue }

commandId = VectorTile.commandIdMoveTo
commandId = MVTEncoder.commandIdMoveTo
commandCount = 1
commandInteger = (commandId & 0x7) | (commandCount << 3)
geometryIntegers.append(commandInteger)

let (x, y) = projectionFunction(moveToCoordinate)
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(y) - dy)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(y) - dy)))
dx = x
dy = y

if featureType == .linestring
|| coordinates.get(at: 0) != coordinates.get(at: -1)
{
commandId = VectorTile.commandIdLineTo
commandId = MVTEncoder.commandIdLineTo
commandCount = UInt32(coordinates.count - 1)
commandInteger = (commandId & 0x7) | (commandCount << 3)
geometryIntegers.append(commandInteger)

for coordinate in coordinates[1...] {
let (x, y) = projectionFunction(coordinate)
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(y) - dy)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(y) - dy)))
dx = x
dy = y
}
}
else {
commandId = VectorTile.commandIdLineTo
commandId = MVTEncoder.commandIdLineTo
commandCount = UInt32(coordinates.count - 2)
commandInteger = (commandId & 0x7) | (commandCount << 3)
geometryIntegers.append(commandInteger)

for coordinate in coordinates[1 ..< coordinates.count - 1] {
let (x, y) = projectionFunction(coordinate)
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(VectorTile.zigZagEncode(Int(y) - dy)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(x) - dx)))
geometryIntegers.append(UInt32(MVTEncoder.zigZagEncode(Int(y) - dy)))
dx = x
dy = y
}
}

if featureType == .polygon {
commandId = VectorTile.commandIdClosePath
commandId = MVTEncoder.commandIdClosePath
commandCount = 1
commandInteger = (commandId & 0x7) | (commandCount << 3)
geometryIntegers.append(commandInteger)
Expand Down
72 changes: 72 additions & 0 deletions Sources/MVTTools/ExportOptions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#if !os(Linux)
import CoreLocation
#endif
import Foundation
import GISTools

@available(*, unavailable, renamed: "VectorTile.ExportOptions", message: "This struct has been moved to the VectorTile namespace")
public struct VectorTileExportOptions {}

extension VectorTile {

/// Various export options.
public struct ExportOptions {

/// Options for the buffer around tiles.
public enum BufferSizeOptions {
/// Use the same dimension as ``ExportOptions.extent``.
case extent(Int)
/// Use pixels (see ``ExportOptions.tileSize``).
case pixel(Int)
}

/// Gzip options.
public enum CompressionOptions: Equatable {
/// Don't compress the vector tile data.
case no
/// The default compression level (*6*).
case `default`
/// A compression level, between *0* (no compression) and *9* (best compression).
case level(Int)
}

/// Options for Feature simplification.
public enum SimplifyFeaturesOptions {
/// Don't simplify featutes.
case no
/// Use the same dimension as ``ExportOptions.extent``.
case extent(Int)
/// Use meters.
case meters(CLLocationDistance)
}

/// The grid width and height of one tile. Always 4096.
public let extent = 4096

/// The tile size in pixels. Always 256.
public let tileSize = 256

/// The buffer around the tile, either in pixels (see ``tileSize``) or in the same dimension as ``extent`` (default: **0**).
public var bufferSize: BufferSizeOptions = .extent(0)

/// Whether to enable compression or not (default: **no**)
///
/// Uses Gzip.
public var compression: CompressionOptions = .no

/// Simplify features before encoding them (default: **no**).
public var simplifyFeatures: SimplifyFeaturesOptions = .no

public init(
bufferSize: BufferSizeOptions = .extent(0),
compression: CompressionOptions = .no,
simplifyFeatures: SimplifyFeaturesOptions = .no)
{
self.bufferSize = bufferSize
self.compression = compression
self.simplifyFeatures = simplifyFeatures
}

}

}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extension VectorTile {

/// Read a tile from `data` and return its layer names
public static func layerNames(from data: Data) -> [String]? {
guard let tile = vectorTile(from: data) else { return nil }
guard let tile = MVTDecoder.vectorTile(from: data) else { return nil }
return tile.layers.map { $0.name }
}

Expand All @@ -33,7 +33,7 @@ extension VectorTile {

/// Read a tile from `data` and return some information about the tile
public static func tileInfo(from data: Data) -> [String: Any]? {
guard let tile = vectorTile(from: data) else { return nil }
guard let tile = MVTDecoder.vectorTile(from: data) else { return nil }

var layers: [[String: Any]] = []

Expand Down
File renamed without changes.
File renamed without changes.
16 changes: 8 additions & 8 deletions Sources/MVTTools/VectorTile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ public struct VectorTile: Sendable {
nil
}

guard let parsedLayers = VectorTile.loadTileFrom(
data: data,
guard let parsedLayers = MVTDecoder.layers(
from: data,
x: x,
y: y,
z: z,
Expand Down Expand Up @@ -260,8 +260,8 @@ public struct VectorTile: Sendable {
return nil
}

guard let parsedLayers = VectorTile.loadTileFrom(
data: data,
guard let parsedLayers = MVTDecoder.layers(
from: data,
x: x,
y: y,
z: z,
Expand Down Expand Up @@ -315,21 +315,21 @@ public struct VectorTile: Sendable {
extension VectorTile {

/// Returns the tile's content as MVT data
public func data(options: VectorTileExportOptions? = nil) -> Data? {
VectorTile.tileDataFor(
public func data(options: ExportOptions? = nil) -> Data? {
MVTEncoder.mvtDataFor(
layers: layers,
x: x,
y: y,
z: z,
projection: projection,
options: options ?? VectorTileExportOptions())
options: options ?? ExportOptions())
}

/// Writes the tile's content to `url` in MVT format
@discardableResult
public func write(
to url: URL,
options: VectorTileExportOptions? = nil)
options: ExportOptions? = nil)
-> Bool
{
guard let data: Data = data(options: options) else { return false }
Expand Down
Loading

0 comments on commit 47c805c

Please sign in to comment.