Search code examples
iosmapkitmkoverlay

Unable to draw MKPolylineView crossing longitude +/-180


I'm having a problem drawing an MKPolylineView on an MKMapView. The line represents a trip around the world, which begins and ends near New York, always traveling east. One leg of the trip, from Japan to San Francisco, crosses the Pacific ocean, and therefore longitude +/-180. The MKPolylineView does connect those two points, but it travels in the wrong direction. That is, the line travels west from Japan back to San Francisco, instead of east across the Pacific. I don't see any option that lets me specify which direction a line segment should travel to connect two points.

To put it simply, the MKMapView doesn't seem to understand that the world is round. Is there a way I can draw the line as intended, traveling east from Japan to San Francisco?

I have a screenshot that displays the problem clearly:
The Polyline http://www.builtlight.org/pub/MKPolylineView.png


Solution

  • This seems to be a limitation of the MKMapView.

    A workaround is to split the +/-180 crossing into "east" and "west" parts.

    For an around-the-world trip (finish == start), you can put the "west" part of the crossing at the front of the polyline.
    For example:

    CLLocationCoordinate2D newYorkCoord = CLLocationCoordinate2DMake(40.7141667, -74.0063889);
    CLLocationCoordinate2D londonCoord = CLLocationCoordinate2DMake(51.5, -0.116667);
    CLLocationCoordinate2D japanCoord = CLLocationCoordinate2DMake(36, 138);
    CLLocationCoordinate2D sanFranciscoCoord = CLLocationCoordinate2DMake(37.775, -122.4183333);
    
    CLLocationCoordinate2D japanToSFMidpointEast;
    //use average calc as crude way to find midpoint...
    japanToSFMidpointEast.latitude = (japanCoord.latitude + sanFranciscoCoord.latitude)/2.0;
    japanToSFMidpointEast.longitude = 180;
    
    CLLocationCoordinate2D japanToSFMidpointWest;
    japanToSFMidpointWest.latitude = japanToSFMidpointEast.latitude;
    japanToSFMidpointWest.longitude = -180;
    
    int pointsCount = 6;
    CLLocationCoordinate2D *points = malloc(pointsCount * sizeof(CLLocationCoordinate2D));
    points[0] = japanToSFMidpointWest;
    points[1] = sanFranciscoCoord;
    points[2] = newYorkCoord;
    points[3] = londonCoord;
    points[4] = japanCoord;
    points[5] = japanToSFMidpointEast;
    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:points count:pointsCount];
    [mapView addOverlay:polyline];
    free(points);
    points = NULL;
    


    If a trip is not around-the-world (finish != start), you'll have to use two polylines.
    This example goes from Japan to SF:

    CLLocationCoordinate2D japanCoord = CLLocationCoordinate2DMake(36, 138);
    CLLocationCoordinate2D sanFranciscoCoord = CLLocationCoordinate2DMake(37.775, -122.4183333);
    
    CLLocationCoordinate2D japanToSFMidpointEast;
    japanToSFMidpointEast.latitude = (japanCoord.latitude + sanFranciscoCoord.latitude)/2.0;
    japanToSFMidpointEast.longitude = 180;
    
    CLLocationCoordinate2D japanToSFMidpointWest;
    japanToSFMidpointWest.latitude = japanToSFMidpointEast.latitude;
    japanToSFMidpointWest.longitude = -180;
    
    int eastPointsCount = 2;
    CLLocationCoordinate2D *eastPoints = malloc(eastPointsCount * sizeof(CLLocationCoordinate2D));
    eastPoints[0] = japanCoord;
    eastPoints[1] = japanToSFMidpointEast;
    MKPolyline *eastPolyline = [MKPolyline polylineWithCoordinates:eastPoints count:eastPointsCount];
    [mapView addOverlay:eastPolyline];
    free(eastPoints);
    eastPoints = NULL;
    
    int westPointsCount = 2;
    CLLocationCoordinate2D *westPoints = malloc(westPointsCount * sizeof(CLLocationCoordinate2D));
    westPoints[0] = japanToSFMidpointWest;
    westPoints[1] = sanFranciscoCoord;
    MKPolyline *westPolyline = [MKPolyline polylineWithCoordinates:westPoints count:westPointsCount];
    [mapView addOverlay:westPolyline];
    free(westPoints);
    westPoints = NULL;