问题:
matplotlib.path
定义不一致。此函数用于检查指定点是否位于闭合路径的内部或外部。半径参数用于使路径变小/变大(取决于半径的符号)。通过这种方式,可以考虑/不考虑靠近路径的点。问题是,半径的符号取决于路径的方向(顺时针或逆时针)。
这个
(在我看来)是存在的,因为在检查点是在路径内还是在路径外时忽略了路径的方向。从数学的严格意义上讲,一个人说:沿途留下的一切都包括在内。
简而言之:
如果路径为逆时针方向,则正半径会考虑更多点。
例子:
-
是包含正半径的点(靠近路径)
-
-
是否包含原点(位于两条路径的中间)
代码:
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. ]])
ccwPath=path.Path(verts, closed=True)
cwPath=path.Path(verts[::-1,:], closed=True)
testPoint=[12,0]
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('clockwise: ','|\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 decreases tolerance \t'
)
输出:
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'
)
给出以下输出:
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
-
有人知道为什么会出现这种不一致吗?
-
有没有更优雅的方式来回避这个问题?例如:使用其他库作为包含点,以更智能/正确的方式使用半径参数,或使用预定义函数查找路径的方向。