首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何确定聚焦在MKMapCamera上的MKPolygon的正确高度

如何确定聚焦在MKMapCamera上的MKPolygon的正确高度
EN

Stack Overflow用户
提问于 2014-01-10 01:04:51
回答 2查看 3.3K关注 0票数 6

我需要弄清楚如何设置MKMapSnapshotterOptions来拍摄与地球多角形区域相关的航空/卫星图像快照。

填充“region”、“scale”、“size”和“mapType”属性是微不足道的,因为我有一个MKPolygon需要处理。棘手的部分是在设置‘照相机’--在我的特殊情况下,我使用的是独立于MKMapSnapshotter的MKMapView (事实上,甚至在主线程上也没有)。

但是,我更倾向于将快照定向,以便它符合基于非零标题的多边形的界限--也就是说,我正在拍摄的区域有一个“开始”和一个“结束”,我想将其从底部定位到结果图像的顶部。由于多边形基本上不会在0度航向上自然定向,所以我需要确定‘中心坐标’、‘航向’和‘高度’。

因为我有多边形的坐标,所以我可以很容易地推导出中心坐标和想要的航向--多边形的第一个坐标与形状的‘开始’相关,在我的例子中,结束(或其他坐标)与‘结束’相关。

计算高度被证明是更困难的;我想确保多边形区域最终填充了我想要显示的快照图像的高宽比。如何在不依赖MKMapView的“MKMapCamera”选择器的情况下计算与setRegion一起使用的正确高度?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-10 01:04:51

为了解决这个问题,我最后做了以下工作:

1)在确定边界矩形时,将MKPolygon围绕其中心坐标旋转,以消除标题/旋转问题:如果不使用该方法,要求MKPolygon将其为“boundingMapRect”,则会返回与整个形状匹配的最小矩形。如果一个细长的多边形恰好从东北向西南方向倾斜,那么边角几乎是正方形。执行旋转允许在确定多边形的高宽比时考虑到多边形的标题。

2)将多边形的标题校正的边框与快照视口的纵横比相匹配:这将确保非常“高”的多边形仍然适合宽角度视图,反之亦然。

3)从我的示例代码中移除,该代码创建了一个经过方面校正的边框的多边形,并使用多边形的中心坐标将其旋转回原来的标题:如果使用大区域,则可能需要这样做,因为下一步涉及到水平/垂直边界距离之间的测量。在我的例子中,我工作的区域非常小,这些区域不应该受到地球曲率的足够影响,从而产生真正的影响。

( 4)以米为单位确定总水平和垂直边界区域。

( 5)利用两个距离的较大维数(维数)构成三角形的基本测量,其中A=轴上最小坐标位置,B=轴上最大坐标位置,C=摄像机位置(多边形中心坐标)。

在这一点上,我有点困惑如何解决所产生的三角形的高度,而不至少有一个角度。在使用MKMapView实例进行一些测试时,看起来MKMapCamera的孔径大约是30度 --这与增加视口的纵横比、多边形的纵横比或地球曲率以外的任何其他因素无关。这个说法我可能错了。

( 5)利用试验中观测到的孔径角,用(维度/ 2) / tan(aperture_angle_in_radians / 2)计算所需高度。

考虑到我在这方面花费了多少时间,我决定在StackOverflow上发布问答组合,希望它能: 1)帮助处于相同情况的其他人,2)被比我聪明得多的人纠正,然后找到一个更好的解决方案

谢谢!

哦,当然,密码是:

