在穿越子午线(以及环绕两极)时仍然必须更加小心,否则 MKMapPointForCoordinate 返回 -1、-1:
public func MKMapRectForCoordinateRegion(region:MKCoordinateRegion) -> MKMapRect {
var topLeft = CLLocationCoordinate2D(
latitude: min(region.center.latitude + (region.span.latitudeDelta/2.0), 90),
longitude: region.center.longitude - (region.span.longitudeDelta/2.0)
)
if topLeft.longitude < -180 {
// We wrapped around the meridian
topLeft.longitude += 360
}
var bottomRight = CLLocationCoordinate2D(
latitude: max(region.center.latitude - (region.span.latitudeDelta/2.0), -90),
longitude: region.center.longitude + (region.span.longitudeDelta/2.0)
)
if bottomRight.longitude > 180 {
// We wrapped around the medridian
bottomRight.longitude -= 360
}
let topLeftMapPoint = MKMapPointForCoordinate(topLeft)
let bottomRightMapPoint = MKMapPointForCoordinate(bottomRight)
var width = bottomRightMapPoint.x - topLeftMapPoint.x
if width < 0.0 {
// Rect crosses meridian
width += MKMapPointForCoordinate(CLLocationCoordinate2D(latitude: 0.0, longitude: 180.0)).x
}
let height = bottomRightMapPoint.y - topLeftMapPoint.y
let size = MKMapSize(width: width, height: height)
return MKMapRect(origin: topLeftMapPoint, size: size)
}
一些测试用例代码(使用 Nimble):
func testMKMapRectForCoordinateRegion() {
let northWesternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(45.0, -90.0), MKCoordinateSpanMake(20.0, 20.0))
let northWesternMapRect = MKMapRectForCoordinateRegion(region: northWesternRegion)
let convertedNWRegion = MKCoordinateRegionForMapRect(northWesternMapRect)
expect(self.equivalentRegions(northWesternRegion, convertedNWRegion)).to(beTrue())
let northEasternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(45.0, 90.0), MKCoordinateSpanMake(20.0, 20.0))
let northEasternMapRect = MKMapRectForCoordinateRegion(region: northEasternRegion)
let convertedNERegion = MKCoordinateRegionForMapRect(northEasternMapRect)
expect(self.equivalentRegions(northEasternRegion, convertedNERegion)).to(beTrue())
let southWesternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(-45.0, -90.0), MKCoordinateSpanMake(20.0, 20.0))
let southWesternMapRect = MKMapRectForCoordinateRegion(region: southWesternRegion)
let convertedSWRegion = MKCoordinateRegionForMapRect(southWesternMapRect)
expect(self.equivalentRegions(southWesternRegion, convertedSWRegion)).to(beTrue())
let southEasternRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(-45.0, 90.0), MKCoordinateSpanMake(20.0, 20.0))
let southEasternMapRect = MKMapRectForCoordinateRegion(region: southEasternRegion)
let convertedSERegion = MKCoordinateRegionForMapRect(southEasternMapRect)
expect(self.equivalentRegions(southEasternRegion, convertedSERegion)).to(beTrue())
let meridianSpanEastRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(0.0, 170.0), MKCoordinateSpanMake(20.0, 20.0))
let meridianSpanEastMapRect = MKMapRectForCoordinateRegion(region: meridianSpanEastRegion)
let convertedMeridianSpanEastRegion = MKCoordinateRegionForMapRect(meridianSpanEastMapRect)
expect(self.equivalentRegions(meridianSpanEastRegion, convertedMeridianSpanEastRegion)).to(beTrue())
let meridianSpanWestRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(0.0, -170.0), MKCoordinateSpanMake(20.0, 20.0))
let meridianSpanWestMapRect = MKMapRectForCoordinateRegion(region: meridianSpanWestRegion)
let convertedMeridianSpanWestRegion = MKCoordinateRegionForMapRect(meridianSpanWestMapRect)
expect(self.equivalentRegions(meridianSpanWestRegion, convertedMeridianSpanWestRegion)).to(beTrue())
}
fileprivate func equivalentRegions(_ regionA: MKCoordinateRegion, _ regionB: MKCoordinateRegion) -> Bool {
// Allow a small delta between values
let deltaAllowed: Double = 1.0
return (fabs(regionA.center.latitude - regionB.center.latitude) < deltaAllowed) &&
(fabs(regionA.center.longitude - regionB.center.longitude) < deltaAllowed) &&
(fabs(regionA.span.latitudeDelta - regionB.span.latitudeDelta) < deltaAllowed) &&
(fabs(regionA.span.longitudeDelta - regionB.span.longitudeDelta) < deltaAllowed)
}