Python 什么';Forster Overfelt的伪代码有什么问题;Greiner-Horman多边形裁剪算法的s版本? 问题
我试图理解并实现Greiner-Horman多边形裁剪算法的功能。我读过关于澄清这个算法的文章,但我似乎仍然无法让它发挥作用 我知道有点不对劲,因为它产生了两个多边形的错误交点,即使是一个没有退化的简单示例:Python 什么';Forster Overfelt的伪代码有什么问题;Greiner-Horman多边形裁剪算法的s版本? 问题,python,algorithm,polygon,computational-geometry,clipping,Python,Algorithm,Polygon,Computational Geometry,Clipping,我试图理解并实现Greiner-Horman多边形裁剪算法的功能。我读过关于澄清这个算法的文章,但我似乎仍然无法让它发挥作用 我知道有点不对劲,因为它产生了两个多边形的错误交点,即使是一个没有退化的简单示例: subjpoly = [(0,0),(6,0),(6,6),(0,6),(0,0)] clippoly = [(1,4),(3,8),(5,4),(5,10),(1,10),(1,4)] 这将生成以下各项的交点: [ [(5.0, 6.0), (4.0, 6.0), (5, 4), (5
subjpoly = [(0,0),(6,0),(6,6),(0,6),(0,0)]
clippoly = [(1,4),(3,8),(5,4),(5,10),(1,10),(1,4)]
这将生成以下各项的交点:
[ [(5.0, 6.0), (4.0, 6.0), (5, 4), (5.0, 6.0)],
[(1.0, 6.0), (2.0, 6.0), (4.0, 6.0)] ]
可视化结果如下所示:
所以这个问题不是关于一段特定的代码或语言语法,而是关于理解算法并将其转化为伪代码。提前谢谢
算法
这里介绍的算法是直接基于Forster Oberfelt论文第4.2节中描述的算法,但显然我遗漏了一些错误的结果
第1部分:
首先循环SUBK和clip,并将每个顶点位置标记为另一个多边形的“in”、“out”或“on”
for s in subj.iter():
s.loc = testLocation(s, clip)
for c in clip.iter():
c.loc = testLocation(c, subj)
第2部分:
继续循环子多边形的交点
for s in subj.iter():
if s.intersect:
第2.1子部分:
通过取消将每个子交叉点标记为交叉点或将其标记为入口或出口来处理每个子交叉点,并对相邻交叉点执行相同操作。注意:本文中介绍的算法只解释了如何标记主对象多边形,但从未说明如何标记相邻多边形,因此这里我只是假设两者都使用相同的规则集进行标记
mark(s)
mark(s.neighbour)
其中,mark()处理规则定义为:
def mark(s):
curlocs = (s.prev.loc,s.next.loc)
neighlocs = (s.neighbour.prev.loc,s.neighbour.next.loc)
# in in
if curlocs == ("in","in"):
if neighlocs == ("in","in")\
or neighlocs == ("out","out")\
or neighlocs == ("on","on"):
s.intersect = False
else:
s.entry = True
# out out
elif curlocs == ("out","out"):
if neighlocs == ("in","in")\
or neighlocs == ("out","out")\
or neighlocs == ("on","on"):
s.intersect = False
else:
s.entry = False
# on on
elif curlocs == ("on","on"):
if neighlocs == ("in","in")\
or neighlocs == ("out","out")\
or neighlocs == ("on","on"):
s.intersect = False
else:
# label opposite of neighbour
# NOTE: this is not specified in the article,
# but one cannot take the opposite of the neighbour's entry flag
# if the neighbour hasn't been marked yet,
# thus the decision to mark the neighbour first
mark(s.neighbour)
s.entry = not s.neighbour
# partial exit
elif curlocs == ("in","on")\
or curlocs == ("on","out"):
s.entry = False
# partial entry
elif curlocs == ("on","in")\
or curlocs == ("out","on"):
s.entry = True
# normal exit
elif curlocs == ("in","out"):
s.entry = False
# normal entry
elif curlocs == ("out","in"):
s.entry = True
第2.2子部分:
最后,确保curr和neighbor没有相同的入口或出口标志;如果他们确实禁用交叉点标志并更改位置标志
if s.entry and s.neighbour.entry:
s.intersect = False
s.neighbour.intersect = False
s.loc = "in"
elif not s.entry and not s.neighbour.entry:
s.intersect = False
s.neighbour.intersect = False
s.loc = "out"
奖金问题
一个额外的问题是如何使该算法同时支持并集和交集操作,因为最初的Greiner算法对并集的支持是通过简单地反转初始入口/出口标志来实现的,但是这个Forster算法没有使用这样的标志?关于并集而不是交集的更多注释。其主要思想是,与交叉操作相比,并集操作将以相反的方向进行。也就是说,如果假设在相交操作中沿着多边形向后移动,那么在并集操作中,将向前移动,反之亦然 现在开始算法:首先,让我们从算法的概要开始。我这里的算法在每个相交操作中只创建一个多边形,因此您必须调整它以创建多个多边形
'''
The following is an adaptation of the above Greiner-Hormann* algorithm to deal
with degenerate cases. The adaptation was briefly described by Liu et al.**
*Greiner, G. and Hormann K., Efficient Clipping of Arbitrary Polygons, ACM
Trans. on Graphics, 17(2), 1998, pp.71-83
**Liu, Y. K., Wang X. Q., Bao S. Z., Gombosi M., and Zalik B, An Algorithm for
Polygon Clipping and for Determining Polygon Intersections and Unions, Comp. &
Geo, 33, pp. 589-598, 2007
'''
def clip(subject, constraint):
subject, constraint = inside_outside(subject, constraint) #label vertices as inside or outside
subject, constraint = poly_inters(subject, constraint) #find intersections
subject, constraint = label(subject, constraint) #label intersections and entry or exit and possibly remove
flag = True #loop flag
#set our current location to the first point in subject
current = subject.first
#loop through our polygon until we have found the first intersection
while flag:
current = current.next
#Either an intersection has been found or no intersections found
if current.intersect or current.pt == subject.first.pt:
flag = False
#reset our flag for the new loop
flag = True
#If a point lies outside of c and there was an intersection clip s
if current.intersect:
append(clipped, current.pt)
While flag:
#Entry
if current.en:
clipped, current = forward(clipped, current)
#Exit
else:
clipped, current = backward(clipped, current)
#Check to see if we have completed a polygon
if current.pt == clipped.first.pt:
#check if the polygon intersect at a point
if clipped.num_vertices is not 1:
#remove the last vertex because it is also the first
remove(clipped, clipped.last)
#we have created our polygon so we can exit
flag = .FALSE.
#change to the neighbor polygon since we are at a new intersection
current = current.neighbor
#Check if one polygon is contained wholly within the other
elif contained(subject, constraint):
clipped = subject
elif contained(subject, constraint):
clipped = constraint
return clipped
现在我们可以讨论标签问题。以下代码是用于将交点标记为内侧或外侧的循环。它不包括确定内部/外部的逻辑,只是操作顺序
#label intersections as entry or exit
def label(poly1, poly2):
#cycle through first polygon and label intersections as en or ex
current = poly1.first
for i in range(0,poly1.num_vertices):
if current.intersect:
current = intersect_cases(current)
#Make sure current is still an intersection
if current.isect:
current.neighbor = intersect_cases(current.neighbor)
#if the intersection is en/en or ex/ex
if current.en == current.neighbor.en:
current = remove_inter(current)
current = current.next #move to the next point
return poly1, poly2
最后处理各种标签案例
#deal with the cases
#on/on, on/out, on/in, out/on, out/out, out/in, in/on, in/out, in/in
def intersect_cases(current):
neighbor = current.neighbor
#on/on
if current.prev.intersect and current.next.intersect:
#Determine what to do based on the neighbor
#en tag is the opposite of the neighbor's en tag
if neighbor.prev.intersect and neighbor.next.intersect:
current = remove_inter(current)
current.en = True
neighbor.en = True
elif neighbor.prev.intersect and not neighbor.next.en:
current.en = False
elif neighbor.prev.intersect and neighbor.next.en:
current.en = True
elif not neighbor.prev.en and neighbor.next.intersect:
current.en = False
elif not (neighbor.prev.en or neighbor.next.en):
current = remove_inter(current)
current.en = True
neighbor.en = False
elif not neighbor.prev.en and neighbor.next.en:
current.en = False
elif neighbor.prev.en and neighbor.next.isect:
current.en = True
elif neighbor.prev.en and not neighbor.next.en:
current.en = True
elif neighbor.prev.en and neighbor.next.en:
current = remove_inter(current)
current.en = False
neighbor.en = True
#on/out
elif current.prev.intersect and not current.next.en:
current.en = False
#on/in
elif current.prev.intersect and current.next.en:
current.en = True
#out/on
elif not current.prev.en and current.next.intersect:
current.en = True
#out/out
elif not (current.prev%en or current.next.en):
if neighbor.prev%intersect and neighbor.next.intersect:
current = remove_inter(current)
neighbor.en = True
elif neighbor.prev.en == neighbor.next.en:
current = remove_inter(current)
else:
if neighbor.prev.en and not neighbor.next.en:
current.en = True
else:
current.en = False
#out/in
elif not current.prev.en and current.next.en:
current.en = True
#in/on
elif current.prev.en and current.next.intersect:
current.en = False
#in/out
elif current.prev.en and not current.next.en:
current.en = False
#in/in
elif current.prev.en and current.next.en:
if neighbor.prev.intersect and neighbor.next.intersect:
current = remove_inter(current)
neighbor.en = False
elif neighbor.prev.en == neighbor.next.en:
current = remove_inter(current)
else:
if neighbor.prev.en and not neighbor.next.en:
current.en = True
else:
current.en = False
return current
上面的代码没有经过测试,也不是为了提高效率而编写的,而是为了可读性和理解性而编写的。它到底是如何被破坏的?输出与您期望的有什么不同?请将其简化为a,并提供更清晰的问题描述。我现在更新了关于如何知道它已损坏的帖子,但没有明确的模式说明它与我期望的有什么不同,因为我给出的任何多边形都不同。稍后我将尝试使用“最小示例”进行更新,但必须包含伪代码的所有部分,以便对其进行检查和验证。在Greiner Horman中反转初始入口/出口标志相当于反转所有标志。通过这样做,一个将跟踪另一个多边形外部的多边形,从而得到一个并集。我将不得不更全面地考虑你的问题,并且稍后会尝试给出一个很好的答案。此外,Foest-ExpRead算法在一些没有退化的基本实例中是有缺陷的,所以我建议看下面的文章,而不是完美的@ LaveLPH!用于处理退化的清晰结构化伪代码。如果我知道如何回答,我会给你更多的学分。这是Liu等人的算法,而不是Forster Oberfelt,但重要的是它看起来很有效。当我有时间尝试实现和测试这一点时,我会发回帖子:)事实上,这是福斯特的过度感受。Foster Overfelt提到该想法来自Liue等人,但该想法并未得到阐述。