Python matplotlib.Path.contains“U点:”;“半径”;参数定义不一致
问题: 函数中包含点的半径参数定义不一致。此函数用于检查指定点是否位于闭合路径的内部或外部。半径参数用于使路径稍微变小/变大(取决于半径的符号)。这样,可以考虑/不考虑靠近路径的点。问题是,半径的符号取决于路径的方向(顺时针或逆时针)。 不一致(在我看来)是存在的,因为在检查点是在路径内部还是外部时,路径的方向被忽略。从数学的严格意义上讲,一个人说:沿着路径留下的所有东西都包括在内 简而言之: 如果路径为逆时针方向,则正半径会考虑更多点。 如果路径为顺时针方向,则正半径考虑的点较少 示例: 在以下示例中,检查了3种情况-分别为顺时针和逆时针路径:Python matplotlib.Path.contains“U点:”;“半径”;参数定义不一致,python,matplotlib,path,contains,point,Python,Matplotlib,Path,Contains,Point,问题: 函数中包含点的半径参数定义不一致。此函数用于检查指定点是否位于闭合路径的内部或外部。半径参数用于使路径稍微变小/变大(取决于半径的符号)。这样,可以考虑/不考虑靠近路径的点。问题是,半径的符号取决于路径的方向(顺时针或逆时针)。 不一致(在我看来)是存在的,因为在检查点是在路径内部还是外部时,路径的方向被忽略。从数学的严格意义上讲,一个人说:沿着路径留下的所有东西都包括在内 简而言之: 如果路径为逆时针方向,则正半径会考虑更多点。 如果路径为顺时针方向,则正半径考虑的点较少 示例: 在以
contains: | [12,0], radius=3 | [12,0], radius=-3 | [0,0]|
counterclockwise: | True | False | True | => radius increases tolerance
clockwise: | False | True | True | => radius decreases tolerance
凸路径的解决方案:
我唯一想到的是,强制路径为逆时针方向,并根据此使用半径
import matplotlib.path as path
import numpy as np
verts=np.array([[-11.5, 16. ],[-11.5, -16. ],[ 11.5, -16. ],[ 11.5, 16. ],[-11.5, 16. ]])
#comment following line out to make isCounterClockWise crash
#verts=np.array([[-11.5, 16. ],[-10,0],[-11.5, -16. ],[ 11.5, -16. ],[ 11.5, 16. ],[-11.5, 16. ]])
ccwPath=path.Path(verts, closed=True)
cwPath=path.Path(verts[::-1,:], closed=True)
testPoint=[12,0]
def isCounterClockWise(myPath):
#directions from on vertex to the other
dirs=myPath.vertices[1:]-myPath.vertices[0:-1]
#rot: array of rotations at ech edge
rot=np.cross(dirs[:-1],dirs[1:])
if len(rot[rot>0])==len(rot):
#counterclockwise
return True
elif len(rot[rot<0])==len(rot):
#clockwise
return False
else:
assert False, 'no yet implemented: This case applies if myPath is concave'
def forceCounterClockWise(myPath):
if not isCounterClockWise(myPath):
myPath.vertices=myPath.vertices[::-1]
forceCounterClockWise(cwPath)
print('contains: ','|\t', '[12,0], radius=3','|\t', '[12,0], radius=-3','|\t', '[0,0]|')
print('counterclockwise: ','|\t'
,'{0:>16s}'.format(str(ccwPath.contains_point(testPoint,radius=3) )),'|\t'
,'{0:>17s}'.format(str(ccwPath.contains_point(testPoint,radius=-3) )),'|\t'
,ccwPath.contains_point([0,0],radius=0) ,'|\t'
,'=> radius increases tolerance \t'
)
print('forced ccw: ','|\t'
,'{0:>16s}'.format(str(cwPath.contains_point(testPoint,radius=3) )),'|\t'
,'{0:>17s}'.format(str(cwPath.contains_point(testPoint,radius=-3) )),'|\t'
,cwPath.contains_point([0,0],radius=0) ,'|\t'
,'=> radius increases tolerance \t'
)
代码注释中给出了此解决方案失败的示例(对于凹形路径)
我的问题:
我认为这里唯一错误的假设是“沿途留下的一切都包括在内”。相反,
包含点
字面意思是指闭合路径是否包含点
然后将半径定义为
- 当路径沿逆时针方向移动并旋转时,展开该路径
- 当路径顺时针移动时收缩路径
下面的示例显示了这一点,其中对于(逆时针)顺时针路径,将绘制展开/shunk区域中包含的点。(红色=不包含\u点,蓝色=包含\u点
)
一个似乎根本没有记录的特殊性是,radius
实际上通过radius/2扩展或收缩路径。
。如上图所示,半径为1
,包含-1.5
和1.5
之间的点,而不是-2
和2
之间的点
关于路径的方向,可能没有一个固定方向。如果有3个点,可以明确地确定方向为顺时针、逆时针(或共线)。一旦你有了更多的点,方向的概念就没有很好的定义
一个选项是检查路径是否“大部分为逆时针方向”
这将允许在“大部分为顺时针”路径的情况下调整半径
这样,正半径总是扩展路径,负半径总是收缩路径
完整示例:
import matplotlib.pyplot as plt
import matplotlib.path as path
import matplotlib.patches as patches
import numpy as np
verts=np.array([[-1, 1 ],[-1, -1 ],[ 1, -1 ],[ 1, 0 ],[ 1, 1],[-1, 1 ]])
ccwPath=path.Path(verts, closed=True)
cwPath=path.Path(verts[::-1,:], closed=True)
paths = [ccwPath, cwPath]
pathstitle = ["ccwPath", "cwPath"]
radii = [1,-1]
testPoint=(np.random.rand(400,2)-.5)*4
c = lambda p,x,r: p.contains_point(x,radius=r)
def is_ccw(p):
v = p.vertices-p.vertices[0,:]
a = np.arctan2(v[1:,1],v[1:,0])
return (a[1:] >= a[:-1]).astype(int).mean() >= 0.5
fig, axes = plt.subplots(nrows=len(radii),ncols=len(paths))
for j in range(len(paths)):
for i in range(len(radii)):
ax = axes[i,j]
r = radii[i]
isccw = is_ccw(paths[j])
r = r*isccw - r*(1-isccw)
patch = patches.PathPatch(paths[j], fill=False, lw=2)
ax.add_patch(patch)
col = [c(paths[j], point[0], r) for point in zip(testPoint)]
ax.scatter(testPoint[:,0], testPoint[:,1], c=col, s=8, vmin=0,vmax=1, cmap="bwr_r")
ax.set_title("{}, r={} (isccw={})".format(pathstitle[j],radii[i], isccw) )
plt.tight_layout()
plt.show()
在深入了解这一点之前:您确定您正确地解释了问题吗。文档说明radius
允许路径稍微变大或变小。因此,它将是偏移半径的路径,而不是点。确切地说,这也是我所看到的!对不起,有什么误会!如果我的问题有误导性,请告诉我,我没有发现问题中有任何不一致之处,因为ccw++r->path expanded
,cw+-r->path expanded
,ccw+-r->path shresk
,cw++r->path shresk
正在按预期工作。但是,如果您选择的半径为+0.9
,我确实看到了一个问题。在这种情况下,(12,0)处的点应位于(ccw)路径内;as 11.5+0.9=12.4>12),但包含\u点
返回False
。因此,尽管有些事情确实很奇怪,但问题中的例子并不适合看到这个问题。
contains: | [12,0], radius=3 | [12,0], radius=-3 | [0,0]|
counterclockwise: | True | False | True | => radius increases tolerance
forced ccw: | True | False | True | => radius increases tolerance
import matplotlib.pyplot as plt
import matplotlib.path as path
import matplotlib.patches as patches
import numpy as np
verts=np.array([[-1, 1 ],[-1, -1 ],[ 1, -1 ],[ 1, 0 ],[ 1, 1],[-1, 1 ]])
ccwPath=path.Path(verts, closed=True)
cwPath=path.Path(verts[::-1,:], closed=True)
paths = [ccwPath, cwPath]
pathstitle = ["ccwPath", "cwPath"]
radii = [1,-1]
testPoint=(np.random.rand(400,2)-.5)*4
c = lambda p,x,r: p.contains_point(x,radius=r)
fig, axes = plt.subplots(nrows=len(paths),ncols=len(radii))
for j in range(len(paths)):
for i in range(len(radii)):
ax = axes[i,j]
r = radii[i]
patch = patches.PathPatch(paths[j], fill=False, lw=2)
ax.add_patch(patch)
col = [c(paths[j], point[0], r) for point in zip(testPoint)]
ax.scatter(testPoint[:,0], testPoint[:,1], c=col, s=8, vmin=0,vmax=1, cmap="bwr_r")
ax.set_title("{}, r={}".format(pathstitle[j],radii[i]) )
plt.tight_layout()
plt.show()
def is_ccw(p):
v = p.vertices-p.vertices[0,:]
a = np.arctan2(v[1:,1],v[1:,0])
return (a[1:] >= a[:-1]).astype(int).mean() >= 0.5
r = r*is_ccw(p) - r*(1-is_ccw(p))
import matplotlib.pyplot as plt
import matplotlib.path as path
import matplotlib.patches as patches
import numpy as np
verts=np.array([[-1, 1 ],[-1, -1 ],[ 1, -1 ],[ 1, 0 ],[ 1, 1],[-1, 1 ]])
ccwPath=path.Path(verts, closed=True)
cwPath=path.Path(verts[::-1,:], closed=True)
paths = [ccwPath, cwPath]
pathstitle = ["ccwPath", "cwPath"]
radii = [1,-1]
testPoint=(np.random.rand(400,2)-.5)*4
c = lambda p,x,r: p.contains_point(x,radius=r)
def is_ccw(p):
v = p.vertices-p.vertices[0,:]
a = np.arctan2(v[1:,1],v[1:,0])
return (a[1:] >= a[:-1]).astype(int).mean() >= 0.5
fig, axes = plt.subplots(nrows=len(radii),ncols=len(paths))
for j in range(len(paths)):
for i in range(len(radii)):
ax = axes[i,j]
r = radii[i]
isccw = is_ccw(paths[j])
r = r*isccw - r*(1-isccw)
patch = patches.PathPatch(paths[j], fill=False, lw=2)
ax.add_patch(patch)
col = [c(paths[j], point[0], r) for point in zip(testPoint)]
ax.scatter(testPoint[:,0], testPoint[:,1], c=col, s=8, vmin=0,vmax=1, cmap="bwr_r")
ax.set_title("{}, r={} (isccw={})".format(pathstitle[j],radii[i], isccw) )
plt.tight_layout()
plt.show()