Skip to content

Commit

Permalink
Adds GeoDrawer.ProjectionMode helper, including .automatic mode (#28
Browse files Browse the repository at this point in the history
)
  • Loading branch information
nighthawk authored Sep 18, 2024
1 parent 692a17e commit d677644
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
74 changes: 74 additions & 0 deletions Sources/GeoDrawer/helpers/BoundingBox+Helpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// BoundingBox+Helpers.swift
// GeoProjector
//
// Created by Adrian Schönig on 18/9/2024.
//

import GeoJSONKit

extension GeoJSON.BoundingBox {

public static func suggestedBox(for positions: [GeoJSON.Position], allowSpanningAntimeridian: Bool = true) -> GeoJSON.BoundingBox {
if positions.count == 1, let only = positions.first {
let extended1 = only.coordinate(at: 10_000, facing: 45)
let extended2 = only.coordinate(at: 10_000, facing: 225)
return GeoJSON.BoundingBox(positions: [extended1, extended2])

} else {
let smallestBoundingBox = GeoJSON.BoundingBox(positions: positions, allowSpanningAntimeridian: allowSpanningAntimeridian)
let fittedBoundingBox: GeoJSON.BoundingBox
if smallestBoundingBox.spansAntimeridian, smallestBoundingBox.longitudeSpan > 180 {
fittedBoundingBox = GeoJSON.BoundingBox(positions: positions, allowSpanningAntimeridian: false)
} else {
fittedBoundingBox = smallestBoundingBox
}
let paddedBoundingBox = fittedBoundingBox.scaled(x: 1.1, y: 1.1)
return paddedBoundingBox
}
}

public var latitudeSpan: Double {
northEasterlyLatitude - southWesterlyLatitude
}

public var longitudeSpan: Double {
if spansAntimeridian {
return northEasterlyLongitude + 360 - southWesterlyLongitude
} else {
return northEasterlyLongitude - southWesterlyLongitude
}
}

public var aspectRatio: Double {
if longitudeSpan > 0, latitudeSpan > 0 {
return longitudeSpan / latitudeSpan
} else {
return 0
}
}

public func scaled(x: Double, y: Double) -> GeoJSON.BoundingBox {
let latitudeDelta = (latitudeSpan * y - latitudeSpan) / 2
let longitudeDelta = (longitudeSpan * x - longitudeSpan) / 2
let candidate = GeoJSON.BoundingBox(
positions: [
.init(latitude: northEasterlyLatitude + latitudeDelta, longitude: northEasterlyLongitude + longitudeDelta),
.init(latitude: northEasterlyLatitude - latitudeDelta, longitude: northEasterlyLongitude - longitudeDelta),
.init(latitude: southWesterlyLatitude + latitudeDelta, longitude: southWesterlyLongitude + longitudeDelta),
.init(latitude: southWesterlyLatitude - latitudeDelta, longitude: southWesterlyLongitude - longitudeDelta),
],
allowSpanningAntimeridian: spansAntimeridian // don't change that
)

// Scaling shouldn't allow going outside the valid latitude bounds. If it
// does, just abort and return un-scaled bounding box.
let validLatitudes = (-90.0)...(90.0)
if validLatitudes.contains(candidate.northEasterlyLatitude), validLatitudes.contains(candidate.southWesterlyLatitude) {
return candidate
} else {
return self
}
}

}
41 changes: 41 additions & 0 deletions Sources/GeoDrawer/styling/GeoDrawer+ProjectionMode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// GeoDrawer+ProjectionMode.swift
// GeoProjector
//
// Created by Adrian Schönig on 18/9/2024.
//

import GeoJSONKit

extension GeoDrawer {
public enum ProjectionMode: String {
case automatic

case mercator
case equirectangular
case equalEarth
case gallPeters
case azimuthal
case orthographic

public func resolve(for boundingBox: GeoJSON.BoundingBox) -> Projection {

switch self {
case .automatic where max(boundingBox.longitudeSpan, boundingBox.latitudeSpan) < 180, .orthographic:
return Projections.Orthographic(reference: boundingBox.center)
case .equalEarth, .automatic:
return Projections.EqualEarth(reference: boundingBox.center)

case .mercator:
return Projections.Mercator(reference: boundingBox.center)
case .equirectangular:
return Projections.Equirectangular(reference: boundingBox.center)
case .gallPeters:
return Projections.GallPeters(reference: boundingBox.center)
case .azimuthal:
return Projections.AzimuthalEquidistant(reference: boundingBox.center)
}

}
}
}

0 comments on commit d677644

Please sign in to comment.