Skip to content

Commit daa883b

Browse files
committed
Added handling for GPX Routes
1 parent 25cdb0f commit daa883b

4 files changed

Lines changed: 153 additions & 2 deletions

File tree

Sources/RCGPX/GPXDocument.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@ public struct GPXDocument {
1717
public var waypoints: [GPXWaypoint]
1818
/// An array of `GPXTrack` contained in this GPX file
1919
public var tracks: [GPXTrack]
20+
/// An array of `GPXRoute` contained in this GPX file
21+
public var routes: [GPXRoute]
2022

2123
public init(
2224
creator: String? = nil,
2325
waypoints: [GPXWaypoint] = [],
24-
tracks: [GPXTrack] = []
26+
tracks: [GPXTrack] = [],
27+
routes: [GPXRoute] = []
2528
) {
2629
self.creator = creator
2730
self.waypoints = waypoints
2831
self.tracks = tracks
32+
self.routes = routes
2933
}
3034
}
3135

@@ -34,7 +38,7 @@ public struct GPXDocument {
3438
public extension GPXDocument {
3539
/// Returns an array of all `GPXFeatures` in the document in no particular order.
3640
var features: [GPXFeature] {
37-
waypoints + tracks
41+
waypoints + tracks + routes
3842
}
3943

4044
/// Returns the full string representation of the GPX file.

Sources/RCGPX/GPXRoute.swift

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// GPXRoute.swift
3+
//
4+
//
5+
// Created by Ryan Linn on 3/28/23.
6+
//
7+
8+
import AEXML
9+
import CoreLocation
10+
import Foundation
11+
12+
/// A representation of a route of travel.
13+
public struct GPXRoute: GPXFeature {
14+
public var name: String
15+
public var gpxDescription: String?
16+
public var routePoints: [GPXRoute.Point]
17+
18+
public init(
19+
name: String,
20+
description: String?,
21+
routePoints: [GPXRoute.Point]
22+
) {
23+
self.name = name
24+
self.gpxDescription = description
25+
self.routePoints = routePoints
26+
}
27+
28+
public init(
29+
name: String,
30+
description: String?,
31+
coordinates: [CLLocationCoordinate2D]
32+
) {
33+
self.name = name
34+
self.gpxDescription = description
35+
self.routePoints = coordinates.map(Point.init)
36+
}
37+
}
38+
39+
extension GPXRoute {
40+
public struct Point {
41+
public var latitude: Double
42+
public var longitude: Double
43+
44+
public var coordinate: CLLocationCoordinate2D {
45+
get {
46+
CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
47+
}
48+
set {
49+
latitude = newValue.latitude
50+
longitude = newValue.longitude
51+
}
52+
}
53+
54+
public init(
55+
latitude: Double,
56+
longitude: Double
57+
) {
58+
self.latitude = latitude
59+
self.longitude = longitude
60+
}
61+
62+
public init(_ coordinate: CLLocationCoordinate2D) {
63+
self.latitude = coordinate.latitude
64+
self.longitude = coordinate.longitude
65+
}
66+
}
67+
}

Sources/RCGPX/Internal/GPXDocument+Internals.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@ extension GPXDocument: GPXElement {
2121
waypoints = try waypointElements.map { try GPXWaypoint(xml: $0) }
2222
let trackElements = xml.children.filter { $0.name == GPXTrack.xmlTag }
2323
tracks = try trackElements.map { try GPXTrack(xml: $0) }
24+
let routeElements = xml.children.filter { $0.name == GPXRoute.xmlTag }
25+
routes = try routeElements.map { try GPXRoute(xml: $0) }
2426
}
2527

2628
var xmlElement: AEXMLElement {
2729
let element = AEXMLElement(name: Self.xmlTag)
2830
element.attributes["creator"] = creator
2931
element.addChildren(waypoints.map(\.xmlElement))
3032
element.addChildren(tracks.map(\.xmlElement))
33+
element.addChildren(routes.map(\.xmlElement))
3134
return element
3235
}
3336
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// GPXRoute+Internals.swift
3+
//
4+
//
5+
// Created by Ryan Linn on 3/28/23.
6+
//
7+
8+
import AEXML
9+
import Foundation
10+
11+
// MARK: GPXRoute: GPXElement
12+
13+
extension GPXRoute: GPXElement {
14+
static var xmlTag: String {
15+
"rte"
16+
}
17+
18+
init(xml: AEXMLElement) throws {
19+
guard let nameElement = xml["name"].value else {
20+
throw GPXError.missingRequiredElement("name")
21+
}
22+
name = nameElement
23+
24+
gpxDescription = xml["desc"].value
25+
26+
routePoints = try xml
27+
.children
28+
.filter { $0.name == GPXRoute.Point.xmlTag }
29+
.map { try GPXRoute.Point(xml: $0) }
30+
}
31+
32+
var xmlElement: AEXMLElement {
33+
let element = AEXMLElement(name: Self.xmlTag)
34+
element.addChild(name: "name", value: name)
35+
if let desc = gpxDescription {
36+
element.addChild(name: "desc", value: desc)
37+
}
38+
element.addChildren(routePoints.map(\.xmlElement))
39+
return element
40+
}
41+
}
42+
43+
// MARK: GPXRoute.Point: GPXElement
44+
45+
extension GPXRoute.Point: GPXElement {
46+
static var xmlTag: String {
47+
"rtept"
48+
}
49+
50+
init(xml: AEXMLElement) throws {
51+
// longitude
52+
guard let longitudeString = xml.attributes["lon"],
53+
let longitudeDouble = Double(longitudeString)
54+
else {
55+
throw GPXError.missingRequiredElement("longitude")
56+
}
57+
longitude = longitudeDouble
58+
59+
// latitude
60+
guard let latitudeString = xml.attributes["lat"],
61+
let latitudeDouble = Double(latitudeString)
62+
else {
63+
throw GPXError.missingRequiredElement("latitude")
64+
}
65+
latitude = latitudeDouble
66+
}
67+
68+
var xmlElement: AEXMLElement {
69+
let attributes = [
70+
"lat": "\(latitude)",
71+
"lon": "\(longitude)",
72+
]
73+
let element = AEXMLElement(name: Self.xmlTag, attributes: attributes)
74+
75+
return element
76+
}
77+
}

0 commit comments

Comments
 (0)