Last active
October 4, 2021 19:32
-
-
Save jmcd/4502302 to your computer and use it in GitHub Desktop.
Calculate a new coordinate given a starting coordinate, bearing and distance. 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
#import <CoreLocation/CoreLocation.h> | |
#import <MapKit/MapKit.h> | |
#import "AnnotationCoordinateUtility.h" | |
@implementation AnnotationCoordinateUtility { | |
} | |
+ (void)mutateCoordinatesOfClashingAnnotations:(NSArray *)annotations { | |
NSDictionary *coordinateValuesToAnnotations = [self groupAnnotationsByLocationValue:annotations]; | |
for (NSValue *coordinateValue in coordinateValuesToAnnotations.allKeys) { | |
NSMutableArray *outletsAtLocation = coordinateValuesToAnnotations[coordinateValue]; | |
if (outletsAtLocation.count > 1) { | |
CLLocationCoordinate2D coordinate; | |
[coordinateValue getValue:&coordinate]; | |
[self repositionAnnotations:outletsAtLocation toAvoidClashAtCoordination:coordinate]; | |
} | |
} | |
} | |
+ (NSDictionary *)groupAnnotationsByLocationValue:(NSArray *)annotations { | |
NSMutableDictionary *result = [NSMutableDictionary dictionary]; | |
for (id<MKAnnotation> pin in annotations) { | |
CLLocationCoordinate2D coordinate = pin.coordinate; | |
NSValue *coordinateValue = [NSValue valueWithBytes:&coordinate objCType:@encode(CLLocationCoordinate2D)]; | |
NSMutableArray *annotationsAtLocation = result[coordinateValue]; | |
if (!annotationsAtLocation) { | |
annotationsAtLocation = [NSMutableArray array]; | |
result[coordinateValue] = annotationsAtLocation; | |
} | |
[annotationsAtLocation addObject:pin]; | |
} | |
return result; | |
} | |
+ (void)repositionAnnotations:(NSMutableArray *)annotations toAvoidClashAtCoordination:(CLLocationCoordinate2D)coordinate { | |
double distance = 3 * annotations.count / 2.0; | |
double radiansBetweenAnnotations = (M_PI * 2) / annotations.count; | |
for (int i = 0; i < annotations.count; i++) { | |
double heading = radiansBetweenAnnotations * i; | |
CLLocationCoordinate2D newCoordinate = [self calculateCoordinateFrom:coordinate onBearing:heading atDistance:distance]; | |
id <MKAnnotation> annotation = annotations[i]; | |
annotation.coordinate = newCoordinate; | |
} | |
} | |
+ (CLLocationCoordinate2D)calculateCoordinateFrom:(CLLocationCoordinate2D)coordinate onBearing:(double)bearingInRadians atDistance:(double)distanceInMetres { | |
double coordinateLatitudeInRadians = coordinate.latitude * M_PI / 180; | |
double coordinateLongitudeInRadians = coordinate.longitude * M_PI / 180; | |
double distanceComparedToEarth = distanceInMetres / 6378100; | |
double resultLatitudeInRadians = asin(sin(coordinateLatitudeInRadians) * cos(distanceComparedToEarth) + cos(coordinateLatitudeInRadians) * sin(distanceComparedToEarth) * cos(bearingInRadians)); | |
double resultLongitudeInRadians = coordinateLongitudeInRadians + atan2(sin(bearingInRadians) * sin(distanceComparedToEarth) * cos(coordinateLatitudeInRadians), cos(distanceComparedToEarth) - sin(coordinateLatitudeInRadians) * sin(resultLatitudeInRadians)); | |
CLLocationCoordinate2D result; | |
result.latitude = resultLatitudeInRadians * 180 / M_PI; | |
result.longitude = resultLongitudeInRadians * 180 / M_PI; | |
return result; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment