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