gpt4 book ai didi

python - 路径 'contains_points' 使用贝塞尔曲线产生不正确的结果

转载 作者:行者123 更新时间:2023-11-28 18:22:10 25 4
gpt4 key购买 nike

我正在尝试根据 matplotlib Path 对象选择数据区域,但是当路径包含贝塞尔曲线(不仅仅是直线)时,所选区域不会完全填充曲线。看起来它正在尝试,但曲线的远侧被切断了。

例如,以下代码定义了一条相当简单的封闭路径,其中包含一条直线和一条三次曲线。当我查看 contains_points 方法的 True/False 结果时,它似乎与曲线本身或原始顶点都不匹配。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.path import Path
from matplotlib.patches import PathPatch

# Make the Path
verts = [(1.0, 1.5), (-2.0, 0.25), (-1.0, 0.0), (1.0, 0.5), (1.0, 1.5)]
codes = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY]
path1 = Path(verts, codes)

# Make a field with points to select
nx, ny = 101, 51
x = np.linspace(-2, 2, nx)
y = np.linspace(0, 2, ny)

yy, xx = np.meshgrid(y, x)
pts = np.column_stack((xx.ravel(), yy.ravel()))

# Construct a True/False array of contained points
tf = path1.contains_points(pts).reshape(nx, ny)

# Make a PathPatch for display
patch1 = PathPatch(path1, facecolor='c', edgecolor='b', lw=2, alpha=0.5)

# Plot the true/false array, the patch, and the vertices
fig, ax = plt.subplots()
ax.imshow(tf.T, origin='lower', extent=(x[0], x[-1], y[0], y[-1]))
ax.add_patch(patch1)
ax.plot(*zip(*verts), 'ro-')

plt.show()

这给了我这个情节:

true points do not completely fill the curve

看起来正在进行某种近似 - 这只是 matplotlib 中计算的基本限制,还是我做错了什么?

可以自己计算曲线内的点,但如果没有必要,我希望不要重新发明这个轮子。

值得注意的是,使用二次曲线的更简单的构造似乎可以正常工作:

quadratic curves emulating a circle work fine

我正在使用 matplotlib 2.0.0。

最佳答案

这与评估路径的空间有关,如 GitHub 问题 #6076 中所述.来自 mdboom 的评论:

Path intersection is done by converting the curves to line segments and then converting the intersection based on the line segments. This conversion happens by "sampling" the curve at increments of 1.0. This is generally the right thing to do when the paths are already scaled in display space, because sampling the curve at a resolution finer than a single pixel doesn't really help. However, when calculating the intersection in data space as you've done here, we obviously need to sample at a finer resolution.

这是在讨论交叉点,但 contains_points 也受到影响。此增强功能仍处于开放状态,因此我们必须看看它是否会在下一个里程碑中得到解决。同时,有几个选项:

1) 如果您无论如何都要显示一个补丁,您可以使用显示转换。在上面的示例中,添加以下内容演示了正确的行为(基于 tacaswell 对重复问题 #8734 的评论,现已关闭):

# Work in transformed (pixel) coordinates
hit_patch = path1.transformed(ax.transData)
tf1 = hit_patch.contains_points(ax.transData.transform(pts)).reshape(nx, ny)

ax.imshow(tf2.T, origin='lower', extent=(x[0], x[-1], y[0], y[-1]))

2) 如果您不使用显示器而只想使用路径进行计算,最好的办法是自己简单地形成贝塞尔曲线并用线段制作路径。将 path1 的形成替换为以下 path2 的计算将产生所需的结果。

from scipy.special import binom
def bernstein(n, i, x):
coeff = binom(n, i)
return coeff * (1-x)**(n-i) * x**i

def bezier(ctrlpts, nseg):
x = np.linspace(0, 1, nseg)
outpts = np.zeros((nseg, 2))
n = len(ctrlpts)-1
for i, point in enumerate(ctrlpts):
outpts[:,0] += bernstein(n, i, x) * point[0]
outpts[:,1] += bernstein(n, i, x) * point[1]

return outpts

verts1 = [(1.0, 1.5), (-2.0, 0.25), (-1.0, 0.0), (1.0, 0.5), (1.0, 1.5)]
nsegments = 31
verts2 = np.concatenate([bezier(verts1[:4], nsegments), np.array([verts1[4]])])
codes2 = [Path.MOVETO] + [Path.LINETO]*(nsegments-1) + [Path.CLOSEPOLY]
path2 = Path(verts2, codes2)

这两种方法都会产生如下所示的结果:

true and false match bezier curve

关于python - 路径 'contains_points' 使用贝塞尔曲线产生不正确的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44423889/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com