给定一系列GPS坐标对,我需要计算多边形的面积(n-gon)。这相对较小(不大于50,000平方英尺)。通过对来自世界文件的数据应用仿射变换来创建地理编码。
我试图通过将地理编码转换为笛卡尔坐标来使用两步法:
double xPos = (lon-lonAnchor)*( Math.toRadians( 6378137 ) )*Math.cos( latAnchor );
double yPos = (lat-latAnchor)*( Math.toRadians( 6378137 ) );
然后我使用cross product计算来确定区域。
问题是结果准确度有些偏差(约1%)。我有什么可以改进的吗?
感谢。
答案 0 :(得分:3)
我正在修改Google地图,以便用户可以计算该区域 单击顶点的多边形它没有给出正确的答案 区域,直到我确定Math.cos(latAnchor)首先是弧度
所以:
double xPos = (lon-lonAnchor)*( Math.toRadians( 6378137 ) )*Math.cos( latAnchor );
成为:
double xPos = (lon-lonAnchor)*( 6378137*PI/180 ) )*Math.cos( latAnchor*PI/180 );
其中lon,lonAnchor和latAnchor是度数。现在就像一个魅力。
答案 1 :(得分:2)
由于您的近似值,1%的误差似乎有点高。您是在与实际测量值或理想计算值进行比较吗?请记住,GPS中也存在错误,可能有所不同。
如果你想要一个更准确的方法来做到这一点,那么在this问题上有一个很好的答案。如果您想要更快的方式,可以使用WGS84大地水准面而不是参考球来转换为笛卡尔坐标(ECEF)。这是转换的wiki link。
答案 2 :(得分:2)
我在互联网上检查了各种多边形区域公式(或代码),但没有找到任何好的或易于实现的。
现在我编写了代码片段来计算地球表面上绘制的多边形的面积。多边形可以有n个顶点,每个顶点都有自己的纬度经度。
几点重要
输出区域的单位为平方米
private static double CalculatePolygonArea(IList<MapPoint> coordinates)
{
double area = 0;
if (coordinates.Count > 2)
{
for (var i = 0; i < coordinates.Count - 1; i++)
{
MapPoint p1 = coordinates[i];
MapPoint p2 = coordinates[i + 1];
area += ConvertToRadian(p2.Longitude - p1.Longitude) * (2 + Math.Sin(ConvertToRadian(p1.Latitude)) + Math.Sin(ConvertToRadian(p2.Latitude)));
}
area = area * 6378137 * 6378137 / 2;
}
return Math.Abs(area);
}
private static double ConvertToRadian(double input)
{
return input * Math.PI / 180;
}
答案 3 :(得分:0)
基于Risky Pathak的解决方案,这里是SQL(Redshift)用于计算GeoJSON multipolygons的面积的解决方案(假设线串0是最外面的多边形)
create or replace view geo_area_area as
with points as (
select ga.id as key_geo_area
, ga.name, gag.linestring
, gag.position
, radians(gag.longitude) as x
, radians(gag.latitude) as y
from geo_area ga
join geo_area_geometry gag on (gag.key_geo_area = ga.id)
)
, polygons as (
select key_geo_area, name, linestring, position
, x
, lag(x) over (partition by key_geo_area, linestring order by position) as prev_x
, y
, lag(y) over (partition by key_geo_area, linestring order by position) as prev_y
from points
)
, area_linestrings as (
select key_geo_area, name, linestring
, abs( sum( (x - prev_x) * (2 + sin(y) + sin(prev_y)) ) ) * 6378137 * 6378137 / 2 / 10^6 as area_km_squared
from polygons
where position != 0
group by 1, 2, 3
)
select key_geo_area, name
, sum(case when linestring = 0 then area_km_squared else -area_km_squared end) as area_km_squared
from area_linestrings
group by 1, 2
;
答案 4 :(得分:0)
将RiskyPathak的代码段修改为PHP
class B():
def __init__(self,myA):
self.myA = myA
def doC(self):
self.myA.doCthing()
class C():
def __init__(self):
pass
def go(self):
print("Made it")
答案 5 :(得分:0)
谢谢冒险冒险!
本着共享的精神,这是我在Delphi中的改编:
interface
uses
System.Math;
TMapGeoPoint = record
Latitude: Double;
Longitude: Double;
end;
function AreaInAcres(AGeoPoints: TList<TMapGeoPoint>): Double;
implementation
function AreaInAcres(AGeoPoints: TList<TMapGeoPoint>): Double;
var
Area: Double;
i: Integer;
P1, P2: TMapGeoPoint;
begin
Area := 0;
// We need at least 2 points
if (AGeoPoints.Count > 2) then
begin
for I := 0 to AGeoPoints.Count - 1 do
begin
P1 := AGeoPoints[i];
if i < AGeoPoints.Count - 1 then
P2 := AGeoPoints[i + 1]
else
P2 := AGeoPoints[0];
Area := Area + DegToRad(P2.Longitude - P1.Longitude) * (2 +
Sin(DegToRad(P1.Latitude)) + Sin(DegToRad(P2.Latitude)));
end;
Area := Area * 6378137 * 6378137 / 2;
end;
Area := Abs(Area); //Area (in sq meters)
// 1 Square Meter = 0.000247105 Acres
result := Area * 0.000247105;
end;
答案 6 :(得分:0)
将RiskyPathak的代码段改编成Ruby
def deg2rad(input)
input * Math::PI / 180.0
end
def polygone_area(coordinates)
return 0.0 unless coordinates.size > 2
area = 0.0
coor_p = coordinates.first
coordinates[1..-1].each{ |coor|
area += deg2rad(coor[1] - coor_p[1]) * (2 + Math.sin(deg2rad(coor_p[0])) + Math.sin(deg2rad(coor[0])))
coor_p = coor
}
(area * 6378137 * 6378137 / 2.0).abs # 6378137 Earth's radius in meters
end