Skip to content

Commit

Permalink
Added a configuration option for applying ST_MakeValid to each geometry
Browse files Browse the repository at this point in the history
  • Loading branch information
trasch committed Oct 15, 2024
1 parent 179bd7c commit a8cb93d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
13 changes: 12 additions & 1 deletion Sources/MVTPostgis/MVTPostgis.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,16 @@ public final class MVTPostgis {
let geometryField = layer.datasource.geometryField?.nilIfEmpty ?? "geometry"
let simplificationOption = MVTPostgis.configuration.simplification(tile.z, self.source)
let clippingOption = MVTPostgis.configuration.clipping(tile.z, self.source)
let validationOption = MVTPostgis.configuration.validation(tile.z, self.source)
var columns = layer.fields.keys.map({ "\"\($0)\"" })
var useLocalSimplification = false

// Assemble the geometry query
var postgisGeometryColumn = "ST_AsBinary("
switch validationOption {
case .none: break
default: postgisGeometryColumn.append("ST_MakeValid(")
}
switch simplificationOption {
case .postgis, .meters(_, _): postgisGeometryColumn.append("ST_Simplify(")
case .local: useLocalSimplification = true
Expand All @@ -223,7 +228,13 @@ public final class MVTPostgis {
}
postgisGeometryColumn.append(")")
}
postgisGeometryColumn.append(") AS \"\(geometryField)\"")
postgisGeometryColumn.append(")")
switch validationOption {
case .none, .`default`, .linework: break
case let .structure(keepCollapsed):
postgisGeometryColumn.append(", 'method=structure keepcollapsed=\(keepCollapsed)')")
}
postgisGeometryColumn.append(" AS \"\(geometryField)\"")
columns.append(postgisGeometryColumn)

// The final query
Expand Down
33 changes: 30 additions & 3 deletions Sources/MVTPostgis/MVTPostgisConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public struct MVTPostgisConfiguration {
/// Controls if and how much features are simplified.
public let simplification: ((_ zoom: Int, _ source: PostgisSource) -> MVTSimplificationOption)

/// Controls whether `ST_MakeValid` should be applied to each geometry.
public let validation: ((_ zoom: Int, _ source: PostgisSource) -> MVTMakeValidOption)

/// Track SQL runtimes and return them together with the vector tile (default: false).
public let trackRuntimes: Bool

Expand All @@ -38,8 +41,9 @@ public struct MVTPostgisConfiguration {
tileTimeout: TimeInterval = 60.0,
poolSize: Int = 10,
maxIdleConnections: Int? = nil,
clipping: @escaping ((_ zoom: Int, _ source: PostgisSource) -> MVTClippingOption) = { _,_ in .postgis },
simplification: @escaping ((_ zoom: Int, _ source: PostgisSource) -> MVTSimplificationOption) = { _,_ in .none },
clipping: @escaping ((_ zoom: Int, _ source: PostgisSource) -> MVTClippingOption) = { _, _ in .postgis },
simplification: @escaping ((_ zoom: Int, _ source: PostgisSource) -> MVTSimplificationOption) = { _, _ in .none },
validation: @escaping ((_ zoom: Int, _ source: PostgisSource) -> MVTMakeValidOption) = { _, _ in .none },
trackRuntimes: Bool = false)
{
self.applicationName = applicationName
Expand All @@ -50,6 +54,7 @@ public struct MVTPostgisConfiguration {
self.maxIdleConnections = maxIdleConnections?.atLeast(0)
self.clipping = clipping
self.simplification = simplification
self.validation = validation
self.trackRuntimes = trackRuntimes
}

Expand Down Expand Up @@ -80,9 +85,31 @@ public enum MVTSimplificationOption {
case none
/// Do the simplification locally, before adding features to the vector tile.
case local
/// Do the simplification in Postgis with `ST_Simplify`.
/// Do the simplification in Postgis with `ST_Simplify` and a
/// simplification distance that depends on the zoom level.
case postgis(preserveCollapsed: Bool)
/// Simplification distance in meters, forwarded to `ST_Simplify`.
case meters(Double, preserveCollapsed: Bool)

}

// MARK: - Validation

/// Controls whether `ST_MakeValid` should be applied to each geometry.
public enum MVTMakeValidOption {

/// No validation will be done.
case none
/// Same as `linework`.
case `default`
/// Builds valid geometries by first extracting all lines, noding that linework together,
/// then building a value output from the linework.
case linework
/// "structure" is an algorithm that distinguishes between interior and exterior rings,
/// building a new geometry by unioning exterior rings, and then differencing all interior rings.
///
/// "keepcollapsed" controls whether geometry components that collapse to a lower dimensionality,
/// for example a one-point linestring should be dropped.
case structure(keepCollapsed: Bool)

}

0 comments on commit a8cb93d

Please sign in to comment.