旋转后在 MKMapView 上获取 SW/NE 个点

Get SW/NE point on MKMapView after rotation

我正在 Swift 中编写一个应用程序,并使用 Parse 作为后端。

为了设置对 Parse 的查询,我想获取当前 MKMapView 上显示的最西南点和最东北点。

我目前得到这些值,如下所示:

//___ To calculate the search bounds, first we need to calculate the corners of the map
    let nePoint = CGPointMake(self.myMap.bounds.origin.x + myMap.bounds.size.width, myMap.bounds.origin.y);
    let swPoint = CGPointMake((self.myMap.bounds.origin.x), (myMap.bounds.origin.y + myMap.bounds.size.height));

    //___ Then transform those point into lat, lng values
    let neCoord = myMap.convertPoint(nePoint, toCoordinateFromView: myMap)
    let swCoord = myMap.convertPoint(swPoint, toCoordinateFromView: myMap)

    let neGP = PFGeoPoint(latitude: neCoord.latitude, longitude: neCoord.longitude)
    let swGP = PFGeoPoint(latitude: swCoord.latitude, longitude: swCoord.longitude)

    var query = PFQuery(className: "locations")
    //___ Limit what could be a lot of points.
    query.limit = 25
    query.whereKey("location", withinGeoBoxFromSouthwest: swGP, toNortheast: neGP)

在地图旋转之前,此方法运行良好。

但是,一旦用户旋转地图,右上角和左下角的点不再代表最东北和最西南的点。

如何始终计算出地图上显示的真正的最西南点和最东北点?

谢谢。

您需要围绕边界中心旋转点

let degrees = 15 // rotation in degrees
// determine the center
let sw = swPoint
let ne = nePoint
let center = CGPoint(x: (ne.x-sw.x)/2+sw.x, y: (ne.y-sw.y)/2+sw.y)
let translate = CGAffineTransformMakeTranslation(-center.x, -center.y)

// Norm the points around the center
let swN = CGPointApplyAffineTransform(sw, translate)
let neN = CGPointApplyAffineTransform(ne, translate)

// Rotate your points around the center
let rotate = CGAffineTransformMakeRotation(CGFloat(degrees/180.0*M_PI))
let swR = CGPointApplyAffineTransform(swN, rotate)
let neR = CGPointApplyAffineTransform(neN, rotate)

// offset from the center back
let translateBack = CGAffineTransformMakeTranslation(center.x, center.y)

// Final coordinates
let newSouth = CGPointApplyAffineTransform(swR, translateBack)
let newNorth = CGPointApplyAffineTransform(neR, translateBack)

有帮助吗?

要从地图中取回坐标,请应用逆变换

编辑:修正最后一行的拼写错误

MKMapView根据当前标题自动转换:

self.mapView.centerCoordinate = CLLocationCoordinate2D(latitude: 45.5249442, longitude: -73.59655650000002)
let pt0 = self.mapView.convertPoint(CGPointZero, toCoordinateFromView: self.mapView)
// pt0: latitude:80.777327154362311
//      longitude:-163.59656124778414
self.mapView.camera.heading = 45.0
let pt1 = self.mapView.convertPoint(CGPointZero, toCoordinateFromView: self.mapView)
 // pt1: latitude: -84.995143020120821
 //      longitude: -71.475233216395111

所以你其实没什么可做的...

我想出了一个(相当笨拙的)解决方案。

这会显示地图视图中可见的实际最东北点和最西南点,而不是仅仅围绕地图中心旋转这些点,这会导致这些点由于屏幕的原因而移出视图长方形。

    let heading = myMap.camera.heading

    let mapWidth = Double(myMap.frame.width)
    let mapHeight = Double(myMap.frame.height)

    var neX = mapWidth
    var neY = 0.0

    var swX = 0.0
    var swY = mapHeight


    if heading >= 0 && heading <= 90 {

        let ratio = heading / 90

        neX = (1 - ratio) * mapWidth
        swX = mapWidth * ratio
    } else if heading >= 90 && heading <= 180 {

        let ratio = (heading - 90) / 90
        neX = 0
        neY = mapHeight * ratio
        swY = (1 - ratio) * mapHeight
        swX = mapWidth

    } else if heading >= 180 && heading <= 270 {

        let ratio = (heading - 180) / 90
        neX = mapWidth * ratio
        neY = mapHeight
        swX = (1 - ratio) * mapWidth
        swY = 0

    } else if heading >= 270 && heading <= 360 {

        let ratio = (heading - 270) / 90
        neX = mapWidth
        neY = (1 - ratio) * mapHeight
        swY = ratio * mapHeight

    }

    let swPoint = CGPointMake(CGFloat(swX), CGFloat(swY))
    let nePoint = CGPointMake(CGFloat(neX), CGFloat(neY))

    let swCoord = myMap.convertPoint(swPoint, toCoordinateFromView: myMap)
    let neCoord = myMap.convertPoint(nePoint, toCoordinateFromView: myMap)


    //___ Then transform those point into lat,lng values
    let swGP = PFGeoPoint(latitude: swCoord.latitude, longitude: swCoord.longitude)
    let neGP = PFGeoPoint(latitude: neCoord.latitude, longitude: neCoord.longitude)

