1 #include <stdlib.h>
2 #include <memory.h>
3 #include <math.h>
4 #include "../../config.h"
5 #include "../q.h"
6 #include "../types.h"
7 #include "active.h"
8
actlist_new()9 actlist_t* actlist_new()
10 {
11 NEW(actlist_t, a);
12 return a;
13 }
actlist_destroy(actlist_t * a)14 void actlist_destroy(actlist_t*a)
15 {
16 free(a);
17 }
18
actlist_dump(actlist_t * a,int32_t y,double gridsize)19 void actlist_dump(actlist_t*a, int32_t y, double gridsize)
20 {
21 segment_t*s = a->list;
22 double lastx;
23 char bad = 0;
24 if(!s) fprintf(stderr, "(empty)\n");
25 while(s) {
26 if(y) {
27 double x = ((double)s->delta.x*(y-s->a.y)/s->delta.y)+s->a.x;
28 if(s!=a->list) {
29 if(lastx>x)
30 fprintf(stderr, "?%.2f<->%.2f? ", lastx * gridsize, x * gridsize);
31 }
32 lastx = x;
33 }
34 fprintf(stderr, "[%d]", (int)s->nr);
35 s = s->right;
36 if(s) fprintf(stderr, " ");
37 else fprintf(stderr, " y=%.2f\n", y * gridsize);
38 }
39 }
actlist_verify(actlist_t * a,int32_t y)40 void actlist_verify(actlist_t*a, int32_t y)
41 {
42 segment_t*s = a->list;
43 assert(!s || !s->left);
44 segment_t*l = 0;
45 while(s) {
46 if(y) {
47 if(l) {
48 /* we need to re-evaluate the x of the previous segment. if we
49 try to store it, it might end up being converted to a double,
50 which will make it non-equal to (and possibly larger than) the
51 "long double" the FPU has in its register. This only happens
52 when compiler optimizations are turned on. */
53 assert((XPOS(s, y) - XPOS(l, y)) >= 0);
54 assert(XDIFF(s,l,y) >= 0);
55 }
56 l = s;
57 }
58 assert(!s->left || s->left->right == s);
59 assert(!s->right || s->right->left == s);
60 s = s->right;
61 }
62 }
63
single_cmp(segment_t * s,point_t p1)64 static inline double single_cmp(segment_t*s, point_t p1)
65 {
66 return LINE_EQ(p1, s);
67 }
68
cmp(segment_t * s,point_t p1,point_t p2)69 static inline double cmp(segment_t*s, point_t p1, point_t p2)
70 {
71 double d = LINE_EQ(p1, s);
72 if(d==0) {
73 d = LINE_EQ(p2, s);
74 if(d==0) {
75 /* We default to always inserting the new segment to the right of the old segment.
76 We do this so that we don't place new segments into the middle of already
77 overlapping lines which may have intersections scheduled.
78 */
79 //fprintf(stderr, "Notice: actlist_find: both points (%d,%d) and (%d,%d) exactly on segment [%d]\n", p1.x, p1.y, p2.x, p2.y, s->nr);
80 }
81 }
82 return d;
83 }
84
85 #ifdef SPLAY
86 static void actlist_splay_dump(actlist_t*a);
actlist_find(actlist_t * a,point_t p1,point_t p2)87 segment_t* actlist_find(actlist_t*a, point_t p1, point_t p2)
88 {
89 #ifdef CHECKS
90 segment_t*t = a->list;
91 char to_the_left = 0;
92 char fail = 0;
93 while(t) {
94 /* this check doesn't work out with cmp() because during horizontal
95 processing, both segments ending as well as segments starting will
96 be active in this scanline */
97 //double d = cmp(t, p1, p2);
98 double d = single_cmp(t, p1);
99 if(d>=0 && to_the_left) {
100 actlist_dump(a, p1.y, 1);
101 segment_t*s = a->list;
102 while(s) {
103 fprintf(stderr, "[%d] %f/%f (%d,%d) -> (%d,%d)\n", SEGNR(s),
104 single_cmp(s,p1), cmp(s,p1,p2),
105 s->a.x, s->a.y, s->b.x, s->b.y);
106 s = s->right;
107 }
108 }
109 assert(!(d>=0 && to_the_left));
110 if(d<0) to_the_left=1;
111 t = t->right;
112 }
113 #if 0
114 if(a->size > 100) {
115 static actlist_t*last = 0;
116 if(last != a) {
117 last = a;
118 actlist_splay_dump(a);
119 }
120 }
121 #endif
122 #endif
123 segment_t*last=0, *s = a->root;
124 if(!s) return 0;
125 double d=0;
126 int depth = 0;
127 while(s) {
128 last = s;
129 depth++;
130 d = single_cmp(s, p1);
131 if(d<=0) {
132 s = s->leftchild;
133 } else {
134 s = s->rightchild;
135 }
136 }
137 //#ifdef DEBUG
138 #if 0
139 if(a->size > 1) {
140 /* 80% hit, average cost per miss ~ 4 nodes */
141 int expected_depth = (int)((double)log2((double)a->size+1))+1;
142 static int hits = 0;
143 static int misses = 0;
144 static int miss_cost = 0;
145 if(depth <= expected_depth) hits++;
146 else {misses++;
147 miss_cost += depth - expected_depth;
148 }
149 if(hits && misses)
150 fprintf(stderr, "%02.2f%% %f\n", hits / (double)(hits+misses), miss_cost / (double)misses);
151 }
152 #endif
153
154 /* this can be optimized for (is not needed in) normal mode (as opposed to horizontal postprocess mode) */
155 segment_t*out = last;
156 if(d<0 || (d==0 && LINE_EQ(p2,last)<0)) {
157 last = last->left;
158 if(!last) {
159 assert(cmp(a->list, p1, p2)<0);
160 return 0;
161 }
162 } else {
163 while(last->right && cmp(last->right, p1, p2)>=0) {
164 last = last->right;
165 }
166 }
167
168 #ifdef CHECKS
169 segment_t*l=0;
170 s = a->list;
171 while(s) {
172 if(cmp(s, p1, p2)<0)
173 break;
174 l = s;s = s->right;
175 }
176 if(l!=last) {
177 printf("[%d]!=[%d]\n", SEGNR(l), SEGNR(last));
178 printf("after tree: [%d]\n", SEGNR(out));
179 actlist_splay_dump(a);
180 s = a->list;
181 while(s) {
182 double d1 = single_cmp(s,p1);
183 double d2 = cmp(s,p1,p2);
184 int x1 = d1<0?-1:(d1>0?1:0);
185 int x2 = d2<0?-1:(d2>0?1:0);
186 printf("[%d](%d,%d) ", SEGNR(s), x1, x2);
187 s = s->right;
188 }
189 printf("\n");
190 }
191 assert(l == last);
192 #endif
193
194 return last;
195 }
196 #else
actlist_find(actlist_t * a,point_t p1,point_t p2)197 segment_t* actlist_find(actlist_t*a, point_t p1, point_t p2)
198 {
199 segment_t*last=0, *s = a->list;
200 if(!s) return last;
201 while(s) {
202 double d = cmp(s, p1, p2);
203 if(d<0)
204 break;
205 last = s;
206 s = s->right;
207 }
208 return last;
209 }
210 #endif
211
212 #ifdef SPLAY
213
214 #define LINK(node,side,child) (node)->side = (child);if(child) {(child)->parent = (node);}
215 //;fprintf(stderr, "[%d]->%s now [%d]\n", SEGNR(node), __STRING(side), SEGNR(child));
216
217 // rotates segment's left node to the top
rotate_right(actlist_t * a,segment_t * s)218 static inline segment_t*rotate_right(actlist_t*a, segment_t*s)
219 {
220 /* s n
221 / \
222 n -> s
223 \ /
224 l l
225 */
226 assert(s->leftchild);
227 segment_t*p = s->parent;
228 segment_t*n = s->leftchild;
229 segment_t*l = n->rightchild;
230 LINK(n,rightchild,s);
231 LINK(s,leftchild,l);
232 n->parent = p;
233 if(p) {
234 if(p->leftchild == s)
235 p->leftchild = n;
236 else if(p->rightchild == s)
237 p->rightchild = n;
238 } else {
239 a->root = n;
240 }
241 return n;
242 }
243 // rotates segment's right node to the top
rotate_left(actlist_t * a,segment_t * s)244 static inline segment_t*rotate_left(actlist_t*a, segment_t*s)
245 {
246 /* s n
247 \ /
248 n -> s
249 / \
250 r r
251 */
252 assert(s->rightchild);
253 segment_t*p = s->parent;
254 segment_t*n = s->rightchild;
255 segment_t*r = n->leftchild;
256 LINK(n,leftchild,s);
257 LINK(s,rightchild,r);
258 n->parent = p;
259 if(p) {
260 if(p->leftchild == s)
261 p->leftchild = n;
262 else if(p->rightchild == s)
263 p->rightchild = n;
264 } else {
265 a->root = n;
266 }
267 return n;
268 }
269
actlist_splay_walk(actlist_t * a,segment_t * s,segment_t ** ss,segment_t * parent)270 static int actlist_splay_walk(actlist_t*a, segment_t*s, segment_t**ss, segment_t*parent)
271 {
272 if(!s) return 1;
273 if(parent != s->parent) {
274 fprintf(stderr, "Parent mismatch in [%d]: [%d] != [%d]\n", SEGNR(s), SEGNR(parent), SEGNR(s->parent));
275 return 0;
276 }
277 if(!actlist_splay_walk(a, s->leftchild, ss, s)) return 0;
278 if(s != *ss) {
279 fprintf(stderr, "[%d] != [%d]\n", SEGNR(s), SEGNR(*ss));
280 return 0;
281 }
282 (*ss) = (*ss)->right;
283 if(!actlist_splay_walk(a, s->rightchild, ss, s)) return 0;
284 return 1;
285 }
286
actlist_splay_verify(actlist_t * a)287 static int actlist_splay_verify(actlist_t*a)
288 {
289 segment_t*c = a->list;
290 if(!actlist_splay_walk(a, a->root, &c, 0)) return 0;
291 if(c) return 0;
292 return 1;
293 }
actlist_splay_dump2(actlist_t * a,segment_t * s,char * mid,char * up,char * down)294 static void actlist_splay_dump2(actlist_t*a, segment_t*s, char*mid, char*up, char*down)
295 {
296 if(!s) return;
297
298 if(s->leftchild || s->rightchild) {
299 int t;
300
301 if(s->leftchild) {
302 char*o3 = malloc(strlen(up)+3);
303 strcpy(o3, up);strcat(o3, "+-");
304 char*newup = malloc(strlen(up)+3);
305 strcpy(newup, up);strcat(newup, "| ");
306 char*newup2 = malloc(strlen(up)+3);
307 strcpy(newup2, up);strcat(newup2, " ");
308 actlist_splay_dump2(a, s->leftchild, o3, newup2, newup);
309 fprintf(stderr, "%s| \n", up);
310 free(newup);
311 free(newup2);
312 free(o3);
313 }
314 fprintf(stderr, "%s[%d]\n", mid, SEGNR(s));
315 if(s->rightchild) {
316 char*o3 = malloc(strlen(down)+3);
317 strcpy(o3, down);strcat(o3, "+-");
318 char*newdown = malloc(strlen(down)+3);
319 strcpy(newdown, down);strcat(newdown, "| ");
320 char*newdown2 = malloc(strlen(down)+3);
321 strcpy(newdown2, down);strcat(newdown2, " ");
322 fprintf(stderr, "%s| \n", down);
323 actlist_splay_dump2(a, s->rightchild, o3, newdown, newdown2);
324 free(newdown);
325 free(newdown2);
326 free(o3);
327 }
328 } else {
329 fprintf(stderr, "%s[%d]\n", mid, SEGNR(s));
330 }
331 }
actlist_splay_dump(actlist_t * a)332 static void actlist_splay_dump(actlist_t*a)
333 {
334 actlist_splay_dump2(a, a->root, "", "", "");
335 }
336
337
move_to_root(actlist_t * a,segment_t * s)338 static void move_to_root(actlist_t*a, segment_t*s)
339 {
340 if(!s) return;
341 /* this is a textbook implementation of the three splay operations
342 zig, zig-zig and zig-zag */
343 int nr=0;
344 while(a->root != s) {
345 assert(s->parent);
346 segment_t*p = s->parent;
347 if(p == a->root) {
348 // zig
349 if(a->root->leftchild == s) {
350 rotate_right(a, a->root);
351 } else {
352 rotate_left(a, a->root);
353 }
354 assert(a->root == s);
355 } else {
356 segment_t*pp = p->parent;
357 if(p->leftchild == s && pp->leftchild == p) {
358 // zig-zig (left)
359 rotate_right(a, pp);
360 rotate_right(a, s->parent);
361 } else if(p->rightchild == s && pp->rightchild == p) {
362 // zig-zig (right)
363 rotate_left(a, pp);
364 rotate_left(a, s->parent);
365 } else if(p->leftchild == s && pp->rightchild == p) {
366 // zig-zag (left)
367 rotate_right(a, p);
368 rotate_left(a, s->parent);
369 } else if(p->rightchild == s && pp->leftchild == p) {
370 // zig-zag (right)
371 rotate_left(a, p);
372 rotate_right(a, s->parent);
373 } else {
374 assert(0);
375 }
376 }
377 }
378 }
379
actlist_splay(actlist_t * a,point_t p1,point_t p2)380 static void actlist_splay(actlist_t*a, point_t p1, point_t p2)
381 {
382 if(!a->list) return;
383
384 segment_t tmp;
385 memset(&tmp, 0, sizeof(tmp));
386 segment_t*left=&tmp,*right=&tmp;
387
388 int c = 0;
389 while(1) {
390 if(cmp(a->root,p1,p2)<0) {
391 /* we're to the left of the root */
392 if(!a->root->leftchild) {
393 c = -1;break;
394 }
395 if(cmp(a->root->leftchild,p1,p2)<0) {
396 /* we're also to the left of the root's left child
397 -> rotate right, so that the left child is root */
398 segment_t*s = a->root->leftchild;
399 LINK(a->root, leftchild, s->rightchild);
400 LINK(s, rightchild, a->root);
401 a->root = s;
402 if(!a->root->leftchild) {
403 c = -1;break;
404 }
405 }
406 LINK(right, leftchild, a->root);
407 right = a->root;
408 a->root = a->root->leftchild;
409 } else /* cmp(a->root,p1,p2)>=0 */ {
410 /* we're to the right of the root */
411 if(!a->root->rightchild) {
412 c = 1;break;
413 }
414 if(cmp(a->root->rightchild,p1,p2)>=0) {
415 /* we're also to the right of the root's right child
416 -> rotate left, so that the right child is root */
417 segment_t*s = a->root->rightchild;
418 LINK(a->root, rightchild, s->leftchild);
419 LINK(s, leftchild, a->root);
420 a->root = s;
421 if(!a->root->rightchild)
422 c = 1;break;
423 }
424 LINK(left, rightchild, a->root);
425 left = a->root;
426 a->root = a->root->rightchild;
427 }
428 }
429 LINK(left, rightchild, a->root->leftchild);
430 LINK(right, leftchild, a->root->rightchild);
431 LINK(a->root, leftchild, tmp.rightchild);
432 LINK(a->root, rightchild, tmp.leftchild);
433 a->root->parent = 0;
434 }
435
436 #endif
437
actlist_insert_after(actlist_t * a,segment_t * left,segment_t * s)438 static void actlist_insert_after(actlist_t*a, segment_t*left, segment_t*s)
439 {
440 #ifdef SPLAY
441 //fprintf(stderr, "insert [%d] after [%d]\n", SEGNR(s), SEGNR(left));
442 //actlist_splay_dump(a);
443 //actlist_dump(a, s->a.y);
444 #endif
445
446 s->left = left;
447 if(left) {
448 s->right = left->right;
449 } else {
450 s->right = a->list;
451 a->list = s;
452 }
453 if(s->left)
454 s->left->right = s;
455 if(s->right)
456 s->right->left = s;
457
458 #ifdef SPLAY
459 // we insert nodes not trees
460 assert(!s->leftchild);
461 assert(!s->rightchild);
462
463 if(a->root) {
464 move_to_root(a, left);
465 if(left) {
466 LINK(s,leftchild,a->root);
467 // steal right child from (previous) root
468 LINK(s,rightchild,a->root->rightchild);
469 a->root->rightchild = 0;
470 } else {
471 LINK(s,rightchild,a->root);
472 }
473 }
474 a->root = s;
475 a->root->parent = 0;
476
477 assert(actlist_splay_verify(a));
478 #endif
479
480 a->size++;
481 }
482
actlist_delete(actlist_t * a,segment_t * s)483 void actlist_delete(actlist_t*a, segment_t*s)
484 {
485 #ifdef SPLAY
486 assert(actlist_splay_verify(a));
487 move_to_root(a, s);
488 assert(actlist_splay_verify(a));
489 #endif
490 if(s->left) {
491 s->left->right = s->right;
492 } else {
493 a->list = s->right;
494 }
495 if(s->right) {
496 s->right->left = s->left;
497 }
498 s->left = s->right = 0;
499 a->size--;
500 #ifdef SPLAY
501 assert(a->root == s);
502 // delete root node
503 if(!a->root->leftchild) {
504 a->root = a->root->rightchild;
505 } else if(!a->root->rightchild) {
506 a->root = a->root->leftchild;
507 } else {
508 #ifdef HAVE_LRAND48
509 if(lrand48()&1) {
510 #else
511 if(((ptroff_t)s)&16) {
512 #endif
513 // free up root->left->right
514 segment_t*t = a->root->leftchild;
515 while(t->rightchild) {
516 segment_t*r = t->rightchild;
517 segment_t*l = r->leftchild;
518 LINK(r, leftchild, t);
519 LINK(t, rightchild, l);
520 t = r;
521 }
522 LINK(a->root,leftchild,t);
523 assert(!a->root->leftchild->rightchild);
524 LINK(a->root->leftchild,rightchild,a->root->rightchild);
525 a->root = a->root->leftchild;
526 } else {
527 // free up root->right->left
528 segment_t*t = a->root->rightchild;
529 while(t->leftchild) {
530 segment_t*l = t->leftchild;
531 segment_t*r = l->rightchild;
532 LINK(l, rightchild, t);
533 LINK(t, leftchild, r);
534 t = l;
535 }
536 LINK(a->root,rightchild,t);
537 assert(!a->root->rightchild->leftchild);
538 LINK(a->root->rightchild,leftchild,a->root->leftchild);
539 a->root = a->root->rightchild;
540 }
541 }
542 if(a->root)
543 a->root->parent = 0;
544 s->leftchild = s->rightchild = s->parent = 0;
545
546 assert(actlist_splay_verify(a));
547 #endif
548 }
549 int actlist_size(actlist_t*a)
550 {
551 return a->size;
552 }
553
554 segment_t* actlist_leftmost(actlist_t*a)
555 {
556 return a->list;
557 }
558
559 segment_t* actlist_rightmost(actlist_t*a)
560 {
561 /* this is only used in checks, so it doesn't matter that it's slow */
562 #ifndef CHECKS
563 fprintf(stderr, "Warning: actlist_rightmost should not be used\n");
564 #endif
565 segment_t*s = a->list;
566 segment_t*last = 0;
567 while(s) {
568 last = s;
569 s = s->right;
570 }
571 return last;
572 }
573
574 void actlist_insert(actlist_t*a, point_t p1, point_t p2, segment_t*s)
575 {
576 segment_t*left = actlist_find(a, p1, p2);
577 actlist_insert_after(a, left, s);
578 }
579
580 void actlist_swap(actlist_t*a, segment_t*s1, segment_t*s2)
581 {
582 #ifdef SPLAY
583 assert(actlist_splay_verify(a));
584 #endif
585 #ifdef CHECKS
586 /* test that s1 is to the left of s2- our swap
587 code depends on that */
588 segment_t*s = s1;
589 while(s && s!=s2) s = s->right;
590 assert(s==s2);
591 #endif
592 /*#ifndef SPLAY
593 actlist_delete(a, s1);
594 actlist_insert_after(a, s2, s1);
595 #else*/
596 segment_t*s1l = s1->left;
597 segment_t*s1r = s1->right;
598 segment_t*s2l = s2->left;
599 segment_t*s2r = s2->right;
600 if(s1l) s1l->right = s2;
601 else a->list = s2;
602 s2->left = s1l;
603 if(s2r) s2r->left = s1;
604 s1->right = s2r;
605 if(s2l!=s1) s1->left = s2l;
606 else s1->left = s2;
607 if(s1r!=s2) s2->right = s1r;
608 else s2->right = s1;
609
610 #ifdef SPLAY
611 if(s2->parent==s1) {
612 /*
613 s1 s2
614 / -> /
615 s2 s1
616 */
617 segment_t*l = s2->leftchild;
618 segment_t*r = s2->rightchild;
619 assert(s1->rightchild == s2); // because s1 < s2
620 segment_t*l1 = s1->leftchild;
621 segment_t*p = s1->parent;
622 s1->parent = s2;
623 s2->parent = p;
624 if(p) {
625 if(p->leftchild == s1) p->leftchild=s2;
626 else {assert(p->rightchild == s1);p->rightchild=s2;}
627 } else {
628 a->root = s2;
629 }
630 s2->leftchild = l1;
631 s2->rightchild = s1;
632 s1->leftchild = l;
633 s1->rightchild = r;
634 } else if(s1->parent==s2) {
635 /*
636 s2 s1
637 / -> /
638 s1 s2
639 */
640 segment_t*l = s1->leftchild;
641 segment_t*r = s1->rightchild;
642 segment_t*r2 = s2->rightchild;
643 assert(s2->leftchild == s1); // because s1 < s2
644 segment_t*p = s2->parent;
645 s2->parent = s1;
646 s1->parent = p;
647 if(p) {
648 if(p->leftchild == s2) p->leftchild=s1;
649 else {assert(p->rightchild == s2);p->rightchild=s1;}
650 } else {
651 a->root = s1;
652 }
653 s1->leftchild = s2;
654 s1->rightchild = r2;
655 s2->leftchild = l;
656 s2->rightchild = r;
657 } else {
658 segment_t*s1p = s1->parent;
659 segment_t*s1l = s1->leftchild;
660 segment_t*s1r = s1->rightchild;
661 segment_t*s2p = s2->parent;
662 segment_t*s2l = s2->leftchild;
663 segment_t*s2r = s2->rightchild;
664 s2->parent = s1p;
665 s2->leftchild = s1l;
666 s2->rightchild = s1r;
667 s1->parent = s2p;
668 s1->leftchild = s2l;
669 s1->rightchild = s2r;
670 assert(s1p || s2p);
671 if(s1p) {
672 if(s1p->leftchild == s1) s1p->leftchild=s2;
673 else {assert(s1p->rightchild == s1);s1p->rightchild=s2;}
674 } else {
675 a->root = s2;
676 }
677 if(s2p) {
678 if(s2p->leftchild == s2) s2p->leftchild=s1;
679 else {assert(s2p->rightchild == s2);s2p->rightchild=s1;}
680 } else {
681 a->root = s1;
682 }
683 }
684 if(s1->leftchild) s1->leftchild->parent = s1;
685 if(s2->leftchild) s2->leftchild->parent = s2;
686 if(s1->rightchild) s1->rightchild->parent = s1;
687 if(s2->rightchild) s2->rightchild->parent = s2;
688
689 assert(actlist_splay_verify(a));
690 #endif
691
692 //#endif
693 }
694