45

我的应用程序中有一个方形 MKMapView,我希望设置一个中心点和视图的确切高度/宽度(以米为单位)。

创建一个 MKCoordinateRegion 并将地图设置为它(如在此代码中...

MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center_coord, 1000.0, 1000.0);
[self.mapView setRegion:region animated:YES];

..) 无法正常工作,因为在此处使用区域仅意味着至少显示该区域,通常比该区域更多。


我打算改用setVisibleMapRect:animated:方法,因为我相信这会放大到实际传递的MKMapRect

那么,有没有一种简单的方法可以在 MKcoordinateRegion 和 MKMapRect 之间进行转换?也许获取该区域的左上角和右下角坐标,并使用它们来制作 MKMapRect?

我在Map Kit Functions Reference中看不到任何方便的东西。

(使用 iOS 5,Xcode 4.2)

4

10 回答 10

61

要将另一个实现添加到堆中:

- (MKMapRect)MKMapRectForCoordinateRegion:(MKCoordinateRegion)region
{
    MKMapPoint a = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
        region.center.latitude + region.span.latitudeDelta / 2, 
        region.center.longitude - region.span.longitudeDelta / 2));
    MKMapPoint b = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
        region.center.latitude - region.span.latitudeDelta / 2, 
        region.center.longitude + region.span.longitudeDelta / 2));
    return MKMapRectMake(MIN(a.x,b.x), MIN(a.y,b.y), ABS(a.x-b.x), ABS(a.y-b.y));
}

注意:有很多方法可以在 和 之间进行MKMapRect转换MKCoordinateRegion。这当然不是的精确倒数MKCoordinateRegionMakeWithDistance(),但可以很好地近似它。所以,来回转换时要小心,因为信息可能会丢失。

于 2013-03-28T13:22:51.770 回答
40

这是 Leo & Barnhart 解决方案的 Swift 版本

func MKMapRectForCoordinateRegion(region:MKCoordinateRegion) -> MKMapRect {
    let topLeft = CLLocationCoordinate2D(latitude: region.center.latitude + (region.span.latitudeDelta/2), longitude: region.center.longitude - (region.span.longitudeDelta/2))
    let bottomRight = CLLocationCoordinate2D(latitude: region.center.latitude - (region.span.latitudeDelta/2), longitude: region.center.longitude + (region.span.longitudeDelta/2))

    let a = MKMapPointForCoordinate(topLeft)
    let b = MKMapPointForCoordinate(bottomRight)
    
    return MKMapRect(origin: MKMapPoint(x:min(a.x,b.x), y:min(a.y,b.y)), size: MKMapSize(width: abs(a.x-b.x), height: abs(a.y-b.y)))
}
于 2016-02-10T17:11:11.283 回答
12

使用 MKMapPointForCoordinate 转换区域的 2 点(上/左和下/右),然后使用 2 MKMapPoints 创建 MKMapRect

        CLLocationCoordinate2D coordinateOrigin = CLLocationCoordinate2DMake(latitude, longitude);
        CLLocationCoordinate2D coordinateMax = CLLocationCoordinate2DMake(latitude + cellSize, longitude + cellSize);

        MKMapPoint upperLeft = MKMapPointForCoordinate(coordinateOrigin);
        MKMapPoint lowerRight = MKMapPointForCoordinate(coordinateMax);

        MKMapRect mapRect = MKMapRectMake(upperLeft.x,
                                          upperLeft.y,
                                          lowerRight.x - upperLeft.x,
                                          lowerRight.y - upperLeft.y);
于 2012-06-21T18:14:55.080 回答
10

您可以使用方法转换MKCoordinateRegionCGRect

- (CGRect)convertRegion:(MKCoordinateRegion)region toRectToView:(UIView *)view

并使用- (MKMapRect)mapRectForRect:(CGRect)rect

或使用MKMapPointForCoordinate方法首先将坐标转换为MKPoint并使用它来形成MKMapRect最终使用setVisibleMapRect:animated:

于 2012-02-14T05:40:39.557 回答
9

@博格丹

我认为应该是:

 CLLocationCoordinate2D topLeftCoordinate =
CLLocationCoordinate2DMake(coordinateRegion.center.latitude
                           + (coordinateRegion.span.latitudeDelta/2.0),
                           coordinateRegion.center.longitude
                           - (coordinateRegion.span.longitudeDelta/2.0));

MKMapPoint topLeftMapPoint = MKMapPointForCoordinate(topLeftCoordinate);