Objective-C版本:

CLLocationDirection heading = mapView.camera.heading;

    float mapWidth = mapView.frame.size.width;
    float mapHeight = mapView.frame.size.height;

    float neX = mapWidth;
    float neY = 0.0;

    float swX = 0.0;
    float swY = mapHeight;


    if (heading >= 0 && heading <= 90) {
        //println("Q1")
        float ratio = heading / 90;

        neX = (1-ratio) * mapWidth;
        swX = (mapWidth*ratio);
    } else if (heading >= 90 && heading <= 180) {
        //println("Q2")
        float ratio = (heading - 90) / 90;
        neX = 0;
        neY = (mapHeight*ratio);
        swY = (1-ratio) * mapHeight;
        swX = mapWidth;

    } else if (heading >= 180 && heading <= 270) {
        //println("Q3")
        float ratio = (heading - 180) / 90;
        neX = mapWidth*ratio;
        neY = mapHeight;
        swX = (1-ratio) * mapWidth;
        swY = 0;

    } else if (heading >= 270 && heading <= 360) {
        //println("Q4");
        float ratio = (heading - 270) / 90;
        neX = mapWidth;
        neY = (1-ratio) * mapHeight;
        swY = ratio * mapHeight;

    }

    CGPoint swPoint = CGPointMake(swX, swY);
    CGPoint nePoint = CGPointMake(neX, neY);

    CLLocationCoordinate2D swCoord = [mapView convertPoint:swPoint toCoordinateFromView:mapView];
    CLLocationCoordinate2D neCoord = [mapView convertPoint:nePoint toCoordinateFromView:mapView];

对于我的应用程序,我必须获得完全包围可见地图区域的框的 NE/SW 个角。

要认识到的重要一点是,您不能仅通过采样两个角来计算出旋转地图的边界坐标。

如果您只选择这张地图的右上角和左下角并转换为 lat/lon,您将得到红色矩形,这可能不是您想要的。

从图中可以看出,NE和SW边界点不在地图视图的任何位置。

相反,您需要对所有四个角进行采样,然后将它们转换为 lat/lon,然后再进行比较,因为地图可能会颠倒旋转,这意味着您不知道哪个角更多 Northerly/Southerly,等等

// Using  code extension name
typealias Edges = (ne: CLLocationCoordinate2D, sw: CLLocationCoordinate2D)

extension MKMapView {
    func edgePoints() -> Edges {
        let corners = [
            CGPoint(x: self.bounds.minX, y: self.bounds.minY),
            CGPoint(x: self.bounds.minX, y: self.bounds.maxY),
            CGPoint(x: self.bounds.maxX, y: self.bounds.maxY),
            CGPoint(x: self.bounds.maxX, y: self.bounds.minY)
        ]
        let coords = corners.map { corner in
            self.convertPoint(corner, toCoordinateFromView: self)
        }
        let startBounds = (
            n: coords[0].latitude, s: coords[0].latitude,
            e: coords[0].longitude, w: coords[0].longitude)
        let bounds = coords.reduce(startBounds) { b, c in
            let n = max(b.n, c.latitude)
            let s = min(b.s, c.latitude)
            let e = max(b.e, c.longitude)
            let w = min(b.w, c.longitude)
            return (n: n, s: s, e: e, w: w)
        }
        return (ne: CLLocationCoordinate2D(latitude: bounds.n, longitude: bounds.e),
                sw: CLLocationCoordinate2D(latitude: bounds.s, longitude: bounds.w))
    }
}

现在当你运行

时你应该很开心
let edges = mapView.edgePoints()
debugPrint("Edges: ", edges)