如何确定MKMapCamera专注于MKPolygon的正确高度 [英] How to determine the correct altitude for an MKMapCamera focusing on an MKPolygon

查看:264
本文介绍了如何确定MKMapCamera专注于MKPolygon的正确高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to figure out how to set up MKMapSnapshotterOptions to take a snapshot of aerial/satellite imagery associated with a polygonal region of the earth.

填写' region','scale','size'和'mapType'属性是微不足道的,因为我有一个MKPolygon可以使用。棘手的部分是设置'相机' - 在我的特定情况下,我独立于MKMapView使用MKMapSnapshotter(事实上,甚至不在主线程上)。

Filling out the 'region', 'scale', 'size', and 'mapType' properties are trivial, as I have an MKPolygon to work with. The tricky part is in setting the 'camera' -- in my particular case, I am using MKMapSnapshotter independently of the MKMapView (in fact, not even on the main thread).

但是,我更喜欢定位快照,使其适合基于非零标题的多边形边界 - 也就是说,我正在拍摄的区域具有'开始'和'结束'我想从最终图像的底部到顶部定位。由于多边形基本上永远不会在0度标题上自然定向,我需要确定'centerCoordinate','heading'和'altitude'。

However, I would prefer to orient the snapshot so that it fits the bounds of the polygon based on a non-zero heading -- that is, the area that I am taking a picture of has a 'start' and an 'end' that I would like to orient from the bottom to the top of the resulting image. Since the polygon is basically never going to be naturally oriented on a 0 degree heading, I will need to determine the 'centerCoordinate', 'heading', and 'altitude'.

由于我有多边形的坐标,我能够非常容易地导出中心坐标和所需的标题 - 多边形的第一个坐标与形状和结束的开始(或者我的情况下的其他坐标)相关联与'结束'相关。

As I have the polygon's coordinates, I am able to derive the center coordinate and desired heading fairly easily -- The first coordinate of the polygon correlates to the 'start' of the shape and the end (or other coordinate, in my case) correlates to the 'end'.

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

Figuring out the altitude is proving to be more difficult; I want to make sure that the polygon area ends up filling the aspect ratio of the snapshot image I wish to display. How do I calculate the correct altitude to use with the MKMapCamera without relying on MKMapView's 'setRegion' selector?

推荐答案

为了解决这个问题,我最终做了以下几点:

In order to solve this problem, I ended up doing the following:

1)在确定边界矩形时围绕它的中心坐标旋转MKPolygon以消除标题/旋转问题:询问MKPolygon没有这个'boundingMapRect'会返回整个形状周围的最小矩形。如果一个长而瘦的多边形恰好从东北向西南方向倾斜,则边界矩形几乎是方形的。执行旋转允许在确定多边形的宽高比时考虑多边形的航向。

1) rotating the MKPolygon around it's center coordinate to eliminate heading/rotation issues when determining a bounding rectangle: asking an MKPolygon for it's 'boundingMapRect' without this would return whatever minimum rectangle fit around the entirety of the shape. If a long, skinny polygon happened to be oriented diagonally from north-east to south-west, the bounding rect would be nearly square. Performing the rotation allows for the heading of the polygon to be taken into account in determining it's aspect ratio.

2)将多边形的经过航向校正的边界矩形拟合到宽高比中快照视口:这可以确保非常高的多边形仍能在宽视角视口中正确匹配,反之亦然。

2) fitting the polygon's heading-corrected bounding rectangle into the aspect ratio of the snapshot viewport: this ensures that a very 'tall' polygon will still fit properly in a wide-aspect viewport and vice-versa.

3) [从我的示例代码中删除] 创建生成的经方面校正的边界矩形的多边形,并使用多边形的中心坐标将其旋转回原始标题:如果使用大区域,则可能需要这样做,如下一步涉及水平/垂直边界距离之间的测量。在我的情况下,我正在处理非常小的区域,这些区域不应受到地球曲率的影响而产生真正的差异。

3)[Removed from my example code] Creating a polygon of the resulting aspect-corrected bounding rectangle and rotating it back to the original heading using the polygon's center coordinate: This would likely be needed if working with large regions, as the next step involves measurement between horizontal/vertical bounding distances. In my case, I am working with very small regions that should not be impacted enough by the curvature of the earth to make a real difference.

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

4) determining the total horizontal and vertical bounding region in meters

5)使用两个距离的较大尺寸(尺寸)来形成三角形的基本测量值,其中A =最小坐标位置轴,B =轴上的最大坐标位置,C =相机位置(多边形的中心坐标)

5) using the larger dimension (Dimension) of the two distances to form the base measurement of a triangle, where A = minimum coordinate location on axis, B = maximum coordinate location on axis, and C = camera location (center coordinate of the polygon)

此时,我有点难过如何在没有至少一个角度的情况下求解所得三角形的高度。在使用MKMapView实例执行某些测试时,看起来MKMapCamera的光圈大约是30度 - 这无论是增加视口的宽高比,多边形的宽高比,还是任何其他因素比地球的曲率。我可能错了这个断言。

At this point, I was a bit stumped as to how to solve the altitude of the resulting triangle without having at least 1 of the angles. In performing some tests using an MKMapView instance, it appears that the aperture of the MKMapCamera is about 30 degrees -- this is regardless of augmenting the aspect ratio of the viewport, aspect ratio of the polygon, or any other factor than the curvature of the earth. I may be wrong about this assertion.

5)使用我测试中观察到的孔径角,使用(尺寸/ 2)/棕褐色计算所需的高度(aperture_angle_in_radians / 2)

5) Using the aperture angle observed in my tests, calculate the needed altitude using (dimension / 2) / tan(aperture_angle_in_radians / 2)

看到我花了多少时间花在这上面,我决定在StackOverflow上发布问题/答案组合,希望它:
1)帮助处于相同情况的其他人
2)通过比我更聪明的方式得到纠正并导致更好的解决方案

Seeing how much time I ended up spending on this, I've decided to post the question/answer combo on StackOverflow in hopes that it either: 1) helps someone else in the same situation 2) is corrected by someone way smarter than I am and leads to an even better solution

谢谢!

OH,当然,代码:

+ (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];
}

这篇关于如何确定MKMapCamera专注于MKPolygon的正确高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