具有边缘情况的整数绕数算法
我想要一个闭合的分段线性路径(例如多边形)的缠绕数一个点,但除此之外,我想检测路径何时经过该点。因此,我将标准缠绕数加倍。对于 CCW 方向的非相交多边形,该值将为:
- 如果点在多边形外部,则为 0
- 如果点在多边形的边或顶点上,则为 1 如果
- 点在多边形内部
,则值为 2其他情况。 (编辑:一些示例的图像)
当点打开时,我发现的每个算法都会失败边或顶点。
我的另一个要求是,当所有输入(即点的坐标和路径的顶点)都是整数时,它必须给出完全正确的结果。因此,这几乎排除了三角函数或平方根,并且必须小心使用除法。
我不需要需要处理具有两个连续重合点或 180 度转弯的简并路径。
无论如何,我想我有一个解决方案。然而,这似乎有点不优雅,而且我不确定它是否正确。 (我真的很困惑当点在顶点上时会发生什么。)这是用 python 编写的:
def orient((x,y), (a0,b0), (a1,b1)):
return cmp((a1-a0)*y + (b0-b1)*x + a0*b1-a1*b0, 0)
def windingnumber(p0, ps):
w, h = 0, [cmp(p, p0) for p in ps]
for j in range(len(ps)):
i, k = (j-1)%len(ps), (j+1)%len(ps)
if h[j] * h[k] == -1:
w += orient(p0, ps[j], ps[k])
elif h[j] == 0 and h[i] == h[k]:
w += orient(ps[k], ps[i], ps[j])
return w
我想要一个正确算法的链接,或者我的算法是否正确的一些确认,或者我的算法失败的测试用例。谢谢!
I want the winding number of a closed, piecewise-linear path (eg a polygon) about a point, but in addition, I want to detect when the path passes through the point. For this reason, I double the standard winding number. For a non-intersecting polygon with CCW orientation, the value will be:
- 0 if the point is outside the polygon
- 1 if the point is on an edge or vertex of the polygon
- 2 if the point is in the interior of the polygon
And similarly in other cases. (EDIT: image of a few examples)
Every algorithm I've found fails when the point is on an edge or vertex.
My other requirement is that it has to give exactly correct results when all of the inputs (ie, the coordinates of the point and the vertices of the path) are integers. So this pretty much precludes trig functions or square roots, and division would have to be used carefully.
I do not need to handle degenerate paths that have two consecutive coincident points, or a 180-degree turn.
Anyway, I think I have a solution. However, it seems a bit inelegant, and I'm not confident that it's correct. (I really confused myself about what happens when the point is on a vertex.) Here it is in python:
def orient((x,y), (a0,b0), (a1,b1)):
return cmp((a1-a0)*y + (b0-b1)*x + a0*b1-a1*b0, 0)
def windingnumber(p0, ps):
w, h = 0, [cmp(p, p0) for p in ps]
for j in range(len(ps)):
i, k = (j-1)%len(ps), (j+1)%len(ps)
if h[j] * h[k] == -1:
w += orient(p0, ps[j], ps[k])
elif h[j] == 0 and h[i] == h[k]:
w += orient(ps[k], ps[i], ps[j])
return w
Link to a version with comments and unit tests.
I would like a link to a correct algorithm, or some confirmation that my algorithm is correct, or a test case where my algorithm fails. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是你的假设是错误的。
没有为轮廓上的点定义绕数。 (特别是积分没有明确定义)。
如果你沿着同一条路径走两次,你会得到两倍的缠绕数。因此,如果您假设如果该点位于计数上,则该数字将为 1,那么这实际上意味着如果您走一次,则绕数为 1/2,但这显然是错误的,因为绕数总是一个整数。
The problem is that your assumption is wrong.
The winding number is not defined for points on the contour. (The integral is not well defined, in particular).
If you follow the same path twice you get twice the winding number. So if your assumption that the number will be 1 if the point is on the countour were true, then that would actually imply that the winding number if you go once is 1/2, but this is clearly wrong, because the winding number is always an integer.