drawille.c - ploot - simple plotting tools
(HTM) git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
(DIR) LICENSE
---
drawille.c (3796B)
---
1 #include "drawille.h"
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <math.h>
7 #include "font.h"
8
9 /*
10 * Terminal-based plotting using drawille character, aka drawille.
11 */
12
13 /* parameters used to draw a line */
14 struct line {
15 int x0, y0, x1, y1; /* point of the line */
16 int dx, dy, sx, sy, err; /* parameters for the algorythm */
17 };
18
19 /*
20 * Turn on the bit at position (row, col) of a single cell. The
21 * pattern is not linear (1-4-2-5-3-6-7-8), because it matches the
22 * drawille pattern.
23 */
24 static void
25 drawille_cell_dot(uint8_t *cell, int row, int col)
26 {
27 uint8_t flags[4][2] = {
28 { 0x01, 0x08 },
29 { 0x02, 0x10 },
30 { 0x04, 0x20 },
31 { 0x40, 0x80 },
32 };
33
34 *cell |= flags[row][col];
35 }
36
37 static size_t
38 drawille_cell_utf(uint8_t cell, char *utf)
39 {
40 long rune;
41
42 rune = 10240 + cell;
43 utf[0] = (char)(0xe0 | (0x0f & (rune >> 12))); /* 1110xxxx */
44 utf[1] = (char)(0x80 | (0x3f & (rune >> 6))); /* 10xxxxxx */
45 utf[2] = (char)(0x80 | (0x3f & (rune))); /* 10xxxxxx */
46 return 3;
47 }
48
49 static uint8_t
50 drawille_get(struct drawille *drw, int row, int col)
51 {
52 return drw->buf[row * drw->col + col];
53 }
54
55 size_t
56 drawille_put_row(FILE *fp, struct drawille *drw, int row)
57 {
58 char txt[] = "xxx";
59 size_t n;
60
61 n = 0;
62 for (int col = 0; col < drw->col; col++) {
63 drawille_cell_utf(drawille_get(drw, row, col), txt);
64 n += fputs(txt, fp);
65 }
66 return n;
67 }
68
69 /*
70 * Coordinates are passed as (x, y), but the canvas stores bits as
71 * (row, col). Conversion is made by this function.
72 */
73 void
74 drawille_dot(struct drawille *drw, int x, int y)
75 {
76 if (x < 0 || x / 2 >= drw->col || y < 0 || y / 4 >= drw->row)
77 return;
78 drawille_cell_dot(drw->buf + (drw->row - y / 4 - 1) * drw->col + (x / 2),
79 3 - y % 4,
80 x % 2);
81 }
82
83 struct drawille *
84 drawille_new(int row, int col)
85 {
86 struct drawille *drw;
87
88 if ((drw = calloc(sizeof(struct drawille) + row * col, 1)) == NULL)
89 return NULL;
90 drw->row = row;
91 drw->col = col;
92 return drw;
93 }
94
95 static void
96 drawille_line_init(struct line *l, int x0, int y0, int x1, int y1)
97 {
98 l->x0 = x0;
99 l->y0 = y0;
100 l->x1 = x1;
101 l->y1 = y1;
102 l->sx = x0 < x1 ? 1 : -1;
103 l->sy = y0 < y1 ? 1 : -1;
104 l->dx = abs(x1 - x0);
105 l->dy = abs(y1 - y0);
106 l->err = (l->dx > l->dy ? l->dx : -l->dy) / 2;
107 }
108
109 static int
110 drawille_line_next(struct line *l)
111 {
112 int err;
113
114 if (l->x0 == l->x1 && l->y0 == l->y1)
115 return 0;
116
117 err = l->err;
118 if (err > -l->dx) {
119 l->x0 += l->sx;
120 l->err -= l->dy;
121 }
122 if (err < l->dy) {
123 l->y0 += l->sy;
124 l->err += l->dx;
125 }
126 return 1;
127 }
128
129 void
130 drawille_line(struct drawille *drw, int x0, int y0, int x1, int y1)
131 {
132 struct line l;
133
134 drawille_line_init(&l, x0, y0, x1, y1);
135 do {
136 drawille_dot(drw, l.x0, l.y0);
137 } while (drawille_line_next(&l));
138 }
139
140 void
141 drawille_histogram_dot(struct drawille *drw, int x, int y, int zero)
142 {
143 int sign;
144
145 sign = (y > zero) ? (+1) : (-1);
146 for (; y != zero; y -= sign)
147 drawille_dot(drw, x, y);
148 drawille_dot(drw, x, y);
149 }
150
151 void
152 drawille_histogram_line(struct drawille *drw, int x0, int y0, int x1, int y1, int zero)
153 {
154 struct line l;
155
156 drawille_line_init(&l, x0, y0, x1, y1);
157 do {
158 drawille_histogram_dot(drw, l.x0, l.y0, zero);
159 } while (drawille_line_next(&l));
160 }
161
162 static int
163 drawille_text_glyph(struct drawille *drw, int x, int y, struct font *font, int c)
164 {
165 int w;
166 char *glyph;
167
168 glyph = font->glyph[(c > 127 || c < 0) ? 0 : c];
169 w = strlen(glyph) / font->height;
170 for (int ix = 0; ix < w; ix++)
171 for (int iy = 0; iy < font->height; iy++)
172 if (glyph[ix + (font->height - 1) * w - iy * w] == 3)
173 drawille_dot(drw, x + ix, y + iy);
174 return w;
175 }
176
177 char *
178 drawille_text(struct drawille *drw, int x, int y, struct font *font, char *s)
179 {
180 if (drw->row*4 < font->height)
181 return NULL;
182 for (; *s != '\0' && x < drw->col*2; s++, x++)
183 x += drawille_text_glyph(drw, x, y, font, *s);
184 return s;
185 }