Skip to content

Commit 817f099

Browse files
committed
Fix one pixel mis-alignment of rounded corners when either the cell dimensions or the thickness of the line is an odd number of pixels
The control points of the Bezier curve and the spread due to thickness must match up with the values used to draw straight lines. In order to ensure that, one calculates them before upscaling by the super sampling factor, rather than after. Fixes #2907
1 parent 1d65127 commit 817f099

File tree

2 files changed

+26
-22
lines changed

2 files changed

+26
-22
lines changed

docs/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
1717
- Fix image leaving behind a black rectangle when switch away and back to
1818
alternate screen (:iss:`2901`)
1919

20+
- Fix one pixel mis-alignment of rounded corners when either the cell
21+
dimensions or the thickness of the line is an odd number of pixels
22+
(:iss:`2907`)
2023

2124
0.18.2 [2020-07-28]
2225
--------------------

kitty/fonts/box_drawing.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -364,20 +364,19 @@ def D(buf: BufType, width: int, height: int, left: bool = True) -> None:
364364
buf[offset + dest_x] = mbuf[offset + src_x]
365365

366366

367-
def draw_parametrized_curve(buf: BufType, width: int, height: int, thickness_in_pixels: int, xfunc: BezierFunc, yfunc: BezierFunc) -> None:
367+
def draw_parametrized_curve(buf: BufType, width: int, height: int, delta: int, extra: int, xfunc: BezierFunc, yfunc: BezierFunc) -> None:
368368
num_samples = height*4
369369
seen = set()
370-
delta, extra = divmod(thickness_in_pixels, 2)
371370
for i in range(num_samples + 1):
372371
t = (i / num_samples)
373372
p = x_p, y_p = int(xfunc(t)), int(yfunc(t))
374373
if p in seen:
375374
continue
376375
seen.add(p)
377-
for y in range(int(y_p) - delta, int(y_p) + delta + extra):
376+
for y in range(y_p - delta, y_p + delta + extra):
378377
if 0 <= y < height:
379378
offset = y * width
380-
for x in range(int(x_p) - delta, int(x_p) + delta + extra):
379+
for x in range(x_p - delta, x_p + delta + extra):
381380
if 0 <= x < width:
382381
pos = offset + x
383382
buf[pos] = min(255, buf[pos] + 255)
@@ -386,29 +385,31 @@ def draw_parametrized_curve(buf: BufType, width: int, height: int, thickness_in_
386385
@supersampled()
387386
def rounded_corner(buf: BufType, width: int, height: int, level: int = 1, which: str = '╭') -> None:
388387
supersample_factor = getattr(buf, 'supersample_factor')
389-
thickness_in_pixels = thickness(level) * supersample_factor
388+
delta, extra = divmod(thickness(level), 2)
389+
hw = ((width / supersample_factor) // 2) * supersample_factor
390+
hh = ((height / supersample_factor) // 2) * supersample_factor
390391
if which == '╭':
391-
start = width // 2, height - 1
392-
end = width - 1, height // 2
393-
c1 = width // 2, int(0.75 * height)
394-
c2 = width // 2, height // 2 + 1
392+
start = hw, height - 1
393+
end = width - 1, hh
394+
c1 = hw, int(0.75 * height)
395+
c2 = hw, hh + 1
395396
elif which == '╮':
396-
start = 0, height // 2
397-
end = width // 2, height - 1
398-
c1 = width // 2, height // 2 + 1
399-
c2 = width // 2, int(0.75 * height)
397+
start = 0, hh
398+
end = hw, height - 1
399+
c1 = hw, hh + 1
400+
c2 = hw, int(0.75 * height)
400401
elif which == '╰':
401402
start = width // 2, 0
402-
end = width - 1, height // 2
403-
c1 = width // 2, int(0.25 * height)
404-
c2 = width // 2 - 1, height // 2 - 1
403+
end = width - 1, hh
404+
c1 = hw, int(0.25 * height)
405+
c2 = hw, hh - 1
405406
elif which == '╯':
406-
start = 0, height // 2
407-
end = width // 2, 0
408-
c1 = width // 2 - 1, height // 2 - 1
409-
c2 = width // 2, int(0.25 * height)
407+
start = 0, hh
408+
end = hw, 0
409+
c1 = hw, hh - 1
410+
c2 = hw, int(0.25 * height)
410411
xfunc, yfunc = cubic_bezier(start, end, c1, c2)
411-
draw_parametrized_curve(buf, width, height, thickness_in_pixels, xfunc, yfunc)
412+
draw_parametrized_curve(buf, width, height, delta * supersample_factor, extra * supersample_factor, xfunc, yfunc)
412413

413414

414415
def half_dhline(buf: BufType, width: int, height: int, level: int = 1, which: str = 'left', only: Optional[str] = None) -> Tuple[int, int]:
@@ -686,7 +687,7 @@ def quad(buf: BufType, width: int, height: int, x: int = 0, y: int = 0) -> None:
686687
for start in '┌┐└┘':
687688
for i, (hlevel, vlevel) in enumerate(((t, t), (f, t), (t, f), (f, f))):
688689
box_chars[chr(ord(start) + i)] = [p(corner, which=start, hlevel=hlevel, vlevel=vlevel)]
689-
for ch in '╭╮╯╰':
690+
for ch in '╭╮╰╯':
690691
box_chars[ch] = [p(rounded_corner, which=ch)]
691692

692693
for i, (a_, b_, c_, d_) in enumerate((

0 commit comments

Comments
 (0)