C# GMap.Net 计算多边形面积

Cédric Bignon  :

Let‘s note Points the points of the polygon (where Points[0] == Points[Points.Count - 1] to close the polygon).

The idea behind the next methods is to split the polygon into triangles (the area is the sum of all triangle areas). But, to support all polygon types with a simple decomposition (not only star-shaped polygon), some triangle contributions are negative (we have a "negative" area). The triangles decomposition I use is : {(O, Points[i], Points[i + 1]} where O is the origin of the affine space.

The area of a non-self-intersecting polygon (in euclidian geometry) is given by:

In 2D:

float GetArea(List<Vector2> points)
{
    float area2 = 0;
    for (int numPoint = 0; numPoint < points.Count - 1; numPoint++)
    {
        MyPoint point = points[numPoint];
        MyPoint nextPoint = points[numPoint + 1];
        area2 += point.x * nextPoint.y - point.y * nextPoint.x;
    }
    return area2 / 2f;
}

In 3D, given normal, the unitary normal of the polygon (which is planar):

float GetArea(List<Vector3> points, Vector3 normal)
{
    Vector3 vector = Vector3.Zero;
    for (int numPoint = 0; numPoint < points.Count - 1; numPoint++)
    {
        MyPoint point = points[numPoint];
        MyPoint nextPoint = points[numPoint + 1];
        vector += Vector3.CrossProduct(point, nextPoint);
    }
    return (1f / 2f) * Math.Abs(Vector3.DotProduct(vector, normal));
}

In the previous code I assumed you have a Vector3 struct with Add, Subtract, Multiply, CrossProduct and DotProduct operations.

In your case, you have a lattitude and longitude. Then, you are not in an 2D euclidean space. It is a spheric space where computing the area of any polygon is much more complex. However, it is locally homeomorphic to a 2D vector space (using the tangent space). Then, if the area you try to measure is not too wide (few kilometers), the above formula should work.

Now, you just have to find the normal of the polygon. To do so, and to reduce the error (because we are approximating the area), we use the normal at the centroid of the polygon. The centroid is given by:

Vector3 GetCentroid(List<Vector3> points)
{
    Vector3 vector = Vector3.Zero;
    Vector3 normal = Vector3.CrossProduct(points[0], points[1]);  // Gets the normal of the first triangle (it is used to know if the contribution of the triangle is positive or negative)
    normal = (1f / normal.Length) * normal;  // Makes the vector unitary
    float sumProjectedAreas = 0;
    for (int numPoint = 0; numPoint < points.Count - 1; numPoint++)
    {
        MyPoint point = points[numPoint];
        MyPoint nextPoint = points[numPoint + 1];
        float triangleProjectedArea = Vector3.DotProduct(Vector3.CrossProduct(point, nextPoint), normal);
        sumProjectedAreas += triangleProjectedArea;
        vector += triangleProjectedArea  * (point + nextPoint);
    }
    return (1f / (6f * sumProjectedAreas)) * vector;
}

I‘ve added a new property to Vector3 : Vector3.Length

Finally, to convert latitude and longitude into a Vector3:

Vector3 GeographicCoordinatesToPoint(float latitude, float longitude)
{
    return EarthRadius * new Vector3(Math.Cos(latitude) * Math.Cos(longitude), Math.Cos(latitude) * Math.Sin(longitude), Math.Sin(latitude));
}

To sum up:

// Converts the latitude/longitude coordinates to 3D coordinates
List<Vector3> pointsIn3D = (from point in points
                            select GeographicCoordinatesToPoint(point.Latitude, point.Longitude))
                           .ToList();

// Gets the centroid (to have the normal of the vector space)
Vector3 centroid = GetCentroid(pointsIn3D );

// As we are on a sphere, the normal at a given point is the colinear to the vector going from the center of the sphere to the point.
Vector3 normal = (1f / centroid.Length) * centroid;  // We want a unitary normal.

// Finally the area is computed using:
float area = GetArea(pointsIn3D, normal);

The Vector3 struct

public struct Vector3
{
    public static readonly Vector3 Zero = new Vector3(0, 0, 0);

    public readonly float X;
    public readonly float Y;
    public readonly float Z;

    public float Length { return Math.Sqrt(X * X + Y * Y + Z * Z); }

    public Vector3(float x, float y, float z)
    {
         X = x;
         Y = y;
         Z = z;
    }

    public static Vector3 operator +(Vector3 vector1, Vector3 vector2)
    {
        return new Vector3(vector1.X + vector2.X, vector1.Y + vector2.Y, vector1.Z + vector2.Z);
    }
    public static Vector3 operator -(Vector3 vector1, Vector3 vector2)
    {
        return new Vector3(vector1.X - vector2.X, vector1.Y - vector2.Y, vector1.Z - vector2.Z);
    }
    public static Vector3 operator *(float scalar, Vector3 vector)
    {
        return new Vector3(scalar * vector.X, scalar * vector.Y, scalar * vector.Z);
    }

    public static float DotProduct(Vector3 vector1, Vector3 vector2)
    {
        return vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;
    }
    public static Vector3 CrossProduct(Vector3 vector1, Vector3 vector2)
    {
        return return new Vector3(vector1.Y * vector2.Z - vector1.Z * vector2.Y,
                                  vector1.Z * vector2.X - vector1.X * vector2.Z,
                                  vector1.X * vector2.Y - vector1.Y * vector2.X);
    }
}

Boeykes :

I fixed it with part of the code from Cédric and code from the internet.

I fixed it by using poly.Points and poly.LocalPoints. The poly.Points are the latitude and longitude while the LocalPoints are points see to the center of the map on the screen.

the C# library has a function to calculate the distance (km) so I calculted the distance and then I calculated the distance in LocalPoints. Dived the localPoints throug the length in km and then you know how long 1 Localpoint is in km.

List<PointLatLng> firstTwoPoints = new List<PointLatLng>();
         firstTwoPoints.Add(poly.Points[0]);
         firstTwoPoints.Add(poly.Points[1]);

         GMapPolygon oneLine = new GMapPolygon(firstTwoPoints,"testesddfsdsd"); //Create new polygone from messuring the distance.
         double lengteLocalLine =
            Math.Sqrt(((poly.LocalPoints[1].X - poly.LocalPoints[0].X)*(poly.LocalPoints[1].X - poly.LocalPoints[0].X)) +
                      ((poly.LocalPoints[1].Y - poly.LocalPoints[0].Y)*(poly.LocalPoints[1].Y - poly.LocalPoints[0].Y))); //This calculates the length of the line in LocalPoints.
         double pointInKm = oneLine.Distance / lengteLocalLine; //This gives me the length of 1 LocalPoint in km.

         List<Carthesian> waarden = new List<Carthesian>(); 

//Here we fill the list "waarden" with the points.
//NOTE: the last value is NOT copied because this is handled in calculation method.
         foreach (GPoint localPoint in poly.LocalPoints)
         {
            waarden.Add(new Carthesian(){X = (localPoint.X * pointInKm), Y = (localPoint.Y * pointInKm)});
         }

         MessageBox.Show("" + GetArea(waarden)*1000000);

    }

