我需要弄清楚如何设置MKMapSnapshotterOptions来拍摄与地球多角形区域相关的航空/卫星图像快照。
填充“region”、“scale”、“size”和“mapType”属性是微不足道的,因为我有一个MKPolygon需要处理。棘手的部分是在设置‘照相机’--在我的特殊情况下,我使用的是独立于MKMapSnapshotter的MKMapView (事实上,甚至在主线程上也没有)。
但是,我更倾向于将快照定向,以便它符合基于非零标题的多边形的界限--也就是说,我正在拍摄的区域有一个“开始”和一个“结束”,我想将其从底部定位到结果图像的顶部。由于多边形基本上不会在0度航向上自然定向,所以我需要确定‘中心坐标’、‘航向’和‘高度’。
因为我有多边形的坐标,所以我可以很容易地推导出中心坐标和想要的航向--多边形的第一个坐标与形状的‘开始’相关,在我的例子中,结束(或其他坐标)与‘结束’相关。
计算高度被证明是更困难的;我想确保多边形区域最终填充了我想要显示的快照图像的高宽比。如何在不依赖MKMapView的“MKMapCamera”选择器的情况下计算与setRegion一起使用的正确高度?
发布于 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)被比我聪明得多的人纠正,然后找到一个更好的解决方案
谢谢!
哦,当然,密码是:
+ (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];
}发布于 2021-07-07 21:16:26
更新了对iOS 13和更高版本的答复
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)
}它可用于计算某一变焦级的最小中心坐标距离。
let minDistance = mapView.calculateCenterCoordinateDistance(for: 12)
mapView.setCameraZoomRange(MKMapView.CameraZoomRange(minCenterCoordinateDistance: minDistance), animated: false)纵向仪表的计算方法如下:
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
https://stackoverflow.com/questions/21034409
复制相似问题