有点晚了,但是您可以计算法线,然后查看沿法线轴的平均值是顺时针还是逆时针围绕法线或曲面的任何单个点。第二种方法你要跟踪的点少了,但基本上是一样的。
- 计算曲面的中心点(坐标总和除以坐标计数);
- 从表面点中减去中心点;
- 按表面法线旋转表面点;
** 您现在只处理 2 轴,因为 z 将始终为零;
- 对相对角度求和 (sum(atan(p[i] - p[0]) for i in (1,2)))
- 如果为正,则为顺时针。
一些代码...
from math import sqrt, atan2, pi
twopi = 2 * pi
dists = lambda s: sqrt(sum(c*c for c in s))
import numpy as np
trans_y_mat = lambda dx, dz: np.array(((dz,0,dx),(0,1,0),(-dx,0,dz)) \
, dtype=np.float64)
def p3d_normal(p3d):
Ux, Uy, Uz = (p3d[1][i] - p3d[0][i] for i in (0,1,2))
Vx, Vy, Vz = (p3d[2][i] - p3d[0][i] for i in (0,1,2))
N = (Uy*Vz - Uz*Vy, Uz*Vx - Ux*Vz, Ux*Vy - Uy*Vx)
d = dists(N)
return tuple(c / d for c in N)
def p3d_is_clockwise(p3d, p3n=None):
if p3n is None: p3n = p3d_normal(p3d)
dnx, dnz = p3n[0]/p3n[1], p3n[2]/p3n[1]
dn = dists((dnz, dnx))
mn = trans_y_mat(dnz/dn, dnx/dn)
p2d = np.matmul(mn, p3d)[:,:2]
asum = 0.0
xp,yp = p2d[0]
ap = 0.0
for (xn,yn) in p2d[1:]:
an = atan2(yn-yp, xn-xp)
asum += (an - ap + pi) % twopi - pi
xp, yp, an = xn, yp, ap
return asum >= 0
faces = (((0.0, 0.0, 100.0), (30.9017, 0.0, 95.1057), (15.4508, 26.7617, 95.1057)) \
, ((0.0, 0.0, 100.0), (15.4508, 26.7617, 95.1057), (-15.4508, 26.7617, 95.1057)) \
, ((0.0, 0.0, 100.0), (-15.4508, 26.7617, 95.1057), (-30.9017, 0.0, 95.1057)) \
, ((0.0, 0.0, 100.0), (-30.9017, 0.0, 95.1057), (-15.4508, -26.7617, 95.1057)) \
, ((0.0, 0.0, 100.0), (-15.4508, -26.7617, 95.1057), (15.4508, -26.7617, 95.1057)) \
, ((0.0, 0.0, 100.0), (15.4508, -26.7617, 95.1057), (30.9017, -0.0, 95.1057)) \
, ((30.9017, 0.0, 95.1057), (50.9037, 29.3893, 80.9017), (58.7785, 0.0, 80.9017)) \
, ((30.9017, 0.0, 95.1057), (15.4508, 26.7617, 95.1057), (50.9037, 29.3893, 80.9017)) \
, ((15.4508, 26.7617, 95.1057), (29.3893, 50.9037, 80.9017), (50.9037, 29.3893, 80.9017)) \
, ((15.4508, 26.7617, 95.1057), (0.0, 58.7785, 80.9017), (29.3893, 50.9037, 80.9017)))
for face in faces:
print(p3d_is_clockwise(face))
输出:
False
False
True
False
False
False
False
False
True
True