CLLocationCoordinate2D bottomRightCoordinate =
CLLocationCoordinate2DMake(coordinateRegion.center.latitude
                           - (coordinateRegion.span.latitudeDelta/2.0),
                           coordinateRegion.center.longitude
                           + (coordinateRegion.span.longitudeDelta/2.0));

MKMapPoint bottomRightMapPoint = MKMapPointForCoordinate(bottomRightCoordinate);

MKMapRect mapRect = MKMapRectMake(topLeftMapPoint.x,
                                  topLeftMapPoint.y,
                                  fabs(bottomRightMapPoint.x-topLeftMapPoint.x),
                                  fabs(bottomRightMapPoint.y-topLeftMapPoint.y));

根据apple api reference, MKCoordinateRegion.center 表示区域的中心点;MKCoordinateSpan.latitudeDelta 表示要在地图上显示的南北距离量(以度为单位);MKCoordinateSpan.longitudeDelta 表示要为地图区域显示的东西距离量(以度为单位)。

于 2012-12-10T09:39:33.427 回答
2

@David 在 Swift 3 中的回答

func mapRect(region: MKCoordinateRegion) -> MKMapRect {
  let topLeft = CLLocationCoordinate2D(
    latitude: region.center.latitude + (region.span.latitudeDelta/2.0),
    longitude: region.center.longitude - (region.span.longitudeDelta/2.0)
  )

  let bottomRight = CLLocationCoordinate2D(
    latitude: region.center.latitude - (region.span.latitudeDelta/2.0),
    longitude: region.center.longitude + (region.span.longitudeDelta/2.0)
  )

  let topLeftMapPoint = MKMapPointForCoordinate(topLeft)
  let bottomRightMapPoint = MKMapPointForCoordinate(bottomRight)

  let origin = MKMapPoint(x: topLeftMapPoint.x,
                          y: topLeftMapPoint.y)
  let size = MKMapSize(width: fabs(bottomRightMapPoint.x - topLeftMapPoint.x),
                       height: fabs(bottomRightMapPoint.y - topLeftMapPoint.y))

  return MKMapRect(origin: origin, size: size)
}
于 2017-05-03T09:46:45.977 回答
1

在穿越子午线(以及环绕两极)时仍然必须更加小心,否则 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)
}
于 2017-09-04T19:11:45.057 回答
1

每当该区域从东半球(经度 0 度到 180 度)越过反子午线到西半球(经度 -180 度)时,@David 给出的答案(以及因此由 @onmyway133 提供的 Swift 3 版本)都会出现重大错误到 0 度)。MKMapRect 的宽度将比它应该的大(通常大得多)。

这是修复(针对 Swift 3 代码):

let topLeftMapPoint = MKMapPointForCoordinate(topLeft)
let bottomRightMapPoint = MKMapPointForCoordinate(bottomRight)
var width = bottomRightMapPoint.x - topLeftMapPoint.x
if width < 0.0 {
    // Rect crosses from the Eastern Hemisphere to the Western Hemisphere
    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)

获取一个 MKCoordinateRegion,使用上面的代码将其转换为 MKMapRect,然后使用 MKCoordinateRegionForMapRect() 将其转换回 MKCoordinateRegion,这让我在地图上各处的输入区域和输出区域之间取得了非常好的一致性。

于 2017-08-09T03:58:37.267 回答
1

斯威夫特 5.1:

func mapRectForCoordinateRegion(_ region: MKCoordinateRegion) -> MKMapRect {
   let topLeftCoordinate = CLLocationCoordinate2DMake(region.center.latitude + (region.span.latitudeDelta / 2.0), region.center.longitude - (region.span.longitudeDelta / 2.0))
   let topLeftMapPoint = MKMapPoint(topLeftCoordinate)
   let bottomRightCoordinate = CLLocationCoordinate2DMake(region.center.latitude - (region.span.latitudeDelta / 2.0), region.center.longitude + (region.span.longitudeDelta / 2.0))
   let bottomRightMapPoint = MKMapPoint(bottomRightCoordinate)
   return MKMapRect(x: topLeftMapPoint.x, y: topLeftMapPoint.y, width: fabs(bottomRightMapPoint.x - topLeftMapPoint.x), height: fabs(bottomRightMapPoint.y - topLeftMapPoint.y))

}

于 2020-10-19T08:59:05.853 回答
-1

使用内置函数MKCoordinateRegionForMapRect

MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect);
于 2012-03-26T15:25:40.327 回答