Created
December 23, 2016 10:41
-
-
Save mrh-is/35ef7aaaec8a1c467518db5749196da3 to your computer and use it in GitHub Desktop.
When will Santa be at my house?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension Location { | |
func closestLocationOnPath(start: Location, end: Location) -> (location: Location, t: Double, distance: Double) { | |
let pathVector = (latitude: end.latitude - start.latitude, longitude: end.longitude - start.longitude) | |
var t = (self.latitude * pathVector.latitude - start.latitude * pathVector.latitude + self.longitude * pathVector.longitude - start.longitude * pathVector.longitude) / (pow(pathVector.latitude,2) + pow(pathVector.longitude,2)) | |
t = min(max(t, 0), 1) | |
let closestLocation = Location(latitude: start.latitude + t * pathVector.latitude, longitude: start.longitude + t * pathVector.longitude) | |
return (location: closestLocation, t: t, distance: distance(to: closestLocation)) | |
} | |
func distance(to other: Location) -> Double { | |
return sqrt(pow(other.latitude-self.latitude,2) + pow(other.longitude-self.longitude,2)) | |
} | |
} | |
extension Date { | |
static func scaled(between first: Date, and second: Date, scale: Double) -> Date { | |
precondition(scale <= 1 && scale >= 0, "Scale must be in [0,1].") | |
let difference = second.timeIntervalSinceReferenceDate - first.timeIntervalSinceReferenceDate | |
return first.addingTimeInterval(difference * scale) | |
} | |
} | |
func getArrivalTime(at location: Location, with stops: List<Stop>) -> Date { | |
guard stops.count > 1 else { | |
return stops.first?.time ?? Date() | |
} | |
var minimumDistance = Double.infinity | |
var closestTime = Date() | |
for index in 0..<(stops.count-1) { | |
let startStop = stops[index], endStop = stops[index+1] | |
guard let startLocation = startStop.location, let endLocation = endStop.location else { | |
continue | |
} | |
let (_, t, distance) = location.closestLocationOnPath(start: startLocation, end: endLocation) | |
if distance < minimumDistance { | |
minimumDistance = distance | |
closestTime = Date.scaled(between: startStop.time, and: endStop.time, scale: t) | |
print(index) | |
print(minimumDistance) | |
print(closestTime) | |
} | |
} | |
return closestTime | |
} | |
getArrivalTime(at: .sanFrancisco, with: santa.route) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment