RMGreatCircleAnnotation.m
5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//
// RMGreatCircleAnnotation.m
// MapView
//
// Copyright (c) 2008-2013, Route-Me Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#import "RMGreatCircleAnnotation.h"
#import "RMShape.h"
@implementation RMGreatCircleAnnotation
- (id)initWithMapView:(RMMapView *)aMapView coordinate1:(CLLocationCoordinate2D)coordinate1 coordinate2:(CLLocationCoordinate2D)coordinate2
{
NSAssert(coordinate1.latitude != coordinate2.latitude || coordinate1.longitude != coordinate2.longitude, @"Start and end coordinates must differ.");
if (!(self = [super initWithMapView:aMapView points:@[ [[CLLocation alloc] initWithLatitude:coordinate1.latitude longitude:coordinate1.longitude], [[CLLocation alloc] initWithLatitude:coordinate2.latitude longitude:coordinate2.longitude]]]))
return nil;
_coordinate1 = coordinate1;
_coordinate2 = coordinate2;
return self;
}
- (RMMapLayer *)layer
{
if ( ! [super layer])
{
RMShape *shape = [[RMShape alloc] initWithView:self.mapView];
[shape performBatchOperations:^(RMShape *aShape)
{
// based on implementation at http://stackoverflow.com/questions/6104517/drawing-great-circle-overlay-lines-on-an-mkmapview
//
double lat1 = self.coordinate1.latitude;
double lon1 = self.coordinate1.longitude;
double lat2 = self.coordinate2.latitude;
double lon2 = self.coordinate2.longitude;
lat1 = lat1 * (M_PI/180);
lon1 = lon1 * (M_PI/180);
lat2 = lat2 * (M_PI/180);
lon2 = lon2 * (M_PI/180);
double d = 2 * asin( sqrt(pow(( sin( (lat1-lat2)/2) ), 2) + cos(lat1) * cos(lat2) * pow(( sin( (lon1-lon2)/2) ), 2)));
int numsegs = 100;
NSMutableArray *coords = [NSMutableArray arrayWithCapacity:numsegs];
double f = 0.0;
for(int i=1; i<=numsegs; i++)
{
f += 1.0 / (float)numsegs;
double A=sin((1-f)*d)/sin(d);
double B=sin(f*d)/sin(d);
double x = A*cos(lat1) * cos(lon1) + B * cos(lat2) * cos(lon2);
double y = A*cos(lat1) * sin(lon1) + B * cos(lat2) * sin(lon2);
double z = A*sin(lat1) + B*sin(lat2);
double latr=atan2(z, sqrt(pow(x, 2) + pow(y, 2) ));
double lonr=atan2(y, x);
double lat = latr * (180/M_PI);
double lon = lonr * (180/M_PI);
[coords addObject:[[CLLocation alloc] initWithLatitude:lat longitude:lon]];
}
CLLocationCoordinate2D prevCoord;
NSMutableArray *coords2 = [NSMutableArray array];
for(int i=0; i<numsegs; i++)
{
CLLocationCoordinate2D coord = ((CLLocation *)coords[i]).coordinate;
if(prevCoord.longitude < -170 && prevCoord.longitude > -180 && prevCoord.longitude < 0
&& coord.longitude > 170 && coord.longitude < 180 && coord.longitude > 0)
{
[coords2 addObjectsFromArray:[coords subarrayWithRange:NSMakeRange(i, [coords count] - i)]];
[coords removeObjectsInRange:NSMakeRange(i, [coords count] - i)];
break;
}
prevCoord = coord;
}
[aShape moveToCoordinate:((CLLocation *)coords[0]).coordinate];
for (int i = 1; i < [coords count]; i++)
[aShape addLineToCoordinate:((CLLocation *)coords[i]).coordinate];
if ([coords2 count])
{
[aShape moveToCoordinate:((CLLocation *)coords2[0]).coordinate];
for (int j = 1; j < [coords2 count]; j++)
[aShape addLineToCoordinate:((CLLocation *)coords2[j]).coordinate];
}
}];
super.layer = shape;
}
return [super layer];
}
@end