5 actlist_t* actlist_new()
10 void actlist_destroy(actlist_t*a)
15 void actlist_dump(actlist_t*a, int32_t y)
17 segment_t*s = a->list;
20 if(!s) fprintf(stderr, "(empty)\n");
23 double x = ((double)s->delta.x*(y-s->a.y)/s->delta.y)+s->a.x;
26 fprintf(stderr, "?%f<->%f? ", lastx, x);
30 fprintf(stderr, "[%d]", s->nr);
32 if(s) fprintf(stderr, " ");
33 else fprintf(stderr, "\n");
36 void actlist_verify(actlist_t*a, int32_t y)
38 segment_t*s = a->list;
39 assert(!s || !s->left);
44 /* we need to re-evaluate the x of the previous segment. if we
45 try to store it, it might end up being converted to a double,
46 which will make it non-equal to (and possibly larger than) the
47 "long double" the FPU has in it's register. This only happens
48 when compiler optimizations are turned on. */
49 assert((XPOS(s, y) - XPOS(l, y)) >= 0);
50 assert(XDIFF(s,l,y) >= 0);
54 assert(!s->left || s->left->right == s);
55 assert(!s->right || s->right->left == s);
60 static inline double cmp(segment_t*s, point_t p1, point_t p2)
62 double d = LINE_EQ(p1, s);
66 /* We default to always inserting the new segment to the right of the old segment.
67 We do this so that we don't place new segments into the middle of already
68 overlapping lines which may have intersections scheduled.
70 //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);
76 segment_t* actlist_find(actlist_t*a, point_t p1, point_t p2)
78 /* this runs in O(n) right now, and should be optimized using a splay
79 tree to run in ammortized O(log(n))
80 (update: currently only 2.5% of the algorithm's running time is spent here,
81 so maybe we don't need to bother)
83 segment_t*last=0, *s = a->list;
86 double d = cmp(s, p1, p2);
95 #define SEGNR(s) ((s)?(s)->nr:-1)
98 #define LINK(node,side,child) (node)->side = (child);if(child) {(child)->parent = (node);}
99 //;fprintf(stderr, "[%d]->%s now [%d]\n", SEGNR(node), __STRING(side), SEGNR(child));
101 // rotates segment's left node to the top
102 static inline segment_t*rotate_right(actlist_t*a, segment_t*s)
110 assert(s->leftchild);
111 segment_t*p = s->parent;
112 segment_t*n = s->leftchild;
113 segment_t*l = n->rightchild;
114 LINK(n,rightchild,s);
118 if(p->leftchild == s)
120 else if(p->rightchild == s)
127 // rotates segment's right node to the top
128 static inline segment_t*rotate_left(actlist_t*a, segment_t*s)
136 assert(s->rightchild);
137 segment_t*p = s->parent;
138 segment_t*n = s->rightchild;
139 segment_t*r = n->leftchild;
141 LINK(s,rightchild,r);
144 if(p->leftchild == s)
146 else if(p->rightchild == s)
154 static int actlist_splay_walk(actlist_t*a, segment_t*s, segment_t**ss, segment_t*parent)
157 if(parent != s->parent) {
158 fprintf(stderr, "Parent mismatch in [%d]: [%d] != [%d]\n", SEGNR(s), SEGNR(parent), SEGNR(s->parent));
161 if(!actlist_splay_walk(a, s->leftchild, ss, s)) return 0;
163 fprintf(stderr, "[%d] != [%d]\n", SEGNR(s), SEGNR(*ss));
166 (*ss) = (*ss)->right;
167 if(!actlist_splay_walk(a, s->rightchild, ss, s)) return 0;
171 static int actlist_splay_verify(actlist_t*a)
173 segment_t*c = a->list;
174 if(!actlist_splay_walk(a, a->root, &c, 0)) return 0;
178 static void actlist_splay_dump2(actlist_t*a, segment_t*s, int indent)
182 if(s->leftchild || s->rightchild) {
183 fprintf(stderr, "(");
184 fprintf(stderr, "[%d]", SEGNR(s->leftchild));
186 actlist_splay_dump2(a, s->leftchild, indent+8);
188 fprintf(stderr, ",");
189 fprintf(stderr, "[%d]", SEGNR(s->rightchild));
191 actlist_splay_dump2(a, s->rightchild, indent+8);
193 fprintf(stderr, ")");
196 static void actlist_splay_dump(actlist_t*a)
198 fprintf(stderr, "[%d]", SEGNR(a->root));
199 actlist_splay_dump2(a, a->root, 1);
200 fprintf(stderr, "\n");
204 static void move_to_root(actlist_t*a, segment_t*s)
207 /* this is a textbook implementation of the three splay operations
208 zig, zig-zig and zig-zag */
210 while(a->root != s) {
212 segment_t*p = s->parent;
215 if(a->root->leftchild == s) {
216 rotate_right(a, a->root);
218 rotate_left(a, a->root);
220 assert(a->root == s);
222 segment_t*pp = p->parent;
223 if(p->leftchild == s && pp->leftchild == p) {
226 rotate_right(a, s->parent);
227 } else if(p->rightchild == s && pp->rightchild == p) {
230 rotate_left(a, s->parent);
231 } else if(p->leftchild == s && pp->rightchild == p) {
234 rotate_left(a, s->parent);
235 } else if(p->rightchild == s && pp->leftchild == p) {
238 rotate_right(a, s->parent);
246 static int actlist_splay(actlist_t*a, point_t p1, point_t p2)
251 memset(&tmp, 0, sizeof(tmp));
252 segment_t*left=&tmp,*right=&tmp;
256 if(cmp(a->root,p1,p2)<0) {
257 /* we're to the left of the root */
258 if(!a->root->leftchild) {
261 if(cmp(a->root->leftchild,p1,p2)<0) {
262 /* we're also to the left of the root's left child
263 -> rotate right, so that the left child is root */
264 segment_t*s = a->root->leftchild;
265 LINK(a->root, leftchild, s->rightchild);
266 LINK(s, rightchild, a->root);
268 if(!a->root->leftchild) {
272 LINK(right, leftchild, a->root);
274 a->root = a->root->leftchild;
275 } else /* cmp(a->root,p1,p2)>=0 */ {
276 /* we're to the right of the root */
277 if(!a->root->rightchild) {
280 if(cmp(a->root->rightchild,p1,p2)>=0) {
281 /* we're also to the right of the root's right child
282 -> rotate left, so that the right child is root */
283 segment_t*s = a->root->rightchild;
284 LINK(a->root, rightchild, s->leftchild);
285 LINK(s, leftchild, a->root);
287 if(!a->root->rightchild)
290 LINK(left, rightchild, a->root);
292 a->root = a->root->rightchild;
295 LINK(left, rightchild, a->root->leftchild);
296 LINK(right, leftchild, a->root->rightchild);
297 LINK(a->root, leftchild, tmp.rightchild);
298 LINK(a->root, rightchild, tmp.leftchild);
304 static void actlist_insert_after(actlist_t*a, segment_t*left, segment_t*s)
307 //fprintf(stderr, "insert [%d] after [%d]\n", SEGNR(s), SEGNR(left));
308 //actlist_splay_dump(a);
309 //actlist_dump(a, s->a.y);
314 s->right = left->right;
325 // we insert nodes not trees
326 assert(!s->leftchild);
327 assert(!s->rightchild);
330 move_to_root(a, left);
333 LINK(s,leftchild,a->root);
334 // steal right child from (previous) root
335 LINK(s,rightchild,a->root->rightchild);
336 a->root->rightchild = 0;
338 LINK(s,rightchild,a->root);
341 /*if(cmp(a->root, s->a, s->b) < 0) {
342 LINK(s,rightchild,a->root);
343 // steal left child from (previous) root
344 LINK(s,leftchild,a->root->leftchild);
345 a->root->leftchild = 0;
347 LINK(s,leftchild,a->root);
348 // steal right child from (previous) root
349 LINK(s,rightchild,a->root->rightchild);
350 a->root->rightchild = 0;
356 assert(actlist_splay_verify(a));
362 void actlist_delete(actlist_t*a, segment_t*s)
365 assert(actlist_splay_verify(a));
367 assert(actlist_splay_verify(a));
370 s->left->right = s->right;
375 s->right->left = s->left;
377 s->left = s->right = 0;
380 assert(a->root == s);
382 if(!a->root->leftchild) {
383 a->root = a->root->rightchild;
384 } else if(!a->root->rightchild) {
385 a->root = a->root->leftchild;
388 // free up root->left->right
389 segment_t*t = a->root->leftchild;
390 while(t->rightchild) {
391 segment_t*r = t->rightchild;
392 segment_t*l = r->leftchild;
393 LINK(r, leftchild, t);
394 LINK(t, rightchild, l);
397 LINK(a->root,leftchild,t);
398 assert(!a->root->leftchild->rightchild);
399 LINK(a->root->leftchild,rightchild,a->root->rightchild);
400 a->root = a->root->leftchild;
402 // free up root->right->left
403 segment_t*t = a->root->rightchild;
404 while(t->leftchild) {
405 segment_t*l = t->leftchild;
406 segment_t*r = l->rightchild;
407 LINK(l, rightchild, t);
408 LINK(t, leftchild, r);
411 LINK(a->root,rightchild,t);
412 assert(!a->root->rightchild->leftchild);
413 LINK(a->root->rightchild,leftchild,a->root->leftchild);
414 a->root = a->root->rightchild;
419 s->leftchild = s->rightchild = s->parent = 0;
421 assert(actlist_splay_verify(a));
424 int actlist_size(actlist_t*a)
429 segment_t* actlist_leftmost(actlist_t*a)
434 segment_t* actlist_rightmost(actlist_t*a)
436 /* this is only used in checks, so it doesn't matter that it's slow */
437 segment_t*s = a->list;
446 void actlist_insert(actlist_t*a, point_t p1, point_t p2, segment_t*s)
448 segment_t*left = actlist_find(a, p1, p2);
449 actlist_insert_after(a, left, s);
453 segment_t* actlist_left(actlist_t*a, segment_t*s)
458 segment_t* actlist_right(actlist_t*a, segment_t*s)
460 if(s) return s->right;
464 void actlist_swap(actlist_t*a, segment_t*s1, segment_t*s2)
467 assert(actlist_splay_verify(a));
470 /* test that s1 is to the left of s2- our swap
471 code depends on that */
473 while(s && s!=s2) s = s->right;
477 actlist_delete(a, s1);
478 actlist_insert_after(a, s2, s1);
480 segment_t*s1l = s1->left;
481 segment_t*s1r = s1->right;
482 segment_t*s2l = s2->left;
483 segment_t*s2r = s2->right;
484 if(s1l) s1l->right = s2;
487 if(s2r) s2r->left = s1;
489 if(s2l!=s1) s1->left = s2l;
491 if(s1r!=s2) s2->right = s1r;
501 segment_t*l = s2->leftchild;
502 segment_t*r = s2->rightchild;
503 assert(s1->rightchild == s2); // because s1 < s2
504 segment_t*l1 = s1->leftchild;
505 segment_t*p = s1->parent;
509 if(p->leftchild == s1) p->leftchild=s2;
510 else {assert(p->rightchild == s1);p->rightchild=s2;}
518 } else if(s1->parent==s2) {
524 segment_t*l = s1->leftchild;
525 segment_t*r = s1->rightchild;
526 segment_t*r2 = s2->rightchild;
527 assert(s2->leftchild == s1); // because s1 < s2
528 segment_t*p = s2->parent;
532 if(p->leftchild == s2) p->leftchild=s1;
533 else {assert(p->rightchild == s2);p->rightchild=s1;}
542 segment_t*s1p = s1->parent;
543 segment_t*s1l = s1->leftchild;
544 segment_t*s1r = s1->rightchild;
545 segment_t*s2p = s2->parent;
546 segment_t*s2l = s2->leftchild;
547 segment_t*s2r = s2->rightchild;
550 s2->rightchild = s1r;
553 s1->rightchild = s2r;
556 if(s1p->leftchild == s1) s1p->leftchild=s2;
557 else {assert(s1p->rightchild == s1);s1p->rightchild=s2;}
562 if(s2p->leftchild == s2) s2p->leftchild=s1;
563 else {assert(s2p->rightchild == s2);s2p->rightchild=s1;}
568 if(s1->leftchild) s1->leftchild->parent = s1;
569 if(s2->leftchild) s2->leftchild->parent = s2;
570 if(s1->rightchild) s1->rightchild->parent = s1;
571 if(s2->rightchild) s2->rightchild->parent = s2;
572 if(!actlist_splay_verify(a)) {
573 actlist_splay_dump(a);
574 actlist_dump(a, s1->a.y);