C# 如何计算质心

C# 如何计算质心,c#,geospatial,centroid,C#,Geospatial,Centroid,我正在研究地理空间形状,并研究质心算法 我已经用C语言实现了代码,就像这样(就是这样改编的) 类程序 { 静态void Main(字符串[]参数) { 列表顶点=新列表(); Add(新点(){X=1,Y=1}); 添加(新点(){X=1,Y=10}); 添加(新点(){X=2,Y=10}); Add(新点(){X=2,Y=2}); 添加(新点(){X=10,Y=2}); 添加(新点(){X=10,Y=1}); Add(新点(){X=1,Y=1}); 点质心=计算二维多边形质心(顶点); }

我正在研究地理空间形状,并研究质心算法

我已经用C语言实现了代码,就像这样(就是这样改编的)

类程序
{
静态void Main(字符串[]参数)
{
列表顶点=新列表();
Add(新点(){X=1,Y=1});
添加(新点(){X=1,Y=10});
添加(新点(){X=2,Y=10});
Add(新点(){X=2,Y=2});
添加(新点(){X=10,Y=2});
添加(新点(){X=10,Y=1});
Add(新点(){X=1,Y=1});
点质心=计算二维多边形质心(顶点);
}
静态点计算2dPolygonCentRoid(列出顶点)
{
点形心=新点(){X=0.0,Y=0.0};
双签名面积=0.0;
double x0=0.0;//当前顶点X
双y0=0.0;//当前顶点Y
双x1=0.0;//下一个顶点X
双y1=0.0;//下一个顶点Y
双a=0.0;//部分有符号区域
//对于除最后一个顶点以外的所有顶点
int i=0;
对于(i=0;i<顶点计数-1;++i)
{
x0=顶点[i].X;
y0=顶点[i].Y;
x1=顶点[i+1].X;
y1=顶点[i+1].Y;
a=x0*y1-x1*y0;
签名区域+=a;
质心X+=(x0+x1)*a;
质心Y+=(y0+y1)*a;
}
//做最后一个顶点
x0=顶点[i].X;
y0=顶点[i].Y;
x1=顶点[0].X;
y1=顶点[0].Y;
a=x0*y1-x1*y0;
签名区域+=a;
质心X+=(x0+x1)*a;
质心Y+=(y0+y1)*a;
签名面积*=0.5;
质心.X/=(6*signedArea);
质心Y/=(6*signedArea);
返回质心;
}
}
公共课点
{
公共双X{get;set;}
公共双Y{get;set;}
}
问题是,当我有这个形状(是L形)时,这个算法

(1,1)(1,10)(2,10)(2,2)(10,2)(10,1)(1,1)

它给出了结果(3.62,3.62)。这是可以的,除了点在形状之外。有没有其他算法考虑到这一点


基本上,一个人要在地图上画一个形状。这个形状可能跨越多条道路(所以可能是L形),我想计算出形状的中心。这样我就可以计算出当时的道路名称。如果他们绘制了一个长而瘦的L形,那么它在形状之外对我来说没有意义。

您可以检查.NET 4.5 DbSpatialServices函数,如

