Last active
May 12, 2018 18:32
-
-
Save arjunattam/50dcb6c7aa9a6fc7c4661c8f0f97415f to your computer and use it in GitHub Desktop.
decode time aware polyline in objective-c
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
// main.m | |
#import <Foundation/Foundation.h> | |
// Main methods declaration | |
NSArray *getDecodedPolyline(NSString *); | |
NSArray *getLocationsTillTime(NSArray *, NSDate *); | |
// Helper methods declaration | |
NSArray *getDecodedDimensionFromPolyline(NSString *, int); | |
NSArray *getFormattedDimensions(NSNumber *, NSNumber *, NSNumber *); | |
NSArray *getMidLocation(NSArray *, NSDate *); | |
int main(int argc, const char * argv[]) { | |
@autoreleasepool { | |
NSString *polyline = @"spxsBsdb|Lymo`qvAx@TKvAr@K"; | |
NSArray *decoded = getDecodedPolyline(polyline); | |
NSLog(@"decoded %@", decoded); | |
NSDate *startTime = decoded[0][2]; | |
NSDate *queryTime = [startTime dateByAddingTimeInterval:5]; | |
NSArray *locations = getLocationsTillTime(decoded, queryTime); | |
NSLog(@"locations %@", locations); | |
} | |
return 0; | |
} | |
// Implementation | |
// returns decoded polyline from string | |
NSArray *getDecodedPolyline(NSString *polyline) { | |
NSMutableArray *gpxLogs = [[NSMutableArray alloc] init]; | |
NSNumber *index = 0, *latPart = 0, *lngPart = 0, *timePart = 0; | |
NSNumber *polylineLength = [NSNumber numberWithInt:[polyline length]]; | |
while (index < polylineLength) { | |
NSNumber *indexOffset, *latOffset, *lngOffset, *timeOffset; | |
NSArray *decodedDimension; | |
// assign index and latPart | |
decodedDimension = getDecodedDimensionFromPolyline(polyline, index.intValue); | |
indexOffset = decodedDimension[0]; | |
latOffset = decodedDimension[1]; | |
index = @(indexOffset.intValue); | |
latPart = @(latPart.intValue + latOffset.intValue); | |
// assign index and lngPart | |
decodedDimension = getDecodedDimensionFromPolyline(polyline, index.intValue); | |
indexOffset = decodedDimension[0]; | |
lngOffset = decodedDimension[1]; | |
index = @(indexOffset.intValue); | |
lngPart = @(lngPart.intValue + lngOffset.intValue); | |
// assign index and timePart | |
decodedDimension = getDecodedDimensionFromPolyline(polyline, index.intValue); | |
indexOffset = decodedDimension[0]; | |
timeOffset = decodedDimension[1]; | |
index = @(indexOffset.intValue); | |
timePart = @(timePart.intValue + timeOffset.intValue); | |
NSArray *decodedDimensions = getFormattedDimensions(latPart, lngPart, timePart); | |
[gpxLogs addObject:decodedDimensions]; | |
} | |
return gpxLogs; | |
} | |
// returns locations [[lat, lng] ..] till timestamp from decoded polyline | |
NSArray *getLocationsTillTime(NSArray *decoded, NSDate *queryTime) { | |
NSMutableArray *locationsElapsed = [[NSMutableArray alloc] init]; | |
int decodedLength = [decoded count]; | |
if (queryTime == nil) { | |
return nil; | |
} | |
if (decoded == nil || [decoded count] == 0) { | |
return locationsElapsed; | |
} | |
NSDate *startTime = decoded[0][2]; | |
if( [queryTime timeIntervalSinceDate:startTime] <= 0 ) { | |
// queryTime is before start time | |
NSArray *locations = @[decoded[0][0], decoded[0][1]]; | |
[locationsElapsed addObject:locations]; | |
return locationsElapsed; | |
} | |
NSMutableArray *currentPair = [[NSMutableArray alloc] init]; | |
for (int index = 0; index < decodedLength; index++) { | |
[currentPair addObject:decoded[index]]; | |
if ([currentPair count] == 2) { | |
NSDate *startTime = currentPair[0][2]; | |
NSDate *endTime = currentPair[1][2]; | |
if ([queryTime timeIntervalSinceDate:startTime] > 0 && | |
[queryTime timeIntervalSinceDate:endTime] <= 0) { | |
// location is in between the current pair | |
NSArray *midLocation = getMidLocation(currentPair, queryTime); | |
[locationsElapsed addObject:midLocation]; | |
return locationsElapsed; | |
} else { | |
// remove first element from current pair | |
[currentPair removeObjectAtIndex:0]; | |
} | |
} | |
NSArray *currentLocation = @[currentPair[0][0], currentPair[0][1]]; | |
[locationsElapsed addObject:currentLocation]; | |
} | |
return locationsElapsed; | |
} | |
// helper method for decoding | |
NSArray *getDecodedDimensionFromPolyline(NSString *polyline, int index) { | |
long result = 1, shift = 0, correctedResult = 1; | |
while (TRUE) { | |
unichar polylineChar = [polyline characterAtIndex:index] - 63 - 1; | |
index += 1; | |
result += polylineChar << shift; | |
shift += 5; | |
if (polylineChar < 0x1f) { | |
break; | |
} | |
} | |
if ((result & 1) != 0) { | |
correctedResult = ~result >> 1; | |
} else { | |
correctedResult = result >> 1; | |
} | |
NSNumber *indexNumber = [NSNumber numberWithInt:index]; | |
NSNumber *resultNumber = [NSNumber numberWithInt:correctedResult]; | |
NSArray *arrayResult = @[indexNumber, resultNumber]; | |
return arrayResult; | |
} | |
// helper method for modifying format of decoded elements | |
NSArray *getFormattedDimensions(NSNumber *lat, NSNumber *lng, NSNumber *time) { | |
NSTimeInterval unixTimeStamp = [time doubleValue]; | |
return @[@([lat floatValue] / 100000.0), | |
@([lng floatValue] / 100000.0), | |
[NSDate dateWithTimeIntervalSince1970:unixTimeStamp]]; | |
} | |
// helper method to find mid location in a pair on a timestamp | |
NSArray *getMidLocation(NSArray *currentPair, NSDate *queryTime) { | |
NSDate *startTime = currentPair[0][2]; | |
NSDate *endTime = currentPair[1][2]; | |
double timeSinceStart = [queryTime timeIntervalSinceDate:startTime]; | |
double intervalLength = [endTime timeIntervalSinceDate:startTime]; | |
float ratio = timeSinceStart / intervalLength; | |
NSNumber *startLat = currentPair[0][0], *startLng = currentPair[0][1]; | |
NSNumber *endLat = currentPair[1][0], *endLng = currentPair[1][1]; | |
return @[@(startLat.floatValue * (1 - ratio) + endLat.floatValue * ratio), | |
@(startLng.floatValue * (1 - ratio) + endLng.floatValue * ratio)]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To run