【问题标题】:Get SW/NE point on MKMapView after rotation旋转后在 MKMapView 上获取 SW/NE 点
【发布时间】:2015-05-05 22:47:04
【问题描述】:

我正在用 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)

这在地图旋转之前完美运行。

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

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

谢谢。

【问题讨论】:

    标签: ios swift mkmapview


    【解决方案1】:

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

    要意识到的重要一点是,您无法通过仅对两个角进行采样来确定旋转地图的边界坐标。

    如果你只选择了这张地图的右上角和左下角并转换为纬度/经度,你会得到红色的矩形,这可能不是你想要的。

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

    相反,您需要对所有四个角进行采样,然后将它们转换为纬度/经度,然后再进行比较,因为地图可能会颠倒旋转,这意味着您不知道哪个角更偏北/更偏南等。

    // Using http://stackoverflow.com/a/28683812/1207583 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)
    

    【讨论】:

      【解决方案2】:

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

      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)
      

      这有帮助吗?

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

      编辑:修正最后一行的错字

      【讨论】:

      • 这还不太适合我。我假设你的最后一行应该是:'let newNorth = CGPointApplyAffineTransform(neR, translateBack)' 在旋转之前我得到: newSouth:(0.0,568.0) newNorth:(320.0, 0.0) 这是正确的。旋转大约 90 度后,我得到:newSouth:(450.329289868992,432.205612053548) newNorth:(-130.329289868992,135.794387946452)。抱歉,我在评论结束前不小心按了 Enter。
      • 获取当前航向,使用mapView的mapCamera属性developer.apple.com/library/ios/documentation/MapKit/Reference/…
      • 啊!我之前得到的度数旋转不同,这产生了负值。现在通过使用标题为我的度值,旋转〜90度我返回: SWR:( - 282.925430844159,-161.892558759343)ner:(282.925430844159,161.8925587599,161.892558759343)新闻:( - 122.925430844159,122.10741240657)Newnorth:(442.925430844157)NewNorth:(442.925430844159, 445.892558759343)
      • 将最后几行替换为: let newSouth = CGPointMake(swR.x + center.x, swR.y + center.y) let newNorth = CGPointMake(neR.x + center.x, neR. y + center.y)
      • 我得到了非常相似的结果:newSouth:(-132.9152050359,140.973140079297) - newNorth:(452.9152050359,427.026859920703)
      【解决方案3】:

      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
      

      所以你实际上没有什么可做的......

      【讨论】:

      • 也许我没有很好地解释我的问题。我需要在地图上找到最东北点和最西南点。如果我将地图旋转 180 度,最东北点将是 (0, 568),西南点将是 (320,0)。
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        这会显示地图视图中可见的实际最东北和最西南的点,而不是仅围绕地图中心旋转这些点,这会导致这些点由于屏幕的矩形形状而移动到视图之外.

            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)
        

        【讨论】:

        • 这是不对的......你的点必须在地图之外,因为它围绕中心旋转并且你正在处理非方形地图。您忘记了,您现在提取的点在地图上根本不可见,因此您很满意,但从数学意义上说并非如此。
        • 我说,“我想在当前的 MKMapView 上显示最西南的点和最东北的点。”这正是我得到的。我不想要可见地图矩形之外的任何点。我非常感谢您的帮助,您的帮助让我得到了这个解决方案。
        • 当您请求 convertPoint 时,会立即从 MKMapView 提供...无论如何,祝您好运。
        猜你喜欢
        • 1970-01-01
        • 2016-08-28
        • 2012-03-16
        • 2014-09-14
        • 2012-06-07
        • 2012-09-23
        • 2020-05-07
        • 1970-01-01
        • 2018-11-01
        相关资源
        最近更新 更多