//Method for calculating area
      private double GetArea(IList<Carthesian> points)
      {
         if (points.Count < 3)
         {
            return 0;
         }
         double area = GetDeterminant(points[points.Count - 1].X , points[points.Count - 1].Y, points[0].X, points[0].Y);

         for (int i = 1; i < points.Count; i++)
         {
            //Debug.WriteLine("Lng: " + points[i].Lng + "   Lat:" + points[i].Lat);
            area += GetDeterminant(points[i - 1].X, points[i - 1].Y , points[i].X,  points[i].Y);
         }
         return Math.Abs(area / 2);
      }

//Methode for getting the Determinant

      private double GetDeterminant(double x1, double y1, double x2, double y2)
      {
         return x1 * y2 - x2 * y1;
      }

//This class is just to make it nicer to show in code and it also was from previous tries
    class Carthesian
       {
          public double X { get; set; }
          public double Y { get; set; }
          public double Z { get; set; }
       }
Because we calculate the surface using 2D there 

Because we calculate the surface using 2D there is a small error, but for my application this is acceptable.

And thanks to Cédric for answering my question and helping me to fix the problem I had.

From :http://stackoverflow.com/questions/17775832/c-sharp-gmap-net-calculate-surface-of-polygon

时间: 2024-12-22 07:42:06

