我正在尝试计算平面多边形的中心,想知道最好的方法是什么。
我可以访问构成多边形的顶点,但没有其他信息。
有人有任何建议吗?
谢谢。
我不会将其投影到二维平面。
将所有顶点的坐标相加,然后除以顶点数。 参见有限点集的质心。
sx = sy = sz = 0
for i in 1..n:
sx = sx + px[i]
sy = sy + py[i]
sz = sz + pz[i]
cx = sx/n
cy = sy/n
cz = sz/n
将所有边缘的质心按其长度加权求和,然后除以总周长。
sx = sy = sz = slen = 0
x1 = px[n]
y1 = py[n]
z1 = pz[n]
for i in 1..n:
x2 = px[i]
y2 = py[i]
z2 = pz[i]
dx = x2 - x1
dy = y2 - y1
dz = z2 - z1
len = sqrt(dx*dx + dy*dy + dz*dz)
sx = sx + (x1 + x2)/2*len
sy = sy + (y1 + y2)/2*len
sz = sz + (z1 + z2)/2*len
slen = slen + len
x1 = x2
y1 = y2
z1 = z2
cx = sx/slen
cy = sy/slen
cz = sz/slen
将多边形三角剖分,然后按其面积加权求出所有三角形的重心之和,再除以总面积。您可以选择一种剖分方式,使得并非所有三角形都完全在多边形内部,只要通过不同方向的三角形来补偿外部区域即可。一个三角形的面积等于两个边向量的叉积的一半。
有关二维情况,请参见多边形的重心,但更合适的是使用面积的几何分解法。此外,三角形的重心说明了曲面的重心等于其顶点的重心。
sx = sy = sz = sarea = 0
x1 = px[1]
y1 = py[1]
z1 = pz[1]
for i in 3..n:
x2 = px[i-1]
y2 = py[i-1]
z2 = pz[i-1]
x3 = px[i]
y3 = py[i]
z3 = pz[i]
dx1 = x3 - x1
dy1 = y3 - y1
dz1 = z3 - z1
dx2 = x3 - x2
dy2 = y3 - y2
dz2 = z3 - z2
cpx = dy1*dz2 - dz1*dy2
cpy = dz1*dx2 - dx1*dz2
cpz = dx1*dy2 - dy1*dx2
area = sqrt(cpx*cpx + cpy*cpy + cpz*cpz)/2
sx = sx + (x1 + x2 + x3)/3*area
sy = sy + (y1 + y2 + y3)/3*area
sz = sz + (z1 + z2 + z3)/3*area
sarea = sarea + area
cx = sx/sarea
cy = sy/sarea
cz = sz/sarea
px,py,pz
是坐标数组。使用基于 1 或基于 0 的索引取决于你的编程语言,但既然你问了,你可能想从 0 开始。并且使用 [n-1]
而不是 [n]
来访问边界循环之前的最后一个点。我的答案一直使用基于 1 的伪代码编写,因为大多数数学公式都是基于 1 表示的。 - MvG public Point3D CalculateCentroid(List<Point3D> verticies)
{
var s = new Vector3D();
var areaTotal = 0.0;
var p1 = verticies[0];
var p2 = verticies[1];
for (var i = 2; i < verticies.Count; i++)
{
var p3 = verticies[i];
var edge1 = p3 - p1;
var edge2 = p3 - p2;
var crossProduct = Vector3D.CrossProduct(edge1, edge2);
var area = crossProduct.Length/2;
s.X += area * (p1.X + p2.X + p3.X)/3;
s.Y += area * (p1.Y + p2.Y + p3.Y)/3;
s.Z += area * (p1.Z + p2.Z + p3.Z)/3;
areaTotal += area;
p2 = p3;
}
var point = new Point3D
{
X = s.X/areaTotal,
Y = s.Y/areaTotal,
Z = s.Z/areaTotal
};
return point;
}