Jon*_*ine 5 python svg drawing
我需要转换路径的 SVG 描述,即。就像是:
M400 597 C235 599 478 607 85 554 C310 675 2 494 399 718 C124 547 569 828 68 400 C-108 317 304 703 96 218 L47 215 L400 290 C602 -146 465 467 550 99 L548 35 L706 400 L580 686 C546 614 591 672 529 629 L400 597 Z
进入沿着该路径落下的所有像素的列表(假设画布是显示器的大小。如您所见,我需要处理的路径数量为涂鸦并且非常复杂。理想情况下,我希望生成这样的路径,然后将整个事物转换为逐像素描述,即。
p= [(403, 808), (403, 807), (403, 805), (403, 802), (403, 801), (403, 800), (403, 799),
(403, 797), (403, 794), (403, 792), (402, 789), (401, 787), (400, 785), (399, 784),
(399, 783), (398, 782)] # ... it'd be much longer, but you get the idea
Run Code Online (Sandbox Code Playgroud)
或者,我对使用曲线和直线成分生成路径的任何方法都感到满意(因为到目前为止,SVG 就是我实现这一目标的方式)。上下文有点奇怪;这是一个认知心理学的实验,其中我需要逐渐动画一个点遍历根据某些规则生成的路径,并将该路径导出为像素数据。
为了制作动画,我打算简单地在路径上的每个 x,y 位置重新绘制点——因此需要上述列表。
我的数学技能不是很好——我是从设计而不是 CS 来编码的——而且路径会变得非常复杂,这意味着仅用数学计算这些点是......也许不会超出我的范围,但肯定比我要求的更高”我的目标。
图书馆、技巧、策略——都受到欢迎和赞赏。
出于一些奇怪的目的,我需要将 SVG 路径转换为离散点。显然没有光源库可以做到这一点。我最终创建了自己的解析器。
输入文件主要由贝塞尔曲线组成。我为此编写了一个快速函数:
def cubic_bezier_sample(start, control1, control2, end):
inputs = np.array([start, control1, control2, end])
cubic_bezier_matrix = np.array([
[-1, 3, -3, 1],
[ 3, -6, 3, 0],
[-3, 3, 0, 0],
[ 1, 0, 0, 0]
])
partial = cubic_bezier_matrix.dot(inputs)
return (lambda t: np.array([t**3, t**2, t, 1]).dot(partial))
def quadratic_sample(start, control, end):
# Quadratic bezier curve is just cubic bezier curve
# with the same control points.
return cubic_bezier_sample(start, control, control, end)
Run Code Online (Sandbox Code Playgroud)
可以按如下方式生成 10 个样本:
n = 10
curve = cubic_bezier_sample((50,0), (50,100), (100,100), (50,0))
points = [curve(float(t)/n) for t in xrange(0, n + 1)]
Run Code Online (Sandbox Code Playgroud)
该代码需要numpy。如果需要,您也可以在没有 numpy 的情况下进行点积。我可以使用svg.path获取参数。
import numpy as np
import matplotlib.pyplot as plt
def cubic_bezier_sample(start, control1, control2, end):
inputs = np.array([start, control1, control2, end])
cubic_bezier_matrix = np.array([
[-1, 3, -3, 1],
[ 3, -6, 3, 0],
[-3, 3, 0, 0],
[ 1, 0, 0, 0]
])
partial = cubic_bezier_matrix.dot(inputs)
return (lambda t: np.array([t**3, t**2, t, 1]).dot(partial))
# == control points ==
start = np.array([0, 0])
control1 = np.array([60, 5])
control2 = np.array([40, 95])
end = np.array([100, 100])
# number of segments to generate
n_segments = 100
# get curve segment generator
curve = cubic_bezier_sample(start, control1, control2, end)
# get points on curve
points = np.array([curve(t) for t in np.linspace(0, 1, n_segments)])
# == plot ==
controls = np.array([start, control1, control2, end])
# segmented curve
plt.plot(points[:, 0], points[:, 1], '-')
# control points
plt.plot(controls[:,0], controls[:,1], 'o')
# misc lines
plt.plot([start[0], control1[0]], [start[1], control1[1]], '-', lw=1)
plt.plot([control2[0], end[0]], [control2[1], end[1]], '-', lw=1)
plt.show()
Run Code Online (Sandbox Code Playgroud)