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 <GDSaux.h>
27 #include <GDStransf.h>
28 #include <GDSboundary.h>
29 
30 static double
getAngle(coord x1,coord y1,coord x2,coord y2)31 getAngle(coord x1, coord y1, coord x2, coord y2)
32 {
33   double angle;
34 
35   if(x1 == x2)
36     angle =  M_PI_2 * ((y2 > y1) ? 1 : -1);
37   else
38   {
39     angle = atan(fabs(y2 - y1)/fabs(x2 - x1));
40     if(y2 >= y1)
41     {
42       if(x2 >= x1)
43         angle += 0;
44       else
45         angle = M_PI - angle;
46     }
47     else
48     {
49       if(x2 >= x1)
50         angle = 2 * M_PI - angle;
51       else
52         angle += M_PI;
53     }
54   }
55 
56   return angle;
57 }
58 
59 #define EPS 1e-8
60 
61 static point
getDeltaXY(coord hw,point p1,point p2,point p3)62 getDeltaXY(coord hw, point p1, point p2, point p3)
63 {
64   double alpha, beta, theta, r;
65   point pnt;
66 
67   alpha = getAngle(p1.x, p1.y, p2.x, p2.y);
68   beta = getAngle(p2.x, p2.y, p3.x, p3.y);
69 
70   theta = (alpha + beta + M_PI)/2.0;
71 
72   if(fabs(cos((alpha - beta)/2.0)) < EPS)
73   {
74     fprintf(stderr, "Internal algorithm error: cos((alpha - beta)/2) = 0\n");
75     exit(1);
76   }
77   r = ((double) hw) / cos((alpha - beta)/2.0);
78 
79   pnt.x = (coord) (r * cos(theta));
80   pnt.y = (coord) (r * sin(theta));
81 
82   return pnt;
83 }
84 
85 static point
getEndDeltaXY(coord hw,point p1,point p2)86 getEndDeltaXY(coord hw, point p1, point p2)
87 {
88   double alpha, theta, r;
89   point pnt;
90 
91   alpha = getAngle(p1.x, p1.y, p2.x, p2.y);
92 
93   theta = alpha;
94   r= hw;
95   pnt.x = (coord)(-r * sin(theta));
96   pnt.y = (coord)(r * cos(theta));
97 
98   return pnt;
99 }
100 
101 
102 boundaryEl *
PathToBoundary(pathEl * path)103 PathToBoundary(pathEl *path)
104 {
105   boundaryEl *boundary;
106   coord hw = path->width / 2;
107   int i, numpoints = path->numpoints;
108   point *points, deltaxy;
109 
110   if (numpoints < 2)
111   {
112     fprintf(stderr,
113             "PathToBoundary(): don't know to handle wires < 2 pts yet\n");
114     return NULL;
115   }
116 
117   points = (point *)MALLOC(sizeof(point) * (2 * numpoints + 1));
118 
119   deltaxy = getEndDeltaXY(hw, path->points[0], path->points[1]);
120 
121   if(path->pathtype == BUTT_END)
122   {
123     points[0].x = path->points[0].x + deltaxy.x;
124     points[0].y = path->points[0].y + deltaxy.y;
125     points[2 * numpoints].x = path->points[0].x + deltaxy.x;
126     points[2 * numpoints].y = path->points[0].y + deltaxy.y;
127     points[2 * numpoints - 1].x = path->points[0].x - deltaxy.x;
128     points[2 * numpoints - 1].y = path->points[0].y - deltaxy.y;
129   }
130   else /* Extended end */
131   {
132     points[0].x = path->points[0].x + deltaxy.x - deltaxy.y;
133     points[0].y = path->points[0].y + deltaxy.y - deltaxy.x;
134     points[2 * numpoints].x = path->points[0].x + deltaxy.x - deltaxy.y;
135     points[2 * numpoints].y = path->points[0].y + deltaxy.y - deltaxy.x;
136     points[2 * numpoints - 1].x = path->points[0].x - deltaxy.x - deltaxy.y;
137     points[2 * numpoints - 1].y = path->points[0].y - deltaxy.y - deltaxy.x;
138   }
139 
140 
141   for(i = 1; i < numpoints - 1; i++)
142   {
143     deltaxy = getDeltaXY(hw, path->points[i - 1],
144                          path->points[i], path->points[i + 1]);
145     points[i].x = path->points[i].x + deltaxy.x;
146     points[i].y = path->points[i].y + deltaxy.y;
147     points[2 * numpoints - i - 1].x = path->points[i].x - deltaxy.x;
148     points[2 * numpoints - i - 1].y = path->points[i].y - deltaxy.y;
149   }
150 
151   deltaxy = getEndDeltaXY(hw, path->points[numpoints - 2],
152                           path->points[numpoints - 1]);
153   if(path->pathtype == BUTT_END)
154   {
155     points[numpoints - 1].x = path->points[numpoints - 1].x + deltaxy.x;
156     points[numpoints - 1].y = path->points[numpoints - 1].y + deltaxy.y;
157     points[numpoints].x = path->points[numpoints - 1].x - deltaxy.x;
158     points[numpoints].y = path->points[numpoints - 1].y - deltaxy.y;
159   }
160   else /* Extended end */
161   {
162     points[numpoints - 1].x = path->points[numpoints - 1].x + deltaxy.x + deltaxy.y;
163     points[numpoints - 1].y = path->points[numpoints - 1].y + deltaxy.y + deltaxy.x;
164     points[numpoints].x = path->points[numpoints - 1].x - deltaxy.x + deltaxy.y;
165     points[numpoints].y = path->points[numpoints - 1].y - deltaxy.y + deltaxy.x;
166   }
167 
168   boundary = (boundaryEl *)MALLOC(sizeof(boundaryEl));
169   boundary->layerptr = path->layerptr;
170   boundary->numpoints = numpoints * 2 + 1;
171   boundary->points = points;
172 
173   return boundary;
174 }
175 
176 bbox
GDSgetPathBBox(pathEl * path)177 GDSgetPathBBox(pathEl *path)
178 {
179   bbox bbx;
180   boundaryEl *boundary;
181 
182   boundary = PathToBoundary(path);
183   if(boundary == NULL)
184   {
185     bbx.ll.x = BIGVAL;
186     bbx.ll.y = BIGVAL;
187     bbx.ur.x = -BIGVAL;
188     bbx.ur.y = -BIGVAL;
189     return bbx;
190   }
191   bbx = GDSgetBoundaryBBox(boundary);
192   FREE(boundary->points);
193   FREE(boundary);
194 
195   return bbx;
196 }
197 
198 void
PathToPS(FILE * psfile,pathEl * path,PSStyle psStyle)199 PathToPS(FILE *psfile, pathEl *path, PSStyle psStyle)
200 {
201   boundaryEl *boundary;
202 
203   if(path->layerptr->layerno != psStyle.gdsno)
204     return;
205   boundary = PathToBoundary(path);
206   if(boundary == NULL)
207     return;
208   BoundaryToPS(psfile, boundary, psStyle);
209   FREE(boundary->points);
210   FREE(boundary);
211 }
212 
213 void
PathToPOV(FILE * povfile,pathEl * path,PSStyle psStyle)214 PathToPOV(FILE *povfile, pathEl *path, PSStyle psStyle)
215 {
216   boundaryEl *boundary;
217   boundary = PathToBoundary(path);
218   if(boundary == NULL)
219     return;
220   BoundaryToPOV(povfile, boundary, psStyle);
221   FREE(boundary->points);
222   FREE(boundary);
223 }
224 
225 void
PathToHPGL(FILE * hpglfile,pathEl * path,PSStyle psStyle)226 PathToHPGL(FILE *hpglfile, pathEl *path, PSStyle psStyle)
227 {
228   boundaryEl *boundary;
229 
230   if(path->layerptr->layerno != psStyle.gdsno)
231     return;
232   boundary = PathToBoundary(path);
233   if(boundary == NULL)
234     return;
235   BoundaryToHPGL(hpglfile, boundary, psStyle);
236   FREE(boundary->points);
237   FREE(boundary);
238 }
239 
240 /*
241  * Frees the cell contents and removes the layer list reference.
242  * The structure list reference has to be removed at the upper level.
243  */
244 void
GDSfreePath(GDScell * cell)245 GDSfreePath(GDScell *cell)
246 {
247   GDScell *cellptr;
248 
249   if(cell == NULL)
250     return;
251   if(cell->type != PATH)
252     return;
253 
254   if(cell == cell->detail.path->layerptr->cells)
255     cell->detail.path->layerptr->cells = cell->next;
256   else
257   {
258     for(cellptr = cell->detail.path->layerptr->cells;
259         cellptr->next != NULL; cellptr = cellptr->next)
260     {
261       if(cellptr->next == cell)
262       {
263         cellptr->next = cellptr->next->next;
264         break;
265       }
266     }
267     if(cellptr == NULL)
268       fprintf(stderr, "Oops! GDSfreePath(): Missing cell in layerptr\n");
269   }
270   FREE(cell->detail.path->points);
271   FREE(cell->detail.path);
272   return;
273 }
274 
275 GDScell *
GDSdupPath(pathEl * path)276 GDSdupPath(pathEl *path)
277 {
278   int i;
279   GDScell *newcell;
280   pathEl *pathptr;
281 
282   if(path == NULL)
283     return NULL;
284 
285   pathptr = (pathEl *)MALLOC(sizeof(pathEl));
286   newcell = (GDScell *)MALLOC(sizeof(GDScell));
287   newcell->type = PATH;
288   newcell->detail.path = pathptr;
289 
290   newcell->next = path->layerptr->cells;
291   path->layerptr->cells = newcell;
292 
293   pathptr->layerptr = path->layerptr;
294   pathptr->pathtype = path->pathtype;
295   pathptr->width= path->width;
296   pathptr->numpoints = path->numpoints;
297   pathptr->points = (point *)MALLOC(pathptr->numpoints * sizeof(point));
298   for(i = 0; i < pathptr->numpoints; i ++)
299   {
300     (pathptr->points[i]).x = (path->points[i]).x;
301     (pathptr->points[i]).y = (path->points[i]).y;
302   }
303 
304   return newcell;
305 }
306 
307 /*
308  * Apply the transform transf to all points in path.
309  */
310 void
GDStransfPath(pathEl * path,transform * transf)311 GDStransfPath(pathEl *path, transform *transf)
312 {
313   int i;
314   double mag;
315   for(i = 0; i < path->numpoints; i++)
316     path->points[i] = GDStransfPoint(&(path->points[i]), transf);
317   /* Check to see if width needs to be changed. */
318   GDSGetTransfValues(transf,&i,&mag);
319   if (mag!=1.0) { path->width= (coord)((double)path->width*mag); }
320   return;
321 }
322 
323 GDScell *
GDSreadPath(int gdsfildes,GDSstruct * structptr)324 GDSreadPath(int gdsfildes, GDSstruct *structptr)
325 {
326   unsigned char *record;
327   int i, nbytes, layerno,datatype;
328   layer *layerptr;
329   GDScell *newcell;
330   pathEl *pathptr;
331 
332   pathptr = (pathEl *)MALLOC(sizeof(pathEl));
333   newcell = (GDScell *)MALLOC(sizeof(GDScell));
334   newcell->type = PATH;
335   newcell->detail.path = pathptr;
336 
337   if(GDSreadRecord(gdsfildes, &record, &nbytes) != LAYER)
338   {
339     fprintf(stderr, "Missing LAYER field in PATH element. Abort!\n");
340     exit(1);
341   }
342   layerno = GDSreadInt2(record + 2);
343   FREE(record);
344 
345   if(GDSreadRecord(gdsfildes, &record, &nbytes) != DATATYPE)
346   {
347     fprintf(stderr, "Missing DATATYPE field in PATH element. Abort!\n");
348     exit(1);
349   }
350   datatype = GDSreadInt2(record + 2);
351   FREE(record);
352 
353   for(layerptr = structptr->layers;
354       layerptr != NULL; layerptr = layerptr->next)
355     if(layerptr->layerno == layerno && layerptr->datatype==datatype)
356       break;
357   if(layerptr == NULL)
358   {
359     layerptr = (layer *)MALLOC(sizeof(layer));
360     layerptr->layerno = layerno;
361     layerptr->datatype = datatype;
362     layerptr->name = NULL; /* to be added later */
363     layerptr->cells = newcell;
364     layerptr->next = structptr->layers;
365     structptr->layers = layerptr;
366   }
367   else
368   {
369     newcell->next = layerptr->cells;
370     layerptr->cells = newcell;
371   }
372   pathptr->layerptr = layerptr;
373 
374   if(GDSreadRecord(gdsfildes, &record, &nbytes) != PATHTYPE)
375   {
376     fprintf(stderr, "Missing PATHTYPE field in PATH element. Abort!\n");
377     exit(1);
378   }
379   pathptr->pathtype = GDSreadInt2(record + 2);
380   FREE(record);
381 
382   switch(pathptr->pathtype)
383   {
384     case ROUND_END:
385       fprintf(stderr,
386               "Round ended path not supported. Used extended instead\n");
387     case CUSTOMPLUS_END:
388       fprintf(stderr,
389               "Custom ended path not supported. Used extended instead\n");
390       pathptr->pathtype = EXTENDED_END;
391     case EXTENDED_END:
392     case BUTT_END:
393       break;
394     default:
395       fprintf(stderr, "Unknown pathtype %d. Used butt end instead\n",
396               pathptr->pathtype);
397       pathptr->pathtype = BUTT_END;
398       break;
399   }
400   if(GDSreadRecord(gdsfildes, &record, &nbytes) != WIDTH)
401   {
402     fprintf(stderr, "Missing WIDTH field in PATH element. Abort!\n");
403     exit(1);
404   }
405   pathptr->width = GDSreadInt4(record + 2);
406   FREE(record);
407 
408   if(GDSreadRecord(gdsfildes, &record, &nbytes) != XY)
409   {
410     fprintf(stderr, "Missing XY field in PATH element. Abort!\n");
411     exit(1);
412   }
413   pathptr->numpoints = (nbytes - 2) / 8;
414   pathptr->points = (point *)MALLOC(pathptr->numpoints * sizeof(point));
415 
416   for(i = 0; i < pathptr->numpoints; i ++)
417   {
418     (pathptr->points[i]).x = GDSreadInt4(record + 8 * i + 2);
419     (pathptr->points[i]).y = GDSreadInt4(record + 8 * i + 6);
420   }
421   FREE(record);
422 
423   if(GDSreadRecord(gdsfildes, &record, &nbytes) != ENDEL)
424   {
425     fprintf(stderr, "Missing ENDEL field in PATH element. Abort!\n");
426     exit(1);
427   }
428   FREE(record);
429 
430   fprintf(stdout, "Path on layer %d, datatype %d, of type %d with width = %d:\n",
431           layerno, layerptr->datatype,pathptr->pathtype, pathptr->width);
432   for(i = 0; i < pathptr->numpoints; i++)
433     fprintf(stdout, "point[%d] = %d %d\n",
434             i, (pathptr->points[i]).x, (pathptr->points[i]).y);
435   return newcell;
436 }
437 
438