如何解决Matplotlib Polygon contains_point 类内部不起作用
我正在修改 poly_editor
here 的 matplolib
,我需要验证某些点是否在多边形内。当在主类和类中创建多边形时,我将 print
设为 poly.contains_point((x,y))
。如果我不更改多边形坐标,这将正常工作,即如果我在主类和类内部打印 poly.contains_point((0,0))
,这在两种情况下都返回 True
,同时更改多边形坐标,即向 {{1 }} 和 x
和 y
的 checkign 返回 (2,2)
如果打印在主要和 True
如果它在类中。
这是我的代码,我在相对于上面链接的教程更改的部分添加了一些 False
:
####
更新:我注意到如果打印放在主文件中的 """
===========
poly Editor
===========
This is an example to show how to build cross-GUI applications using
Matplotlib event handling to interact with objects on the canvas.
"""
import numpy as np
from matplotlib.lines import Line2D
from matplotlib.artist import Artist
def dist(x,y):
"""
Return the distance between two points.
"""
d = x - y
return np.sqrt(np.dot(d,d))
def dist_point_to_segment(p,s0,s1):
"""
Get the distance of a point to a segment.
*P*,*s0*,*s1* are *xy* sequences
This algorithm from
http://geomalgorithms.com/a02-_lines.html
"""
v = s1 - s0
w = p - s0
c1 = np.dot(w,v)
if c1 <= 0:
return dist(p,s0)
c2 = np.dot(v,v)
if c2 <= c1:
return dist(p,s1)
b = c1 / c2
pb = s0 + b * v
return dist(p,pb)
class polygonInteractor:
"""
A polygon editor.
Key-bindings
't' toggle vertex markers on and off. When vertex markers are on,you can move them,delete them
'd' delete the vertex under point
'i' insert a vertex at point. You must be within epsilon of the
line connecting two existing vertices
"""
showverts = True
epsilon = 5 # max pixel distance to count as a vertex hit
def __init__(self,ax,poly):
if poly.figure is None:
raise RuntimeError('You must first add the polygon to a figure '
'or canvas before defining the interactor')
self.ax = ax
canvas = poly.figure.canvas
self.poly = poly
print(self.poly.contains_point((2,2))) ########################
x,y = zip(*self.poly.xy)
self.line = Line2D(x,y,marker='o',markerfacecolor='r',animated=True)
self.ax.add_line(self.line)
self.cid = self.poly.add_callback(self.poly_changed)
self._ind = None # the active vert
canvas.mpl_connect('draw_event',self.on_draw)
canvas.mpl_connect('button_press_event',self.on_button_press)
canvas.mpl_connect('key_press_event',self.on_key_press)
canvas.mpl_connect('button_release_event',self.on_button_release)
canvas.mpl_connect('motion_notify_event',self.on_mouse_move)
self.canvas = canvas
def on_draw(self,event):
self.background = self.canvas.copy_from_bBox(self.ax.bBox)
self.ax.draw_artist(self.poly)
self.ax.draw_artist(self.line)
# do not need to blit here,this will fire before the screen is
# updated
def poly_changed(self,poly):
"""This method is called whenever the pathpatch object is called."""
# only copy the artist props to the line (except visibility)
vis = self.line.get_visible()
Artist.update_from(self.line,poly)
self.line.set_visible(vis) # don't use the poly visibility state
def get_ind_under_point(self,event):
"""
Return the index of the point closest to the event position or *None*
if no point is within ``self.epsilon`` to the event position.
"""
# display coords
xy = np.asarray(self.poly.xy)
xyt = self.poly.get_transform().transform(xy)
xt,yt = xyt[:,0],xyt[:,1]
d = np.hypot(xt - event.x,yt - event.y)
indseq,= np.nonzero(d == d.min())
ind = indseq[0]
if d[ind] >= self.epsilon:
ind = None
return ind
def on_button_press(self,event):
"""Callback for mouse button presses."""
if not self.showverts:
return
if event.inaxes is None:
return
if event.button != 1:
return
self._ind = self.get_ind_under_point(event)
def on_button_release(self,event):
"""Callback for mouse button releases."""
if not self.showverts:
return
if event.button != 1:
return
self._ind = None
def on_key_press(self,event):
"""Callback for key presses."""
if not event.inaxes:
return
if event.key == 't':
self.showverts = not self.showverts
self.line.set_visible(self.showverts)
if not self.showverts:
self._ind = None
elif event.key == 'd':
ind = self.get_ind_under_point(event)
if ind is not None:
self.poly.xy = np.delete(self.poly.xy,ind,axis=0)
self.line.set_data(zip(*self.poly.xy))
elif event.key == 'i':
xys = self.poly.get_transform().transform(self.poly.xy)
p = event.x,event.y # display coords
for i in range(len(xys) - 1):
s0 = xys[i]
s1 = xys[i + 1]
d = dist_point_to_segment(p,s1)
if d <= self.epsilon:
self.poly.xy = np.insert(
self.poly.xy,i+1,[event.xdata,event.ydata],axis=0)
self.line.set_data(zip(*self.poly.xy))
break
if self.line.stale:
self.canvas.draw_idle()
def on_mouse_move(self,event):
"""Callback for mouse movements."""
if not self.showverts:
return
if self._ind is None:
return
if event.inaxes is None:
return
if event.button != 1:
return
x,y = event.xdata,event.ydata
self.poly.xy[self._ind] = x,y
if self._ind == 0:
self.poly.xy[-1] = x,y
elif self._ind == len(self.poly.xy) - 1:
self.poly.xy[0] = x,y
self.line.set_data(zip(*self.poly.xy))
self.canvas.restore_region(self.background)
self.ax.draw_artist(self.poly)
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bBox)
if __name__ == '__main__':
import matplotlib.pyplot as plt
from matplotlib.patches import polygon
theta = np.arange(0,2*np.pi,0.1)
r = 1.5
xs = r * np.cos(theta) +2 ####################
ys = r * np.sin(theta) +2 #####################
poly = polygon(np.column_stack([xs,ys]),animated=True)
fig,ax = plt.subplots()
print(poly.contains_point((2,2))) ###################### True
ax.add_patch(poly)
print(poly.contains_point((2,2))) ###################### False
p = polygonInteractor(ax,poly)
ax.set_title('Click and drag a point to move it')
ax.set_xlim((0,4)) ############### changed from (-2,2)
ax.set_ylim((0,4)) ###############
plt.show()
之后,它也会返回 add_patch
,那么 False
有什么变化?
解决方法
我发现这是因为 contains_point
方法在我检查点的数据坐标时引用了显示坐标。因此,在检查数据坐标中的点之前,必须通过以下方式将其转换为显示坐标:
point = (2,2)
point = poly.get_transform().transform(point)
poly.contains_point(point)
>>> True
当 poly 没有被 2 转换时,这个转换只是 Identity 转换,所以在没有转换之前检查也可以工作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。