Authored by Justin R. Miller

first cut of great circles

... ... @@ -36,6 +36,7 @@
#import "RMConfiguration.h"
#import "RMCoordinateGridSource.h"
#import "RMDatabaseCache.h"
#import "RMGreatCircleAnnotation.h"
#import "RMInteractiveSource.h"
#import "RMMBTilesSource.h"
#import "RMMapBoxSource.h"
... ...
//
// 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 "RMShapeAnnotation.h"
@interface RMGreatCircleAnnotation : RMShapeAnnotation
- (id)initWithMapView:(RMMapView *)aMapView coordinate1:(CLLocationCoordinate2D)coordinate1 coordinate2:(CLLocationCoordinate2D)coordinate2;
@property (nonatomic, readonly, assign) CLLocationCoordinate2D coordinate1;
@property (nonatomic, readonly, assign) CLLocationCoordinate2D coordinate2;
@end
... ...
//
// 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
{
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
... ...
... ... @@ -112,6 +112,8 @@
DD5A200B15CAD09400FE4157 /* GRMustache.h in Headers */ = {isa = PBXBuildFile; fileRef = DD5A200A15CAD09400FE4157 /* GRMustache.h */; };
DD5FA1EB15E2B020004EB6C5 /* RMLoadingTileView.h in Headers */ = {isa = PBXBuildFile; fileRef = DD5FA1E915E2B020004EB6C5 /* RMLoadingTileView.h */; settings = {ATTRIBUTES = (Private, ); }; };
DD5FA1EC15E2B020004EB6C5 /* RMLoadingTileView.m in Sources */ = {isa = PBXBuildFile; fileRef = DD5FA1EA15E2B020004EB6C5 /* RMLoadingTileView.m */; };
DD63175F17D1506D008CA79B /* RMGreatCircleAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = DD63175D17D1506D008CA79B /* RMGreatCircleAnnotation.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD63176017D1506D008CA79B /* RMGreatCircleAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = DD63175E17D1506D008CA79B /* RMGreatCircleAnnotation.m */; };
DD63176317D15EB5008CA79B /* RMCircleAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = DD63176117D15EB5008CA79B /* RMCircleAnnotation.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD63176417D15EB5008CA79B /* RMCircleAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = DD63176217D15EB5008CA79B /* RMCircleAnnotation.m */; };
DD7C7E38164C894F0021CCA5 /* RMStaticMapView.h in Headers */ = {isa = PBXBuildFile; fileRef = DD7C7E36164C894F0021CCA5 /* RMStaticMapView.h */; settings = {ATTRIBUTES = (Public, ); }; };
... ... @@ -274,6 +276,8 @@
DD5A200A15CAD09400FE4157 /* GRMustache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRMustache.h; path = GRMustache/include/GRMustache.h; sourceTree = "<group>"; };
DD5FA1E915E2B020004EB6C5 /* RMLoadingTileView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMLoadingTileView.h; sourceTree = "<group>"; };
DD5FA1EA15E2B020004EB6C5 /* RMLoadingTileView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMLoadingTileView.m; sourceTree = "<group>"; };
DD63175D17D1506D008CA79B /* RMGreatCircleAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMGreatCircleAnnotation.h; sourceTree = "<group>"; };
DD63175E17D1506D008CA79B /* RMGreatCircleAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMGreatCircleAnnotation.m; sourceTree = "<group>"; };
DD63176117D15EB5008CA79B /* RMCircleAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMCircleAnnotation.h; sourceTree = "<group>"; };
DD63176217D15EB5008CA79B /* RMCircleAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMCircleAnnotation.m; sourceTree = "<group>"; };
DD6A83751644A20C0097F31F /* MapBox.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MapBox.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
... ... @@ -509,6 +513,8 @@
DDE357F716522CD8001DB842 /* RMPolygonAnnotation.m */,
DD63176117D15EB5008CA79B /* RMCircleAnnotation.h */,
DD63176217D15EB5008CA79B /* RMCircleAnnotation.m */,
DD63175D17D1506D008CA79B /* RMGreatCircleAnnotation.h */,
DD63175E17D1506D008CA79B /* RMGreatCircleAnnotation.m */,
16FAB66213E03D55002F4E1C /* RMQuadTree.h */,
16FAB66313E03D55002F4E1C /* RMQuadTree.m */,
B86F26AC0E87442C007A3773 /* RMMapLayer.h */,
... ... @@ -704,6 +710,7 @@
DDE357F816522CD8001DB842 /* RMPolygonAnnotation.h in Headers */,
DD1985C1165C5F6400DF667F /* RMTileMillSource.h in Headers */,
DD63176317D15EB5008CA79B /* RMCircleAnnotation.h in Headers */,
DD63175F17D1506D008CA79B /* RMGreatCircleAnnotation.h in Headers */,
B8C974220E8A19B2007D16AD /* RMProjection.h in Headers */,
B8C974260E8A19B2007D16AD /* RMTile.h in Headers */,
B8C974270E8A19B2007D16AD /* RMPixel.h in Headers */,
... ... @@ -867,6 +874,7 @@
16128CF6148D295300C23C0E /* RMOpenSeaMapSource.m in Sources */,
DD2B374614CF8041008DE8CB /* FMDatabase.m in Sources */,
DD2B374814CF8041008DE8CB /* FMDatabaseAdditions.m in Sources */,
DD63176017D1506D008CA79B /* RMGreatCircleAnnotation.m in Sources */,
DD2B374A14CF8041008DE8CB /* FMResultSet.m in Sources */,
DD2B375014CF814F008DE8CB /* FMDatabasePool.m in Sources */,
DD2B375214CF814F008DE8CB /* FMDatabaseQueue.m in Sources */,
... ...