ios 将 MKCoordinateRegion 转换为 MKMapRect

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9270268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:49:57  来源:igfitidea点击:

Convert MKCoordinateRegion to MKMapRect

iosmkmapviewmkcoordinateregionmkmaprect

提问by Jon Cox

I have a square MKMapView in my app, and I wish to set a center point and the exact height/width of the view in meters.

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

Creating an MKCoordinateRegion and setting the map to it (as in this code...

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

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

..) doesn't work properly because using regions here just means that at least that region is displayed, typically more than the region is.

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


I'm planning on using setVisibleMapRect:animated:method instead, as I believe this will zoom to the actual MKMapRectpassed.


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

So, is there a simple way to convert between an MKcoordinateRegion and an MKMapRect? Perhaps getting the top-left and bottom-right coordinates of the region, and using them to the make the MKMapRect?

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

I couldn't see anything handy in the Map Kit Functions Reference.

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

(Using iOS 5, Xcode 4.2)

(使用 iOS 5、Xcode 4.2)

回答by leo

To add another implementation to the pile:

向堆中添加另一个实现:

- (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));
}

NB: There are many ways to convert between MKMapRectand MKCoordinateRegion. This one certainly is notthe exact inverse of MKCoordinateRegionMakeWithDistance(), but approximates it fairly well. So, be careful converting back and forth, because information can be lost.

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

回答by Mike

This is a Swift verion to Leo & Barnhart solution

这是 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)))
}

回答by Bogdan

Use MKMapPointForCoordinate to convert the 2 point of the region (top/left and bottom/right), then create the MKMapRect using the 2 MKMapPoints

使用 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);

回答by chatur

you can use method to convert MKCoordinateRegionto CGRect

您可以使用方法转换MKCoordinateRegionCGRect

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

and use - (MKMapRect)mapRectForRect:(CGRect)rect

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

or use MKMapPointForCoordinatemethod to first convert coordinates to MKPointand use that to form MKMapRectto eventually use setVisibleMapRect:animated:

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

回答by David

@Bogdan

@博格丹

I think it should be:

我觉得应该是:

 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));

According to apple api reference, MKCoordinateRegion.center represents the center point of the region; and MKCoordinateSpan.latitudeDelta represents the amount of north-to-south distance (measured in degrees) to display on the map; MKCoordinateSpan.longitudeDelta represents amount of east-to-west distance (measured in degrees) to display for the map region.

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

回答by onmyway133

@David's answer, in Swift 3

@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)
}

回答by Mark A Durham

The answer @David gave (and consequently the Swift 3 version by @onmyway133) has a significant error whenever the region crosses over the anti-meridian from the Eastern Hemisphere (longitude 0 degrees to 180 degrees) to the Western Hemisphere (longitude -180 degrees to 0 degrees). The width of the MKMapRect will be bigger than it should be (usually muchbigger).

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

Here is the fix (for the Swift 3 code):

这是修复(针对 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)

Taking an MKCoordinateRegion, converting it into an MKMapRect with the code above, and then turning it back into an MKCoordinateRegion using MKCoordinateRegionForMapRect() gives me very good agreement between the input region and the output region everywhere on the map.

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

回答by GilroyKilroy

Still have to be a bit more careful about crossing the meridian (as well as wrapping around the poles) otherwise MKMapPointForCoordinate returns -1, -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)
}

Some test case code (using Nimble):

一些测试用例代码(使用 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)
}

回答by Duane Fields

Use the built in function MKCoordinateRegionForMapRect

使用内置函数 MKCoordinateRegionForMapRect

MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect);