1 /*
2  * gdsreader - simple Calma parser/printer tool
3  * Copyright (C) 1999 Serban-Mihai Popescu, serbanp@ix.netcom.com
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <strings.h>
22 #include <math.h>
23 
24 #include <GDSstructs.h>
25 #include <GDSconsts.h>
26 #include <GDSglobals.h>
27 #include <GDSaux.h>
28 #include <GDStransf.h>
29 
30 /*
31  * Both PostScript and HPGL interpreters are faster when dealing with rectangles
32  */
33 static int
BoundaryIsRectangle(boundaryEl * boundary)34 BoundaryIsRectangle(boundaryEl *boundary)
35 {
36   if(boundary->numpoints != 5)
37     return 0;
38 
39   if(boundary->points[0].x != boundary->points[1].x)
40   {
41     if(boundary->points[0].y != boundary->points[1].y)
42       return 0;
43     if(boundary->points[0].x != boundary->points[3].x)
44       return 0;
45     if(boundary->points[2].x != boundary->points[1].x)
46       return 0;
47     if(boundary->points[2].y != boundary->points[3].y)
48       return 0;
49   }
50   else
51   {
52     if(boundary->points[0].y != boundary->points[3].y)
53       return 0;
54     if(boundary->points[2].y != boundary->points[1].y)
55       return 0;
56     if(boundary->points[2].x != boundary->points[3].x)
57       return 0;
58   }
59   return 1;
60 }
61 
62 bbox
GDSgetBoundaryBBox(boundaryEl * boundary)63 GDSgetBoundaryBBox(boundaryEl *boundary)
64 {
65   int i;
66   bbox bbx;
67 
68   bbx.ll.x = BIGVAL;
69   bbx.ll.y = BIGVAL;
70   bbx.ur.x = -BIGVAL;
71   bbx.ur.y = -BIGVAL;
72 
73   for(i = 0; i < boundary->numpoints; i++)
74   {
75     if(boundary->points[i].x < bbx.ll.x)
76       bbx.ll.x = boundary->points[i].x;
77     if(boundary->points[i].x > bbx.ur.x)
78       bbx.ur.x = boundary->points[i].x;
79 
80     if(boundary->points[i].y < bbx.ll.y)
81       bbx.ll.y = boundary->points[i].y;
82     if(boundary->points[i].y > bbx.ur.y)
83       bbx.ur.y = boundary->points[i].y;
84   }
85 
86   return bbx;
87 }
88 
89 void
BoundaryToHPGL(FILE * hpglfile,boundaryEl * boundary,PSStyle psStyle)90 BoundaryToHPGL(FILE *hpglfile, boundaryEl *boundary, PSStyle psStyle)
91 {
92   int i;
93 
94   if(boundary->layerptr->layerno != psStyle.gdsno)
95     return;
96 
97   if(BoundaryIsRectangle(boundary))
98   {
99     fprintf(hpglfile, "PU%d,%dER%d,%d",
100             boundary->points[0].x / InternalScaleFactor,
101             boundary->points[0].y / InternalScaleFactor,
102             (boundary->points[2].x - boundary->points[0].x) /
103              InternalScaleFactor,
104             (boundary->points[2].y - boundary->points[0].y) /
105              InternalScaleFactor);
106     if(psStyle.fill || psStyle.hatch)
107       fprintf(hpglfile, "PU%d,%dRR%d,%d",
108               boundary->points[0].x / InternalScaleFactor,
109               boundary->points[0].y / InternalScaleFactor,
110               (boundary->points[2].x - boundary->points[0].x) /
111                InternalScaleFactor,
112               (boundary->points[2].y - boundary->points[0].y) /
113                InternalScaleFactor);
114   }
115   else
116   {
117     fprintf(hpglfile, "PU%d,%dPM0",
118             boundary->points[0].x / InternalScaleFactor,
119             boundary->points[0].y / InternalScaleFactor);
120     for(i = 1; i < boundary->numpoints; i++)
121       fprintf(hpglfile, "PD%d,%d",
122               boundary->points[i].x / InternalScaleFactor,
123               boundary->points[i].y / InternalScaleFactor);
124     fprintf(hpglfile, "PM2EP");
125     if(psStyle.fill || psStyle.hatch)
126       fprintf(hpglfile, "FP");
127   }
128   fprintf(hpglfile, "\n");
129 }
130 
131 int
GDSgetBoundaryWinding(boundaryEl * boundary)132 GDSgetBoundaryWinding(boundaryEl *boundary)
133 {
134   bbox bbx;
135   coord xmin, ymin, ycut, x1, x2, y1, y2;
136   int i, imin;
137 
138   ymin = BIGVAL;
139 
140   bbx = GDSgetBoundaryBBox(boundary);
141 
142   xmin = bbx.ll.x + (bbx.ur.x - bbx.ll.x) / 2;
143   for(i = 0; i < boundary->numpoints - 1; i++)
144   {
145     x1 = boundary->points[i].x;
146     y1 = boundary->points[i].y;
147     x2 = boundary->points[i + 1].x;
148     y2 = boundary->points[i + 1].y;
149 
150     if(x1 == x2)
151       continue;
152     else if(boundary->points[i].x > boundary->points[i + 1].x)
153     {
154       x1 = boundary->points[i + 1].x;
155       y1 = boundary->points[i + 1].y;
156       x2 = boundary->points[i].x;
157       y2 = boundary->points[i].y;
158     }
159     else
160     {
161       x1 = boundary->points[i].x;
162       y1 = boundary->points[i].y;
163       x2 = boundary->points[i + 1].x;
164       y2 = boundary->points[i + 1].y;
165     }
166     if(x1 <= xmin && x2 >= xmin)
167       ycut = y1 + (coord)(((double)(y2 - y1)) * (xmin - x1) / (x2 - x1));
168     else
169       continue;
170     if(ycut < ymin)
171     {
172       ymin = ycut;
173       imin = i;
174     }
175   }
176   if(boundary->points[imin].x > boundary->points[imin + 1].x)
177     return 1;
178   else
179     return -1;
180 }
181 
182 
183 void
BoundaryToPS(FILE * psfile,boundaryEl * boundary,PSStyle psStyle)184 BoundaryToPS(FILE *psfile, boundaryEl *boundary, PSStyle psStyle)
185 {
186   int i;
187 
188   if(boundary->layerptr->layerno != psStyle.gdsno)
189     return;
190 
191   if(BoundaryIsRectangle(boundary))
192   {
193     fprintf(psfile, "%d %d %d %d rectstroke\n",
194             boundary->points[0].x / InternalScaleFactor,
195             boundary->points[0].y / InternalScaleFactor,
196             (boundary->points[2].x - boundary->points[0].x) / InternalScaleFactor,
197             (boundary->points[2].y - boundary->points[0].y) / InternalScaleFactor);
198   }
199   else
200   {
201     fprintf(psfile, "%d %d m\n",
202             boundary->points[boundary->numpoints - 1].x / InternalScaleFactor,
203             boundary->points[boundary->numpoints - 1].y / InternalScaleFactor);
204     for(i = boundary->numpoints - 2; i >= 0; i--)
205       fprintf(psfile, "%d %d l\n",
206               boundary->points[i].x / InternalScaleFactor,
207               boundary->points[i].y / InternalScaleFactor);
208     fprintf(psfile, "closepath stroke\n");
209   }
210   fprintf(psfile, "%d %d m\n",
211           boundary->points[boundary->numpoints - 1].x / InternalScaleFactor,
212           boundary->points[boundary->numpoints - 1].y / InternalScaleFactor);
213   for(i = boundary->numpoints - 2; i >= 0; i--)
214     fprintf(psfile, "%d %d l\n",
215             boundary->points[i].x / InternalScaleFactor,
216             boundary->points[i].y / InternalScaleFactor);
217   fprintf(psfile, "closepath\n");
218 
219   if(psStyle.fill)
220     fprintf(psfile, "fill\n");
221   if(psStyle.hatch)
222     fprintf(psfile, "/FONT%s findfont patternfill\n", psStyle.layername);
223 
224   return;
225 }
226 
227 void
BoundaryToPOV(FILE * povfile,boundaryEl * boundary,PSStyle psStyle)228 BoundaryToPOV(FILE *povfile, boundaryEl *boundary, PSStyle psStyle)
229 {
230   int i;
231   char *ts;
232   if(BoundaryIsRectangle(boundary)) /* Basically a box */
233   {
234     fprintf(povfile, " box { <%f,%f,%f> <%f,%f,%f>\n",
235      (double)(boundary->points[2].x),
236      psStyle.depth,
237      (double)(boundary->points[2].y),
238      (double)(boundary->points[0].x),
239      psStyle.depth-psStyle.thickness,
240      (double)(boundary->points[0].y));
241      fprintf(povfile,"  texture { %s }\n",
242            ts=GDSLayerToTEXName(boundary->layerptr));
243      fprintf(povfile, " }\n");
244      FREE(ts);
245   }
246   else
247   {
248 
249      fprintf(povfile, " prism {\n  linear_spline %f,%f,%d\n",psStyle.depth,
250                             psStyle.depth-psStyle.thickness,boundary->numpoints);
251      for(i=0 ;i < (boundary->numpoints)-1 ; i++)
252        fprintf(povfile, " <%f,%f>,\n",
253               (double)(boundary->points[i].x),
254               (double)(boundary->points[i].y));
255      fprintf(povfile, " <%f,%f>\n",
256               (double)(boundary->points[(boundary->numpoints)-1].x),
257               (double)(boundary->points[(boundary->numpoints)-1].y));
258      fprintf(povfile,"  texture { %s }\n",
259                  ts=GDSLayerToTEXName(boundary->layerptr));
260      fprintf(povfile,"}\n");
261      FREE(ts);
262   }
263   return;
264 }
265 
266 
267 /*
268  * Frees the cell contents and removes the layer list reference.
269  * The structure list reference has to be removed at the upper level.
270  */
271 void
GDSfreeBoundary(GDScell * cell)272 GDSfreeBoundary(GDScell *cell)
273 {
274   GDScell *cellptr;
275 
276   if(cell == NULL)
277     return;
278   if(cell->type != BOUNDARY)
279     return;
280 
281   if(cell == cell->detail.boundary->layerptr->cells)
282     cell->detail.boundary->layerptr->cells = cell->next;
283   else
284   {
285     for(cellptr = cell->detail.boundary->layerptr->cells;
286         cellptr->next != NULL; cellptr = cellptr->next)
287     {
288       if(cellptr->next == cell)
289       {
290         cellptr->next = cellptr->next->next;
291         break;
292       }
293     }
294     if(cellptr == NULL)
295       fprintf(stderr, "Oops! GDSfreeBoundary(): Missing cell in layerptr\n");
296   }
297   FREE(cell->detail.boundary->points);
298   FREE(cell->detail.boundary);
299   return;
300 }
301 
302 GDScell *
GDSdupBoundary(boundaryEl * boundary)303 GDSdupBoundary(boundaryEl *boundary)
304 {
305   int i;
306   GDScell *newcell;
307   boundaryEl *boundaryptr;
308 
309   if(boundary == NULL)
310     return NULL;
311 
312   boundaryptr = (boundaryEl *)MALLOC(sizeof(boundaryEl));
313   newcell = (GDScell *)MALLOC(sizeof(GDScell));
314   newcell->type = BOUNDARY;
315   newcell->detail.boundary = boundaryptr;
316 
317   newcell->next = boundary->layerptr->cells;
318   boundary->layerptr->cells = newcell;
319 
320   boundaryptr->layerptr = boundary->layerptr;
321   boundaryptr->numpoints = boundary->numpoints;
322   boundaryptr->points = (point *)MALLOC(boundaryptr->numpoints * sizeof(point));
323   for(i = 0; i < boundaryptr->numpoints; i ++)
324   {
325     (boundaryptr->points[i]).x = (boundary->points[i]).x;
326     (boundaryptr->points[i]).y = (boundary->points[i]).y;
327   }
328 
329   return newcell;
330 }
331 
332 /*
333  * Apply the transform transf to all points in boundary.
334  */
335 void
GDStransfBoundary(boundaryEl * boundary,transform * transf)336 GDStransfBoundary(boundaryEl *boundary, transform *transf)
337 {
338   int i;
339 
340   for(i = 0; i < boundary->numpoints; i++)
341     boundary->points[i] = GDStransfPoint(&(boundary->points[i]), transf);
342 
343   return;
344 }
345 
346 GDScell *
GDSreadBoundary(int gdsfildes,GDSstruct * structptr)347 GDSreadBoundary(int gdsfildes, GDSstruct *structptr)
348 {
349   unsigned char *record;
350   int i, nbytes, layerno, datatype;
351   layer *layerptr;
352   GDScell *newcell;
353   boundaryEl *boundaryptr;
354 
355   boundaryptr = (boundaryEl *)MALLOC(sizeof(boundaryEl));
356   newcell = (GDScell *)MALLOC(sizeof(GDScell));
357   newcell->type = BOUNDARY;
358   newcell->detail.boundary = boundaryptr;
359 
360   if(GDSreadRecord(gdsfildes, &record, &nbytes) != LAYER)
361   {
362     fprintf(stderr, "Missing LAYER field in BOUNDARY element. Abort!\n");
363     exit(1);
364   }
365   layerno = GDSreadInt2(record + 2);
366   FREE(record);
367 
368   if(GDSreadRecord(gdsfildes, &record, &nbytes) != DATATYPE)
369   {
370     fprintf(stderr, "Missing DATATYPE field in BOUNDARY element. Abort!\n");
371     exit(1);
372   }
373   datatype = GDSreadInt2(record + 2);
374   FREE(record);
375 
376   for(layerptr = structptr->layers;
377       layerptr != NULL; layerptr = layerptr->next)
378     if(layerptr->layerno == layerno && layerptr->datatype==datatype)
379       break;
380   if(layerptr == NULL)
381   {
382     layerptr = (layer *)MALLOC(sizeof(layer));
383     layerptr->layerno = layerno;
384     layerptr->datatype = datatype;
385     layerptr->name = NULL; /* to be added later */
386     layerptr->cells = newcell;
387     layerptr->next = structptr->layers;
388     structptr->layers = layerptr;
389   }
390   else
391   {
392     newcell->next = layerptr->cells;
393     layerptr->cells = newcell;
394   }
395   boundaryptr->layerptr = layerptr;
396 
397 
398   if(GDSreadRecord(gdsfildes, &record, &nbytes) != XY)
399   {
400     fprintf(stderr, "Missing XY field in BOUNDARY element. Abort!\n");
401     exit(1);
402   }
403   boundaryptr->numpoints = (nbytes - 2) / 8;
404   boundaryptr->points = (point *)MALLOC(boundaryptr->numpoints * sizeof(point));
405 
406   for(i = 0; i < boundaryptr->numpoints; i ++)
407   {
408     (boundaryptr->points[i]).x = GDSreadInt4(record + 8 * i + 2);
409     (boundaryptr->points[i]).y = GDSreadInt4(record + 8 * i + 6);
410   }
411   FREE(record);
412 
413   if(GDSreadRecord(gdsfildes, &record, &nbytes) != ENDEL)
414   {
415     fprintf(stderr, "Missing ENDEL field in BOUNDARY element. Abort!\n");
416     exit(1);
417   }
418   FREE(record);
419 
420   fprintf(stdout, "Boundary on layer %d, datatype %d:\n", layerno,
421         layerptr->datatype);
422   for(i = 0; i < boundaryptr->numpoints; i++)
423     fprintf(stdout, "point[%d] = %d %d\n",
424             i, (boundaryptr->points[i]).x, (boundaryptr->points[i]).y);
425   return newcell;
426 }
427 
428