Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中检测任意形状内外角的最佳算法_Python_Algorithm_Geometry - Fatal编程技术网

python中检测任意形状内外角的最佳算法

python中检测任意形状内外角的最佳算法,python,algorithm,geometry,Python,Algorithm,Geometry,我一直在使用python 3.2.5开发一个二维对象创建程序,该程序处理任意形状的操作,并计算它们之间的碰撞检测。该程序允许您输入一个形状的坐标,从那里它将执行您希望它执行的任何其他操作(将形状绘制到屏幕上,扩展边框,操纵单个坐标,使其对称,等等) 但是我在计算任意多边形的内角时遇到了一个问题。虽然我使用算法计算角度,技术上输出正确的角度,但我无法判断程序是否输出内角或外角(因为用户输入的任意形状可能有凹面顶点) 从纸面上看,这似乎是小菜一碟,因为你可以想象形状,你可以自动解释哪个角度是内部和外

我一直在使用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
    的内容。反余弦是一种代码气味。它的范围有限,不会给你符号,需要手动参数钳制,并且在极限时精度很差。如果你发现自己在使用它,试试别的
  • 任何涉及坡度的东西。精度差,当然,垂直向量的精度未定义
  • 根据额外测试手动选择角度范围。这可能导致轴附近出现不连续

我尝试使用一种算法计算两条相邻直线的坡度,以计算它们相交时的角度。然后,计算变成math.atan((slope1-slope2)/(1+slope1*slope2)),它将吐出角度。它从哪个角度吐出来我不完全确定。我想知道我是否应该进行计算,找出哪个斜率更大,然后从分子中的大斜率中减去小斜率,但从我研究的结果来看,这是行不通的。啊!在这种情况下,您需要atan2,因为atan没有足够的信息为您提供右符号角度。您知道如何检查两条线是左转还是右转吗?这是格雷厄姆扫描的例子,我猜你遇到了困难,因为你的多边形不是规则的,可以是凸的。我试着画出你给出的点,比如,A=(35,35)B=(33,43)C=(30,50)D=(40,50)E=(35,47)F=(37,43)我们可以把ABCDEF,ABCEDF和ABECDF构造成多边形。在每个多边形中都有大于180度的内角。@kalhartt建议的方法可能是最好的?