Permalink
Browse files

Convert Swift class to struct. Massive speed improvement.

  • Loading branch information...
harrycheung committed Mar 18, 2015
1 parent 7c918af commit c09b1b55d475145ddbb167514fe6b5f476f4d214
@@ -408,7 +408,7 @@
4A3526A31A8D443900CC8A6B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = arm64;
ARCHS = "$(ARCHS_STANDARD)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
INFOPLIST_FILE = SwiftApp/Info.plist;
@@ -423,7 +423,7 @@
4A3526A41A8D443900CC8A6B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = arm64;
ARCHS = "$(ARCHS_STANDARD)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
GCC_OPTIMIZATION_LEVEL = fast;
@@ -22,43 +22,41 @@ final class Gate {
let LINE_WIDTH: Double = 30
let BEARING_RANGE: Double = 5
var location:Point
var location: Point
let type: GateType
let splitNumber: Int
var leftPoint, rightPoint: Point?
init(type: GateType, splitNumber: Int, latitude: Double, longitude: Double, bearing: Double) {
self.type = type
self.splitNumber = splitNumber
location = Point(latitude: latitude, longitude: longitude, inRadians: false)
self.location = Point(latitude: latitude, longitude: longitude, inRadians: false)
let leftBearing = bearing - 90 < 0 ? bearing + 270 : bearing - 90
let rightBearing = bearing + 90 > 360 ? bearing - 270 : bearing + 90
self.leftPoint = location.destination(leftBearing, distance: LINE_WIDTH / 2)
self.rightPoint = location.destination(rightBearing, distance: LINE_WIDTH / 2)
self.location.bearing = bearing
}
func crossed(#start: Point, destination: Point) -> Point? {
func crossed(#start: Point, destination: Point, inout cross: Point) -> Bool {
let pathBearing = start.bearingTo(destination)
var cross: Point? = nil
if pathBearing > (location.bearing - BEARING_RANGE) &&
pathBearing < (location.bearing + BEARING_RANGE) {
cross = Point.intersectSimple(p: leftPoint!, p2: rightPoint!, q: start, q2: destination)
if cross != nil {
let distance = start.distanceTo(cross!)
if Point.intersectSimple(p: leftPoint!, p2: rightPoint!, q: start, q2: destination, intersection: &cross) {
let distance = start.distanceTo(cross)
let timeSince = destination.timestamp - start.timestamp
let acceleration = (destination.speed - start.speed) / timeSince
let timeCross = Physics.time(distance: distance, velocity: start.speed, acceleration: acceleration)
cross!.generated = true
cross!.speed = start.speed + acceleration * timeCross
cross!.bearing = start.bearingTo(destination)
cross!.timestamp = start.timestamp + timeCross
cross!.lapDistance = start.lapDistance + distance
cross!.lapTime = start.lapTime + timeCross
cross!.splitTime = start.splitTime + timeCross
cross.generated = true
cross.speed = start.speed + acceleration * timeCross
cross.bearing = start.bearingTo(destination)
cross.timestamp = start.timestamp + timeCross
cross.lapDistance = start.lapDistance + distance
cross.lapTime = start.lapTime + timeCross
cross.splitTime = start.splitTime + timeCross
return true
}
}
return cross
return false
}
}
@@ -34,6 +34,10 @@ struct Point: Equatable {
var acceleration: Double
var generated: Bool = false
init() {
self.init(latitude: 0, longitude: 0, inRadians: false)
}
init (latitude: Double, longitude: Double, inRadians: Bool) {
if inRadians {
self.latitude = latitude
@@ -138,23 +142,25 @@ struct Point: Equatable {
return RADIUS * 2 * atan2(sqrt(a), sqrt(1 - a))
}
static func intersectSimple(#p: Point, p2: Point, q: Point, q2: Point) -> Point? {
static func intersectSimple(#p: Point, p2: Point, q: Point, q2: Point, inout intersection: Point) -> Bool {
let s1_x = p2.longitude - p.longitude
let s1_y = p2.latitude - p.latitude
let s2_x = q2.longitude - q.longitude
let s2_y = q2.latitude - q.latitude
let den = (-s2_x * s1_y + s1_x * s2_y)
if den == 0 { return nil }
if den == 0 { return false }
let s = (-s1_y * (p.longitude - q.longitude) + s1_x * (p.latitude - q.latitude)) / den
let t = ( s2_x * (p.latitude - q.latitude) - s2_y * (p.longitude - q.longitude)) / den
if s >= 0 && s <= 1 && t >= 0 && t <= 1 {
return Point(latitude: p.latitude + (t * s1_y), longitude: p.longitude + (t * s1_x), inRadians: true)
intersection.latitude = p.latitude + (t * s1_y)
intersection.longitude = p.longitude + (t * s1_x)
return true
}
return nil
return false
}
}
@@ -13,7 +13,7 @@ final class SessionManager {
var session: Session? = nil
var currentLap: Lap?
var bestLap: Lap?
var lastPoint: Point?
var lastPoint: Point = Point()
var bestIndex: Int = 0
var nextGate: Gate?
var gateIter: Int = 0
@@ -61,11 +61,11 @@ final class SessionManager {
var point = Point(latitude: latitude, longitude: longitude, speed: speed,
bearing: bearing, horizontalAccuracy: horizontalAccuracy,
verticalAccuracy: verticalAccuracy, timestamp: timestamp)
if lastPoint != nil {
var cross = nextGate!.crossed(start: lastPoint!, destination: point)
if cross != nil {
currentLap!.add(cross!)
currentLap!.splits[currentSplit] = cross!.splitTime
if currentLap!.points.count == 0 {
var cross: Point = Point()
if nextGate!.crossed(start: lastPoint, destination: point, cross: &cross) {
currentLap!.add(cross)
currentLap!.splits[currentSplit] = cross.splitTime
switch nextGate!.type {
case .START_FINISH, .FINISH:
if currentLap!.points[0].generated {
@@ -77,18 +77,18 @@ final class SessionManager {
fallthrough
case .START:
lapNumber += 1
currentLap = Lap(session: session!, track: track!, startTime: cross!.timestamp, lapNumber: lapNumber)
lastPoint = Point(latitude: cross!.latitudeDegrees(),
longitude: cross!.longitudeDegrees(),
speed: cross!.speed,
bearing: cross!.bearing,
horizontalAccuracy: cross!.hAccuracy,
verticalAccuracy: cross!.vAccuracy,
timestamp: cross!.timestamp)
lastPoint!.lapDistance = 0
lastPoint!.lapTime = 0
lastPoint!.generated = true
currentLap!.add(lastPoint!);
currentLap = Lap(session: session!, track: track!, startTime: cross.timestamp, lapNumber: lapNumber)
lastPoint = Point(latitude: cross.latitudeDegrees(),
longitude: cross.longitudeDegrees(),
speed: cross.speed,
bearing: cross.bearing,
horizontalAccuracy: cross.hAccuracy,
verticalAccuracy: cross.vAccuracy,
timestamp: cross.timestamp)
lastPoint.lapDistance = 0
lastPoint.lapTime = 0
lastPoint.generated = true
currentLap!.add(lastPoint);
session!.laps.append(currentLap!)
gap = 0
for (index, gap) in enumerate(splitGaps) {
@@ -102,7 +102,7 @@ final class SessionManager {
}
currentSplit++
}
splitStartTime = cross!.timestamp
splitStartTime = cross.timestamp
nextGate = track!.gates[currentSplit]
}
if bestLap != nil && bestIndex < bestLap!.points.count {
@@ -121,7 +121,7 @@ final class SessionManager {
bestIndex++
}
}
point.lapDistance = lastPoint!.lapDistance + lastPoint!.distanceTo(point)
point.lapDistance = lastPoint.lapDistance + lastPoint.distanceTo(point)
point.setLapTime(currentLap!.startTime, splitStartTime: splitStartTime)
}
currentLap!.add(point)
@@ -21,19 +21,19 @@ class GateTests: XCTestCase {
let c = Point(latitude: 37.45263, longitude: -122.207023,
speed: 14.15999984741211, bearing: 32.09501647949219,
horizontalAccuracy: 0, verticalAccuracy: 0, timestamp: 3)
let cross = gate.crossed(start: b, destination: c)
// XCTAssertNil(gate.crossed(start: a, destination: b))
// XCTAssertNil(gate.crossed(start: c, destination: b))
XCTAssertTrue(cross!.generated)
XCTAssertEqual(cross!.latitudeDegrees(), 37.452593)
XCTAssertEqual(cross!.longitudeDegrees(), -122.207052)
XCTAssertEqualWithAccuracy(cross!.speed, 14.18, 0.01)
XCTAssertEqualWithAccuracy(cross!.bearing, 31.93, 0.01)
XCTAssertEqualWithAccuracy(cross!.timestamp, 2.64915, 0.00001)
XCTAssertEqualWithAccuracy(cross!.lapDistance, b.lapDistance + b.distanceTo(cross!), 0.01)
XCTAssertEqualWithAccuracy(cross!.lapTime, 0.74915, 0.00001)
XCTAssertEqualWithAccuracy(cross!.splitTime, 0.64915, 0.00001)
var cross = Point()
XCTAssertFalse(gate.crossed(start: a, destination: b, cross: &cross))
XCTAssertFalse(gate.crossed(start: c, destination: b, cross: &cross))
XCTAssertTrue(gate.crossed(start: b, destination: c, cross: &cross))
XCTAssertTrue(cross.generated)
XCTAssertEqual(cross.latitudeDegrees(), 37.452593)
XCTAssertEqual(cross.longitudeDegrees(), -122.207052)
XCTAssertEqualWithAccuracy(cross.speed, 14.18, 0.01)
XCTAssertEqualWithAccuracy(cross.bearing, 31.93, 0.01)
XCTAssertEqualWithAccuracy(cross.timestamp, 2.64915, 0.00001)
XCTAssertEqualWithAccuracy(cross.lapDistance, b.lapDistance + b.distanceTo(cross), 0.01)
XCTAssertEqualWithAccuracy(cross.lapTime, 0.74915, 0.00001)
XCTAssertEqualWithAccuracy(cross.splitTime, 0.64915, 0.00001)
}
}
@@ -52,10 +52,10 @@ class PointTests: XCTestCase {
let b = Point(latitude: 15, longitude: 15)
let c = Point(latitude: 5, longitude: 15)
let d = Point(latitude: 15, longitude: 5)
var intersection = Point()
Point.intersectSimple(p: a, p2: b, q: c, q2: d, intersection: &intersection)
var i = Point.intersectSimple(p: a, p2: b, q: c, q2: d)
XCTAssertEqual(i!, Point(latitude: 10, longitude: 10))
XCTAssertEqual(intersection, Point(latitude: 10, longitude: 10))
}
}

0 comments on commit c09b1b5

Please sign in to comment.