Skip to content

Commit d588061

Browse files
committed
fix: smooth SVG arc/cubic curves with quadratic sub-segments
Cubic/Arc segments (e.g. <circle>) were sampled into straight-line chords at _STEPS points, faceting curves. Now each is split into _STEPS quadratic bezier sub-segments fit through their midpoint (control = 2*mid - 0.5*(p0+p2)), keeping circles smooth.
1 parent 45ee056 commit d588061

2 files changed

Lines changed: 18 additions & 6 deletions

File tree

test/visual/golden/svg_frame0.png

-31 Bytes
Loading

videocode/input/shape/svg/_SVGHelper.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,13 @@ def _segmentsToContours(segments: list) -> list[list[point]]:
5353
pairs `[a0, h0, a1, h1, ...]` — same format as `_TextHelper.walkContourQuadratics`.
5454
5555
Line/Close: anchor + midpoint handle. QuadraticBezier: anchor + its
56-
control point (already the target format). Cubic/Arc: sampled at
57-
`_STEPS` and emitted as straight (midpoint-handle) segments. Each
58-
subpath is auto-closed back to its start if it didn't end with `Close`.
56+
control point (already the target format). Cubic/Arc: split into
57+
`_STEPS` quadratic sub-segments, each fit to pass through the
58+
sub-segment's midpoint (solving the quadratic bezier formula for the
59+
control point at t=0.5: `control = 2*mid - 0.5*(p0+p2)`) — keeps curves
60+
smooth (e.g. circles) instead of faceting them into straight chords.
61+
Each subpath is auto-closed back to its start if it didn't end with
62+
`Close`.
5963
"""
6064
contours: list[list[point]] = []
6165
pairs: list[point] = []
@@ -89,9 +93,17 @@ def flush():
8993
pairs.append(_pt(seg.control))
9094
cur = _pt(seg.end)
9195
elif isinstance(seg, (se.CubicBezier, se.Arc)):
92-
for s in range(1, _STEPS + 1):
93-
t = s / _STEPS
94-
line(_pt(seg.point(t)))
96+
p0 = cur
97+
for s in range(_STEPS):
98+
t1 = (s + 1) / _STEPS
99+
tm = (s + 0.5) / _STEPS
100+
p2 = _pt(seg.point(t1))
101+
mid = _pt(seg.point(tm))
102+
control = (2 * mid[0] - 0.5 * (p0[0] + p2[0]), 2 * mid[1] - 0.5 * (p0[1] + p2[1]))
103+
pairs.append(p0)
104+
pairs.append(control)
105+
p0 = p2
106+
cur = p0
95107

96108
flush()
97109
return contours

0 commit comments

Comments
 (0)