我只是不知道如何计算MKMapView上的区域。谁解决了这个问题呢?
这是我的代码,但它返回的方式太多了:
func ringArea() -> Double{
var area: Double = 0
if templocations.count > 2 {
var p1,p2:CLLocationCoordinate2D
for var i = 0; i < templocations.count - 1; i++ {
var loc = templocations[i] as CLLocation
p1 = CLLocationCoordinate2D(latitude: loc.coordinate.latitude, longitude: loc.coordinate.longitude)
loc = templocations[i+1] as CLLocation
p2 = CLLocationCoordinate2D(latitude: loc.coordinate.latitude, longitude: loc.coordinate.longitude)
var sinfunc: Float = (2 + sinf(Float(degreeToRadiant(p1.latitude))) + sinf(Float(degreeToRadiant(p2.latitude))))
area += degreeToRadiant(p2.longitude - p1.longitude) * Double(sinfunc)
}
area = area * kEarthRadius * kEarthRadius / 2;
}
return area
}
答案 0 :(得分:5)
Stefan的回答在 Swift 3.0 :
中实现import MapKit
let kEarthRadius = 6378137.0
func radians(degrees: Double) -> Double {
return degrees * M_PI / 180;
}
func regionArea(locations: [CLLocationCoordinate2D]) -> Double {
guard locations.count > 2 else { return 0 }
var area = 0.0
for i in 0..<locations.count {
let p1 = locations[i > 0 ? i - 1 : locations.count - 1]
let p2 = locations[i]
area += radians(degrees: p2.longitude - p1.longitude) * (2 + sin(radians(degrees: p1.latitude)) + sin(radians(degrees: p2.latitude)) )
}
area = -(area * kEarthRadius * kEarthRadius / 2);
return max(area, -area) // In order not to worry about is polygon clockwise or counterclockwise defined.
}
答案 1 :(得分:4)
#define kEarthRadius 6378137
@implementation MKPolygon (AreaCalculation)
- (double) area {
double area = 0;
NSMutableArray *coords = [[self coordinates] mutableCopy];
[coords addObject:[coords firstObject]];
if (coords.count > 2) {
CLLocationCoordinate2D p1, p2;
for (int i = 0; i < coords.count - 1; i++) {
p1 = [coords[i] MKCoordinateValue];
p2 = [coords[i + 1] MKCoordinateValue];
area += degreesToRadians(p2.longitude - p1.longitude) * (2 + sinf(degreesToRadians(p1.latitude)) + sinf(degreesToRadians(p2.latitude)));
}
area = - (area * kEarthRadius * kEarthRadius / 2);
}
return area;
}
- (NSArray *)coordinates {
NSMutableArray *points = [NSMutableArray arrayWithCapacity:self.pointCount];
for (int i = 0; i < self.pointCount; i++) {
MKMapPoint *point = &self.points[i];
[points addObject:[NSValue valueWithMKCoordinate:MKCoordinateForMapPoint(* point)]];
}
return points.copy;
}
double degreesToRadians(double radius) {
return radius * M_PI / 180;
}
答案 2 :(得分:1)
我用球形多余物来计算面积。 StefanS的回答中的文章很好地解释了球形多余物的工作原理。它使用三角形,其中一条边是多边形线段,另一条边是连接到极点的子午线。维基百科建议使用具有相同原理的“球形四边形”。它使用了多边形线段,赤道和连接到赤道的两个子午线边缘。
StefanS的答案使用方程式来近似面积。我想更精确些。我实现了3种不同的功能。近似值,精确的球形三角形和精确的球形四边形。
在我的用例中,时间可以忽略不计,但这是基线:
0.208-近似时间基线
0.517-精确的球形四边形时间基线
0.779-精确的球形三角形时间基准
作为奖励,四边形解不需要对后视点进行任何调整,而近似值则需要。四边形解决方案比三角形解决方案简单得多。在我的测试中,四边形和三角形解之间的最大结果差约为0.0000001%。
我使用了维基百科的球形三角学,面积和球形多余度中的这个等式:https://en.wikipedia.org/wiki/Spherical_trigonometry#Area_and_spherical_excess
StefanS的文章: Chamberlain&Duquette撰写的“球形多边形上的某些算法”(加利福尼亚理工学院,JPL出版07-3,2007年)中详细介绍了“球形情况”方程。
func areaUsingQuadrilateralSphericalExcess(_ coordinates: [CLLocationCoordinate2D]) -> Double {
// the poles cannot be in the polygon
guard coordinates.count > 2 else { return 0 }
let kEarthRadius = 6378137.0
var sum = 0.0
for i in 0..<coordinates.count {
let p1Latitude = coordinates[i].latitude.degreesToRadians
let p1Longitude = coordinates[i].longitude.degreesToRadians
let p2Latitude = coordinates[i + 1].latitude.degreesToRadians
let p2Longitude = coordinates[i + 1].longitude.degreesToRadians
let sphericalExcess = 2 * atan((sin(0.5 * (p2Latitude + p1Latitude))/cos(0.5 * (p2Latitude - p1Latitude))) * tan((p2Longitude - p1Longitude)/2))
sum += sphericalExcess
}
return abs(sum * kEarthRadius * kEarthRadius) // if a clockwise polygon, sum will be negative
}
答案 3 :(得分:0)
如果您所在区域的尺寸不是太大,以至于您需要调整地球椭球体的效果,您仍然可以使用2D几何来计算表面区域。
假设p1和p2相距小于几度且p1是圆的中心,而p2是半径上的任意点(径向点),则以下函数将返回以平方米为单位的面积。 / p>
func findCircleArea(centre: CLLocation, radialLocation: CLLocation) -> Double {
// Find the distance from the centre to the radial location in metres
let radius = centre.distanceFromLocation(radialLocation)
// Apply standard 2D area calculation for a circle
let area = M_PI * radius * radius
// Answer is in square metres
return area
}
如果p1和p2都是圆周上的点,则改为使用此函数:
func findCircleAreaBetweenPoints(p1: CLLocation, p2: CLLocation) -> Double {
// Find the distance from the two points and halve it
let radius = p1.distanceFromLocation(p2) / 2.0
// Apply standard 2D area calculation for a circle
let area = M_PI * radius * radius
// Answer is in square metres
return area
}
如果您不使用公制测量,请相应地调整答案。
请记住,所有表面积计算都是近似值,因为在标准海平面测量的标准WGS84球体的假设不考虑给定位置的高程变化。 distanceFromLocation()计算使用Great Circle计算来获得点之间的正确距离,因此半径相当准确,但是当半径太大时,近似误差也会增大。