@@ -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.
16331649static void
16341650justified_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.
16521670static void
16531671justified_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.
16681686static void
16691687justified_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).
17061724static void
17071725twelfth_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