Skip to content

Commit be1d47e

Browse files
committed
🚧 WIP Remove some genericity from Geodesy
1 parent cfa5256 commit be1d47e

File tree

3 files changed

+221
-410
lines changed

3 files changed

+221
-410
lines changed

Sources/Geodesy/Conversions.swift

Lines changed: 60 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,105 +8,105 @@
88

99
import Foundation
1010

11-
public protocol Conversion<OldCRS, NewCRS> {
12-
associatedtype OldCRS: CoordinateReferenceSystem
13-
associatedtype NewCRS: CoordinateReferenceSystem
11+
public protocol Conversion<C1, C2> {
12+
associatedtype C1: Coordinates
13+
associatedtype C2: Coordinates
14+
associatedtype EPSGRef: EPSGItem
1415

15-
// static var name: String { get }
16-
// static var code: Int { get }
17-
18-
static func apply<C1: Coordinates<OldCRS>, C2: Coordinates<NewCRS>>(on coordinate: C1) -> C2
16+
static func apply(on coordinate: C1) -> C2
1917
}
2018

2119
public protocol ReversibleConversion: Conversion {
22-
static func unapply<C1: Coordinates<OldCRS>, C2: Coordinates<NewCRS>>(from coordinate: C2) -> C1
20+
static func unapply(from coordinate: C2) -> C1
2321
}
2422

2523
// MARK: EPSG 9659 (Geographic 3D to 2D conversions)
2624

27-
public enum EPSG9659<OldCRS, NewCRS>: ReversibleConversion
28-
where OldCRS: GeographicCRS & ThreeDimensionalCRS,
29-
NewCRS: GeographicCRS & TwoDimensionalCRS,
30-
NewCRS.Datum.PrimeMeridian == OldCRS.Datum.PrimeMeridian
25+
public enum EPSG9659Ref: EPSGItem {
26+
public static let epsgName: String = "Geographic 3D to 2D conversions"
27+
public static let epsgCode: Int = 9659
28+
}
29+
30+
public enum EPSG9659<C1, C2>: ReversibleConversion
31+
where C1: ThreeDimensionalCoordinates,
32+
C1.CRS: GeographicCRS,
33+
C2: TwoDimensionalCoordinates,
34+
C2.CRS: GeographicCRS,
35+
C2.CRS.Datum.PrimeMeridian == C1.CRS.Datum.PrimeMeridian
3136
{
32-
// FIXME: Static stored properties not supported in generic types
33-
// static let name: String = "Geographic 3D to 2D conversions"
34-
// static let code: Int = 9659
37+
public typealias EPSGRef = EPSG9659Ref
3538

3639
/// Geographic 3D to 2D conversion.
3740
///
3841
/// <https://drive.tiny.cloud/1/4m326iu12oa8re9cjiadxonharclteqb4mumfxj71zsttwkx/5e0ec79e-49fa-4e7a-acca-3d6f6c989877> section 4.1.4
39-
public static func apply<
40-
C1: Coordinates<OldCRS>,
41-
C2: Coordinates<NewCRS>
42-
>(on coordinate: C1) -> C2 {
43-
return C2.init(x: .init(coordinate.x), y: .init(coordinate.y))
42+
public static func apply(on coordinate: C1) -> C2 {
43+
return .init(x: .init(coordinate.x), y: .init(coordinate.y))
4444
}
4545

4646
/// Geographic 2D to 3D conversion.
4747
///
4848
/// <https://drive.tiny.cloud/1/4m326iu12oa8re9cjiadxonharclteqb4mumfxj71zsttwkx/5e0ec79e-49fa-4e7a-acca-3d6f6c989877> section 4.1.1
49-
public static func unapply<
50-
C1: Coordinates<OldCRS>,
51-
C2: Coordinates<NewCRS>
52-
>(from coordinate: C2) -> C1 {
53-
return C1.init(x: .init(Double(coordinate.x)), y: .init(coordinate.y), z: .init(0.0))
49+
public static func unapply(from coordinate: C2) -> C1 {
50+
return .init(x: .init(Double(coordinate.x)), y: .init(coordinate.y), z: .init(0.0))
5451
}
5552
}
5653

57-
public extension ThreeDimensionalCoordinate {
54+
public extension ThreeDimensionalCoordinates where CRS: GeographicCRS {
5855
func transformed<NewCRS, C: Coordinates<NewCRS>>(to _: C.Type) -> C
59-
where CRS: GeographicCRS,
60-
NewCRS: GeographicCRS & TwoDimensionalCRS,
56+
where C: TwoDimensionalCoordinates,
57+
NewCRS: GeographicCRS,
6158
NewCRS.Datum.PrimeMeridian == CRS.Datum.PrimeMeridian
6259
{
63-
EPSG9659<CRS, NewCRS>.apply(on: self)
60+
EPSG9659<Self, C>.apply(on: self)
6461
}
65-
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinate2DOf<NewCRS>
66-
where CRS: GeographicCRS,
67-
NewCRS: GeographicCRS & TwoDimensionalCRS,
62+
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinates2D<NewCRS>
63+
where NewCRS: GeographicCRS & TwoDimensionalCRS,
6864
NewCRS.Datum.PrimeMeridian == CRS.Datum.PrimeMeridian
6965
{
70-
EPSG9659<CRS, NewCRS>.apply(on: self)
66+
EPSG9659<Self, Coordinates2D<NewCRS>>.apply(on: self)
7167
}
7268
}
7369

74-
public extension TwoDimensionalCoordinate {
70+
public extension TwoDimensionalCoordinates where CRS: GeographicCRS {
7571
func transformed<NewCRS, C: Coordinates<NewCRS>>(to _: C.Type) -> C
76-
where CRS: GeographicCRS,
77-
NewCRS: GeographicCRS & ThreeDimensionalCRS,
72+
where C: ThreeDimensionalCoordinates,
73+
NewCRS: GeographicCRS,
7874
NewCRS.Datum.PrimeMeridian == CRS.Datum.PrimeMeridian
7975
{
80-
EPSG9659<NewCRS, CRS>.unapply(from: self)
76+
EPSG9659<C, Self>.unapply(from: self)
8177
}
82-
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinate3DOf<NewCRS>
83-
where CRS: GeographicCRS,
84-
NewCRS: GeographicCRS & ThreeDimensionalCRS,
78+
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinates3D<NewCRS>
79+
where NewCRS: GeographicCRS & ThreeDimensionalCRS,
8580
NewCRS.Datum.PrimeMeridian == CRS.Datum.PrimeMeridian
8681
{
87-
EPSG9659<NewCRS, CRS>.unapply(from: self)
82+
EPSG9659<Coordinates3D<NewCRS>, Self>.unapply(from: self)
8883
}
8984
}
9085

9186
// MARK: EPSG 9602 (Geographic/geocentric conversions)
9287

93-
public enum EPSG9602<OldCRS, NewCRS>: ReversibleConversion
94-
where OldCRS: GeographicCRS & ThreeDimensionalCRS,
95-
NewCRS: GeocentricCRS & ThreeDimensionalCRS,
96-
NewCRS.Datum.PrimeMeridian == OldCRS.Datum.PrimeMeridian
88+
public enum EPSG9602Ref: EPSGItem {
89+
public static let epsgName: String = "Geographic/geocentric conversions"
90+
public static let epsgCode: Int = 9602
91+
}
92+
93+
public enum EPSG9602<C1, C2>: ReversibleConversion
94+
where C1: ThreeDimensionalCoordinates,
95+
C1.CRS: GeographicCRS,
96+
C2: ThreeDimensionalCoordinates,
97+
C2.CRS: GeocentricCRS,
98+
C2.CRS.Datum.PrimeMeridian == C1.CRS.Datum.PrimeMeridian
9799
{
98-
// FIXME: Static stored properties not supported in generic types
99-
// static let name: String = "Geographic/geocentric conversions"
100-
// static let code: Int = 9602
100+
public typealias EPSGRef = EPSG9602Ref
101+
102+
typealias OldCRS = C1.CRS
103+
typealias NewCRS = C2.CRS
101104

102105
/// Geographic to geocentric conversion.
103106
///
104107
/// <https://epsg.org/coord-operation-method_9602/Geographic-geocentric-conversions.html>
105108
/// <https://drive.tiny.cloud/1/4m326iu12oa8re9cjiadxonharclteqb4mumfxj71zsttwkx/5e0ec79e-49fa-4e7a-acca-3d6f6c989877> page 101
106-
public static func apply<
107-
C1: Coordinates<OldCRS>,
108-
C2: Coordinates<NewCRS>
109-
>(on coordinate: C1) -> C2 {
109+
public static func apply(on coordinate: C1) -> C2 {
110110
// φ and λ are respectively the latitude and longitude (related to Greenwich) of the point
111111
let φ = Double(coordinate.x).toRadians
112112
let λ = Double(coordinate.y).toRadians
@@ -123,17 +123,14 @@ where OldCRS: GeographicCRS & ThreeDimensionalCRS,
123123
let y = (ν + h) * cos(φ) * sin(λ)
124124
let z = ((1 - e2) * ν + h) * sin(φ)
125125

126-
return C2.init(x: .init(x), y: .init(y), z: .init(z))
126+
return .init(x: .init(x), y: .init(y), z: .init(z))
127127
}
128128

129129
/// Geocentric to geographic conversion.
130130
///
131131
/// <https://epsg.org/coord-operation-method_9602/Geographic-geocentric-conversions.html>
132132
/// <https://drive.tiny.cloud/1/4m326iu12oa8re9cjiadxonharclteqb4mumfxj71zsttwkx/5e0ec79e-49fa-4e7a-acca-3d6f6c989877> page 101
133-
public static func unapply<
134-
C1: Coordinates<OldCRS>,
135-
C2: Coordinates<NewCRS>
136-
>(from coordinate: C2) -> C1 {
133+
public static func unapply(from coordinate: C2) -> C1 {
137134
let x = Double(coordinate.x)
138135
let y = Double(coordinate.y)
139136
let z = Double(coordinate.z)
@@ -157,25 +154,25 @@ where OldCRS: GeographicCRS & ThreeDimensionalCRS,
157154
// h = (p / cos φ) - ν
158155
let h = (p / cos(φ)) - ν
159156

160-
return C1.init(x: .init(φ.fromRadians), y: .init(λ.fromRadians), z: .init(h))
157+
return .init(x: .init(φ.fromRadians), y: .init(λ.fromRadians), z: .init(h))
161158
}
162159
}
163160

164-
public extension ThreeDimensionalCoordinate {
165-
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinate3DOf<NewCRS>
161+
public extension ThreeDimensionalCoordinates {
162+
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinates3D<NewCRS>
166163
where CRS: GeographicCRS,
167164
NewCRS: GeocentricCRS & ThreeDimensionalCRS,
168165
NewCRS.Datum.PrimeMeridian == CRS.Datum.PrimeMeridian
169166
{
170-
EPSG9602<CRS, NewCRS>.apply(on: self)
167+
EPSG9602<Self, Coordinates3D<NewCRS>>.apply(on: self)
171168
}
172169

173-
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinate3DOf<NewCRS>
170+
func transformed<NewCRS>(toCRS newCRS: NewCRS.Type) -> Coordinates3D<NewCRS>
174171
where CRS: GeocentricCRS,
175172
NewCRS: GeographicCRS & ThreeDimensionalCRS,
176173
NewCRS.Datum.PrimeMeridian == CRS.Datum.PrimeMeridian
177174
{
178-
EPSG9602<NewCRS, CRS>.unapply(from: self)
175+
EPSG9602<Coordinates3D<NewCRS>, Self>.unapply(from: self)
179176
}
180177
}
181178

0 commit comments

Comments
 (0)