2 /************************************************************
4 ** COPYRIGHT (C) 1993 UNIVERSITY OF PITTSBURGH
5 ** COPYRIGHT (C) 1996 GANNON UNIVERSITY
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 ************************************************************/
24 /* ------------------------------------------------------------------------
25 * Common definitions for Corner Stiching (see Osterhout '84 DAC paper) 1/90 stf
27 * ------------------------------------------------------------------------
33 extern int debug_level
;
35 /*------- Forward !#*&^@!*#@ Reference ------------------------- */
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;
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
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 /*------------------------------------------------------------------------ */
88 /*------------------------------------------------------------------------ */
89 /*------------------------------------------------------------------------ */
90 void reset_boundaries(root
, 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
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
;
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: */
126 for(tl
= right
; tl
!= NULL
; tl
= tl
->next
)
128 if (tl
->this->x_pos
>= maxX
) maxX
= tl
->this->x_pos
+ 1;
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: */
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; ) */
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
)
184 int *x1
, *y1
, *x2
, *y2
;
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. */
194 /* Reset the bb based on the minimum permissible boundry: */
196 reset_boundaries(root
, 0, 0, 0, 0);
198 ul
= find_ULHC(root
);
199 lr
= find_LRHC(root
);
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
;
211 /* Create a tile from scratch */
214 t
= (tile
*)calloc(1, sizeof(tile
));
220 t
->bl
= t
->lb
= t
->rt
= t
->tr
= NULL
;
223 /*------------------------------------------------------------------------ */
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
);
235 /*------------------------------------------------------------------------ */
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. */
243 tilist
*tl
= NULL
, *scrap
;
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
;
259 /* need to fix all of the pointers pointing to <temp> so they will
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)) &&
266 if (tl
->this->rt
== temp
) tl
->this->rt
= t
;
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
;
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
;
286 (*manage_contents__hmerge
)(t
, temp
);
287 (*manage_contents__dead_tile
)(temp
);
294 /*------------------------------------------------------------------------ */
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. */
302 tilist
*tl
= NULL
, *scrap
;
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
;
319 /* need to fix all of the pointers pointing to <temp> so they will
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)) &&
327 if (tl
->this->tr
== temp
) tl
->this->tr
= t
;
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
;
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
;
347 (*manage_contents__vmerge
)(t
, temp
);
348 (*manage_contents__dead_tile
)(temp
);
356 /*------------------------------------------------------------------------ */
357 /*------------------------------------------------------------------------ */
358 tile
*locate(start
, 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. */
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
));
384 /*------------------------------------------------------------------------ */
385 tilist
*list_neighbors(who
, side
)
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
;
396 case(TOP
): { s
= who
->rt
;
401 while((s
!= NULL
) && (s
->x_pos
>= who
->x_pos
))
410 case(RIGHT
): { s
= who
->tr
;
415 while((s
!= NULL
) && (s
->y_pos
>= who
->y_pos
))
424 case(BOTTOM
): { s
= who
->lb
;
429 while((s
!= NULL
) && (s
->x_pos
< who
->x_pos
+ who
->x_len
))
438 case(LEFT
): { s
= who
->bl
;
443 while((s
!= NULL
) && (s
->y_pos
< who
->y_pos
+ who
->y_len
))
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
));
475 /*------------------------------------------------------------------------ */
478 /* return TRUE iff tile t is used. */
480 return((t
->this != NULL
) ? TRUE
: FALSE
);
482 /*------------------------------------------------------------------------ */
483 void std_insert_contents(t
, w
)
486 { /* Make the standard assignment for tile contents (add <w> to <t>) */
489 /*------------------------------------------------------------------------ */
490 int std_contents_equivalentp(t1
, t2
)
492 { /* Return TRUE if the tiles are of the same color */
493 if (t1
->this == t2
->this) return(TRUE
);
496 /*------------------------------------------------------------------------ */
497 int containsp(t
, 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
);
508 /*------------------------------------------------------------------------ */
509 list
*create_tile_pair(t1
, t2
)
512 /* Create a list that is an ordered pair of tiles */
513 list
*l
= (list
*)calloc(1, sizeof(tilist
));
518 /*------------------------------------------------------------------------ */
519 tile
*vsplit_tile(p
, y
)
523 /* Split <p> along the axis <y>. Return the lower tile. All pointers should be
524 correct. Opposite of "vmerge" */
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 */
531 p
->y_len
= p
->y_pos
+ p
->y_len
- y
;
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
);
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
)
572 /* Split <p> along the axis <x>. Return the rh tile. All pointers should be
573 correct. Opposite of "hmerge" */
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 */
580 c
->x_len
= p
->x_pos
+ p
->x_len
- x
;
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
);
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
;
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. */
651 new = hsplit_tile(left
, xorg
);
652 right
= hsplit_tile(new, x
);
654 insert_contents(new, what
);
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");
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 */
694 return (*min
+ *epsilon
);
696 else/* (direction == CLOSER) */
698 /* Move in the direction of <min> */
699 *epsilon
= (*epsilon
== 1) ? 0 : (current
- *min
+ 1)/ 2;
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
711 int pivX
, pivY
; /* the pivot point of the <new> tile. (relative to (0,0),
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. */
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
739 if (cornerTile
!= NULL
)
741 /* There is a tile <cornerTile> lying along the line that may interfere: */
743 { /* Moving to the right: */
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 @
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
;
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 +
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
)) +
776 /* intersection occurs along left edge of <cornerTile> */
777 maxX
= cornerTile
->x_pos
;
782 { /* Moving to the left: */
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
;
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 =
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
)) +
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: */
826 { /* Moving to the right: */
827 cornerTile
= find_LRHC(start
);
829 maxX
= cornerTile
->x_pos
+ cornerTile
->x_len
;
832 { /* Moving to the left: */
833 cornerTile
= find_ULHC(start
);
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
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
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
);
867 { /* The tile can't go here. - try going further away */
868 currentX
= next_move(&minX
, &maxX
, currentX
, FURTHER
, &epsilon
);
871 { /* The tile can go here - try going closer */
872 currentX
= next_move(&minX
, &maxX
, currentX
, CLOSER
, &epsilon
);
880 /* Otherwise, operate on the top and bottom 90 degree arcs: */
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
)
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 @
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
;
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 +
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
)) +
922 /* intersection occurs along bottom edge of <cornerTile> */
923 maxX
= cornerTile
->y_pos
;
928 { /* Moving Down: (delY < 0) */
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
;
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 =
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
)) +
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: */
972 cornerTile
= find_ULHC(start
);
974 maxX
= cornerTile
->y_pos
+ cornerTile
->y_len
;
978 cornerTile
= find_LRHC(start
);
979 maxX
= cornerTile
->y_pos
;
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
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
);
1011 { /* The tile can't go here. - try going further away */
1012 currentX
= next_move(&minX
, &maxX
, currentX
, FURTHER
, &epsilon
);
1015 { /* The tile can go here - try going closer */
1016 currentX
= next_move(&minX
, &maxX
, currentX
, CLOSER
, &epsilon
);
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");*/
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
1043 int pivX
, pivY
; /* the pivot point of the <new> tile. (relative to (0,0),
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
;
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.
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: */
1091 y
= (int)((float)delY
/(float)delX
* (cornerTile
->x_pos
- newAnchX
)) + newAnchY
;
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
)))
1101 else newAnchY
= cornerTile
->y_pos
;
1103 if ((x
>= cornerTile
->x_pos
) && (x
<= (cornerTile
->x_pos
+ cornerTile
->x_len
)))
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");
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
1132 int delX
, delY
; /* slope+dir of the axis of motion (line along which the
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
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. */
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
1162 if (cornerTile
!= NULL
)
1164 /* There is a tile <cornerTile> lying along the line that may interfere: */
1166 { /* Moving to the right: */
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
;
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
;
1196 /* intersection occurs along left edge of <cornerTile> */
1197 maxX
= cornerTile
->x_pos
;
1202 { /* Moving to the left: */
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
;
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
;
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: */
1244 { /* Moving to the right: */
1245 cornerTile
= find_LRHC(start
);
1247 maxX
= cornerTile
->x_pos
+ cornerTile
->x_len
;
1250 { /* Moving to the left: */
1251 cornerTile
= find_ULHC(start
);
1252 maxX
= cornerTile
->x_pos
;
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
;
1288 { /* The tile set can't go here. - try going further away */
1289 currentX
= next_move(&minX
, &maxX
, currentX
, FURTHER
, &epsilon
);
1292 { /* The tiles can go here - try going closer */
1293 currentX
= next_move(&minX
, &maxX
, currentX
, CLOSER
, &epsilon
);
1302 /* Otherwise, operate on the top and bottom 90 degree arcs: */
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
)
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
;
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
;
1341 /* intersection occurs along bottom edge of <cornerTile> */
1342 maxX
= cornerTile
->y_pos
;
1347 { /* Moving Down: (delY < 0) */
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
;
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
)) +
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: */
1390 cornerTile
= find_ULHC(start
);
1392 maxX
= cornerTile
->y_pos
+ cornerTile
->y_len
;
1395 { /* Moving Down: */
1396 cornerTile
= find_LRHC(start
);
1397 maxX
= cornerTile
->y_pos
;
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
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
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
;
1437 { /* The tile set can't go here. - try going further away */
1438 currentX
= next_move(&minX
, &maxX
, currentX
, FURTHER
, &epsilon
);
1441 { /* The tiles can go here - try going closer */
1442 currentX
= next_move(&minX
, &maxX
, currentX
, CLOSER
, &epsilon
);
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: */
1466 /* fprintf(stderr, "angled_group_tile_help: failure to install tile\n"); */
1471 /*------------------------------------------------------------------------ */
1472 tile
*angled_group_tile_insertion(start
, anchX
, anchY
, delX
, delY
, pivX
, pivY
,
1474 tile
*start
; /* the starting (reference) tile */
1475 int anchX
, anchY
; /* XY origin of axis of motion (anchor point) in <start>'s
1477 int delX
, delY
; /* slope+dir of the axis of motion (line along which the new
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
;
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.
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: */
1527 y
= (int)((float)delY
/(float)delX
* (cornerTile
->x_pos
- newAnchX
)) +
1532 x
= (int)((float)delX
/(float)delY
* (cornerTile
->x_pos
- newAnchY
)) +
1535 if ((y
>= cornerTile
->y_pos
)&&(y
<= (cornerTile
->y_pos
+ cornerTile
->y_len
)))
1539 else newAnchY
= cornerTile
->y_pos
;
1541 if ((x
>= cornerTile
->x_pos
) && (x
<= (cornerTile
->x_pos
+ cornerTile
->x_len
)))
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
,
1559 /*Check to see that the insertion was successful: */
1560 if (new == NULL
) fprintf(stderr
, "angled_group_tile_insertion: Complete Failure\n");
1565 /*------------------------------------------------------------------------*/
1566 tile
*delete_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 &
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:*/
1592 scrap
= list_neighbors(temp1
, RIGHT
);
1593 for (tll
= scrap
; tll
!= NULL
; tll
= tll
->next
)
1595 temp2
= scrub_right(temp1
, tll
->this);
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
);
1608 /*----------------------------------------------------------------------------*/
1609 tile
*scrub_right(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
;
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 */
1632 left2
->y_len
= Rtop
- left2
->y_pos
;
1634 left
->lb
= left2
; /* left becomes the upper tile */
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
);
1648 else if (Ltop
< Rtop
) /* spilt right @ y = Ltop */
1650 right2
= copy_tile(right
); /* right2 becomes the lower tile */
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
);
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 */
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
);
1690 else /* No splits required, just do mergers */
1698 /*------------------------------------------------------------------------ */
1699 int clean_up_neighbors(who
)
1701 { /* See that all of <who>'s neighbors point to him. */
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
;
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
))
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
))
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
;
1729 /*------------------------------------------------------------------------ */
1730 tilist
*translate_origin(tl
, x
, y
)
1734 /* Translate the location of all tiles on <tl> by the <x> & <y> given: */
1736 for (tll
= tl
; tll
!= NULL
; tll
= tll
->next
)
1738 tll
->this->x_pos
+= x
;
1739 tll
->this->y_pos
+= y
;
1743 /*------------------------------------------------------------------------ */
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 /*------------------------------------------------------------------------ */
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 /*------------------------------------------------------------------------ */
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
)
1793 int (*filterFn
)(); /* given a tile, returns TRUE if the tile is to be
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: */
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");
1824 if (debug_level
== 5)
1825 fprintf(stderr
, "no.\n");
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
);
1841 /*------------------------------------------------------------------------ */
1842 tilist
*area_enumerate(t
, soFar
, filterFn
, xorg
, yorg
, xext
, yext
)
1845 int (*filterFn
)(); /* given a tile, returns TRUE if the tile is to be
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>. */
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
);
1866 /*------------------------------------------------------------------------ */
1867 tilist
*helpEnumerate(t
, soFar
, filterFn
)
1870 int (*filterFn
)(); /* given a tile, returns TRUE if the tile is to be
1873 { /* Return a list containing all tiles to the right of the given tile,
1874 which return TRUE when passed to the <filterFn>. */
1877 /* Add the given tile to the listing: */
1878 if (filterFn(t
) != FALSE
) push(t
, soFar
);
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
);
1892 /*------------------------------------------------------------------------------- */
1893 tilist
*enumerate(t
, soFar
, filterFn
)
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>. */
1901 for (temp
= find_ULHC(t
); temp
!= NULL
; temp
= temp
->lb
)
1903 *soFar
= helpEnumerate(temp
, soFar
, filterFn
);
1908 /*------------------------------------------------------------------------ */
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 /*------------------------------------------------------------------------ */
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
)
1945 int srcX
, srcY
, delX
, delY
;
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 */
1956 int yset
= FALSE
, xset
= FALSE
;
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
)))
1968 "find_all_tiles_along_line: Hit edge of space along Y-dimension\n"); */
1972 else if ((temp
->y_pos
== srcY
) ||
1973 ((temp
->y_pos
+ temp
->y_len
== srcY
)))
1976 "find_all_tiles_along_line: Hit edge of space along X-dimension\n"); */
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
));
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: */
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
))
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
))
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 */
2032 if (delY
> 0) /* Upper... */
2034 if (delX
> 0) /* Right-Hand Corner */
2036 /* nextX = x + 1; Might be needed....
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
);
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
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
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
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
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
;
2115 cy2
= srcY
+ length
; cy3
= srcY
+ length
;
2119 cy2
= srcY
- length
; cy3
= srcY
- length
;
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
;
2129 cx2
= srcX
+ length
; cx3
= srcX
+ length
;
2133 cx2
= srcX
- length
; cx3
= srcX
- length
;
2137 /* Now the arctangent is defined, so use it: */
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>>>>>> */
2158 /*------------------------------------------------------------------------ */
2159 /*------------------------------------------------------------------------ */
2160 tile
*first_noncontiguous_full_tile(tlist
)
2162 { /* Return the first non-empty ((*solidp)) tile on the given <tlist> */
2163 /* <tlist> had best be an ordered list. */
2166 int returnNextFullTile
= FALSE
;
2168 for (tl
= *tlist
; (tl
!= NULL
); tl
= tl
->next
)
2170 if ((returnNextFullTile
== TRUE
) && ((*solidp
)(tl
->this) == TRUE
))
2175 else if (((*solidp
)(tl
->this) == FALSE
) && (tl
->next
!= NULL
))
2176 returnNextFullTile
= TRUE
;
2182 /*---------------------------------------------------------------
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. */
2197 tl
= nonFreespace(t
, &tl
);
2200 for (tl
= tl
->next
; (tl
!= NULL
); tl
= tl
->next
)
2202 temp
= (filterFn(temp
, tl
->this) != FALSE
) ? temp
: tl
->this;
2207 /*------------------------------------------------------------------------ */
2208 int adjacent_tiles_p(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
);
2219 /*------------------------------------------------------------------------ */
2220 int most_right(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
);
2229 /*------------------------------------------------------------------------ */
2230 int most_left(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
);
2239 /*------------------------------------------------------------------------ */
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
);
2249 /*------------------------------------------------------------------------ */
2250 int most_down(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
);
2259 /*------------------------------------------------------------------------ */
2260 int verify_tile_space(t
)
2263 /* This checks to see if the tile space is corrupted: */
2264 tilist
*tl
= NULL
, *tll
= NULL
, *errorList
= NULL
;
2268 if (t
== NULL
) return(TRUE
); /* Let someone else catch this error */
2270 /* First check the given tile... */
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 */
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 */
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 */
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 */
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
)
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 */
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 */
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 */
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 */
2350 push(tp
, &errorList
);
2353 if (error
== FALSE
) return(TRUE
);
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. */
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",
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 */
2382 fprintf(f
, "newpath %d %d moveto %d %d lineto stroke\n", x2
, y2
, x2
, y1
);
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
)
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>. */
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': */
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
);
2420 /*------------------------------------------------------------------------ */
2421 void ps_print_tile_space(t
, f
, ps_printFn
, edgesP
)
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 */
2430 for (temp
= find_ULHC(t
); temp
!= NULL
; temp
= temp
->lb
)
2432 enumerateForPrinting(temp
, f
, ps_printFn
, edgesP
);
2435 /*------------------------------------------------------------------------ */
2436 /*---------------------------------------------------------------
2438 *---------------------------------------------------------------