所以我有一些函数接收N个随机2D
点。
是否有算法计算输入点定义的形状区域?
答案 0 :(得分:28)
您想要calculate the area of a polygon?
(取自链接,转换为C#)
class Point { double x, y; }
double PolygonArea(Point[] polygon)
{
int i,j;
double area = 0;
for (i=0; i < polygon.Length; i++) {
j = (i + 1) % polygon.Length;
area += polygon[i].x * polygon[j].y;
area -= polygon[i].y * polygon[j].x;
}
area /= 2;
return (area < 0 ? -area : area);
}
答案 1 :(得分:1)
定义点集合的“区域”可能很难,例如如果你想获得包含你的集合的直线边界的最小区域,那么我不知道如何继续。可能你想要做的是计算你的点集的凸包的面积;这是一个标准问题,Steven Skiena在Stony Brook Algorithms repository给出了解决方案实现链接问题的描述。从那里计算面积的一种方法(在我看来显而易见的方法)是对区域进行三角测量并计算每个三角形的面积。
答案 2 :(得分:1)
你可以使用Timothy Chan的算法在nlogh中找到凸包,其中n是点数,h是凸包顶点的数量。如果您想要一个简单的算法,请选择格雷厄姆扫描。
另外,如果您知道您的数据是按照简单的链排序的,那么点不会相互交叉,您可以使用Melkman的算法来计算O(N)中的凸包。
此外,凸壳的另一个有趣特性是,它具有最小周长。
答案 3 :(得分:0)
您的问题并不直接暗示存在现成的多边形(由this answer假设)。我建议使用三角测量法,例如Delaunay Triangulation,然后平凡地计算每个三角形的面积。 OpenCV(我已经将它用于大量的2D点并且它非常有效)并且CGAL提供了用于确定三角测量的出色实现。
答案 4 :(得分:0)
我发现了另一个function written in Java,所以我将其转换为C#
public static double area(List<Double> lats,List<Double> lons)
{
double sum=0;
double prevcolat=0;
double prevaz=0;
double colat0=0;
double az0=0;
for (int i=0;i<lats.Count;i++)
{
double colat=2*Math.Atan2(Math.Sqrt(Math.Pow(Math.Sin(lats[i]*Math.PI/180/2), 2)+ Math.Cos(lats[i]*Math.PI/180)*Math.Pow(Math.Sin(lons[i]*Math.PI/180/2), 2)),
Math.Sqrt(1- Math.Pow(Math.Sin(lats[i]*Math.PI/180/2), 2)- Math.Cos(lats[i]*Math.PI/180)*Math.Pow(Math.Sin(lons[i]*Math.PI/180/2), 2)));
double az=0;
if (lats[i]>=90)
{
az=0;
}
else if (lats[i]<=-90)
{
az=Math.PI;
}
else
{
az=Math.Atan2(Math.Cos(lats[i]*Math.PI/180) * Math.Sin(lons[i]*Math.PI/180),Math.Sin(lats[i]*Math.PI/180))% (2*Math.PI);
}
if(i==0)
{
colat0=colat;
az0=az;
}
if(i>0 && i<lats.Count)
{
sum=sum+(1-Math.Cos(prevcolat + (colat-prevcolat)/2))*Math.PI*((Math.Abs(az-prevaz)/Math.PI)-2*Math.Ceiling(((Math.Abs(az-prevaz)/Math.PI)-1)/2))* Math.Sign(az-prevaz);
}
prevcolat=colat;
prevaz=az;
}
sum=sum+(1-Math.Cos(prevcolat + (colat0-prevcolat)/2))*(az0-prevaz);
return 5.10072E14* Math.Min(Math.Abs(sum)/4/Math.PI,1-Math.Abs(sum)/4/Math.PI);
}