Modified the UGetCursor() routine to return a valid response if the
[xcircuit.git] / asg / cstitch.c
blob6c76dff8bec191e559d45ad9bae4dd82fb6b4255
2 /************************************************************
3 **
4 ** COPYRIGHT (C) 1993 UNIVERSITY OF PITTSBURGH
5 ** COPYRIGHT (C) 1996 GANNON UNIVERSITY
6 ** ALL RIGHTS RESERVED
7 **
8 ** This software is distributed on an as-is basis
9 ** with no warranty implied or intended. No author
10 ** or distributor takes responsibility to anyone
11 ** regarding its use of or suitability.
13 ** The software may be distributed and modified
14 ** freely for academic and other non-commercial
15 ** use but may NOT be utilized or included in whole
16 ** or part within any commercial product.
18 ** This copyright notice must remain on all copies
19 ** and modified versions of this software.
21 ************************************************************/
23 /* file cstitch.c */
24 /* ------------------------------------------------------------------------
25 * Common definitions for Corner Stiching (see Osterhout '84 DAC paper) 1/90 stf
27 * ------------------------------------------------------------------------
30 #include "cstitch.h"
31 #include "list.h"
33 extern int debug_level;
35 /*------- Forward !#*&^@!*#@ Reference ------------------------- */
36 int std_solidp();
37 int std_contents_equivalentp();
38 void std_insert_contents();
40 /*---------------------------------------------------------------
41 * Templates for corner-stiched data-structures (see cstitch.h)
42 *---------------------------------------------------------------
44 * typedef struct tile_struct tile;
45 * typedef struct tile_list tilist;
47 * struct tile_struct
48 * {
49 * int x_pos, y_pos; lower left cartesian coordinates (bl,lb)
50 * int x_len, y_len; relative upper rh coordinates (rt,tr)
51 * int *this; contents of the rectangle
52 * tile *bl, *lb; lower-left (lower left side & bottom) stitches
53 * tile *rt, *tr; upper-right (top & side) stitches
54 * };
56 * struct tile_list
57 * {
58 * tile *this;
59 * tilist *next;
60 * };
63 #define MAX(a,b) (((a)>(b))?(a):(b))
64 #define MIN(a,b) (((a)<(b))?(a):(b))
66 /* ---- Global variables required by cstitch.c: ---------------------------*/
67 /* If anything interesting is done with the contents, these functions need to be
68 overloaded so that the merger/splitting functions can do interesting things... */
70 int (*solidp)() = std_solidp;
71 int (*contents_equivalentp)() = std_contents_equivalentp;
72 void (*insert_contents)() = std_insert_contents;
73 void (*manage_contents__hmerge)() = null;
74 void (*manage_contents__vmerge)() = null;
75 void (*manage_contents__hsplit)() = null;
76 void (*manage_contents__vsplit)() = null;
77 void (*manage_contents__dead_tile)() = null;
80 /*------------------------------------------------------------------------ */
81 tilist *list_neighbors();
82 int verify_tile_space();
84 /*------------------------------------------------------------------------ */
85 void null(t)
86 tile *t;
88 /*------------------------------------------------------------------------ */
89 /*------------------------------------------------------------------------ */
90 void reset_boundaries(root, x1, y1, x2, y2)
91 tile *root;
92 int x1, y1, x2, y2;
94 /* This will reset the boudaries of the tilespace containing <root> to the
95 given dimensions, as long as no tiles are removed. Otherwise, the
96 smallest size is set.
98 This code makes a BIG assumption in that no (colored) tiles run up to
99 the edge of the tile space... */
101 int minX, maxX, minY, maxY, diff;
102 tilist *tl, *right = NULL, *left = NULL;
103 tilist *top = NULL, *bottom = NULL;
104 tile *ulhc, *lrhc;
106 /* Added by Tim for debugging */
107 if (verify_tile_space(root) == FALSE)
109 fprintf(stderr, "reset_boundaries: Corrupted tile space! (on entry)\n");
111 /* end of addition --Tim */
113 ulhc = find_ULHC(root);
114 lrhc = find_LRHC(root);
116 minX = ulhc->x_pos; maxY = ulhc->y_pos + ulhc->y_len;
117 maxX = lrhc->x_pos + lrhc->x_len; minY = lrhc->y_pos;
119 right = find_all_tiles_along_line(lrhc, maxX - 1, maxY - 1, 0, -1, &right);
120 left = find_all_tiles_along_line(ulhc, minX + 1, minY + 1, 0, 1, &left);
121 bottom = find_all_tiles_along_line(lrhc, maxX - 1, minY + 1, -1, 0, &bottom);
122 top = find_all_tiles_along_line(ulhc, minX + 1, maxY - 1, 1, 0, &top);
124 /* be assured that the min/max X settings aren't bad: */
125 maxX = MAX(x1, x2);
126 for(tl = right; tl != NULL; tl = tl->next)
128 if (tl->this->x_pos >= maxX) maxX = tl->this->x_pos + 1;
130 minX = MIN(x1, x2);
131 for(tl = left; tl != NULL; tl = tl->next)
133 if (tl->this->x_pos + tl->this->x_len <= minX)
134 minX = tl->this->x_pos + tl->this->x_len - 1;
137 /* be assured that the min/max Y settings aren't bad: */
138 maxY = MAX(y1,y2);
139 minY = MIN(y1,y2);
140 if (ulhc->y_pos >= maxY) maxY = ulhc->y_pos + 1;
141 if (lrhc->y_pos + lrhc->y_len <= minY) minY = lrhc->y_pos + lrhc->y_len - 1;
143 /* Now reset the boundaries: along the left and right sides: */
144 for (tl = left; tl != NULL; tl = tl->next)
146 diff = tl->this->x_pos - minX;
147 tl->this->x_pos = minX;
148 tl->this->x_len += diff;
150 for (tl = right; tl != NULL; tl = tl->next)
152 tl->this->x_len = maxX - tl->this->x_pos;
155 /* Now reset the boundaries: along the top and bottom: */
156 for (tl = bottom; tl != NULL; tl = tl->next)
158 diff = tl->this->y_pos - minY;
159 tl->this->y_pos = minY;
160 tl->this->y_len += diff;
161 /* This whole loop was:
162 diff = lrhc->y_pos - minY; lrhc->y_pos = minY;
163 lrhc->y_len += diff;) */
165 for (tl = top; tl != NULL; tl = tl->next)
167 tl->this->y_len = maxY - tl->this->y_pos;
168 /* (This whole loop was : ulhc->y_len = maxY - ulhc->y_pos; ) */
171 /* Cleanup */
172 free_list(right); free_list(top);
173 free_list(left); free_list(bottom);
175 if (verify_tile_space(root) == FALSE)
177 fprintf(stderr, "reset_boundaries: Corrupted tile space! (on exit)\n");
181 /*-----------------------------------------------------------------------*/
182 void determine_bounding_box(root, x1, y1, x2, y2, compress)
183 tile *root;
184 int *x1, *y1, *x2, *y2;
185 int compress;
187 /* Determine the min. bounding box that will contain all of the filled
188 tiles within the tile-space defined by <root>.
189 NOTE: This is a destructive routine, in that the BB for <root> remains
190 set to the minimum discovered. */
192 tile *ul, *lr;
194 /* Reset the bb based on the minimum permissible boundry: */
195 if (compress)
196 reset_boundaries(root, 0, 0, 0, 0);
198 ul = find_ULHC(root);
199 lr = find_LRHC(root);
201 *x1 = ul->x_pos;
202 *y1 = lr->y_pos;
203 *x2 = lr->x_pos + lr->x_len;
204 *y2 = ul->y_pos + ul->y_len;
206 /*------------------------------------------------------------------------ */
207 tile *create_tile(xsize,ysize,what,xorg,yorg)
208 int xorg,yorg,xsize,ysize;
209 int *what;
211 /* Create a tile from scratch */
213 tile *t;
214 t = (tile *)calloc(1, sizeof(tile));
215 t->x_pos = xorg;
216 t->y_pos = yorg;
217 t->x_len = xsize;
218 t->y_len = ysize;
219 t->this = what;
220 t->bl = t->lb = t->rt = t->tr = NULL;
221 return(t);
223 /*------------------------------------------------------------------------ */
224 tile *copy_tile(t)
225 tile *t;
226 /* return a unique copy of the given tile <t>. */
228 tile *s = create_tile(t->x_len, t->y_len, t->this, t->x_pos, t->y_pos);
229 s->bl = t->bl;
230 s->lb = t->lb;
231 s->rt = t->rt;
232 s->tr = t->tr;
233 return(s);
235 /*------------------------------------------------------------------------ */
236 tile *hmerge_tile(t)
237 tile *t;
238 /* Check <t> for merger with its current right-hand neighbor. If a merger is
239 * appropriate, then nuke the neighbor and expand <t>, returning <t>.
240 * The contents should be correct before this is called. */
242 tile *temp;
243 tilist *tl = NULL, *scrap;
245 if (t != NULL)
247 if ((t->tr != NULL) && /* If there's a guy to the right */
248 (contents_equivalentp(t, t->tr) == TRUE) &&
249 (t->tr->y_pos == t->y_pos) && /* And everything is lined up OK */
250 (t->tr->y_len == t->y_len))
252 temp = t->tr; /* Nuke the guy to the right */
254 /* Fixup the tile contents to reflect these changes: */
256 t->x_len += temp->x_len;
257 t->tr = temp->tr;
258 t->rt = temp->rt;
259 /* need to fix all of the pointers pointing to <temp> so they will
260 point to <t> */
261 scrap = list_neighbors(temp, BOTTOM);
262 for (tl = scrap; tl != NULL; tl = tl->next)
264 /* if (((tl->this->x_pos + tl->this->x_len) <= (t->x_pos + t->x_len)) &&
265 (tl->this != t)) */
266 if (tl->this->rt == temp) tl->this->rt = t;
268 free_list(scrap);
270 scrap = list_neighbors(temp, RIGHT);
271 for (tl = scrap; tl != NULL; tl = tl->next)
273 /* if ((tl->this->y_pos >= t->y_pos) && (tl->this != t)) */
274 if (tl->this->bl == temp) tl->this->bl = t;
276 free_list(scrap);
278 scrap = list_neighbors(temp, TOP);
279 for (tl = scrap; tl != NULL; tl = tl->next)
281 /* if ((tl->this->x_pos >= t->x_pos) && (tl->this != t)) */
282 if (tl->this->lb == temp)tl->this->lb = t;
284 free_list(scrap);
286 (*manage_contents__hmerge)(t, temp);
287 (*manage_contents__dead_tile)(temp);
288 my_free(temp);
289 temp = NULL;
292 return(t);
294 /*------------------------------------------------------------------------ */
295 tile *vmerge_tile(t)
296 tile *t;
297 /* Check <t> for merger with its current upward neighbor. If a merger is
298 * appropriate, then nuke the neighbor and expand <t>, returning <t>.
299 * The contents should be correct before this is called. */
301 tile *temp;
302 tilist *tl = NULL, *scrap;
304 if (t != NULL)
306 if ((t->rt != NULL) && /* If there's a guy on top */
307 (contents_equivalentp(t, t->rt) == TRUE) &&
308 (t->rt->x_pos == t->x_pos) && /* And things line up OK */
309 (t->rt->x_len == t->x_len))
311 temp = t->rt; /* nuke the guy on top */
313 /* Fixup the tile contents to reflect these changes: */
315 t->y_len += temp->y_len;
316 t->rt = temp->rt;
317 t->tr = temp->tr;
319 /* need to fix all of the pointers pointing to <temp> so they will
320 point to <t>*/
322 scrap = list_neighbors(temp, LEFT);
323 for (tl = scrap; tl != NULL; tl = tl->next)
325 /* if (((tl->this->y_pos + tl->this->y_len) <= (t->y_pos + t->y_len)) &&
326 (tl->this != t)) */
327 if (tl->this->tr == temp) tl->this->tr = t;
329 free_list(scrap);
331 scrap = list_neighbors(temp, RIGHT);
332 for (tl = scrap; tl != NULL; tl = tl->next)
334 /* if ((tl->this->y_pos >= t->y_pos) && (tl->this != t)) */
335 if (tl->this->bl == temp) tl->this->bl = t;
337 free_list(scrap);
339 scrap = list_neighbors(temp, TOP);
340 for (tl = scrap; tl != NULL; tl = tl->next)
342 /* if ((tl->this->x_pos >= t->x_pos) && (tl->this != t)) */
343 if (tl->this->lb == temp) tl->this->lb = t;
345 free_list(scrap);
347 (*manage_contents__vmerge)(t, temp);
348 (*manage_contents__dead_tile)(temp);
349 my_free(temp);
350 temp = NULL;
353 return(t);
356 /*------------------------------------------------------------------------ */
357 /*------------------------------------------------------------------------ */
358 tile *locate(start, x, y)
359 tile *start;
360 int x, y;
361 /* locate the tile containing the point (x,y) given a <start> tile. NOTE: This
362 * is slightly different from the algorithm in [Ost84].
363 * NOTE: This arranges tiles such that the top and right edges contain points, whereas
364 * the left and bottom edges do not. Also, a tile is considered to contain its
365 * top & right-side edges, but not its left/bottom edges. */
367 tile *t = start;
368 if (t == NULL) return (NULL); /* bad requests cause big problems */
370 /* first find the right 'row' of tiles */
371 else if (y < t->y_pos) t = locate(t->lb, x, y);
372 else if ((y == t->y_pos) && (t->lb != NULL)) t = locate(t->lb, x, y);
373 else if ((t->y_len + t->y_pos) < y) t = locate(t->rt, x, y);
375 if (t == NULL) return (NULL); /* bad requests cause big problems */
377 /* walk down the 'row' */
378 if (t->x_pos > x) return(locate(t->bl, x, y));
379 if ((t->x_pos == x) && (t->bl != NULL)) return(locate(t->bl, x, y));
380 else if ((t->x_len + t->x_pos) < x) return(locate(t->tr, x, y));
381 else return(t);
384 /*------------------------------------------------------------------------ */
385 tilist *list_neighbors(who, side)
386 tile *who;
387 int side; /* {TOP, BOTTOM, LEFT, RIGHT } */
388 /* create a list of pointers for all of the neighboring tiles on the given side */
389 /* This is simply a pointer-tracing routine. */
391 tilist *tlist = NULL;
392 tile *s;
394 switch(side)
396 case(TOP): { s = who->rt;
397 if (s != NULL)
399 push(s, &tlist);
400 s = s->bl;
401 while((s != NULL) && (s->x_pos >= who->x_pos))
403 push(s, &tlist);
404 s = s->bl;
407 break;
410 case(RIGHT): { s = who->tr;
411 if (s != NULL)
413 queue(s, &tlist);
414 s = s->lb;
415 while((s != NULL) && (s->y_pos >= who->y_pos))
417 queue(s, &tlist);
418 s = s->lb;
421 break;
424 case(BOTTOM): { s = who->lb;
425 if (s != NULL)
427 queue(s, &tlist);
428 s = s->tr;
429 while((s != NULL) && (s->x_pos < who->x_pos + who->x_len))
431 queue(s, &tlist);
432 s = s->tr;
435 break;
438 case(LEFT): { s = who->bl;
439 if (s != NULL)
441 push(s, &tlist);
442 s = s->rt;
443 while((s != NULL) && (s->y_pos < who->y_pos + who->y_len))
445 push(s, &tlist);
446 s = s->rt;
449 break;
452 return(tlist);
454 /*------------------------------------------------------------------------ */
455 tile *area_search(start, xorg, yorg, xsize, ysize)
456 tile *start; /* a starting tile */
457 int xorg, yorg, xsize, ysize; /* defines the area of interest */
458 /* This returns a pointer to the first 'used' tile in the given area. If
459 * none are found, then NULL is returned. */
461 int x = xorg + xsize;
462 tile *s = locate(start, xorg, yorg + ysize);
464 /* Boundry condition problem */
465 if (((s->x_pos + s->x_len) <= xorg) && (s->tr != NULL))
466 s = locate(s->tr, xorg + 1, yorg + ysize);
468 if ((*solidp)(s) == TRUE) return(s);
469 else if ((s->x_pos + s->x_len) < x) return(s->tr);
470 else if (s->y_pos > yorg)
471 return(area_search(s, xorg, yorg, xsize, s->y_pos - yorg));
472 else return (NULL);
475 /*------------------------------------------------------------------------ */
476 int std_solidp(t)
477 tile *t;
478 /* return TRUE iff tile t is used. */
480 return((t->this != NULL) ? TRUE : FALSE);
482 /*------------------------------------------------------------------------ */
483 void std_insert_contents(t, w)
484 tile *t;
485 int *w;
486 { /* Make the standard assignment for tile contents (add <w> to <t>) */
487 t->this = w;
489 /*------------------------------------------------------------------------ */
490 int std_contents_equivalentp(t1, t2)
491 tile *t1, *t2;
492 { /* Return TRUE if the tiles are of the same color */
493 if (t1->this == t2->this) return(TRUE);
494 else return(FALSE);
496 /*------------------------------------------------------------------------ */
497 int containsp(t, x, y)
498 tile *t;
499 int x, y;
500 /* return TRUE if the given tile contains the given (x,y) point.
501 * NOTE: This definition arranges the tiles st a tile contains all of the points
502 * on its top and right edges. */
504 if ((t->x_pos < x) && ((t->x_pos + t->x_len) >= x) &&
505 (t->y_pos < y) && ((t->y_pos + t->y_len) >= y)) return (TRUE);
506 return(FALSE);
508 /*------------------------------------------------------------------------ */
509 list *create_tile_pair(t1, t2)
510 tile *t1, *t2;
512 /* Create a list that is an ordered pair of tiles */
513 list *l = (list *)calloc(1, sizeof(tilist));
514 push(t2, &l);
515 push(t1, &l);
516 return(l);
518 /*------------------------------------------------------------------------ */
519 tile *vsplit_tile(p, y)
520 tile *p;
521 int y;
523 /* Split <p> along the axis <y>. Return the lower tile. All pointers should be
524 correct. Opposite of "vmerge" */
526 tile *c;
527 if ((p != NULL) && (y > p->y_pos) && (y < (p->y_pos + p->y_len)))
529 c = copy_tile(p); /* <c> becomes the lower tile */
530 p->lb = c;
531 p->y_len = p->y_pos + p->y_len - y;
532 p->y_pos = y;
534 c->rt = p;
535 c->y_len = y - c->y_pos;
536 c->tr = locate(p, c->x_pos + c->x_len + 1, c->y_pos + c->y_len + 1);
537 if ((c->tr != NULL) && (c->tr->y_pos >= y))
538 c->tr = locate(p, c->x_pos + c->x_len + 1, c->y_pos + c->y_len);
540 p->bl = locate(p, p->x_pos - 1, y);
542 /* Now hunt down all of the special cases where the <= vs < issues can bite
543 you: (These work around weaknesses in the definition of a tile as being
544 inclusive vs being exclusive of its borders) */
545 if ((p->bl != NULL) && (p->bl->y_pos + p->bl->y_len <= y))
546 p->bl = locate(p, p->x_pos - 1, y + 1);
547 if ((p->bl != NULL) && (p->bl->y_pos > p->y_pos))
548 p->bl = locate(p, p->x_pos - 1, y - 1);
549 if ((p->bl != NULL) && (p->bl->x_pos + p->bl->x_len < p->x_pos))
550 p->bl = locate(p, p->x_pos, y);
552 clean_up_neighbors(p);
553 clean_up_neighbors(c);
555 if ((verify_tile_space(p) == FALSE) || (verify_tile_space(c) == FALSE))
557 fprintf(stderr, "vsplit_tile: Corrupted tile space!\n");
559 /* Clean up the contents of these tiles: */
560 (*manage_contents__vsplit)(p, c);
561 return(c);
563 else if (y == p->y_pos) return(p->lb);
564 else if (y == (p->y_pos + p->y_len)) return(p);
565 else return(NULL); /* Big Problem */
567 /*------------------------------------------------------------------------ */
568 tile *hsplit_tile(p, x)
569 tile *p;
570 int x;
572 /* Split <p> along the axis <x>. Return the rh tile. All pointers should be
573 correct. Opposite of "hmerge" */
575 tile *c;
576 if ((p != NULL) && (x > p->x_pos) && (x < (p->x_pos + p->x_len)))
578 c = copy_tile(p); /* <c> becomes the right side tile */
579 c->bl = p;
580 c->x_len = p->x_pos + p->x_len - x;
581 c->x_pos = x;
582 p->tr = c;
584 p->x_len = x - p->x_pos;
585 c->lb = locate(p, x + 1, c->y_pos);
587 /* Now hunt down all of the special cases where the <= vs < issues can bite
588 you: (These work around weaknesses in the definition of a tile as being
589 inclusive vs being exclusive of its borders) */
590 if (c->lb != NULL && (c->lb->x_pos > c->x_pos))
591 c->lb = locate(p, x, c->y_pos);
592 p->rt = locate(p, x - 1, p->y_pos + p->y_len + 1);
593 if ((p->rt != NULL) && (p->rt->x_pos + p->rt->x_len <= x))
594 p->rt = locate(p, x, p->y_pos + p->y_len + 1);
595 clean_up_neighbors(p);
596 clean_up_neighbors(c);
598 if ((verify_tile_space(p) == FALSE) || (verify_tile_space(c) == FALSE))
600 fprintf(stderr, "hsplit_tile: Corrupted tile space!\n");
603 /* Clean up the contents of these tiles: */
604 (*manage_contents__hsplit)(p, c);
605 return(c);
607 else if (x == p->x_pos) return(p);
608 else if (x == (p->x_pos + p->x_len)) return(p->tr);
609 else return(NULL); /* Big Problem */
611 /*------------------------------------------------------------------------ */
612 tile *insert_tile(start, xorg, yorg, xsize, ysize, what)
613 tile *start; /* a starting tile */
614 int xorg, yorg, xsize, ysize; /* defines the area of interest */
615 int *what; /* contents of the new tile */
617 /* This returns a pointer to a newly-created tile of the given size, at the
618 * given position if one can be made. Otherwise NULL is returned. */
620 /* To maintain the internals of the tiles, as each tile is cut or made, it is
621 added to a list of tiles to be handled specially. */
623 tile *left, *right, *lefTop, *righTop, *leftBot, *rightBot;
624 tile *temp, *bot, *top, *new;
625 tilist *tl, *Copied = NULL, *Clipped = NULL, *New = NULL;
627 int x = xorg + xsize;
628 int y = yorg + ysize;
629 int ymark = y;
631 /* First see if such a tile can be made: */
632 if (area_search(start, xorg, yorg, xsize, ysize) != NULL) return(NULL);
634 /* locate the top left-hand (LH) corner tile for the AOI */
635 top = locate(start, xorg + 1, y);
637 /* Now split this tile vertically, as necessary: <leftBot> becomes the lower tile */
638 leftBot = vsplit_tile(top, y); /* <leftBot> becomes the lower tile */
640 /* Do the same to the bottom of the AOI: */
641 temp = locate(top, xorg, yorg);
642 bot = vsplit_tile(temp, yorg);
645 /* Now begin a loop, splitting tiles as you go. Note that the pointers for, and
646 the size of <new> changes as you go along to insure correctness. */
647 left = leftBot;
649 while (ymark > yorg)
651 new = hsplit_tile(left, xorg);
652 right = hsplit_tile(new, x);
654 insert_contents(new, what);
655 vmerge_tile(left);
656 vmerge_tile(right);
657 vmerge_tile(new);
659 ymark = new->y_pos;
660 left = locate(new, xorg, ymark);
661 if ((left != NULL) && (left->y_pos >= ymark))
662 left = locate(new, xorg, ymark - 1);
663 if ((left != NULL) && ((left->x_pos + left->x_len) <= xorg))
665 if (new->lb->y_len == 1) left = locate(new, xorg + 1, ymark);
666 else left = locate(new, xorg + 1, ymark - 1);
669 /* Cleanup the tiles directly below the area of interest: */
670 if ((new->bl != NULL) && (new->bl->lb != NULL)) vmerge_tile(new->bl->lb);
671 if ((right != NULL) && (right->lb != NULL)) vmerge_tile(right->lb);
673 if (verify_tile_space(new) == FALSE)
675 fprintf(stderr, "insert_tile: Corrupted tile space! abort! (on exit)\n");
676 /* exit(1); */
677 return NULL;
680 return(new);
682 /*------------------------------------------------------------------------ */
683 int next_move(min, max, current, direction, epsilon)
684 int *min, *max, current, *epsilon;
686 /* return the new value of current, if a newtonian search step is taken in
687 * the direction of <del>. <epsilon is reset to reflect the move. */
689 if (direction == FURTHER)
691 /* Move in the direction of <max> */
692 *epsilon = (*epsilon == 1) ? 0 : (*max - current + 1)/ 2; /* roundoff bias */
693 *min = current;
694 return (*min + *epsilon);
696 else/* (direction == CLOSER) */
698 /* Move in the direction of <min> */
699 *epsilon = (*epsilon == 1) ? 0 : (current - *min + 1)/ 2;
700 *max = current;
701 return (*max - *epsilon);
704 /*------------------------------------------------------------------------ */
705 tile *angled_tile_help(start, anchX, anchY, delX, delY,
706 pivX, pivY, sizeX, sizeY, box, cornerTile)
707 tile *start; /* the starting (reference) tile */
708 int anchX, anchY; /* XY origin of axis of motion (anchor point). */
709 int delX, delY; /* slope+dir of the axis of motion (line along which the
710 new tile moves) */
711 int pivX, pivY; /* the pivot point of the <new> tile. (relative to (0,0),
712 (sizeX, sizeY) */
713 int sizeX, sizeY; /* defines the size of the tile to be installed */
714 int *box; /* contents of the <new> tile. Reference to (0,0). */
715 tile *cornerTile; /* tile on the edge of the area to search in */
718 /* This returns a pointer to a newly-created tile of the given size, at the
719 * some position lying along a line given at an angle defined by <ydir>/<xdir>.
720 * The position closest to the given <start> tile is selected. The line is
721 * drawn from the origin of <start> to the origin of the new tile. */
723 /* NO ATTEMPT HAS BEEN MADE TO OPTIMIZE THIS CODE, so it is rather redundant. */
725 tilist *tl;
726 tile *new, *flag;
727 int epsilon, b, currentX, lastX, maxX, minX;
728 int orgX, orgY, tempOrgX, tempOrgY;
729 int x, y, foundOne = FALSE;
731 /* This section of code locates the closest, viable origin for <new>: */
733 /* Operate on the left and right 90 degree arcs: */
734 if ((delX != 0) && (abs(delX) > abs(delY)))
735 { /* Given a useful delta-X value, move along the X-Axis: */
737 /* Now if there is no such tile, reset corner based on the edge of the
738 known universe: */
739 if (cornerTile != NULL)
741 /* There is a tile <cornerTile> lying along the line that may interfere: */
742 if (delX > 0)
743 { /* Moving to the right: */
744 minX = anchX;
745 y = (int)((float)delY/(float)delX * (cornerTile->x_pos - anchX)) + anchY;
747 if (delY == 0) maxX = cornerTile->x_pos;
749 else if (delY > 0) /* either maxX = corner->x_pos or @
750 y = corner->y_pos */
752 /* Moving up and to the right: */
753 if (y < cornerTile->y_pos)
754 { /* intersection occurs along bottom edge of <cornerTile> */
755 maxX = (int)((float)delX/(float)delY *
756 (cornerTile->y_pos - anchY)) + anchX;
758 else
759 { /* intersection occurs along left edge of <cornerTile> */
760 maxX = cornerTile->x_pos;
763 else /* either maxX = corner->x_pos or @ y = corner->y_pos +
764 corner->y_len */
766 /* Moving down and to the right: */
767 if (y > (cornerTile->y_pos + cornerTile->y_len))
769 /* intersection occurs along top edge of <cornerTile> */
770 maxX = (int)((float)delX/(float)delY *
771 (cornerTile->y_pos + cornerTile->y_len - anchY)) +
772 anchX;
774 else
776 /* intersection occurs along left edge of <cornerTile> */
777 maxX = cornerTile->x_pos;
781 else
782 { /* Moving to the left: */
783 minX = anchX;
784 y = (int)((float)delY/(float)delX *
785 (cornerTile->x_pos + cornerTile->x_len - anchX)) + anchY;
787 if (delY == 0) maxX = cornerTile->x_pos + cornerTile->x_len;
789 else if (delY > 0) /* either minX = corner->x_pos + corner->x_len
790 or @ y = corner->y_pos + corner->y_len */
792 /* Moving up and to the left: */
793 if (y < (cornerTile->y_pos + cornerTile->y_len))
794 { /* intersection occurs along bottom edge of <cornerTile> */
795 maxX = (int)((float)delX/(float)delY *
796 (cornerTile->y_pos - anchY)) + anchX;
798 else
799 { /* intersection occurs along right edge of <cornerTile> */
800 maxX = cornerTile->x_pos + cornerTile->x_len;
803 else /* either minX = corner->x_pos + corner->x_len or @ y =
804 corner->y_pos */
806 /* Moving down and to the left: */
807 if (y > (cornerTile->y_pos + cornerTile->y_len))
809 /* intersection occurs along top edge of <cornerTile> */
810 maxX = (int)((float)delX/(float)delY *
811 (cornerTile->y_pos + cornerTile->y_len - anchY)) +
812 anchX;
814 else
815 { /* intersection occurs along right edge of <cornerTile> */
816 maxX = cornerTile->x_pos + cornerTile->x_len;
821 else /* cornerTile = NULL -- The simple case */
823 /* First find the corner tile on the edge of the given space in the
824 direction that the new tile is to be moved: */
825 if (delX > 0)
826 { /* Moving to the right: */
827 cornerTile = find_LRHC(start);
828 minX = anchX;
829 maxX = cornerTile->x_pos + cornerTile->x_len;
831 else
832 { /* Moving to the left: */
833 cornerTile = find_ULHC(start);
834 minX = anchX;
835 maxX = cornerTile->x_pos;
839 /* Choose a first point to start at */
840 epsilon = currentX = (minX + maxX) / 2;
841 b = ( anchY - (int)((float)delY/(float)delX * (float)anchX) );
843 /* Check the initial points to insure that they fall within the tile
844 space defined */
845 tempOrgX = currentX - pivX;
846 tempOrgY = (int)(((float)delY/(float)delX) * (float)currentX) + b - pivY;
847 if (locate(start, tempOrgX, tempOrgY) == NULL) /* This is a problem */
849 epsilon = currentX = currentX/2; /* A guess. */
850 fprintf(stderr, "Bad origin point selected; trying again...\n");
855 /* Perform a newtonian search (along the X-Axis) to find the closest
856 point to use: */
857 while (abs(epsilon) > 1)
859 /* define the where <new>'s origin should go, based on the axis of motion: */
860 tempOrgX = currentX - pivX;
861 tempOrgY = (int)(((float)delY/(float)delX) * (float)currentX) + b - pivY;
863 /* See if <new> can be placed: */
864 flag = area_search(start, tempOrgX, tempOrgY, sizeX, sizeY);
866 if (flag != NULL)
867 { /* The tile can't go here. - try going further away */
868 currentX = next_move(&minX, &maxX, currentX, FURTHER, &epsilon);
870 else
871 { /* The tile can go here - try going closer */
872 currentX = next_move(&minX, &maxX, currentX, CLOSER, &epsilon);
873 orgX = tempOrgX;
874 orgY = tempOrgY;
875 foundOne = TRUE;
880 /* Otherwise, operate on the top and bottom 90 degree arcs: */
881 else if (delY != 0)
882 { /* The delY value is more useful, so use y dimensions: */
883 /* This section of code locates the closest, viable origin for <new>: */
884 if(cornerTile != NULL)
886 if (delY > 0)
887 { /* Moving Up: */
888 minX = anchY;
889 x = (int)((float)delX/(float)delY * (cornerTile->y_pos - anchY)) + anchX;
891 if (delX == 0) maxX = cornerTile->y_pos;
893 else if (delX > 0) /* either maxX = corner->y_pos or @
894 x = corner->x_pos */
896 /* Moving up and to the right: */
897 if (x > cornerTile->x_pos)
899 /* intersection occurs along bottom edge of <cornerTile> */
900 maxX = cornerTile->y_pos;
902 else
904 /* intersection occurs along left edge of <cornerTile> */
905 maxX = (int)((float)delY/(float)delX *
906 (cornerTile->x_pos - anchX)) + anchY;
909 else /* either maxX = corner->y_pos or @ x = corner->x_pos +
910 corner->x_len */
912 /* Moving up and to the left: */
913 if (x > (cornerTile->x_pos + cornerTile->x_len))
915 /* intersection occurs along right edge of <cornerTile> */
916 maxX = (int)((float)delY/(float)delX *
917 (cornerTile->x_pos + cornerTile->x_len - anchX)) +
918 anchY;
920 else
922 /* intersection occurs along bottom edge of <cornerTile> */
923 maxX = cornerTile->y_pos;
927 else
928 { /* Moving Down: (delY < 0) */
929 minX = anchY;
930 x = (int)((float)delX/(float)delY *
931 (cornerTile->y_pos + cornerTile->y_len - anchY)) + anchX;
933 if (delX == 0) maxX = cornerTile->y_pos + cornerTile->y_len;
935 else if (delX > 0) /* either minY = corner->y_pos + corner->y_len
936 or @ x=corner->x_pos */
938 /* Moving down and to the right: */
939 if (x > cornerTile->x_pos)
940 { /* intersection occurs along top edge of <cornerTile> */
941 maxX = cornerTile->y_pos + cornerTile->y_len;
943 else
944 { /* intersection occurs along left edge of <cornerTile> */
945 maxX = (int)((float)delY/(float)delX *
946 (cornerTile->x_pos - anchX)) + anchY;
949 else /* either minY = corner->y_pos + corner->y_len or @ x =
950 corner->x_pos */
952 if (x > (cornerTile->y_pos + cornerTile->y_len))
953 { /* intersection occurs along right edge of <cornerTile> */
954 maxX = (int)((float)delY/(float)delX *
955 (cornerTile->x_pos + cornerTile->x_len - anchX)) +
956 anchY;
958 else
960 /* intersection occurs along top edge of <cornerTile> */
961 maxX = cornerTile->y_pos + cornerTile->y_len;
966 else /* cornerTile == NULL -- The simple case: */
968 /* First find the corner tile on the edge of the given space in the
969 direction that the new tile is to be moved: */
970 if (delY > 0)
971 { /* Moving Up: */
972 cornerTile = find_ULHC(start);
973 minX = anchY;
974 maxX = cornerTile->y_pos + cornerTile->y_len;
976 else
977 { /* Moving Down: */
978 cornerTile = find_LRHC(start);
979 maxX = cornerTile->y_pos;
980 minX = anchY;
984 /* Choose a first point to start at */
985 epsilon = currentX = (minX + maxX) / 2;
986 b = (anchX - (int)(((float)delX/(float)delY) * (float)anchY));
988 /* Check the initial points to insure that they fall within the tile
989 space defined */
990 tempOrgY = currentX - pivY;
991 tempOrgX = (int)(((float)delX/(float)delY) * (float)currentX) + b - pivX;
992 if (locate(start, tempOrgX, tempOrgY) == NULL) /* This is a problem */
994 epsilon = currentX = currentX / 2; /* A guess. */
995 fprintf(stderr, "Bad origin point selected; trying again...\n");
999 /* Perform a newtonian search (along the Y-Axis) to find the closest point
1000 to use: Note that <currentX>, <maxX>, & <minX> are now misnamed. */
1001 while (abs(epsilon) > 1)
1003 /* define the where <new>'s origin should go, based on the axis of motion: */
1004 tempOrgY = currentX - pivY;
1005 tempOrgX = (int)(((float)delX/(float)delY) * (float)currentX) + b - pivX;
1007 /* See if <new> can be placed: */
1008 flag = area_search(start, tempOrgX, tempOrgY, sizeX, sizeY);
1010 if (flag != NULL)
1011 { /* The tile can't go here. - try going further away */
1012 currentX = next_move(&minX, &maxX, currentX, FURTHER, &epsilon);
1014 else
1015 { /* The tile can go here - try going closer */
1016 currentX = next_move(&minX, &maxX, currentX, CLOSER, &epsilon);
1017 orgX = tempOrgX;
1018 orgY = tempOrgY;
1019 foundOne = TRUE;
1023 else
1025 fprintf(stderr, "angled_tile_help: NULL <delY>, <delX> values given.\n");
1029 /* Given a corner point where to insert the new area, adding it to the new space: */
1030 new = (foundOne == TRUE) ? insert_tile(start, orgX, orgY, sizeX, sizeY, box) : NULL;
1032 /*Check to see that the insertion was successful: */
1033 if (new == NULL) ;/*fprintf(stderr, "angled_tile_help: failure to install tile\n");*/
1035 return(new);
1037 /*------------------------------------------------------------------------ */
1038 tile *angled_tile_insertion(start, anchX, anchY, delX, delY, pivX, pivY, sizeX, sizeY, box)
1039 tile *start; /* the starting (reference) tile */
1040 int anchX, anchY; /* XY origin of axis of motion (anchor point). */
1041 int delX, delY; /* slope+dir of the axis of motion (line along which the
1042 new tile moves) */
1043 int pivX, pivY; /* the pivot point of the <new> tile. (relative to (0,0),
1044 (sizeX, sizeY) */
1045 int sizeX, sizeY; /* defines the size of the tile to be installed */
1046 int *box; /* contents of the <new> tile. Reference to (0,0). */
1048 /* This returns a pointer to a newly-created tile of the given size, at the
1049 * some position lying along a line given at an angle defined by <ydir>/<xdir>.
1050 * The position closest to the given <start> tile is selected. The line is
1051 * drawn from the origin of <start> to the origin of the new tile. */
1053 tilist *lineList = NULL, *tl;
1055 tile *cornerTile, *new = NULL;
1056 int x, y;
1057 int newAnchX = anchX, newAnchY = anchY;
1059 /* Make sure there is a useful axis of motion to use: */
1060 if ((delX == 0) && (delY == 0))
1062 fprintf(stderr, "angled_tile_insertion: Bad Axis of motion given.\n");
1063 return(NULL); /* Bad call */
1066 /* To locate the proper search space, map the axis of motion onto the tile-space:
1067 * this creates a list of tiles, starting with the anchor tile that will indicate
1068 * the limits of the search (maxX and minX)
1069 * COMMENT: This expansion should probably be more like a swath then a line.
1070 * */
1071 lineList = find_all_tiles_along_line(start, newAnchX, newAnchY, delX, delY, &lineList);
1073 /* Find the next corner-tile candidate and advance the <lineList> pointer to indicate
1074 what tiles have been examined */
1075 cornerTile = first_noncontiguous_full_tile(&lineList);
1077 /* See if this <cornerTile> defines an area where the tile can go: */
1078 while (lineList != NULL)
1080 new = angled_tile_help(start, newAnchX, newAnchY, delX, delY,
1081 pivX, pivY, sizeX, sizeY, box, cornerTile);
1083 if (new != NULL) break; /* The thing fit! */
1084 else /* The bloody thing didn't fit, so keep trying */
1086 /* reset the anchor-point and <cornerTile> and try again */
1087 /* The new anchor point is some point in the current cornerTile that
1088 lies along the axis of motion: */
1089 if (delX != 0)
1091 y = (int)((float)delY/(float)delX * (cornerTile->x_pos - newAnchX)) + newAnchY;
1093 if (delY != 0)
1095 x = (int)((float)delX/(float)delY * (cornerTile->x_pos - newAnchY)) + newAnchX;
1097 if ((y >= cornerTile->y_pos) && (y <= (cornerTile->y_pos + cornerTile->y_len)))
1099 newAnchY = y;
1101 else newAnchY = cornerTile->y_pos;
1103 if ((x >= cornerTile->x_pos) && (x <= (cornerTile->x_pos + cornerTile->x_len)))
1105 newAnchX = x;
1107 else newAnchY = cornerTile->x_pos;
1109 /* Find the next <cornerTile> off the unused portion of <lineList> */
1110 cornerTile = first_noncontiguous_full_tile(&lineList);
1112 /*fprintf(stderr, "angled_tile_insertion: retrying at (%d, %d)\n",
1113 newAnchX, newAnchY);*/
1117 if (new == NULL) new = angled_tile_help(start, newAnchX, newAnchY, delX, delY,
1118 pivX, pivY, sizeX, sizeY, box, cornerTile);
1120 /*Check to see that the insertion was successful: */
1121 if (new == NULL) fprintf(stderr, "angled_tile_insertion: Complete Failure\n");
1123 return(new);
1126 /*------------------------------------------------------------------------ */
1127 tile *angled_group_tile_help(start, anchX, anchY, delX, delY, pivX, pivY,
1128 orgX, orgY, tlist, cornerTile)
1129 tile *start; /* the starting (reference) tile */
1130 int anchX, anchY; /* XY origin of axis of motion (anchor point) in <start>'s
1131 tile space. */
1132 int delX, delY; /* slope+dir of the axis of motion (line along which the
1133 new tile moves) */
1134 int pivX, pivY; /* the pivot point of the <new> tile set. (relative to (0,0)) */
1135 int *orgX, *orgY; /* to return the solution found */
1136 tilist *tlist; /* list of tiles to be inserted into <start>'s tile space */
1137 tile *cornerTile; /* defines the end of the area to search in along the
1138 axis of motion */
1141 /* This returns a pointer to a newly-created tile of the given size, at the
1142 * some position lying along a line given at an angle defined by <ydir>/<xdir>.
1143 * The position closest to the given <start> tile is selected. The line is
1144 * drawn from the origin of <start> to the origin of the new tile. */
1146 /* NO ATTEMPT HAS BEEN MADE TO OPTIMIZE THIS CODE, so it is rather redundant. */
1148 tilist *tl;
1149 tile *new = NULL, *snew, *flag = NULL, *sflag;
1150 int epsilon, b, currentX, lastX, maxX, minX;
1151 int tempOrgX, tempOrgY;
1152 int x, y, foundOne = FALSE;
1154 /* This section of code locates the closest, viable origin for <new>: */
1156 /* Operate on the left and right 90 degree arcs: */
1157 if ((delX != 0) && (abs(delX) > abs(delY)))
1158 { /* Given a useful delta-X value, move along the X-Axis: */
1160 /* Now if there is no such tile, reset corner based on the edge of the
1161 known universe: */
1162 if (cornerTile != NULL)
1164 /* There is a tile <cornerTile> lying along the line that may interfere: */
1165 if (delX > 0)
1166 { /* Moving to the right: */
1167 minX = anchX;
1168 y = (int)((float)delY/(float)delX * (cornerTile->x_pos - anchX)) + anchY;
1170 if (delY == 0) maxX = cornerTile->x_pos;
1172 else if (delY > 0) /* either maxX = corner->x_pos or @ y=corner->y_pos */
1174 /* Moving up and to the right: */
1175 if (y < cornerTile->y_pos)
1176 { /* intersection occurs along bottom edge of <cornerTile> */
1177 maxX = (int)((float)delX/(float)delY *
1178 (cornerTile->y_pos - anchY)) + anchX;
1180 else
1181 { /* intersection occurs along left edge of <cornerTile> */
1182 maxX = cornerTile->x_pos;
1185 else /* either maxX = corner->x_pos or @ y=corner->y_pos + corner->y_len*/
1187 /* Moving down and to the right: */
1188 if (y > (cornerTile->y_pos + cornerTile->y_len))
1190 /* intersection occurs along top edge of <cornerTile> */
1191 maxX = (int)((float)delX/(float)delY *
1192 (cornerTile->y_pos + cornerTile->y_len - anchY)) + anchX;
1194 else
1196 /* intersection occurs along left edge of <cornerTile> */
1197 maxX = cornerTile->x_pos;
1201 else
1202 { /* Moving to the left: */
1203 minX = anchX;
1204 y = (int)((float)delY/(float)delX *
1205 (cornerTile->x_pos + cornerTile->x_len - anchX)) + anchY;
1207 if (delY == 0) maxX = cornerTile->x_pos + cornerTile->x_len;
1209 else if (delY > 0) /* either minX = corner->x_pos + corner->x_len or
1210 @ y=corner->y_pos + corner->y_len */
1212 /* Moving up and to the left: */
1213 if (y < (cornerTile->y_pos + cornerTile->y_len))
1214 { /* intersection occurs along bottom edge of <cornerTile> */
1215 maxX = (int)((float)delX/(float)delY *
1216 (cornerTile->y_pos - anchY)) + anchX;
1218 else
1219 { /* intersection occurs along right edge of <cornerTile> */
1220 maxX = cornerTile->x_pos + cornerTile->x_len;
1223 else /* either minX = corner->x_pos + corner->x_len or @ y=corner->y_pos */
1225 /* Moving down and to the left: */
1226 if (y > (cornerTile->y_pos + cornerTile->y_len))
1228 /* intersection occurs along top edge of <cornerTile> */
1229 maxX = (int)((float)delX/(float)delY *
1230 (cornerTile->y_pos + cornerTile->y_len - anchY)) + anchX;
1232 else
1233 { /* intersection occurs along right edge of <cornerTile> */
1234 maxX = cornerTile->x_pos + cornerTile->x_len;
1239 else /* cornerTile = NULL -- The simple case */
1241 /* First find the corner tile on the edge of the given space in the direction that
1242 the new tile is to be moved: */
1243 if (delX > 0)
1244 { /* Moving to the right: */
1245 cornerTile = find_LRHC(start);
1246 minX = anchX;
1247 maxX = cornerTile->x_pos + cornerTile->x_len;
1249 else
1250 { /* Moving to the left: */
1251 cornerTile = find_ULHC(start);
1252 maxX = cornerTile->x_pos;
1253 minX = anchX;
1257 /* Choose a first point to start at */
1258 epsilon = currentX = (minX + maxX) / 2;
1259 b = ( anchY - (int)((float)delY/(float)delX * (float)anchX) );
1261 /* Check the initial points to insure that they fall within the tile space defined */
1262 tempOrgX = currentX - pivX;
1263 tempOrgY = (int)(((float)delY/(float)delX) * (float)currentX) + b - pivY;
1264 if (locate(start, tempOrgX, tempOrgY) == NULL) /* This is a problem */
1266 epsilon = currentX = currentX / 2; /* A guess. */
1267 fprintf(stderr, "Bad origin point selected; trying again...\n");
1271 /* Perform a newtonian search (along the X-Axis) to find the closest point to use: */
1272 while (abs(epsilon) >= 1)
1274 /* define the where <new>'s origin should go, based on the axis of motion: */
1275 tempOrgX = currentX - pivX;
1276 tempOrgY = (int)(((float)delY/(float)delX) * (float)currentX) + b - pivY;
1278 /* See if <new> can be placed: This involves checking everybody on the list: */
1279 for (tl = tlist; ((tl != NULL) && (flag == NULL)); tl = tl->next)
1281 sflag = area_search(start,
1282 tempOrgX + tl->this->x_pos, tempOrgY + tl->this->y_pos,
1283 tl->this->x_len, tl->this->y_len);
1284 if (flag == NULL) flag = sflag;
1287 if (flag != NULL)
1288 { /* The tile set can't go here. - try going further away */
1289 currentX = next_move(&minX, &maxX, currentX, FURTHER, &epsilon);
1291 else
1292 { /* The tiles can go here - try going closer */
1293 currentX = next_move(&minX, &maxX, currentX, CLOSER, &epsilon);
1294 *orgX = tempOrgX;
1295 *orgY = tempOrgY;
1296 foundOne = TRUE;
1298 flag = NULL;
1302 /* Otherwise, operate on the top and bottom 90 degree arcs: */
1303 else if (delY != 0)
1304 { /* The delY value is more useful, so use y dimensions: */
1305 /* This section of code locates the closest, viable origin for <new>: */
1306 if(cornerTile != NULL)
1308 if (delY > 0)
1309 { /* Moving Up: */
1310 minX = anchY;
1311 x = (int)((float)delX/(float)delY * (cornerTile->y_pos - anchY)) + anchX;
1313 if (delX == 0) maxX = cornerTile->y_pos;
1315 else if (delX > 0) /* either maxX = corner->y_pos or @ x=corner->x_pos */
1317 /* Moving up and to the right: */
1318 if (x > cornerTile->x_pos)
1320 /* intersection occurs along bottom edge of <cornerTile> */
1321 maxX = cornerTile->y_pos;
1323 else
1325 /* intersection occurs along left edge of <cornerTile> */
1326 maxX = (int)((float)delY/(float)delX *
1327 (cornerTile->x_pos - anchX)) + anchY;
1330 else /* either maxX = corner->y_pos or @ x=corner->x_pos + corner->x_len*/
1332 /* Moving up and to the left: */
1333 if (x > (cornerTile->x_pos + cornerTile->x_len))
1335 /* intersection occurs along right edge of <cornerTile> */
1336 maxX = (int)((float)delY/(float)delX *
1337 (cornerTile->x_pos + cornerTile->x_len - anchX)) + anchY;
1339 else
1341 /* intersection occurs along bottom edge of <cornerTile> */
1342 maxX = cornerTile->y_pos;
1346 else
1347 { /* Moving Down: (delY < 0) */
1348 minX = anchY;
1349 x = (int)((float)delX/(float)delY *
1350 (cornerTile->y_pos + cornerTile->y_len - anchY)) + anchX;
1352 if (delX == 0) maxX = cornerTile->y_pos + cornerTile->y_len;
1354 else if (delX > 0) /* either minY = corner->y_pos + corner->y_len or
1355 @ x=corner->x_pos */
1357 /* Moving down and to the right: */
1358 if (x > cornerTile->x_pos)
1359 { /* intersection occurs along top edge of <cornerTile> */
1360 maxX = cornerTile->y_pos + cornerTile->y_len;
1362 else
1363 { /* intersection occurs along left edge of <cornerTile> */
1364 maxX = (int)((float)delY/(float)delX *
1365 (cornerTile->x_pos - anchX)) + anchY;
1368 else /* either minY = corner->y_pos + corner->y_len or @ x=corner->x_pos */
1370 if (x > (cornerTile->y_pos + cornerTile->y_len))
1371 { /* intersection occurs along right edge of <cornerTile> */
1372 maxX = (int)((float)delY/(float)delX *
1373 (cornerTile->x_pos + cornerTile->x_len - anchX)) +
1374 anchY;
1376 else
1378 /* intersection occurs along top edge of <cornerTile> */
1379 maxX = cornerTile->y_pos + cornerTile->y_len;
1384 else /* cornerTile == NULL -- The simple case: */
1386 /* First find the corner tile on the edge of the given space in the
1387 direction that the new tile is to be moved: */
1388 if (delY > 0)
1389 { /* Moving Up: */
1390 cornerTile = find_ULHC(start);
1391 minX = anchY;
1392 maxX = cornerTile->y_pos + cornerTile->y_len;
1394 else
1395 { /* Moving Down: */
1396 cornerTile = find_LRHC(start);
1397 maxX = cornerTile->y_pos;
1398 minX = anchY;
1402 /* Choose a first point to start at */
1403 epsilon = currentX = (minX + maxX) / 2;
1404 b = (anchX - (int)(((float)delX/(float)delY) * (float)anchY));
1406 /* Check the initial points to insure that they fall within the tile
1407 space defined */
1408 tempOrgY = currentX - pivY;
1409 tempOrgX = (int)(((float)delX/(float)delY) * (float)currentX) + b - pivX;
1410 if (locate(start, tempOrgX, tempOrgY) == NULL) /* This is a problem */
1412 epsilon = currentX = currentX / 2; /* A guess. */
1413 fprintf(stderr, "Bad origin point selected; trying again...\n");
1418 /* Perform a newtonian search (along the Y-Axis) to find the closest point
1419 to use: Note that <currentX>, <maxX>, & <minX> are now misnamed. */
1420 while (abs(epsilon) >= 1)
1422 /* define the where <new>'s origin should go, based on the axis of motion: */
1423 tempOrgY = currentX - pivY;
1424 tempOrgX = (int)(((float)delX/(float)delY) * (float)currentX) + b - pivX;
1426 /* See if <new> can be placed: This involves checking everybody on
1427 the <tlist>: */
1428 for (tl = tlist; ((tl != NULL) && (flag == NULL)); tl = tl->next)
1430 sflag = area_search(start,
1431 tempOrgX + tl->this->x_pos, tempOrgY + tl->this->y_pos,
1432 tl->this->x_len, tl->this->y_len);
1433 if (flag == NULL) flag = sflag;
1436 if (flag != NULL)
1437 { /* The tile set can't go here. - try going further away */
1438 currentX = next_move(&minX, &maxX, currentX, FURTHER, &epsilon);
1440 else
1441 { /* The tiles can go here - try going closer */
1442 currentX = next_move(&minX, &maxX, currentX, CLOSER, &epsilon);
1443 *orgX = tempOrgX;
1444 *orgY = tempOrgY;
1445 foundOne = TRUE;
1447 flag = NULL;
1450 else
1452 fprintf(stderr, "angled_group_tile_help: NULL <delY>, <delX> values given.\n");
1455 /* Given a corner point where to insert the new area, add all of them to the new space: */
1456 for (tl = tlist; ((tl != NULL) && (foundOne == TRUE)); tl = tl->next)
1458 new = insert_tile(start, *orgX + tl->this->x_pos, *orgY + tl->this->y_pos,
1459 tl->this->x_len, tl->this->y_len, tl->this->this);
1460 if (new == NULL) foundOne = FALSE;
1463 /*Check to see that the insertion was successful: */
1464 if (new == NULL)
1466 /* fprintf(stderr, "angled_group_tile_help: failure to install tile\n"); */
1467 return(NULL);
1469 return(new);
1471 /*------------------------------------------------------------------------ */
1472 tile *angled_group_tile_insertion(start, anchX, anchY, delX, delY, pivX, pivY,
1473 orgX, orgY, tlist)
1474 tile *start; /* the starting (reference) tile */
1475 int anchX, anchY; /* XY origin of axis of motion (anchor point) in <start>'s
1476 tile space */
1477 int delX, delY; /* slope+dir of the axis of motion (line along which the new
1478 tiles move) */
1479 int pivX, pivY; /* the pivot point of the <new> tile set. (relative to (0,0)) */
1480 int *orgX, *orgY; /* to return the solution found */
1481 tilist *tlist; /* list of tiles to be inserted into <start>'s tile space */
1483 /* This returns a pointer to one of a set of newly-created tiles, created by adding
1484 * all of the tiles on <tlist> to the tile space defined by <start>. They are added
1485 * at some position lying along a line given at an angle defined by <ydir>/<xdir>.
1486 * The position closest to the anchor point is selected. */
1488 tilist *lineList = NULL, *tl;
1490 tile *cornerTile, *new = NULL;
1491 int x, y;
1492 int newAnchX = anchX, newAnchY = anchY;
1494 /* Make sure there is a useful axis of motion to use: */
1495 if ((delX == 0) && (delY == 0))
1497 fprintf(stderr, "angled_group_tile_insertion: Bad Axis of motion given.\n");
1498 return(NULL); /* Bad call */
1501 /* To locate the proper search space, map the axis of motion onto the tile-space:
1502 * this creates a list of tiles, starting with the anchor tile that will indicate
1503 * the limits of the search (maxX and minX)
1504 * COMMENT: This expansion should probably be more like a swath then a line.
1505 * */
1506 lineList = find_all_tiles_along_line(start, newAnchX, newAnchY,
1507 delX, delY, &lineList);
1509 /* Find the next corner-tile candidate and advance the <lineList> pointer to indicate
1510 what tiles have been examined */
1511 cornerTile = first_noncontiguous_full_tile(&lineList);
1513 /* See if this <cornerTile> defines an area where the tile can go: */
1514 while (lineList != NULL)
1516 new = angled_group_tile_help(start, newAnchX, newAnchY, delX, delY,
1517 pivX, pivY, orgX, orgY, tlist, cornerTile);
1519 if (new != NULL) break; /* The thing fit! */
1520 else /* The bloody thing didn't fit, so keep trying */
1522 /* reset the anchor-point and <cornerTile> and try again */
1523 /* The new anchor point is some point in the current cornerTile that
1524 lies along the axis of motion: */
1525 if (delX != 0)
1527 y = (int)((float)delY/(float)delX * (cornerTile->x_pos - newAnchX)) +
1528 newAnchY;
1530 if (delY != 0)
1532 x = (int)((float)delX/(float)delY * (cornerTile->x_pos - newAnchY)) +
1533 newAnchX;
1535 if ((y >= cornerTile->y_pos)&&(y <= (cornerTile->y_pos + cornerTile->y_len)))
1537 newAnchY = y;
1539 else newAnchY = cornerTile->y_pos;
1541 if ((x >= cornerTile->x_pos) && (x <= (cornerTile->x_pos + cornerTile->x_len)))
1543 newAnchX = x;
1545 else newAnchX = cornerTile->x_pos;
1547 /* Find the next <cornerTile> off the unused portion of <lineList> */
1548 cornerTile = first_noncontiguous_full_tile(&lineList);
1550 /*fprintf(stderr, "angled_group_tile_insertion: retrying at (%d, %d)\n",
1551 newAnchX, newAnchY); */
1555 if (new == NULL) new = angled_group_tile_help(start, newAnchX, newAnchY, delX, delY,
1556 pivX, pivY, orgX, orgY, tlist,
1557 cornerTile);
1559 /*Check to see that the insertion was successful: */
1560 if (new == NULL) fprintf(stderr, "angled_group_tile_insertion: Complete Failure\n");
1562 return(new);
1565 /*------------------------------------------------------------------------*/
1566 tile *delete_tile(deadTile)
1567 tile *deadTile;
1568 /* This functions removes <t> from the set of tiles, performing all of
1569 * the necessary mergers, etc.. The function returns an active pointer
1570 * to some tile in the space, often near the location of <deadTile>. */
1571 /* NOTE: This function depends upon the notion that the upper and right
1572 * border of a tile are included in the tile, but not the lower &
1573 * left sides. */
1575 tile *temp1, *temp2, *scrub_right();
1576 tilist *tl, *tll, *rightList, *leftList, *scrap;
1578 deadTile->this = NULL;
1579 rightList = list_neighbors(deadTile, RIGHT);
1580 leftList = list_neighbors(deadTile, LEFT);
1582 for (tl = rightList; tl != NULL; tl = tl->next)
1583 { /* Loop through <deadTile>'s right-hand neighbors */
1585 temp2 = scrub_right(deadTile, tl->this);
1588 for (tl = leftList; tl != NULL; tl = tl->next)
1589 { /* Loop through the right-hand neighbors to <deadTile>'s left hand neighbors:*/
1591 temp1 = tl->this;
1592 scrap = list_neighbors(temp1, RIGHT);
1593 for (tll = scrap; tll != NULL; tll = tll->next)
1595 temp2 = scrub_right(temp1, tll->this);
1597 free_list(scrap);
1600 /* Do a Vmerge on the bottom */
1601 if (temp2->lb != NULL) return(vmerge_tile(temp2->lb));
1602 (*manage_contents__dead_tile)(deadTile);
1604 free_list(leftList); free_list(rightList);
1605 return(temp2);
1608 /*----------------------------------------------------------------------------*/
1609 tile *scrub_right(left, right)
1610 tile *left, *right;
1612 /* given two tiles <right> & <left>, split and merge them appropriately
1613 to insure that they maintain the horizontal-strip relationship */
1615 int Ltop, Lbase, Rtop, Rbase;
1616 tile *left2, *right2;
1618 if (right == NULL) return(left);
1620 Rtop = right->y_pos + right->y_len;
1621 Rbase = right->y_pos;
1623 if (left != NULL)
1624 { /* Not on a left edge */
1625 Ltop = left->y_pos + left->y_len;
1626 Lbase = left->y_pos;
1628 if (Ltop > Rtop) /* split left @ y = Rtop */
1630 left2 = copy_tile(left); /* left2 becomes the lower tile */
1631 left2->rt = left;
1632 left2->y_len = Rtop - left2->y_pos;
1634 left->lb = left2; /* left becomes the upper tile */
1635 left->y_pos = Rtop;
1636 left->y_len -= left2->y_len;
1637 left->tr = locate(right, left2->x_pos + left2->x_len, Rtop);
1638 clean_up_neighbors(left);
1639 clean_up_neighbors(left2);
1641 hmerge_tile(left);
1642 vmerge_tile(left);
1643 hmerge_tile(left2);
1644 vmerge_tile(left2);
1645 return(left2);
1648 else if (Ltop < Rtop) /* spilt right @ y = Ltop */
1650 right2 = copy_tile(right); /* right2 becomes the lower tile */
1651 right2->rt = right;
1652 right2->y_len = Ltop - right2->y_pos;
1654 right->lb = right2; /* right becomes the upper tile */
1655 right->bl = locate(left, right2->x_pos, Ltop);
1656 right->y_pos = Ltop;
1657 right->y_len -= right2->y_len;
1659 clean_up_neighbors(right);
1660 clean_up_neighbors(right2);
1662 /* Look for other pieces above left to deal with */
1663 hmerge_tile(left->rt);
1664 vmerge_tile(left->rt);
1665 hmerge_tile(left);
1666 vmerge_tile(left);
1667 return(left);
1670 if (Lbase < Rbase) /* split left @ y = Rbase */
1672 left = locate(left, Rbase, Rtop); /* Redundant ? */
1673 left2 = copy_tile(left); /* left2 becomes the lower tile */
1674 left2->rt = left;
1675 left2->y_len = Rbase - left2->y_pos;
1676 left2->tr = locate(right, left2->x_pos + left2->x_len, Rbase);
1678 left->lb = left2; /* left becomes the upper tile */
1679 left->y_pos = Rbase;
1680 left->y_len -= left2->y_len;
1681 clean_up_neighbors(left);
1682 clean_up_neighbors(left2);
1684 hmerge_tile(left);
1685 vmerge_tile(left);
1686 hmerge_tile(left2);
1687 vmerge_tile(left2);
1688 return (left2);
1690 else /* No splits required, just do mergers */
1692 hmerge_tile(left);
1693 vmerge_tile(left);
1694 return(left);
1698 /*------------------------------------------------------------------------ */
1699 int clean_up_neighbors(who)
1700 tile *who;
1701 { /* See that all of <who>'s neighbors point to him. */
1702 tilist *tl, *temp;
1704 temp = list_neighbors(who, LEFT);
1705 for (tl = temp; tl != NULL; tl = tl->next)
1706 if (((tl->this->y_pos + tl->this->y_len) <= (who->y_pos + who->y_len)) &&
1707 (tl->this != who)) tl->this->tr = who;
1708 free_list(temp);
1710 temp = list_neighbors(who, RIGHT);
1711 for (tl = temp; tl != NULL; tl = tl->next)
1712 if ((tl->this->y_pos >= who->y_pos) && (tl->this != who))
1713 tl->this->bl = who;
1714 free_list(temp);
1716 temp = list_neighbors(who, TOP);
1717 for (tl = temp; tl != NULL; tl = tl->next)
1718 if ((tl->this->x_pos >= who->x_pos) && (tl->this != who))
1719 tl->this->lb = who;
1720 free_list(temp);
1722 temp = list_neighbors(who, BOTTOM);
1723 for (tl = temp; tl != NULL; tl = tl->next)
1724 if (((tl->this->x_pos + tl->this->x_len) <= (who->x_pos + who->x_len)) &&
1725 (tl->this != who)) tl->this->rt = who;
1726 free_list(temp);
1729 /*------------------------------------------------------------------------ */
1730 tilist *translate_origin(tl, x, y)
1731 tilist *tl;
1732 int x, y;
1734 /* Translate the location of all tiles on <tl> by the <x> & <y> given: */
1735 tilist *tll;
1736 for (tll = tl; tll != NULL; tll = tll->next)
1738 tll->this->x_pos += x;
1739 tll->this->y_pos += y;
1741 return(tl);
1743 /*------------------------------------------------------------------------ */
1744 int TileP(t)
1745 tile *t;
1747 return (TRUE);
1749 /*------------------------------------------------------------------------ */
1750 tilist *allspace(t, tl)
1751 tile *t; /* Some tile in area to search */
1752 tilist **tl; /* Where to list the located tiles */
1754 /* Form a list of all tiles within the area containing <t>.*/
1755 return(enumerate(t, tl, TileP));
1757 /*------------------------------------------------------------------------ */
1758 int freeSpaceP(t)
1759 tile *t;
1761 return (((*solidp)(t) == FALSE) ? TRUE : FALSE);
1763 /*------------------------------------------------------------------------ */
1764 tilist *freespace(t, tl)
1765 tile *t; /* Some tile in area to search */
1766 tilist **tl; /* Where to list the empty tiles */
1768 /* Form a list of all tiles within the area containing <t> that have
1769 no valid <this> entry: */
1770 return(enumerate(t, tl, freeSpaceP));
1773 /*------------------------------------------------------------------------ */
1774 int usedSpaceP(t)
1775 tile *t;
1777 return (((*solidp)(t) == FALSE) ? FALSE : TRUE);
1779 /*------------------------------------------------------------------------ */
1780 tilist *nonFreespace(t, tl)
1781 tile *t; /* Some tile in area to search */
1782 tilist **tl; /* Where to list the used tiles */
1784 /* Form a list of all tiles within the area containing <t> that have
1785 no valid <this> entry: */
1786 return(enumerate(t, tl, usedSpaceP));
1789 /*------------------------------------------------------------------------ */
1790 tilist *helpAreaEnumerate(t, soFar, filterFn, xorg, yorg, maxX, maxY)
1791 tile *t;
1792 tilist **soFar;
1793 int (*filterFn)(); /* given a tile, returns TRUE if the tile is to be
1794 listed */
1795 int xorg, yorg; /* Origin of area of interest (AOI) */
1796 int maxX, maxY; /* Extent of area of interest */
1799 { /* Return a list containing all tiles to the right of the given
1800 tile, within the prescribed area: */
1801 tilist *tl, *temp;
1802 int x = t->x_pos + t->x_len;
1803 int y = t->y_pos + t->y_len;
1805 if (debug_level == 5)
1806 fprintf(stderr, "t=0x%x (%d, %d)->(%d, %d) in (%d, %d)->(%d, %d) ? ",
1807 t, t->x_pos, t->y_pos, x, y, xorg, yorg, maxX, maxY);
1809 /* If <t> is in the specified range, add it to the listing: */
1810 if ((filterFn(t) != FALSE) &&
1811 ((((x <= maxX) && (x > xorg)) ||
1812 ((t->x_pos < maxX) && (t->x_pos >= xorg)) ||
1813 ((x >= maxX) && (t->x_pos <= xorg)))
1815 (((y <= maxY) && (y > yorg)) ||
1816 ((t->y_pos < maxY) && (t->y_pos >= yorg)) ||
1817 ((y >= maxY) && (t->y_pos <= yorg)))))
1819 push(t, soFar); /* Enumerate the little bugger */
1820 if (debug_level == 5)
1821 fprintf(stderr, "yes!\n");
1823 else
1824 if (debug_level == 5)
1825 fprintf(stderr, "no.\n");
1828 if (t->tr != NULL)
1829 { /* Enmumerate all of the tiles on the right-side of the given tile: */
1830 temp = list_neighbors(t, RIGHT);
1831 for (tl = temp; (tl != NULL) && (tl->this->x_pos < maxX); tl = tl->next)
1833 if (tl->this->bl == t)
1834 helpAreaEnumerate(tl->this, soFar, filterFn, xorg, yorg, maxX, maxY);
1836 free_list(temp);
1838 return(*soFar);
1841 /*------------------------------------------------------------------------ */
1842 tilist *area_enumerate(t, soFar, filterFn, xorg, yorg, xext, yext)
1843 tile *t;
1844 tilist **soFar;
1845 int (*filterFn)(); /* given a tile, returns TRUE if the tile is to be
1846 listed */
1847 int xorg, yorg; /* Origin of area of interest (AOI) */
1848 int xext, yext; /* Extent of area of interest */
1850 { /* Return a list containing all tiles within the area defined by <t>
1851 which return TRUE when passed to the <filterFn>. */
1852 tile *temp;
1853 int maxX = xorg + xext;
1854 int maxY = yorg + yext;
1856 /* Walk down the left edge of the AOI: */
1857 for (temp = locate(t, xorg, maxY);
1858 ((temp != NULL) && ((temp->y_pos >= yorg) ||
1859 (temp->y_pos + temp->y_len > yorg)));
1860 temp = locate(temp->lb, xorg, temp->y_pos))
1862 *soFar = helpAreaEnumerate(temp, soFar, filterFn, xorg, yorg, maxX, maxY);
1864 return(*soFar);
1866 /*------------------------------------------------------------------------ */
1867 tilist *helpEnumerate(t, soFar, filterFn)
1868 tile *t;
1869 tilist **soFar;
1870 int (*filterFn)(); /* given a tile, returns TRUE if the tile is to be
1871 listed */
1873 { /* Return a list containing all tiles to the right of the given tile,
1874 which return TRUE when passed to the <filterFn>. */
1875 tilist *tl, *temp;
1877 /* Add the given tile to the listing: */
1878 if (filterFn(t) != FALSE) push(t, soFar);
1880 if (t->tr != NULL)
1881 { /* Enmumerate all of the tiles on the right-side of the given tile: */
1882 temp = list_neighbors(t, RIGHT);
1883 for (tl = temp; tl != NULL; tl = tl->next)
1885 if (tl->this->bl == t) helpEnumerate(tl->this, soFar, filterFn);
1887 free_list(temp);
1889 return(*soFar);
1892 /*------------------------------------------------------------------------------- */
1893 tilist *enumerate(t, soFar, filterFn)
1894 tile *t;
1895 tilist **soFar;
1896 int (*filterFn)(); /* given a tile, returns TRUE if the tile is to be listed */
1898 { /* Return a list containing all tiles within the area defined by <t> which
1899 return TRUE when passed to the <filterFn>. */
1900 tile *temp;
1901 for (temp = find_ULHC(t); temp != NULL; temp = temp->lb)
1903 *soFar = helpEnumerate(temp, soFar, filterFn);
1905 return(*soFar);
1908 /*------------------------------------------------------------------------ */
1909 tile *find_ULHC(t)
1910 tile *t;
1912 tile *temp = t;
1914 /* find the upper-left-hand corner of the given tile-set */
1915 if ((temp->bl == NULL) && (temp->rt == NULL)) return(temp);
1917 /* Walk up to the proper 'row':*/
1918 while (temp->rt != NULL) temp = temp->rt;
1920 /* Walk over to the proper 'column': */
1921 while (temp->bl != NULL) temp = temp->bl;
1923 return(find_ULHC(temp));
1925 /*------------------------------------------------------------------------ */
1926 tile *find_LRHC(t)
1927 tile *t;
1929 tile *temp = t;
1931 /* find the lower-right-hand corner of the given tile-set */
1932 if ((temp->lb == NULL) && (temp->tr == NULL)) return(temp);
1934 /* Walk up to the proper 'row':*/
1935 while (temp->lb != NULL) temp = temp->lb;
1937 /* Walk over to the proper 'column': */
1938 while (temp->tr != NULL) temp = temp->tr;
1940 return(find_LRHC(temp));
1942 /*------------------------------------------------------------------------ */
1943 tilist *find_all_tiles_along_line(start, srcX, srcY, delX, delY, soFar)
1944 tile *start;
1945 int srcX, srcY, delX, delY;
1946 tilist **soFar;
1948 /* This function walks down the given line, and adds each tile it encounters to
1949 the list returned. */
1951 tile *temp = NULL, *neighbor;
1952 tilist *tl; /* Used to search through <soFar> to avoid replicate entry */
1954 int x, y, xx, yy; /* point on <temp>'s far edge that lies on the line */
1955 int bx, by;
1956 int yset = FALSE, xset = FALSE;
1957 int nextX, nextY;
1959 temp = locate(start, srcX, srcY);
1960 if (temp == NULL) return(*soFar);
1962 if (temp == start) /* <srcX> and <srcY> are in <start> */
1964 /* Recursion Stop?? */
1965 if ((temp->x_pos == srcX) || ((temp->x_pos + temp->x_len == srcX)))
1967 /* fprintf(stderr,
1968 "find_all_tiles_along_line: Hit edge of space along Y-dimension\n"); */
1969 return(*soFar);
1972 else if ((temp->y_pos == srcY) ||
1973 ((temp->y_pos + temp->y_len == srcY)))
1975 /* fprintf(stderr,
1976 "find_all_tiles_along_line: Hit edge of space along X-dimension\n"); */
1977 return(*soFar);
1979 /* else
1981 fprintf(stderr,
1982 "find_all_tiles_along_line: Problem, am totally lost! \n");
1987 /* Due to the strageness introduced by adding all tiles around a corner
1988 that lies on a line, check to see if this tile is on the list already,
1989 so he isn't added twice. Note that this means that only the last two
1990 entries on the list need be checked. If <temp> is not on <soFar>,
1991 then add him. If so, don't add him. */
1993 for (tl = *soFar; ((tl != NULL) && (tl->next != NULL) &&
1994 (tl->next->next == NULL));
1995 tl = tl->next);
1997 /* Now at or near the end of <soFar> */
1998 if (tl == NULL) queue(temp, soFar); /* list_length(*soFar) = 0 */
1999 else if ((tl->next != NULL) && ((tl->this != temp) && (tl->next->this != temp)))
2000 queue(temp, soFar); /* list_length(*soFar) = 2 */
2001 else if ((tl->this != temp) && (tl->next == NULL)) queue(temp, soFar);
2002 /* list_length(*soFar) = 1*/
2004 /* Find the points where the line intersects the edge of the tile: */
2005 if (delX != 0)
2007 xx = (delX < 0) ? temp->x_pos : temp->x_pos + temp->x_len;
2008 by = ( srcY - (int)((float)delY/(float)delX * (float)srcX) );
2009 y = (int)((float)delY/(float)delX * (float)xx) + by;
2010 nextY = (int)((float)delY/(float)delX *
2011 ((float)xx + (float)delX/abs(delX))) + by;
2012 if ((y <= (temp->y_pos + temp->y_len)) && (y >= temp->y_pos))
2013 yset = TRUE;
2016 if (delY != 0)
2018 yy = (delY < 0) ? temp->y_pos : temp->y_pos + temp->y_len;
2019 bx = ( srcX - (int)((float)delX/(float)delY * (float)srcY) );
2020 x = (int)((float)delX/(float)delY * (float)yy) + bx;
2021 nextX = (int)((float)delX/(float)delY *
2022 ((float)yy + (float)delY/abs(delY))) + bx;
2023 if ((x <= (temp->x_pos + temp->x_len)) && (x >= temp->x_pos))
2024 xset = TRUE;
2027 /* now that these calculations are done, locate the edge intersection: */
2028 if ((yset == TRUE) && (xset == TRUE)) /* The point is a corner @ (x,y) */
2030 y = yy; /* This causes other problems */
2031 x = xx;
2032 if (delY > 0) /* Upper... */
2034 if (delX > 0) /* Right-Hand Corner */
2036 /* nextX = x + 1; Might be needed....
2037 nextY = y + 1; */
2038 if (temp->tr != NULL) queue(temp->tr, soFar);
2039 if (temp->rt != NULL) queue(temp->rt, soFar);
2041 else /* Left Hand Corner */
2043 neighbor = locate(temp, x - 1, y + 1);
2044 if (neighbor != NULL) queue(neighbor, soFar);
2045 /* tiles might get on <soFar>2x */
2046 neighbor = locate(temp, x - 1, y - 1);
2047 if (neighbor != NULL) queue(neighbor, soFar);
2050 else /* Lower... */
2052 if (delX > 0) /* Right-Hand Corner */
2054 neighbor = locate(temp, x + 1, y - 1);
2055 if (neighbor != NULL) queue(neighbor, soFar);
2056 neighbor = locate(temp, x - 1, y - 1);
2057 if (neighbor != NULL) queue(neighbor, soFar);
2059 else /* Left Hand Corner */
2061 if (temp->lb != NULL) queue(temp->lb, soFar);
2062 if (temp->bl != NULL) queue(temp->bl, soFar);
2067 else if (yset == TRUE) /* The point is along the
2068 left/right side */
2070 if (delX < 0) nextX = x = temp->x_pos; /* left side */
2071 else nextX = x = temp->x_pos + temp->x_len + 1; /* right side */
2073 else if (xset == TRUE) /* The point is along the
2074 top/bottom edge */
2076 if (delY < 0) nextY = y = temp->y_pos; /* bottom */
2077 else nextY = y = temp->y_pos + temp->y_len + 1; /* top */
2079 else /* Problem... */
2081 fprintf(stderr, "find_all_tiles_along_line: can't find anything! \n");
2085 return(find_all_tiles_along_line(temp, nextX, nextY, delX, delY, soFar));
2088 /*------------------------------------------------------------------------ */
2089 tilist *find_all_tiles_along_swath(start, srcX, srcY, delX, delY,
2090 width, length, soFar)
2091 tile *start; /* Tile in which to start looking */
2092 int srcX, srcY; /* Center Point on line (in start?) */
2093 int delX, delY; /* Slope of line */
2094 int width, length; /* Width & Length of swath being checked */
2095 tilist **soFar; /* Where to list the tiles found */
2097 /* This function walks down the given line, and adds each tile it encounters to
2098 the list returned. A tile is encountered if it touches the given swath at
2099 any point. */
2101 int cx1, cx2, cx3, cx4, lxProj;
2102 int cy1, cy2, cy3, cy4, lyProj;
2103 float cosTheta, sinTheta, a = (float)width/2.0;
2104 /* the tricky part is to determine the corner points for the AOI given by the
2105 swath: */
2107 if (delX == 0) /* Handle the special cases: */
2109 cx1 = srcX - (int)(a + 0.5); cx3 = srcX + (int)(a + 0.5);
2110 cx2 = srcX - (int)(a + 0.5); cx4 = srcX + (int)(a + 0.5);
2111 cy1 = srcY; cy4 = srcY;
2113 if (delY >= 0)
2115 cy2 = srcY + length; cy3 = srcY + length;
2117 else
2119 cy2 = srcY - length; cy3 = srcY - length;
2122 else if (delY == 0)
2124 cy1 = srcY + (int)(a + 0.5); cy2 = srcY + (int)(a + 0.5);
2125 cy3 = srcY - (int)(a + 0.5); cy3 = srcY - (int)(a + 0.5);
2126 cx1 = srcX; cx4 = srcX;
2127 if (delX >= 0)
2129 cx2 = srcX + length; cx3 = srcX + length;
2131 else
2133 cx2 = srcX - length; cx3 = srcX - length;
2137 /* Now the arctangent is defined, so use it: */
2138 else
2140 cosTheta = (float) cos((double)atan((double)delY/(double)delX));
2141 sinTheta = (float) sin((double)atan((double)delY/(double)delX));
2142 lxProj = (int)(((double)length * cosTheta) + 0.5);
2143 lyProj = (int)(((double)length * sinTheta) + 0.5);
2144 cx1 = srcX + (int)((a * cosTheta) + 0.5);
2145 cx4 = srcX - (int)((a * cosTheta) + 0.5);
2146 cx2 = srcX + (int)((a * cosTheta) + 0.5) + lxProj;
2147 cx3 = srcX - (int)((a * cosTheta) + 0.5) + lxProj;
2149 cy1 = srcY + (int)((a * sinTheta) + 0.5);
2150 cy4 = srcY - (int)((a * sinTheta) + 0.5);
2151 cy2 = srcY + (int)((a * sinTheta) + 0.5) + lyProj;
2152 cy3 = srcY - (int)((a * sinTheta) + 0.5) + lyProj;
2155 /* INCOMPLETE>>>>>> */
2156 return(NULL);
2158 /*------------------------------------------------------------------------ */
2159 /*------------------------------------------------------------------------ */
2160 tile *first_noncontiguous_full_tile(tlist)
2161 tilist **tlist;
2162 { /* Return the first non-empty ((*solidp)) tile on the given <tlist> */
2163 /* <tlist> had best be an ordered list. */
2165 tilist *tl;
2166 int returnNextFullTile = FALSE;
2168 for (tl = *tlist; (tl != NULL); tl = tl->next)
2170 if ((returnNextFullTile == TRUE) && ((*solidp)(tl->this) == TRUE))
2172 *tlist = tl;
2173 return(tl->this);
2175 else if (((*solidp)(tl->this) == FALSE) && (tl->next != NULL))
2176 returnNextFullTile = TRUE;
2178 *tlist = tl;
2179 return(NULL);
2182 /*---------------------------------------------------------------
2183 * Space statistics:
2184 *---------------------------------------------------------------
2186 /*------------------------------------------------------------------------ */
2187 tile *best_tile_in_space(t, filterFn)
2188 tile *t; /* some tile in the desired tile space */
2189 int (*filterFn)(); /* returns TRUE if <t1> is better than <t2>. */
2192 /* This returns the best filled tile in the given tile space. */
2194 tilist *tl = NULL;
2195 tile *temp;
2197 tl = nonFreespace(t, &tl);
2198 temp = tl->this;
2200 for (tl = tl->next; (tl != NULL); tl = tl->next)
2202 temp = (filterFn(temp, tl->this) != FALSE) ? temp : tl->this;
2204 return(temp);
2207 /*------------------------------------------------------------------------ */
2208 int adjacent_tiles_p(t1, t2)
2209 tile *t1, *t2;
2211 /* Return TRUE iff t1 & t2 share a common edge */
2212 if ((t1 == NULL) || (t2 == NULL)) return(TRUE);
2213 else if ((t1->x_pos == t2->x_pos + t2->x_len) ||
2214 (t2->x_pos == t1->x_pos + t1->x_len) ||
2215 (t1->y_pos == t2->y_pos + t2->y_len) ||
2216 (t2->y_pos == t1->y_pos + t1->y_len)) return(TRUE);
2217 else return(FALSE);
2219 /*------------------------------------------------------------------------ */
2220 int most_right(t1, t2)
2221 tile *t1, *t2;
2223 /* given two tiles, return TRUE if the right-edge of <t1> is further to
2224 the right than the right edge of <t2>: */
2225 if ((t1->x_pos + t1->x_len) > (t2->x_pos + t2->x_len)) return(TRUE);
2226 else return(FALSE);
2229 /*------------------------------------------------------------------------ */
2230 int most_left(t1, t2)
2231 tile *t1, *t2;
2233 /* given two tiles, return TRUE if the left edge of <t1> is further to
2234 the left than the left edge of <t2>: */
2235 if (t1->x_pos < t2->x_pos) return (TRUE);
2236 else return(FALSE);
2239 /*------------------------------------------------------------------------ */
2240 int most_up(t1, t2)
2241 tile *t1, *t2;
2243 /* given two tiles, return TRUE if the top-edge of <t1> is further up
2244 than the top edge of <t2>: */
2245 if ((t1->y_pos + t1->y_len) > (t2->y_pos + t2->y_len)) return (TRUE);
2246 else return(FALSE);
2249 /*------------------------------------------------------------------------ */
2250 int most_down(t1, t2)
2251 tile *t1, *t2;
2253 /* given two tiles, return TRUE if the bottom-edge of <t1> is further
2254 down than the bottom edge of <t2>: */
2255 if (t1->y_pos < t2->y_pos) return (TRUE);
2256 else return(FALSE);
2259 /*------------------------------------------------------------------------ */
2260 int verify_tile_space(t)
2261 tile *t;
2263 /* This checks to see if the tile space is corrupted: */
2264 tilist *tl = NULL, *tll = NULL, *errorList = NULL;
2265 tile *tp;
2266 int error = FALSE;
2268 if (t == NULL) return(TRUE); /* Let someone else catch this error */
2270 /* First check the given tile... */
2271 tp = t;
2272 if(((tp->rt != NULL) && (tp->rt->y_pos != (tp->y_pos + tp->y_len))) ||
2273 ((tp->rt == NULL) && (tp->tr != NULL) &&
2274 ((tp->tr->y_pos + tp->tr->y_len) > tp->y_pos + tp->y_len)) ||
2275 ((tp->rt != NULL) && ((tp->x_pos + tp->x_len) <= tp->rt->x_pos)) ||
2276 ((tp->rt != NULL) && ((tp->x_pos + tp->x_len) >
2277 (tp->rt->x_pos + tp->rt->x_len))))
2279 { /* the top tile/tile pointer is screwed */
2280 error = TRUE;
2281 push(tp, &errorList);
2283 else if (((tp->tr != NULL) && (tp->tr->x_pos != (tp->x_pos + tp->x_len))) ||
2284 ((tp->tr == NULL) && (tp->rt != NULL) &&
2285 ((tp->rt->x_pos + tp->rt->x_len) > tp->x_pos + tp->x_len)) ||
2286 ((tp->tr != NULL) && ((tp->y_pos + tp->y_len) <= tp->tr->y_pos)) ||
2287 ((tp->tr != NULL) && ((tp->y_pos + tp->y_len) >
2288 (tp->tr->y_pos + tp->tr->y_len))))
2289 { /* the right tile/tile pointer is screwed */
2290 error = TRUE;
2291 push(tp, &errorList);
2293 else if (((tp->lb != NULL) && ((tp->lb->y_pos + tp->lb->y_len) != tp->y_pos)) ||
2294 ((tp->lb == NULL) && (tp->bl != NULL) && (tp->bl->y_pos < tp->y_pos)) ||
2295 ((tp->lb != NULL) && (tp->x_pos < tp->lb->x_pos)) ||
2296 ((tp->lb != NULL) && (tp->x_pos >= (tp->lb->x_pos + tp->lb->x_len))))
2297 { /* the bottom tile/tile pointer is screwed */
2298 error = TRUE;
2299 push(tp, &errorList);
2301 else if (((tp->bl != NULL) && ((tp->bl->x_pos + tp->bl->x_len) != tp->x_pos)) ||
2302 ((tp->bl == NULL) && (tp->lb != NULL) && (tp->lb->x_pos < tp->x_pos)) ||
2303 ((tp->bl != NULL) && (tp->y_pos < tp->bl->y_pos)) ||
2304 ((tp->bl != NULL) && (tp->y_pos >= (tp->bl->y_pos + tp->bl->y_len))))
2305 { /* The left tile/tile pointer is screwed */
2306 error = TRUE;
2307 push(tp, &errorList);
2310 /* Then check the whole tile space */
2311 tl = allspace(t, &tl);
2312 for (tll = tl; (tll != NULL); tll = tll->next)
2314 tp = tll->this;
2315 if(((tp->rt != NULL) && (tp->rt->y_pos != (tp->y_pos + tp->y_len))) ||
2316 ((tp->rt == NULL) && (tp->tr != NULL) &&
2317 ((tp->tr->y_pos + tp->tr->y_len) > tp->y_pos + tp->y_len)) ||
2318 ((tp->rt != NULL) && ((tp->x_pos + tp->x_len) <= tp->rt->x_pos)) ||
2319 ((tp->rt != NULL) && ((tp->x_pos + tp->x_len) >
2320 (tp->rt->x_pos + tp->rt->x_len))))
2322 { /* the top tile/tile pointer is screwed */
2323 error = TRUE;
2324 push(tp, &errorList);
2326 else if (((tp->tr != NULL) && (tp->tr->x_pos != (tp->x_pos + tp->x_len))) ||
2327 ((tp->tr == NULL) && (tp->rt != NULL) &&
2328 ((tp->rt->x_pos + tp->rt->x_len) > tp->x_pos + tp->x_len)) ||
2329 ((tp->tr != NULL) && ((tp->y_pos + tp->y_len) <= tp->tr->y_pos)) ||
2330 ((tp->tr != NULL) && ((tp->y_pos + tp->y_len) >
2331 (tp->tr->y_pos + tp->tr->y_len))))
2332 { /* the right tile/tile pointer is screwed */
2333 error = TRUE;
2334 push(tp, &errorList);
2336 else if (((tp->lb != NULL) && ((tp->lb->y_pos + tp->lb->y_len) != tp->y_pos)) ||
2337 ((tp->lb == NULL) && (tp->bl != NULL) && (tp->bl->y_pos < tp->y_pos)) ||
2338 ((tp->lb != NULL) && (tp->x_pos < tp->lb->x_pos)) ||
2339 ((tp->lb != NULL) && (tp->x_pos >= (tp->lb->x_pos + tp->lb->x_len))))
2340 { /* the bottom tile/tile pointer is screwed */
2341 error = TRUE;
2342 push(tp, &errorList);
2344 else if (((tp->bl != NULL) && ((tp->bl->x_pos + tp->bl->x_len) != tp->x_pos)) ||
2345 ((tp->bl == NULL) && (tp->lb != NULL) && (tp->lb->x_pos < tp->x_pos)) ||
2346 ((tp->bl != NULL) && (tp->y_pos < tp->bl->y_pos)) ||
2347 ((tp->bl != NULL) && (tp->y_pos >= (tp->bl->y_pos + tp->bl->y_len))))
2348 { /* The left tile/tile pointer is screwed */
2349 error = TRUE;
2350 push(tp, &errorList);
2353 if (error == FALSE) return(TRUE);
2354 return(FALSE);
2357 /*------------------------------------------------------------------------ */
2358 void ps_print_tile_edges(f, t)
2359 FILE *f; /* Where to write things */
2360 tile *t; /* The tile to be printed */
2362 /* This function prints a dotted line that corresponds to the border of the
2363 tile in question. Normally, print only the left and top borders of the
2364 tile, and let the other tiles fill in the bottom and right sides. This
2365 leaves the special cases, where the tile is on the edge of the tilespace. */
2367 int x1, y1, x2, y2;
2369 if (t != NULL)
2371 x1 = t->x_pos; y1 = t->y_pos;
2372 x2 = x1 + t->x_len; y2 = y1 + t->y_len;
2374 fprintf(f,"%%%% Tile and contents for %x LLHC(%d,%d), URHC=(%d,%d) %%%%\n",
2375 t, x1, y1, x2, y2);
2376 fprintf(f,"[1 2] 0.2 setdash\n");
2377 fprintf(f, "newpath %d %d moveto %d %d lineto ", x1, y1, x1, y2); /* left edge */
2378 fprintf(f, "%d %d lineto stroke \n", x2, y2); /* top edge */
2380 if (t->tr == NULL)
2382 fprintf(f, "newpath %d %d moveto %d %d lineto stroke\n", x2, y2, x2, y1);
2385 if (t->lb == NULL)
2387 fprintf(f, "newpath %d %d moveto %d %d lineto stroke\n", x1, y1, x2, y1);
2389 fprintf(f, "[] 0 setdash\n");
2392 /*------------------------------------------------------------------------ */
2393 /*------------------------------------------------------------------------ */
2394 void enumerateForPrinting(t, f, printFn, edgesP)
2395 tile *t;
2396 FILE *f;
2397 int (*printFn)(); /* given a tile, produces POSTSCRIPT output to file <f>*/
2398 int edgesP; /* Flag to indicate edge printing */
2400 { /* Return a list containing all tiles to the right of the given tile, which return
2401 * TRUE when passed to the <filterFn>. */
2402 tilist *tl, *temp;
2404 /* Print the given tile to the listing: */
2405 if(edgesP == TRUE) ps_print_tile_edges(f, t);
2407 if ((*solidp)(t) == TRUE) printFn(f,t);
2409 /* Print the remaining tiles in the current 'row': */
2410 if (t->tr != NULL)
2411 { /* Enmumerate all of the tiles on the right-side of the given tile: */
2412 temp = list_neighbors(t, RIGHT);
2413 for (tl = temp; tl != NULL; tl = tl->next)
2415 if (tl->this->bl == t) enumerateForPrinting(tl->this, f, printFn, edgesP);
2417 free_list(temp);
2420 /*------------------------------------------------------------------------ */
2421 void ps_print_tile_space(t, f, ps_printFn, edgesP)
2422 tile *t;
2423 FILE *f; /* Where to print the stuff to */
2424 int (*ps_printFn)(); /* given a file and a tile, print post-script code to represent
2425 * the contents of the tile. Should be able to handle NULL. */
2426 int edgesP; /* Flag that indicates the inclusion of the tile edges */
2428 { tile *temp;
2430 for (temp = find_ULHC(t); temp != NULL; temp = temp->lb)
2432 enumerateForPrinting(temp, f, ps_printFn, edgesP);
2435 /*------------------------------------------------------------------------ */
2436 /*---------------------------------------------------------------
2437 * END OF FILE
2438 *---------------------------------------------------------------