Skip to content

Instantly share code, notes, and snippets.

@arjunattam
Last active May 12, 2018 18:32
Show Gist options
  • Save arjunattam/50dcb6c7aa9a6fc7c4661c8f0f97415f to your computer and use it in GitHub Desktop.
Save arjunattam/50dcb6c7aa9a6fc7c4661c8f0f97415f to your computer and use it in GitHub Desktop.
decode time aware polyline in objective-c
// 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)];
}
@arjunattam
Copy link
Author

To run

clang main.m -fobjc-arc -fmodules -mmacosx-version-min=10.6 -o main
./main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment