aboutsummaryrefslogtreecommitdiffstats
path: root/7_2/src/figure.c
diff options
context:
space:
mode:
Diffstat (limited to '7_2/src/figure.c')
-rw-r--r--7_2/src/figure.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/7_2/src/figure.c b/7_2/src/figure.c
new file mode 100644
index 0000000..290d4af
--- /dev/null
+++ b/7_2/src/figure.c
@@ -0,0 +1,139 @@
+
+#include "figure.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+void (*const draw_lookup[])(const struct figure *, struct drawable *) = {
+ [F_NONE] = NULL,
+ [F_POINT] = draw_point,
+ [F_RECT] = draw_rect,
+ [F_LINE] = draw_line,
+ [F_CIRCLE] = draw_circle
+};
+
+void swapl(long *x, long *y) {
+ long tmp = *x;
+ *x = *y;
+ *y = tmp;
+}
+
+struct figure figure_point(vector2 p) {
+ return (struct figure) {
+ .type = F_POINT,
+ .point.coords = p,
+ .draw = draw_point
+ };
+}
+
+struct figure figure_rect(vector2 upleft, vector2 downright) {
+ return (struct figure) {
+ .type = F_RECT,
+ .rect = {upleft, downright},
+ .draw = draw_rect
+ };
+}
+
+struct figure figure_line(vector2 start, vector2 end) {
+ return (struct figure) {
+ .type = F_LINE,
+ .line = {start, end},
+ .draw = draw_line
+ };
+}
+
+struct figure figure_circle(vector2 center, long radius) {
+ return (struct figure) {
+ .type = F_CIRCLE,
+ .circle = {center, radius},
+ .draw = draw_circle
+ };
+}
+
+
+void draw_point(const struct figure *self, struct drawable *d) {
+ d->put(d, self->point.coords.x, self->point.coords.y);
+}
+
+void draw_rect(const struct figure *self, struct drawable *d) {
+ vector2 upleft = self->rect.upleft;
+ vector2 downright = self->rect.downright;
+ for (long i = upleft.x; i < downright.x + 1; ++i) {
+ d->put(d, i, upleft.y);
+ d->put(d, i, downright.y);
+ }
+ for (long j = upleft.y + 1; j < downright.y; ++j) {
+ d->put(d, upleft.x, j);
+ d->put(d, downright.x, j);
+ }
+}
+
+void draw_line(const struct figure *self, struct drawable *d) {
+ vector2 start = self->line.start;
+ vector2 end = self->line.end;
+ char gt45 = labs(end.y - start.y) > labs(end.x - start.x);
+ long x0 = start.x, y0 = start.y,
+ x1 = end.x, y1 = end.y;
+ if (gt45) {
+ swapl(&x0, &y0);
+ swapl(&x1, &y1);
+ }
+ if (x0 > x1) {
+ swapl(&x0, &x1);
+ swapl(&y0, &y1);
+ }
+ long dy = labs(y1-y0),
+ dx = x1 - x0,
+ err = dx >> 1, // *2
+ yinc = (y1 > y0 ? 1 : -1);
+
+ for (long x = x0, y = y0; x <= x1; ++x) {
+ if (gt45) d->put(d, y, x);
+ else d->put(d, x, y);
+ err -= dy;
+ if (err < 0) {
+ y += yinc;
+ err += dx;
+ }
+ }
+}
+
+void draw_circle(const struct figure *self, struct drawable *f) {
+ const vector2 p = self->circle.center;
+ const long rad = self->circle.rad - 1;
+ const long pi4 = ceil(M_SQRT1_2 * rad);
+ long x0 = 0, y0 = rad;
+ do {
+ // выглядит коряво, зато в 8 раз меньше повторений цикла
+ f->put(f, p.x-x0, p.y-y0); // 3 четверть
+ f->put(f, p.x-x0, p.y+y0); // 2 чет.
+ f->put(f, p.x+x0, p.y-y0); // 4 ч.
+ f->put(f, p.x+x0, p.y+y0); // 1 ч
+ f->put(f, p.x-y0, p.y-x0);
+ f->put(f, p.x-y0, p.y+x0);
+ f->put(f, p.x+y0, p.y-x0);
+ f->put(f, p.x+y0, p.y+x0);
+ ++x0;
+ // вычисляем x^2 + (y+1/2)^2 - r^2
+ // раскрыли скобки и умножили на 4, чтобы не иметь дело
+ // с дробными числами (они медленные)
+ long func = 4*x0*x0 + 4*y0*y0 - 4*y0 + 1 - 4*rad*rad;
+ y0 = (func >= 0 ? y0 - 1 : y0);
+ } while (x0 < pi4);
+}
+
+void print_figure(const struct figure *self) {
+ printf("figure {\n\t.type = %i\n\t{%li, %li},\n\t", self->type, self->line.start.x, self->line.start.y);
+ switch (self->type) {
+ case F_LINE:
+ case F_RECT:
+ printf("{%li, %li}\n\t", self->line.end.x, self->line.end.y);
+ break;
+ case F_CIRCLE:
+ printf("%li\n\t", self->circle.rad);
+ // fallthrough
+ case F_NONE:
+ case F_POINT:;
+ }
+ printf(".draw = %p\n}\n", self->draw);
+}