Skip to content

Commit ddab718

Browse files
Copilotkovidgoyal
andauthored
Fix circle sizing, twelfth circle geometry, and diagonal join fading
- Twelfth circles: use shared circle center at (2w, 2h) in the 4x4 grid coordinate space with radius 2*min(w,h). Each cell draws its 30° arc segment. Quarter circles use center at shared corner of 2x2 grid. - Half/quarter circles: set diameter = cell width for all edges. Left/right circles were using 2x cell width. Now vertically centered. - Diagonal joins: add filled square at apex of > < shapes to prevent visual thinning at the junction point. Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/ce5a54f9-41cc-462b-85f4-6ed56ab7fc94 Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
1 parent 199452a commit ddab718

1 file changed

Lines changed: 112 additions & 88 deletions

File tree

kitty/decorations.c

Lines changed: 112 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,32 +1627,50 @@ diagonal_line(Canvas *self, uint level, int x1, int y1, int x2, int y2) {
16271627
thick_line(self, diagonal_thickness(thickness(self, level, true), p1, p2), p1, p2);
16281628
}
16291629

1630+
// Draw a small filled square at a junction point to prevent visual thinning
1631+
// when two diagonal lines meet. The square size matches the line thickness.
1632+
static void
1633+
diagonal_join(Canvas *self, uint level, int jx, int jy) {
1634+
uint th = thickness(self, level, true);
1635+
int half = (int)(th / 2);
1636+
int extra = (int)(th % 2);
1637+
for (int y = MAX(0, jy - half); y < MIN(jy + half + extra, (int)self->height); y++) {
1638+
for (int x = MAX(0, jx - half); x < MIN(jx + half + extra, (int)self->width); x++) {
1639+
self->mask[x + y * self->width] = 255;
1640+
}
1641+
}
1642+
}
1643+
16301644
// Justified half/quarter circle (filled)
1631-
// A half circle touching one edge of the cell, filled solid.
1632-
// edge: which cell edge the flat side touches (e.g. TOP_EDGE means flat at top, arc goes down)
1645+
// For top/bottom: diameter = cell width, circle centered horizontally.
1646+
// Top: flat edge at top, arc going down. Bottom: flat edge at bottom, arc going up.
1647+
// For left/right: diameter = cell width, circle vertically centered.
1648+
// Left: flat edge at left, arc going right. Right: flat edge at right, arc going left.
16331649
static void
16341650
justified_half_circle(Canvas *self, Edge edge) {
16351651
double cx, cy, radius;
1652+
double w = self->width, h = self->height;
1653+
radius = w / 2.0;
16361654
switch (edge) {
1637-
case TOP_EDGE: // flat at top, semicircle going down
1638-
cx = self->width / 2.0; cy = 0; radius = fmin(self->width / 2.0, (double)self->height); break;
1639-
case BOTTOM_EDGE: // flat at bottom, semicircle going up
1640-
cx = self->width / 2.0; cy = self->height; radius = fmin(self->width / 2.0, (double)self->height); break;
1641-
case LEFT_EDGE: // flat at left, semicircle going right
1642-
cx = 0; cy = self->height / 2.0; radius = fmin((double)self->width, self->height / 2.0); break;
1643-
case RIGHT_EDGE: // flat at right, semicircle going left
1644-
cx = self->width; cy = self->height / 2.0; radius = fmin((double)self->width, self->height / 2.0); break;
1655+
case TOP_EDGE:
1656+
cx = w / 2.0; cy = 0; break;
1657+
case BOTTOM_EDGE:
1658+
cx = w / 2.0; cy = h; break;
1659+
case LEFT_EDGE:
1660+
cx = 0; cy = h / 2.0; break;
1661+
case RIGHT_EDGE:
1662+
cx = w; cy = h / 2.0; break;
16451663
default: return;
16461664
}
16471665
fill_circle_of_radius(self, cx, cy, radius, 255);
16481666
}
16491667

