1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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);
}
|