我该如何从svgpathtools的贝塞尔曲线中获取坐标列表?

4

我有一段Python代码可以创建贝塞尔曲线,从中我可以创建一条贝塞尔路径。

以下是我的导入:

import from svgpathtools import Path, Line, CubicBezier

这是我的代码:

    bezier_curve = CubicBezier(start_coordinate, control_point_1, control_point_2, end_coordinate)
    bezier_path = Path(bezier_curve)

我想创建一个坐标列表,用于描述这条曲线,但是我正在阅读的 文档 没有提供直接的方法。bezier_curve 和 bezier_path 只有起始点、结束点和控制点的参数。

“组成这条曲线的坐标”是什么意思?bezier_curve.bpoints()将返回元组(起始坐标,控制点1,控制点2,结束坐标),但这似乎不是您要找的内容。贝塞尔曲线是多项式,例如,三次贝塞尔曲线完全由其四个系数确定。如需更多信息,请参阅: https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves - mathandy
4个回答

8

这似乎是一个相当合理的问题。惊讶的是没有答案。最近我自己不得不做这个,秘密就是使用point()

以下是我使用您的模板作为起点完成此操作的方法:

from svgpathtools import Path, Line, CubicBezier

bezier_curve = CubicBezier(start=(300+100j), control1=(100+100j), control2=(200+200j), end=(200+300j))
bezier_path = Path(bezier_curve)

NUM_SAMPLES = 10

myPath = []
for i in range(NUM_SAMPLES):
    myPath.append(bezier_path.point(i/(NUM_SAMPLES-1)))

print(myPath)

输出:

[(300+100j), (243.8957475994513+103.56652949245542j), (206.72153635116598+113.71742112482853j), (185.1851851851852+129.62962962962962j), (175.99451303155004+150.480109739369j), (175.85733882030178+175.44581618655695j), (181.4814814814815+203.7037037037037j), (189.57475994513032+234.43072702331963j), (196.84499314128942+266.8038408779149j), (200+300j)]

2

上面给出的答案对我非常有效。我只需要对代码进行微小的修改:

from svgpathtools import Path, Line, CubicBezier

bezier_curve = CubicBezier(start=(300+100j), control1=(100+100j), control2=(200+200j), end=(200+300j))
bezier_path = Path(bezier_curve)

NUM_SAMPLES = 10

myPath = []
for i in range(NUM_SAMPLES):
    myPath.append(bezier_path.point(i/(**float(NUM_SAMPLES)**-1)))

print(myPath)

i/(NUM_SAMPLES -1) 改为 i/(float(NUM_SAMPLES) -1) 可以确保当曲线从0到1参数化时,行为正确。否则只会产生整数除法。


1
#to demonstrate lines and cubics, improving readibility

from svgpathtools import Path, Line, CubicBezier

cubic = CubicBezier(300+100j, 100+100j, 200+200j, 200+300j)  # A cubic beginning at (300, 100) and ending at (200, 300)
line = Line(200+300j, 250+350j)  # A line beginning at (200, 300) and ending at (250, 350)

number_of_points = 10

cubic_points = []

for i in range(number_of_points):
    cubic_points.append(cubic.point(i/(NUM_SAMPLES-1)))

print('cubic points', path_points)

line_points = []

for i in range(number_of_points):
    line_points.append(line.point(i/(NUM_SAMPLES-1)))

print('line points', path_points)

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

0

我需要一种更通用的形式来提取具有不同特征的多个路径。这是一种递归解决方案,可以同时处理路径、路径列表、段列表和单个段。您可以为曲线指定每个段的sample_points,但是对于直线而言,保持2个点以避免不必要的额外点:

import svgpathtools.path

def svgpathtools_unpacker(obj, sample_points=10):
    path = []
    if isinstance(obj, (svgpathtools.path.Path, list)):
        for i in obj:
            path.extend(svgpathtools_unpacker(i, sample_points=sample_points))
    elif isinstance(obj, svgpathtools.path.Line):
        path.extend(obj.bpoints())
    elif isinstance(obj, (svgpathtools.path.CubicBezier, svgpathtools.path.QuadraticBezier)):
        path.extend(obj.points(np.linspace(0,1,sample_points)))
    else:
        print(type(obj))
    return np.array(path)

并且您可以如何使用它:

import matplotlib.pyplot as plt

bezier_curve = svgpathtools.path.CubicBezier(start=(300+100j), control1=(100+100j), control2=(200+200j), end=(200+300j))
bezier_quad = svgpathtools.path.QuadraticBezier(bezier_curve.end, control=(200+200j), end=(300+150j))
line = svgpathtools.path.Line(start=bezier_quad.end, end=bezier_curve.start)
bezier_path = svgpathtools.path.Path(bezier_curve, bezier_quad, line)

plt.figure()
for i in [10, 100]:
    xy = svgpathtools_unpacker(bezier_path, sample_points=i)
    plt.plot(xy.real, xy.imag, label=f'sample_points={i}')
plt.legend()

plot


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接