python中检测任意形状内外角的最佳算法
我一直在使用python 3.2.5开发一个二维对象创建程序,该程序处理任意形状的操作,并计算它们之间的碰撞检测。该程序允许您输入一个形状的坐标,从那里它将执行您希望它执行的任何其他操作(将形状绘制到屏幕上,扩展边框,操纵单个坐标,使其对称,等等) 但是我在计算任意多边形的内角时遇到了一个问题。虽然我使用算法计算角度,技术上输出正确的角度,但我无法判断程序是否输出内角或外角(因为用户输入的任意形状可能有凹面顶点) 从纸面上看,这似乎是小菜一碟,因为你可以想象形状,你可以自动解释哪个角度是内部和外部。但是,由于程序只存储坐标值,实际上并没有直观地创建对象来外推数据,所以解决这个问题变得有点棘手 所以我的问题是: 我应该使用什么方法来计算两条线之间的角度,以及如何使用它来确定内角和外角之间的差异python中检测任意形状内外角的最佳算法,python,algorithm,geometry,Python,Algorithm,Geometry,我一直在使用python 3.2.5开发一个二维对象创建程序,该程序处理任意形状的操作,并计算它们之间的碰撞检测。该程序允许您输入一个形状的坐标,从那里它将执行您希望它执行的任何其他操作(将形状绘制到屏幕上,扩展边框,操纵单个坐标,使其对称,等等) 但是我在计算任意多边形的内角时遇到了一个问题。虽然我使用算法计算角度,技术上输出正确的角度,但我无法判断程序是否输出内角或外角(因为用户输入的任意形状可能有凹面顶点) 从纸面上看,这似乎是小菜一碟,因为你可以想象形状,你可以自动解释哪个角度是内部和外
例如,如果我有一个形状有坐标((30,50),(35,47),(40,50),(37,43),(35,35),(33,43))(最终看起来有点像一个有凹底的倒置尖顶),我可以很容易地计算线之间的角度,但我计算的角度是个谜。我不知道你尝试过什么算法,但是,通常通过以相同的顺序(例如,顺时针)存储点列表来解决此问题,这样每次按顺序在三个点上运行角度计算时,都会得到形状的同一侧(例如,内角) 有一个简单的算法来检查多边形内部是否存在点。他还很好地描述了它的工作原理。下面是用C编写的,但是可以很容易地转换为python
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
int-pnpoly(int-nvert,float*vertx,float*verty,float-testx,float-testy)
{
int i,j,c=0;
对于(i=0,j=nvert-1;itesty)!=(verty[j]>testy))&&
(testx<(vertx[j]-vertx[i])*(testy-verty[i])/(verty[j]-verty[i])+vertx[i]))
c=!c;
}
返回c;
}
无论如何,您可以使用此算法通过对照没有测试顶点的多边形来检查顶点是凹的还是凸的
所以如果你有一个顶点为a,b,c,d的四边形,你想看看b是凸的还是凹的,你可以测试b是否在三角形a,c,d内。如果它在里面,它是凸的,如果不是凹的,如果两者都不是顶点
如果知道它是凸面还是凹面,您应该能够解析出哪个是内角,哪个是外角。正如Jesse所建议的,您首先需要以某种顺序保留顶点列表。我建议逆时针方向。使用点积找到十字积的角度和符号,告诉你它在哪一边。按逆时针顺序存储时,内角为正
# Its a square with the top edge poked in
points = [
( 1.0, 1.0),
( 0.0, 0.0),
(-1.0, 1.0),
(-1.0, -1.0),
( 1.0, -1.0)]
def angle(x1, y1, x2, y2):
# Use dotproduct to find angle between vectors
# This always returns an angle between 0, pi
numer = (x1 * x2 + y1 * y2)
denom = sqrt((x1 ** 2 + y1 ** 2) * (x2 ** 2 + y2 ** 2))
return acos(numer / denom)
def cross_sign(x1, y1, x2, y2):
# True if cross is positive
# False if negative or zero
return x1 * y2 > x2 * y1
for i in range(len(points)):
p1 = points[i]
ref = points[i - 1]
p2 = points[i - 2]
x1, y1 = p1[0] - ref[0], p1[1] - ref[1]
x2, y2 = p2[0] - ref[0], p2[1] - ref[1]
print('Points', p1, ref, p2)
print('Angle', angle(x1, y1, x2, y2))
if cross_sign(x1, y1, x2, y2):
print('Inner Angle')
else:
print('Outer Angle')
print('')
求两个向量之间有符号角的黄金标准是
atan2(交叉(a,b)),dot(a,b))
。高精度和鲁棒性在所有角度。(在2D中,cross
是垂直点积,ax*by ay*bx
。在三维中,使用十字积的长度;其方向是旋转轴。)
有些事情不能做:
- 任何涉及
的内容。反余弦是一种代码气味。它的范围有限,不会给你符号,需要手动参数钳制,并且在极限时精度很差。如果你发现自己在使用它,试试别的acos
- 任何涉及坡度的东西。精度差,当然,垂直向量的精度未定义
- 根据额外测试手动选择角度范围。这可能导致轴附近出现不连续