Draw Great Circle Overlays on MKMapView

I am trying to draw the Great Circle line between two lat / lon points on MKMapView. This is the line that will appear to be rounded (a “straight” line on the globe) and is best rendered here . In fact, this very strange WordPress site seems to be starting to describe exactly how to do this, but it ends abruptly after the first few steps.

Reading Apple documentation I see

In iOS 4.0 and later, you can also use the predicted map coordinates instead of regions to indicate some values. When you project the curved surface of the globe onto a flat surface, you get a two-dimensional version of the map where the longitude lines seem parallel. The location and distances on this map are specified using the MKMapPoint, MKMapSize, and MKMapRect data types. These data types can be used to indicate the visible area of ​​maps and determine the location of overlays.

How I would apply it to the cover of Great Circle. I'm not sure. Can anyone help?

+3
source share
4 answers

I implemented this to draw a wide range of routes for airplanes traveling between two airports using MKPolyline.

+ (void)createGreatCircleMKPolylineFromPoint:(CLLocationCoordinate2D)point1 
                                     toPoint:(CLLocationCoordinate2D)point2
                                  forMapView:(MKMapView*)mapView
{
double lat1 = point1.latitude;
double lon1 = point1.longitude;
double lat2 = point2.latitude;
double lon2 = point2.longitude;
lat1 = lat1 * (PI/180);
lon1 = lon1 * (PI/180);
lat2 = lat2 * (PI/180);
lon2 = lon2 * (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;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * 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/PI);
    double lon = lonr * (180/PI);
    //        NSLog(@"lat: %f lon: %f", lat, lon);
    CLLocationCoordinate2D loc = CLLocationCoordinate2DMake(lat, lon);
    coords[i - 1] = loc;
}

//check for circling west to east. If the plane is crossing 180, we need
//to draw two lines or else the polyline connects the dots and draws a straight
//line all the way across the map.
CLLocationCoordinate2D prevCoord;
BOOL twoLines = NO;
int numsegs2 = 0;
CLLocationCoordinate2D *coords2;

for(int i=0; i<numsegs; i++)
{
    CLLocationCoordinate2D coord = coords[i];
    if(prevCoord.longitude < -170 && prevCoord.longitude > -180  && prevCoord.longitude < 0 
       && coord.longitude > 170 && coord.longitude < 180 && coord.longitude > 0)
    {
        twoLines = YES;
        coords2 = malloc(sizeof(CLLocationCoordinate2D) * (numsegs - i));
        numsegs2 = numsegs - i;
        for(int j=0; j<numsegs2; j++)
        {
            coords2[j] = coords[i + j];
        }
        break;
    }
    prevCoord = coord;
}

//remove any previously added overlays
[mapView removeOverlays:mapView.overlays];

if(twoLines)
{
    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:numsegs - numsegs2];
    free(coords);
    [mapView addOverlay:polyline];

    MKPolyline *polyline2 = [MKPolyline polylineWithCoordinates:coords2 count:numsegs2];
    free(coords2);
    [mapView addOverlay:polyline2];
}
else
{
    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:numsegs];
    free(coords);
    [mapView addOverlay:polyline];
}

}

(), MKOverlayView mapView: viewForOverlay.

- (MKOverlayView*)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
    MKPolyline *polyline = (MKPolyline*)overlay;
    MKPolylineView *view = [[[MKPolylineView alloc] initWithPolyline:polyline] autorelease];
    //choose your line params here
    view.lineWidth = 2;
    view.fillColor = [UIColor blueColor];
    return view;
}

, .

http://s1-03.twitpicproxy.com/photos/large/489178500.png

+9

, MKGeodesicPolyline, iOS 7.0, " ".

MKPolylineOverlay .

points = [CLLocationCoordinate2DMake(27.123, 85.765),
                  CLLocationCoordinate2DMake(41.444, 106.987)]
geodesic = MKGeodesicPolyline(coordinates: points, count: 2)
mapView.add(geodesic)

mapView :

//MARK: - MKMapView Delegate Method
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if overlay is MKGeodesicPolyline {
        let polylineRenderer = MKPolylineRenderer(overlay: overlay)
        polylineRenderer.strokeColor = UIColor.white
        polylineRenderer.lineWidth = 2.5
        return polylineRenderer
    }
}
+1

MKOverlayPathView. (void) createPath, UIBezierPath , , .

Once you define the path to the method, you need to set the path property of the class with the newly created path. This way, the path will be rendered automatically.

Hope this helps.

0
source

The numsegs parameter should vary depending on the level of map scaling and the distance between two points. The lat / lon coordinate of two points can be converted to a pixel coordinate. Thus, the numsegs parameter can be considered as a function of pixel differences.

0
source

All Articles