使用从笛卡尔空间和世界文件生成的纬度和经度计算多边形区域

时间:2010-05-18 21:27:27

标签: map geocoding latitude-longitude area

给定一系列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%)。我有什么可以改进的吗?

感谢。

7 个答案:

答案 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个顶点,每个顶点都有自己的纬度经度。

几点重要

  1. 此功能的数组输入将具有" n + 1"元素。最后一个元素的值与第一个元素的值相同。
  2. 我编写了非常基本的C#代码,以便人们也可以用其他语言进行修改。
  3. 6378137是地球半径的值,以米为单位。
  4. 输出区域的单位为平方米

    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