如何计算质心

我正在使用地理空间形状并在这里查看质心算法,

http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon

我已经在C#中实现了这样的代码(这只是这个改编),

找到多边形的质心?

class Program { static void Main(string[] args) { List vertices = new List(); 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 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; } } 

问题是这个算法,当我有这个形状(这是一个L形),

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

它给了我结果(3.62,3.62)。 哪个是好的,除了那个点在形状之外。 还有其他算法考虑到这一点吗?

基本上,一个人将在地图上绘制一个形状。 这个形状可能跨越多条道路(因此可能是L形),我想弄清楚形状的中心。 这样我就可以在那时找出道路名称。 如果它们画出一个长的瘦L形状,那么它在形状之外是没有意义的。

我建议不要自己编写,而是使用SharpMap

http://sharpmap.codeplex.com/

他们做了很好的工作,给你的质心(甚至必须在里面)以及你想要的更多function。

这个答案的灵感来自于Jer2654及其来源的答案: http ://coding-experiments.blogspot.com/2009/09/xna-quest-for-centroid-of-polygon.html

  ///  /// Method to compute the centroid of a polygon. This does NOT work for a complex polygon. ///  /// points that define the polygon /// centroid point, or PointF.Empty if something wrong public static PointF GetCentroid(List 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); } 

您可以检查.NET 4.5 DbSpatialServices是否起作用,如DbSpatialServices.GetCentroid

 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 = aY * bX - aX * bY; area += k; x += ( aX + bX ) * k; y += ( aY + bY ) * k; b = a; } area *= 3; return ( area == 0 ) ? Point.Empty : new Point( x /= area, y /= area ); }