1 /*
2 * plotPS.c --
3 *
4 * This file contains procedures that generate PS-format files
5 * to describe a section of layout.
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/plot/plotPS.c,v 1.3 2010/06/24 12:37:25 tim Exp $";
22 #endif /* not lint */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
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 "utils/tech.h"
34 #include "utils/malloc.h"
35 #include "utils/utils.h"
36 #include "windows/windows.h"
37 #include "commands/commands.h"
38 #include "dbwind/dbwind.h"
39 #include "textio/textio.h"
40
41 /* Records of the following type are used to describe how to generate
42 * PS output for a particular set of mask layers. Each style
43 * describes the PS figures to draw for a particular set of
44 * layers. A single layer may participate in several ps styles.
45 */
46
47 typedef struct psstyle
48 {
49 TileTypeBitMask grs_layers; /* Layers to plot in this style. */
50 int grs_stipple; /* Index of fill to use. */
51 int grs_color; /* Index of color to use. */
52 struct psstyle *grs_next; /* Next style in chain. */
53 } PSStyle;
54
55 typedef struct pspattern
56 {
57 int index;
58 unsigned long stipple[8];
59 struct pspattern *pat_next;
60 } PSPattern;
61
62 typedef struct pscolor
63 {
64 int index;
65 unsigned char color[4];
66 struct pscolor *col_next;
67 } PSColor;
68
69
70 static PSStyle *plotPSStyles = NULL;
71 static PSPattern *plotPSPatterns = NULL;
72 static PSColor *plotPSColors = NULL;
73
74 int delta, xnmargin, ynmargin, xpmargin, ypmargin;
75 float fscale;
76
77 /* Most of the grs_stipple values are PS stipple numbers. However,
78 * if a grs_stipple value is less than zero, it means something special.
79 * The definitions below give the possible alternatives:
80 *
81 * CROSS: Draw a thick outline around the tile with
82 * a cross through it (used for contacts).
83 * BORDER: Same as CROSS, except draw the outline with
84 * no cross through it.
85 * SOLID: This is the same as a solid stipple but renders
86 * much faster.
87 */
88
89 #define CROSS -1
90 #define BORDER -2
91 #define SOLID -3
92
93 /* The definitions below give the integers used for various PS
94 * line drawing styles (brushes).
95 */
96
97 #define PS_THIN 1
98 #define PS_MEDIUM 2
99 #define PS_THICK 3
100
101 /* The variables below are used to pass information from the top-level
102 * procedure PlotPS down to the lower-level search functions
103 * that are invoked for pieces of the layout.
104 */
105
106 static FILE *file; /* File to use for output. */
107 static PSStyle *curStyle; /* Current style being output. */
108 static PSColor *curColor; /* Current color being output. */
109 static PSPattern *curPattern; /* Current pattern being output. */
110 static int curLineWidth; /* Current line width */
111 static int curFont; /* Current font */
112 static TileTypeBitMask curMask; /* Layers currently being searched: this
113 * is the AND of the mask from curStyle and
114 * the layers that the user specified.
115 */
116 static Rect bbox; /* Bounding box, in root coordinates, of
117 * area being plotted.
118 */
119
120 /* Parameters passed to the plotting process */
121
122 static char *defaultBoldFont = "/HelveticaBold";
123 static char *defaultFont = "/Helvetica";
124 char *PlotPSIdFont = NULL;
125 char *PlotPSNameFont = NULL;
126 char *PlotPSLabelFont = NULL;
127 int PlotPSIdSize = 8;
128 int PlotPSNameSize = 12;
129 int PlotPSLabelSize = 12;
130 int PlotPSBoundary = 1; /* Print boundaries around all layers */
131 int PlotPSHeight = 792; /* 11 inches * 72 PS units/inch */
132 int PlotPSWidth = 612; /* 8.5 inches */
133 int PlotPSMargin = 72; /* 1 inch */
134
135 int curx1, curx2, cury1, cury2; /* Last encountered line */
136 int curxbot, curybot, curwidth, curheight; /* Last encountered rectangle */
137
138 /*
139 * ----------------------------------------------------------------------------
140 *
141 * PSReset()
142 *
143 * Plot optimization: Reset buffered line and rectangle to default values
144 *
145 * ----------------------------------------------------------------------------
146 */
147
148 void
PSReset()149 PSReset()
150 {
151 curxbot = curybot = curwidth = curheight = -2;
152 curx1 = curx2 = cury1 = cury2 = -2;
153 }
154
155
156 /*
157 * ----------------------------------------------------------------------------
158 * PlotPSTechInit --
159 *
160 * Called once at beginning of technology file read-in to initialize
161 * data structures.
162 *
163 * Results:
164 * None.
165 *
166 * Side effects:
167 * Clears out the list of things to plot.
168 * ----------------------------------------------------------------------------
169 */
170
171 void
PlotPSTechInit()172 PlotPSTechInit()
173 {
174 int i, j;
175 PSStyle *style;
176 PSColor *color;
177 PSPattern *pattern;
178
179 /* Clear out any old information */
180
181 for (style = plotPSStyles; style != NULL; style = style->grs_next)
182 {
183 freeMagic((char *) style);
184 }
185 plotPSStyles = NULL;
186
187 for (pattern = plotPSPatterns; pattern != NULL; pattern = pattern->pat_next)
188 {
189 freeMagic((char *) pattern);
190 }
191 plotPSPatterns = NULL;
192
193 for (color = plotPSColors; color != NULL; color = color->col_next)
194 {
195 freeMagic((char *) color);
196 }
197 plotPSColors = NULL;
198
199 if (!PlotPSIdFont)
200 StrDup(&PlotPSIdFont, defaultFont);
201 if (!PlotPSNameFont)
202 StrDup(&PlotPSNameFont, defaultBoldFont);
203 if (!PlotPSLabelFont)
204 StrDup(&PlotPSLabelFont, defaultFont);
205 }
206
207 /*
208 * ----------------------------------------------------------------------------
209 * PlotPSTechLine --
210 *
211 * This procedure is invoked by the technology module once for
212 * each line in the "ps" subsection of the "plot" section
213 * of the technology file.
214 *
215 * Results:
216 * Always returns TRUE (otherwise the technology module would
217 * abort Magic with a fatal error).
218 *
219 * Side effects:
220 * Builds up the table of PS styles.
221 * ----------------------------------------------------------------------------
222 */
223
224 bool
PlotPSTechLine(sectionName,argc,argv)225 PlotPSTechLine(sectionName, argc, argv)
226 char *sectionName; /* Name of this section (unused). */
227 int argc; /* Number of arguments on line. */
228 char *argv[]; /* Pointers to fields of line. */
229 {
230 PSStyle *newstyle;
231 PSColor *newcolor;
232 PSPattern *newpattern;
233 int i, color, stipple;
234
235 if (argc != 9 && argc != 5 && argc != 3)
236 {
237 TechError("\"ps\" lines must have either 9, 5, or 3 arguments.\n");
238 return TRUE;
239 }
240
241 if (argc == 9) /* pattern definition */
242 {
243 newpattern = (PSPattern *) mallocMagic(sizeof(PSPattern));
244 sscanf(argv[0], "%d", &(newpattern->index));
245 for(i = 0; i < 8; i++)
246 {
247 sscanf(argv[1 + i], "%08lx", &(newpattern->stipple[i]));
248 }
249 newpattern->pat_next = plotPSPatterns;
250 plotPSPatterns = newpattern;
251 }
252 else if (argc == 5) /* color definition */
253 {
254 int tmpint;
255 newcolor = (PSColor *) mallocMagic(sizeof(PSColor));
256 sscanf(argv[0], "%d", &(newcolor->index));
257 for(i = 0; i < 4; i++)
258 {
259 sscanf(argv[1 + i], "%d", &tmpint);
260 newcolor->color[i] = (unsigned char)(tmpint & 0xff);
261 }
262 newcolor->col_next = plotPSColors;
263 plotPSColors = newcolor;
264 }
265 else { /* 3 args: layer definition */
266 if (!StrIsInt(argv[1]))
267 {
268 TechError("2nd field must be an integer\n");
269 return TRUE;
270 }
271 color = atoi(argv[1]);
272
273 if (strcmp(argv[2], "X") == 0)
274 stipple = CROSS;
275 else if (strcmp(argv[2], "B") == 0)
276 stipple = BORDER;
277 else if (strcmp(argv[2], "S") == 0)
278 stipple = SOLID;
279 else
280 {
281 if (!StrIsInt(argv[2]))
282 {
283 TechError("3rd field must be an integer or \"S\", \"X\", or \"B\".\n");
284 return TRUE;
285 }
286 stipple = atoi(argv[2]);
287 }
288
289 newstyle = (PSStyle *) mallocMagic(sizeof(PSStyle));
290
291 DBTechNoisyNameMask(argv[0], &newstyle->grs_layers);
292
293 /* Replace non-primary contact images with primary images. */
294
295 for (i = TT_TECHDEPBASE; i < DBNumTypes; i++)
296 {
297 if TTMaskHasType(&newstyle->grs_layers, i)
298 TTMaskSetMask(&newstyle->grs_layers, &DBLayerTypeMaskTbl[i]);
299 }
300 TTMaskAndMask(&newstyle->grs_layers, &DBUserLayerBits);
301 newstyle->grs_stipple = stipple;
302 newstyle->grs_color = color;
303 newstyle->grs_next = plotPSStyles;
304 plotPSStyles = newstyle;
305 }
306
307 return TRUE;
308 }
309
310 /*
311 * ----------------------------------------------------------------------------
312 *
313 * plotPSFlushRect()
314 *
315 * Plot optimization: Draw last buffered rectangle.
316 *
317 * ----------------------------------------------------------------------------
318 */
319
320 void
plotPSFlushRect(style)321 plotPSFlushRect(style)
322 int style;
323 {
324 if (curwidth > 0)
325 {
326 if (style == SOLID)
327 fprintf(file, "%d %d %d %d ms\n", curxbot, curybot,
328 curwidth, curheight);
329 else
330 fprintf(file, "%d %d %d %d fb\n", curxbot, curybot,
331 curxbot + curwidth, curybot + curheight);
332 }
333 }
334
335 /*
336 * ----------------------------------------------------------------------------
337 *
338 * plotPSFlushLine()
339 *
340 * Plot optimization: Draw last buffered line.
341 *
342 * ----------------------------------------------------------------------------
343 */
344
345 void
plotPSFlushLine()346 plotPSFlushLine()
347 {
348 if (cury1 == cury2)
349 {
350 if (curx1 != curx2) /* true only if nothing is buffered */
351 fprintf(file, "%d %d %d hl\n", curx2 - curx1, curx1, cury1);
352 }
353 else if (curx1 == curx2)
354 fprintf(file, "%d %d %d vl\n", cury2 - cury1, curx1, cury1);
355 else
356 fprintf(file, "%d %d %d %d ml\n", curx1, cury1, curx2, cury2);
357 }
358
359
360 /*
361 * ----------------------------------------------------------------------------
362 *
363 * plotPSLine --
364 *
365 * Outputs a line into the current PS file.
366 *
367 * Results:
368 * None.
369 *
370 * Side effects:
371 * I/O.
372 *
373 * ----------------------------------------------------------------------------
374 */
375
376 void
plotPSLine(p1,p2)377 plotPSLine(p1, p2)
378 Point *p1, *p2; /* Endpoints of line, given in root
379 * coordinates.
380 */
381 {
382 int x1, x2, y1, y2, limit, diff;
383 bool tmptf;
384
385 /* Clip the line to the rectangular area being output. First,
386 * arrange for the first x-coordinate to be the smaller, then
387 * clip against vertical lines at the x-boundaries.
388 */
389
390 if (p1->p_x <= p2->p_x)
391 {
392 x1 = p1->p_x - bbox.r_xbot;
393 x2 = p2->p_x - bbox.r_xbot;
394 y1 = p1->p_y - bbox.r_ybot;
395 y2 = p2->p_y - bbox.r_ybot;
396 }
397 else
398 {
399 x1 = p2->p_x - bbox.r_xbot;
400 x2 = p1->p_x - bbox.r_xbot;
401 y1 = p2->p_y - bbox.r_ybot;
402 y2 = p1->p_y - bbox.r_ybot;
403 }
404 limit = bbox.r_xtop - bbox.r_xbot;
405 if ((x1 > limit) || (x2 < 0)) return;
406
407 /* Now clip against horizontal lines at the y-boundaries. */
408
409 if (y2 < y1)
410 {
411 float tmp;
412 tmp = y2; y2 = y1; y1 = tmp;
413 tmp = x2; x2 = x1; x1 = tmp;
414 }
415 limit = bbox.r_ytop - bbox.r_ybot;
416 if ((y1 > limit) || (y2 < 0)) return;
417
418 /* compare against last output line and merge if possible */
419 if (((x1 == x2) && (x1 == curx1) && (x2 == curx2)
420 && ((tmptf = (y1 == cury2)) || (y2 == cury1))))
421 {
422 if (tmptf) cury2 = y2;
423 else cury1 = y1;
424 }
425 else if (((y1 == y2) && (y1 == cury1) && (y2 == cury2)
426 && ((tmptf = (x1 == curx2)) || (x2 == curx1))))
427 {
428 if (tmptf) curx2 = x2;
429 else curx1 = x1;
430 }
431 else
432 {
433 plotPSFlushLine();
434 curx1 = x1;
435 curx2 = x2;
436 cury1 = y1;
437 cury2 = y2;
438 }
439 }
440
441
442 /*
443 * ----------------------------------------------------------------------------
444 *
445 * plotPSRect --
446 *
447 * Outputs PS statements to draw a rectangular area as
448 * an outline with a given line style.
449 *
450 * Results:
451 * None.
452 *
453 * Side effects:
454 * Adds information to the current PS file.
455 *
456 * ----------------------------------------------------------------------------
457 */
458
459 void
plotPSRect(rect,style)460 plotPSRect(rect, style)
461 Rect *rect; /* Rectangle to be drawn, in root coords. */
462 int style;
463 {
464 int x, y, w, h;
465
466 /* Output all boxes with any part visible. Depend on PostScript to */
467 /* do the clipping of any boxes crossing the plot boundary. */
468
469 x = rect->r_xbot - bbox.r_xbot;
470 if ((x < 0) || (rect->r_xbot > bbox.r_xtop)) return;
471 w = rect->r_xtop - rect->r_xbot;
472 y = rect->r_ybot - bbox.r_ybot;
473 if ((y < 0) || (rect->r_ybot > bbox.r_ytop)) return;
474 h = rect->r_ytop - rect->r_ybot;
475
476 fprintf(file, "%d %d %d %d m%c\n", x, y, w, h, (style == CROSS) ? 'x' :
477 (style == SOLID) ? 's' : 'r');
478 }
479
480
481 /*
482 * ----------------------------------------------------------------------------
483 *
484 * plotPSPaint --
485 *
486 * This procedure is invoked once for each paint rectangle in
487 * the area being plotted.
488 *
489 * Results:
490 * Always returns 0 to keep the search alive.
491 *
492 * Side effects:
493 * Outputs information for the tile, including stipple for its
494 * interior, and a solid line for any portion of the boundary
495 * of the tile that is adjacent to a tile NOT in this style.
496 *
497 * ----------------------------------------------------------------------------
498 */
499
500 int
plotPSPaint(tile,cxp)501 plotPSPaint(tile, cxp)
502 Tile *tile; /* Tile that's of type to be output. */
503 TreeContext *cxp; /* Describes search in progress. */
504 {
505 Rect tileArea, edge, rootArea;
506 int xbot, width, ybot, height;
507 Tile *neighbor;
508 SearchContext *scx = cxp->tc_scx;
509 bool tmptf;
510 TileType ntype;
511
512 /* First transform tile coords to root coords */
513
514 TiToRect(tile, &tileArea);
515 GeoTransRect(&scx->scx_trans, &tileArea, &rootArea);
516
517 /* See if this tile gets special handling. */
518
519 if ((curStyle->grs_stipple == CROSS) || (curStyle->grs_stipple == BORDER))
520 {
521 /* Draw tile as a thick outline with a cross from corner
522 * to corner, and skip the rest of this procedure.
523 */
524
525 Point ul, lr;
526
527 if (curLineWidth != PS_MEDIUM) {
528 fprintf(file, "l2\n");
529 curLineWidth = PS_MEDIUM;
530 }
531
532 plotPSRect(&rootArea, curStyle->grs_stipple);
533 return 0;
534 }
535
536 /* If this is a triangle, output the last rect and deal with this one */
537 /* individually. */
538
539 if (IsSplit(tile))
540 {
541 int np, i, j;
542 TileType dinfo;
543 Point polyp[5];
544
545 plotPSFlushRect(curStyle->grs_stipple);
546 plotPSFlushLine();
547 PSReset();
548
549 /* Side and direction are altered by geometric transformations */
550
551 dinfo = DBTransformDiagonal(TiGetTypeExact(tile), &scx->scx_trans);
552
553 /* Use GrClipTriangle() routine to get the n-sided polygon that */
554 /* results from clipping a triangle to the clip region. */
555
556 GrClipTriangle(&rootArea, &bbox, TRUE, dinfo, polyp, &np);
557 for (i = 0; i < np; i++)
558 {
559 polyp[i].p_x -= bbox.r_xbot;
560 polyp[i].p_y -= bbox.r_ybot;
561 fprintf(file, "%d %d ", polyp[i].p_x, polyp[i].p_y);
562 }
563 fprintf(file, "%d tb\n", np);
564
565 if (PlotPSBoundary)
566 {
567 if (curLineWidth != PS_THIN) {
568 fprintf(file, "l1\n");
569 curLineWidth = PS_THIN;
570 }
571
572 /* Diagonal is always drawn */
573
574 for (i = 0; i < np; i++)
575 {
576 j = (i + 1) % np;
577 if (polyp[i].p_x != polyp[j].p_x &&
578 polyp[i].p_y != polyp[j].p_y)
579 {
580 fprintf(file, "%d %d %d %d ml\n", polyp[i].p_x, polyp[i].p_y,
581 polyp[j].p_x, polyp[j].p_y);
582 break;
583 }
584 }
585 }
586 }
587 else
588 {
589
590 /* This tile gets "normal" processing (i.e. stippling and outlining).
591 * Clip it to the plotting area and output.
592 */
593
594 GeoClip(&rootArea, &bbox);
595 xbot = rootArea.r_xbot - bbox.r_xbot;
596 width = rootArea.r_xtop - rootArea.r_xbot;
597 ybot = rootArea.r_ybot - bbox.r_ybot;
598 height = rootArea.r_ytop - rootArea.r_ybot;
599
600 /* compare against last output rectangle and merge if possible */
601 if ((width == curwidth) && (xbot == curxbot) && ((tmptf = (ybot == curybot
602 + curheight)) || (ybot + height == curybot)))
603 {
604 curheight += height;
605 if (!tmptf) curybot = ybot;
606 }
607 else if ((height == curheight) && (ybot == curybot) && ((tmptf = (xbot
608 == curxbot + curwidth)) || (xbot + width == curxbot)))
609 {
610 curwidth += width;
611 if (!tmptf) curxbot = xbot;
612 }
613 else
614 {
615 plotPSFlushRect(curStyle->grs_stipple);
616 curheight = height;
617 curwidth = width;
618 curxbot = xbot;
619 curybot = ybot;
620 }
621
622 if (PlotPSBoundary && (curLineWidth != PS_THIN)) {
623 fprintf(file, "l1\n");
624 curLineWidth = PS_THIN;
625 }
626 }
627
628 if (!PlotPSBoundary) return 0; /* No borders */
629
630 /* Now output lines for any edges between material of the type
631 * currently being drawn and material of other types. This is
632 * done by searching along the tile's borders for neighbors that
633 * have the wrong types. First, search the tile's bottom border
634 * (unless it is at infinity).
635 *
636 * (This code is essentially a duplicate of selRedisplayFunc())
637 */
638
639 if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
640 goto searchleft; /* nothing on bottom of split */
641
642 if (tileArea.r_ybot > TiPlaneRect.r_ybot)
643 {
644 edge.r_ybot = edge.r_ytop = tileArea.r_ybot;
645 for (neighbor = LB(tile); LEFT(neighbor) < tileArea.r_xtop;
646 neighbor = TR(neighbor))
647 {
648 ntype = TiGetTopType(neighbor);
649 if (TTMaskHasType(&curMask, ntype)) continue;
650 edge.r_xbot = LEFT(neighbor);
651 edge.r_xtop = RIGHT(neighbor);
652 if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot;
653 if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop;
654 GeoTransRect(&scx->scx_trans, &edge, &rootArea);
655 plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
656 }
657 }
658
659 /* Now go along the tile's left border, doing the same thing. Ignore
660 * edges that are at infinity.
661 */
662
663 searchleft:
664 if (IsSplit(tile) && SplitSide(tile))
665 goto searchtop; /* Nothing on left side of tile */
666
667 if (tileArea.r_xbot > TiPlaneRect.r_xbot)
668 {
669 edge.r_xbot = edge.r_xtop = tileArea.r_xbot;
670 for (neighbor = BL(tile); BOTTOM(neighbor) < tileArea.r_ytop;
671 neighbor = RT(neighbor))
672 {
673 ntype = TiGetRightType(neighbor);
674 if (TTMaskHasType(&curMask, ntype)) continue;
675 edge.r_ybot = BOTTOM(neighbor);
676 edge.r_ytop = TOP(neighbor);
677 if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot;
678 if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop;
679 GeoTransRect(&scx->scx_trans, &edge, &rootArea);
680 plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
681 }
682 }
683
684 /* Same thing for the tile's top border. */
685
686 searchtop:
687 if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile)))
688 goto searchright; /* Nothing on top side of tile */
689
690 if (tileArea.r_ytop < TiPlaneRect.r_ytop)
691 {
692 edge.r_ybot = edge.r_ytop = tileArea.r_ytop;
693 for (neighbor = RT(tile); RIGHT(neighbor) > tileArea.r_xbot;
694 neighbor = BL(neighbor))
695 {
696 ntype = TiGetBottomType(neighbor);
697 if (TTMaskHasType(&curMask, ntype)) continue;
698 edge.r_xbot = LEFT(neighbor);
699 edge.r_xtop = RIGHT(neighbor);
700 if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot;
701 if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop;
702 GeoTransRect(&scx->scx_trans, &edge, &rootArea);
703 plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
704 }
705 }
706
707 /* Finally, the right border. */
708
709 searchright:
710 if (IsSplit(tile) && !SplitSide(tile))
711 return 0; /* Nothing on right side of tile */
712
713 if (tileArea.r_xtop < TiPlaneRect.r_xtop)
714 {
715 edge.r_xbot = edge.r_xtop = tileArea.r_xtop;
716 for (neighbor = TR(tile); TOP(neighbor) > tileArea.r_ybot;
717 neighbor = LB(neighbor))
718 {
719 ntype = TiGetLeftType(neighbor);
720 if (TTMaskHasType(&curMask, ntype)) continue;
721 edge.r_ybot = BOTTOM(neighbor);
722 edge.r_ytop = TOP(neighbor);
723 if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot;
724 if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop;
725 GeoTransRect(&scx->scx_trans, &edge, &rootArea);
726 plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
727 }
728 }
729
730 return 0;
731 }
732
733
734 /*
735 * ----------------------------------------------------------------------------
736 *
737 * plotPSLabelPosition --
738 *
739 * Determine the label position, orientation, and approximate bounding box
740 *
741 * ----------------------------------------------------------------------------
742 */
743
744 int
plotPSLabelPosition(scx,label,x,y,p)745 plotPSLabelPosition(scx, label, x, y, p)
746 SearchContext *scx; /* Describes state of search when label
747 * was found.
748 */
749 Label *label; /* Label that was found. */
750 int *x; /* returned x position */
751 int *y; /* returned y position */
752 int *p; /* returned orientation */
753 {
754 Rect rootArea;
755 int pos;
756
757 /* Mapping from our GEO_xxx positions to PS object types: */
758
759 static int psPosition[] =
760 {
761 5, /* CENTCENT */
762 1, /* TOPCENT */
763 0, /* TOPRIGHT */
764 4, /* CENTRIGHT */
765 12, /* BOTRIGHT */
766 13, /* BOTCENT */
767 15, /* BOTLEFT */
768 7, /* CENTLEFT */
769 3 /* TOPLEFT */
770 };
771
772 GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea);
773 pos = GeoTransPos(&scx->scx_trans, label->lab_just);
774 switch (pos)
775 {
776 case GEO_NORTH:
777 case GEO_NORTHEAST:
778 case GEO_NORTHWEST:
779 *y = (rootArea.r_ytop - bbox.r_ybot);
780 *y += delta;
781 break;
782
783 case GEO_CENTER:
784 case GEO_WEST:
785 case GEO_EAST:
786 *y = (rootArea.r_ytop + rootArea.r_ybot) / 2 - bbox.r_ybot;
787 break;
788
789 case GEO_SOUTH:
790 case GEO_SOUTHEAST:
791 case GEO_SOUTHWEST:
792 *y = (rootArea.r_ybot - bbox.r_ybot);
793 *y -= delta;
794 break;
795 }
796 switch (pos)
797 {
798 case GEO_WEST:
799 case GEO_NORTHWEST:
800 case GEO_SOUTHWEST:
801 *x = (rootArea.r_xbot - bbox.r_xbot);
802 *x -= delta;
803 break;
804
805 case GEO_CENTER:
806 case GEO_NORTH:
807 case GEO_SOUTH:
808 *x = (rootArea.r_xtop + rootArea.r_xbot) / 2 - bbox.r_xbot;
809 break;
810
811 case GEO_EAST:
812 case GEO_NORTHEAST:
813 case GEO_SOUTHEAST:
814 *x = (rootArea.r_xtop - bbox.r_xbot);
815 *x += delta;
816 break;
817 }
818 *p = psPosition[pos];
819 return 0;
820 }
821
822
823 /*
824 * ----------------------------------------------------------------------------
825 *
826 * plotPSLabelBounds --
827 *
828 * Estimate the bounding box extension based on label strings.
829 * In reality, we need to know label sizes to compute the scale,
830 * and we need to know the scale to compute label sizes. However,
831 * in practice, we can only estimate the label size anyway, so we
832 * allow for some slop and just wing it.
833 *
834 * ----------------------------------------------------------------------------
835 */
836
837 #define AVGCHARWIDTH 0.7
838 #define CHARHEIGHT 1.4
839
840 int
plotPSLabelBounds(scx,label)841 plotPSLabelBounds(scx, label)
842 SearchContext *scx; /* Describes state of search when label
843 * was found.
844 */
845 Label *label; /* Label that was found. */
846 {
847 int pspos;
848 int ls, psxsize, psysize;
849 int llx, lly, urx, ury;
850 int psdelta = (int)((float)delta / fscale);
851
852 plotPSLabelPosition(scx, label, &llx, &lly, &pspos);
853 urx = (int)((float)(llx - bbox.r_xtop) / fscale);
854 ury = (int)((float)(lly - bbox.r_ytop) / fscale);
855 llx = (int)((float)(bbox.r_xbot - llx) / fscale);
856 lly = (int)((float)(bbox.r_ybot - lly) / fscale);
857 ls = strlen(label->lab_text);
858
859 psxsize = ls * (int)((float)PlotPSLabelSize * AVGCHARWIDTH);
860 psysize = (int)((float)PlotPSLabelSize * CHARHEIGHT);
861
862 switch (pspos) {
863 case 0:
864 ury += psysize + psdelta;
865 urx += psxsize + psdelta;
866 break;
867 case 4:
868 ury += psysize / 2;
869 lly += psysize / 2;
870 urx += psxsize + psdelta;
871 break;
872 case 12:
873 lly += psysize + psdelta;
874 urx += psxsize + psdelta;
875 break;
876 case 13:
877 lly += psysize + psdelta;
878 urx += psxsize / 2;
879 llx += psxsize / 2;
880 break;
881 case 15:
882 lly += psysize + psdelta;
883 llx += psxsize + psdelta;
884 break;
885 case 7:
886 ury += psysize / 2;
887 lly += psysize / 2;
888 llx += psxsize + psdelta;
889 break;
890 case 3:
891 ury += psysize + psdelta;
892 llx += psxsize + psdelta;
893 break;
894 case 1:
895 ury += psysize + psdelta;
896 urx += psxsize / 2;
897 llx += psxsize / 2;
898 break;
899 case 5:
900 ury += psysize / 2;
901 lly += psysize / 2;
902 urx += psxsize / 2;
903 llx += psxsize / 2;
904 break;
905 }
906
907 if (xpmargin < urx) xpmargin = urx;
908 if (ypmargin < ury) ypmargin = ury;
909 if (xnmargin < llx) xnmargin = llx;
910 if (ynmargin < lly) ynmargin = lly;
911
912 return 0;
913 }
914
915 /*
916 * ----------------------------------------------------------------------------
917 *
918 * plotPSLabelBox --
919 *
920 * Output the box connected to a label
921 *
922 * ----------------------------------------------------------------------------
923 */
924
925 int
plotPSLabelBox(scx,label)926 plotPSLabelBox(scx, label)
927 SearchContext *scx; /* Describes state of search when label
928 * was found.
929 */
930 Label *label; /* Label that was found. */
931 {
932 Rect rootArea;
933 int x, y;
934
935 GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea);
936
937 /* Output lines marking the label's area. Different things are
938 * done depending on whether the label is a point, a line, or an
939 * area.
940 */
941
942 if (curLineWidth != PS_MEDIUM) {
943 fprintf(file, "l2\n");
944 curLineWidth = PS_MEDIUM;
945 }
946
947 if ((rootArea.r_xbot == rootArea.r_xtop) &&
948 (rootArea.r_ybot == rootArea.r_ytop))
949 {
950 /* Point label. Output a cross. */
951
952 x = (rootArea.r_xbot - bbox.r_xbot);
953 y = (rootArea.r_ybot - bbox.r_ybot);
954 fprintf(file, "%d %d %d pl\n", delta, x, y);
955 }
956 else if ((rootArea.r_xbot == rootArea.r_xtop) ||
957 (rootArea.r_ybot == rootArea.r_ytop))
958 {
959 /* Line label. Just draw a medium-thickness line. */
960
961 plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
962 }
963 else
964 {
965 /* Rectangular. Draw lines around the boundary. */
966
967 plotPSRect(&rootArea, 0);
968 }
969 return 0;
970 }
971
972 /*
973 * ----------------------------------------------------------------------------
974 *
975 * plotPSLabel --
976 *
977 * This procedure is invoked once for each label overlapping the
978 * area being plotted. It generates PS output to describe
979 * the label.
980 *
981 * Results:
982 * Always returns 0 to keep the search from aborting.
983 *
984 * Side effects:
985 * PS information is output.
986 *
987 * ----------------------------------------------------------------------------
988 */
989
990 int
plotPSLabel(scx,label)991 plotPSLabel(scx, label)
992 SearchContext *scx; /* Describes state of search when label
993 * was found.
994 */
995 Label *label; /* Label that was found. */
996 {
997 int x, y;
998 int pspos;
999
1000 plotPSLabelPosition(scx, label, &x, &y, &pspos);
1001
1002 /* Output the text for the label, if the label is within delta
1003 * of the area we're plotting (a large label could overlap a
1004 * bit of the area but stick out way off-screen too).
1005 */
1006
1007 if ((x >= -delta) && (y >= -delta) &&
1008 (x <= (bbox.r_xtop - bbox.r_xbot) + delta) &&
1009 (y <= (bbox.r_ytop - bbox.r_ybot) + delta))
1010 {
1011 fprintf(file, "(%s) %d %d %d lb\n", label->lab_text, pspos, x, y);
1012 }
1013 return 0;
1014 }
1015
1016 /*
1017 * ----------------------------------------------------------------------------
1018 *
1019 * plotPSCell --
1020 *
1021 * This procedure is invoked once for each unexpanded cell that
1022 * overlaps the area being plotted.
1023 *
1024 * Results:
1025 * Always returns 0 to keep the search from aborting.
1026 *
1027 * Side effects:
1028 * PS information is output to describe the cell.
1029 *
1030 * ----------------------------------------------------------------------------
1031 */
1032
1033 int
plotPSCell(scx)1034 plotPSCell(scx)
1035 SearchContext *scx; /* Describes cell whose bbox is to
1036 * be plotted.
1037 */
1038 {
1039 extern bool PlotShowCellNames;
1040 char idName[100];
1041 Rect rootArea;
1042 CellDef *def;
1043 int x, y;
1044
1045 /* Convert the cell's bounding box to root coordinates and then
1046 * draw as a thick outline.
1047 */
1048
1049 def = scx->scx_use->cu_def;
1050 GeoTransRect(&scx->scx_trans, &def->cd_bbox, &rootArea);
1051 if (curLineWidth != PS_THICK) {
1052 fprintf(file, "l3\n");
1053 curLineWidth = PS_THICK;
1054 }
1055 plotPSRect(&rootArea, 0);
1056
1057 if (!PlotShowCellNames)
1058 return 0;
1059
1060 /* Output the cell definition's name in the top of the bounding box.
1061 * Use a bold font (#3), in a medium size (#2). Make sure that the
1062 * name's positioning point is within the area we're plotting.
1063 */
1064
1065 x = (rootArea.r_xtop + rootArea.r_xbot - 2*bbox.r_xbot)/2;
1066 y = (2*rootArea.r_ytop + rootArea.r_ybot - 3*bbox.r_ybot)/3;
1067 if ((x >= 0) && (y >= 0) &&
1068 (x <= (bbox.r_xtop - bbox.r_xbot)) &&
1069 (y <= (bbox.r_ytop - bbox.r_ybot)))
1070 {
1071 fprintf(file, "f2 (%s) 5 %d %d lb\n", def->cd_name, x, y);
1072 }
1073
1074 /* Output the cell id in the bottom of the bounding box.
1075 * Use an italic font (#2) in a medium size (#2).
1076 */
1077
1078 x = (rootArea.r_xtop + rootArea.r_xbot - 2*bbox.r_xbot)/2;
1079 y = (rootArea.r_ytop + 2*rootArea.r_ybot - 3*bbox.r_ybot)/3;
1080 if ((x >= 0) && (y >= 0) &&
1081 (x <= (bbox.r_xtop - bbox.r_xbot)) &&
1082 (y <= (bbox.r_ytop - bbox.r_ybot)))
1083 {
1084 (void) DBPrintUseId(scx, idName, 100, TRUE);
1085 fprintf(file, "f3 (%s) 5 %d %d lb\n", idName, x, y);
1086 }
1087
1088 return 0;
1089 }
1090
1091
1092 /*
1093 * ----------------------------------------------------------------------------
1094 *
1095 * PlotPS --
1096 *
1097 * This procedure generates a PS file to describe an area of
1098 * a layout.
1099 *
1100 * Results:
1101 * None.
1102 *
1103 * Side effects:
1104 * None.
1105 *
1106 * ----------------------------------------------------------------------------
1107 */
1108
1109 void
PlotPS(fileName,scx,layers,xMask)1110 PlotPS(fileName, scx, layers, xMask)
1111 char *fileName; /* Name of PS file to write. */
1112 SearchContext *scx; /* The use and area and transformation
1113 * in this describe what to plot.
1114 */
1115 TileTypeBitMask *layers; /* Tells what layers to plot. Only
1116 * paint layers in this mask, and also
1117 * expanded according to xMask, are
1118 * plotted. If L_LABELS is set, then
1119 * labels on the layers are also
1120 * plotted, if expanded according to
1121 * xMask. If L_CELL is set, then
1122 * subcells that are unexpanded
1123 * according to xMask are plotted as
1124 * bounding boxes.
1125 */
1126 int xMask; /* An expansion mask, used to indicate
1127 * the window whose expansion status
1128 * will be used to determine
1129 * visibility. Zero means treat
1130 * everything as expanded.
1131 */
1132 {
1133 int xsize, ysize;
1134 float yscale;
1135 FILE *infile;
1136 int i, j;
1137 int twidth, theight;
1138 char *fontptr, *fptr2, *fptr3;
1139 char line_in[100];
1140
1141 PSReset();
1142
1143 /* Compute a scale factor between our coordinates and PS
1144 * coordinates.
1145 */
1146
1147 GeoTransRect(&scx->scx_trans, &scx->scx_area, &bbox);
1148 xsize = bbox.r_xtop - bbox.r_xbot;
1149 ysize = bbox.r_ytop - bbox.r_ybot;
1150 fscale = (float)(PlotPSWidth - 2 * PlotPSMargin) / (float)xsize;
1151 yscale = (float)(PlotPSHeight - 2 * PlotPSMargin) / (float)ysize;
1152 if (yscale < fscale) fscale = yscale;
1153
1154 /* Compute a distance equal to 1/8th the size of a typical wire
1155 * (max of thicknesses of routing layers). This is used to offset
1156 * text from labels and to compute cross size for point labels.
1157 */
1158
1159 if (RtrMetalWidth > RtrPolyWidth)
1160 delta = RtrMetalWidth / 8;
1161 else delta = RtrPolyWidth / 8;
1162 if (delta == 0) delta = 1;
1163
1164 /* Go through labels once to estimate the bounding box, including labels */
1165
1166 xnmargin = ynmargin = xpmargin = ypmargin = 0;
1167 if (TTMaskHasType(layers, L_LABEL))
1168 {
1169 curMask = *layers;
1170 TTMaskSetType(&curMask, TT_SPACE);
1171 (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL,
1172 TF_LABEL_ATTACH, plotPSLabelBounds, (ClientData) NULL);
1173 fscale = (float)(PlotPSWidth - 2 * PlotPSMargin - xnmargin - xpmargin)
1174 / (float)(xsize);
1175 yscale = (float)(PlotPSHeight - 2 * PlotPSMargin - ynmargin - ypmargin)
1176 / (float)(ysize);
1177 if (yscale < fscale) fscale = yscale;
1178 }
1179 twidth = (xsize * fscale) + xnmargin + xpmargin;
1180 theight = (ysize * fscale) + ynmargin + ypmargin;
1181
1182 /* Open the PS file and output header information. */
1183
1184 file = PaOpen(fileName, "w", (char *) NULL, ".", (char *) NULL,
1185 (char **) NULL);
1186 if (file == NULL)
1187 {
1188 TxError("Couldn't write PS file \"%s\".\n", fileName);
1189 return;
1190 }
1191 fprintf(file, "%%!PS-Adobe-3.0 EPSF-3.0\n");
1192 fprintf(file, "%%%%BoundingBox: %d %d %d %d\n",
1193 PlotPSMargin, PlotPSMargin, twidth + PlotPSMargin,
1194 theight + PlotPSMargin);
1195 fontptr = PlotPSIdFont;
1196 fprintf(file, "%%%%DocumentNeededResources: font %s", fontptr);
1197 if (!Match(fptr2 = PlotPSNameFont, fontptr));
1198 fprintf(file, " font %s", fptr2);
1199 if (!Match(fptr3 = PlotPSLabelFont, fontptr))
1200 if (!Match(fptr3, fptr2))
1201 fprintf(file, " font %s", fptr3);
1202 fprintf(file, "\n");
1203 fprintf(file, "%%%%EndComments\n");
1204
1205 /* Insert the prolog here */
1206
1207 infile = PaOpen("magicps", "r", ".pro", ".", SysLibPath, NULL);
1208 if (infile != NULL)
1209 while(fgets(line_in, 99, infile) != NULL)
1210 fputs(line_in, file);
1211 else
1212 fprintf(file, "\npostscript_prolog_is_missing\n\n");
1213
1214 /* Insert the font definitions here. */
1215
1216 fprintf(file, "/f1 { %.3f %s sf } def\n", (float)PlotPSLabelSize / fscale,
1217 PlotPSLabelFont);
1218 fprintf(file, "/f2 { %.3f %s sf } def\n", (float)PlotPSNameSize / fscale,
1219 PlotPSNameFont);
1220 fprintf(file, "/f3 { %.3f %s sf } def\n", (float)PlotPSIdSize / fscale,
1221 PlotPSIdFont);
1222
1223 /* Insert the color and stipple definitions here. */
1224
1225 for (curColor = plotPSColors; curColor != NULL;
1226 curColor = curColor->col_next)
1227 {
1228 fprintf(file, "/col%d {%.3f %.3f %.3f %.3f sc} bind def\n",
1229 curColor->index,
1230 (float)curColor->color[0] / 255.0,
1231 (float)curColor->color[1] / 255.0,
1232 (float)curColor->color[2] / 255.0,
1233 (float)curColor->color[3] / 255.0);
1234 }
1235
1236 for (curPattern = plotPSPatterns; curPattern != NULL;
1237 curPattern = curPattern->pat_next)
1238 {
1239 fprintf(file, "{<");
1240 for (j = 0; j < 8; j++)
1241 fprintf(file, "%08lx%08lx", curPattern->stipple[j], curPattern->stipple[j]);
1242 fprintf(file, ">} %d dp\n", curPattern->index);
1243 }
1244
1245 fprintf(file, "%%%%EndResource\n%%%%EndProlog\n\n");
1246 fprintf(file, "%%%%Page: 1 1\n");
1247 fprintf(file, "/pgsave save def bop\n");
1248 fprintf(file, "%% 0 0 offsets\nninit\n");
1249 fprintf(file, "%d %d translate\n", PlotPSMargin + xnmargin, PlotPSMargin
1250 + ynmargin);
1251 fprintf(file, "%.3f %.3f scale\nminit\n", fscale, fscale);
1252 fprintf(file, "0 0 %d %d gsave rectclip\n", xsize, ysize);
1253 fprintf(file, "l2\nsp\n\n");
1254
1255 curLineWidth = PS_MEDIUM;
1256
1257 /* For each PS style, find all the paint layers that belong
1258 * to that style and put plot information into the file.
1259 */
1260
1261 for (curStyle = plotPSStyles; curStyle != NULL;
1262 curStyle = curStyle->grs_next)
1263 {
1264 fprintf(file, "col%d\n", curStyle->grs_color);
1265 if (curStyle->grs_stipple >= 0)
1266 fprintf(file, "%d sl\n", curStyle->grs_stipple);
1267 TTMaskAndMask3(&curMask, layers, &curStyle->grs_layers);
1268 (void) DBTreeSrTiles(scx, &curMask, xMask, plotPSPaint,
1269 (ClientData) NULL);
1270 plotPSFlushRect(curStyle->grs_stipple);
1271 plotPSFlushLine();
1272 PSReset();
1273 }
1274
1275 /* Output subcell bounding boxes, if they are wanted. */
1276
1277 if (TTMaskHasType(layers, L_CELL))
1278 {
1279 (void) DBTreeSrCells(scx, xMask, plotPSCell, (ClientData) NULL);
1280 plotPSFlushRect(BORDER);
1281 plotPSFlushLine();
1282 }
1283
1284 /* Output label boxes followed by labels */
1285
1286 if (TTMaskHasType(layers, L_LABEL))
1287 {
1288 curMask = *layers;
1289 TTMaskSetType(&curMask, TT_SPACE);
1290 (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL,
1291 TF_LABEL_ATTACH, plotPSLabelBox, (ClientData) NULL);
1292 plotPSFlushRect(BORDER);
1293 plotPSFlushLine();
1294 PSReset();
1295 fprintf(file, "grestore\n"); /* end clipping rectangle */
1296 fprintf(file, "f1 0 setgray\n"); /* set font, set color to black */
1297
1298 curMask = *layers;
1299 TTMaskSetType(&curMask, TT_SPACE);
1300 (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL,
1301 TF_LABEL_ATTACH, plotPSLabel, (ClientData) NULL);
1302 }
1303 else
1304 {
1305 fprintf(file, "grestore\n"); /* end clipping rectangle */
1306 }
1307
1308 /* Output trailer information into the file, and close it. */
1309
1310 fprintf(file, "pgsave restore showpage\n\n");
1311 fprintf(file, "%%%%Trailer\nMAGICsave restore\n%%%%EOF\n");
1312 fclose(file);
1313 return;
1314 }
1315