1 /* CIFgen.c -
2 *
3 * This file provides routines that generate CIF from Magic
4 * tile information, using one of the styles read from the
5 * technology file.
6 *
7 * *********************************************************************
8 * * Copyright (C) 1985, 1990 Regents of the University of California. *
9 * * Permission to use, copy, modify, and distribute this *
10 * * software and its documentation for any purpose and without *
11 * * fee is hereby granted, provided that the above copyright *
12 * * notice appear in all copies. The University of California *
13 * * makes no representations about the suitability of this *
14 * * software for any purpose. It is provided "as is" without *
15 * * express or implied warranty. Export of this software outside *
16 * * of the United States of America may require an export license. *
17 * *********************************************************************
18 */
19
20 #ifndef lint
21 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFgen.c,v 1.23 2010/06/24 20:35:54 tim Exp $";
22 #endif /* not lint */
23
24 #include <stdio.h>
25 #include <stdlib.h> /* for abs() */
26 #include <math.h> /* for ceil() and sqrt() */
27
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "tiles/tile.h"
31 #include "utils/hash.h"
32 #include "database/database.h"
33 #include "cif/CIFint.h"
34 #include "calma/calma.h" /* for CalmaContactArrays */
35 #include "commands/commands.h" /* for CmdFindNetProc() */
36 #include "select/selInt.h" /* for select use and def */
37 #include "select/select.h"
38 #include "utils/stack.h"
39 #include "utils/malloc.h"
40 #include "utils/maxrect.h"
41
42 /* TRUE to run (very slow) algorithm for optimizing non-manhattan tiles */
43 /* (cuts size of output; see also the GDS "merge" option) */
44 bool CIFUnfracture = FALSE;
45
46 /* The following global arrays hold pointers to the CIF planes
47 * generated by the procedures in this module. There are two
48 * kinds of planes: real CIF, which will ostensibly be output,
49 * and temporary layers used to build up more complex geometric
50 * functions.
51 */
52
53 global Plane *CIFPlanes[MAXCIFLAYERS];
54
55 /* The following are paint tables used by the routines that implement
56 * the geometric operations on mask layers, such as AND, OR, GROW,
57 * etc. There are really only two tables. The first will paint
58 * CIF_SOLIDTYPE over anything else, and the second will paint
59 * space over anything else. These tables are used on planes with
60 * only two tile types, TT_SPACE and CIF_SOLIDTYPE, so they only
61 * have two entries each.
62 */
63
64 PaintResultType CIFPaintTable[] = {CIF_SOLIDTYPE, CIF_SOLIDTYPE};
65 PaintResultType CIFEraseTable[] = {TT_SPACE, TT_SPACE};
66
67 /* The following local variables are used as a convenience to pass
68 * information between CIFGen and the various search functions.
69 */
70
71 static int growDistance; /* Distance to grow stuff. */
72 static Plane *cifPlane; /* Plane acted on by search functions. */
73 static int cifScale; /* Scale factor to use on tiles. */
74
75 extern void cifClipPlane();
76 extern void cifGenClip();
77
78 /*
79 * ----------------------------------------------------------------------------
80 *
81 * cifPaintFunc --
82 *
83 * This search function is called during CIF_AND and CIF_OR
84 * and CIF_ANDNOT operations for each relevant tile.
85 *
86 * Results:
87 * Always returns 0 to keep the search alive.
88 *
89 * Side effects:
90 * For the area of the tile, either paints or erases in
91 * cifNewPlane, depending on the paint table passed as parameter.
92 * The tile's area is scaled by cifScale first.
93 * ----------------------------------------------------------------------------
94 */
95
96 int
cifPaintFunc(tile,table)97 cifPaintFunc(tile, table)
98 Tile *tile;
99 PaintResultType *table; /* Used for painting. */
100 {
101 Rect area;
102
103 TiToRect(tile, &area);
104 area.r_xbot *= cifScale;
105 area.r_xtop *= cifScale;
106 area.r_ybot *= cifScale;
107 area.r_ytop *= cifScale;
108
109 DBNMPaintPlane(cifPlane, TiGetTypeExact(tile), &area, table,
110 (PaintUndoInfo *) NULL);
111 CIFTileOps += 1;
112 return 0;
113 }
114
115 /*
116 * ----------------------------------------------------------------------------
117 * SetBoxGrid ---
118 *
119 * Adjust the given area by expanding each side individually to
120 * ensure that it falls on the CIF minimum grid.
121 *
122 * Returns: Nothing
123 *
124 * Side Effects: Point to Rect "area" may be modified.
125 *
126 * ----------------------------------------------------------------------------
127 */
128
129 void
SetBoxGrid(area)130 SetBoxGrid(area)
131 Rect *area;
132 {
133 int limit;
134 int delta;
135
136 limit = CIFCurStyle->cs_gridLimit;
137
138 if (CIFCurStyle && (limit > 1))
139 {
140 delta = abs(area->r_xbot) % limit;
141 if (delta > 0)
142 {
143 if (area->r_xbot < 0)
144 {
145 area->r_xbot += delta;
146 area->r_xbot -= limit;
147 }
148 else
149 area->r_xbot -= delta;
150 }
151
152 delta = abs(area->r_xtop) % limit;
153 if (delta > 0)
154 {
155 if (area->r_xtop < 0)
156 area->r_xtop += delta;
157 else
158 {
159 area->r_xtop -= delta;
160 area->r_xtop += limit;
161 }
162 }
163
164 delta = abs(area->r_ybot) % limit;
165 if (delta > 0)
166 {
167 if (area->r_ybot < 0)
168 {
169 area->r_ybot += delta;
170 area->r_ybot -= limit;
171 }
172 else
173 area->r_ybot -= delta;
174 }
175
176 delta = abs(area->r_ytop) % limit;
177 if (delta > 0)
178 {
179 if (area->r_ytop < 0)
180 area->r_ytop += delta;
181 else
182 {
183 area->r_ytop -= delta;
184 area->r_ytop += limit;
185 }
186 }
187 }
188 }
189
190 /*
191 * ----------------------------------------------------------------------------
192 * SetValueGrid ---
193 *
194 * Adjust the given distance to the nearest CIF minimum grid.
195 *
196 * Returns: The adjusted value.
197 *
198 * Side Effects: None.
199 *
200 * Notes: Value is assumed to be a distance, therefore always positive.
201 *
202 * ----------------------------------------------------------------------------
203 */
204
205 int
SetValueGrid(value)206 SetValueGrid(value)
207 int value;
208 {
209 int limit;
210 int delta;
211
212 limit = CIFCurStyle->cs_gridLimit;
213
214 if (CIFCurStyle && (limit > 1))
215 {
216 delta = value % limit;
217 if (delta > 0)
218 value += limit - delta;
219 }
220 return value;
221 }
222
223 /*
224 * ----------------------------------------------------------------------------
225 * SetMinBoxGrid ---
226 *
227 * Adjust the given area by expanding evenly on both sides so that it
228 * has a width and heigth no less than the given width. Then further
229 * expand the box to ensure that it falls on the CIF minimum grid.
230 *
231 * Returns: Nothing
232 *
233 * Side Effects: Point to Rect "area" may be modified.
234 *
235 * ----------------------------------------------------------------------------
236 */
237
238 void
SetMinBoxGrid(area,width)239 SetMinBoxGrid(area, width)
240 Rect *area;
241 int width;
242 {
243 int wtest;
244 int wtot;
245
246 wtest = (area->r_xtop - area->r_xbot);
247 wtot = area->r_xtop + area->r_xbot;
248 if (wtest < width)
249 {
250 area->r_xbot = (wtot - width) / 2;
251 area->r_xtop = (wtot + width) / 2;
252 }
253 wtest = (area->r_ytop - area->r_ybot);
254 wtot = area->r_ytop + area->r_ybot;
255 if (wtest < width)
256 {
257 area->r_ybot = (wtot - width) / 2;
258 area->r_ytop = (wtot + width) / 2;
259 }
260
261 SetBoxGrid(area);
262 }
263
264 /*
265 * ----------------------------------------------------------------------------
266 *
267 * cifGrowMinFunc --
268 *
269 * Called for each relevant tile during grow-min operations.
270 *
271 * Results:
272 * Always returns 0 to keep the search alive.
273 *
274 * Side effects:
275 * May paint into cifNewPlane
276 *
277 * Algorithm (based on maximum horizontal stripes rule):
278 * Scan top and bottom boundaries from left to right. For any
279 * distance (including distance zero) sharing the same type (0 or 1)
280 * on both the tile top and bottom, find the diagonal length. If
281 * less than co_distance, then expand this area and paint.
282 * NOTE: This algorithm does not cover a number of geometry cases
283 * and needs to be reworked. It should be restricted to cases of
284 * layers that have "rect_only" DRC rules. Since the rule is usually
285 * needed for implants on FET gates to maintain the implant width for
286 * small gates, the "rect_only" requirement is not particularly
287 * constraining.
288 *
289 * ----------------------------------------------------------------------------
290 */
291
292 int
cifGrowMinFunc(tile,table)293 cifGrowMinFunc(tile, table)
294 Tile *tile;
295 PaintResultType *table; /* Table to be used for painting. */
296 {
297 Rect area, parea;
298 int locDist, width, height, h;
299 TileType type, tptype;
300 Tile *tp, *tp2;
301 bool changed;
302 void SetMinBoxGrid(); /* Forward reference */
303
304 TiToRect(tile, &area);
305
306 area.r_xbot *= cifScale;
307 area.r_xtop *= cifScale;
308 area.r_ybot *= cifScale;
309 area.r_ytop *= cifScale;
310
311 parea = area;
312 changed = FALSE;
313
314 /* Check whole tile for minimum width */
315 width = area.r_xtop - area.r_xbot;
316 if (width < growDistance)
317 {
318 locDist = (growDistance - width) / 2;
319 area.r_xbot -= locDist;
320 area.r_xtop += locDist;
321
322 /* If there is another tile on top or bottom, and the height is */
323 /* less than minimum, then extend height in the direction of */
324 /* the bordering tile. Otherwise, if the height is less than */
325 /* minimum, then grow halfway in both directions. */
326
327 height = area.r_ytop - area.r_ybot;
328 if (height < growDistance)
329 {
330 bool freeTop, freeBot;
331
332 freeTop = freeBot = TRUE;
333
334 for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
335 if (TiGetTopType(tp) == TiGetBottomType(tile))
336 {
337 freeBot = FALSE;
338 break;
339 }
340
341 for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
342 if (TiGetBottomType(tp2) == TiGetTopType(tile))
343 {
344 freeTop = FALSE;
345 break;
346 }
347
348 /* In the following, value h ensures that the euclidean */
349 /* distance between inside corners of the layer */
350 /* satisfies growDistance. */
351
352 if (freeTop == TRUE && freeBot == FALSE)
353 {
354 locDist = (growDistance - height) / 2;
355 h = (int)sqrt((double)(growDistance * growDistance) -
356 0.25 * (double)((growDistance + width) *
357 (growDistance + width)) + 0.5);
358 area.r_ybot -= h;
359 changed = TRUE;
360 }
361 else if (freeTop == FALSE && freeBot == TRUE)
362 {
363 h = (int)sqrt((double)(growDistance * growDistance) -
364 0.25 * (double)((growDistance + width) *
365 (growDistance + width)) + 0.5);
366 area.r_ytop += h;
367 changed = TRUE;
368 }
369 else {
370 locDist = (growDistance - height) / 2;
371 area.r_ybot -= locDist;
372 area.r_ytop += locDist;
373 changed = TRUE;
374 }
375 }
376 }
377
378 /* Ensure grid limit is not violated */
379 if (changed) SetMinBoxGrid(&area, growDistance);
380
381 DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
382
383 area = parea;
384
385 /* Scan bottom from left to right */
386 for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
387 {
388 tptype = TiGetTopType(tp);
389 /* Scan top from right to left across range of tp */
390 for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
391 if (TiGetBottomType(tp2) == tptype)
392 {
393 /* Set range to length of overlap */
394 if ((LEFT(tp2) <= RIGHT(tp)) && (LEFT(tp2) >= LEFT(tp)))
395 {
396 area.r_xbot = LEFT(tp2) < LEFT(tile) ? LEFT(tile) : LEFT(tp2);
397 area.r_xtop = RIGHT(tp) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp);
398 }
399 else if ((RIGHT(tp2) >= LEFT(tp)) && (RIGHT(tp2) <= RIGHT(tp)))
400 {
401 area.r_xbot = LEFT(tp) < LEFT(tile) ? LEFT(tile) : LEFT(tp);
402 area.r_xtop = RIGHT(tp2) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp2);
403 }
404 else continue;
405
406 area.r_xbot *= cifScale;
407 area.r_xtop *= cifScale;
408
409 /* Does area violate minimum width requirement? */
410 width = area.r_xtop - area.r_xbot;
411 height = area.r_ytop - area.r_ybot;
412
413 /* Manhattan requirement (to-do: Euclidean) */
414 if (width < growDistance)
415 {
416 locDist = (growDistance - width) / 2;
417 parea.r_xbot = area.r_xbot - locDist;
418 parea.r_xtop = area.r_xtop + locDist;
419 }
420 else
421 {
422 parea.r_xbot = area.r_xbot;
423 parea.r_xtop = area.r_xtop;
424 }
425 if (height < growDistance)
426 {
427 locDist = (growDistance - height) / 2;
428 parea.r_ybot = area.r_ybot - locDist;
429 parea.r_ytop = area.r_ytop + locDist;
430 }
431 else
432 {
433 parea.r_ybot = area.r_ybot;
434 parea.r_ytop = area.r_ytop;
435 }
436 if ((width < growDistance) || (height < growDistance))
437 {
438 /* Ensure grid limit is not violated */
439 SetMinBoxGrid(&parea, growDistance);
440 DBPaintPlane(cifPlane, &parea, table, (PaintUndoInfo *) NULL);
441 }
442 }
443 }
444
445 CIFTileOps += 1;
446 return 0;
447 }
448
449 /*
450 * ----------------------------------------------------------------------------
451 *
452 * cifGrowGridFunc --
453 *
454 * Called for each relevant tile during grow-grid operations.
455 *
456 * Results:
457 * Always returns 0 to keep the search alive.
458 *
459 * Side effects:
460 * Scales the tile by cifScale, then expands its area by the
461 * remainder of the distance to the nearest grid point, as
462 * defined by the grid distance (growDistance) in the current
463 * CIFOp, then paints this area into cifNewPlane using the table
464 * passed as parameter.
465 * ----------------------------------------------------------------------------
466 */
467
468 int
cifGrowGridFunc(tile,table)469 cifGrowGridFunc(tile, table)
470 Tile *tile;
471 PaintResultType *table; /* Table to be used for painting. */
472 {
473 Rect area;
474 int remainder;
475
476 /* To be done---handle non-Manhattan geometry */
477 TileType oldType = TiGetType(tile);
478
479 TiToRect(tile, &area);
480
481 /* In scaling the tile, watch out for infinities!! If something
482 * is already infinity, don't change it. */
483
484 if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot *= cifScale;
485 if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot *= cifScale;
486 if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop *= cifScale;
487 if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop *= cifScale;
488
489 /* In scaling the tile, watch out for infinities!! If something
490 * is already infinity, don't change it. */
491
492 if (area.r_xbot > TiPlaneRect.r_xbot)
493 area.r_xbot -= (abs(area.r_xbot) % growDistance);
494 if (area.r_ybot > TiPlaneRect.r_ybot)
495 area.r_ybot -= (abs(area.r_ybot) % growDistance);
496 if (area.r_xtop < TiPlaneRect.r_xtop)
497 area.r_xtop += (abs(area.r_xtop) % growDistance);
498 if (area.r_ytop < TiPlaneRect.r_ytop)
499 area.r_ytop += (abs(area.r_ytop) % growDistance);
500
501 DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
502
503 CIFTileOps += 1;
504 return 0;
505 }
506
507 /*
508 * ----------------------------------------------------------------------------
509 *
510 * cifGrowEuclideanFunc --
511 *
512 * Called for each relevant tile during grow or shrink operations.
513 * For growing, these are solid tiles. For shrinking, these are
514 * space tiles. This routine differs from cifGrowFunc in that it
515 * grows the minimum distance on non-Manhattan edges necessary to
516 * create a euclidean distance to the edge of growDistance while
517 * keeping corner points on-grid. This requires a substantially
518 * different algorithm from cifGrowFunc.
519 *
520 * Results:
521 * Always returns 0 to keep the search alive.
522 *
523 * Side effects:
524 * Scales the tile by cifScale, then expands its area by the
525 * distance in the current CIFOp, then paints this area into
526 * cifNewPlane using the table passed as parameter.
527 * ----------------------------------------------------------------------------
528 */
529
530 #define GROW_NORTH 0x1
531 #define GROW_SOUTH 0x2
532 #define GROW_EAST 0x4
533 #define GROW_WEST 0x8
534
535 #define STOP_NW 0x1 /* WN EN */
536 #define STOP_SW 0x2 /* NW +-------+ NE */
537 #define STOP_NE 0x4 /* | | */
538 #define STOP_SE 0x8 /* | | */
539 #define STOP_WN 0x10 /* SW +-------+ SE */
540 #define STOP_WS 0x20 /* WS ES */
541 #define STOP_EN 0x40
542 #define STOP_ES 0x80
543
544 int
cifGrowEuclideanFunc(tile,table)545 cifGrowEuclideanFunc(tile, table)
546 Tile *tile;
547 PaintResultType *table; /* Table to be used for painting. */
548 {
549 Tile *tp;
550 Rect area, rtmp;
551 TileType oldType = TiGetTypeExact(tile);
552 unsigned char growDirs = GROW_NORTH | GROW_SOUTH | GROW_EAST | GROW_WEST;
553 unsigned char cornerDirs = 0;
554
555 TiToRect(tile, &area);
556
557 /* In scaling the tile, watch out for infinities!! If something
558 * is already infinity, don't change it. */
559
560 if (area.r_xbot > TiPlaneRect.r_xbot)
561 area.r_xbot *= cifScale;
562 else
563 growDirs &= ~GROW_WEST;
564 if (area.r_ybot > TiPlaneRect.r_ybot)
565 area.r_ybot *= cifScale;
566 else
567 growDirs &= ~GROW_SOUTH;
568 if (area.r_xtop < TiPlaneRect.r_xtop)
569 area.r_xtop *= cifScale;
570 else
571 growDirs &= ~GROW_EAST;
572 if (area.r_ytop < TiPlaneRect.r_ytop)
573 area.r_ytop *= cifScale;
574 else
575 growDirs &= ~GROW_NORTH;
576
577 /* Grow on diagonal tiles: grow rectangular tiles around the */
578 /* straight edges of the right-triangle, then copy the diagonal */
579 /* tile (at its original size) in the direction of the diagonal. */
580 /* Note: A diagonal tile, by definition, can't have infinities. */
581
582 if (oldType & TT_DIAGONAL)
583 {
584 int growDistanceX, growDistanceY;
585 int height, width;
586 double hyp;
587 int limit;
588
589 if (oldType & TT_SIDE)
590 growDirs &= ~GROW_WEST;
591 else
592 growDirs &= ~GROW_EAST;
593
594 if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION))
595 growDirs &= ~GROW_SOUTH;
596 else
597 growDirs &= ~GROW_NORTH;
598
599 /* Grow non-Manhattan edges to (the closest integer value */
600 /* to) growDistance along the normal to the edge. This */
601 /* will overestimate the distance only to the minimum */
602 /* amount necessary to ensure on-grid endpoints. */
603
604 width = area.r_xtop - area.r_xbot;
605 height = area.r_ytop - area.r_ybot;
606 hyp = sqrt((double)(width * width + height * height));
607 growDistanceY = ceil((double)(growDistance * width) / hyp);
608 growDistanceX = ceil((double)(growDistance * height) / hyp);
609
610 /* Adjust for grid limit */
611 growDistanceX = SetValueGrid(growDistanceX);
612 growDistanceY = SetValueGrid(growDistanceY);
613
614 /* Draw vertical tile to distance X */
615
616 rtmp = area;
617 if (!(growDirs & GROW_EAST)) rtmp.r_xtop = rtmp.r_xbot + growDistanceX;
618 if (!(growDirs & GROW_WEST)) rtmp.r_xbot = rtmp.r_xtop - growDistanceX;
619 if (!(growDirs & GROW_SOUTH)) rtmp.r_ybot -= growDistance;
620 if (!(growDirs & GROW_NORTH)) rtmp.r_ytop += growDistance;
621 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
622
623 /* Draw horizontal tile to distance Y */
624
625 rtmp = area;
626 if (!(growDirs & GROW_EAST)) rtmp.r_xtop += growDistance;
627 if (!(growDirs & GROW_WEST)) rtmp.r_xbot -= growDistance;
628 if (!(growDirs & GROW_SOUTH)) rtmp.r_ybot = rtmp.r_ytop - growDistanceY;
629 if (!(growDirs & GROW_NORTH)) rtmp.r_ytop = rtmp.r_ybot + growDistanceY;
630 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
631
632 /* Finally, translate, resize, and paint the diagonal tile */
633
634 rtmp = area;
635
636 if (!(growDirs & GROW_NORTH))
637 rtmp.r_ytop += growDistance;
638 else
639 rtmp.r_ytop -= growDistanceY;
640 if (!(growDirs & GROW_SOUTH))
641 rtmp.r_ybot -= growDistance;
642 else
643 rtmp.r_ybot += growDistanceY;
644 if (!(growDirs & GROW_EAST))
645 rtmp.r_xtop += growDistance;
646 else
647 rtmp.r_xtop -= growDistanceX;
648 if (!(growDirs & GROW_WEST))
649 rtmp.r_xbot -= growDistance;
650 else
651 rtmp.r_xbot += growDistanceX;
652
653 DBNMPaintPlane(cifPlane, oldType, &rtmp, table, (PaintUndoInfo *) NULL);
654
655 oldType = (growDirs & GROW_EAST) ? TiGetRightType(tile) : TiGetLeftType(tile);
656 }
657 else
658 DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
659
660 /* Check tile corner areas for paint */
661
662 tp = TR(tile);
663 if (TiGetLeftType(tp) == oldType) cornerDirs |= STOP_NE;
664 for (; TOP(LB(tp)) > BOTTOM(tile); tp = LB(tp));
665 if (TiGetLeftType(tp) == oldType) cornerDirs |= STOP_SE;
666
667 tp = RT(tile);
668 if (TiGetBottomType(tp) == oldType) cornerDirs |= STOP_EN;
669 for (; RIGHT(BL(tp)) > LEFT(tile); tp = BL(tp));
670 if (TiGetBottomType(tp) == oldType) cornerDirs |= STOP_WN;
671
672 tp = BL(tile);
673 if (TiGetRightType(tp) == oldType) cornerDirs |= STOP_SW;
674 for (; BOTTOM(RT(tp)) < TOP(tile); tp = RT(tp));
675 if (TiGetRightType(tp) == oldType) cornerDirs |= STOP_NW;
676
677 tp = LB(tile);
678 if (TiGetTopType(tp) == oldType) cornerDirs |= STOP_WS;
679 for (; LEFT(TR(tp)) < RIGHT(tile); tp = TR(tp));
680 if (TiGetTopType(tp) == oldType) cornerDirs |= STOP_ES;
681
682 if (growDirs & GROW_NORTH)
683 {
684 rtmp = area;
685 rtmp.r_ybot = area.r_ytop;
686 rtmp.r_ytop = area.r_ytop + growDistance;
687 if ((cornerDirs & (STOP_EN | STOP_NE)) == 0)
688 if (growDirs & GROW_EAST) rtmp.r_xtop += growDistance;
689 if ((cornerDirs & (STOP_WN | STOP_NW)) == 0)
690 if (growDirs & GROW_WEST) rtmp.r_xbot -= growDistance;
691 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
692 }
693
694 if (growDirs & GROW_EAST)
695 {
696 rtmp = area;
697 rtmp.r_xbot = area.r_xtop;
698 rtmp.r_xtop = area.r_xtop + growDistance;
699 if ((cornerDirs & (STOP_EN | STOP_NE)) == 0)
700 if (growDirs & GROW_NORTH) rtmp.r_ytop += growDistance;
701 if ((cornerDirs & (STOP_SE | STOP_ES)) == 0)
702 if (growDirs & GROW_SOUTH) rtmp.r_ybot -= growDistance;
703 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
704 }
705
706 if (growDirs & GROW_SOUTH)
707 {
708 rtmp = area;
709 rtmp.r_ytop = area.r_ybot;
710 rtmp.r_ybot = area.r_ybot - growDistance;
711 if ((cornerDirs & (STOP_SE | STOP_ES)) == 0)
712 if (growDirs & GROW_EAST) rtmp.r_xtop += growDistance;
713 if ((cornerDirs & (STOP_SW | STOP_WS)) == 0)
714 if (growDirs & GROW_WEST) rtmp.r_xbot -= growDistance;
715 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
716 }
717
718 if (growDirs & GROW_WEST)
719 {
720 rtmp = area;
721 rtmp.r_xtop = area.r_xbot;
722 rtmp.r_xbot = area.r_xbot - growDistance;
723 if ((cornerDirs & (STOP_NW | STOP_WN)) == 0)
724 if (growDirs & GROW_NORTH) rtmp.r_ytop += growDistance;
725 if ((cornerDirs & (STOP_SW | STOP_WS)) == 0)
726 if (growDirs & GROW_SOUTH) rtmp.r_ybot -= growDistance;
727 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
728 }
729
730 CIFTileOps++;
731 return 0;
732 }
733
734 /*
735 * ----------------------------------------------------------------------------
736 *
737 * cifGrowFunc --
738 *
739 * Called for each relevant tile during grow or shrink operations.
740 * For growing, these are solid tiles. For shrinking, these are
741 * space tiles.
742 *
743 * Results:
744 * Always returns 0 to keep the search alive.
745 *
746 * Side effects:
747 * Scales the tile by cifScale, then expands its area by the
748 * distance in the current CIFOp, then paints this area into
749 * cifNewPlane using the table passed as parameter.
750 * ----------------------------------------------------------------------------
751 */
752
753 int
cifGrowFunc(tile,table)754 cifGrowFunc(tile, table)
755 Tile *tile;
756 PaintResultType *table; /* Table to be used for painting. */
757 {
758 Rect area;
759 TileType oldType = TiGetTypeExact(tile);
760
761 TiToRect(tile, &area);
762
763 /* In scaling the tile, watch out for infinities!! If something
764 * is already infinity, don't change it. */
765
766 if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot *= cifScale;
767 if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot *= cifScale;
768 if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop *= cifScale;
769 if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop *= cifScale;
770
771 /* Grow on diagonal tiles: grow rectangular tiles around the */
772 /* straight edges of the right-triangle, then copy the diagonal */
773 /* tile (at its original size) in the direction of the diagonal. */
774 /* Note: A diagonal tile, by definition, can't have infinities. */
775
776 if (oldType & TT_DIAGONAL)
777 {
778 Rect rtmp;
779
780 /* Grow top and bottom */
781
782 rtmp.r_ybot = area.r_ybot - growDistance;
783 rtmp.r_ytop = area.r_ytop + growDistance;
784
785 /* Grow around left or right edge */
786
787 if (oldType & TT_SIDE)
788 {
789 rtmp.r_xbot = area.r_xtop - growDistance;
790 rtmp.r_xtop = area.r_xtop + growDistance;
791 }
792 else
793 {
794 rtmp.r_xbot = area.r_xbot - growDistance;
795 rtmp.r_xtop = area.r_xbot + growDistance;
796 }
797 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
798
799 /* Now do the same for the other edge. */
800
801 rtmp.r_xbot = area.r_xbot - growDistance;
802 rtmp.r_xtop = area.r_xtop + growDistance;
803
804 if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
805 {
806 rtmp.r_ybot = area.r_ytop - growDistance;
807 rtmp.r_ytop = area.r_ytop + growDistance;
808 }
809 else /* bottom */
810 {
811 rtmp.r_ybot = area.r_ybot - growDistance;
812 rtmp.r_ytop = area.r_ybot + growDistance;
813 }
814 DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL);
815
816 /* Finally, Move and replace the diagonal tile */
817
818 if (oldType & TT_SIDE)
819 {
820 rtmp.r_xtop = area.r_xtop - growDistance;
821 rtmp.r_xbot = area.r_xbot - growDistance;
822 }
823 else
824 {
825 rtmp.r_xtop = area.r_xtop + growDistance;
826 rtmp.r_xbot = area.r_xbot + growDistance;
827 }
828
829 if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
830 {
831 rtmp.r_ytop = area.r_ytop - growDistance;
832 rtmp.r_ybot = area.r_ybot - growDistance;
833 }
834 else /* bottom */
835 {
836 rtmp.r_ytop = area.r_ytop + growDistance;
837 rtmp.r_ybot = area.r_ybot + growDistance;
838 }
839 DBNMPaintPlane(cifPlane, oldType, &rtmp, table, (PaintUndoInfo *) NULL);
840 }
841 else
842 {
843
844 /* In scaling the tile, watch out for infinities!! If something
845 * is already infinity, don't change it. */
846
847 if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot -= growDistance;
848 if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot -= growDistance;
849 if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop += growDistance;
850 if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop += growDistance;
851
852 DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
853 }
854
855 CIFTileOps += 1;
856 return 0;
857 }
858
859 /*
860 * ----------------------------------------------------------------------------
861 *
862 * cifBloatFunc --
863 *
864 * Called once for each tile to be selectively bloated.
865 *
866 * Results:
867 * Always returns 0 to keep the search alive.
868 *
869 * Side effects:
870 * Uses the bloat table in the current CIFOp to expand the
871 * tile depending on which tiles it abuts, then paints the
872 * expanded area into the new CIF plane. The bloat table
873 * contains one entry for each tile type. When that tile
874 * type is seen next to the current tile, the area of the current
875 * tile is bloated by the table value in that location. The
876 * only exception to this rule is that internal edges (between
877 * two tiles of the same type) cause no bloating.
878 * Note: the original tile is scaled into CIF coordinates.
879 * ----------------------------------------------------------------------------
880 */
881
882 int
cifBloatFunc(tile,clientData)883 cifBloatFunc(tile, clientData)
884 Tile *tile;
885 ClientData clientData;
886 {
887 Rect tileArea, cifArea, bloat;
888 TileType oldType, type, topLeftType, bottomRightType;
889 Tile *t;
890 int tilestart, tilestop, cifstart, cifstop;
891 BloatData *bloats = (BloatData *)clientData;
892 int *bloatTable = (int *)bloats->bl_distance;
893
894 oldType = TiGetTypeExact(tile);
895 TiToRect(tile, &tileArea);
896
897 /* Output the original area of the tile. */
898
899 cifArea = tileArea;
900 cifArea.r_xbot *= cifScale;
901 cifArea.r_xtop *= cifScale;
902 cifArea.r_ybot *= cifScale;
903 cifArea.r_ytop *= cifScale;
904
905 /* This is a modified version of the nonmanhattan grow function. */
906 /* We grow only in the direction of the diagonal. */
907 /* This will not work in all situations! Corner extensions are not */
908 /* considered (but should be, for completeness). */
909
910 if (oldType & TT_DIAGONAL)
911 {
912 TileType otherType = (oldType & TT_SIDE) ?
913 TiGetLeftType(tile) : TiGetRightType(tile);
914 int dist = bloatTable[otherType];
915
916 /* The Euclidean grow function is identical to Euclidean bloat-or */
917 if (CIFCurStyle->cs_flags & CWF_GROW_EUCLIDEAN)
918 {
919 growDistance = dist;
920 cifGrowEuclideanFunc(tile, CIFPaintTable);
921 }
922 else
923 {
924
925 /* Grow top and bottom */
926
927 if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
928 {
929 bloat.r_ybot = cifArea.r_ytop - dist;
930 bloat.r_ytop = cifArea.r_ytop;
931 }
932 else /* bottom */
933 {
934 bloat.r_ybot = cifArea.r_ybot;
935 bloat.r_ytop = cifArea.r_ybot + dist;
936 }
937
938 /* Grow around left or right edge */
939
940 if (oldType & TT_SIDE)
941 {
942 bloat.r_xbot = cifArea.r_xbot - dist;
943 bloat.r_xtop = cifArea.r_xtop;
944 }
945 else
946 {
947 bloat.r_xbot = cifArea.r_xbot;
948 bloat.r_xtop = cifArea.r_xtop + dist;
949 }
950 DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL);
951
952 /* Now do the same for the left or right edge. */
953
954 if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
955 {
956 bloat.r_ybot = cifArea.r_ybot - dist;
957 bloat.r_ytop = cifArea.r_ytop;
958 }
959 else /* bottom */
960 {
961 bloat.r_ybot = cifArea.r_ybot;
962 bloat.r_ytop = cifArea.r_ytop + dist;
963 }
964
965 if (oldType & TT_SIDE)
966 {
967 bloat.r_xbot = cifArea.r_xtop - dist;
968 bloat.r_xtop = cifArea.r_xtop;
969 }
970 else
971 {
972 bloat.r_xbot = cifArea.r_xbot;
973 bloat.r_xtop = cifArea.r_xbot + dist;
974 }
975 DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL);
976
977 /* Finally, Move and replace the diagonal tile */
978
979 if (oldType & TT_SIDE)
980 {
981 bloat.r_xtop = cifArea.r_xtop - dist;
982 bloat.r_xbot = cifArea.r_xbot - dist;
983 }
984 else
985 {
986 bloat.r_xtop = cifArea.r_xtop + dist;
987 bloat.r_xbot = cifArea.r_xbot + dist;
988 }
989
990 if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */
991 {
992 bloat.r_ytop = cifArea.r_ytop - dist;
993 bloat.r_ybot = cifArea.r_ybot - dist;
994 }
995 else /* bottom */
996 {
997 bloat.r_ytop = cifArea.r_ytop + dist;
998 bloat.r_ybot = cifArea.r_ybot + dist;
999 }
1000 DBNMPaintPlane(cifPlane, oldType, &bloat, CIFPaintTable,
1001 (PaintUndoInfo *) NULL);
1002 }
1003 }
1004 else
1005 DBNMPaintPlane(cifPlane, oldType, &cifArea, CIFPaintTable,
1006 (PaintUndoInfo *) NULL);
1007
1008 /* Go around the tile, scanning the neighbors along each side.
1009 * Start with the left side, and output the bloats along that
1010 * side, if any.
1011 */
1012
1013 tilestop = tileArea.r_ytop;
1014 cifstop = cifArea.r_ytop;
1015 type = oldType;
1016
1017 /* If the tile type doesn't exist on the left side, skip */
1018 if (oldType & TT_DIAGONAL)
1019 {
1020 type = TiGetLeftType(tile);
1021 if (oldType & TT_SIDE)
1022 {
1023 if (oldType & TT_DIRECTION)
1024 {
1025 topLeftType = type;
1026 goto dotop;
1027 }
1028 else
1029 {
1030 tilestop = tileArea.r_ybot;
1031 cifstop = cifArea.r_ybot;
1032 type = TiGetBottomType(tile);
1033 }
1034 }
1035 }
1036
1037 bloat.r_ybot = cifArea.r_ybot - bloatTable[TiGetRightType(LB(tile))];
1038 bloat.r_xtop = cifArea.r_xbot;
1039 for (t = BL(tile); BOTTOM(t) < TOP(tile); t = RT(t))
1040 {
1041 if (BOTTOM(t) >= tilestop) continue;
1042 topLeftType = TiGetRightType(t);
1043 bloat.r_xbot = bloat.r_xtop - bloatTable[topLeftType];
1044 if (TOP(t) > tilestop)
1045 bloat.r_ytop = cifstop;
1046 else bloat.r_ytop = cifScale * TOP(t);
1047 if ((bloatTable[topLeftType] != 0) && (topLeftType != type))
1048 DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1049 (PaintUndoInfo *) NULL);
1050 bloat.r_ybot = bloat.r_ytop;
1051 }
1052
1053 /* Now do the top side. Use the type of the top-left tile to
1054 * side-extend the left end of the top bloat in order to match
1055 * things up at the corner.
1056 */
1057
1058 dotop:
1059 cifstart = cifArea.r_xtop;
1060 tilestart = tileArea.r_xtop;
1061
1062 /* If the tile type doesn't exist on the top side, skip */
1063 if (oldType & TT_DIAGONAL)
1064 {
1065 type = TiGetTopType(tile);
1066 if (((oldType & TT_SIDE) >> 1) != (oldType & TT_DIRECTION))
1067 {
1068 if (oldType & TT_SIDE)
1069 goto doright;
1070 else
1071 {
1072 cifstart = cifArea.r_xbot;
1073 tilestart = tileArea.r_xbot;
1074 type = TiGetLeftType(tile);
1075 }
1076 }
1077 }
1078
1079 bloat.r_ybot = cifArea.r_ytop;
1080 bloat.r_xtop = cifstart;
1081 for (t = RT(tile); RIGHT(t) > LEFT(tile); t = BL(t))
1082 {
1083 TileType otherType;
1084 if (LEFT(t) >= tilestart) continue;
1085 otherType = TiGetBottomType(t);
1086 bloat.r_ytop = bloat.r_ybot + bloatTable[otherType];
1087 if (LEFT(t) <= tileArea.r_xbot)
1088 bloat.r_xbot = cifArea.r_xbot - bloatTable[topLeftType];
1089 else bloat.r_xbot = cifScale * LEFT(t);
1090 if ((bloatTable[otherType] != 0) && (otherType != type))
1091 DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1092 (PaintUndoInfo *) NULL);
1093 bloat.r_xtop = bloat.r_xbot;
1094 }
1095
1096 /* Now do the right side. */
1097
1098 doright:
1099 tilestop = tileArea.r_ybot;
1100 cifstop = cifArea.r_ybot;
1101
1102 /* If the tile type doesn't exist on the right side, skip */
1103 if (oldType & TT_DIAGONAL)
1104 {
1105 type = TiGetRightType(tile);
1106 if (!(oldType & TT_SIDE))
1107 {
1108 if (oldType & TT_DIRECTION)
1109 {
1110 bottomRightType = type;
1111 goto dobottom;
1112 }
1113 else
1114 {
1115 tilestop = tileArea.r_ytop;
1116 cifstop = cifArea.r_ytop;
1117 type = TiGetTopType(tile);
1118 }
1119 }
1120 }
1121
1122 bloat.r_ytop = cifArea.r_ytop + bloatTable[TiGetLeftType(RT(tile))];
1123 bloat.r_xbot = cifArea.r_xtop;
1124 for (t = TR(tile); TOP(t) > BOTTOM(tile); t = LB(t))
1125 {
1126 if (TOP(t) <= tilestop) continue;
1127 bottomRightType = TiGetLeftType(t);
1128 bloat.r_xtop = bloat.r_xbot + bloatTable[bottomRightType];
1129 if (BOTTOM(t) < tilestop)
1130 bloat.r_ybot = cifstop;
1131 else bloat.r_ybot = cifScale * BOTTOM(t);
1132 if ((bloatTable[bottomRightType] != 0) && (bottomRightType != type))
1133 DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1134 (PaintUndoInfo *) NULL);
1135 bloat.r_ytop = bloat.r_ybot;
1136 }
1137
1138 /* Now do the bottom side. Use the type of the bottom-right tile
1139 * to side-extend the right end of the bottom bloat in order to match
1140 * things up at the corner.
1141 */
1142
1143 dobottom:
1144 cifstart = cifArea.r_xbot;
1145 tilestart = tileArea.r_xbot;
1146
1147 /* If the tile type doesn't exist on the bottom side, skip */
1148 if (oldType & TT_DIAGONAL)
1149 {
1150 type = TiGetBottomType(tile);
1151 if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION))
1152 {
1153 if (!(oldType & TT_DIRECTION))
1154 goto endbloat;
1155 else
1156 {
1157 cifstart = cifArea.r_xtop;
1158 tilestart = tileArea.r_xtop;
1159 type = TiGetRightType(tile);
1160 }
1161 }
1162 }
1163
1164 bloat.r_ytop = cifArea.r_ybot;
1165 bloat.r_xbot = cifstart;
1166 for (t = LB(tile); LEFT(t) < RIGHT(tile); t = TR(t))
1167 {
1168 TileType otherType;
1169 if (RIGHT(t) <= tilestart) continue;
1170 otherType = TiGetTopType(t);
1171 bloat.r_ybot = bloat.r_ytop - bloatTable[otherType];
1172 if (RIGHT(t) >= tileArea.r_xtop)
1173 bloat.r_xtop = cifArea.r_xtop + bloatTable[bottomRightType];
1174 else bloat.r_xtop = cifScale * RIGHT(t);
1175 if ((bloatTable[otherType] != 0) && (otherType != type))
1176 DBPaintPlane(cifPlane, &bloat, CIFPaintTable,
1177 (PaintUndoInfo *) NULL);
1178 bloat.r_xbot = bloat.r_xtop;
1179 }
1180
1181 endbloat:
1182 CIFTileOps += 1;
1183 return 0;
1184 }
1185
1186 #define CIF_PENDING 0
1187 #define CIF_UNPROCESSED CLIENTDEFAULT
1188 #define CIF_PROCESSED 1
1189 #define CIF_IGNORE 2
1190
1191 #define PUSHTILE(tp, stack) \
1192 if ((tp)->ti_client == (ClientData) CIF_UNPROCESSED) { \
1193 (tp)->ti_client = (ClientData) CIF_PENDING; \
1194 STACKPUSH((ClientData) (tp), stack); \
1195 }
1196
1197 /*
1198 *-------------------------------------------------------
1199 *
1200 * cifProcessResetFunc --
1201 *
1202 * Unmark tiles
1203 *
1204 * Results: Return 0 to keep the search going.
1205 *
1206 *-------------------------------------------------------
1207 */
1208
1209 int
cifProcessResetFunc(tile,clientData)1210 cifProcessResetFunc(tile, clientData)
1211 Tile *tile;
1212 ClientData clientData; /* unused */
1213 {
1214 tile->ti_client = (ClientData) CIF_UNPROCESSED;
1215 return 0;
1216 }
1217
1218 /*
1219 *-------------------------------------------------------
1220 *
1221 * cifFoundFunc --
1222 *
1223 * Find the first tile in the given area.
1224 *
1225 * Results:
1226 * Return 1 to stop the search and process.
1227 * Set clientData to the tile found.
1228 *
1229 *-------------------------------------------------------
1230 */
1231
1232 int
cifFoundFunc(tile,BloatStackPtr)1233 cifFoundFunc(tile, BloatStackPtr)
1234 Tile *tile;
1235 Stack **BloatStackPtr;
1236 {
1237 PUSHTILE(tile, *BloatStackPtr);
1238 return 0;
1239 }
1240
1241 /* Data structure for bloat-all function */
1242 typedef struct _bloatStruct {
1243 CIFOp *op;
1244 CellDef *def;
1245 TileTypeBitMask connect;
1246 Plane **temps;
1247 } BloatStruct;
1248
1249 /*
1250 * ----------------------------------------------------------------------------
1251 *
1252 * cifBloatAllFunc --
1253 *
1254 * Called once for each tile to be selectively bloated
1255 * using the CIFOP_BLOATALL operation.
1256 *
1257 * Results:
1258 * Always returns 0 to keep the search alive.
1259 *
1260 * Side effects:
1261 * Uses the bloat table in the current CIFOp to expand the tile,
1262 * depending on which tiles it abuts. All bordering material that
1263 * has bl_distance = 1 is painted into the result plane.
1264 *
1265 * ----------------------------------------------------------------------------
1266 */
1267
1268 int
cifBloatAllFunc(tile,bls)1269 cifBloatAllFunc(tile, bls)
1270 Tile *tile; /* The tile to be processed. */
1271 BloatStruct *bls;
1272 {
1273 Rect area;
1274 TileTypeBitMask *connect;
1275 Tile *t, *tp;
1276 TileType type, ttype;
1277 BloatData *bloats;
1278 int i, locScale;
1279 PlaneMask pmask;
1280 CIFOp *op;
1281 CellDef *def;
1282 Plane **temps;
1283 static Stack *BloatStack = (Stack *)NULL;
1284
1285 op = bls->op;
1286 def = bls->def;
1287 temps = bls->temps;
1288 connect = &bls->connect;
1289 bloats = (BloatData *)op->co_client;
1290
1291 /* This search function is based on drcCheckArea */
1292
1293 if (BloatStack == (Stack *)NULL)
1294 BloatStack = StackNew(64);
1295
1296 /* If the type of the tile to be processed is not in the same plane */
1297 /* as the bloat type(s), then find any tile under the tile to be */
1298 /* processed that belongs to the connect mask, and use that as the */
1299 /* starting tile. */
1300
1301 t = tile;
1302 type = TiGetType(tile);
1303 if (type == CIF_SOLIDTYPE)
1304 {
1305 pmask = 0;
1306 if (bloats->bl_plane < 0) /* Bloat types are CIF types */
1307 locScale = 1;
1308 else
1309 locScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
1310
1311 /* Get the tile into magic database coordinates if it's in CIF coords */
1312 TiToRect(tile, &area);
1313 area.r_xbot /= locScale;
1314 area.r_xtop /= locScale;
1315 area.r_ybot /= locScale;
1316 area.r_ytop /= locScale;
1317 }
1318 else
1319 {
1320 int pNum = DBPlane(type);
1321 pmask = (bloats->bl_plane < 0) ? 0 :
1322 CoincidentPlanes(connect, PlaneNumToMaskBit(pNum));
1323 if (pmask == 0) TiToRect(tile, &area);
1324 if (bloats->bl_plane < 0)
1325 {
1326 /* Get the tile into CIF database coordinates if it's in magic coords */
1327 area.r_xbot *= cifScale;
1328 area.r_xtop *= cifScale;
1329 area.r_ybot *= cifScale;
1330 area.r_ytop *= cifScale;
1331 locScale = 1;
1332 }
1333 else
1334 {
1335 locScale = cifScale;
1336 }
1337 }
1338 if (pmask == 0)
1339 {
1340 if (bloats->bl_plane < 0) /* Bloat types are CIF types */
1341 {
1342 /* This expands the area to the OR of all temp layers specified */
1343 /* which may or may not be useful; normally one would expand */
1344 /* into a single layer if a temp layer is specified. */
1345
1346 for (ttype = 0; ttype < TT_MAXTYPES; ttype++, temps++)
1347 if (bloats->bl_distance[ttype] > 0)
1348 (void) DBSrPaintArea((Tile *)NULL, *temps, &area,
1349 &CIFSolidBits, cifFoundFunc, (ClientData)(&BloatStack));
1350 }
1351 else
1352 DBSrPaintArea((Tile *)NULL, def->cd_planes[bloats->bl_plane], &area,
1353 connect, cifFoundFunc, (ClientData)(&BloatStack));
1354 }
1355 else
1356 PUSHTILE(t, BloatStack);
1357
1358 while (!StackEmpty(BloatStack))
1359 {
1360 t = (Tile *) STACKPOP(BloatStack);
1361 if (t->ti_client != (ClientData)CIF_PENDING) continue;
1362 t->ti_client = (ClientData)CIF_PROCESSED;
1363
1364 /* Get the tile into CIF coordinates. */
1365
1366 TiToRect(t, &area);
1367 area.r_xbot *= locScale;
1368 area.r_ybot *= locScale;
1369 area.r_xtop *= locScale;
1370 area.r_ytop *= locScale;
1371
1372 DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
1373 CIFPaintTable, (PaintUndoInfo *) NULL);
1374
1375 /* Top */
1376 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
1377 if (TTMaskHasType(connect, TiGetBottomType(tp)))
1378 PUSHTILE(tp, BloatStack);
1379
1380 /* Left */
1381 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
1382 if (TTMaskHasType(connect, TiGetRightType(tp)))
1383 PUSHTILE(tp, BloatStack);
1384
1385 /* Bottom */
1386 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
1387 if (TTMaskHasType(connect, TiGetTopType(tp)))
1388 PUSHTILE(tp, BloatStack);
1389
1390 /* Right */
1391 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
1392 if (TTMaskHasType(connect, TiGetLeftType(tp)))
1393 PUSHTILE(tp, BloatStack);
1394 }
1395
1396 /* Clear the tiles that were processed */
1397
1398 tile->ti_client = (ClientData)CIF_UNPROCESSED;
1399 STACKPUSH(tile, BloatStack);
1400 while (!StackEmpty(BloatStack))
1401 {
1402 t = (Tile *) STACKPOP(BloatStack);
1403
1404 /* Top */
1405 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
1406 if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1407 {
1408 tp->ti_client = (ClientData)CIF_UNPROCESSED;
1409 STACKPUSH(tp, BloatStack);
1410 }
1411
1412 /* Left */
1413 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
1414 if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1415 {
1416 tp->ti_client = (ClientData)CIF_UNPROCESSED;
1417 STACKPUSH(tp, BloatStack);
1418 }
1419
1420 /* Bottom */
1421 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
1422 if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1423 {
1424 tp->ti_client = (ClientData)CIF_UNPROCESSED;
1425 STACKPUSH(tp, BloatStack);
1426 }
1427
1428 /* Right */
1429 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
1430 if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
1431 {
1432 tp->ti_client = (ClientData)CIF_UNPROCESSED;
1433 STACKPUSH(tp, BloatStack);
1434 }
1435 }
1436
1437 return 0; /* Keep the search alive. . . */
1438 }
1439
1440 /* Data structure to pass plane and minimum width to the callback function */
1441 typedef struct _bridgeStruct {
1442 Plane *plane;
1443 BridgeData *bridge;
1444 } BridgeStruct;
1445
1446 /* Bridge Check data structure */
1447 typedef struct _bridgeCheckStruct {
1448 Tile *tile; /* Tile that triggered search (ignore this tile) */
1449 Rect *area; /* Area of search */
1450 int direction; /* What outside corner to look for */
1451 Tile *violator; /* Return the violator tile in this space */
1452 TileType checktype; /* Type to check for, either TT_SPACE or CIF_SOLIDTYPE */
1453 } BridgeCheckStruct;
1454
1455 /* Direction flags */
1456 #define BRIDGE_NW 1
1457 #define BRIDGE_SW 2
1458
1459 /*
1460 * ----------------------------------------------------------------------------
1461 *
1462 * Function that returns the Euclidean distance corresponding to a manhattan
1463 * distance of the given width, at 45 degrees.
1464 *
1465 * This is used by the bridging method to keep the amount of extra material
1466 * added to a minimum.
1467 *
1468 * ----------------------------------------------------------------------------
1469 */
1470
1471 int
GetEuclideanWidthGrid(width)1472 GetEuclideanWidthGrid(width)
1473 int width;
1474 {
1475 int weuclid;
1476 int delta;
1477 int limit;
1478
1479 limit = CIFCurStyle->cs_gridLimit;
1480
1481 weuclid = (int)(ceil((double)width * 0.70711));
1482 if (CIFCurStyle && (limit > 1))
1483 {
1484 delta = weuclid % limit;
1485 if (delta > 0)
1486 {
1487 weuclid -= delta;
1488 weuclid += limit;
1489 }
1490 }
1491 return weuclid;
1492 }
1493
1494 /*
1495 * ----------------------------------------------------------------------------
1496 *
1497 * GetExpandedAreaGrid --
1498 *
1499 * Given a pointer "area" to a Rect and a minimum layer width "width",
1500 * find the minimum size rectangle that expands "area" in all directions
1501 * equally to ensure that the length of the diagonal of the expanded
1502 * area is greater than or equal to "width". This is used by the
1503 * "bridge" operator to ensure that the bridging rectangle meets the
1504 * minimum layer width requirement.
1505 *
1506 * Results:
1507 * None.
1508 *
1509 * Side effects:
1510 * The Rect structure pointed to by "area" may be altered.
1511 *
1512 * Notes:
1513 * The calculation needed depends on the geometry. If there is a
1514 * horizontal gap between the tiles, then the bridging shape must
1515 * be as tall as the minimum width rule; this is the vertical
1516 * case (horiz = FALSE). If there is a vertical gap between the
1517 * tiles, then the bridging shape must be as wide as the minimum
1518 * width rule; this is the horizontal case (horiz = TRUE). Then
1519 * calculate the length of the bridging shape in the other direction
1520 * needed to ensure that the join of the bridging shape and the
1521 * preexisting shapes is always wide enough to satisfy the width
1522 * rule. Which calculation is needed depends on whether the shapes
1523 * are catecorner (overlap = FALSE) or overlapping in one direction
1524 * (overlap = TRUE).
1525 *
1526 * ----------------------------------------------------------------------------
1527 */
1528
1529 void
GetExpandedAreaGrid(wrule,space,area)1530 GetExpandedAreaGrid(wrule, space, area)
1531 int wrule;
1532 bool space;
1533 Rect *area;
1534 {
1535 bool horiz;
1536 bool overlap;
1537 Rect r;
1538
1539 int width, height, dx, dy, a, b, delta, dx2, dy2, limit;
1540
1541 overlap = FALSE;
1542 if (area->r_xbot > area->r_xtop)
1543 {
1544 overlap = TRUE;
1545 horiz = (space) ? FALSE : TRUE;
1546 }
1547 if (area->r_ybot > area->r_ytop)
1548 {
1549 overlap = TRUE;
1550 horiz = (space) ? TRUE : FALSE;
1551 }
1552
1553 GeoCanonicalRect(area, &r);
1554 width = r.r_xtop - r.r_xbot;
1555 height = r.r_ytop - r.r_ybot;
1556
1557 if (overlap == FALSE)
1558 horiz = (width > height);
1559
1560 if (horiz)
1561 {
1562 a = wrule - width;
1563 dx = (int)ceilf((float)a / 2.0);
1564 if (overlap || space)
1565 b = wrule * wrule - (width + dx) * (width + dx);
1566 else
1567 b = wrule * wrule - dx * dx;
1568 if (space && !overlap)
1569 dy = (int)ceilf(sqrtf((float)b) - height);
1570 else
1571 dy = (int)ceilf(sqrtf((float)b));
1572
1573 b = wrule * wrule - width * width;
1574 dy2 = (int)ceilf((sqrtf((float)b) - height) / 2.0);
1575 if (dy2 > dy) dy = dy2;
1576 }
1577 else
1578 {
1579 a = wrule - height;
1580 dy = (int)ceilf((float)a / 2.0);
1581 if (overlap || space)
1582 b = wrule * wrule - (height + dy) * (height + dy);
1583 else
1584 b = wrule * wrule - dy * dy;
1585 if (space && !overlap)
1586 dx = (int)ceilf(sqrtf((float)b) - width);
1587 else
1588 dx = (int)ceilf(sqrtf((float)b));
1589
1590 b = wrule * wrule - height * height;
1591 dx2 = (int)ceilf((sqrtf((float)b) - width) / 2.0);
1592 if (dx2 > dx) dx = dx2;
1593 }
1594
1595 r.r_xbot -= dx;
1596 r.r_xtop += dx;
1597 r.r_ybot -= dy;
1598 r.r_ytop += dy;
1599
1600 limit = CIFCurStyle->cs_gridLimit;
1601
1602 if (CIFCurStyle && (limit > 1))
1603 {
1604 delta = r.r_xbot % limit;
1605 if (delta > 0)
1606 r.r_xbot -= delta;
1607 else if (delta < 0)
1608 r.r_xbot -= limit + delta;
1609
1610 delta = r.r_xtop % limit;
1611 if (delta > 0)
1612 r.r_xtop += limit - delta;
1613 else if (delta < 0)
1614 r.r_xtop -= delta;
1615
1616 delta = r.r_ybot % limit;
1617 if (delta > 0)
1618 r.r_ybot -= delta;
1619 else if (delta < 0)
1620 r.r_ybot -= limit + delta;
1621
1622 delta = r.r_ytop % limit;
1623 if (delta > 0)
1624 r.r_ytop += limit - delta;
1625 else if (delta < 0)
1626 r.r_ytop -= delta;
1627 }
1628
1629 *area = r;
1630 }
1631
1632 /*
1633 * ----------------------------------------------------------------------------
1634 *
1635 * cifBridgeFunc1 --
1636 *
1637 * Called for each relevant tile during bridge operations. The
1638 * bridge operation is responsible for preventing a grow-shrink
1639 * pair of operations from leaving width or spacing DRC errors,
1640 * which happens when tiles are in a catecorner position from
1641 * each other. The bridge operation adds a bridge of material
1642 * between the two tiles that solves spacing requirements between
1643 * the two tiles while satisfying the minimum width requirements,
1644 * adding a minimum amount of material to do so.
1645 *
1646 * The current version of this routine adds material on a stair-step
1647 * pattern; preferably this should be extended to create material
1648 * at allowed angles, where the allowed angles (90, 45, or any) are
1649 * specified as an option to the bridge statement in the tech file.
1650 *
1651 * GrowDistance is equal to the spacing rule distance needing to be
1652 * satisfied.
1653 *
1654 * Results:
1655 * Always returns 0 to keep the search alive.
1656 *
1657 * Side effects:
1658 * Paints into cifNewPlane. Tiles in old plane are tagged with
1659 * a static value in ClientData, which does not need to be reset
1660 * since the old plane will be free'd.
1661 * ----------------------------------------------------------------------------
1662 */
1663
1664 int
cifBridgeFunc1(tile,brs)1665 cifBridgeFunc1(tile, brs)
1666 Tile *tile;
1667 BridgeStruct *brs;
1668 {
1669 Plane *plane = brs->plane;
1670 Rect area;
1671 Tile *tp1, *tp2, *tpx;
1672 int width = brs->bridge->br_width;
1673 int spacing = growDistance;
1674 BridgeCheckStruct brcs;
1675 int cifBridgeCheckFunc(); /* Forward reference */
1676
1677 /* If tile is marked, then it has been handled, so ignore it */
1678 if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
1679
1680 /* Find each tile outside corner (only two cases need to be checked) */
1681
1682 /* Check for NE outside corner */
1683 tp1 = TR(tile); /* Tile on right side at the top of this tile */
1684 tp2 = RT(tile); /* Tile on top side at the right of this tile */
1685 if ((TiGetLeftType(tp1) == TT_SPACE) &&
1686 (TiGetBottomType(tp2) == TT_SPACE))
1687 {
1688 /* Set search box */
1689 area.r_xbot = RIGHT(tile) - width;
1690 area.r_xtop = RIGHT(tile) + spacing;
1691 area.r_ybot = TOP(tile) - width;
1692 area.r_ytop = TOP(tile) + spacing;
1693
1694 /* Find violator tiles */
1695 brcs.tile = tile;
1696 brcs.area = &area;
1697 brcs.direction = BRIDGE_SW;
1698 brcs.checktype = TT_SPACE;
1699 if (DBSrPaintArea((Tile *) NULL, plane, &area,
1700 &CIFSolidBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1701 {
1702 tpx = brcs.violator;
1703
1704 area.r_xbot = RIGHT(tile);
1705 area.r_ybot = TOP(tile);
1706 area.r_xtop = LEFT(tpx);
1707 area.r_ytop = BOTTOM(tpx);
1708
1709 GetExpandedAreaGrid(width, FALSE, &area);
1710
1711 /* Trivial implementation: fill box */
1712 /* (to do: use stairstep to avoid filling unnecessary areas) */
1713 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1714 }
1715 }
1716
1717 /* Check for SE outside corner */
1718 for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
1719 for (tp2 = LB(tile); RIGHT(tp1) < RIGHT(tile); tp2 = TR(tp2));
1720 if ((TiGetLeftType(tp1) == TT_SPACE) &&
1721 (TiGetTopType(tp2) == TT_SPACE))
1722 {
1723 /* Set search box */
1724 area.r_xbot = RIGHT(tile) - width;
1725 area.r_xtop = RIGHT(tile) + spacing;
1726 area.r_ybot = BOTTOM(tile) - spacing;
1727 area.r_ytop = BOTTOM(tile) + width;
1728
1729 /* Find violator tiles */
1730 brcs.tile = tile;
1731 brcs.area = &area;
1732 brcs.direction = BRIDGE_NW;
1733 brcs.checktype = TT_SPACE;
1734 if (DBSrPaintArea((Tile *) NULL, plane, &area,
1735 &CIFSolidBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1736 {
1737 tpx = brcs.violator;
1738
1739 area.r_xbot = RIGHT(tile);
1740 area.r_ybot = TOP(tpx);
1741 area.r_xtop = LEFT(tpx);
1742 area.r_ytop = BOTTOM(tile);
1743
1744 GetExpandedAreaGrid(width, FALSE, &area);
1745
1746 /* Trivial implementation: fill box */
1747 /* (to do: use stairstep to avoid filling unnecessary areas) */
1748 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1749 }
1750 }
1751 return 0;
1752 }
1753
1754 /*
1755 * ----------------------------------------------------------------------------
1756 *
1757 * cifBridgeFunc2 --
1758 *
1759 * Called for each relevant tile during bridge operations. The
1760 * bridge operation is responsible for preventing a grow-shrink
1761 * pair of operations from leaving width or spacing DRC errors,
1762 * which happens when tiles are overlapping at a corner with the
1763 * overlap failing to meet the minimum width requirement. The
1764 * bridge operation adds a bridge of material over the pinch
1765 * point that solves the minimum width requirement, adding a
1766 * minimum amount of material to do so.
1767 *
1768 * The current version of this routine adds material on a stair-step
1769 * pattern; preferably this should be extended to create material
1770 * at allowed angles, where the allowed angles (90, 45, or any) are
1771 * specified as an option to the bridge statement in the tech file.
1772 *
1773 * growDistance is equal to the spacing rule distance needing to be
1774 * satisfied.
1775 *
1776 * Results:
1777 * Always returns 0 to keep the search alive.
1778 *
1779 * Side effects:
1780 * Paints into cifNewPlane. Tiles in old plane are tagged with
1781 * a static value in ClientData, which does not need to be reset
1782 * since the old plane will be free'd.
1783 * ----------------------------------------------------------------------------
1784 */
1785
1786 int
cifBridgeFunc2(tile,brs)1787 cifBridgeFunc2(tile, brs)
1788 Tile *tile;
1789 BridgeStruct *brs;
1790 {
1791 Plane *plane = brs->plane;
1792 Rect area;
1793 Tile *tp1, *tp2, *tpx;
1794 int width = brs->bridge->br_width;
1795 int wtest;
1796 int spacing = growDistance;
1797 BridgeCheckStruct brcs;
1798 int cifBridgeCheckFunc(); /* Forward reference */
1799
1800 /* If tile is marked, then it has been handled, so ignore it */
1801 if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
1802
1803 /* Find each tile outside corner (only two cases need to be checked) */
1804
1805 /* Check for NE outside corner */
1806 tp1 = TR(tile); /* Tile on right side at the top of this tile */
1807 tp2 = RT(tile); /* Tile on top side at the right of this tile */
1808 if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
1809 (TiGetBottomType(tp2) == CIF_SOLIDTYPE))
1810 {
1811 /* Set search box */
1812 area.r_xbot = RIGHT(tile) - spacing;
1813 area.r_xtop = RIGHT(tile) + width;
1814 area.r_ybot = TOP(tile) - spacing;
1815 area.r_ytop = TOP(tile) + width;
1816
1817 /* Find violator tiles */
1818 brcs.tile = tile;
1819 brcs.area = &area;
1820 brcs.direction = BRIDGE_SW;
1821 brcs.checktype = CIF_SOLIDTYPE;
1822 if (DBSrPaintArea((Tile *) NULL, plane, &area,
1823 &DBSpaceBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1824 {
1825 tpx = brcs.violator;
1826
1827 area.r_xbot = RIGHT(tile);
1828 area.r_ybot = TOP(tile);
1829 area.r_xtop = LEFT(tpx);
1830 area.r_ytop = BOTTOM(tpx);
1831
1832 GetExpandedAreaGrid(width, TRUE, &area);
1833
1834 /* Trivial implementation: fill box */
1835 /* (to do: use stairstep to avoid filling unnecessary areas) */
1836 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1837 }
1838 }
1839
1840 /* Check for SE outside corner */
1841 for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
1842 for (tp2 = LB(tile); RIGHT(tp2) < RIGHT(tile); tp2 = TR(tp2));
1843 if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
1844 (TiGetTopType(tp2) == CIF_SOLIDTYPE))
1845 {
1846 /* Set search box */
1847 area.r_xbot = RIGHT(tile) - spacing;
1848 area.r_xtop = RIGHT(tile) + width;
1849 area.r_ybot = BOTTOM(tile) - width;
1850 area.r_ytop = BOTTOM(tile) + spacing;
1851
1852 /* Find violator tiles */
1853 brcs.tile = tile;
1854 brcs.area = &area;
1855 brcs.direction = BRIDGE_NW;
1856 brcs.checktype = CIF_SOLIDTYPE;
1857 if (DBSrPaintArea((Tile *) NULL, plane, &area,
1858 &DBSpaceBits, cifBridgeCheckFunc, (ClientData)&brcs) == 1)
1859 {
1860 tpx = brcs.violator;
1861
1862 area.r_xbot = RIGHT(tile);
1863 area.r_ybot = TOP(tpx);
1864 area.r_xtop = LEFT(tpx);
1865 area.r_ytop = BOTTOM(tile);
1866
1867 GetExpandedAreaGrid(width, TRUE, &area);
1868
1869 /* Trivial implementation: fill box */
1870 /* (to do: use stairstep to avoid filling unnecessary areas) */
1871 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
1872 }
1873 }
1874 return 0;
1875 }
1876
1877 /*
1878 *-----------------------------------------------------------------------
1879 * Callback function for cifBridgeFunc1 and cifBridgeFunc2 to find if
1880 * there are violator cells in the search area. If a violator cell is
1881 * found, then put the tile pointer in the BridgeCheckStruct and return
1882 * value 1 to stop the search. Otherwise return 0 to keep going.
1883 *-----------------------------------------------------------------------
1884 */
1885
1886 int
cifBridgeCheckFunc(tile,brcs)1887 cifBridgeCheckFunc(tile, brcs)
1888 Tile *tile;
1889 BridgeCheckStruct *brcs;
1890 {
1891 int dir = brcs->direction;
1892 Tile *self = brcs->tile;
1893 Tile *tp1, *tp2;
1894 TileType checktype = brcs->checktype;
1895
1896 if (self == tile) return 0; /* Ignore the triggering tile */
1897
1898 switch (dir) {
1899 case BRIDGE_NW:
1900 /* Ignore tile if NW corner is not in the search area */
1901 for (tp1 = RT(tile); LEFT(tp1) > LEFT(tile); tp1 = BL(tp1));
1902 if (LEFT(tile) <= brcs->area->r_xbot || TOP(tile) >= brcs->area->r_ytop)
1903 break;
1904 /* Check that this is not a false corner */
1905 else if (TiGetBottomType(tp1) == TiGetTopType(tile))
1906 break;
1907 /* Ignore tile if split, and SE corner is clipped */
1908 if (TiGetRightType(tile) == checktype || TiGetBottomType(tile) == checktype)
1909 break;
1910 for (tp2 = BL(tile); TOP(tp2) < TOP(tile); tp2 = RT(tp2));
1911 if ((TiGetBottomType(tp1) == checktype) &&
1912 (TiGetRightType(tp2) == checktype))
1913 {
1914 brcs->violator = tile;
1915 return 1; /* Violator found */
1916 }
1917 break;
1918 case BRIDGE_SW:
1919 /* Ignore tile if SW corner is not in the search area */
1920 tp1 = LB(tile);
1921 if (LEFT(tile) <= brcs->area->r_xbot || BOTTOM(tile) <= brcs->area->r_ybot)
1922 break;
1923 /* Check that this is not a false corner */
1924 else if (TiGetTopType(tp1) == TiGetBottomType(tile))
1925 break;
1926 /* Ignore tile if split, and NE corner is clipped */
1927 if (TiGetRightType(tile) == checktype || TiGetTopType(tile) == checktype)
1928 break;
1929 tp2 = BL(tile);
1930 if ((TiGetTopType(tp1) == checktype) ||
1931 (TiGetRightType(tp2) == checktype))
1932 {
1933 brcs->violator = tile;
1934 return 1; /* Violator found */
1935 }
1936 break;
1937 }
1938 return 0; /* Nothing found here, so keep going */
1939 }
1940
1941 /*
1942 * ----------------------------------------------------------------------------
1943 *
1944 * cifCloseFunc --
1945 *
1946 * Called for each relevant tile during close operations.
1947 *
1948 * Results:
1949 * Always returns 0 to keep the search alive.
1950 *
1951 * Side effects:
1952 * Paints into cifNewPlane. Tiles in old plane are tagged with
1953 * a static value in ClientData, which does not need to be reset
1954 * since the old plane will be free'd.
1955 * ----------------------------------------------------------------------------
1956 */
1957
1958 #define CLOSE_SEARCH 0
1959 #define CLOSE_FILL 1
1960 #define CLOSE_DONE 2
1961
1962 int
cifCloseFunc(tile,plane)1963 cifCloseFunc(tile, plane)
1964 Tile *tile;
1965 Plane *plane;
1966 {
1967 Rect area, newarea;
1968 int atotal;
1969 int cifGatherFunc();
1970
1971 /* If tile is marked, then it has been handled, so ignore it */
1972 if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
1973
1974 atotal = 0;
1975
1976 /* Search all sides for connected space tiles, and accumulate the total */
1977 /* area. If any connected tile borders infinity, then stop searching */
1978 /* because the area is not enclosed. */
1979
1980 cifGatherFunc(tile, &atotal, CLOSE_SEARCH);
1981
1982 /* If the total area is smaller than the rule area, then paint all the */
1983 /* tile areas into the destination plane. */
1984
1985 if ((atotal != INFINITY) && (atotal < growDistance))
1986 {
1987 cifGatherFunc(tile, &atotal, CLOSE_FILL);
1988 }
1989 else
1990 {
1991 cifGatherFunc(tile, &atotal, CLOSE_DONE);
1992 }
1993
1994 return 0;
1995 }
1996
1997 int
cifGatherFunc(tile,atotal,mode)1998 cifGatherFunc(tile, atotal, mode)
1999 Tile *tile;
2000 int *atotal;
2001 bool mode;
2002 {
2003 Tile *tp;
2004 TileType type;
2005 dlong locarea;
2006 Rect area, newarea;
2007 ClientData cdata = (mode == CLOSE_SEARCH) ? (ClientData)CIF_UNPROCESSED :
2008 (ClientData)CIF_PENDING;
2009
2010 static Stack *GatherStack = (Stack *)NULL;
2011
2012 if (GatherStack == (Stack *)NULL)
2013 GatherStack = StackNew(64);
2014
2015 STACKPUSH(tile, GatherStack);
2016 while (!StackEmpty(GatherStack))
2017 {
2018 tile = (Tile *)STACKPOP(GatherStack);
2019
2020 /* Ignore if tile has already been processed */
2021 if (tile->ti_client != cdata) continue;
2022
2023 TiToRect(tile, &area);
2024
2025 /* Boundary tiles indicate an unclosed area, so set the area total to */
2026 /* INFINITY and don't try to run calculations on it. NOTE: */
2027 /* TiPlaneRect is slightly smaller than the plane boundaries on all */
2028 /* sides. */
2029
2030 if ((area.r_xbot <= TiPlaneRect.r_xbot) ||
2031 (area.r_ybot <= TiPlaneRect.r_ybot) ||
2032 (area.r_xtop >= TiPlaneRect.r_xtop) ||
2033 (area.r_ytop >= TiPlaneRect.r_ytop))
2034 *atotal = INFINITY;
2035
2036 /* Stop accumulating if already larger than growDistance to avoid the */
2037 /* possibility of integer overflow. */
2038 if (mode == CLOSE_SEARCH)
2039 {
2040 if ((*atotal != INFINITY) && (*atotal < growDistance))
2041 {
2042 locarea = (dlong)(area.r_xtop - area.r_xbot)
2043 * (dlong)(area.r_ytop - area.r_ybot);
2044 if (IsSplit(tile)) locarea /= 2;
2045 if (locarea > (dlong)INFINITY)
2046 *atotal = INFINITY;
2047 else
2048 *atotal += (int)locarea;
2049 }
2050 }
2051 else if (mode == CLOSE_FILL)
2052 {
2053 TileType dinfo = TiGetTypeExact(tile);
2054
2055 /* The tile type cannot be depended on to have the TT_SIDE bit set */
2056 /* for the side of the tile that is TT_SPACE. So set the side bit */
2057 /* manually. */
2058
2059 if (IsSplit(tile))
2060 {
2061 if (TiGetLeftType(tile) == TT_SPACE)
2062 dinfo &= ~TT_SIDE;
2063 else
2064 dinfo |= TT_SIDE;
2065 }
2066
2067 DBNMPaintPlane(cifPlane, dinfo, &area, CIFPaintTable, (PaintUndoInfo *)NULL);
2068 CIFTileOps++;
2069 }
2070
2071 if (mode == CLOSE_SEARCH)
2072 tile->ti_client = (ClientData)CIF_PENDING;
2073 else
2074 tile->ti_client = (ClientData)CIF_PROCESSED;
2075
2076 /* Look for additional neighboring space tiles */
2077 /* Check top */
2078 if (area.r_ytop != TiPlaneRect.r_ytop)
2079 for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
2080 if (tp->ti_client == cdata && TiGetBottomType(tp) == TT_SPACE)
2081 {
2082 STACKPUSH(tp, GatherStack);
2083 }
2084
2085 /* Check bottom */
2086 if (area.r_ybot != TiPlaneRect.r_ybot)
2087 for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
2088 if (tp->ti_client == cdata && TiGetTopType(tp) == TT_SPACE)
2089 {
2090 STACKPUSH(tp, GatherStack);
2091 }
2092
2093 /* Check left */
2094 if (area.r_xbot != TiPlaneRect.r_xbot)
2095 for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
2096 if (tp->ti_client == cdata && TiGetRightType(tp) == TT_SPACE)
2097 {
2098 STACKPUSH(tp, GatherStack);
2099 }
2100
2101 /* Check right */
2102 if (area.r_xtop != TiPlaneRect.r_xtop)
2103 for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
2104 if (tp->ti_client == cdata && TiGetLeftType(tp) == TT_SPACE)
2105 {
2106 STACKPUSH(tp, GatherStack);
2107 }
2108 }
2109 return 0;
2110 }
2111
2112 /*--------------------------------------------------------------*/
2113 /* Support routines and definitions for cifSquaresFillArea */
2114 /*--------------------------------------------------------------*/
2115
2116 /*------------------------------------------------------*/
2117 /* Data structure used for identifying contact strips */
2118 /*------------------------------------------------------*/
2119
2120 typedef struct _linkedStrip {
2121 Rect area;
2122 bool vertical; /* Tile is vertical */
2123 bool shrink_ld; /* Shrink left or down before creating cuts */
2124 bool shrink_ur; /* Shrink right or up before creating cuts */
2125 struct _linkedStrip *strip_next;
2126 } linkedStrip;
2127
2128 typedef struct
2129 {
2130 int size;
2131 int pitch;
2132 linkedStrip *strips;
2133 } StripsData;
2134
2135 /*
2136 *-------------------------------------------------------
2137 *
2138 * cifSquaresInitFunc --
2139 *
2140 * Find the first unprocessed tile in the plane.
2141 *
2142 * Results:
2143 * Return 1 to stop the search and process.
2144 * Otherwise, return 0 to keep the search going.
2145 *
2146 *-------------------------------------------------------
2147 */
2148
2149 int
cifSquaresInitFunc(tile,clientData)2150 cifSquaresInitFunc(tile, clientData)
2151 Tile *tile;
2152 ClientData clientData;
2153 {
2154 if (tile->ti_client == (ClientData) CIF_UNPROCESSED)
2155 return 1;
2156 else
2157 return 0;
2158 }
2159
2160 /*
2161 *-------------------------------------------------------
2162 *
2163 * cifSquaresStripFunc --
2164 *
2165 * Find vertical or horizontal strips of contact
2166 * material that is between 1 and 2 contact cuts wide.
2167 * Generate and return a list of all such strips.
2168 *
2169 * Results: Return 0 to keep the search going.
2170 *
2171 *-------------------------------------------------------
2172 */
2173
2174 int
cifSquaresStripFunc(tile,stripsData)2175 cifSquaresStripFunc(tile, stripsData)
2176 Tile *tile;
2177 StripsData *stripsData;
2178 {
2179 bool vertical;
2180 int width, height;
2181 linkedStrip *newStrip;
2182 Tile *tp, *tp2;
2183 Rect bbox;
2184
2185 if (IsSplit(tile))
2186 return 0;
2187 TiToRect(tile, &bbox);
2188
2189 /* Check if the tile is wide enough for exactly one cut */
2190
2191 width = bbox.r_xtop - bbox.r_xbot;
2192 height = bbox.r_ytop - bbox.r_ybot;
2193
2194 if (height > width)
2195 {
2196 vertical = TRUE;
2197 height = width;
2198 }
2199 else
2200 vertical = FALSE;
2201
2202 if ((height < stripsData->size) || (height >=
2203 (stripsData->size + stripsData->pitch)))
2204 return 0;
2205
2206 /* Ignore strips that are part of a larger */
2207 /* collection of non-manhattan geometry. */
2208
2209 for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
2210 if (IsSplit(tp))
2211 break;
2212 if (BOTTOM(tp) < TOP(tile))
2213 return 0;
2214
2215 /* Note that the max horizontal stripes rule guarantees */
2216 /* that a tile is always bounded on left and right by */
2217 /* TT_SPACE. Thus, we only need to search the top and */
2218 /* bottom boundaries of horizontal tiles. */
2219
2220 if (vertical)
2221 {
2222 newStrip = (linkedStrip *)mallocMagic(sizeof(linkedStrip));
2223 newStrip->area = bbox;
2224 newStrip->vertical = TRUE;
2225 newStrip->shrink_ur = (TTMaskHasType(&CIFSolidBits,
2226 TiGetBottomType(RT(tile)))) ? TRUE : FALSE;
2227 newStrip->shrink_ld = (TTMaskHasType(&CIFSolidBits,
2228 TiGetTopType(LB(tile)))) ? TRUE : FALSE;
2229 newStrip->strip_next = stripsData->strips;
2230 stripsData->strips = newStrip;
2231 }
2232 else
2233 {
2234 int segstart, segend;
2235 int matchstart, matchend;
2236
2237 tp = RT(tile);
2238 segend = RIGHT(tile);
2239 while (RIGHT(tp) > LEFT(tile))
2240 {
2241 /* Isolate segments of space along the top of the tile */
2242
2243 while ((RIGHT(tp) > LEFT(tile)) &&
2244 TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2245 tp = BL(tp);
2246 segend = MIN(segend, RIGHT(tp));
2247 while ((RIGHT(tp) > LEFT(tile)) &&
2248 TTMaskHasType(&DBSpaceBits, TiGetBottomType(tp)))
2249 tp = BL(tp);
2250 segstart = MAX(LEFT(tile), RIGHT(tp));
2251 if (segend <= segstart) break;
2252
2253 /* Find matching segments along the bottom of the tile */
2254
2255 for (tp2 = LB(tile); RIGHT(tp2) < segstart; tp2 = TR(tp2));
2256
2257 while (LEFT(tp2) < segend)
2258 {
2259 while (RIGHT(tp2) < segstart) tp2 = TR(tp2);
2260 while ((LEFT(tp2) < segend) &&
2261 TTMaskHasType(&CIFSolidBits, TiGetTopType(tp2)))
2262 tp2 = TR(tp2);
2263 matchstart = MAX(LEFT(tp2), segstart);
2264 while ((LEFT(tp2) < segend) &&
2265 TTMaskHasType(&DBSpaceBits, TiGetTopType(tp2)))
2266 tp2 = TR(tp2);
2267 matchend = MIN(LEFT(tp2), segend);
2268 if (matchend <= matchstart) break;
2269
2270 /* Process the strip */
2271
2272 newStrip = (linkedStrip *)mallocMagic(sizeof(linkedStrip));
2273 newStrip->area = bbox;
2274 newStrip->area.r_xbot = matchstart;
2275 newStrip->area.r_xtop = matchend;
2276 newStrip->vertical = FALSE;
2277 newStrip->strip_next = stripsData->strips;
2278 newStrip->shrink_ur = (matchend != RIGHT(tile)) ? TRUE : FALSE;
2279 newStrip->shrink_ld = (matchstart != LEFT(tile)) ? TRUE : FALSE;
2280
2281 stripsData->strips = newStrip;
2282 }
2283 }
2284 }
2285 return 0;
2286 }
2287
2288 /*
2289 *-------------------------------------------------------
2290 *
2291 * cifUnconnectFunc --
2292 *
2293 * Find space tiles inside a possible contact area
2294 *
2295 * Results: Return 1 to stop the ongoing search.
2296 *
2297 *-------------------------------------------------------
2298 */
2299
2300
2301 int
cifUnconnectFunc(tile,clientData)2302 cifUnconnectFunc(tile, clientData)
2303 Tile *tile;
2304 ClientData clientData; /* unused */
2305 {
2306 TileType t = TiGetTypeExact(tile);
2307 if (t == TT_SPACE) return 1;
2308 else if (t & TT_DIAGONAL) return 1;
2309 else if (tile->ti_client != (ClientData)CIF_PROCESSED) return 1;
2310 return 0;
2311 }
2312
2313 /*
2314 * ----------------------------------------------------------------------------
2315 *
2316 * cifRectBoundingBox --
2317 *
2318 * Fill regions of the current CIF plane with rectangles that represent
2319 * the bounding box of each unconnected area. This function "cleans
2320 * up" areas processed by multiple rules and removes notches and
2321 * cut-outs.
2322 *
2323 * Results:
2324 * None.
2325 *
2326 * Side effects:
2327 *
2328 * ----------------------------------------------------------------------------
2329 */
2330
2331 void
cifRectBoundingBox(op,cellDef,plane)2332 cifRectBoundingBox(op, cellDef, plane)
2333 CIFOp *op;
2334 CellDef *cellDef;
2335 Plane *plane;
2336 {
2337 Tile *tile = NULL, *t, *tp;
2338 Rect bbox, area, *maxr;
2339 int i, j, savecount;
2340 TileType type;
2341 bool simple;
2342 static Stack *BoxStack = (Stack *)NULL;
2343
2344 if (BoxStack == (Stack *)NULL)
2345 BoxStack = StackNew(64);
2346
2347 while (DBSrPaintArea((Tile *)tile, plane, &TiPlaneRect, &CIFSolidBits,
2348 cifSquaresInitFunc, (ClientData)NULL) != 0)
2349 {
2350 /* Now, search for (nontrivially) connected tiles in all */
2351 /* directions. Mark the tiles, and record the bounding box. */
2352 /* (Largely copied from cifSquaresFillArea) */
2353
2354 simple = TRUE;
2355 tile = plane->pl_hint;
2356 TiToRect(tile, &bbox);
2357
2358 PUSHTILE(tile, BoxStack);
2359 while (!StackEmpty(BoxStack))
2360 {
2361 t = (Tile *) STACKPOP(BoxStack);
2362 if (t->ti_client != (ClientData)CIF_PENDING) continue;
2363 t->ti_client = (ClientData)CIF_PROCESSED;
2364
2365 /* Adjust bounding box */
2366 TiToRect(t, &area);
2367 GeoInclude(&area, &bbox);
2368
2369 if (IsSplit(t)) simple = FALSE;
2370
2371 /* Top */
2372 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2373 if (TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2374 {
2375 simple = FALSE;
2376 PUSHTILE(tp, BoxStack);
2377 }
2378
2379 /* Left */
2380 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2381 if (TTMaskHasType(&CIFSolidBits, TiGetRightType(tp)))
2382 {
2383 simple = FALSE;
2384 PUSHTILE(tp, BoxStack);
2385 }
2386
2387 /* Bottom */
2388 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2389 if (TTMaskHasType(&CIFSolidBits, TiGetTopType(tp)))
2390 {
2391 simple = FALSE;
2392 PUSHTILE(tp, BoxStack);
2393 }
2394
2395 /* Right */
2396 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2397 if (TTMaskHasType(&CIFSolidBits, TiGetLeftType(tp)))
2398 {
2399 simple = FALSE;
2400 PUSHTILE(tp, BoxStack);
2401 }
2402 }
2403
2404 if (op->co_client == (ClientData)1) /* external */
2405 {
2406 DBPaintPlane(cifPlane, &bbox, CIFPaintTable, (PaintUndoInfo *)NULL);
2407 CIFTileOps++;
2408 }
2409 else /* internal */
2410 {
2411 if (simple)
2412 {
2413 DBPaintPlane(cifPlane, &bbox, CIFPaintTable, (PaintUndoInfo *)NULL);
2414 CIFTileOps++;
2415 }
2416 else
2417 {
2418 maxr = FindMaxRectangle2(&bbox, tile, plane, NULL);
2419 DBPaintPlane(cifPlane, maxr, CIFPaintTable, (PaintUndoInfo *)NULL);
2420 CIFTileOps++;
2421 }
2422 }
2423
2424 /* Clear the tiles that were processed in this set */
2425
2426 tile->ti_client = (ClientData)CIF_IGNORE;
2427 STACKPUSH(tile, BoxStack);
2428 while (!StackEmpty(BoxStack))
2429 {
2430 t = (Tile *) STACKPOP(BoxStack);
2431
2432 /* Top */
2433 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2434 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2435 {
2436 tp->ti_client = (ClientData)CIF_IGNORE;
2437 STACKPUSH(tp, BoxStack);
2438 }
2439
2440 /* Left */
2441 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2442 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2443 {
2444 tp->ti_client = (ClientData)CIF_IGNORE;
2445 STACKPUSH(tp, BoxStack);
2446 }
2447
2448 /* Bottom */
2449 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2450 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2451 {
2452 tp->ti_client = (ClientData)CIF_IGNORE;
2453 STACKPUSH(tp, BoxStack);
2454 }
2455
2456 /* Right */
2457 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2458 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2459 {
2460 tp->ti_client = (ClientData)CIF_IGNORE;
2461 STACKPUSH(tp, BoxStack);
2462 }
2463 }
2464 }
2465 }
2466
2467 /*
2468 * ----------------------------------------------------------------------------
2469 *
2470 * cifSquaresFillArea --
2471 *
2472 * Fill areas in the current CIF output plane with contact cuts based on
2473 * the SQUARES operation passed in "op". This differs from the original
2474 * tile-based contact cut generation by collecting all connected tiles
2475 * in an area, and placing cuts relative to that area's bounding box.
2476 * A tile search is used to select the parts of any non-rectangular area
2477 * inside the bounding box that allow contact cuts, which lets cuts
2478 * be placed across tile boundaries and inside non-manhattan tiles.
2479 * It also allows contacts to be placed inside complex structures such
2480 * as (possibly intersecting) guardrings.
2481 *
2482 * Results:
2483 * None.
2484 *
2485 * Side effects:
2486 *
2487 * ----------------------------------------------------------------------------
2488 */
2489
2490 void
cifSquaresFillArea(op,cellDef,plane)2491 cifSquaresFillArea(op, cellDef, plane)
2492 CIFOp *op;
2493 CellDef *cellDef;
2494 Plane *plane;
2495 {
2496 Tile *tile, *t, *tp;
2497 Rect bbox, area, square, cut, llcut;
2498 int nAcross, nUp, left, pitch, size, diff, right;
2499 int i, j, k, savecount;
2500 TileType type;
2501 SquaresData *squares = (SquaresData *)op->co_client;
2502 StripsData stripsData;
2503 linkedStrip *stripList;
2504 bool simple;
2505 static Stack *CutStack = (Stack *)NULL;
2506
2507 pitch = squares->sq_size + squares->sq_sep;
2508 size = squares->sq_size + 2 * squares->sq_border;
2509 diff = squares->sq_sep - 2 * squares->sq_border;
2510
2511 if (CutStack == (Stack *)NULL)
2512 CutStack = StackNew(64);
2513
2514 /* Two-pass algorithm */
2515
2516 /* Search the plane for "strips", sections of contact that are only */
2517 /* wide enough for 1 cut. Process them separately, then erase the */
2518 /* processed areas. The purpose of this is to avoid applying the */
2519 /* contact matrix algorithm on non-convex spaces, such as guard */
2520 /* rings, where centering the matrix on the bounding box of the */
2521 /* contact area may produce a matrix misaligned with the contact */
2522 /* strips, preventing any contacts from being drawn! Due to the */
2523 /* maximum horizontal stripes rule for corner stitched tiles, we */
2524 /* need only identify vertical contact strips. After processing */
2525 /* and erasing them, all remaining areas will be convex. This */
2526 /* algorithm allows contacts to be drawn in any arbitrary geometry. */
2527
2528 stripsData.size = size;
2529 stripsData.pitch = pitch;
2530 stripsData.strips = NULL;
2531 DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2532 cifSquaresStripFunc, (ClientData)&stripsData);
2533
2534 /* Generate cuts in each strip found, then erase the strip */
2535
2536 stripList = stripsData.strips;
2537 while (stripList != NULL)
2538 {
2539 Rect stripLess = stripList->area;
2540
2541 if (diff > 0)
2542 {
2543 if (stripList->vertical)
2544 {
2545 if (stripList->shrink_ur) stripLess.r_ytop -= diff;
2546 if (stripList->shrink_ld) stripLess.r_ybot += diff;
2547 }
2548 else
2549 {
2550 if (stripList->shrink_ur) stripLess.r_xtop -= diff;
2551 if (stripList->shrink_ld) stripLess.r_xbot += diff;
2552 }
2553 }
2554
2555 /* Create the cuts */
2556
2557 if (op->co_opcode == CIFOP_SQUARES)
2558 cifSquareFunc(&stripLess, op, &nUp, &nAcross, &llcut);
2559 else if (op->co_opcode == CIFOP_SQUARES_G)
2560 cifSquareGridFunc(&stripLess, op, &nUp, &nAcross, &llcut);
2561
2562 cut.r_ybot = llcut.r_ybot;
2563 cut.r_ytop = llcut.r_ytop;
2564
2565 for (i = 0; i < nUp; i++)
2566 {
2567 cut.r_xbot = llcut.r_xbot;
2568 cut.r_xtop = llcut.r_xtop;
2569 for (j = 0; j < nAcross; j++)
2570 {
2571 DBPaintPlane(cifPlane, &cut, CIFPaintTable, (PaintUndoInfo *)NULL);
2572 cut.r_xbot += pitch;
2573 cut.r_xtop += pitch;
2574 }
2575 cut.r_ybot += pitch;
2576 cut.r_ytop += pitch;
2577 }
2578 if (nUp == 0)
2579 {
2580 if (stripList->shrink_ur == 0 && stripList->shrink_ld == 0)
2581 {
2582 /* The following code is backwardly-compatible with the */
2583 /* original behavior of allowing cuts that do not have */
2584 /* sufficient border. Here, we restrict that to contact */
2585 /* areas exactly matching the cut size. There should be */
2586 /* a flag to allow contacts to be generated this way. */
2587
2588 if ((stripList->area.r_xtop - stripList->area.r_xbot
2589 == squares->sq_size) && (stripList->area.r_ytop
2590 - stripList->area.r_ybot == squares->sq_size))
2591 {
2592 DBPaintPlane(cifPlane, &stripList->area, CIFPaintTable,
2593 (PaintUndoInfo *)NULL);
2594 CIFTileOps++;
2595 }
2596 else
2597 CIFError(&stripList->area, "no room for contact cuts in area!");
2598 }
2599
2600 /* Ad hoc rule catches problems due to contact areas of the proper */
2601 /* size not fitting cuts because the grid offset prohibits it. */
2602 else if (((stripList->area.r_ur.p_x - stripList->area.r_ll.p_x) *
2603 (stripList->area.r_ur.p_y - stripList->area.r_ll.p_y)) >
2604 2 * (pitch * pitch))
2605 CIFError(&stripList->area, "contact strip with no room for cuts!");
2606 }
2607
2608 DBPaintPlane(plane, &stripList->area, CIFEraseTable,
2609 (PaintUndoInfo *) NULL);
2610 freeMagic(stripList);
2611 stripList = stripList->strip_next;
2612 }
2613
2614 /* 2nd pass: Search the plane for unmarked tiles */
2615
2616 while (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2617 cifSquaresInitFunc, (ClientData)NULL) != 0)
2618 {
2619 /* Now, search for (nontrivially) connected tiles in all */
2620 /* directions. Mark the tiles, and record the bounding box. */
2621 /* (Largely copied from cifBloatAllFunc) */
2622
2623 simple = TRUE;
2624 tile = plane->pl_hint;
2625 TiToRect(tile, &bbox);
2626
2627 PUSHTILE(tile, CutStack);
2628 while (!StackEmpty(CutStack))
2629 {
2630 t = (Tile *) STACKPOP(CutStack);
2631 if (t->ti_client != (ClientData)CIF_PENDING) continue;
2632 t->ti_client = (ClientData)CIF_PROCESSED;
2633
2634 /* Adjust bounding box */
2635 TiToRect(t, &area);
2636 GeoInclude(&area, &bbox);
2637
2638 if (IsSplit(t)) simple = FALSE;
2639
2640 /* Top */
2641 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2642 if (TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2643 {
2644 simple = FALSE;
2645 PUSHTILE(tp, CutStack);
2646 }
2647
2648 /* Left */
2649 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2650 if (TTMaskHasType(&CIFSolidBits, TiGetRightType(tp)))
2651 {
2652 simple = FALSE;
2653 PUSHTILE(tp, CutStack);
2654 }
2655
2656 /* Bottom */
2657 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2658 if (TTMaskHasType(&CIFSolidBits, TiGetTopType(tp)))
2659 {
2660 simple = FALSE;
2661 PUSHTILE(tp, CutStack);
2662 }
2663
2664 /* Right */
2665 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2666 if (TTMaskHasType(&CIFSolidBits, TiGetLeftType(tp)))
2667 {
2668 simple = FALSE;
2669 PUSHTILE(tp, CutStack);
2670 }
2671 }
2672
2673 savecount = CIFTileOps;
2674
2675 for (k = 0; k < 3; k++) /* prepare for up to 3 passes */
2676 {
2677 /* Determine the contact cut offsets from the bounding box */
2678
2679 if (op->co_opcode == CIFOP_SQUARES)
2680 cifSquareFunc(&bbox, op, &nUp, &nAcross, &llcut);
2681 else if (op->co_opcode == CIFOP_SQUARES_G)
2682 cifSquareGridFunc(&bbox, op, &nUp, &nAcross, &llcut);
2683
2684 cut.r_ybot = llcut.r_ybot;
2685 cut.r_ytop = llcut.r_ytop;
2686
2687 /* For each contact cut area, check that there is */
2688 /* no whitespace */
2689
2690 for (i = 0; i < nUp; i++)
2691 {
2692 cut.r_xbot = llcut.r_xbot;
2693 cut.r_xtop = llcut.r_xtop;
2694
2695 square.r_ybot = cut.r_ybot - squares->sq_border;
2696 square.r_ytop = cut.r_ytop + squares->sq_border;
2697
2698 for (j = 0; j < nAcross; j++)
2699 {
2700 square.r_xbot = cut.r_xbot - squares->sq_border;
2701 square.r_xtop = cut.r_xtop + squares->sq_border;
2702
2703 /* If there is only one simple rectangle in the */
2704 /* area, the area is convex, so we don't have to */
2705 /* check for unconnected regions. */
2706
2707 if (simple || DBSrPaintArea((Tile *)tile, plane, &square,
2708 &DBAllTypeBits, cifUnconnectFunc,
2709 (ClientData)NULL) == 0)
2710 {
2711 DBPaintPlane(cifPlane, &cut, CIFPaintTable,
2712 (PaintUndoInfo *)NULL);
2713 CIFTileOps++;
2714 }
2715 cut.r_xbot += pitch;
2716 cut.r_xtop += pitch;
2717 }
2718 cut.r_ybot += pitch;
2719 cut.r_ytop += pitch;
2720 }
2721 if (savecount != CIFTileOps) break;
2722
2723 /* In non-Manhattan regions with beveled corners, where */
2724 /* the bounding box has space for 2 contacts, there may not */
2725 /* be space in the shape itself for more than one. We will */
2726 /* attempt to shrink X, Y, and/or both to fit (up to 3 */
2727 /* passes may be necessary). */
2728
2729 if (nUp == 2)
2730 {
2731 int bdiff = 1 + (bbox.r_ytop - bbox.r_ybot) -
2732 (2 * (squares->sq_size + squares->sq_border) +
2733 squares->sq_sep);
2734 if (bdiff & 0x1) bdiff++; /* bdiff must be even */
2735 bdiff >>= 1; /* take half */
2736 bbox.r_ytop -= bdiff;
2737 bbox.r_ybot += bdiff;
2738 }
2739 else if (nAcross == 2)
2740 {
2741 int bdiff = 1 + (bbox.r_xtop - bbox.r_xbot) -
2742 (2 * (squares->sq_size + squares->sq_border) +
2743 squares->sq_sep);
2744 if (bdiff & 0x1) bdiff++; /* bdiff must be even */
2745 bdiff >>= 1; /* take half */
2746 bbox.r_xtop -= bdiff;
2747 bbox.r_xbot += bdiff;
2748 }
2749 else
2750 break;
2751 }
2752 if (savecount == CIFTileOps)
2753 CIFError(&bbox, "no room for contacts in area!");
2754
2755 /* Clear the tiles that were processed */
2756
2757 tile->ti_client = (ClientData)CIF_IGNORE;
2758 STACKPUSH(tile, CutStack);
2759 while (!StackEmpty(CutStack))
2760 {
2761 t = (Tile *) STACKPOP(CutStack);
2762
2763 /* Top */
2764 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2765 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2766 {
2767 tp->ti_client = (ClientData)CIF_IGNORE;
2768 STACKPUSH(tp, CutStack);
2769 }
2770
2771 /* Left */
2772 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2773 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2774 {
2775 tp->ti_client = (ClientData)CIF_IGNORE;
2776 STACKPUSH(tp, CutStack);
2777 }
2778
2779 /* Bottom */
2780 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
2781 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2782 {
2783 tp->ti_client = (ClientData)CIF_IGNORE;
2784 STACKPUSH(tp, CutStack);
2785 }
2786
2787 /* Right */
2788 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
2789 if (tp->ti_client == (ClientData)CIF_PROCESSED)
2790 {
2791 tp->ti_client = (ClientData)CIF_IGNORE;
2792 STACKPUSH(tp, CutStack);
2793 }
2794 }
2795 }
2796
2797 /* Clear all the tiles that were processed */
2798 DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2799 cifProcessResetFunc, (ClientData)NULL);
2800 }
2801
2802 /*
2803 * ----------------------------------------------------------------------------
2804 *
2805 * cifSlotsFillArea --
2806 *
2807 * Fill areas in the current CIF output plane with contact cuts based on
2808 * the SLOTS operation passed in "op". This routine is like
2809 * cifSquaresFillArea but handles X and Y dimensions independently.
2810 *
2811 * Results:
2812 * None.
2813 *
2814 * Side effects:
2815 *
2816 * ----------------------------------------------------------------------------
2817 */
2818
2819 void
cifSlotsFillArea(op,cellDef,plane)2820 cifSlotsFillArea(op, cellDef, plane)
2821 CIFOp *op;
2822 CellDef *cellDef;
2823 Plane *plane;
2824 {
2825 Tile *tile, *t, *tp;
2826 Rect bbox, area, square, cut, llcut;
2827 int nAcross, nUp, left, spitch, lpitch, ssize, lsize, offset;
2828 int diff, right;
2829 int xpitch, ypitch, xborder, yborder, xdiff, ydiff;
2830 int i, j, k, savecount;
2831 TileType type;
2832 SlotsData *slots = (SlotsData *)op->co_client;
2833 StripsData stripsData;
2834 linkedStrip *stripList;
2835 bool simple, vertical;
2836 static Stack *CutStack = (Stack *)NULL;
2837
2838 spitch = slots->sl_ssize + slots->sl_ssep;
2839 lpitch = slots->sl_lsize + slots->sl_lsep;
2840 ssize = slots->sl_ssize + 2 * slots->sl_sborder;
2841 lsize = slots->sl_lsize + 2 * slots->sl_lborder;
2842
2843 /* This may not be good in all cases! Amount to shorten a strip */
2844 /* depends on the orientation of the cuts on either side of the */
2845 /* connected strip edge. . . */
2846 diff = slots->sl_lsep - slots->sl_lborder - slots->sl_sborder;
2847
2848 if (CutStack == (Stack *)NULL)
2849 CutStack = StackNew(64);
2850
2851 /* Two-pass algorithm */
2852
2853 /* Search the plane for "strips", sections of contact that are only */
2854 /* wide enough for 1 cut. Process them separately, then erase the */
2855 /* processed areas. The purpose of this is to avoid applying the */
2856 /* contact matrix algorithm on non-convex spaces, such as guard */
2857 /* rings, where centering the matrix on the bounding box of the */
2858 /* contact area may produce a matrix misaligned with the contact */
2859 /* strips, preventing any contacts from being drawn! Due to the */
2860 /* maximum horizontal stripes rule for corner stitched tiles, we */
2861 /* need only identify vertical contact strips. After processing */
2862 /* and erasing them, all remaining areas will be convex. This */
2863 /* algorithm allows contacts to be drawn in any arbitrary geometry. */
2864
2865 stripsData.size = ssize;
2866 stripsData.pitch = spitch;
2867 stripsData.strips = NULL;
2868 DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2869 cifSquaresStripFunc, (ClientData)&stripsData);
2870
2871 /* Generate cuts in each strip found, then erase the strip */
2872
2873 stripList = stripsData.strips;
2874 while (stripList != NULL)
2875 {
2876 Rect stripLess = stripList->area;
2877
2878 if (diff > 0)
2879 {
2880 if (stripList->vertical)
2881 {
2882 if (stripList->shrink_ur) stripLess.r_ytop -= diff;
2883 if (stripList->shrink_ld) stripLess.r_ybot += diff;
2884 }
2885 else
2886 {
2887 if (stripList->shrink_ur) stripLess.r_xtop -= diff;
2888 if (stripList->shrink_ld) stripLess.r_xbot += diff;
2889 }
2890 }
2891
2892 /* Create the cuts */
2893
2894 cifSlotFunc(&stripLess, op, &nUp, &nAcross, &llcut, stripList->vertical);
2895
2896 cut = llcut;
2897
2898 if (stripList->vertical)
2899 {
2900 for (i = 0; i < nUp; i++)
2901 {
2902 DBPaintPlane(cifPlane, &cut, CIFPaintTable, (PaintUndoInfo *)NULL);
2903 cut.r_ybot += lpitch;
2904 cut.r_ytop += lpitch;
2905 }
2906 }
2907 else
2908 {
2909 for (i = 0; i < nAcross; i++)
2910 {
2911 DBPaintPlane(cifPlane, &cut, CIFPaintTable, (PaintUndoInfo *)NULL);
2912 cut.r_xbot += lpitch;
2913 cut.r_xtop += lpitch;
2914 }
2915 }
2916
2917 if (nUp == 0 || nAcross == 0)
2918 {
2919 if (stripList->shrink_ur == 0 && stripList->shrink_ld == 0)
2920 {
2921 /* The following code is backwardly-compatible with the */
2922 /* original behavior of allowing cuts that do not have */
2923 /* sufficient border. Here, we restrict that to contact */
2924 /* areas exactly matching the cut size. There should be */
2925 /* a flag to allow contacts to be generated this way. */
2926
2927 if (((stripList->area.r_xtop - stripList->area.r_xbot
2928 == slots->sl_ssize) && (stripList->area.r_ytop
2929 - stripList->area.r_ybot == slots->sl_lsize)) ||
2930 ((stripList->area.r_xtop - stripList->area.r_xbot
2931 == slots->sl_lsize) && (stripList->area.r_ytop
2932 - stripList->area.r_ybot == slots->sl_ssize)))
2933 {
2934 DBPaintPlane(cifPlane, &stripList->area, CIFPaintTable,
2935 (PaintUndoInfo *)NULL);
2936 CIFTileOps++;
2937 }
2938 else
2939 CIFError(&stripList->area, "no room for contact cuts in area!");
2940 }
2941
2942 /* Ad hoc rule catches problems due to contact areas of the proper */
2943 /* size not fitting cuts because the grid offset prohibits it. */
2944 else if (((stripList->area.r_ur.p_x - stripList->area.r_ll.p_x) *
2945 (stripList->area.r_ur.p_y - stripList->area.r_ll.p_y)) >
2946 2 * (lpitch * spitch))
2947 CIFError(&stripList->area, "contact strip with no room for cuts!");
2948 }
2949
2950 DBPaintPlane(plane, &stripList->area, CIFEraseTable,
2951 (PaintUndoInfo *) NULL);
2952 freeMagic(stripList);
2953 stripList = stripList->strip_next;
2954 }
2955
2956 /* 2nd pass: Search the plane for unmarked tiles */
2957
2958 while (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
2959 cifSquaresInitFunc, (ClientData)NULL) != 0)
2960 {
2961 /* Now, search for (nontrivially) connected tiles in all */
2962 /* directions. Mark the tiles, and record the bounding box. */
2963 /* (Largely copied from cifBloatAllFunc) */
2964
2965 simple = TRUE;
2966 tile = plane->pl_hint;
2967 TiToRect(tile, &bbox);
2968
2969 PUSHTILE(tile, CutStack);
2970 while (!StackEmpty(CutStack))
2971 {
2972 t = (Tile *) STACKPOP(CutStack);
2973 if (t->ti_client != (ClientData)CIF_PENDING) continue;
2974 t->ti_client = (ClientData)CIF_PROCESSED;
2975
2976 /* Adjust bounding box */
2977 TiToRect(t, &area);
2978 GeoInclude(&area, &bbox);
2979
2980 if (IsSplit(t)) simple = FALSE;
2981
2982 /* Top */
2983 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
2984 if (TTMaskHasType(&CIFSolidBits, TiGetBottomType(tp)))
2985 {
2986 simple = FALSE;
2987 PUSHTILE(tp, CutStack);
2988 }
2989
2990 /* Left */
2991 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
2992 if (TTMaskHasType(&CIFSolidBits, TiGetRightType(tp)))
2993 {
2994 simple = FALSE;
2995 PUSHTILE(tp, CutStack);
2996 }
2997
2998 /* Bottom */
2999 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
3000 if (TTMaskHasType(&CIFSolidBits, TiGetTopType(tp)))
3001 {
3002 simple = FALSE;
3003 PUSHTILE(tp, CutStack);
3004 }
3005
3006 /* Right */
3007 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
3008 if (TTMaskHasType(&CIFSolidBits, TiGetLeftType(tp)))
3009 {
3010 simple = FALSE;
3011 PUSHTILE(tp, CutStack);
3012 }
3013 }
3014
3015 /* May want to attempt a second pass with the orthogonal alignment? */
3016 if ((bbox.r_xtop - bbox.r_xbot) > (bbox.r_ytop - bbox.r_ybot))
3017 vertical = FALSE;
3018 else
3019 vertical = TRUE;
3020
3021 if (vertical)
3022 {
3023 xpitch = spitch;
3024 ypitch = lpitch;
3025 xborder = slots->sl_sborder;
3026 yborder = slots->sl_lborder;
3027 xdiff = 2 * (slots->sl_ssize + slots->sl_sborder) + slots->sl_ssep;
3028 ydiff = 2 * (slots->sl_lsize + slots->sl_lborder) + slots->sl_lsep;
3029 }
3030 else
3031 {
3032 xpitch = lpitch;
3033 ypitch = spitch;
3034 xborder = slots->sl_lborder;
3035 yborder = slots->sl_sborder;
3036 xdiff = 2 * (slots->sl_lsize + slots->sl_lborder) + slots->sl_lsep;
3037 ydiff = 2 * (slots->sl_ssize + slots->sl_sborder) + slots->sl_ssep;
3038 }
3039
3040 savecount = CIFTileOps;
3041
3042 for (k = 0; k < 3; k++) /* prepare for up to 3 passes */
3043 {
3044 /* Determine the contact cut offsets from the bounding box */
3045
3046 cifSlotFunc(&bbox, op, &nUp, &nAcross, &llcut, vertical);
3047
3048 cut.r_ybot = llcut.r_ybot + slots->sl_start;
3049 cut.r_ytop = llcut.r_ytop + slots->sl_start;
3050
3051 /* For each contact cut area, check that there is */
3052 /* no whitespace */
3053
3054 offset = slots->sl_start;
3055 for (i = 0; i < nUp; i++)
3056 {
3057 cut.r_xbot = llcut.r_xbot + offset;
3058 cut.r_xtop = llcut.r_xtop + offset;
3059
3060 square.r_ybot = cut.r_ybot - yborder;
3061 square.r_ytop = cut.r_ytop + yborder;
3062
3063 for (j = 0; j < nAcross; j++)
3064 {
3065 square.r_xbot = cut.r_xbot - xborder;
3066 square.r_xtop = cut.r_xtop + xborder;
3067
3068 /* If there is only one simple rectangle in the */
3069 /* area, the area is convex, so we don't have to */
3070 /* check for unconnected regions. */
3071
3072 if (simple || DBSrPaintArea((Tile *)tile, plane, &square,
3073 &DBAllTypeBits, cifUnconnectFunc,
3074 (ClientData)NULL) == 0)
3075 {
3076 DBPaintPlane(cifPlane, &cut, CIFPaintTable,
3077 (PaintUndoInfo *)NULL);
3078 CIFTileOps++;
3079 }
3080 cut.r_xbot += xpitch;
3081 cut.r_xtop += xpitch;
3082 }
3083 cut.r_ybot += ypitch;
3084 cut.r_ytop += ypitch;
3085 offset += slots->sl_offset;
3086 if (offset >= xpitch) offset -= xpitch;
3087 }
3088 if (savecount != CIFTileOps) break;
3089
3090 /* In non-Manhattan regions with beveled corners, where */
3091 /* the bounding box has space for 2 contacts, there may not */
3092 /* be space in the shape itself for more than one. We will */
3093 /* attempt to shrink X, Y, and/or both to fit (up to 3 */
3094 /* passes may be necessary). */
3095
3096 if (nUp == 2)
3097 {
3098 int bdiff = 1 + (bbox.r_ytop - bbox.r_ybot) - ydiff;
3099 if (bdiff & 0x1) bdiff++; /* bdiff must be even */
3100 bdiff >>= 1; /* take half */
3101 bbox.r_ytop -= bdiff;
3102 bbox.r_ybot += bdiff;
3103 }
3104 else if (nAcross == 2)
3105 {
3106 int bdiff = 1 + (bbox.r_xtop - bbox.r_xbot) - xdiff;
3107 if (bdiff & 0x1) bdiff++; /* bdiff must be even */
3108 bdiff >>= 1; /* take half */
3109 bbox.r_xtop -= bdiff;
3110 bbox.r_xbot += bdiff;
3111 }
3112 else
3113 break;
3114 }
3115 if (savecount == CIFTileOps)
3116 CIFError(&bbox, "no room for contacts in area!");
3117
3118 /* Clear the tiles that were processed */
3119
3120 tile->ti_client = (ClientData)CIF_IGNORE;
3121 STACKPUSH(tile, CutStack);
3122 while (!StackEmpty(CutStack))
3123 {
3124 t = (Tile *) STACKPOP(CutStack);
3125
3126 /* Top */
3127 for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
3128 if (tp->ti_client == (ClientData)CIF_PROCESSED)
3129 {
3130 tp->ti_client = (ClientData)CIF_IGNORE;
3131 STACKPUSH(tp, CutStack);
3132 }
3133
3134 /* Left */
3135 for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
3136 if (tp->ti_client == (ClientData)CIF_PROCESSED)
3137 {
3138 tp->ti_client = (ClientData)CIF_IGNORE;
3139 STACKPUSH(tp, CutStack);
3140 }
3141
3142 /* Bottom */
3143 for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
3144 if (tp->ti_client == (ClientData)CIF_PROCESSED)
3145 {
3146 tp->ti_client = (ClientData)CIF_IGNORE;
3147 STACKPUSH(tp, CutStack);
3148 }
3149
3150 /* Right */
3151 for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
3152 if (tp->ti_client == (ClientData)CIF_PROCESSED)
3153 {
3154 tp->ti_client = (ClientData)CIF_IGNORE;
3155 STACKPUSH(tp, CutStack);
3156 }
3157 }
3158 }
3159
3160 /* Clear all the tiles that were processed */
3161 DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
3162 cifProcessResetFunc, (ClientData)NULL);
3163 }
3164
3165 /*
3166 * ----------------------------------------------------------------------------
3167 *
3168 * cifBloatMaxFunc --
3169 *
3170 * Called once for each tile to be selectively bloated or
3171 * shrunk using the CIFOP_BLOATMAX or CIFOP_BLOATMIN operation.
3172 *
3173 * Results:
3174 * Always returns 0 to keep the search alive.
3175 *
3176 * Side effects:
3177 * Uses the bloat table in the current CIFOp to expand or shrink
3178 * the tile, depending on which tiles it abuts. The rectangular
3179 * area of the tile is modified by moving each side in or out
3180 * by the maximum bloat distance for any of its neighbors on
3181 * that side. The result is a new rectangle, which is OR'ed
3182 * into the result plane. Note: any edge between two tiles of
3183 * same type is given a zero bloat factor.
3184 *
3185 * ----------------------------------------------------------------------------
3186 */
3187
3188 int
cifBloatMaxFunc(tile,op)3189 cifBloatMaxFunc(tile, op)
3190 Tile *tile; /* The tile to be processed. */
3191 CIFOp *op; /* Describes the operation to be performed
3192 * (all we care about is the opcode and
3193 * bloat table).
3194 */
3195 {
3196 Rect area;
3197 int bloat, tmp;
3198 Tile *t;
3199 TileType type, otherType;
3200 BloatData *bloats = (BloatData *)op->co_client;
3201
3202 /* Get the tile into CIF coordinates. */
3203
3204 type = TiGetType(tile);
3205 TiToRect(tile, &area);
3206 area.r_xbot *= cifScale;
3207 area.r_ybot *= cifScale;
3208 area.r_xtop *= cifScale;
3209 area.r_ytop *= cifScale;
3210
3211 /* See how much to adjust the left side of the tile. */
3212
3213 if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3214 else bloat = 10000000;
3215 for (t = BL(tile); BOTTOM(t) < TOP(tile); t = RT(t))
3216 {
3217 otherType = TiGetType(t);
3218 if (otherType == type) continue;
3219 tmp = bloats->bl_distance[otherType];
3220 if (op->co_opcode == CIFOP_BLOATMAX)
3221 {
3222 if (tmp > bloat) bloat = tmp;
3223 }
3224 else if (tmp < bloat) bloat = tmp;
3225 }
3226 if ((bloat < 10000000) && (bloat > -10000000))
3227 area.r_xbot -= bloat;
3228
3229 /* Now figure out how much to adjust the top side of the tile. */
3230
3231 if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3232 else bloat = 10000000;
3233 for (t = RT(tile); RIGHT(t) > LEFT(tile); t = BL(t))
3234 {
3235 otherType = TiGetType(t);
3236 if (otherType == type) continue;
3237 tmp = bloats->bl_distance[otherType];
3238 if (op->co_opcode == CIFOP_BLOATMAX)
3239 {
3240 if (tmp > bloat) bloat = tmp;
3241 }
3242 else if (tmp < bloat) bloat = tmp;
3243 }
3244 if ((bloat < 10000000) && (bloat > -10000000))
3245 area.r_ytop += bloat;
3246
3247 /* Now the right side. */
3248
3249 if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3250 else bloat = 10000000;
3251 for (t = TR(tile); TOP(t) > BOTTOM(tile); t = LB(t))
3252 {
3253 otherType = TiGetType(t);
3254 if (otherType == type) continue;
3255 tmp = bloats->bl_distance[otherType];
3256 if (op->co_opcode == CIFOP_BLOATMAX)
3257 {
3258 if (tmp > bloat) bloat = tmp;
3259 }
3260 else if (tmp < bloat) bloat = tmp;
3261 }
3262 if ((bloat < 10000000) && (bloat > -10000000))
3263 area.r_xtop += bloat;
3264
3265 /* Lastly, do the bottom side. */
3266
3267 if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000;
3268 else bloat = 10000000;
3269 for (t = LB(tile); LEFT(t) < RIGHT(tile); t = TR(t))
3270 {
3271 otherType = TiGetType(t);
3272 if (otherType == type) continue;
3273 tmp = bloats->bl_distance[otherType];
3274 if (op->co_opcode == CIFOP_BLOATMAX)
3275 {
3276 if (tmp > bloat) bloat = tmp;
3277 }
3278 else if (tmp < bloat) bloat = tmp;
3279 }
3280 if ((bloat < 10000000) && (bloat > -10000000))
3281 area.r_ybot -= bloat;
3282
3283 /* Make sure the tile didn't shrink into negativity. If it's
3284 * ok, paint it into the new plane being built.
3285 */
3286
3287 if ((area.r_xbot > area.r_xtop) || (area.r_ybot > area.r_ytop))
3288 {
3289 TiToRect(tile, &area);
3290 area.r_xbot *= cifScale;
3291 area.r_xtop *= cifScale;
3292 area.r_ybot *= cifScale;
3293 area.r_ytop *= cifScale;
3294 CIFError(&area, "tile inverted by shrink");
3295 }
3296 else
3297 DBNMPaintPlane(cifPlane, TiGetTypeExact(tile), &area,
3298 CIFPaintTable, (PaintUndoInfo *) NULL);
3299
3300 CIFTileOps += 1;
3301 return 0;
3302 }
3303
3304 /*
3305 * ----------------------------------------------------------------------------
3306 *
3307 * inside_triangle --
3308 *
3309 * Test if the specified rectangle is completely inside the tile.
3310 * Tile is presumed to be a split tile.
3311 *
3312 * Results:
3313 * TRUE if inside, FALSE if outside or overlapping.
3314 *
3315 * Side Effects:
3316 * None.
3317 *
3318 * Notes:
3319 * This is an optimized version of the code in DBtiles.c. It
3320 * assumes that the square is never infinite.
3321 *
3322 * ----------------------------------------------------------------------------
3323 */
3324
3325 bool
inside_triangle(rect,tile)3326 inside_triangle(rect, tile)
3327 Rect *rect;
3328 Tile *tile;
3329 {
3330 int theight, twidth;
3331 dlong f1, f2, f3, f4;
3332
3333 theight = TOP(tile) - BOTTOM(tile);
3334 twidth = RIGHT(tile) - LEFT(tile);
3335
3336 f1 = (dlong)(TOP(tile) - rect->r_ybot) * twidth;
3337 f2 = (dlong)(rect->r_ytop - BOTTOM(tile)) * twidth;
3338
3339 if (SplitLeftType(tile) != TT_SPACE)
3340 {
3341 /* Inside-of-triangle check */
3342 f4 = (dlong)(rect->r_xbot - LEFT(tile)) * theight;
3343 if (SplitDirection(tile) ? (f1 > f4) : (f2 > f4))
3344 return TRUE;
3345 }
3346 else
3347 {
3348 /* Inside-of-triangle check */
3349 f3 = (dlong)(RIGHT(tile) - rect->r_xtop) * theight;
3350 if (SplitDirection(tile) ? (f2 > f3) : (f1 > f3))
3351 return TRUE;
3352 }
3353 return FALSE;
3354 }
3355
3356 /*
3357 * ----------------------------------------------------------------------------
3358 *
3359 * cifContactFunc --
3360 *
3361 * Called for each relevant tile when chopping up contacts into
3362 * square cuts using the procedure of using a pre-defined cell
3363 * definition of a single contact and arraying the cell.
3364 * Technically, this is not a CIF function because CIF does not
3365 * have an array method for cells, so there is no advantage to
3366 * drawing lots of subcells in place of drawing lots of boxes.
3367 * In GDS, however, the array method is much more compact than
3368 * drawing individual cuts when the array size is larger than 1.
3369 *
3370 * Results:
3371 * Normally returns 0 to keep the search going. Return 1 if
3372 * the contact type cannot be found, which halts the search.
3373 *
3374 * Side effects:
3375 * Stuff is painted into cifPlane.
3376 *
3377 * ----------------------------------------------------------------------------
3378 */
3379
3380 int
cifContactFunc(tile,csi)3381 cifContactFunc(tile, csi)
3382 Tile *tile; /* Tile to be diced up. */
3383 CIFSquaresInfo *csi; /* Describes how to generate squares. */
3384 {
3385 Rect area;
3386 int i, nAcross, j, nUp, left, bottom, pitch, halfsize;
3387 bool result;
3388 SquaresData *squares = csi->csi_squares;
3389
3390 /* For now, don't allow squares on non-manhattan tiles */
3391 if (IsSplit(tile))
3392 return 0;
3393
3394 TiToRect(tile, &area);
3395 pitch = squares->sq_size + squares->sq_sep;
3396
3397 nAcross = (area.r_xtop - area.r_xbot + squares->sq_sep
3398 - (2 * squares->sq_border)) / pitch;
3399 if (nAcross == 0)
3400 {
3401 left = (area.r_xbot + area.r_xtop - squares->sq_size) / 2;
3402 if (left >= area.r_xbot) nAcross = 1;
3403 }
3404 else
3405 left = (area.r_xbot + area.r_xtop + squares->sq_sep
3406 - (nAcross * pitch)) / 2;
3407
3408 nUp = (area.r_ytop - area.r_ybot + squares->sq_sep
3409 - (2 * squares->sq_border)) / pitch;
3410 if (nUp == 0)
3411 {
3412 bottom = (area.r_ybot + area.r_ytop - squares->sq_size) / 2;
3413 if (bottom >= area.r_ybot) nUp = 1;
3414 }
3415 else
3416 bottom = (area.r_ybot + area.r_ytop + squares->sq_sep
3417 - (nUp * pitch)) / 2;
3418
3419 /* Lower-left coordinate should be centered on the contact cut, as
3420 * contact definitions are centered on the origin.
3421 */
3422 halfsize = (squares->sq_size / 2);
3423 left += halfsize;
3424 bottom += halfsize;
3425
3426 result = CalmaGenerateArray((FILE *)csi->csi_client, csi->csi_type,
3427 left, bottom, pitch, nAcross, nUp);
3428
3429 return (result == TRUE) ? 0 : 1;
3430 }
3431
3432 /*
3433 * ----------------------------------------------------------------------------
3434 *
3435 * cifSlotFunc --
3436 *
3437 * Called for each relevant tile area when chopping areas up into
3438 * slots (rectangles). Determines how to divide up the area into
3439 * slots, and generates the number of rows, columns, and the lower-
3440 * left-most cut rectangle.
3441 *
3442 * Results:
3443 * Always return 0
3444 *
3445 * Side effects:
3446 * Pointers "rows", "columns", and "cut" are filled with
3447 * appropriate values.
3448 *
3449 * ----------------------------------------------------------------------------
3450 */
3451
3452 int
cifSlotFunc(area,op,numY,numX,cut,vertical)3453 cifSlotFunc(area, op, numY, numX, cut, vertical)
3454 Rect *area; /* Area to be diced up */
3455 CIFOp *op; /* Describes how to generate squares. */
3456 int *numY, *numX; /* Return values: # rows and # columns */
3457 Rect *cut; /* initial (lower left) cut area */
3458 bool vertical; /* if TRUE, slot is aligned vertically */
3459 {
3460 int i, j, xpitch, ypitch, delta, limit;
3461 int *axtop, *axbot, *aytop, *aybot;
3462 int *sxtop, *sxbot, *sytop, *sybot;
3463 int *rows, *columns;
3464 SlotsData *slots = (SlotsData *)op->co_client;
3465
3466 /* Orient to the short/long orientation of the tile */
3467
3468 /* Assume a vertical tile; if not, reorient area and remember */
3469 if (vertical)
3470 {
3471 axbot = &area->r_xbot;
3472 aybot = &area->r_ybot;
3473 axtop = &area->r_xtop;
3474 aytop = &area->r_ytop;
3475 sxbot = &cut->r_xbot;
3476 sybot = &cut->r_ybot;
3477 sxtop = &cut->r_xtop;
3478 sytop = &cut->r_ytop;
3479 rows = numY;
3480 columns = numX;
3481 }
3482 else
3483 {
3484 axbot = &area->r_ybot;
3485 aybot = &area->r_xbot;
3486 axtop = &area->r_ytop;
3487 aytop = &area->r_xtop;
3488 sxbot = &cut->r_ybot;
3489 sybot = &cut->r_xbot;
3490 sxtop = &cut->r_ytop;
3491 sytop = &cut->r_xtop;
3492 rows = numX;
3493 columns = numY;
3494 }
3495
3496 xpitch = slots->sl_ssize + slots->sl_ssep;
3497
3498 calcX:
3499 *columns = (*axtop - *axbot + slots->sl_ssep - (2 * slots->sl_sborder)) / xpitch;
3500 if (*columns == 0)
3501 {
3502 *rows = 0;
3503 return 0;
3504 // *sxbot = (*axbot + *axtop - slots->sl_ssize) / 2;
3505 // if (*sxbot >= *axbot) *columns = 1;
3506 }
3507 else
3508 *sxbot = (*axbot + *axtop + slots->sl_ssep - (*columns * xpitch)) / 2;
3509 *sxtop = *sxbot + slots->sl_ssize;
3510
3511 /* Check that we are not violating any gridlimit */
3512
3513 limit = CIFCurStyle->cs_gridLimit;
3514
3515 if (CIFCurStyle && (limit > 1))
3516 {
3517 delta = abs(*sxbot) % limit;
3518 if (delta > 0)
3519 {
3520 if (*sxbot >= 0)
3521 *axtop -= 2 * delta;
3522 else
3523 *axtop += 2 * delta;
3524 goto calcX;
3525 }
3526 }
3527
3528 if (slots->sl_lsize > 0)
3529 {
3530 ypitch = slots->sl_lsize + slots->sl_lsep;
3531 calcY:
3532 *rows = (*aytop - *aybot + slots->sl_lsep - (2 * slots->sl_lborder)) / ypitch;
3533 if (*rows == 0)
3534 {
3535 return 0;
3536 // *sybot = (*aybot + *aytop - slots->sl_lsize) / 2;
3537 // if (*sybot >= *aybot) *rows = 1;
3538 }
3539 else
3540 *sybot = (*aybot + *aytop + slots->sl_lsep - (*rows * ypitch)) / 2;
3541 *sytop = *sybot + slots->sl_lsize;
3542
3543 /* Check that we are not violating any gridlimit */
3544
3545 if (CIFCurStyle && (limit > 1))
3546 {
3547 delta = abs(*sybot) % limit;
3548 if (delta > 0)
3549 {
3550 if (*sybot >= 0)
3551 *aytop -= 2 * delta;
3552 else
3553 *aytop += 2 * delta;
3554 goto calcY;
3555 }
3556 }
3557 }
3558 else
3559 {
3560 *rows = 1;
3561 *sybot = *aybot + slots->sl_lborder;
3562 *sytop = *aytop - slots->sl_lborder;
3563 /* There's no space to fit a slot */
3564 if (*sytop - *sybot <= 0)
3565 return 0;
3566 }
3567
3568 /* To be done---slot offsets */
3569
3570 return 0;
3571 }
3572
3573 /*
3574 * ----------------------------------------------------------------------------
3575 *
3576 * cifSquareFunc --
3577 *
3578 * Called for each relevant rectangle when chopping areas up into
3579 * squares. Determines the number of rows and columns in the area
3580 * and returns these and the area of the lower-left cut.
3581 *
3582 * Results:
3583 * Always return 0
3584 *
3585 * Side effects:
3586 * Results filled in the pointer positions passed to the function
3587 *
3588 * ----------------------------------------------------------------------------
3589 */
3590
3591 int
cifSquareFunc(area,op,rows,columns,cut)3592 cifSquareFunc(area, op, rows, columns, cut)
3593 Rect *area; /* Area to be diced up */
3594 CIFOp *op; /* Describes how to generate squares. */
3595 int *rows, *columns; /* Return values: # rows and # columns, */
3596 Rect *cut; /* initial (lower left) cut area. */
3597 {
3598 int pitch, delta, limit;
3599 bool glimit;
3600 SquaresData *squares = (SquaresData *)op->co_client;
3601
3602 limit = CIFCurStyle->cs_gridLimit;
3603
3604 glimit = (CIFCurStyle && (limit > 1)) ? TRUE : FALSE;
3605 pitch = squares->sq_size + squares->sq_sep;
3606
3607 /* Compute the real border to leave around the sides. If only
3608 * one square will fit in a particular direction, center it
3609 * regardless of the requested border size. If more than one
3610 * square will fit, then fit it in extras only if at least the
3611 * requested border size can be left. Also center things in the
3612 * rectangle, so that the box's exact size doesn't matter. This
3613 * trickiness is done so that coincident contacts from overlapping
3614 * cells always have their squares line up, regardless of the
3615 * orientation of the cells.
3616 *
3617 * Update 1/13/09: Removed the "feature" that allows contact
3618 * cuts that violate the border requirement. The "slots" rule
3619 * can be used if necessary to generate cuts with different
3620 * border allowances.
3621 */
3622
3623 sqX:
3624 *columns = (area->r_xtop - area->r_xbot + squares->sq_sep
3625 - (2 * squares->sq_border)) / pitch;
3626 if (*columns == 0)
3627 {
3628 *rows = 0;
3629 return 0;
3630
3631 // cut->r_xbot = (area->r_xbot + area->r_xtop - squares->sq_size) / 2;
3632 // if (cut->r_xbot >= area->r_xbot) *columns = 1;
3633 }
3634 else
3635 {
3636 cut->r_xbot = (area->r_xbot + area->r_xtop + squares->sq_sep
3637 - (*columns * pitch)) / 2;
3638 }
3639
3640 /* Check for any gridlimit violation */
3641
3642 if (glimit)
3643 {
3644 delta = abs(cut->r_xbot) % limit;
3645 if (delta > 0)
3646 {
3647 area->r_xtop -= 2 * delta;
3648 goto sqX;
3649 }
3650 }
3651
3652 sqY:
3653 *rows = (area->r_ytop - area->r_ybot + squares->sq_sep
3654 - (2 * squares->sq_border)) / pitch;
3655 if (*rows == 0)
3656 {
3657 return 0;
3658
3659 // cut->r_ybot = (area->r_ybot + area->r_ytop - squares->sq_size) / 2;
3660 // if (cut->r_ybot >= area->r_ybot) *rows = 1;
3661 }
3662 else
3663 {
3664 cut->r_ybot = (area->r_ybot + area->r_ytop + squares->sq_sep
3665 - (*rows * pitch)) / 2;
3666 }
3667
3668 /* Check for any gridlimit violation */
3669
3670 if (glimit)
3671 {
3672 delta = abs(cut->r_ybot) % limit;
3673 if (delta > 0)
3674 {
3675 area->r_ytop -= 2 * delta;
3676 goto sqY;
3677 }
3678 }
3679
3680 cut->r_xtop = cut->r_xbot + squares->sq_size;
3681 cut->r_ytop = cut->r_ybot + squares->sq_size;
3682 return 0;
3683 }
3684
3685 /*
3686 * ----------------------------------------------------------------------------
3687 *
3688 * cifSquareGridFunc --
3689 *
3690 * Called for each relevant rectangle when chopping areas up into
3691 * squares. Determines the number of rows and columns in the area
3692 * and returns these and the area of the lower-left cut.
3693 *
3694 * Results:
3695 * Always return 0
3696 *
3697 * Side effects:
3698 * Results filled in the pointer positions passed to the function
3699 *
3700 * ----------------------------------------------------------------------------
3701 */
3702
3703 int
cifSquareGridFunc(area,op,rows,columns,cut)3704 cifSquareGridFunc(area, op, rows, columns, cut)
3705 Rect *area; /* Area to be diced up */
3706 CIFOp *op; /* Describes how to generate squares. */
3707 int *rows, *columns; /* Return values: # rows and # columns, */
3708 Rect *cut; /* initial (lower left) cut area. */
3709 {
3710 Rect locarea;
3711 int left, bottom, right, top, pitch;
3712 int gridx, gridy, margin;
3713 SquaresData *squares = (SquaresData *)op->co_client;
3714
3715 /*
3716 * It may be necessary to generate contacts on a specific grid; e.g.,
3717 * to avoid placing contacts at half-lambda. If this is the case,
3718 * then the DRC section of the techfile should specify "no overlap"
3719 * for these types.
3720 *
3721 * This routine has been simplified. It flags a warning when there
3722 * is not enough space for a contact cut, rather than attempting to
3723 * draw a cut without enough border area. The routine has also been
3724 * extended to allow different x and y grids to be specified. This
3725 * allows certain tricks, such as generating offset contact grids on
3726 * a pad, as required by some processes.
3727 */
3728
3729 pitch = squares->sq_size + squares->sq_sep;
3730 gridx = squares->sq_gridx;
3731 gridy = squares->sq_gridy;
3732
3733 locarea.r_xtop = area->r_xtop - squares->sq_border;
3734 locarea.r_ytop = area->r_ytop - squares->sq_border;
3735 locarea.r_xbot = area->r_xbot + squares->sq_border;
3736 locarea.r_ybot = area->r_ybot + squares->sq_border;
3737
3738 left = locarea.r_xbot / gridx;
3739 left *= gridx;
3740 if (left < locarea.r_xbot) left += gridx;
3741
3742 bottom = locarea.r_ybot / gridy;
3743 bottom *= gridy;
3744 if (bottom < locarea.r_ybot) bottom += gridy;
3745
3746 *columns = (locarea.r_xtop - left + squares->sq_sep) / pitch;
3747 if (*columns == 0)
3748 {
3749 *rows = 0;
3750 return 0;
3751 }
3752
3753 *rows = (locarea.r_ytop - bottom + squares->sq_sep) / pitch;
3754 if (*rows == 0) return 0;
3755
3756 /* Center the contacts while remaining on-grid */
3757 right = left + *columns * squares->sq_size + (*columns - 1) * squares->sq_sep;
3758 top = bottom + *rows * squares->sq_size + (*rows - 1) * squares->sq_sep;
3759 margin = ((locarea.r_xtop - right) - (left - locarea.r_xbot)) / (gridx * 2);
3760 locarea.r_xbot = left + margin * gridx;
3761 margin = ((locarea.r_ytop - top) - (bottom - locarea.r_ybot)) / (gridy * 2);
3762 locarea.r_ybot = bottom + margin * gridy;
3763
3764 cut->r_ybot = locarea.r_ybot;
3765 cut->r_ytop = cut->r_ybot + squares->sq_size;
3766 cut->r_xbot = locarea.r_xbot;
3767 cut->r_xtop = cut->r_xbot + squares->sq_size;
3768 return 0;
3769 }
3770
3771
3772 /*
3773 * ----------------------------------------------------------------------------
3774 *
3775 * cifSrTiles --
3776 *
3777 * This is a utility procedure that just calls DBSrPaintArea
3778 * one or more times for the planes being used in processing
3779 * one CIFOp.
3780 *
3781 * Results:
3782 * None.
3783 *
3784 * Side effects:
3785 * This procedure itself has no side effects. For each of the
3786 * paint or temporary planes indicated in cifOp, we call
3787 * DBSrPaintArea to find the desired tiles in the desired
3788 * area for the operation. DBSrPaintArea is given func as a
3789 * search function, and cdArg as ClientData.
3790 *
3791 * ----------------------------------------------------------------------------
3792 */
3793
3794 void
cifSrTiles(cifOp,area,cellDef,temps,func,cdArg)3795 cifSrTiles(cifOp, area, cellDef, temps, func, cdArg)
3796 CIFOp *cifOp; /* Geometric operation being processed. */
3797 Rect *area; /* Area of Magic paint to consider. */
3798 CellDef *cellDef; /* CellDef to search for paint. */
3799 Plane *temps[]; /* Planes to use for temporaries. */
3800 int (*func)(); /* Search function to pass to DBSrPaintArea. */
3801 ClientData cdArg; /* Client data for func. */
3802 {
3803 TileTypeBitMask maskBits;
3804 TileType t;
3805 Tile *tp;
3806 int i;
3807 BloatData *bloats;
3808
3809 /* When reading data from a cell, it must first be scaled to
3810 * CIF units. Check for CIFCurStyle, as we don't want to
3811 * crash while reading CIF/GDS just becuase the techfile
3812 * "cifoutput" section was blank.
3813 */
3814
3815 cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
3816
3817 /* Bloat operations (except bloat-all) have to be in a single plane */
3818
3819 switch (cifOp->co_opcode) {
3820 case CIFOP_BLOAT:
3821 case CIFOP_BLOATMIN:
3822 case CIFOP_BLOATMAX:
3823 bloats = (BloatData *)cifOp->co_client;
3824 i = bloats->bl_plane;
3825 maskBits = DBPlaneTypes[i];
3826 TTMaskAndMask(&maskBits, &cifOp->co_paintMask);
3827 if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
3828 DBSrPaintArea((Tile *) NULL, cellDef->cd_planes[i],
3829 area, &cifOp->co_paintMask, func, cdArg);
3830 break;
3831
3832 default:
3833 for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
3834 {
3835 maskBits = DBPlaneTypes[i];
3836 TTMaskAndMask(&maskBits, &cifOp->co_paintMask);
3837 if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
3838 (void) DBSrPaintArea((Tile *) NULL, cellDef->cd_planes[i],
3839 area, &cifOp->co_paintMask, func, cdArg);
3840 }
3841 break;
3842 }
3843
3844 /* When processing CIF data, use everything in the plane. */
3845
3846 cifScale = 1;
3847 for (t = 0; t < TT_MAXTYPES; t++, temps++)
3848 if (TTMaskHasType(&cifOp->co_cifMask, t))
3849 (void) DBSrPaintArea((Tile *) NULL, *temps, &TiPlaneRect,
3850 &CIFSolidBits, func, (ClientData) cdArg);
3851 }
3852
3853 /* Data structure to pass plane and minimum width to the callback function */
3854 typedef struct _bridgeLimStruct {
3855 Plane *plane;
3856 BridgeData *bridge;
3857 CellDef *def;
3858 Plane **temps;
3859 TileTypeBitMask co_paintMask;/* Zero or more paint layers to consider. */
3860 TileTypeBitMask co_cifMask; /* Zero or more other CIF layers. */
3861 } BridgeLimStruct;
3862
3863 static int xOverlap, yOverlap;
3864
3865 /* Bridge-lim Check data structure */
3866 typedef struct _bridgeLimCheckStruct {
3867 Tile *tile; /* Tile that triggered search (ignore this tile) */
3868 int direction; /* What outside corner to look for */
3869 Tile *violator; /* Return the violator tile in this space */
3870 TileType checktype; /* Type to check for, either TT_SPACE or CIF_SOLIDTYPE */
3871 long sqdistance; /* Square of the minimum distance */
3872 } BridgeLimCheckStruct;
3873 /*
3874 *-----------------------------------------------------------------------
3875 * Callback function for bridgeLimSrTiles used when a limiting layer tile
3876 * was found in the specified area. If calcOverlap is TRUE then the xOverlap
3877 * and yOverlap are updated and return 0 to continue searching. Otherwise
3878 * return 1 to stop the search.
3879 *-----------------------------------------------------------------------
3880 */
3881 int
bridgeLimFound(tile,calcOverlap)3882 bridgeLimFound(tile, calcOverlap)
3883 Tile *tile;
3884 bool calcOverlap;
3885 {
3886 if (calcOverlap)
3887 {
3888 if (RIGHT(tile) > xOverlap)
3889 xOverlap = RIGHT(tile);
3890 if (TOP(tile) > yOverlap)
3891 yOverlap = TOP(tile);
3892 return 0; // continue searching
3893 } else
3894 return 1; // tile found, stop the search
3895 }
3896
3897 /*
3898 *------------------------------------------------------------------------
3899 * Callback function used in bridge-lim operations to find if the specified
3900 * area contains tiles of the limiting layers.
3901 *------------------------------------------------------------------------
3902 */
3903 int
bridgeLimSrTiles(brlims,area,calcOverlap)3904 bridgeLimSrTiles(brlims, area, calcOverlap)
3905 BridgeLimStruct *brlims; /* Bridge-Lim structure. */
3906 Rect *area; /* Area of Magic paint to consider. */
3907 bool calcOverlap; /* TRUE to calculate the overlap of the limiting tiles in the specified area. */
3908 {
3909 TileTypeBitMask maskBits;
3910 TileType t;
3911 int i;
3912 Plane **temps = brlims->temps;
3913 xOverlap = area->r_xbot;
3914 yOverlap = area->r_ybot;
3915
3916 for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
3917 {
3918 maskBits = DBPlaneTypes[i];
3919 TTMaskAndMask(&maskBits, &brlims->co_paintMask);
3920 if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
3921 if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, bridgeLimFound, calcOverlap))
3922 return 0;
3923 }
3924
3925 for (t = 0; t < TT_MAXTYPES; t++, temps++)
3926 if (TTMaskHasType(&brlims->co_cifMask, t))
3927 if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, bridgeLimFound, calcOverlap))
3928 return 0;
3929
3930 if (( xOverlap != area->r_xbot) || (yOverlap != area->r_ybot))
3931 return 0; //Constraint tile found
3932 else
3933 return 1; //Nothing found
3934 }
3935
3936 /*
3937 * ----------------------------------------------------------------------------
3938 *
3939 * cifBridgeLimFunc0 --
3940 *
3941 * Called for each relevant tile during bridge-lim operations. The
3942 * bridge-lim operation is similar to the bridge operation with the
3943 * difference that the material created to meet the minimum spacing/width
3944 * rules do not overlap the limiting layers.
3945 *
3946 * Results:
3947 * Always returns 0 to keep the search alive.
3948 *
3949 * Side effects:
3950 * May paint into cifNewPlane
3951 *
3952 * Algorithm (based on maximum horizontal stripes rule):
3953 * This function grows dimentions of tiles to meet a minimimum width rule (only
3954 * applies to vertical or horizontal directions). This is done in two steps:
3955 * 1. Adjust tile width to accomplish the minimimum width rule, limited by
3956 * the constraint layers.
3957 * 2. Search top and bottom tiles of same type, for each segment verify if
3958 * height meets the minimimum value, if not, adjust the segment height
3959 * but do not paint over limiting layer tiles.
3960 * ----------------------------------------------------------------------------
3961 */
3962 int
cifBridgeLimFunc0(tile,brlims)3963 cifBridgeLimFunc0(tile, brlims)
3964 Tile *tile;
3965 BridgeLimStruct *brlims;
3966 {
3967 Plane *plane = brlims->plane;
3968 Rect area, parea;
3969 int minDistance = brlims->bridge->br_width;
3970 int width, height, ybot0, tp2lim;
3971 Tile *tp, *tp2;
3972
3973 TiToRect(tile, &area);
3974
3975 /* Check whole tile for minimum width */
3976 width = area.r_xtop - area.r_xbot;
3977 if (width < minDistance)
3978 {
3979 area.r_xbot = area.r_xtop - minDistance;
3980 if (!bridgeLimSrTiles(brlims, &area, TRUE))
3981 {
3982 area.r_xbot = MIN(LEFT(tile), xOverlap);
3983 area.r_xtop = area.r_xbot + minDistance;
3984 }
3985 }
3986
3987 /* If there is another tile on top or bottom, and the height is */
3988 /* less than minimum, then extend height in the direction of */
3989 /* the bordering tile. Otherwise, if the height is less than */
3990 /* minimum, then grow considering the limiting layers. */
3991
3992 height = area.r_ytop - area.r_ybot;
3993 if (height < minDistance)
3994 {
3995 for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
3996 {
3997 tp2lim = MAX(LEFT(tp), area.r_xbot);
3998 for (tp2 = RT(tile); RIGHT(tp2) > tp2lim; tp2 = BL(tp2))
3999 if (LEFT(tp2) < RIGHT(tp))
4000 {
4001 parea.r_xbot = MAX(LEFT(tp2), tp2lim);
4002 parea.r_xtop = MIN(MIN(RIGHT(tp2), RIGHT(tp)), area.r_xtop);
4003 if (TiGetBottomType(tp2) == TiGetTopType(tile))
4004 parea.r_ytop = TOP(tp2);
4005 else
4006 parea.r_ytop = area.r_ytop;
4007 if (TiGetTopType(tp) == TiGetBottomType(tile))
4008 ybot0 = BOTTOM(tp);
4009 else
4010 ybot0 = area.r_ybot;
4011 height = parea.r_ytop - ybot0;
4012 if (height < minDistance)
4013 {
4014 parea.r_ybot = parea.r_ytop - minDistance;
4015 if (!bridgeLimSrTiles(brlims, &parea, TRUE))
4016 {
4017 parea.r_ybot = MIN(ybot0 , yOverlap);
4018 parea.r_ytop = parea.r_ybot + minDistance;
4019 }
4020 DBPaintPlane(cifPlane, &parea, CIFPaintTable, (PaintUndoInfo *) NULL);
4021 }
4022 }
4023 }
4024 }
4025 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4026 return 0;
4027 }
4028
4029 /*
4030 *-----------------------------------------------------------------------
4031 * Callback function for cifBridgeLimFunc1 and cifBridgeLimFunc2 to find if
4032 * there are violator cells in the search area. If a violator cell is
4033 * found, then put the tile pointer in the BridgeCheckStruct and return
4034 * value 1 to stop the search. Otherwise return 0 to keep going.
4035 *-----------------------------------------------------------------------
4036 */
4037 int
bridgeLimCheckFunc(tile,brlimcs)4038 bridgeLimCheckFunc(tile, brlimcs)
4039 Tile *tile;
4040 BridgeLimCheckStruct *brlimcs;
4041 {
4042 int dir = brlimcs->direction;
4043 Tile *self = brlimcs->tile;
4044 Tile *tp1, *tp2;
4045 TileType checktype = brlimcs->checktype;
4046 long sqdistance = brlimcs->sqdistance;
4047 int dx, dy;
4048 long sqcheck;
4049
4050 if (self == tile) return 0; /* Ignore the triggering tile */
4051
4052 switch (dir) {
4053 case BRIDGE_NW:
4054 /* Ignore tile if split, and SE corner is clipped */
4055 if (IsSplit(tile))
4056 if (TiGetRightType(tile) == checktype || TiGetBottomType(tile) == checktype)
4057 break;
4058 for (tp1 = RT(tile); LEFT(tp1) > LEFT(tile); tp1 = BL(tp1));
4059 for (tp2 = BL(tile); TOP(tp2) < TOP(tile); tp2 = RT(tp2));
4060 if ((TiGetBottomType(tp1) == checktype) &&
4061 (TiGetRightType(tp2) == checktype))
4062 {
4063 dx = LEFT(tile) - RIGHT(self);
4064 dy = BOTTOM(self) - TOP(tile);
4065 if ((dx > 0) && (dy > 0))
4066 {
4067 sqcheck = (long)dx*dx + (long)dy*dy;
4068 if (sqcheck >= sqdistance)
4069 return 0;
4070 }
4071 brlimcs->violator = tile;
4072 return 1; /* Violator found */
4073 }
4074 break;
4075 case BRIDGE_SW:
4076 /* Ignore tile if split, and NE corner is clipped */
4077 if (IsSplit(tile))
4078 if (TiGetRightType(tile) == checktype || TiGetTopType(tile) == checktype)
4079 break;
4080 tp1 = LB(tile);
4081 tp2 = BL(tile);
4082 if ((TiGetTopType(tp1) == checktype) &&
4083 (TiGetRightType(tp2) == checktype))
4084 {
4085 dx = LEFT(tile) - RIGHT(self);
4086 dy = BOTTOM(tile) - TOP(self);
4087 if ((dx > 0) && (dy > 0))
4088 {
4089 sqcheck = (long)dx*dx + (long)dy*dy;
4090 if (sqcheck >= sqdistance)
4091 return 0;
4092 }
4093 brlimcs->violator = tile;
4094 return 1; /* Violator found */
4095 }
4096 break;
4097 }
4098 return 0; /* Nothing found here, so keep going */
4099 }
4100
4101 /*
4102 *-----------------------------------------------------------------------
4103 * Callback function used in bridge-lim operations to do not paint areas
4104 * where new bridge overlaps the limiting layer tiles.
4105 *-----------------------------------------------------------------------
4106 */
4107 int
bridgeErase(brlims,area)4108 bridgeErase(brlims, area)
4109 BridgeLimStruct *brlims; /* Bridge-lim structure. */
4110 Rect *area; /* Area of Magic paint to consider. */
4111 {
4112 TileTypeBitMask maskBits;
4113 TileType t;
4114 int i;
4115 Plane **temps = brlims->temps;
4116
4117 for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
4118 {
4119 maskBits = DBPlaneTypes[i];
4120 TTMaskAndMask(&maskBits, &brlims->co_paintMask);
4121 if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
4122 if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, cifPaintFunc, CIFEraseTable))
4123 return 0;
4124 }
4125
4126 for (t = 0; t < TT_MAXTYPES; t++, temps++)
4127 if (TTMaskHasType(&brlims->co_cifMask, t))
4128 if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, cifPaintFunc, CIFEraseTable))
4129 return 0;
4130
4131 return 1; //Nothing found
4132 }
4133
4134 /*
4135 * ----------------------------------------------------------------------------
4136 *
4137 * cifBridgeLimFunc1 --
4138 *
4139 * Called for each relevant tile during bridge-lim operations. The
4140 * bridge-lim operation is similar to the bridge operation with the
4141 * difference that the material created to meet the minimum spacing/width
4142 * rules do not overlap the limiting layers.
4143 *
4144 * Results:
4145 * Always returns 0 to keep the search alive.
4146 *
4147 * Side effects:
4148 * May paint into cifNewPlane
4149 * ----------------------------------------------------------------------------
4150 */
4151 int
cifBridgeLimFunc1(tile,brlims)4152 cifBridgeLimFunc1(tile, brlims)
4153 Tile *tile;
4154 BridgeLimStruct *brlims;
4155 {
4156 Plane *plane = brlims->plane;
4157 Rect area;
4158 Tile *tp1, *tp2, *tpx;
4159 int width = brlims->bridge->br_width;
4160 int spacing = growDistance;
4161 BridgeLimCheckStruct brlimcs;
4162 brlimcs.sqdistance = (long) spacing * spacing;
4163
4164 /* If tile is marked, then it has been handled, so ignore it */
4165 if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
4166
4167 /* Find each tile outside corner (up to four) */
4168
4169 /* Check for NE outside corner */
4170 tp1 = TR(tile); /* Tile on right side at the top of this tile */
4171 tp2 = RT(tile); /* Tile on top side at the right of this tile */
4172 if ((TiGetLeftType(tp1) == TT_SPACE) &&
4173 (TiGetBottomType(tp2) == TT_SPACE))
4174 {
4175 /* Set search box */
4176 area.r_xbot = RIGHT(tile);
4177 area.r_xtop = RIGHT(tile) + spacing;
4178 area.r_ybot = TOP(tile);
4179 area.r_ytop = TOP(tile) + spacing;
4180
4181 /* Find violator tiles */
4182 brlimcs.tile = tile;
4183 brlimcs.direction = BRIDGE_SW;
4184 brlimcs.checktype = TT_SPACE;
4185 if (DBSrPaintArea((Tile *) NULL, plane, &area,
4186 &CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4187 {
4188 tpx = brlimcs.violator;
4189 area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4190 area.r_ytop = MAX(TOP(tile), BOTTOM(tpx));
4191 area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
4192 area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
4193 if (bridgeLimSrTiles(brlims, &area, FALSE))
4194 {
4195 /* First option of bridge can be implemented (there are not limiting tiles in the area)*/
4196 area.r_ytop = TOP(tile);
4197 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4198 area.r_xbot = LEFT(tpx);
4199 area.r_ytop = MAX(TOP(tile), BOTTOM(tpx));
4200 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4201 }
4202 else
4203 {
4204 area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
4205 area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
4206 area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4207 area.r_ybot = MIN(BOTTOM(tpx), TOP(tile));
4208 if (bridgeLimSrTiles(brlims, &area, FALSE))
4209 {
4210 /* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
4211 area.r_ybot = BOTTOM(tpx);
4212 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4213 area.r_xtop = RIGHT(tile);
4214 area.r_ybot = MIN(BOTTOM(tpx), TOP(tile));
4215 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4216 }
4217 else
4218 {
4219 /* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
4220 area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4221 area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
4222 area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4223 area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
4224 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4225 bridgeErase(brlims, &area);
4226 }
4227 }
4228 }
4229 }
4230
4231 /* Check for SE outside corner */
4232 for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
4233 for (tp2 = LB(tile); RIGHT(tp1) < RIGHT(tile); tp2 = TR(tp2));
4234 if ((TiGetLeftType(tp1) == TT_SPACE) &&
4235 (TiGetTopType(tp2) == TT_SPACE))
4236 {
4237 /* Set search box */
4238 area.r_xbot = RIGHT(tile);
4239 area.r_xtop = RIGHT(tile) + spacing;
4240 area.r_ybot = BOTTOM(tile) - spacing;
4241 area.r_ytop = BOTTOM(tile);
4242
4243 /* Find violator tiles */
4244 brlimcs.tile = tile;
4245 brlimcs.direction = BRIDGE_NW;
4246 brlimcs.checktype = TT_SPACE;
4247 if (DBSrPaintArea((Tile *) NULL, plane, &area,
4248 &CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4249 {
4250 tpx = brlimcs.violator;
4251 area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
4252 area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
4253 area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4254 area.r_ytop = MAX(TOP(tpx), BOTTOM(tile));
4255 if (bridgeLimSrTiles(brlims, &area, FALSE))
4256 {
4257 /* First option of bridge can be implemented (there are not limiting tiles in the area)*/
4258 area.r_xtop = RIGHT(tile);
4259 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4260 area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
4261 area.r_ytop = TOP(tpx);
4262 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4263 }
4264 else
4265 {
4266 area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4267 area.r_ybot = MIN(BOTTOM(tile), TOP(tpx));
4268 area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
4269 area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
4270 if (bridgeLimSrTiles(brlims, &area, FALSE))
4271 {
4272 /* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
4273 area.r_xbot = LEFT(tpx);
4274 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4275 area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
4276 area.r_ybot = BOTTOM(tile);
4277 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4278 }
4279 else
4280 {
4281 /* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
4282 area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
4283 area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
4284 area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
4285 area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
4286 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4287 bridgeErase(brlims, &area);
4288 }
4289 }
4290 }
4291 }
4292
4293 return 0;
4294 }
4295
4296 /*
4297 * ----------------------------------------------------------------------------
4298 * cifBridgeLimFunc2 --
4299 *
4300 * Called for each relevant tile during bridge-lim operations. The
4301 * bridge-lim operation is similar to the bridge operation with the
4302 * difference that the material created to meet the minimum spacing/width
4303 * rules do not overlap the limiting layers.
4304 *
4305 * Results:
4306 * Always returns 0 to keep the search alive.
4307 *
4308 * Side effects:
4309 * May paint into cifNewPlane
4310 * ----------------------------------------------------------------------------
4311 */
4312 int
cifBridgeLimFunc2(tile,brlims)4313 cifBridgeLimFunc2(tile, brlims)
4314 Tile *tile;
4315 BridgeLimStruct *brlims;
4316 {
4317 Plane *plane = brlims->plane;
4318 Rect area;
4319 Tile *tp1, *tp2, *tpx;
4320 int width = brlims->bridge->br_width;
4321 int thirdOption;
4322 int spacing = growDistance;
4323 BridgeLimCheckStruct brlimcs;
4324 brlimcs.sqdistance = (long) width * width;
4325
4326 /* If tile is marked, then it has been handled, so ignore it */
4327 if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
4328
4329 /* Find each tile outside corner (up to four) */
4330
4331 /* Check for NE outside corner */
4332 tp1 = TR(tile); /* Tile on right side at the top of this tile */
4333 tp2 = RT(tile); /* Tile on top side at the right of this tile */
4334 if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
4335 (TiGetBottomType(tp2) == CIF_SOLIDTYPE))
4336 {
4337 /* Set search box */
4338 area.r_xbot = RIGHT(tile);
4339 area.r_xtop = RIGHT(tile) + width;
4340 area.r_ybot = TOP(tile);
4341 area.r_ytop = TOP(tile) + width;
4342
4343 /* Find violator tiles */
4344 brlimcs.tile = tile;
4345 brlimcs.direction = BRIDGE_SW;
4346 brlimcs.checktype = CIF_SOLIDTYPE;
4347 if (DBSrPaintArea((Tile *) NULL, plane, &area,
4348 &DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4349 {
4350 tpx = brlimcs.violator;
4351 area.r_xtop = RIGHT(tile);
4352 area.r_ytop = TOP(tile);
4353 area.r_xbot = LEFT(tpx) - width;
4354 area.r_ybot = BOTTOM(tpx) - width;
4355
4356 thirdOption = 0;
4357 if (!bridgeLimSrTiles(brlims, &area, FALSE))
4358 {
4359 area.r_xtop = RIGHT(tile) + width;
4360 area.r_ytop = TOP(tile) + width;
4361 area.r_xbot = LEFT(tpx);
4362 area.r_ybot = BOTTOM(tpx);
4363 if (!bridgeLimSrTiles(brlims, &area, FALSE))
4364 {
4365 area.r_xbot = LEFT(tpx) - width;
4366 area.r_ybot = BOTTOM(tpx) - width;
4367 thirdOption = 1;
4368 }
4369 }
4370 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4371 if (thirdOption)
4372 bridgeErase(brlims, &area);
4373 }
4374 }
4375
4376 /* Check for SE outside corner */
4377 for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
4378 for (tp2 = LB(tile); RIGHT(tp2) < RIGHT(tile); tp2 = TR(tp2));
4379 if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
4380 (TiGetTopType(tp2) == CIF_SOLIDTYPE))
4381 {
4382 /* Set search box */
4383 area.r_xbot = RIGHT(tile);
4384 area.r_xtop = RIGHT(tile) + width;
4385 area.r_ybot = BOTTOM(tile) - width;
4386 area.r_ytop = BOTTOM(tile);
4387
4388 /* Find violator tiles */
4389 brlimcs.tile = tile;
4390 brlimcs.direction = BRIDGE_NW;
4391 brlimcs.checktype = CIF_SOLIDTYPE;
4392 if (DBSrPaintArea((Tile *) NULL, plane, &area,
4393 &DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
4394 {
4395 tpx = brlimcs.violator;
4396 area.r_xtop = RIGHT(tile) + width;
4397 area.r_ytop = TOP(tpx);
4398 area.r_xbot = LEFT(tpx);
4399 area.r_ybot = BOTTOM(tile) - width;
4400
4401 thirdOption = 0;
4402 if (!bridgeLimSrTiles(brlims, &area, FALSE))
4403 {
4404 area.r_xtop = RIGHT(tile);
4405 area.r_ytop = TOP(tpx) + width;
4406 area.r_xbot = LEFT(tpx) - width;
4407 area.r_ybot = BOTTOM(tile);
4408 if (!bridgeLimSrTiles(brlims, &area, FALSE))
4409 {
4410 area.r_xtop = RIGHT(tile) + width;
4411 area.r_ybot = BOTTOM(tile) - width;
4412 thirdOption = 1;
4413 }
4414 }
4415 DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
4416 if (thirdOption)
4417 bridgeErase(brlims, &area);
4418 }
4419 }
4420
4421 return 0;
4422 }
4423
4424 /*
4425 * ----------------------------------------------------------------------------
4426 *
4427 * CIFGenLayer --
4428 *
4429 * This routine will generate one CIF layer.
4430 * It provides the core of the CIF generator.
4431 *
4432 * Results:
4433 * Returns a malloc'ed plane with tiles of type CIF_SOLIDTYPE
4434 * marking the area of this CIF layer as built up by op.
4435 *
4436 * Side effects:
4437 * None, except to create a new plane holding the CIF for the layer.
4438 * The CIF that's generated may fall outside of area... it's what
4439 * results from considering everything in area. In most cases the
4440 * caller will clip the results down to the desired area.
4441 *
4442 * ----------------------------------------------------------------------------
4443 */
4444
4445 Plane *
CIFGenLayer(op,area,cellDef,origDef,temps,hier,clientdata)4446 CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata)
4447 CIFOp *op; /* List of CIFOps telling how to make layer. */
4448 Rect *area; /* Area to consider when generating CIF. Only
4449 * material in this area will be considered, so
4450 * the caller should usually expand his desired
4451 * area by one CIF radius.
4452 */
4453 CellDef *cellDef; /* CellDef to search when paint layers are
4454 * needed for operation.
4455 */
4456 CellDef *origDef; /* Original CellDef for which output is being
4457 * generated (cellDef may be derived from this).
4458 */
4459 Plane *temps[]; /* Temporary layers to be used when needed
4460 * for operation.
4461 */
4462 bool hier; /* TRUE if called from CIFGenSubcells or CIFGenArrays */
4463 ClientData clientdata; /*
4464 * Data that may be passed to the CIF operation
4465 * function.
4466 */
4467 {
4468 Plane *temp;
4469 static Plane *nextPlane, *curPlane;
4470 Rect bbox;
4471 CIFOp *tempOp;
4472 CIFSquaresInfo csi;
4473 SearchContext scx;
4474 TileType ttype;
4475 char *netname;
4476 BloatStruct bls;
4477 BridgeStruct brs;
4478 BridgeLimStruct brlims;
4479 BridgeData *bridge;
4480 BloatData *bloats;
4481 bool hstop = FALSE;
4482 char *propvalue;
4483 bool found;
4484
4485 int (*cifGrowFuncPtr)() = (CIFCurStyle->cs_flags & CWF_GROW_EUCLIDEAN) ?
4486 cifGrowEuclideanFunc : cifGrowFunc;
4487
4488 /* Set up temporary planes used during computation. One of these
4489 * will be returned as the result (whichever is curPlane at the
4490 * end of the computation). The other is saved for later use.
4491 */
4492
4493 if (nextPlane == NULL)
4494 nextPlane = DBNewPlane((ClientData) TT_SPACE);
4495 curPlane = DBNewPlane((ClientData) TT_SPACE);
4496
4497 /* Go through the geometric operations and process them one
4498 * at a time.
4499 *
4500 * NOTE: Some opcodes (and whatever follows them) should never
4501 * be run during hierarchical processing. That includes BOUNDARY,
4502 * SQUARES/SLOTS, BBOX, and NET.
4503 *
4504 * Caveat: SQUARES/SLOTS followed by GROW can be used to define
4505 * an etch area around a contact; this should be considered a
4506 * special case that requires hierarchical processing on SQUARES/
4507 * SLOTS.
4508 */
4509
4510 for ( ; op != NULL; op = op->co_next)
4511 {
4512 switch (op->co_opcode)
4513 {
4514 /* For AND, first collect all the stuff to be anded with
4515 * plane in a temporary plane. Then find all the places
4516 * where there isn't any stuff, and erase from the
4517 * current plane.
4518 */
4519
4520 case CIFOP_AND:
4521 DBClearPaintPlane(nextPlane);
4522 cifPlane = nextPlane;
4523 cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4524 (ClientData) CIFPaintTable);
4525 cifPlane = curPlane;
4526 cifScale = 1;
4527 (void) DBSrPaintArea((Tile *) NULL, nextPlane, &TiPlaneRect,
4528 &DBSpaceBits, cifPaintFunc,
4529 (ClientData) CIFEraseTable);
4530 break;
4531
4532 /* For OR, just use cifPaintFunc to OR the areas of all
4533 * relevant tiles into plane. HOWEVER, if the co_client
4534 * record is non-NULL and CalmaContactArrays is TRUE,
4535 * then for each contact type, we do the paint function
4536 * separately, then call the contact array generation
4537 * procedure.
4538 */
4539
4540 case CIFOP_OR:
4541 cifPlane = curPlane;
4542 cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4543
4544 if ((op->co_client != (ClientData)NULL)
4545 && (CalmaContactArrays == TRUE))
4546 {
4547 TileTypeBitMask paintMask, errMask, *rMask;
4548 TileType i, j;
4549
4550 TTMaskZero(&errMask);
4551 TTMaskZero(&paintMask);
4552 TTMaskSetMask(&paintMask, &op->co_paintMask);
4553 for (i = TT_TECHDEPBASE; i < DBNumUserLayers; i++)
4554 {
4555 if (TTMaskHasType(&paintMask, i))
4556 {
4557 TTMaskSetOnlyType(&op->co_paintMask, i);
4558 for (j = DBNumUserLayers; j < DBNumTypes; j++)
4559 {
4560 rMask = DBResidueMask(j);
4561 if (TTMaskHasType(rMask, i))
4562 TTMaskSetType(&op->co_paintMask, j);
4563 }
4564
4565 cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4566 (ClientData) CIFPaintTable);
4567
4568 csi.csi_squares = (SquaresData *)op->co_client;
4569 csi.csi_type = i;
4570 csi.csi_client = clientdata;
4571
4572 if (DBSrPaintArea((Tile *) NULL, curPlane,
4573 &TiPlaneRect, &CIFSolidBits,
4574 cifContactFunc, (ClientData) &csi))
4575 {
4576 /* Failure of DBSrPaintArea() (returns 1)
4577 * indicates that a contact cell type
4578 * could not be found for magic layer i.
4579 * Record the error for subsequent handling.
4580 */
4581 TTMaskSetType(&errMask, i);
4582 }
4583 DBClearPaintPlane(curPlane);
4584 }
4585 }
4586 if (!TTMaskIsZero(&errMask))
4587 {
4588 /*
4589 * Handle layers for which a contact cell could
4590 * not be found in the default manner.
4591 */
4592 TTMaskZero(&op->co_paintMask);
4593 TTMaskSetMask(&op->co_paintMask, &errMask);
4594 cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4595 (ClientData) CIFPaintTable);
4596 }
4597
4598 /* Recover the original magic layer mask for the cifop */
4599
4600 TTMaskZero(&op->co_paintMask);
4601 TTMaskSetMask(&op->co_paintMask, &paintMask);
4602 }
4603 else
4604 {
4605 cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4606 (ClientData) CIFPaintTable);
4607 }
4608 break;
4609
4610 /* For ANDNOT, do exactly the same thing as OR, except erase
4611 * instead of paint.
4612 */
4613
4614 case CIFOP_ANDNOT:
4615 cifPlane = curPlane;
4616 cifSrTiles(op, area, cellDef, temps, cifPaintFunc,
4617 (ClientData) CIFEraseTable);
4618 break;
4619
4620 /* For GROW, just find all solid tiles in the current plane,
4621 * and paint a larger version into a new plane. The switch
4622 * the current and new planes.
4623 */
4624
4625 case CIFOP_GROW:
4626 growDistance = op->co_distance;
4627 DBClearPaintPlane(nextPlane);
4628 cifPlane = nextPlane;
4629 cifScale = 1;
4630 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4631 &CIFSolidBits, *cifGrowFuncPtr, (ClientData) CIFPaintTable);
4632 temp = curPlane;
4633 curPlane = nextPlane;
4634 nextPlane = temp;
4635 break;
4636
4637 /* GROWMIN grows non-uniformly to ensure minimum dimensions */
4638
4639 case CIFOP_GROWMIN:
4640 growDistance = op->co_distance;
4641 DBClearPaintPlane(nextPlane);
4642 cifPlane = nextPlane;
4643 cifScale = 1;
4644 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4645 &CIFSolidBits, cifGrowMinFunc, (ClientData)CIFPaintTable);
4646 temp = curPlane;
4647 curPlane = nextPlane;
4648 nextPlane = temp;
4649 break;
4650
4651 /* GROW_G grows non-uniformly to the indicated grid. */
4652
4653 case CIFOP_GROW_G:
4654 growDistance = op->co_distance;
4655 DBClearPaintPlane(nextPlane);
4656 cifPlane = nextPlane;
4657 cifScale = 1;
4658 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4659 &CIFSolidBits, cifGrowGridFunc, (ClientData) CIFPaintTable);
4660 temp = curPlane;
4661 curPlane = nextPlane;
4662 nextPlane = temp;
4663 break;
4664
4665 /* SHRINK is just like grow except work from the space tiles. */
4666
4667 case CIFOP_SHRINK:
4668 growDistance = op->co_distance;
4669 DBClearPaintPlane(nextPlane);
4670 DBPaintPlane(nextPlane, &TiPlaneRect, CIFPaintTable,
4671 (PaintUndoInfo *) NULL);
4672 cifPlane = nextPlane;
4673 cifScale = 1;
4674 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4675 &DBSpaceBits, *cifGrowFuncPtr, (ClientData) CIFEraseTable);
4676 temp = curPlane;
4677 curPlane = nextPlane;
4678 nextPlane = temp;
4679 break;
4680
4681 case CIFOP_CLOSE:
4682 growDistance = op->co_distance;
4683 DBClearPaintPlane(nextPlane);
4684 cifPlane = nextPlane;
4685 cifScale = 1;
4686 /* First copy the existing paint into the target plane */
4687 DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4688 &CIFSolidBits, cifPaintFunc, (ClientData)CIFPaintTable);
4689 DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4690 &DBSpaceBits, cifCloseFunc, (ClientData)&curPlane);
4691
4692 temp = curPlane;
4693 curPlane = nextPlane;
4694 nextPlane = temp;
4695 break;
4696
4697 case CIFOP_BRIDGE:
4698 growDistance = op->co_distance;
4699 DBClearPaintPlane(nextPlane);
4700 cifPlane = nextPlane;
4701 cifScale = 1;
4702 /* First copy the existing paint into the target plane */
4703 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4704 &CIFSolidBits, cifPaintFunc, (ClientData)CIFPaintTable);
4705
4706 brs.plane = curPlane;
4707 brs.bridge = (BridgeData *)op->co_client;
4708 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4709 &CIFSolidBits, cifBridgeFunc1, (ClientData)&brs);
4710 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4711 &DBSpaceBits, cifBridgeFunc2, (ClientData)&brs);
4712 temp = curPlane;
4713 curPlane = nextPlane;
4714 nextPlane = temp;
4715 break;
4716
4717 case CIFOP_BRIDGELIM:
4718 growDistance = op->co_distance;
4719 DBClearPaintPlane(nextPlane);
4720 cifPlane = nextPlane;
4721 cifScale = 1;
4722
4723 brlims.bridge = (BridgeData *)op->co_client;
4724 brlims.def = cellDef;
4725 brlims.temps = temps;
4726 brlims.co_paintMask = op->co_paintMask;
4727 brlims.co_cifMask = op->co_cifMask;
4728
4729 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4730 &CIFSolidBits, cifBridgeLimFunc0, (ClientData)&brlims);
4731 temp = curPlane;
4732 curPlane = nextPlane;
4733 brlims.plane = curPlane;
4734
4735 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4736 &CIFSolidBits, cifBridgeLimFunc1, (ClientData)&brlims);
4737 (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
4738 &DBSpaceBits, cifBridgeLimFunc2, (ClientData)&brlims);
4739 curPlane = nextPlane;
4740 nextPlane = temp;
4741 break;
4742
4743 case CIFOP_BLOAT:
4744 cifPlane = curPlane;
4745 cifSrTiles(op, area, cellDef, temps,
4746 cifBloatFunc, op->co_client);
4747 break;
4748
4749 case CIFOP_BLOATMAX:
4750 case CIFOP_BLOATMIN:
4751 cifPlane = curPlane;
4752 cifSrTiles(op, area, cellDef, temps,
4753 cifBloatMaxFunc, (ClientData) op);
4754 break;
4755
4756 case CIFOP_BLOATALL:
4757 cifPlane = curPlane;
4758 bls.op = op;
4759 bls.def = cellDef;
4760 bls.temps = temps;
4761
4762 /* Create a mask of all connecting types (these must be in a single
4763 * plane), then call a search function to find all connecting material
4764 * of these types (if the bloat types are temp layers, then this mask
4765 * is not used).
4766 */
4767
4768 bloats = (BloatData *)op->co_client;
4769 if (bloats->bl_plane < 0)
4770 {
4771 /* bl_plane == -1 indicates bloating into a CIF templayer, */
4772 /* so the only connecting type should be CIF_SOLIDTYPE. */
4773 TTMaskSetOnlyType(&bls.connect, CIF_SOLIDTYPE);
4774 }
4775 else
4776 {
4777 int i;
4778 TTMaskZero(&bls.connect);
4779 for (i = 0; i < TT_MAXTYPES; i++)
4780 if (bloats->bl_distance[i] != 0)
4781 TTMaskSetType(&bls.connect, i);
4782 }
4783
4784 cifSrTiles(op, area, cellDef, temps, cifBloatAllFunc, (ClientData)&bls);
4785
4786 /* Reset marked tiles */
4787
4788 if (bloats->bl_plane < 0) /* Bloat types are CIF types */
4789 {
4790 bls.temps = temps;
4791 for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
4792 if (bloats->bl_distance[ttype] > 0)
4793 (void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
4794 &CIFSolidBits, cifProcessResetFunc,
4795 (ClientData)NULL);
4796 }
4797 else
4798 DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
4799 &TiPlaneRect, &bls.connect, cifProcessResetFunc,
4800 (ClientData)NULL);
4801
4802 break;
4803
4804 case CIFOP_SQUARES:
4805 if (hier)
4806 {
4807 if ((op->co_next == NULL) || (op->co_next->co_opcode != CIFOP_GROW))
4808 {
4809 hstop = TRUE; /* Stop hierarchical processing */
4810 break;
4811 }
4812 }
4813 if (CalmaContactArrays == FALSE)
4814 {
4815 DBClearPaintPlane(nextPlane);
4816 cifPlane = nextPlane;
4817 cifSquaresFillArea(op, cellDef, curPlane);
4818 temp = curPlane;
4819 curPlane = nextPlane;
4820 nextPlane = temp;
4821 }
4822 break;
4823
4824 case CIFOP_SQUARES_G:
4825 if (hier)
4826 {
4827 if ((op->co_next == NULL) || (op->co_next->co_opcode != CIFOP_GROW))
4828 {
4829 hstop = TRUE; /* Stop hierarchical processing */
4830 break;
4831 }
4832 }
4833 DBClearPaintPlane(nextPlane);
4834 cifPlane = nextPlane;
4835 cifSquaresFillArea(op, cellDef, curPlane);
4836 temp = curPlane;
4837 curPlane = nextPlane;
4838 nextPlane = temp;
4839 break;
4840
4841 case CIFOP_SLOTS:
4842 if (hier)
4843 {
4844 if ((op->co_next == NULL) || (op->co_next->co_opcode != CIFOP_GROW))
4845 {
4846 hstop = TRUE; /* Stop hierarchical processing */
4847 break;
4848 }
4849 }
4850 DBClearPaintPlane(nextPlane);
4851 cifPlane = nextPlane;
4852 cifSlotsFillArea(op, cellDef, curPlane);
4853 temp = curPlane;
4854 curPlane = nextPlane;
4855 nextPlane = temp;
4856 break;
4857
4858 case CIFOP_MAXRECT:
4859 cifPlane = curPlane;
4860
4861 DBClearPaintPlane(nextPlane);
4862 cifPlane = nextPlane;
4863 cifRectBoundingBox(op, cellDef, curPlane);
4864 temp = curPlane;
4865 curPlane = nextPlane;
4866 nextPlane = temp;
4867 break;
4868
4869 case CIFOP_NET:
4870 if (hier)
4871 {
4872 hstop = TRUE; /* Stop hierarchical processing */
4873 break;
4874 }
4875 netname = (char *)op->co_client;
4876 cifPlane = curPlane;
4877 ttype = CmdFindNetProc(netname, CIFDummyUse, &bbox, FALSE);
4878 if (ttype != TT_SPACE)
4879 {
4880 UndoDisable();
4881 DBCellClearDef(Select2Def);
4882 scx.scx_area = bbox;
4883 scx.scx_use = CIFDummyUse;
4884 scx.scx_trans = GeoIdentityTransform;
4885 DBTreeCopyConnect(&scx, &DBConnectTbl[ttype], 0,
4886 DBConnectTbl, &TiPlaneRect, SEL_NO_LABELS, Select2Use);
4887 cifSrTiles(op, area, Select2Def, temps, cifPaintFunc,
4888 (ClientData) CIFPaintTable);
4889 DBCellClearDef(Select2Def);
4890 UndoEnable();
4891 }
4892 break;
4893
4894 case CIFOP_BOUNDARY:
4895 if (hier)
4896 {
4897 hstop = TRUE; /* Stop hierarchical processing */
4898 break;
4899 }
4900 cifPlane = curPlane;
4901 /* This function for cifoutput only. cifinput handled separately. */
4902
4903 if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
4904 {
4905 propvalue = (char *)DBPropGet(origDef, "FIXED_BBOX", &found);
4906 if (!found) break;
4907 if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
4908 &bbox.r_xtop, &bbox.r_ytop) != 4) break;
4909
4910 cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4911 bbox.r_xbot *= cifScale;
4912 bbox.r_xtop *= cifScale;
4913 bbox.r_ybot *= cifScale;
4914 bbox.r_ytop *= cifScale;
4915 cifScale = 1;
4916 DBNMPaintPlane(cifPlane, CIF_SOLIDTYPE, &bbox,
4917 CIFPaintTable, (PaintUndoInfo *)NULL);
4918 }
4919 break;
4920
4921 case CIFOP_BBOX:
4922 if (hier)
4923 {
4924 hstop = TRUE; /* Stop hierarchical processing */
4925 break;
4926 }
4927 if (CIFErrorDef == NULL) break;
4928
4929 /* co_client contains the flag (1) for top-level only */
4930 if ((int)op->co_client == 1)
4931 {
4932 /* Only generate output for the top-level cell */
4933 int found = 0;
4934 CellUse *celluse;
4935 for (celluse = CIFErrorDef->cd_parents;
4936 celluse != (CellUse *) NULL;
4937 celluse = celluse->cu_nextuse)
4938 {
4939 if (celluse->cu_parent != (CellDef *) NULL)
4940 if ((celluse->cu_parent->cd_flags & CDINTERNAL)
4941 != CDINTERNAL)
4942 {
4943 found = 1;
4944 break;
4945 }
4946 }
4947 if (found != 0) break;
4948 }
4949 cifPlane = curPlane;
4950 bbox = CIFErrorDef->cd_bbox;
4951 cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4952 bbox.r_xbot *= cifScale;
4953 bbox.r_xtop *= cifScale;
4954 bbox.r_ybot *= cifScale;
4955 bbox.r_ytop *= cifScale;
4956 cifScale = 1;
4957 DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
4958 CIFPaintTable, (PaintUndoInfo *)NULL);
4959 break;
4960
4961 /* The CIFOP_MASKHINTS operator checks the current cell for */
4962 /* a property with "MASKHINTS_" followed by the name saved */
4963 /* in the co_client record. If there is such a property, */
4964 /* then the property value is parsed for geometry in */
4965 /* internal units, grouped in sets of four values llx lly */
4966 /* urx ury. */
4967
4968 case CIFOP_MASKHINTS:
4969 {
4970 int j, numfound;
4971 char propname[512];
4972 char *propptr;
4973 char *layername = (char *)op->co_client;
4974
4975 sprintf(propname, "MASKHINTS_%s", layername);
4976
4977 propvalue = (char *)DBPropGet(cellDef, propname, &found);
4978 if (!found) break; /* No mask hints available */
4979 propptr = propvalue;
4980 while (*propptr)
4981 {
4982 numfound = sscanf(propptr, "%d %d %d %d",
4983 &bbox.r_xbot, &bbox.r_ybot,
4984 &bbox.r_xtop, &bbox.r_ytop);
4985
4986 if (numfound != 4)
4987 {
4988 /* To do: Allow keyword "rect", "tri", or "poly"
4989 * at the start of the list and parse accordingly.
4990 * For now, this only flags an error.
4991 */
4992 TxError("%s: Cannot read rectangle values.\n", propname);
4993 break;
4994 }
4995 cifPlane = curPlane;
4996 cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
4997 bbox.r_xbot *= cifScale;
4998 bbox.r_xtop *= cifScale;
4999 bbox.r_ybot *= cifScale;
5000 bbox.r_ytop *= cifScale;
5001 cifScale = 1;
5002 DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
5003 CIFPaintTable, (PaintUndoInfo *)NULL);
5004 for (j = 0; j < 4; j++)
5005 {
5006 while (*propptr && isspace(*propptr)) propptr++;
5007 while (*propptr && !isspace(*propptr)) propptr++;
5008 }
5009 }
5010 }
5011 break;
5012
5013 default:
5014 continue;
5015 }
5016 if (hstop) break; /* Don't process any further rules */
5017 }
5018
5019 return curPlane;
5020 }
5021
5022 /*
5023 * ----------------------------------------------------------------------------
5024 *
5025 * CIFGen --
5026 *
5027 * This procedure generates a complete set of CIF layers for
5028 * a particular area of a particular cell. NOTE: if the argument
5029 * genAllPlanes is FALSE, only planes for those layers having
5030 * a bit set in 'layers' are generated; the others are set
5031 * to NULL.
5032 *
5033 * Results:
5034 * None.
5035 *
5036 * Side effects:
5037 * The parameters realPlanes and tempPlanes are modified
5038 * to hold the CIF and temporary layers for area of cellDef,
5039 * as determined by the current CIF generation rules.
5040 *
5041 * ----------------------------------------------------------------------------
5042 */
5043
5044 void
CIFGen(cellDef,origDef,area,planes,layers,replace,genAllPlanes,hier,clientdata)5045 CIFGen(cellDef, origDef, area, planes, layers, replace, genAllPlanes, hier, clientdata)
5046 CellDef *cellDef; /* Cell for which CIF is to be generated. */
5047 CellDef *origDef; /* Original cell, if different from cellDef */
5048 Rect *area; /* Any CIF overlapping this area (in coords
5049 * of cellDef) will be generated. The CIF
5050 * will be clipped to this area.
5051 */
5052 Plane **planes; /* Pointer to array of pointers to planes
5053 * to hold "real" CIF layers that are
5054 * generated. Pointers may initially be
5055 * NULL.
5056 */
5057 TileTypeBitMask *layers; /* CIF layers to generate. */
5058 bool replace; /* TRUE means that the new CIF is to replace
5059 * anything that was previously in planes.
5060 * FALSE means that the new CIF is to be
5061 * OR'ed in with the current contents of
5062 * planes.
5063 */
5064 bool genAllPlanes; /* If TRUE, generate a tile plane even for
5065 * those layers not specified as being
5066 * generated in the 'layers' mask above.
5067 */
5068 bool hier; /* TRUE if called from CIFGenSubcells or CIFGenArrays */
5069 ClientData clientdata; /* Data that may be passed along to the
5070 * CIF operation functions.
5071 */
5072 {
5073 int i;
5074 Plane *new[MAXCIFLAYERS];
5075 Rect expanded, clip;
5076
5077 /*
5078 * Generate the area in magic coordinates to search, and the area in
5079 * cif coordinates to use in clipping the results of CIFGenLayer().
5080 */
5081 cifGenClip(area, &expanded, &clip);
5082
5083 /*
5084 * Generate all of the new layers in a temporary place.
5085 * If a layer isn't being generated, leave new[i] set to
5086 * NULL to indicate this fact.
5087 */
5088 for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
5089 {
5090 if (TTMaskHasType(layers,i))
5091 {
5092 CIFErrorLayer = i;
5093 new[i] = CIFGenLayer(CIFCurStyle->cs_layers[i]->cl_ops,
5094 &expanded, cellDef, origDef, new, hier, clientdata);
5095
5096 /* Clean up the non-manhattan geometry in the plane */
5097 if (CIFUnfracture) DBMergeNMTiles(new[i], &expanded,
5098 (PaintUndoInfo *)NULL);
5099 }
5100 else if (genAllPlanes) new[i] = DBNewPlane((ClientData) TT_SPACE);
5101 else new[i] = (Plane *) NULL;
5102 }
5103
5104 /*
5105 * Now mask off all the unwanted material in the new layers, and
5106 * either OR them into the existing layers or replace the existing
5107 * material with them.
5108 */
5109 for (i = 0; i < CIFCurStyle->cs_nLayers; i += 1)
5110 {
5111 if (new[i])
5112 cifClipPlane(new[i], &clip);
5113
5114 if (replace)
5115 {
5116 if (planes[i])
5117 {
5118 DBFreePaintPlane(planes[i]);
5119 TiFreePlane(planes[i]);
5120 }
5121 planes[i] = new[i];
5122 continue;
5123 }
5124
5125 if (planes[i])
5126 {
5127 if (new[i])
5128 {
5129 cifPlane = planes[i];
5130 cifScale = 1;
5131 (void) DBSrPaintArea((Tile *) NULL, new[i], &TiPlaneRect,
5132 &CIFSolidBits, cifPaintFunc,
5133 (ClientData) CIFPaintTable);
5134 DBFreePaintPlane(new[i]);
5135 TiFreePlane(new[i]);
5136 }
5137 }
5138 else planes[i] = new[i];
5139 }
5140 }
5141
5142 /*
5143 * ----------------------------------------------------------------------------
5144 *
5145 * cifClipPlane --
5146 *
5147 * Erase the portions of the plane 'plane' that lie outside of 'clip'.
5148 *
5149 * Results:
5150 * None.
5151 *
5152 * Side effects:
5153 * See above.
5154 *
5155 * ----------------------------------------------------------------------------
5156 */
5157
5158 void
cifClipPlane(plane,clip)5159 cifClipPlane(plane, clip)
5160 Plane *plane;
5161 Rect *clip;
5162 {
5163 Rect r;
5164
5165 if (clip->r_xtop < TiPlaneRect.r_xtop)
5166 {
5167 r = TiPlaneRect;
5168 r.r_xbot = clip->r_xtop;
5169 DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5170 }
5171 if (clip->r_ytop < TiPlaneRect.r_ytop)
5172 {
5173 r = TiPlaneRect;
5174 r.r_ybot = clip->r_ytop;
5175 DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5176 }
5177 if (clip->r_xbot > TiPlaneRect.r_xbot)
5178 {
5179 r = TiPlaneRect;
5180 r.r_xtop = clip->r_xbot;
5181 DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5182 }
5183 if (clip->r_ybot > TiPlaneRect.r_ybot)
5184 {
5185 r = TiPlaneRect;
5186 r.r_ytop = clip->r_ybot;
5187 DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL);
5188 }
5189 }
5190
5191 /*
5192 * ----------------------------------------------------------------------------
5193 *
5194 * cifGenClip --
5195 *
5196 * Compute two new areas from the original area: one ('expanded')
5197 * is expanded by a CIF halo and is used to determine how much of
5198 * the database to search to find what's relevant for CIF generation;
5199 * the other ('clip') is the CIF equivalent of area and is used to
5200 * clip the resulting CIF. This code is tricky because area may run
5201 * off to infinity, and we have to be careful not to expand past infinity.
5202 *
5203 * Results:
5204 * None.
5205 *
5206 * Side effects:
5207 * Sets *expanded and *clip.
5208 *
5209 * ----------------------------------------------------------------------------
5210 */
5211
5212 void
cifGenClip(area,expanded,clip)5213 cifGenClip(area, expanded, clip)
5214 Rect *area; /* Any CIF overlapping this area (in coords
5215 * of cellDef) will be generated. The CIF
5216 * will be clipped to this area.
5217 */
5218 Rect *expanded, *clip;
5219 {
5220 if (area->r_xbot > TiPlaneRect.r_xbot)
5221 {
5222 clip->r_xbot = area->r_xbot * CIFCurStyle->cs_scaleFactor;
5223 expanded->r_xbot = area->r_xbot - CIFCurStyle->cs_radius;
5224 }
5225 else clip->r_xbot = expanded->r_xbot = area->r_xbot;
5226 if (area->r_ybot > TiPlaneRect.r_ybot)
5227 {
5228 clip->r_ybot = area->r_ybot * CIFCurStyle->cs_scaleFactor;
5229 expanded->r_ybot = area->r_ybot - CIFCurStyle->cs_radius;
5230 }
5231 else clip->r_ybot = expanded->r_ybot = area->r_ybot;
5232 if (area->r_xtop < TiPlaneRect.r_xtop)
5233 {
5234 clip->r_xtop = area->r_xtop * CIFCurStyle->cs_scaleFactor;
5235 expanded->r_xtop = area->r_xtop + CIFCurStyle->cs_radius;
5236 }
5237 else clip->r_xtop = expanded->r_xtop = area->r_xtop;
5238 if (area->r_ytop < TiPlaneRect.r_ytop)
5239 {
5240 clip->r_ytop = area->r_ytop * CIFCurStyle->cs_scaleFactor;
5241 expanded->r_ytop = area->r_ytop + CIFCurStyle->cs_radius;
5242 }
5243 else clip->r_ytop = expanded->r_ytop = area->r_ytop;
5244 }
5245
5246 /*
5247 * ----------------------------------------------------------------------------
5248 *
5249 * CIFClearPlanes --
5250 *
5251 * This procedure clears out a collection of CIF planes.
5252 *
5253 * Results:
5254 * None.
5255 *
5256 * Side effects:
5257 * Each of the planes in "planes" is re-initialized to point to
5258 * an empty paint plane.
5259 *
5260 * ----------------------------------------------------------------------------
5261 */
5262
5263 void
CIFClearPlanes(planes)5264 CIFClearPlanes(planes)
5265 Plane **planes; /* Pointer to an array of MAXCIFLAYERS
5266 * planes.
5267 */
5268 {
5269 int i;
5270
5271 for (i = 0; i < MAXCIFLAYERS; i++)
5272 {
5273 if (planes[i] == NULL)
5274 {
5275 planes[i] = DBNewPlane((ClientData) TT_SPACE);
5276 }
5277 else
5278 {
5279 DBClearPaintPlane(planes[i]);
5280 }
5281 }
5282 }
5283