Skip to content

Commit

Permalink
🎨 Remove most genericity from GeodeticGeometry
Browse files Browse the repository at this point in the history
  • Loading branch information
RemiBardon committed Dec 1, 2022
1 parent 152354d commit 593393a
Show file tree
Hide file tree
Showing 22 changed files with 421 additions and 870 deletions.
9 changes: 7 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import PackageDescription
let package = Package(
name: "swift-geo",
platforms: [
.macOS(.v10_15),
// TODO: Support `.macOS(.v10_15)` again by using a backwards compatile logging system
.macOS(.v11),
],
products: [
// Products define the executables and libraries a package produces,
Expand Down Expand Up @@ -127,7 +128,11 @@ let package = Package(
.target(name: "WGS84Turf", dependencies: ["WGS84Geometry", "Turf"]),

// 🎭 Conversions from one Coordinate Reference System to another
.target(name: "GeodeticConversions", dependencies: ["Geodesy", "WGS84Core"]),
.target(name: "GeodeticConversions", dependencies: [
"Geodesy",
"GeodeticGeometry",
"WGS84Core",
]),
.testTarget(name: "GeodeticConversionsTests", dependencies: [
"GeodeticConversions",
"WGS84Conversions",
Expand Down
69 changes: 38 additions & 31 deletions Sources/Geodesy/Geodesy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public protocol EPSGItem {
// MARK: - Coordinates

public protocol Coordinates<CRS>:
Equatable,
Hashable,
Zeroable,
AdditiveArithmetic,
MultiplicativeArithmetic,
Expand All @@ -29,20 +29,33 @@ public protocol Coordinates<CRS>:
CustomDebugStringConvertible
{
associatedtype CRS: Geodesy.CoordinateReferenceSystem
associatedtype Components

var components: Components { get set }

init(components: Components)
}

// CustomStringConvertible & CustomDebugStringConvertible
public extension Coordinates {
var description: String { String(describing: self.components) }
var debugDescription: String {
"<\(Self.CRS.epsgName)>\(String(reflecting: self.components))"
}
}

// MARK: 2D Coordinates

public protocol TwoDimensionalCoordinates<CRS>: Geodesy.Coordinates
where CRS: TwoDimensionalCRS
{
public protocol AtLeastTwoDimensionalCoordinates<CRS>: Geodesy.Coordinates
where CRS: AtLeastTwoDimensionalCRS {
associatedtype X: CoordinateComponent
associatedtype Y: CoordinateComponent

var x: X { get set }
var y: Y { get set }
var components: (X, Y) { get set }

}
public protocol TwoDimensionalCoordinates<CRS>: AtLeastTwoDimensionalCoordinates
where Components == (X, Y) {
init(x: X, y: Y)
}

Expand All @@ -68,6 +81,9 @@ where CRS: TwoDimensionalCRS
self.x = x
self.y = y
}
public init(components: (X, Y)) {
self.init(x: components.0, y: components.1)
}
}

// Zeroable
Expand Down Expand Up @@ -107,12 +123,6 @@ public extension Coordinates2DOf {
}
}

// CustomStringConvertible & CustomDebugStringConvertible
public extension Coordinates2DOf {
var description: String { String(describing: self.components) }
var debugDescription: String { String(reflecting: self.components) }
}

public extension Coordinates2DOf where CRS: GeographicCRS {
var latitude: X { self.x }
var longitude: Y { self.y }
Expand All @@ -123,7 +133,7 @@ public extension Coordinates2DOf where CRS: GeographicCRS {

public extension Coordinates2DOf
where CRS: GeographicCRS,
Self.Y: AngularCoordinateComponent
Y: AngularCoordinateComponent
{
var withPositiveLongitude: Self {
Self.init(latitude: self.latitude, longitude: self.longitude.positive)
Expand All @@ -132,18 +142,14 @@ where CRS: GeographicCRS,

// MARK: 3D Coordinates

public protocol ThreeDimensionalCoordinates<CRS>: Geodesy.Coordinates
where CRS: ThreeDimensionalCRS
{
associatedtype X: CoordinateComponent
associatedtype Y: CoordinateComponent
public protocol AtLeastThreeDimensionalCoordinates<CRS>: AtLeastTwoDimensionalCoordinates
where CRS: AtLeastTwoDimensionalCRS {
associatedtype Z: CoordinateComponent

var x: X { get set }
var y: Y { get set }
var z: Z { get set }
var components: (X, Y, Z) { get set }

}
public protocol ThreeDimensionalCoordinates<CRS>: AtLeastThreeDimensionalCoordinates
where Components == (X, Y, Z) {
init(x: X, y: Y, z: Z)
}

Expand Down Expand Up @@ -171,6 +177,9 @@ public struct Coordinates3DOf<CRS: ThreeDimensionalCRS>: ThreeDimensionalCoordin
self.y = y
self.z = z
}
public init(components: (X, Y, Z)) {
self.init(x: components.0, y: components.1, z: components.2)
}
}

// Zeroable
Expand Down Expand Up @@ -210,12 +219,6 @@ public extension Coordinates3DOf {
}
}

// CustomStringConvertible & CustomDebugStringConvertible
public extension Coordinates3DOf {
var description: String { String(describing: self.components) }
var debugDescription: String { String(reflecting: self.components) }
}

public extension ThreeDimensionalCoordinates where CRS: GeographicCRS {
var latitude: X { self.x }
var longitude: Y { self.y }
Expand All @@ -227,7 +230,7 @@ public extension ThreeDimensionalCoordinates where CRS: GeographicCRS {

public extension ThreeDimensionalCoordinates
where CRS: GeographicCRS,
Self.Y: AngularCoordinateComponent
Y: AngularCoordinateComponent
{
var withPositiveLongitude: Self {
Self.init(
Expand All @@ -247,13 +250,17 @@ public protocol CoordinateReferenceSystem: EPSGItem {
}

public protocol AtLeastTwoDimensionalCRS: CoordinateReferenceSystem
where CoordinateSystem: AtLeastTwoDimensionalCS {}
where CoordinateSystem: AtLeastTwoDimensionalCS,
Coordinates: AtLeastTwoDimensionalCoordinates
{}
public protocol TwoDimensionalCRS: AtLeastTwoDimensionalCRS
where CoordinateSystem: TwoDimensionalCS,
Coordinates: TwoDimensionalCoordinates
{}
public protocol AtLeastThreeDimensionalCRS: AtLeastTwoDimensionalCRS
where CoordinateSystem: AtLeastThreeDimensionalCS {}
where CoordinateSystem: AtLeastThreeDimensionalCS,
Coordinates: AtLeastThreeDimensionalCoordinates
{}
public protocol ThreeDimensionalCRS: AtLeastThreeDimensionalCRS
where CoordinateSystem: ThreeDimensionalCS,
Coordinates: ThreeDimensionalCoordinates
Expand Down
16 changes: 16 additions & 0 deletions Sources/GeodeticConversions/ConvertibleCRS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Geodesy
import GeodeticGeometry
import WGS84Core

public protocol ConvertibleCRS: CoordinateReferenceSystem {
Expand Down Expand Up @@ -36,3 +37,18 @@ public extension Coordinates3DOf<EPSG4978> {
NewCRS.fromEPSG4978(self) as! C
}
}

public extension Point {
static func + <OtherCRS>(lhs: Self, rhs: Point<OtherCRS>) -> Self
where CRS: ConvertibleCRS, OtherCRS: ConvertibleCRS
{
Self.init(coordinates: lhs.coordinates + rhs.coordinates.to(to: OtherCRS.self))
}
}

public extension Vector {
init<OtherCRS>(from: Point<CRS>, to: Point<OtherCRS>)
where CRS: ConvertibleCRS, OtherCRS: ConvertibleCRS {
self.init(rawValue: to.coordinates.to(CRS.self) - from.coordinates)
}
}
45 changes: 22 additions & 23 deletions Sources/GeodeticGeometry/Concepts/BoundingBox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,32 @@
import Geodesy
import SwiftGeoToolbox

public protocol BoundingBox<GeometricSystem>: Hashable, Zeroable {

typealias CRS = GeometricSystem.CRS
associatedtype GeometricSystem: GeodeticGeometry.GeometricSystem<CRS>
typealias Coordinates = GeometricSystem.Coordinates
typealias Size = GeometricSystem.Size

var origin: Coordinates { get }
var size: Size { get }

init(origin: Coordinates, size: Size)
init(min: Coordinates, max: Coordinates)
public struct BoundingBox<CRS: Geodesy.CoordinateReferenceSystem> {
public typealias Coordinates = CRS.Coordinates
public typealias Size = GeodeticGeometry.Size<CRS>

public var origin: Self.Coordinates
public var size: Self.Size

public var center: Self.Coordinates {
self.origin + self.size / 2
}

public init(origin: Self.Coordinates, size: Self.Size) {
self.origin = origin
self.size = size
}
public init(min: Self.Coordinates, max: Self.Coordinates) {
self.init(origin: min, size: .init(from: min, to: max))
}

#warning("TODO: Reimplement `BoundingBox.union(_ other: Self)`")
/// The union of bounding boxes gives a new bounding box that encloses the given two.
// func union(_ other: Self) -> Self

// public func union(_ other: Self) -> Self
}

public extension BoundingBox {

static var zero: Self {
Self.init(origin: .zero, size: .zero)
}
extension BoundingBox: Hashable {}

init(min: Coordinates, max: Coordinates) {
self.init(origin: min, size: Size.init(from: min, to: max))
}

extension BoundingBox: Zeroable {
public static var zero: Self { Self.init(origin: .zero, size: .zero) }
}
111 changes: 10 additions & 101 deletions Sources/GeodeticGeometry/Concepts/Size.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,116 +2,25 @@
// Size.swift
// SwiftGeo
//
// Created by Rémi Bardon on 26/03/2022.
// Created by Rémi Bardon on 28/11/2022.
// Copyright © 2022 Rémi Bardon. All rights reserved.
//

import Geodesy
import SwiftGeoToolbox

public protocol Size<GeometricSystem>:
Hashable,
SafeRawRepresentable,
Zeroable,
AdditiveArithmetic,
MultiplicativeArithmetic,
InitializableByNumber
{
typealias CRS = GeometricSystem.CRS
associatedtype GeometricSystem: GeodeticGeometry.GeometricSystem
public typealias Size = Vector

init(from: GeometricSystem.Coordinates, to: GeometricSystem.Coordinates)
}

public extension Size where RawValue: Zeroable {
static var zero: Self { Self.init(rawValue: .zero) }
}

public extension Size where RawValue: InitializableByInteger {
init<Source>(_ value: Source) where Source: BinaryInteger {
self.init(rawValue: .init(value))
}
}

public extension Size where RawValue: InitializableByFloatingPoint {
init<Source>(_ value: Source) where Source: BinaryFloatingPoint {
self.init(rawValue: .init(value))
}
}

public extension Size where RawValue == GeometricSystem.Point.Coordinates {
init(from: GeometricSystem.Coordinates, to: GeometricSystem.Coordinates) {
self.init(rawValue: to - from)
}
}

public extension Size where RawValue: AdditiveArithmetic {
static func + (lhs: Self, rhs: Self) -> Self {
Self.init(rawValue: lhs.rawValue + rhs.rawValue)
}
static func - (lhs: Self, rhs: Self) -> Self {
Self.init(rawValue: lhs.rawValue - rhs.rawValue)
}
}

public extension Size where RawValue: MultiplicativeArithmetic {
static func * (lhs: Self, rhs: Self) -> Self {
Self.init(rawValue: lhs.rawValue * rhs.rawValue)
}
static func / (lhs: Self, rhs: Self) -> Self {
Self.init(rawValue: lhs.rawValue / rhs.rawValue)
}
}

// MARK: - 2D

public extension Size where RawValue: AtLeastTwoDimensionalCoordinate {
var dx: RawValue.X { self.rawValue.x }
var dy: RawValue.Y { self.rawValue.y }

/// - Warning: In a geographic CRS, ``Size2D/width`` represents the vertical length,
/// because ``Size2D/DX`` represents the latitude (vertical axis).
/// You can use ``Size2D/horizontalDelta`` to remove ambiguity.
public extension Size where RawValue: AtLeastTwoDimensionalCoordinates {
/// - Warning: In a geographic CRS, ``Vector2D/width`` represents the vertical length,
/// because ``Vector2D/DX`` represents the latitude (vertical axis).
/// You can use ``Vector2D/horizontalDelta`` to remove ambiguity.
var width: RawValue.X { self.dx }
/// - Warning: In a geographic CRS, ``Size2D/height`` represents the horizontal length,
/// because ``Size2D/DY`` represents the longitude (horizontal axis).
/// You can use ``Size2D/horizontalDelta`` to remove ambiguity.
/// - Warning: In a geographic CRS, ``Vector2D/height`` represents the horizontal length,
/// because ``Vector2D/DY`` represents the longitude (horizontal axis).
/// You can use ``Vector2D/horizontalDelta`` to remove ambiguity.
var height: RawValue.Y { self.dy }

var verticalDelta: RawValue.X { self.dx }
var horizontalDelta: RawValue.Y { self.dy }
}

public protocol Size2D<GeometricSystem>: Size {
associatedtype DX: CoordinateComponent
associatedtype DY: CoordinateComponent

/// - Warning: In a geographic CRS, ``Size2D/dx`` represents the vertical length,
/// because ``Size2D/DX`` represents the latitude (vertical axis).
/// You can use ``Size2D/verticalDelta`` to remove ambiguity.
var dx: DX { get }
/// - Warning: In a geographic CRS, ``Size2D/dy`` represents the horizontal length,
/// because ``Size2D/DY`` represents the longitude (horizontal axis).
/// You can use ``Size2D/horizontalDelta`` to remove ambiguity.
var dy: DY { get }

var verticalDelta: DX { get }
var horizontalDelta: DY { get }
}

public extension Size2D {
var verticalDelta: DX { self.dx }
var horizontalDelta: DY { self.dy }
}

// MARK: - 3D

public extension Size where RawValue: AtLeastThreeDimensionalCoordinate {
var dz: RawValue.Z { self.rawValue.z }
public extension Size where RawValue: AtLeastThreeDimensionalCoordinates {
var zHeight: RawValue.Z { self.dz }
}

public protocol Size3D<GeometricSystem>: Size2D {
associatedtype DZ: CoordinateComponent
var dz: DZ { get }
}
Loading

0 comments on commit 593393a

Please sign in to comment.