16501668
// Justified quarter circle (filled)
1651-
// A quarter circle touching one corner of the cell, filled solid.
1669+
// Diameter = cell width. Circle center at corner of cell.
16521670
static void
16531671
justified_quarter_circle(Canvas *self, Corner corner) {
1654-
double cx, cy, radius;
1655-
radius = fmin((double)self->width, (double)self->height);
1672+
double cx, cy;
1673+
double radius = self->width / 2.0;
16561674
switch (corner) {
16571675
case TOP_RIGHT: cx = self->width; cy = 0; break;
16581676
case BOTTOM_LEFT: cx = 0; cy = self->height; break;
@@ -1663,30 +1681,28 @@ justified_quarter_circle(Canvas *self, Corner corner) {
16631681
fill_circle_of_radius(self, cx, cy, radius, 255);
16641682
}
16651683

1666-
// Justified half circle outline (white/unfilled circle arc drawn as a stroked curve)
1667-
// edge: which cell edge the diameter touches
1684+
// Justified half circle outline (white/unfilled circle arc)
1685+
// Diameter = cell width for all edges. Vertically centered for left/right.
16681686
static void
16691687
justified_half_circle_outline(Canvas *self, uint level, Edge edge) {
16701688
double cx, cy, radius;
16711689
double line_width = thickness_as_float(self, level, true);
16721690
double half_lw = fmax(0.5, line_width / 2.0);
1691+
double w = self->width, h = self->height;
16731692
double start_deg, end_deg;
1693+
radius = w / 2.0 - half_lw;
16741694
switch (edge) {
1675-
case TOP_EDGE: // flat at top, arc going down
1676-
cx = self->width / 2.0; cy = half_lw;
1677-
radius = fmin(self->width / 2.0, (double)self->height) - half_lw;
1695+
case TOP_EDGE:
1696+
cx = w / 2.0; cy = half_lw;
16781697
start_deg = 0; end_deg = 180; break;
1679-
case BOTTOM_EDGE: // flat at bottom, arc going up
1680-
cx = self->width / 2.0; cy = self->height - half_lw;
1681-
radius = fmin(self->width / 2.0, (double)self->height) - half_lw;
1698+
case BOTTOM_EDGE:
1699+
cx = w / 2.0; cy = h - half_lw;
16821700
start_deg = 180; end_deg = 360; break;
1683-
case LEFT_EDGE: // flat at left, arc going right
1684-
cx = half_lw; cy = self->height / 2.0;
1685-
radius = fmin((double)self->width, self->height / 2.0) - half_lw;
1701+
case LEFT_EDGE:
1702+
cx = half_lw; cy = h / 2.0;
16861703
start_deg = 270; end_deg = 450; break;
1687-
case RIGHT_EDGE: // flat at right, arc going left
1688-
cx = self->width - half_lw; cy = self->height / 2.0;
1689-
radius = fmin((double)self->width, self->height / 2.0) - half_lw;
1704+
case RIGHT_EDGE:
1705+
cx = w - half_lw; cy = h / 2.0;
16901706
start_deg = 90; end_deg = 270; break;
16911707
default: return;
16921708
}
@@ -1697,12 +1713,14 @@ justified_half_circle_outline(Canvas *self, uint level, Edge edge) {
16971713
}
16981714

16991715
// Twelfth/quarter circle arcs for U+1CC30-U+1CC3F
1700-
// These are arc segments positioned at specific locations around the cell edges.
1701-
// The 16 positions form a 4x4 grid of arcs around the cell perimeter:
1702-
// Row 0 (top): upper-left, upper-centre-left, upper-centre-right, upper-right
1703-
// Row 1: upper-middle-left, upper-left-quarter, upper-right-quarter, upper-middle-right
1704-
// Row 2: lower-middle-left, lower-left-quarter, lower-right-quarter, lower-middle-right
1705-
// Row 3 (bottom): lower-left, lower-centre-left, lower-centre-right, lower-right
1716+
// The 12 twelfth circles form a continuous circle when printed in a 4x4 grid:
1717+
// printf '\U1cc30\U1cc31\U1cc32\U1cc33\n\U1cc34 \U1cc37\n\U1cc38 \U1cc3b\n\U1cc3c\U1cc3d\U1cc3e\U1cc3f'
1718+
// The 4 quarter circles form a continuous circle when printed in a 2x2 grid:
1719+
// printf '\U1cc35\U1cc36\n\U1cc39\U1cc3a'
1720+
// For the twelfth circles: the shared circle center is at the center of the 4x4 grid.
1721+
// Each cell at grid position (col, row) has local center at (2w - col*w, 2h - row*h).
1722+
// Radius = 2*min(w, h). Each arc spans 30° (1/12 of 360°).
1723+
// For the quarter circles: center at corner shared by the 2x2 grid, radius = min(w, h).
17061724
static void
17071725
twelfth_circle(Canvas *self, uint level, uint pos) {
17081726
double line_width = thickness_as_float(self, level, true);
@@ -1711,61 +1729,65 @@ twelfth_circle(Canvas *self, uint level, uint pos) {
17111729
double cx, cy, radius, start_deg, end_deg;
17121730

17131731
switch (pos) {
1714-
// Top edge arcs: center is on the top edge, arcs curve downward
1715-
case 0: // upper left twelfth circle - at top-left corner, small arc
1716-
cx = 0; cy = 0; radius = fmin(w / 2.0, h / 2.0) - half_lw;
1717-
start_deg = 0; end_deg = 90; break;
1718-
case 1: // upper centre left twelfth circle
1719-
cx = w / 4.0; cy = 0; radius = fmin(w / 4.0, h / 2.0) - half_lw;
1720-
start_deg = 0; end_deg = 90; break;
1721-
case 2: // upper centre right twelfth circle
1722-
cx = 3.0 * w / 4.0; cy = 0; radius = fmin(w / 4.0, h / 2.0) - half_lw;
1723-
start_deg = 90; end_deg = 180; break;
1724-
case 3: // upper right twelfth circle
1725-
cx = w; cy = 0; radius = fmin(w / 2.0, h / 2.0) - half_lw;
1726-
start_deg = 90; end_deg = 180; break;
1727-
1728-
// Upper middle arcs: center is on the left/right edge at 1/4 height
1729-
case 4: // upper middle left twelfth circle
1730-
cx = 0; cy = h / 4.0; radius = fmin(w / 2.0, h / 4.0) - half_lw;
1731-
start_deg = 270; end_deg = 360; break;
1732-
case 5: // upper left quarter circle - large quarter arc at top-left
1733-
cx = 0; cy = 0; radius = fmin(w, h) - half_lw;
1734-
start_deg = 0; end_deg = 90; break;
1735-
case 6: // upper right quarter circle - large quarter arc at top-right
1736-
cx = w; cy = 0; radius = fmin(w, h) - half_lw;
1737-
start_deg = 90; end_deg = 180; break;
1738-
case 7: // upper middle right twelfth circle
1739-
cx = w; cy = h / 4.0; radius = fmin(w / 2.0, h / 4.0) - half_lw;
1732+
// Top row (row=0): arcs from the upper part of the circle
1733+
case 0: // upper left twelfth (col=0, row=0): 210° to 240°
1734+
cx = 2*w; cy = 2*h; radius = 2*fmin(w, h) - half_lw;
1735+
start_deg = 210; end_deg = 240; break;
1736+
case 1: // upper centre left twelfth (col=1, row=0): 240° to 270°
1737+
cx = w; cy = 2*h; radius = 2*fmin(w, h) - half_lw;
1738+
start_deg = 240; end_deg = 270; break;
1739+
case 2: // upper centre right twelfth (col=2, row=0): 270° to 300°
1740+
cx = 0; cy = 2*h; radius = 2*fmin(w, h) - half_lw;
1741+
start_deg = 270; end_deg = 300; break;
1742+
case 3: // upper right twelfth (col=3, row=0): 300° to 330°
1743+
cx = -w; cy = 2*h; radius = 2*fmin(w, h) - half_lw;
1744+
start_deg = 300; end_deg = 330; break;
1745+
1746+
// Side cells row=1
1747+
case 4: // upper middle left twelfth (col=0, row=1): 180° to 210°
1748+
cx = 2*w; cy = h; radius = 2*fmin(w, h) - half_lw;
1749+
start_deg = 180; end_deg = 210; break;
1750+
case 5: // upper left quarter circle (2x2 grid: col=0, row=0)
1751+
// Center at bottom-right corner of cell, radius = min(w,h)
1752+
cx = w; cy = h; radius = fmin(w, h) - half_lw;
17401753
start_deg = 180; end_deg = 270; break;
1741-
1742-
// Lower middle arcs: center is on the left/right edge at 3/4 height
1743-
case 8: // lower middle left twelfth circle
1744-
cx = 0; cy = 3.0 * h / 4.0; radius = fmin(w / 2.0, h / 4.0) - half_lw;
1745-
start_deg = 0; end_deg = 90; break;
1746-
case 9: // lower left quarter circle - large quarter arc at bottom-left
1754+
case 6: // upper right quarter circle (2x2 grid: col=1, row=0)
1755+
// Center at bottom-left corner of cell
17471756
cx = 0; cy = h; radius = fmin(w, h) - half_lw;
17481757
start_deg = 270; end_deg = 360; break;
1749-
case 10: // lower right quarter circle - large quarter arc at bottom-right
1750-
cx = w; cy = h; radius = fmin(w, h) - half_lw;
1751-
start_deg = 180; end_deg = 270; break;
1752-
case 11: // lower middle right twelfth circle
1753-
cx = w; cy = 3.0 * h / 4.0; radius = fmin(w / 2.0, h / 4.0) - half_lw;
1758+
case 7: // upper middle right twelfth (col=3, row=1): 330° to 360°
1759+
cx = -w; cy = h; radius = 2*fmin(w, h) - half_lw;
1760+
start_deg = 330; end_deg = 360; break;
1761+
1762+
// Side cells row=2
1763+
case 8: // lower middle left twelfth (col=0, row=2): 150° to 180°
1764+
cx = 2*w; cy = 0; radius = 2*fmin(w, h) - half_lw;
1765+
start_deg = 150; end_deg = 180; break;
1766+
case 9: // lower left quarter circle (2x2 grid: col=0, row=1)
1767+
// Center at top-right corner of cell
1768+
cx = w; cy = 0; radius = fmin(w, h) - half_lw;
17541769
start_deg = 90; end_deg = 180; break;
1755-
1756-
// Bottom edge arcs: center is on the bottom edge, arcs curve upward
1757-
case 12: // lower left twelfth circle
1758-
cx = 0; cy = h; radius = fmin(w / 2.0, h / 2.0) - half_lw;
1759-
start_deg = 270; end_deg = 360; break;
1760-
case 13: // lower centre left twelfth circle
1761-
cx = w / 4.0; cy = h; radius = fmin(w / 4.0, h / 2.0) - half_lw;
1762-
start_deg = 270; end_deg = 360; break;
1763-
case 14: // lower centre right twelfth circle
1764-
cx = 3.0 * w / 4.0; cy = h; radius = fmin(w / 4.0, h / 2.0) - half_lw;
1765-
start_deg = 180; end_deg = 270; break;
1766-
case 15: // lower right twelfth circle
1767-
cx = w; cy = h; radius = fmin(w / 2.0, h / 2.0) - half_lw;
1768-
start_deg = 180; end_deg = 270; break;
1770+
case 10: // lower right quarter circle (2x2 grid: col=1, row=1)
1771+
// Center at top-left corner of cell
1772+
cx = 0; cy = 0; radius = fmin(w, h) - half_lw;
1773+
start_deg = 0; end_deg = 90; break;
1774+
case 11: // lower middle right twelfth (col=3, row=2): 0° to 30°
1775+
cx = -w; cy = 0; radius = 2*fmin(w, h) - half_lw;
1776+
start_deg = 0; end_deg = 30; break;
1777+
1778+
// Bottom row (row=3): arcs from the lower part of the circle
1779+
case 12: // lower left twelfth (col=0, row=3): 120° to 150°
1780+
cx = 2*w; cy = -h; radius = 2*fmin(w, h) - half_lw;
1781+
start_deg = 120; end_deg = 150; break;
1782+
case 13: // lower centre left twelfth (col=1, row=3): 90° to 120°
1783+
cx = w; cy = -h; radius = 2*fmin(w, h) - half_lw;
1784+
start_deg = 90; end_deg = 120; break;
1785+
case 14: // lower centre right twelfth (col=2, row=3): 60° to 90°
1786+
cx = 0; cy = -h; radius = 2*fmin(w, h) - half_lw;
1787+
start_deg = 60; end_deg = 90; break;
1788+
case 15: // lower right twelfth (col=3, row=3): 30° to 60°
1789+
cx = -w; cy = -h; radius = 2*fmin(w, h) - half_lw;
1790+
start_deg = 30; end_deg = 60; break;
17691791
default: return;
17701792
}
17711793
if (radius < 1) radius = 1;
@@ -2157,6 +2179,7 @@ START_ALLOW_CASE_RANGE
21572179
// Key points used: UL=(0,0), UC=(w/2,0), UR=(w,0), ML=(0,h/2), MC=(w/2,h/2), MR=(w,h/2),
21582180
// LL=(0,h), LC=(w/2,h), LR=(w,h)
21592181
#define DL(x1,y1,x2,y2) diagonal_line(c, 1, x1, y1, x2, y2)
2182+
#define DJ(x,y) diagonal_join(c, 1, x, y)
21602183
#define W (int)minus(c->width,1)
21612184
#define H (int)minus(c->height,1)
21622185
#define HW ((int)(c->width/2))
@@ -2180,20 +2203,21 @@ START_ALLOW_CASE_RANGE
21802203
// 1FBD8: upper left to middle centre to upper right (V open down)
21812204
SS(0x1fbd8, DL(0, 0, HW, HH); DL(HW, HH, W, 0));
21822205
// 1FBD9: upper right to middle centre to lower right (> shape)
2183-
SS(0x1fbd9, DL(W, 0, HW, HH); DL(HW, HH, W, H));
2206+
SS(0x1fbd9, DL(W, 0, HW, HH); DL(HW, HH, W, H); DJ(HW, HH));
21842207
// 1FBDA: lower left to middle centre to lower right (^ shape)
21852208
SS(0x1fbda, DL(0, H, HW, HH); DL(HW, HH, W, H));
21862209
// 1FBDB: upper left to middle centre to lower left (< shape)
2187-
SS(0x1fbdb, DL(0, 0, HW, HH); DL(HW, HH, 0, H));
2210+
SS(0x1fbdb, DL(0, 0, HW, HH); DL(HW, HH, 0, H); DJ(HW, HH));
21882211
// 1FBDC: upper left to lower centre to upper right (V with apex at bottom-center)
21892212
SS(0x1fbdc, DL(0, 0, HW, H); DL(HW, H, W, 0));
21902213
// 1FBDD: upper right to middle left to lower right (> with apex at middle-left)
2191-
SS(0x1fbdd, DL(W, 0, 0, HH); DL(0, HH, W, H));
2214+
SS(0x1fbdd, DL(W, 0, 0, HH); DL(0, HH, W, H); DJ(0, HH));
21922215
// 1FBDE: lower left to upper centre to lower right (^ with apex at upper-center)
21932216
SS(0x1fbde, DL(0, H, HW, 0); DL(HW, 0, W, H));
21942217
// 1FBDF: upper left to middle right to lower left (< with apex at middle-right)
2195-
SS(0x1fbdf, DL(0, 0, W, HH); DL(W, HH, 0, H));
2218+
SS(0x1fbdf, DL(0, 0, W, HH); DL(W, HH, 0, H); DJ(W, HH));
21962219
#undef DL
2220+
#undef DJ
21972221
#undef W
21982222
#undef H
21992223
#undef HW

0 commit comments

Comments
 (0)