Skip to content

Commit f67c8f1

Browse files
committed
Cleaned up a lot
1 parent 06e99e1 commit f67c8f1

File tree

10 files changed

+328
-260
lines changed

10 files changed

+328
-260
lines changed

Package.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,14 @@ let package = Package(
1111
.watchOS(.v3)
1212
],
1313
products: [
14-
// Products define the executables and libraries a package produces, and make them visible to other packages.
1514
.library(
1615
name: "RCGPX",
1716
targets: ["RCGPX"]),
1817
],
1918
dependencies: [
20-
// Dependencies declare other packages that this package depends on.
2119
.package(url: "https://github.com/tadija/AEXML.git", from:"4.6.0"),
2220
],
2321
targets: [
24-
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
25-
// Targets can depend on other targets in this package, and on products in packages this package depends on.
2622
.target(
2723
name: "RCGPX",
2824
dependencies: ["AEXML"]),

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# RCGPX
22

3-
A library for reading & writing GPX tracks and waypoints in Swift.
3+
A simple library for reading & writing GPX tracks and waypoints in Swift, specifically designed for simplicity and ease of use.
44

55
---
66

@@ -22,8 +22,8 @@ A library for reading & writing GPX tracks and waypoints in Swift.
2222
# GPX Types
2323

2424
- GPXTrack
25-
- GPXTrackSegment
26-
- GPXTrackPoint
25+
- .Segment
26+
- .Point
2727
- GPXWaypoint
2828

2929
# GPXDocument
@@ -49,9 +49,9 @@ let fileUrl = ...
4949
let fileData = try Data(contentsOf: fileUrl)
5050
let gpxString = try? String(contentsOf: fileUrl, encoding: .utf8)
5151

52-
let documentFromData = try? GPXDocument(data: fileData)
53-
let documentFromFileUrl = try? GPXDocument(url: fileUrl)
54-
let documentFromString = try? GPXDocument(string: gpxString)
52+
let documentFromData = try? GPXDocument(fileData)
53+
let documentFromFileUrl = try? GPXDocument(fileUrl)
54+
let documentFromString = try? GPXDocument(gpxString)
5555
```
5656

5757
---

Sources/RCGPX/GPXDocument.swift

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,54 @@
11
//
22
// GPXDocument.swift
3-
//
3+
//
44
//
55
// Created by Ryan Linn on 7/9/21.
66
//
77

8-
import Foundation
98
import AEXML
9+
import Foundation
1010

1111
/// The root of a GPX file representation. The basics of this are an optional
1212
/// `creator` string, and arrays of waypoints and tracks.
1313
public struct GPXDocument {
1414
/// An optional name for who or what created this GPX file
15-
var creator: String?
15+
public var creator: String?
1616
/// An array of `GPXWaypoint` contained in this GPX file
17-
var waypoints: [GPXWaypoint]
17+
public var waypoints: [GPXWaypoint]
1818
/// An array of `GPXTrack` contained in this GPX file
19-
var tracks: [GPXTrack]
20-
21-
public init(creator: String? = nil,
22-
waypoints: [GPXWaypoint] = [],
23-
tracks: [GPXTrack] = []) {
19+
public var tracks: [GPXTrack]
20+
21+
public init(
22+
creator: String? = nil,
23+
waypoints: [GPXWaypoint] = [],
24+
tracks: [GPXTrack] = []
25+
) {
2426
self.creator = creator
2527
self.waypoints = waypoints
2628
self.tracks = tracks
2729
}
2830
}
2931

30-
extension GPXDocument: GPXElement {
31-
static var xmlTag: String {
32-
"gpx"
33-
}
34-
35-
init(xml: AEXMLElement) throws {
36-
self.creator = xml.attributes["creator"]
37-
let waypointElements = xml.children.filter({ $0.name == GPXWaypoint.xmlTag })
38-
self.waypoints = try waypointElements.map({ try GPXWaypoint(xml: $0) })
39-
let trackElements = xml.children.filter({ $0.name == GPXTrack.xmlTag })
40-
self.tracks = try trackElements.map({ try GPXTrack(xml: $0) })
41-
}
42-
43-
var xmlElement: AEXMLElement {
44-
let element = AEXMLElement(name: Self.xmlTag)
45-
element.attributes["creator"] = creator
46-
element.addChildren(waypoints.map(\.xmlElement))
47-
element.addChildren(tracks.map(\.xmlElement))
48-
return element
49-
}
50-
}
32+
// MARK: - Accessors
5133

52-
//MARK:- Accessors
5334
public extension GPXDocument {
5435
/// Returns the full string representation of the GPX file.
5536
func gpxString() -> String {
5637
let xmlDoc = AEXMLDocument()
5738
xmlDoc.addChild(xmlElement)
5839
return xmlDoc.xml
5940
}
60-
41+
6142
/// Returns the file data representation of the GPX file.
6243
func gpxData() -> Data? {
6344
gpxString().data(using: .utf8)
6445
}
65-
6646
}
6747

68-
//MARK:- Initializers
69-
extension GPXDocument {
70-
71-
init(data: Data) throws {
48+
// MARK: - Initializers
49+
50+
public extension GPXDocument {
51+
init(_ data: Data) throws {
7252
let xmlDoc = try AEXMLDocument(xml: data)
7353
guard let documentElement = xmlDoc.firstDescendant(where: { $0.name == Self.xmlTag }) else {
7454
throw GPXError.missingRequiredElement("Document")
@@ -78,17 +58,16 @@ extension GPXDocument {
7858
}
7959
try self.init(xml: documentElement)
8060
}
81-
82-
init(string: String) throws {
61+
62+
init(_ string: String) throws {
8363
guard let data = string.data(using: .utf8) else {
8464
throw GPXError.missingRequiredElement("xml")
8565
}
86-
try self.init(data: data)
66+
try self.init(data)
8767
}
88-
89-
init(url: URL) throws {
68+
69+
init(_ url: URL) throws {
9070
let data = try Data(contentsOf: url)
91-
try self.init(data: data)
71+
try self.init(data)
9272
}
93-
9473
}

Sources/RCGPX/GPXTrack.swift

Lines changed: 55 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,87 @@
11
//
22
// GPXTrack.swift
3-
//
3+
//
44
//
55
// Created by Ryan Linn on 7/9/21.
66
//
77

8-
import Foundation
98
import AEXML
9+
import Foundation
10+
11+
// MARK: - Track
1012

11-
//MARK:- Track
1213
/// A representation of one or more lines on the map.
1314
public struct GPXTrack {
1415
/// The unique name of the track to be displayed in a list of GPX elements.
1516
public var name: String
1617
/// An optional, user-provided description of the track
1718
public var gpxDescription: String?
18-
/// An ordered array of `GPXTrackSegment` that make up the overall track.
19-
public var segments: [GPXTrackSegment]
20-
21-
public init(name: String,
22-
description: String?,
23-
segments: [GPXTrackSegment]) {
19+
/// An ordered array of `GPXTrack.Segment` that make up the overall track.
20+
public var segments: [Segment]
21+
22+
public init(
23+
name: String,
24+
description: String?,
25+
segments: [Segment]
26+
) {
2427
self.name = name
25-
self.gpxDescription = description
28+
gpxDescription = description
2629
self.segments = segments
2730
}
28-
}
29-
30-
extension GPXTrack: GPXElement {
31-
static var xmlTag: String {
32-
"trk"
33-
}
3431

35-
init(xml: AEXMLElement) throws {
36-
guard let nameElement = xml["name"].value else {
37-
throw GPXError.missingRequiredElement("name")
38-
}
39-
self.name = nameElement
40-
41-
self.gpxDescription = xml["desc"].value
42-
43-
self.segments = try xml.all(withValue: GPXTrackSegment.xmlTag)?.map({ try GPXTrackSegment(xml: $0) }) ?? []
32+
/// Returns an array of all `GPXTrackPoint` in the Track, combining
33+
/// all segments in the track in order.
34+
public func allTrackPoints() -> [Point] {
35+
segments
36+
.map(\.trackPoints)
37+
.reduce([]) { $0 + $1 }
4438
}
45-
46-
var xmlElement: AEXMLElement {
47-
let element = AEXMLElement(name: Self.xmlTag)
48-
element.addChild(name: "name", value: name)
49-
element.addChild(name: "desc", value: gpxDescription)
50-
element.addChildren(segments.map(\.xmlElement))
51-
return element
52-
}
53-
5439
}
5540

41+
// MARK: - TrackSegment
5642

57-
//MARK:- TrackSegment
58-
/// A section of a GPX Track, consisting of an
59-
/// array of TrackPoints in directional order.
60-
public struct GPXTrackSegment {
61-
/// An array of TrackPoints in directional order that make up this segment.
62-
public var trackPoints: [GPXTrackPoint]
63-
64-
public init(points: [GPXTrackPoint]) {
65-
self.trackPoints = points
66-
}
67-
}
68-
69-
extension GPXTrackSegment: GPXElement {
70-
public static var xmlTag: String {
71-
"trkseg"
72-
}
73-
74-
public init(xml: AEXMLElement) throws {
75-
let pointChildren = xml.all(withValue: GPXTrackPoint.xmlTag) ?? []
76-
self.trackPoints = try pointChildren.map({ try GPXTrackPoint(xml: $0) })
77-
}
78-
79-
public var xmlElement: AEXMLElement {
80-
let element = AEXMLElement(name: Self.xmlTag)
81-
element.addChildren(trackPoints.map(\.xmlElement))
82-
return element
83-
}
84-
85-
86-
}
43+
public extension GPXTrack {
44+
/// A section of a GPX Track, consisting of an
45+
/// array of TrackPoints in directional order.
46+
struct Segment {
47+
/// An array of TrackPoints in directional order that make up this segment.
48+
public var trackPoints: [Point]
8749

88-
//MARK: TrackPoint
89-
/// A simple representation of a point along a GPX track,
90-
/// made up of latitude, longitude, elevation (in meters), and a time stamp.
91-
public struct GPXTrackPoint {
92-
public var latitude: Double
93-
public var longitude: Double
94-
public var elevation: Double?
95-
public var time: Date?
96-
97-
private static var dateFormatter: ISO8601DateFormatter = ISO8601DateFormatter()
98-
99-
public init(latitude: Double,
100-
longitude: Double,
101-
elevation: Double? = nil,
102-
time: Date? = nil) {
103-
self.latitude = latitude
104-
self.longitude = longitude
105-
self.elevation = elevation
106-
self.time = time
50+
public init(points: [Point]) {
51+
trackPoints = points
52+
}
10753
}
10854
}
10955

110-
extension GPXTrackPoint: GPXElement {
111-
public static var xmlTag: String {
112-
"trkpt"
113-
}
114-
115-
public init(xml: AEXMLElement) throws {
116-
//longitude
117-
guard let longitudeString = xml.attributes["lon"],
118-
let longitudeDouble = Double(longitudeString)
119-
else {
120-
throw GPXError.missingRequiredElement("longitude")
121-
}
122-
self.longitude = longitudeDouble
56+
// MARK: - TrackPoint
12357

124-
//latitude
125-
guard let latitudeString = xml.attributes["lat"],
126-
let latitudeDouble = Double(latitudeString)
127-
else {
128-
throw GPXError.missingRequiredElement("latitude")
129-
}
130-
self.latitude = latitudeDouble
131-
132-
//elevation
133-
self.elevation = xml["ele"].double
58+
public extension GPXTrack {
59+
/// A simple representation of a point along a GPX track,
60+
/// made up of latitude, longitude, elevation (in meters), and a time stamp.
61+
struct Point {
62+
public var latitude: Double
63+
public var longitude: Double
64+
public var elevation: Double?
65+
public var time: Date?
13466

135-
//Time
136-
if let timeElement = xml["time"].value {
137-
self.time = Self.dateFormatter.date(from: timeElement)
138-
}
139-
}
140-
141-
public var xmlElement: AEXMLElement {
142-
let attributes = [
143-
"lat": "\(latitude)",
144-
"lon": "\(longitude)"
145-
]
146-
let element = AEXMLElement(name: Self.xmlTag, attributes: attributes)
67+
internal static var dateFormatter: ISO8601DateFormatter? = {
68+
if #available(iOS 15.0, macOS 12.0, watchOS 8.0, *) {
69+
return nil
70+
} else {
71+
return ISO8601DateFormatter()
72+
}
73+
}()
14774

148-
//elevation
149-
if let elevation = elevation {
150-
element.addChild(name: "ele", value: "\(elevation)")
151-
}
152-
153-
//time
154-
if let time = time {
155-
element.addChild(name: "time", value: Self.dateFormatter.string(from: time))
75+
public init(
76+
latitude: Double,
77+
longitude: Double,
78+
elevation: Double? = nil,
79+
time: Date? = nil
80+
) {
81+
self.latitude = latitude
82+
self.longitude = longitude
83+
self.elevation = elevation
84+
self.time = time
15685
}
157-
158-
return element
15986
}
160-
161-
16287
}

0 commit comments

Comments
 (0)