9 return x == 0 ? 0 : x < 0 ? -1 : 1;
27 int maj1, min1, maj2, min2;
45 box bounds = { .x1 = 10, .x2 = 30, .y1 = 10, .y2 = 30 };
50 assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b);
51 return (a + b - 1) // b - 1;
55 div_floor_plus_one(a, b) {
57 assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b);
62 clip(*clip_context c, *clip_box b)
64 int adjust_major = 0, adjust_minor = 0;
67 if (c->major < b->maj1) {
68 if (c->sign_major <= 0)
70 adjust_major = b->maj1 - c->major;
71 } else if (c->major >= b->maj2) {
72 if (c->sign_major >= 0)
74 adjust_major = c->major - (b->maj2-1);
78 if (c->minor < b->min1) {
79 if (c->sign_minor <= 0)
81 adjust_minor = b->min1 - c->minor;
82 } else if (c->minor >= b->min2) {
83 if (c->sign_minor >= 0)
85 adjust_minor = c->minor - (b->min2-1);
88 /* If unclipped, we're done */
89 if (adjust_major == 0 && adjust_minor == 0)
92 /* See how much minor adjustment would happen during
93 * a major clip. This is a bit tricky because line drawing
94 * isn't symmetrical when the line passes exactly between
95 * two pixels, we have to pick which one gets drawn
100 adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3);
102 adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3);
104 /* Compare that to the minor clip and pick
107 printf ("\tinitial major %d minor %d error %d e1 %d e3 %d\n", c->major, c->minor, c->e, c->e1, c->e3);
109 if (adj_min < adjust_minor) {
110 printf("\tminor clip dominates %d < %d. adjust major %d -> ",
111 adj_min, adjust_minor, adjust_major);
113 adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1);
115 adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1);
116 printf("%d\n", adjust_major);
118 printf("\tminor clip dominates %d > %d. adjust minor %d -> ",
119 adj_min, adjust_minor, adjust_minor);
120 adjust_minor = adj_min;
121 printf("%d\n", adjust_minor);
124 c->e += adjust_major * c->e1 + adjust_minor * c->e3;
126 c->major += c->sign_major * adjust_major;
127 c->minor += c->sign_minor * adjust_minor;
129 printf ("\tadjust major %d adjust minor %d e %d e1 %d e3 %e\n",
130 adjust_major, adjust_minor, c->e, c->e1, c->e3);
133 printf ("error positive e %d e1 %d e3 %d\n",
136 printf ("error magnitude too large e %d e1 %d e3 %d\n", c->e, c->e1, c->e3);
142 line(int x1, int y1, int x2, int y2, *box b) {
146 int signdx = sign(dx);
147 int signdy = sign(dy);
153 clip_context clip_1, clip_2;
155 bool clipped = false;
162 .clipped = (point[...]) {},
163 .run = (point[...]) {}
169 e2 = e1 - (adx << 1);
177 clip_1.sign_major = signdx;
178 clip_1.sign_minor = signdy;
187 e2 = e1 - (ady << 1);
195 clip_1.sign_major = signdy;
196 clip_1.sign_minor = signdx;
207 clip_2.first = false;
208 clip_2.e = clip_1.e = e;
209 clip_2.e1 = clip_1.e1 = e1;
210 clip_2.e3 = clip_1.e3 = e3;
211 clip_2.sign_major = -clip_1.sign_major;
212 clip_2.sign_minor = -clip_1.sign_minor;
214 printf ("clip start:\n");
215 if (!clip(&clip_1, &c))
218 printf("clip end:\n");
219 if (!clip(&clip_2, &c))
225 int x_major, x_minor;
226 int y_major, y_minor;
228 clip_len = clip_1.sign_major * (clip_2.major - clip_1.major);
234 if (axis == X_AXIS) {
237 x_major = clip_1.sign_major;
240 y_minor = clip_1.sign_minor;
245 x_minor = clip_1.sign_minor;
246 y_major = clip_1.sign_major;
255 while (clip_len-- >= 0) {
256 t.clipped[dim(t.clipped)] = (point) { .x = x, .y = y };
271 if (bounds.x1 <= x && x < bounds.x2 &&
272 bounds.y1 <= y && y < bounds.y2) {
273 t.run[dim(t.run)] = (point) { .x = x, .y = y };
287 void read_events (Cairo::cairo_t cr)
289 file event = Cairo::open_event(cr);
291 while (!File::end(event)) {
292 string event_line = File::fgets(event);
293 if (String::index(event_line, "delete") >= 0)
298 #for (int y = 0; y < 20; y++)
301 show(cairo_t cr, test t)
303 rectangle(cr, 0, 0, 40, 40);
304 set_source_rgba(cr, 1, 1, 1, 1);
307 set_source_rgba(cr, 0, 1, 0, .2);
308 set_line_width(cr, 0.1);
309 for (int x = 0; x < 40; x++) {
317 rectangle(cr, t.b.x1, t.b.y1, t.b.x2 - t.b.x1, t.b.y2 - t.b.y1);
318 set_line_width(cr, 0.1);
319 set_source_rgba(cr, 0, 0, 0, 1);
322 move_to(cr, t.x1+.5, t.y1+.5);
323 line_to(cr, t.x2+.5, t.y2+.5);
324 move_to(cr, t.x2, t.y2);
325 line_to(cr, t.x2+1, t.y2+1);
326 move_to(cr, t.x2+1, t.y2);
327 line_to(cr, t.x2, t.y2+1);
330 void pixels(point[] pt) {
331 for (int i = 0; i < dim(pt); i++) {
332 rectangle(cr, pt[i].x, pt[i].y, 1, 1);
337 set_source_rgba(cr, 1, 0, 0, .5);
340 set_source_rgba(cr, 0, 0, 1, .5);
347 if (dim(t.clipped) != dim(t.run))
350 for (int i = 0; i < dim(t.clipped); i++)
351 if (t.clipped[i] != t.run[i])
362 cairo_t cr = new(800, 800);
368 int x1 = PRNG::randint(40);
369 int x2 = PRNG::randint(40);
370 int y1 = PRNG::randint(40);
371 int y2 = PRNG::randint(40);
373 test t = line (x1, y1, x2, y2, &bounds);
376 printf("line %d -- %d x %d - %d x %d\n", i, x1, y1, x2, y2);