7 actlist_t* actlist_new()
12 void actlist_destroy(actlist_t*a)
17 void actlist_dump(actlist_t*a, int32_t y)
19 segment_t*s = a->list;
22 if(!s) fprintf(stderr, "(empty)\n");
25 double x = ((double)s->delta.x*(y-s->a.y)/s->delta.y)+s->a.x;
28 fprintf(stderr, "?%f<->%f? ", lastx, x);
32 fprintf(stderr, "[%d]", s->nr);
34 if(s) fprintf(stderr, " ");
35 else fprintf(stderr, "\n");
38 void actlist_verify(actlist_t*a, int32_t y)
40 segment_t*s = a->list;
41 assert(!s || !s->left);
46 /* we need to re-evaluate the x of the previous segment. if we
47 try to store it, it might end up being converted to a double,
48 which will make it non-equal to (and possibly larger than) the
49 "long double" the FPU has in it's register. This only happens
50 when compiler optimizations are turned on. */
51 assert((XPOS(s, y) - XPOS(l, y)) >= 0);
52 assert(XDIFF(s,l,y) >= 0);
56 assert(!s->left || s->left->right == s);
57 assert(!s->right || s->right->left == s);
62 static inline double single_cmp(segment_t*s, point_t p1)
64 return LINE_EQ(p1, s);
67 static inline double cmp(segment_t*s, point_t p1, point_t p2)
69 double d = LINE_EQ(p1, s);
73 /* We default to always inserting the new segment to the right of the old segment.
74 We do this so that we don't place new segments into the middle of already
75 overlapping lines which may have intersections scheduled.
77 //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);
84 static void actlist_splay_dump(actlist_t*a);
85 segment_t* actlist_find(actlist_t*a, point_t p1, point_t p2)
88 segment_t*t = a->list;
92 /* this check doesn't work out with cmp() because during horizontal
93 processing, both segments ending as well as segments starting will
94 be active in this scanline */
95 //double d = cmp(t, p1, p2);
96 double d = single_cmp(t, p1);
97 if(d>=0 && to_the_left) {
98 segment_t*s = a->list;
100 fprintf(stderr, "[%d] %f/%f (%d,%d) -> (%d,%d)\n", s->nr,
101 single_cmp(s,p1), cmp(s,p1,p2),
102 s->a.x, s->a.y, s->b.x, s->b.y);
106 assert(!(d>=0 && to_the_left));
107 if(d<0) to_the_left=1;
112 static actlist_t*last = 0;
115 actlist_splay_dump(a);
120 segment_t*last=0, *s = a->root;
127 d = single_cmp(s, p1);
137 /* 80% hit, average cost per miss ~ 4 nodes */
138 int expected_depth = (int)((double)log2((double)a->size+1))+1;
140 static int misses = 0;
141 static int miss_cost = 0;
142 if(depth <= expected_depth) hits++;
144 miss_cost += depth - expected_depth;
147 fprintf(stderr, "%02.2f%% %f\n", hits / (double)(hits+misses), miss_cost / (double)misses);
151 segment_t*out = last;
152 if(d<0 || (d==0 && LINE_EQ(p2,last)<0)) {
155 assert(cmp(a->list, p1, p2)<0);
159 while(last->right && cmp(last->right, p1, p2)>=0) {
173 printf("[%d]!=[%d]\n", SEGNR(l), SEGNR(last));
174 printf("after tree: [%d]\n", SEGNR(out));
175 actlist_splay_dump(a);
178 double d1 = single_cmp(s,p1);
179 double d2 = cmp(s,p1,p2);
180 int x1 = d1<0?-1:(d1>0?1:0);
181 int x2 = d2<0?-1:(d2>0?1:0);
182 printf("[%d](%d,%d) ", SEGNR(s), x1, x2);
193 segment_t* actlist_find(actlist_t*a, point_t p1, point_t p2)
195 segment_t*last=0, *s = a->list;
198 double d = cmp(s, p1, p2);
210 #define LINK(node,side,child) (node)->side = (child);if(child) {(child)->parent = (node);}
211 //;fprintf(stderr, "[%d]->%s now [%d]\n", SEGNR(node), __STRING(side), SEGNR(child));
213 // rotates segment's left node to the top
214 static inline segment_t*rotate_right(actlist_t*a, segment_t*s)
222 assert(s->leftchild);
223 segment_t*p = s->parent;
224 segment_t*n = s->leftchild;
225 segment_t*l = n->rightchild;
226 LINK(n,rightchild,s);
230 if(p->leftchild == s)
232 else if(p->rightchild == s)
239 // rotates segment's right node to the top
240 static inline segment_t*rotate_left(actlist_t*a, segment_t*s)
248 assert(s->rightchild);
249 segment_t*p = s->parent;
250 segment_t*n = s->rightchild;
251 segment_t*r = n->leftchild;
253 LINK(s,rightchild,r);
256 if(p->leftchild == s)
258 else if(p->rightchild == s)
266 static int actlist_splay_walk(actlist_t*a, segment_t*s, segment_t**ss, segment_t*parent)
269 if(parent != s->parent) {
270 fprintf(stderr, "Parent mismatch in [%d]: [%d] != [%d]\n", SEGNR(s), SEGNR(parent), SEGNR(s->parent));
273 if(!actlist_splay_walk(a, s->leftchild, ss, s)) return 0;
275 fprintf(stderr, "[%d] != [%d]\n", SEGNR(s), SEGNR(*ss));
278 (*ss) = (*ss)->right;
279 if(!actlist_splay_walk(a, s->rightchild, ss, s)) return 0;
283 static int actlist_splay_verify(actlist_t*a)
285 segment_t*c = a->list;
286 if(!actlist_splay_walk(a, a->root, &c, 0)) return 0;
290 static void actlist_splay_dump2(actlist_t*a, segment_t*s, char*mid, char*up, char*down)
294 if(s->leftchild || s->rightchild) {
298 char*o3 = malloc(strlen(up)+3);
299 strcpy(o3, up);strcat(o3, "+-");
300 char*newup = malloc(strlen(up)+3);
301 strcpy(newup, up);strcat(newup, "| ");
302 char*newup2 = malloc(strlen(up)+3);
303 strcpy(newup2, up);strcat(newup2, " ");
304 actlist_splay_dump2(a, s->leftchild, o3, newup2, newup);
305 fprintf(stderr, "%s| \n", up);
310 fprintf(stderr, "%s[%d]\n", mid, SEGNR(s));
312 char*o3 = malloc(strlen(down)+3);
313 strcpy(o3, down);strcat(o3, "+-");
314 char*newdown = malloc(strlen(down)+3);
315 strcpy(newdown, down);strcat(newdown, "| ");
316 char*newdown2 = malloc(strlen(down)+3);
317 strcpy(newdown2, down);strcat(newdown2, " ");
318 fprintf(stderr, "%s| \n", down);
319 actlist_splay_dump2(a, s->rightchild, o3, newdown, newdown2);
325 fprintf(stderr, "%s[%d]\n", mid, SEGNR(s));
328 static void actlist_splay_dump(actlist_t*a)
330 actlist_splay_dump2(a, a->root, "", "", "");
334 static void move_to_root(actlist_t*a, segment_t*s)
337 /* this is a textbook implementation of the three splay operations
338 zig, zig-zig and zig-zag */
340 while(a->root != s) {
342 segment_t*p = s->parent;
345 if(a->root->leftchild == s) {
346 rotate_right(a, a->root);
348 rotate_left(a, a->root);
350 assert(a->root == s);
352 segment_t*pp = p->parent;
353 if(p->leftchild == s && pp->leftchild == p) {
356 rotate_right(a, s->parent);
357 } else if(p->rightchild == s && pp->rightchild == p) {
360 rotate_left(a, s->parent);
361 } else if(p->leftchild == s && pp->rightchild == p) {
364 rotate_left(a, s->parent);
365 } else if(p->rightchild == s && pp->leftchild == p) {
368 rotate_right(a, s->parent);
376 static int actlist_splay(actlist_t*a, point_t p1, point_t p2)
381 memset(&tmp, 0, sizeof(tmp));
382 segment_t*left=&tmp,*right=&tmp;
386 if(cmp(a->root,p1,p2)<0) {
387 /* we're to the left of the root */
388 if(!a->root->leftchild) {
391 if(cmp(a->root->leftchild,p1,p2)<0) {
392 /* we're also to the left of the root's left child
393 -> rotate right, so that the left child is root */
394 segment_t*s = a->root->leftchild;
395 LINK(a->root, leftchild, s->rightchild);
396 LINK(s, rightchild, a->root);
398 if(!a->root->leftchild) {
402 LINK(right, leftchild, a->root);
404 a->root = a->root->leftchild;
405 } else /* cmp(a->root,p1,p2)>=0 */ {
406 /* we're to the right of the root */
407 if(!a->root->rightchild) {
410 if(cmp(a->root->rightchild,p1,p2)>=0) {
411 /* we're also to the right of the root's right child
412 -> rotate left, so that the right child is root */
413 segment_t*s = a->root->rightchild;
414 LINK(a->root, rightchild, s->leftchild);
415 LINK(s, leftchild, a->root);
417 if(!a->root->rightchild)
420 LINK(left, rightchild, a->root);
422 a->root = a->root->rightchild;
425 LINK(left, rightchild, a->root->leftchild);
426 LINK(right, leftchild, a->root->rightchild);
427 LINK(a->root, leftchild, tmp.rightchild);
428 LINK(a->root, rightchild, tmp.leftchild);
434 static void actlist_insert_after(actlist_t*a, segment_t*left, segment_t*s)
437 //fprintf(stderr, "insert [%d] after [%d]\n", SEGNR(s), SEGNR(left));
438 //actlist_splay_dump(a);
439 //actlist_dump(a, s->a.y);
444 s->right = left->right;
455 // we insert nodes not trees
456 assert(!s->leftchild);
457 assert(!s->rightchild);
460 move_to_root(a, left);
462 LINK(s,leftchild,a->root);
463 // steal right child from (previous) root
464 LINK(s,rightchild,a->root->rightchild);
465 a->root->rightchild = 0;
467 LINK(s,rightchild,a->root);
473 assert(actlist_splay_verify(a));
479 void actlist_delete(actlist_t*a, segment_t*s)
482 assert(actlist_splay_verify(a));
484 assert(actlist_splay_verify(a));
487 s->left->right = s->right;
492 s->right->left = s->left;
494 s->left = s->right = 0;
497 assert(a->root == s);
499 if(!a->root->leftchild) {
500 a->root = a->root->rightchild;
501 } else if(!a->root->rightchild) {
502 a->root = a->root->leftchild;
505 // free up root->left->right
506 segment_t*t = a->root->leftchild;
507 while(t->rightchild) {
508 segment_t*r = t->rightchild;
509 segment_t*l = r->leftchild;
510 LINK(r, leftchild, t);
511 LINK(t, rightchild, l);
514 LINK(a->root,leftchild,t);
515 assert(!a->root->leftchild->rightchild);
516 LINK(a->root->leftchild,rightchild,a->root->rightchild);
517 a->root = a->root->leftchild;
519 // free up root->right->left
520 segment_t*t = a->root->rightchild;
521 while(t->leftchild) {
522 segment_t*l = t->leftchild;
523 segment_t*r = l->rightchild;
524 LINK(l, rightchild, t);
525 LINK(t, leftchild, r);
528 LINK(a->root,rightchild,t);
529 assert(!a->root->rightchild->leftchild);
530 LINK(a->root->rightchild,leftchild,a->root->leftchild);
531 a->root = a->root->rightchild;
536 s->leftchild = s->rightchild = s->parent = 0;
538 assert(actlist_splay_verify(a));
541 int actlist_size(actlist_t*a)
546 segment_t* actlist_leftmost(actlist_t*a)
551 segment_t* actlist_rightmost(actlist_t*a)
553 /* this is only used in checks, so it doesn't matter that it's slow */
555 fprintf(stderr, "Warning: actlist_rightmost should not be used\n");
557 segment_t*s = a->list;
566 void actlist_insert(actlist_t*a, point_t p1, point_t p2, segment_t*s)
568 segment_t*left = actlist_find(a, p1, p2);
569 actlist_insert_after(a, left, s);
572 void actlist_swap(actlist_t*a, segment_t*s1, segment_t*s2)
575 assert(actlist_splay_verify(a));
578 /* test that s1 is to the left of s2- our swap
579 code depends on that */
581 while(s && s!=s2) s = s->right;
585 actlist_delete(a, s1);
586 actlist_insert_after(a, s2, s1);
588 segment_t*s1l = s1->left;
589 segment_t*s1r = s1->right;
590 segment_t*s2l = s2->left;
591 segment_t*s2r = s2->right;
592 if(s1l) s1l->right = s2;
595 if(s2r) s2r->left = s1;
597 if(s2l!=s1) s1->left = s2l;
599 if(s1r!=s2) s2->right = s1r;
609 segment_t*l = s2->leftchild;
610 segment_t*r = s2->rightchild;
611 assert(s1->rightchild == s2); // because s1 < s2
612 segment_t*l1 = s1->leftchild;
613 segment_t*p = s1->parent;
617 if(p->leftchild == s1) p->leftchild=s2;
618 else {assert(p->rightchild == s1);p->rightchild=s2;}
626 } else if(s1->parent==s2) {
632 segment_t*l = s1->leftchild;
633 segment_t*r = s1->rightchild;
634 segment_t*r2 = s2->rightchild;
635 assert(s2->leftchild == s1); // because s1 < s2
636 segment_t*p = s2->parent;
640 if(p->leftchild == s2) p->leftchild=s1;
641 else {assert(p->rightchild == s2);p->rightchild=s1;}
650 segment_t*s1p = s1->parent;
651 segment_t*s1l = s1->leftchild;
652 segment_t*s1r = s1->rightchild;
653 segment_t*s2p = s2->parent;
654 segment_t*s2l = s2->leftchild;
655 segment_t*s2r = s2->rightchild;
658 s2->rightchild = s1r;
661 s1->rightchild = s2r;
664 if(s1p->leftchild == s1) s1p->leftchild=s2;
665 else {assert(s1p->rightchild == s1);s1p->rightchild=s2;}
670 if(s2p->leftchild == s2) s2p->leftchild=s1;
671 else {assert(s2p->rightchild == s2);s2p->rightchild=s1;}
676 if(s1->leftchild) s1->leftchild->parent = s1;
677 if(s2->leftchild) s2->leftchild->parent = s2;
678 if(s1->rightchild) s1->rightchild->parent = s1;
679 if(s2->rightchild) s2->rightchild->parent = s2;
681 assert(actlist_splay_verify(a));