代码语言:javascript
复制
+ (double)determineAltitudeForPolygon:(MKPolygon *)polygon withHeading:(double)heading andWithViewport:(CGSize)viewport {
    // Get a bounding rectangle that encompasses the polygon and represents its
    // true aspect ratio based on the understanding of its heading.
    MKMapRect boundingRect = [[self rotatePolygon:polygon withCenter:MKMapPointForCoordinate(polygon.coordinate) byHeading:heading] boundingMapRect];

    MKCoordinateRegion boundingRectRegion = MKCoordinateRegionForMapRect(boundingRect);

    // Calculate a new bounding rectangle that is corrected for the aspect ratio
    // of the viewport/camera -- this will be needed to ensure the resulting
    // altitude actually fits the polygon in view for the observer.
    CLLocationCoordinate2D upperLeftCoord = CLLocationCoordinate2DMake(boundingRectRegion.center.latitude + boundingRectRegion.span.latitudeDelta / 2, boundingRectRegion.center.longitude - boundingRectRegion.span.longitudeDelta / 2);
    CLLocationCoordinate2D upperRightCoord = CLLocationCoordinate2DMake(boundingRectRegion.center.latitude + boundingRectRegion.span.latitudeDelta / 2, boundingRectRegion.center.longitude + boundingRectRegion.span.longitudeDelta / 2);
    CLLocationCoordinate2D lowerLeftCoord = CLLocationCoordinate2DMake(boundingRectRegion.center.latitude - boundingRectRegion.span.latitudeDelta / 2, boundingRectRegion.center.longitude - boundingRectRegion.span.longitudeDelta / 2);

    CLLocationDistance hDist = MKMetersBetweenMapPoints(MKMapPointForCoordinate(upperLeftCoord), MKMapPointForCoordinate(upperRightCoord));
    CLLocationDistance vDist = MKMetersBetweenMapPoints(MKMapPointForCoordinate(upperLeftCoord), MKMapPointForCoordinate(lowerLeftCoord));

    double adjacent;
    double newHDist, newVDist;

    if (boundingRect.size.height > boundingRect.size.width) {
        newVDist = vDist;
        newHDist = (viewport.width / viewport.height) * vDist;

        adjacent = vDist / 2;
    } else {
        newVDist = (viewport.height / viewport.width) * hDist;
        newHDist = hDist;

        adjacent = hDist / 2;
    }

    double result = adjacent / tan(Deg_to_Rad(15));
    return result;
}

+ (MKPolygon *)rotatePolygon:(MKPolygon *)polygon withCenter:(MKMapPoint)centerPoint byHeading:(double)heading {
    MKMapPoint points[polygon.pointCount];
    double rotation_angle = -Deg_to_Rad(heading);

    for(int i = 0; i < polygon.pointCount; i++) {
        MKMapPoint point = polygon.points[i];

        // Translate each point by the coordinate to rotate around, use matrix
        // algebra to perform the rotation, then translate back into the
        // original coordinate space.
        double newX = ((point.x - centerPoint.x) * cos(rotation_angle)) + ((centerPoint.y - point.y) * sin(rotation_angle)) + centerPoint.x;
        double newY = ((point.x - centerPoint.x) * sin(rotation_angle)) - ((centerPoint.y - point.y) * cos(rotation_angle)) + centerPoint.y;

        point.x = newX;
        point.y = newY;

        points[i] = point;
    }

    return [MKPolygon polygonWithPoints:points count:polygon.pointCount];
}
票数 21
EN

Stack Overflow用户

发布于 2021-07-07 21:16:26

更新了对iOS 13和更高版本的答复

代码语言:javascript
复制
func calculateCenterCoordinateDistance(for zoomLevel: CGFloat) -> CLLocationDistance {
    let width = self.frame.size.width
    let span = MKCoordinateSpan(latitudeDelta: 0.0, longitudeDelta:
        CLLocationDegrees(360 * width / (pow(2, (zoomLevel - 1)) * 256)))
    let region = MKCoordinateRegion(center: self.region.center, span: span)
    
    let aspectRatio = Double(self.frame.size.height / self.frame.size.width)
    let radianCameraAperture: Double = 30 * .pi / 180
    let areaRadius = aspectRatio * region.longitudinalMeters / 2

    return areaRadius / tan(radianCameraAperture / 2)
}

它可用于计算某一变焦级的最小中心坐标距离。

代码语言:javascript
复制
let minDistance = mapView.calculateCenterCoordinateDistance(for: 12)
mapView.setCameraZoomRange(MKMapView.CameraZoomRange(minCenterCoordinateDistance: minDistance), animated: false)

纵向仪表的计算方法如下:

代码语言:javascript
复制
extension MKCoordinateRegion {
    var east: CLLocation {
        return CLLocation(latitude: center.latitude, longitude: center.longitude + span.longitudeDelta / 2)
    }
    var west: CLLocation {
        return CLLocation(latitude: center.latitude, longitude: center.longitude - span.longitudeDelta / 2)
    }
    var longitudinalMeters: CLLocationDistance {
        return east.distance(from: west)
    }
}

学分:https://gist.github.com/marmelroy/0fee54bfe69bfbfcbbf7057298fca046

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21034409

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档