C# GMap.Net 计算多边形面积的相关文章

POJ 3907 Build Your Home | 计算多边形面积

给个多边形 计算面积 输出要四舍五入 直接用向量叉乘就好 四舍五入可以+0.5向下取整 #include<cstdio> #include<algorithm> #include<cstring> #define N 10005 #define eps 1e-8 using namespace std; struct point { double x,y; inline double operator *(const point &rhs) const { re

HDU2036 计算多边形的面积

计算多边形面积就是通过拆分三角形的方法,即为选取任意一个点,从该点出发,连接多边形的每一个顶点,这样就将多边形分为了许多个三角形.计算每一个三角形的面积即可,用叉积计算的每一个三角形的面积为"有向面积",直接将所有三角形的有向面积相加,结果的绝对值就是多边形的面积. #define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cmath> const double EPS = 1e-8; const

地球椭球面上多边形面积量算(C++代码)

昨天突然测试的时候发现以前产品中写的地球椭球面上面积计算的代码有点问题,于是今天就彻底修正,从QGIS中抠出代码来用C++重写了一下,新代码可以比较准确计算椭球面上多边形的面积,这个基础函数对空间量算功能中的面积量测非常重要,在这里共享出来供大家参考甚至直接拿过去用. 头文件如下: /** * @file DistanceArea.h * @brief 椭球面上计算多边形面积的接口文件 * @details * @author zxg * @date 2015年5月15日 * @version

多边形面积的求法

学了高数的同学,会学到向量的外积,也可知道它有一个用途,可以求三角面积. •外积的几何意义:α和β所张成的平行四边形的有向面积 •由求三角形面积的方法可以推广求凸多边形面积,如图,从一固定点出发,向其他各点引辅助线,这样就分割成了若干个三角形,利用上式求出每个三角形的面积再相加即可. 代码实现: 不过这种方法有局限性,只能求凸多边形的面积,对于凹多边形似乎就不可以了. 这里再提供一种凸凹都合适的求法,不过我也不太懂,如果哪位大神看到了,就不吝赐教一下,现在这里谢过了. •double Area(

凸包,多边形面积,线段在多边形内的判定。

zoj3570  Lott's Seal http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4569 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 const double eps=1e-8; 7 const int M=10001

多边形面积

多边形面积 多边形通常分为凸多边形和凹多边形 计算多边形面积有几种好用的算法 其核心思想都是把一个n(n>=3)边形转化为n-2个三角形,然后计算 一:海伦公式 最常见的多边形面积计算公式 此公式表达式为: S= sqrt( p*(p-a)*(p-b)*(p-c)) 其中p为此三角形的半周长,而a,b,c为三角形三边长 若三角形三点为x1,y1,x2,y2,x3,y3, 即p=(a+b+c)/2 a=sqrt((x2-x1)2+(y2-y1)2) b=sqrt((x3-x2)2+(y3-y2)2

【改革春风吹满地 HDU - 2036 】【计算几何-----利用叉积计算多边形的面积】

利用叉积计算多边形的面积 我们都知道计算三角形的面积时可以用两个邻边对应向量积(叉积)的绝对值的一半表示,那么同样,对于多边形,我们可以以多边形上的一个点为源点,作过该点并且过多边形其他点中的某一个的多条射线,这样就可以把该多边形变为多个三角形,然后利用叉积求面积即可. 不过要注意,对于三角形可以简单的用叉积的绝对值的一半表示,但对于多边形不可随意将它分割成的几个三角形对应的叉积的绝对值相加,要有一定顺序才可. 对于三角形,有 [该图片来源:https://www.cnblogs.com/xie

poj 1654 Area(求多边形面积)

题意:从原点出发向八个方向走,所给数字串每个数字代表一个方向,终点与原点连线,求所得多边形面积: 思路:(性质)共起点的两向量叉积的一半为两向量围成三角形的面积.以此计算每条边首尾两个向量的叉积,求和,除二: #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const dou

HDU 3060 多边形面积并

Area2 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1197    Accepted Submission(s): 278 Problem Description 小白近期又被空军特招为飞行员,參与一项实战演习.演习的内容还是轰炸某个岛屿(这次的岛屿非常大,非常大非常大非常大,大到炸弹怎么扔都能全然在岛屿上引爆),看来小白确实是