I am working with viewports and bounds returned from Google Geocoding API. When doing reverse geocoding for a given coordinate, the service returns several results with various granularity (country, administrative area, locality, sublocality, route, etc.). I want to select the most appropriate on the results given the current visible area on the map.
I’ve settled on algorithm that compares the ratios of areas (in MKMapPoint²) of the location viewport, current map viewport and their intersection (using MKMapRectIntersection function). This works very well as long as the location viewport does not span the 180 meridian. In that case their intersection is 0.
I’ve started to investigate the cause and as debugging aid I do display MKPolygon overlays on the map to give me visual clues as to what is going on. To avoid possible errors introduced by my code that does conversion between geo-coordinates and MKMapRect, I have constructed the polygon overlay using original coordinates from Google results like this:
CLLocationCoordinate2D sw, ne, nw, se;
sw = location.viewportSouthWest.coordinate;
ne = location.viewportNorthEast.coordinate;
nw = CLLocationCoordinate2DMake(ne.latitude, sw.longitude);
se = CLLocationCoordinate2DMake(sw.latitude, ne.longitude);
CLLocationCoordinate2D coords[] = {nw, ne, se, sw};
MKPolygon *p = [MKPolygon polygonWithCoordinates:coords count:4];
For example of problematic location, here is the viewport returned for United States, last result of type country, when geocoding coordinates somewhere in Virginia:
Southwest: 18.9110643, 172.4546967
Northeast: 71.3898880, -66.9453948
Notice how the southwest coordinate, which is in the lower left corner of the location viewport lies across the 180 meridian. When displaying this location overlayed as polygon on the map it displays incorrectly to the right of USA borders (big brown rectangle, only lower left corner visible):


Similarily, displaying location viewport for Russia shows the rectangle positioned incorrectly to the left of the border of Russia.
This visually confirms there is similar problem going on, when I convert the location viewport to MKMapPoints and MKMapRect and find no intersection between the map viewport (white rectangle in the picture above) and the location viewport.
The way I compute the map rect is similar to answers in this SO question:
How to fit a certain bounds consisting of NE and SW coordinates into the visible map view?
…which works fine unless the coordinates span the 180th meridian. Testing the MKMapRect with MKMapRectSpans180thMeridian return false, so that construction method is incorrect.
Apple documentation is not helpful in this regards. Only hint I’ve found is in MKOverlay.h:
// boundingMapRect should be the smallest rectangle that completely contains
// the overlay.
// For overlays that span the 180th meridian, boundingMapRect should have
// either a negative MinX or a MaxX that is greater than MKMapSizeWorld.width.
@property (nonatomic, readonly) MKMapRect boundingMapRect;
What is the correct way to display the polygon overlay that span the 180th meridian?
How to correctly construct MKMapRect that spans 180th meridian?
According to that comment in
MKOverlay.h, if the nw and sw corners were specified as negativeMKMapPointvalues, the overlay should be “drawn correctly”.If we try this:
The resulting
p.boundingMapRectdoes returnYESforMKMapRectSpans180thMeridian(but the code already figured that out from the coordinates since it didn’t have the maprect to begin with).Unfortunately, however, creating the maprect with the negative values fixes only half the problem. The half of the polygon that is east of the dateline is now drawn correctly. However, the other half on the west of the dateline does not get drawn at all.
Apparently, the built-in
MKPolygonViewdoes not callMKMapRectSpans180thMeridianand draw the polygon in two parts.You can create a custom overlay view and do this drawing yourself (you’d create one overlay but the view would draw two polygons).
Or, you could just create two
MKPolygonoverlays and let the map view draw them by adding the following after the above code:By the way, there is a similar issue with drawing
MKPolylineoverlays that cross +/-180 (see this question).