C# 如何计算质心
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9815699/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Calculate Centroid
提问by peter
I am working with geospatial shapes and looking at the centroid algorithm here,
我正在处理地理空间形状并在这里查看质心算法,
http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
I have implemented the code in C# like this (which is just this adapted),
我已经在 C# 中实现了这样的代码(就是这样改编的),
Finding the centroid of a polygon?
class Program
{
static void Main(string[] args)
{
List<Point> vertices = new List<Point>();
vertices.Add(new Point() { X = 1, Y = 1 });
vertices.Add(new Point() { X = 1, Y = 10 });
vertices.Add(new Point() { X = 2, Y = 10 });
vertices.Add(new Point() { X = 2, Y = 2 });
vertices.Add(new Point() { X = 10, Y = 2 });
vertices.Add(new Point() { X = 10, Y = 1 });
vertices.Add(new Point() { X = 1, Y = 1 });
Point centroid = Compute2DPolygonCentroid(vertices);
}
static Point Compute2DPolygonCentroid(List<Point> vertices)
{
Point centroid = new Point() { X = 0.0, Y = 0.0 };
double signedArea = 0.0;
double x0 = 0.0; // Current vertex X
double y0 = 0.0; // Current vertex Y
double x1 = 0.0; // Next vertex X
double y1 = 0.0; // Next vertex Y
double a = 0.0; // Partial signed area
// For all vertices except last
int i=0;
for (i = 0; i < vertices.Count - 1; ++i)
{
x0 = vertices[i].X;
y0 = vertices[i].Y;
x1 = vertices[i+1].X;
y1 = vertices[i+1].Y;
a = x0*y1 - x1*y0;
signedArea += a;
centroid.X += (x0 + x1)*a;
centroid.Y += (y0 + y1)*a;
}
// Do last vertex
x0 = vertices[i].X;
y0 = vertices[i].Y;
x1 = vertices[0].X;
y1 = vertices[0].Y;
a = x0*y1 - x1*y0;
signedArea += a;
centroid.X += (x0 + x1)*a;
centroid.Y += (y0 + y1)*a;
signedArea *= 0.5;
centroid.X /= (6*signedArea);
centroid.Y /= (6*signedArea);
return centroid;
}
}
public class Point
{
public double X { get; set; }
public double Y { get; set; }
}
The problem is that this algorithm when I have this shape (which is an L shape),
问题是当我有这个形状(这是一个 L 形状)时,这个算法,
(1,1) (1,10) (2,10) (2,2) (10,2) (10,1) (1,1)
(1,1) (1,10) (2,10) (2,2) (10,2) (10,1) (1,1)
It gives me the result (3.62, 3.62). Which is OK, except that point is outside the shape. Is there another algorithm around that takes this into account?
它给了我结果 (3.62, 3.62)。没关系,除了那个点在形状之外。是否有另一种算法考虑到这一点?
Basically a person is going to be drawing a shape on a map. This shape might span multiple roads (so could be an L shape) and I want to work out the centre of the shape. This is so I can work out the road name at that point. It doesn't make sense to me for it to be outside the shape if they have drawn a long skinny L shape.
基本上,一个人将在地图上绘制一个形状。这个形状可能跨越多条道路(所以可能是 L 形),我想计算出形状的中心。这样我就可以在那时算出道路名称。如果他们画了一个细长的 L 形,那么它在形状之外对我来说没有意义。
回答by ITmeze
You may check if .NET 4.5 DbSpatialServices functions, like DbSpatialServices.GetCentroid
您可以检查 .NET 4.5 DbSpatialServices 函数,如DbSpatialServices.GetCentroid
回答by Jer2654
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 );
}
回答by RenniePet
This answer is inspired by the answer by Jer2654 and this source: http://coding-experiments.blogspot.com/2009/09/xna-quest-for-centroid-of-polygon.html
这个答案的灵感来自 Jer2654 的答案和这个来源:http://coding-experiments.blogspot.com/2009/09/xna-quest-for-centroid-of-polygon.html
/// <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);
}