公共静态点GetCentroid(点[]节点,int计数)
{
int x=0,y=0,面积=0,k;
点a,b=节点[计数-1];
for(int i=0;i
此答案的灵感来源于Jer2654的答案和以下来源:

//
///方法计算多边形的质心。这不适用于复杂多边形。
/// 
///定义多边形的点
///质心点,或点F。如果出现问题,则为空
公共静态点F GetCentroid(列表多边形)
{
浮动累计面积=0.0f;
浮动中心X=0.0f;
浮动中心Y=0.0f;
对于(int i=0,j=poly.Count-1;i
对于3d点,我用C语言创建了一种方法,希望我能帮助您:

public static double[] GetCentroid(List<double[]> listOfPoints)
    {
        // centroid[0] = X
        // centroid[1] = Y
        // centroid[2] = Z
        double[] centroid = new double[3];

        // List iteration
        // Link reference:
        // https://en.wikipedia.org/wiki/Centroid
        foreach (double[] point in listOfPoints)
        {
            centroid[0] += point[0];
            centroid[1] += point[1];
            centroid[2] += point[2];
        }

        centroid[0] /= listOfPoints.Count;
        centroid[1] /= listOfPoints.Count;
        centroid[2] /= listOfPoints.Count;

        return centroid;
    }
publicstaticdouble[]GetCentroid(点列表)
{
//质心[0]=X
//质心[1]=Y
//质心[2]=Z
双[]质心=新双[3];
//列表迭代
//链接参考:
// https://en.wikipedia.org/wiki/Centroid
foreach(点列表中的双[]点)
{
质心[0]+=点[0];
质心[1]+=点[1];
质心[2]+=点[2];
}
质心[0]/=listOfPoints.Count;
质心[1]/=listOfPoints.Count;
质心[2]/=listOfPoints.Count;
返回质心;
}

多边形的质心不必在其内部。这只保证适用于凸多边形。是的,算法是正确的,我同意,但是否有其他算法可以确保计算多边形内的点?理想情况下,上述形状的结果是(1.5,1.5)。如果对您的问题有意义,您可以将道路表示为粗线,甚至是并集或矩形(通过引入轴的概念)。您的中心是该轴的中点。不要使用点来查找道路名称。无法保证该点距离正在勾勒的道路足够近。正确的做法是检索该区域的道路线段,并找出多边形中长度最大的道路。看起来这是基于与此处使用的相同算法:if(Math.Abs(acgregatedrea)<1E-7f)@Koray谢谢!我不太明白这样做的必要性,但我认为你是对的,我已经在我的回答中包括了你的建议——在我自己使用的这段代码中,也是我在Android应用程序中使用的Java版本。你的代码工作得很好,但是如果某些坐标为负,这是必需的。如果保证每个坐标都是正的,
public static Point GetCentroid( Point[ ] nodes, int count )
{
    int x = 0, y = 0, area = 0, k;
    Point a, b = nodes[ count - 1 ];

    for( int i = 0; i < count; i++ )
    {
        a = nodes[ i ];

        k = a.Y * b.X - a.X * b.Y;
        area += k;
        x += ( a.X + b.X ) * k;
        y += ( a.Y + b.Y ) * k;

        b = a;
    }
    area *= 3;

    return ( area == 0 ) ? Point.Empty : new Point( x /= area, y /= area );
}
  /// <summary>
  /// Method to compute the centroid of a polygon. This does NOT work for a complex polygon.
  /// </summary>
  /// <param name="poly">points that define the polygon</param>
  /// <returns>centroid point, or PointF.Empty if something wrong</returns>
  public static PointF GetCentroid(List<PointF> poly)
  {
     float accumulatedArea = 0.0f;
     float centerX = 0.0f;
     float centerY = 0.0f;

     for (int i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
     {
        float temp = poly[i].X * poly[j].Y - poly[j].X * poly[i].Y;
        accumulatedArea += temp;
        centerX += (poly[i].X + poly[j].X) * temp;
        centerY += (poly[i].Y + poly[j].Y) * temp;
     }

     if (Math.Abs(accumulatedArea) < 1E-7f)
        return PointF.Empty;  // Avoid division by zero

     accumulatedArea *= 3f;
     return new PointF(centerX / accumulatedArea, centerY / accumulatedArea);
  }
public static double[] GetCentroid(List<double[]> listOfPoints)
    {
        // centroid[0] = X
        // centroid[1] = Y
        // centroid[2] = Z
        double[] centroid = new double[3];

        // List iteration
        // Link reference:
        // https://en.wikipedia.org/wiki/Centroid
        foreach (double[] point in listOfPoints)
        {
            centroid[0] += point[0];
            centroid[1] += point[1];
            centroid[2] += point[2];
        }

        centroid[0] /= listOfPoints.Count;
        centroid[1] /= listOfPoints.Count;
        centroid[2] /= listOfPoints.Count;

        return centroid;
    }