[英]Drawing Bezier curve with multiple off curve points in PyQt
I would like to draw a TrueType Font glyph with PyQt5 QPainterPath.我想用 PyQt5 QPainterPath 绘制一个 TrueType 字体字形。 Example glyph fragment: (data from Fonttools ttx )
字形片段示例:(来自 Fonttools ttx 的数据)
<pt x="115" y="255" on="1"/>
<pt x="71" y="255" on="0"/>
<pt x="64" y="244" on="0"/>
<pt x="53" y="213" on="0"/>
<pt x="44" y="180" on="0"/>
<pt x="39" y="166" on="1"/>
on=0 means a control point and on=1 means a start/end point I'm assuming this would not use (QPainterPath) quadTo or cubicTo as it is a higher order curve. on=0 表示控制点,on=1 表示起点/终点我假设这不会使用 (QPainterPath) quadTo 或cubicTo,因为它是更高阶的曲线。
True type fonts actually use only quadratic Bézier curves.真正的类型 fonts 实际上只使用二次贝塞尔曲线。 This makes sense, they are pretty simple curves that don't require a lot of computation, which is good for performance when you have to potentially draw hundreds or thousands of curves even for a simple paragraph.
这是有道理的,它们是非常简单的曲线,不需要大量计算,当您必须为简单的段落绘制成百上千条曲线时,这对性能很有好处。
After realizing this, I found out strange that you have a curve with 4 control points, but then I did a bit of research and found out this interesting answer .意识到这一点后,我发现你有一条有 4 个控制点的曲线很奇怪,但后来我做了一些研究,发现了这个有趣的答案。
In reality, the TrueType format allows grouping quadratic curves that always share each start or end point at the middle of each control point.实际上,TrueType 格式允许对始终在每个控制点中间共享每个起点或终点的二次曲线进行分组。
So, starting with your list:因此,从您的列表开始:
Start <pt x="115" y="255" on="1"/>
C1 <pt x="71" y="255" on="0"/>
C2 <pt x="64" y="244" on="0"/>
C3 <pt x="53" y="213" on="0"/>
C4 <pt x="44" y="180" on="0"/>
End <pt x="39" y="166" on="1"/>
We have 6 points, but there are 4 curves, and the intermediate points between the 4 control points are the remaining start/end points that exist on the curve:我们有 6 个点,但有 4 条曲线,4 个控制点之间的中间点是曲线上存在的剩余起点/终点:
start![]() |
control![]() |
end![]() |
---|---|---|
Start![]() |
C1 ![]() |
(C2-C1)/2 ![]() |
(C2-C1)/2 ![]() |
C2 ![]() |
(C3-C2)/2 ![]() |
(C3-C2)/2 ![]() |
C3 ![]() |
(C4-C3)/2 ![]() |
(C4-C3)/2 ![]() |
C4 ![]() |
End![]() |
To compute all that, we can cycle through the points and store a reference to the previous, and whenever we have a control point or an on-curve point after them, we add a new quadratic curve to the path.为了计算所有这些,我们可以循环遍历这些点并存储对前一个的引用,并且每当我们在它们之后有一个控制点或曲线上的点时,我们就会在路径中添加一条新的二次曲线。
start![]() |
control![]() |
end![]() |
---|---|---|
115 x 255 ![]() |
71 x 255 ![]() |
67.5 x 249.5 ![]() |
67.5 x 249.5 ![]() |
64 x 244 ![]() |
58.5 x 228.5 ![]() |
58.5 x 228.5 ![]() |
53 x 213 ![]() |
48.5 x 106.5 ![]() |
48.5 x 106.5 ![]() |
44 x 180 ![]() |
39 x 166 ![]() |
The following code will create a QPainterPath that corresponds to each <contour>
group.以下代码将创建一个对应于每个
<contour>
组的 QPainterPath。
path = QtGui.QPainterPath()
currentCurve = []
started = False
for x, y, onCurve in contour:
point = QtCore.QPointF(x, y)
if onCurve:
if not currentCurve:
# start of curve
currentCurve.append(point)
else:
# end of curve
start, cp = currentCurve
path.quadTo(cp, point)
currentCurve = []
started = False
else:
if len(currentCurve) == 1:
# control point
currentCurve.append(point)
else:
start, cp = currentCurve
# find the midpoint
end = QtCore.QLineF(cp, point).pointAt(.5)
if not started:
# first curve of many
path.moveTo(start)
started = True
path.quadTo(cp, end)
currentCurve = [end, point]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.