1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: dbmath.c
6 * Database transformation and mathematics support module
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "global.h"
33 #include "database.h"
34 #include "egraphics.h"
35 #include "efunction.h"
36 #include "tecart.h"
37 #include "tecgen.h"
38 #include "tecschem.h"
39 #include "usr.h"
40 #include "drc.h"
41 #include <math.h>
42 #include <float.h>
43
44 /* clipping directions */
45 #define LEFT 1
46 #define RIGHT 2
47 #define BOTTOM 4
48 #define TOP 8
49
50 static WINDOWPART *db_windowpartfree = NOWINDOWPART; /* top of free list of windows */
51 static INTBIG db_rectx[4] = {0, 0, 1, 1};
52 static INTBIG db_recty[4] = {0, 1, 1, 0};
53 static POLYGON *db_staticpolygons = NOPOLYGON;
54
55 static INTBIG *db_primearray; /* array of small prime numbers */
56 static INTBIG db_primearraytotal = 0; /* size of small prime number array */
57 static INTBIG db_maxcheckableprime; /* max value that can be checked with array */
58 static POLYGON *db_freepolygons = NOPOLYGON;
59 static void *db_polygonmutex = 0; /* mutex for polygon modules */
60 static void *db_primenumbermutex = 0; /* mutex for prime numbers */
61
62 /* prototypes for local routines */
63 static BOOLEAN db_addpointtopoly(INTBIG x, INTBIG y, POLYGON *poly);
64 static void db_findconnectionpoint(INTBIG, INTBIG, INTBIG, INTBIG, float, float, float, INTBIG*, INTBIG*);
65 static INTBIG db_quadrant(INTBIG, INTBIG);
66 static void db_closestpointtoline(INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG*, INTBIG*);
67 static VIEW *db_makepermanentview(CHAR*, CHAR*, INTBIG);
68 static void db_clipedge(POLYGON*, POLYGON*, INTBIG, INTBIG);
69 static BOOLEAN db_clip(INTBIG*, INTBIG*, INTBIG*, INTBIG*, INTBIG, INTBIG);
70 static BOOLEAN db_lineintersect(INTBIG, INTBIG, INTBIG, INTBIG, POLYGON*);
71 static BOOLEAN db_isprime(INTBIG);
72 static BOOLEAN db_isachildof(NODEPROTO *parent, NODEPROTO *child);
73 static int db_anglelistdescending(const void *e1, const void *e2);
74 static BOOLEAN db_primeinit(void);
75 static BOOLEAN db_extendprimetable(INTBIG length);
76 static void db_deallocatepolygon(POLYGON *poly);
77
78 /*
79 * Routine to free all memory associated with this module.
80 */
db_freemathmemory(void)81 void db_freemathmemory(void)
82 {
83 REGISTER WINDOWPART *w;
84 REGISTER POLYGON *poly;
85
86 /* free all statically allocated polygons */
87 while (db_staticpolygons != NOPOLYGON)
88 {
89 poly = db_staticpolygons;
90 db_staticpolygons = db_staticpolygons->nextpolygon;
91 freepolygon(poly);
92 }
93
94 /* cleanup cached polygons */
95 while (db_freepolygons != NOPOLYGON)
96 {
97 poly = db_freepolygons;
98 db_freepolygons = db_freepolygons->nextpolygon;
99 db_deallocatepolygon(poly);
100 }
101
102 /* free all window partitions */
103 while (el_topwindowpart != NOWINDOWPART)
104 {
105 w = el_topwindowpart;
106 el_topwindowpart = el_topwindowpart->nextwindowpart;
107 freewindowpart(w);
108 }
109
110 /* free unused pool of window partitions */
111 while (db_windowpartfree != NOWINDOWPART)
112 {
113 w = db_windowpartfree;
114 db_windowpartfree = db_windowpartfree->nextwindowpart;
115 efree((CHAR *)w);
116 }
117
118 /* free miscellaneous allocations */
119 efree((CHAR *)el_libdir);
120 if (db_primearraytotal != 0) efree((CHAR *)db_primearray);
121 }
122
123 /************************* TRANSFORMATION *************************/
124
125 #define ZE 0 /* fractional representation of 0 */
126 #define P1 (1<<30) /* fractional representation of 1 */
127 #define N1 (-1<<30) /* fractional representation of -1 */
128
129 /*
130 * there are eight different standard transformation matrices that cover
131 * all of the Manhattan transformations:
132 *
133 * +------+ +------+
134 * |^ | +-----------+ | | +-----------+
135 * | | | | | | | >|
136 * | R0 | | R90 | | R180 | | R270 |
137 * | | |< | | | | |
138 * | | +-----------+ | v| +-----------+
139 * +------+ +------+
140 *
141 * +------+ +------+
142 * +-----------+ | ^| +-----------+ | |
143 * |< | | | | | | |
144 * | R0T | | R90T | | R180T | |R270T |
145 * | | | | | >| | |
146 * +-----------+ | | +-----------+ |v |
147 * +------+ +------+
148 *
149 * Form 0 (R0): 0 rotation, no transposition: 1 0
150 * 0 1
151 * Form 1 (R90): 90 rotation, no transposition: 0 1
152 * -1 0
153 * Form 2 (R180): 180 rotation, no transposition: -1 0
154 * 0 -1
155 * Form 3 (R270): 270 rotation, no transposition: 0 -1
156 * 1 0
157 * Form 4 (R0T): 0 rotation, transposition: 0 -1
158 * -1 0
159 * Form 5 (R90T): 90 rotation, transposition: -1 0
160 * 0 1
161 * Form 6 (R180T): 180 rotation, transposition: 0 1
162 * 1 0
163 * Form 7 (R270T): 270 rotation, transposition: 1 0
164 * 0 -1
165 *
166 * When element [2][2] of a transformation matrix is not equal to P1, then
167 * that matrix is in standard form and the value of element [2][2] selects
168 * from the eight forms above.
169 */
170
171 /* the rotational contents of the eight standard forms */
172 static INTBIG db_matstyle[8][2][2] =
173 {
174 {{P1, ZE}, {ZE, P1}},
175 {{ZE, P1}, {N1, ZE}},
176 {{N1, ZE}, {ZE, N1}},
177 {{ZE, N1}, {P1, ZE}},
178 {{ZE, N1}, {N1, ZE}},
179 {{N1, ZE}, {ZE, P1}},
180 {{ZE, P1}, {P1, ZE}},
181 {{P1, ZE}, {ZE, N1}}
182 };
183
184 /* the transpose of the eight standard forms */
185 static INTBIG db_mattrans[8] = {0, 3, 2, 1, 4, 5, 6, 7};
186
187 /* the determinants of the eight standard forms */
188 static INTBIG db_determinant[8] = {1, 1, 1, 1, -1, -1, -1, -1};
189
190 /* the product of the eight standard forms (filled in by "db_initdatabase") */
191 static INTBIG db_matmult[8][8];
192
193 /*
194 * routine to transform the point (x, y) through the transformation matrix in
195 * the array "trans" and produce a transformed co-ordinate in (newx, newy)
196 */
xform(INTBIG x,INTBIG y,INTBIG * newx,INTBIG * newy,XARRAY trans)197 void xform(INTBIG x, INTBIG y, INTBIG *newx, INTBIG *newy, XARRAY trans)
198 {
199 REGISTER INTBIG px, py, t22;
200
201 px = trans[2][0]; py = trans[2][1]; t22 = trans[2][2];
202 if (t22 != P1)
203 {
204 switch (t22)
205 {
206 case 0: *newx = x + px; *newy = y + py; return;
207 case 1: *newx = -y + px; *newy = x + py; return;
208 case 2: *newx = -x + px; *newy = -y + py; return;
209 case 3: *newx = y + px; *newy = -x + py; return;
210 case 4: *newx = -y + px; *newy = -x + py; return;
211 case 5: *newx = -x + px; *newy = y + py; return;
212 case 6: *newx = y + px; *newy = x + py; return;
213 case 7: *newx = x + px; *newy = -y + py; return;
214 }
215 (void)db_error(DBBADTMAT|DBXFORM);
216 return;
217 }
218 *newx = mult(trans[0][0],x) + mult(trans[1][0],y) + px;
219 *newy = mult(trans[0][1],x) + mult(trans[1][1],y) + py;
220 }
221
222 /*
223 * Takes a box specified by lx, hx, ly, hy, transforms it by trans, and
224 * returns the box in lx, hx, ly, hy. The relationship between lx, hx,
225 * ly, hy is preserved - i.e hx > lx, hy > ly
226 */
xformbox(INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy,XARRAY trans)227 void xformbox(INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy, XARRAY trans)
228 {
229 INTBIG tx, ty;
230 REGISTER INTBIG lowx, highx, lowy, highy;
231
232 lowx = *lx; highx = *hx;
233 lowy = *ly; highy = *hy;
234 xform(lowx, lowy, lx,ly, trans); *hx = *lx; *hy = *ly;
235 xform(lowx, highy, &tx,&ty, trans);
236 if (tx < *lx) *lx = tx; if (tx > *hx) *hx = tx;
237 if (ty < *ly) *ly = ty; if (ty > *hy) *hy = ty;
238 xform(highx, highy, &tx,&ty, trans);
239 if (tx < *lx) *lx = tx; if (tx > *hx) *hx = tx;
240 if (ty < *ly) *ly = ty; if (ty > *hy) *hy = ty;
241 xform(highx, lowy, &tx,&ty, trans);
242 if (tx < *lx) *lx = tx; if (tx > *hx) *hx = tx;
243 if (ty < *ly) *ly = ty; if (ty > *hy) *hy = ty;
244 }
245
246 /*
247 * routine to make a transformation matrix in the array "trans" which
248 * rotates the nodeinst "ni" in its offset position.
249 * The nodeinst is first translated to (0,0), then rotated to its proper
250 * orientation, then translated back to its original position.
251 */
makerot(NODEINST * ni,XARRAY trans)252 void makerot(NODEINST *ni, XARRAY trans)
253 {
254 makeangle(ni->rotation, ni->transpose, trans);
255
256 /*
257 * the code used to be: (but caused roundoff errors)
258 * trans[2][0] = (ni->lowx+ni->highx) / 2;
259 * trans[2][1] = (ni->lowy+ni->highy) / 2;
260 * xform(-trans[2][0], -trans[2][1], &trans[2][0], &trans[2][1], trans);
261 */
262 trans[2][0] = ni->lowx + ni->highx;
263 trans[2][1] = ni->lowy + ni->highy;
264 xform(-trans[2][0], -trans[2][1], &trans[2][0], &trans[2][1], trans);
265 trans[2][0] /= 2; trans[2][1] /= 2;
266 }
267
makerotI(NODEINST * ni,XARRAY trans)268 void makerotI(NODEINST *ni, XARRAY trans)
269 {
270 if (ni->transpose != 0)
271 {
272 makeangle(ni->rotation, ni->transpose, trans);
273 } else
274 {
275 makeangle((3600 - ni->rotation)%3600, 0, trans);
276 }
277
278 /*
279 * the code used to be: (but caused roundoff errors)
280 * trans[2][0] = (ni->lowx+ni->highx) / 2;
281 * trans[2][1] = (ni->lowy+ni->highy) / 2;
282 * xform(-trans[2][0], -trans[2][1], &trans[2][0], &trans[2][1], trans);
283 */
284 trans[2][0] = ni->lowx + ni->highx;
285 trans[2][1] = ni->lowy + ni->highy;
286 xform(-trans[2][0], -trans[2][1], &trans[2][0], &trans[2][1], trans);
287 trans[2][0] /= 2; trans[2][1] /= 2;
288 }
289
makeangle(INTBIG rot,INTBIG tra,XARRAY trans)290 void makeangle(INTBIG rot, INTBIG tra, XARRAY trans)
291 {
292 REGISTER INTBIG i;
293
294 switch (rot)
295 {
296 case 0: if (tra) trans[2][2] = 4; else trans[2][2] = 0; break;
297 case 900: if (tra) trans[2][2] = 5; else trans[2][2] = 1; break;
298 case 1800: if (tra) trans[2][2] = 6; else trans[2][2] = 2; break;
299 case 2700: if (tra) trans[2][2] = 7; else trans[2][2] = 3; break;
300 default:
301 /* get rotation matrix from sine and cosine */
302 trans[0][0] = trans[1][1] = cosine(rot);
303 trans[0][1] = sine(rot); trans[1][0] = -trans[0][1];
304
305 /* re-organize if the matrix is transposed */
306 if (tra)
307 {
308 i = trans[0][0]; trans[0][0] = -trans[0][1]; trans[0][1] = -i;
309 i = trans[1][1]; trans[1][1] = -trans[1][0]; trans[1][0] = -i;
310 }
311 trans[2][2] = P1; break;
312 }
313
314 /* fill in edge values */
315 trans[2][0] = trans[2][1] = ZE;
316 trans[0][2] = trans[1][2] = ZE;
317 }
318
319 /*
320 * routine to make transformation matrix in "trans" for translating points
321 * in nodeinst "ni" to the outside environment.
322 */
maketrans(NODEINST * ni,XARRAY trans)323 void maketrans(NODEINST *ni, XARRAY trans)
324 {
325 REGISTER NODEPROTO *np;
326
327 np = ni->proto;
328 transid(trans);
329
330 /*
331 * the code used to be: (but caused roundoff errors)
332 * trans[2][0] = (ni->lowx + ni->highx)/2 - (np->lowx + np->highx)/2;
333 * trans[2][1] = (ni->lowy + ni->highy)/2 - (np->lowy + np->highy)/2;
334 */
335 trans[2][0] = (ni->lowx + ni->highx - np->lowx - np->highx)/2;
336 trans[2][1] = (ni->lowy + ni->highy - np->lowy - np->highy)/2;
337 }
338
339 /*
340 * routine to make transformation matrix in "trans" for translating points
341 * from the outside environment to the nodeinst "ni".
342 */
maketransI(NODEINST * ni,XARRAY trans)343 void maketransI(NODEINST *ni, XARRAY trans)
344 {
345 REGISTER NODEPROTO *np;
346
347 np = ni->proto;
348 transid(trans);
349 /*
350 * the code used to be: (but caused roundoff errors)
351 * trans[2][0] = (np->lowx + np->highx)/2 - (ni->lowx + ni->highx)/2;
352 * trans[2][1] = (np->lowy + np->highy)/2 - (ni->lowy + ni->highy)/2;
353 */
354 trans[2][0] = (np->lowx + np->highx - ni->lowx - ni->highx)/2;
355 trans[2][1] = (np->lowy + np->highy - ni->lowy - ni->highy)/2;
356 }
357
358 /* routine to create an identity transformation matrix in the array "matr" */
transid(XARRAY matr)359 void transid(XARRAY matr)
360 {
361 /* make standard matrix with edge values zero */
362 matr[2][0] = matr[2][1] = matr[0][2] = matr[1][2] = ZE;
363 matr[2][2] = 0;
364 }
365
366 /*
367 * routine to copy from the transformation matrix in the array "mats"
368 * to the transformation matrix in the array "matd"
369 */
transcpy(XARRAY mats,XARRAY matd)370 void transcpy(XARRAY mats, XARRAY matd)
371 {
372 REGISTER INTBIG i, j;
373
374 if (mats[2][2] != P1)
375 {
376 /* standard matrix: copy edge values and matrix type */
377 matd[0][2] = mats[0][2]; matd[1][2] = mats[1][2];
378 matd[2][0] = mats[2][0]; matd[2][1] = mats[2][1];
379 matd[2][2] = mats[2][2];
380 return;
381 }
382
383 /* normal matrix: copy everything */
384 for(i=0; i<3; i++) for(j=0; j<3; j++) matd[i][j] = mats[i][j];
385 }
386
387 /*
388 * routine to multiply the transformation matrix in the array "mata" with
389 * the transformation matrix in the array "matb" to produce the transformation
390 * matrix in the array "matc"
391 */
transmult(XARRAY mata,XARRAY matb,XARRAY matc)392 void transmult(XARRAY mata, XARRAY matb, XARRAY matc)
393 {
394 REGISTER INTBIG sum, ma, mb, i, j, k;
395
396 ma = mata[2][2];
397 mb = matb[2][2];
398 if (ma != P1 && mb != P1)
399 {
400 /* standard matrix: compute edges, use tables for matrix type */
401 if (ma < 0 || ma > 7 || mb < 0 || mb > 7)
402 {
403 (void)db_error(DBBADTMAT|DBTRANSMULT);
404 return;
405 }
406 matc[2][2] = db_matmult[ma][mb];
407
408 i = mata[2][0]; mata[2][0] = mata[0][2];
409 j = mata[2][1]; mata[2][1] = mata[1][2];
410 mata[2][2] = db_mattrans[ma];
411 xform(matb[0][2], matb[1][2], &matc[0][2], &matc[1][2], mata);
412 mata[2][0] = i; mata[2][1] = j; mata[2][2] = ma;
413 xform(mata[2][0], mata[2][1], &matc[2][0], &matc[2][1], matb);
414 return;
415 }
416
417 /* normal matrices: make sure both are in full form */
418 if (ma != P1)
419 {
420 for(i=0; i<2; i++) for(j=0; j<2; j++)
421 mata[i][j] = db_matstyle[ma][i][j];
422 mata[2][2] = P1;
423 }
424 if (mb != P1)
425 {
426 for(i=0; i<2; i++) for(j=0; j<2; j++)
427 matb[i][j] = db_matstyle[mb][i][j];
428 matb[2][2] = P1;
429 }
430
431 /* multiply the matrices */
432 for(i=0; i<3; i++) for(j=0; j<3; j++)
433 {
434 sum = 0;
435 for(k=0; k<3; k++) sum += mult(mata[i][k], matb[k][j]);
436 matc[i][j] = sum;
437 }
438 mata[2][2] = ma; matb[2][2] = mb;
439 }
440
441 /*
442 * routine to tell whether the array "trans" is a manhattan orientation.
443 * returns true if so.
444 */
ismanhattan(XARRAY trans)445 BOOLEAN ismanhattan(XARRAY trans)
446 {
447 if (trans[2][2] != P1) return(TRUE);
448 return(FALSE);
449 }
450
451 /*
452 * routine to rotate label style "oldstyle" according to the rotation factor
453 * in "trans", returning the new rotation factor
454 */
455 static INTBIG db_textstyle[8] = {TEXTLEFT, TEXTBOTLEFT, TEXTBOT, TEXTBOTRIGHT,
456 TEXTRIGHT, TEXTTOPRIGHT, TEXTTOP, TEXTTOPLEFT};
457 static INTBIG db_texttranspose[8] = {TEXTTOP, TEXTTOPRIGHT, TEXTRIGHT,
458 TEXTBOTRIGHT, TEXTBOT, TEXTBOTLEFT, TEXTLEFT, TEXTTOPLEFT};
rotatelabel(INTBIG oldstyle,INTBIG rotation,XARRAY trans)459 INTBIG rotatelabel(INTBIG oldstyle, INTBIG rotation, XARRAY trans)
460 {
461 REGISTER INTBIG i;
462
463 /* if text style is not offset, rotation not done */
464 if (oldstyle == TEXTCENT || oldstyle == TEXTBOX) return(oldstyle);
465
466 /* cannot handle nonmanhattan rotations */
467 if (trans[2][2] == P1) return(oldstyle);
468
469 /* find the label style */
470 for(i=0; i<8; i++) if (db_textstyle[i] == oldstyle) break;
471 if (i >= 8) return(oldstyle);
472
473 /* handle nontransposed transformation */
474 if (trans[2][2] <= 3)
475 return(db_textstyle[(i + 2*trans[2][2] + rotation*2) % 8]);
476
477 /* handle transposed transformation */
478 return(db_texttranspose[(i + 2*(trans[2][2]-4) + rotation*2) % 8]);
479 }
480
481 /************************* TRANSCENDENTAL MATH *************************/
482
483 static INTBIG db_sinetable[] =
484 {
485 0x00000000,0x001C9870,0x003930DA,0x0055C939,0x00726187,0x008EF9BE,
486 0x00AB91D9,0x00C829D1,0x00E4C1A1,0x01015944,0x011DF0B3,0x013A87E9,
487 0x01571EE0,0x0173B593,0x01904BFC,0x01ACE214,0x01C977D7,0x01E60D3F,
488 0x0202A246,0x021F36E6,0x023BCB19,0x02585EDB,0x0274F224,0x029184F0,
489 0x02AE1739,0x02CAA8F9,0x02E73A2A,0x0303CAC6,0x03205AC9,0x033CEA2C,
490 0x035978E9,0x037606FB,0x0392945D,0x03AF2107,0x03CBACF6,0x03E83822,
491 0x0404C287,0x04214C1E,0x043DD4E3,0x045A5CCE,0x0476E3DB,0x04936A04,
492 0x04AFEF43,0x04CC7393,0x04E8F6ED,0x0505794D,0x0521FAAB,0x053E7B04,
493 0x055AFA50,0x0577788B,0x0593F5AE,0x05B071B4,0x05CCEC98,0x05E96653,
494 0x0605DEE0,0x06225639,0x063ECC59,0x065B4139,0x0677B4D5,0x06942726,
495 0x06B09827,0x06CD07D2,0x06E97621,0x0705E30F,0x07224E97,0x073EB8B1,
496 0x075B215A,0x0777888A,0x0793EE3D,0x07B0526C,0x07CCB513,0x07E9162B,
497 0x080575AF,0x0821D399,0x083E2FE3,0x085A8A88,0x0876E382,0x08933ACB,
498 0x08AF905E,0x08CBE436,0x08E8364B,0x0904869A,0x0920D51B,0x093D21CB,
499 0x09596CA2,0x0975B59B,0x0991FCB0,0x09AE41DD,0x09CA851B,0x09E6C664,
500 0x0A0305B4,0x0A1F4304,0x0A3B7E4E,0x0A57B78E,0x0A73EEBD,0x0A9023D5,
501 0x0AAC56D2,0x0AC887AE,0x0AE4B662,0x0B00E2EA,0x0B1D0D3F,0x0B39355C,
502 0x0B555B3C,0x0B717ED9,0x0B8DA02C,0x0BA9BF32,0x0BC5DBE3,0x0BE1F63A,
503 0x0BFE0E33,0x0C1A23C6,0x0C3636EF,0x0C5247A7,0x0C6E55EB,0x0C8A61B2,
504 0x0CA66AF9,0x0CC271BA,0x0CDE75EE,0x0CFA7790,0x0D16769C,0x0D32730A,
505 0x0D4E6CD6,0x0D6A63FA,0x0D865870,0x0DA24A34,0x0DBE393E,0x0DDA258A,
506 0x0DF60F12,0x0E11F5D0,0x0E2DD9C0,0x0E49BADB,0x0E65991B,0x0E81747C,
507 0x0E9D4CF8,0x0EB92288,0x0ED4F529,0x0EF0C4D3,0x0F0C9181,0x0F285B2F,
508 0x0F4421D6,0x0F5FE570,0x0F7BA5F9,0x0F97636B,0x0FB31DC0,0x0FCED4F2,
509 0x0FEA88FD,0x100639DA,0x1021E784,0x103D91F6,0x1059392A,0x1074DD1A,
510 0x10907DC2,0x10AC1B1A,0x10C7B51F,0x10E34BCA,0x10FEDF16,0x111A6EFD,
511 0x1135FB7B,0x11518488,0x116D0A21,0x11888C3F,0x11A40ADD,0x11BF85F6,
512 0x11DAFD83,0x11F67180,0x1211E1E7,0x122D4EB2,0x1248B7DD,0x12641D61,
513 0x127F7F39,0x129ADD60,0x12B637D0,0x12D18E83,0x12ECE175,0x130830A0,
514 0x13237BFE,0x133EC38A,0x135A073E,0x13754715,0x1390830A,0x13ABBB17,
515 0x13C6EF37,0x13E21F64,0x13FD4B99,0x141873D0,0x14339805,0x144EB831,
516 0x1469D44F,0x1484EC59,0x14A0004B,0x14BB101F,0x14D61BD0,0x14F12358,
517 0x150C26B1,0x152725D7,0x154220C4,0x155D1772,0x157809DC,0x1592F7FE,
518 0x15ADE1D0,0x15C8C74F,0x15E3A875,0x15FE853B,0x16195D9E,0x16343197,
519 0x164F0122,0x1669CC38,0x168492D5,0x169F54F3,0x16BA128E,0x16D4CB9E,
520 0x16EF8020,0x170A300D,0x1724DB61,0x173F8217,0x175A2428,0x1774C190,
521 0x178F5A49,0x17A9EE4E,0x17C47D99,0x17DF0826,0x17F98DEF,0x18140EEF,
522 0x182E8B20,0x1849027D,0x18637501,0x187DE2A7,0x18984B69,0x18B2AF42,
523 0x18CD0E2D,0x18E76824,0x1901BD23,0x191C0D23,0x19365821,0x19509E15,
524 0x196ADEFC,0x19851AD1,0x199F518C,0x19B9832B,0x19D3AFA7,0x19EDD6FA,
525 0x1A07F921,0x1A221615,0x1A3C2DD2,0x1A564052,0x1A704D90,0x1A8A5587,
526 0x1AA45831,0x1ABE558A,0x1AD84D8C,0x1AF24032,0x1B0C2D77,0x1B261556,
527 0x1B3FF7C9,0x1B59D4CC,0x1B73AC59,0x1B8D7E6A,0x1BA74AFC,0x1BC11208,
528 0x1BDAD38A,0x1BF48F7D,0x1C0E45DB,0x1C27F69F,0x1C41A1C4,0x1C5B4745,
529 0x1C74E71C,0x1C8E8146,0x1CA815BC,0x1CC1A479,0x1CDB2D79,0x1CF4B0B6,
530 0x1D0E2E2B,0x1D27A5D4,0x1D4117AA,0x1D5A83A9,0x1D73E9CC,0x1D8D4A0E,
531 0x1DA6A46A,0x1DBFF8DA,0x1DD9475A,0x1DF28FE4,0x1E0BD274,0x1E250F04,
532 0x1E3E4590,0x1E577612,0x1E70A086,0x1E89C4E6,0x1EA2E32D,0x1EBBFB56,
533 0x1ED50D5D,0x1EEE193C,0x1F071EEE,0x1F201E6E,0x1F3917B8,0x1F520AC6,
534 0x1F6AF794,0x1F83DE1C,0x1F9CBE59,0x1FB59846,0x1FCE6BDF,0x1FE7391F,
535 0x20000000,0x2018C07E,0x20317A93,0x204A2E3B,0x2062DB71,0x207B8230,
536 0x20942272,0x20ACBC34,0x20C54F70,0x20DDDC21,0x20F66242,0x210EE1CF,
537 0x21275AC2,0x213FCD17,0x215838C8,0x21709DD2,0x2188FC2E,0x21A153D9,
538 0x21B9A4CD,0x21D1EF05,0x21EA327D,0x22026F30,0x221AA519,0x2232D432,
539 0x224AFC78,0x22631DE5,0x227B3875,0x22934C23,0x22AB58EA,0x22C35EC5,
540 0x22DB5DAF,0x22F355A4,0x230B469E,0x2323309A,0x233B1392,0x2352EF81,
541 0x236AC463,0x23829234,0x239A58ED,0x23B2188B,0x23C9D108,0x23E18261,
542 0x23F92C8F,0x2410CF90,0x24286B5D,0x243FFFF2,0x24578D4B,0x246F1362,
543 0x24869233,0x249E09BA,0x24B579F1,0x24CCE2D4,0x24E4445F,0x24FB9E8C,
544 0x2512F157,0x252A3CBB,0x254180B4,0x2558BD3D,0x256FF251,0x25871FEC,
545 0x259E4609,0x25B564A3,0x25CC7BB7,0x25E38B3E,0x25FA9336,0x26119398,
546 0x26288C61,0x263F7D8B,0x26566713,0x266D48F4,0x26842329,0x269AF5AD,
547 0x26B1C07C,0x26C88392,0x26DF3EEA,0x26F5F27F,0x270C9E4D,0x27234250,
548 0x2739DE82,0x275072DF,0x2766FF63,0x277D840A,0x279400CE,0x27AA75AC,
549 0x27C0E29F,0x27D747A1,0x27EDA4B0,0x2803F9C6,0x281A46DF,0x28308BF7,
550 0x2846C909,0x285CFE10,0x28732B08,0x28894FED,0x289F6CBB,0x28B5816C,
551 0x28CB8DFD,0x28E19269,0x28F78EAC,0x290D82C1,0x29236EA4,0x29395251,
552 0x294F2DC3,0x296500F6,0x297ACBE5,0x29908E8C,0x29A648E7,0x29BBFAF2,
553 0x29D1A4A7,0x29E74604,0x29FCDF02,0x2A126F9F,0x2A27F7D6,0x2A3D77A3,
554 0x2A52EF00,0x2A685DEB,0x2A7DC45F,0x2A932256,0x2AA877CE,0x2ABDC4C2,
555 0x2AD3092E,0x2AE8450D,0x2AFD785B,0x2B12A314,0x2B27C534,0x2B3CDEB6,
556 0x2B51EF96,0x2B66F7D1,0x2B7BF761,0x2B90EE43,0x2BA5DC73,0x2BBAC1EC,
557 0x2BCF9EAA,0x2BE472A9,0x2BF93DE5,0x2C0E005A,0x2C22BA03,0x2C376ADC,
558 0x2C4C12E2,0x2C60B210,0x2C754862,0x2C89D5D4,0x2C9E5A61,0x2CB2D606,
559 0x2CC748BF,0x2CDBB288,0x2CF0135C,0x2D046B37,0x2D18BA16,0x2D2CFFF4,
560 0x2D413CCD,0x2D55709D,0x2D699B61,0x2D7DBD14,0x2D91D5B1,0x2DA5E536,
561 0x2DB9EB9E,0x2DCDE8E5,0x2DE1DD07,0x2DF5C801,0x2E09A9CD,0x2E1D8269,
562 0x2E3151D0,0x2E4517FE,0x2E58D4EF,0x2E6C88A0,0x2E80330C,0x2E93D430,
563 0x2EA76C08,0x2EBAFA8F,0x2ECE7FC2,0x2EE1FB9C,0x2EF56E1B,0x2F08D73A,
564 0x2F1C36F5,0x2F2F8D48,0x2F42DA30,0x2F561DA9,0x2F6957AE,0x2F7C883D,
565 0x2F8FAF50,0x2FA2CCE5,0x2FB5E0F8,0x2FC8EB84,0x2FDBEC86,0x2FEEE3FA,
566 0x3001D1DC,0x3014B629,0x302790DD,0x303A61F3,0x304D2969,0x305FE73B,
567 0x30729B64,0x308545E1,0x3097E6AE,0x30AA7DC8,0x30BD0B2B,0x30CF8ED3,
568 0x30E208BD,0x30F478E4,0x3106DF46,0x31193BDD,0x312B8EA8,0x313DD7A2,
569 0x315016C7,0x31624C14,0x31747785,0x31869916,0x3198B0C5,0x31AABE8D,
570 0x31BCC26A,0x31CEBC5A,0x31E0AC58,0x31F29261,0x32046E72,0x32164086,
571 0x3228089A,0x3239C6AC,0x324B7AB6,0x325D24B6,0x326EC4A8,0x32805A89,
572 0x3291E654,0x32A36807,0x32B4DF9F,0x32C64D17,0x32D7B06C,0x32E9099A,
573 0x32FA589F,0x330B9D77,0x331CD81D,0x332E0890,0x333F2ECB,0x33504ACB,
574 0x33615C8C,0x3372640C,0x33836146,0x33945438,0x33A53CDD,0x33B61B34,
575 0x33C6EF37,0x33D7B8E5,0x33E87838,0x33F92D2F,0x3409D7C6,0x341A77FA,
576 0x342B0DC6,0x343B9929,0x344C1A1E,0x345C90A2,0x346CFCB2,0x347D5E4B,
577 0x348DB56A,0x349E020A,0x34AE442A,0x34BE7BC5,0x34CEA8D9,0x34DECB62,
578 0x34EEE35C,0x34FEF0C6,0x350EF39B,0x351EEBD9,0x352ED97C,0x353EBC81,
579 0x354E94E4,0x355E62A4,0x356E25BB,0x357DDE29,0x358D8BE8,0x359D2EF7,
580 0x35ACC751,0x35BC54F5,0x35CBD7DE,0x35DB500A,0x35EABD75,0x35FA201D,
581 0x360977FF,0x3618C517,0x36280762,0x36373EDD,0x36466B86,0x36558D58,
582 0x3664A452,0x3673B070,0x3682B1B0,0x3691A80D,0x36A09386,0x36AF7417,
583 0x36BE49BD,0x36CD1475,0x36DBD43D,0x36EA8911,0x36F932EE,0x3707D1D2,
584 0x371665BA,0x3724EEA2,0x37336C88,0x3741DF69,0x37504742,0x375EA410,
585 0x376CF5D1,0x377B3C80,0x3789781D,0x3797A8A3,0x37A5CE10,0x37B3E860,
586 0x37C1F793,0x37CFFBA3,0x37DDF48F,0x37EBE255,0x37F9C4F0,0x38079C5E,
587 0x3815689D,0x382329AA,0x3830DF81,0x383E8A21,0x384C2987,0x3859BDB0,
588 0x38674698,0x3874C43E,0x3882369F,0x388F9DB8,0x389CF986,0x38AA4A07,
589 0x38B78F38,0x38C4C916,0x38D1F79F,0x38DF1AD0,0x38EC32A7,0x38F93F21,
590 0x3906403A,0x391335F2,0x39202045,0x392CFF30,0x3939D2B1,0x39469AC6,
591 0x3953576B,0x3960089F,0x396CAE5E,0x397948A7,0x3985D777,0x39925ACA,
592 0x399ED2A0,0x39AB3EF4,0x39B79FC6,0x39C3F512,0x39D03ED5,0x39DC7D0E,
593 0x39E8AFBA,0x39F4D6D6,0x3A00F260,0x3A0D0256,0x3A1906B6,0x3A24FF7C,
594 0x3A30ECA6,0x3A3CCE33,0x3A48A41F,0x3A546E69,0x3A602D0D,0x3A6BE00A,
595 0x3A77875E,0x3A832305,0x3A8EB2FF,0x3A9A3747,0x3AA5AFDD,0x3AB11CBD,
596 0x3ABC7DE6,0x3AC7D355,0x3AD31D08,0x3ADE5AFC,0x3AE98D30,0x3AF4B3A2,
597 0x3AFFCE4E,0x3B0ADD33,0x3B15E04E,0x3B20D79E,0x3B2BC320,0x3B36A2D3,
598 0x3B4176B3,0x3B4C3EBE,0x3B56FAF3,0x3B61AB50,0x3B6C4FD1,0x3B76E876,
599 0x3B81753C,0x3B8BF621,0x3B966B22,0x3BA0D43E,0x3BAB3173,0x3BB582BE,
600 0x3BBFC81E,0x3BCA0190,0x3BD42F13,0x3BDE50A4,0x3BE86641,0x3BF26FE9,
601 0x3BFC6D99,0x3C065F4F,0x3C10450A,0x3C1A1EC7,0x3C23EC85,0x3C2DAE41,
602 0x3C3763F9,0x3C410DAC,0x3C4AAB58,0x3C543CFA,0x3C5DC291,0x3C673C1B,
603 0x3C70A996,0x3C7A0B01,0x3C836058,0x3C8CA99B,0x3C95E6C7,0x3C9F17DB,
604 0x3CA83CD5,0x3CB155B3,0x3CBA6273,0x3CC36314,0x3CCC5793,0x3CD53FEF,
605 0x3CDE1C27,0x3CE6EC37,0x3CEFB01F,0x3CF867DD,0x3D01136E,0x3D09B2D2,
606 0x3D124607,0x3D1ACD0A,0x3D2347DB,0x3D2BB677,0x3D3418DD,0x3D3C6F0B,
607 0x3D44B8FF,0x3D4CF6B9,0x3D552835,0x3D5D4D73,0x3D656671,0x3D6D732D,
608 0x3D7573A6,0x3D7D67D9,0x3D854FC7,0x3D8D2B6C,0x3D94FAC7,0x3D9CBDD8,
609 0x3DA4749B,0x3DAC1F10,0x3DB3BD36,0x3DBB4F0A,0x3DC2D48B,0x3DCA4DB8,
610 0x3DD1BA8F,0x3DD91B0E,0x3DE06F35,0x3DE7B701,0x3DEEF272,0x3DF62185,
611 0x3DFD443A,0x3E045A8F,0x3E0B6482,0x3E126213,0x3E19533F,0x3E203806,
612 0x3E271065,0x3E2DDC5C,0x3E349BEA,0x3E3B4F0C,0x3E41F5C2,0x3E48900A,
613 0x3E4F1DE3,0x3E559F4C,0x3E5C1443,0x3E627CC7,0x3E68D8D6,0x3E6F2871,
614 0x3E756B94,0x3E7BA23F,0x3E81CC72,0x3E87EA29,0x3E8DFB65,0x3E940024,
615 0x3E99F865,0x3E9FE426,0x3EA5C367,0x3EAB9627,0x3EB15C63,0x3EB7161C,
616 0x3EBCC34F,0x3EC263FC,0x3EC7F822,0x3ECD7FBF,0x3ED2FAD2,0x3ED8695B,
617 0x3EDDCB58,0x3EE320C8,0x3EE869AB,0x3EEDA5FE,0x3EF2D5C1,0x3EF7F8F3,
618 0x3EFD0F93,0x3F0219A0,0x3F071719,0x3F0C07FD,0x3F10EC4A,0x3F15C401,
619 0x3F1A8F1F,0x3F1F4DA5,0x3F23FF90,0x3F28A4E1,0x3F2D3D96,0x3F31C9AE,
620 0x3F364928,0x3F3ABC04,0x3F3F2241,0x3F437BDD,0x3F47C8D8,0x3F4C0931,
621 0x3F503CE7,0x3F5463FA,0x3F587E68,0x3F5C8C30,0x3F608D52,0x3F6481CE,
622 0x3F6869A1,0x3F6C44CC,0x3F70134E,0x3F73D526,0x3F778A53,0x3F7B32D4,
623 0x3F7ECEA9,0x3F825DD1,0x3F85E04B,0x3F895617,0x3F8CBF34,0x3F901BA1,
624 0x3F936B5D,0x3F96AE69,0x3F99E4C2,0x3F9D0E69,0x3FA02B5D,0x3FA33B9E,
625 0x3FA63F2A,0x3FA93601,0x3FAC2023,0x3FAEFD8F,0x3FB1CE44,0x3FB49242,
626 0x3FB74988,0x3FB9F416,0x3FBC91EB,0x3FBF2306,0x3FC1A768,0x3FC41F10,
627 0x3FC689FC,0x3FC8E82E,0x3FCB39A3,0x3FCD7E5C,0x3FCFB659,0x3FD1E198,
628 0x3FD4001A,0x3FD611DE,0x3FD816E3,0x3FDA0F29,0x3FDBFAB1,0x3FDDD978,
629 0x3FDFAB80,0x3FE170C7,0x3FE3294E,0x3FE4D513,0x3FE67417,0x3FE8065A,
630 0x3FE98BDA,0x3FEB0498,0x3FEC7094,0x3FEDCFCC,0x3FEF2242,0x3FF067F4,
631 0x3FF1A0E2,0x3FF2CD0C,0x3FF3EC73,0x3FF4FF14,0x3FF604F1,0x3FF6FE0A,
632 0x3FF7EA5D,0x3FF8C9EB,0x3FF99CB4,0x3FFA62B7,0x3FFB1BF5,0x3FFBC86D,
633 0x3FFC681F,0x3FFCFB0A,0x3FFD8130,0x3FFDFA8F,0x3FFE6728,0x3FFEC6FA,
634 0x3FFF1A06,0x3FFF604B,0x3FFF99CA,0x3FFFC681,0x3FFFE672,0x3FFFF99D,
635 0x40000000};
636
637 /*
638 * routine to return a fixed-point sine value for "n" (in tenth-degrees from 0 to
639 * 3599)
640 */
sine(INTBIG n)641 INTBIG sine(INTBIG n)
642 {
643 if (n <= 900) return(db_sinetable[n]);
644 if (n <= 1800) return(db_sinetable[1800-n]);
645 if (n <= 2700) return(-db_sinetable[n-1800]);
646 return(-db_sinetable[3600-n]);
647 }
648
649 /*
650 * routine to return a fixed-point cosine value for "n" (in tenth-degrees from 0 to
651 * 3599)
652 */
cosine(INTBIG n)653 INTBIG cosine(INTBIG n)
654 {
655 if (n <= 900) return(db_sinetable[900-n]);
656 if (n <= 1800) return(-db_sinetable[n-900]);
657 if (n <= 2700) return(-db_sinetable[2700-n]);
658 return(db_sinetable[n-2700]);
659 }
660
661 /*
662 * routine to return the angle from point (x1,y1) to point (x2,y2) in tenth-degrees
663 * where right-pointing is 0 and positive angles are counter-clockwise.
664 */
figureangle(INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2)665 INTBIG figureangle(INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2)
666 {
667 double dx, dy, ang;
668 INTBIG iang;
669
670 dx = x2 - x1;
671 dy = y2 - y1;
672 if (dx == 0.0 && dy == 0.0)
673 {
674 ttyputerr(_("Warning: domain violation while figuring angle"));
675 return(0);
676 }
677 ang = atan2(dy, dx);
678 if (ang < 0.0) ang += EPI*2.0;
679 iang = rounddouble(ang * 1800.0 / EPI);
680 return(iang);
681 }
682
683 /*
684 * routine to return the angle from point (x1,y1) to point (x2,y2) in tenth-degrees
685 * where right-pointing is 0 and positive angles are counter-clockwise.
686 */
ffigureangle(INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2)687 double ffigureangle(INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2)
688 {
689 double dx, dy, ang;
690
691 dx = x2 - x1;
692 dy = y2 - y1;
693 if (dx == 0.0 && dy == 0.0)
694 {
695 ttyputerr(_("Warning: domain violation while figuring angle"));
696 return(0);
697 }
698 ang = atan2(dy, dx);
699 if (ang < 0.0) ang += EPI*2.0;
700 return(ang);
701 }
702
703 /************************* PRIME NUMBERS *************************/
704
705 /* This table contains the first few hundred prime numbers */
706 static INTBIG db_small_primes[] =
707 {
708 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
709 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
710 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191,
711 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257,
712 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331,
713 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401,
714 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467,
715 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563,
716 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
717 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709,
718 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
719 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877,
720 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967,
721 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
722 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
723 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181,
724 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249,
725 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307,
726 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423,
727 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481,
728 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549,
729 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609,
730 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693,
731 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759,
732 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861,
733 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931,
734 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003,
735 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083,
736 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143,
737 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
738 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311,
739 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383,
740 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459,
741 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
742 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657,
743 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707,
744 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777,
745 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851,
746 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939,
747 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023,
748 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119,
749 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209,
750 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301,
751 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361,
752 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461,
753 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533,
754 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
755 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677,
756 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767,
757 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851,
758 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923,
759 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013,
760 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093,
761 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
762 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259,
763 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349,
764 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447,
765 4451, 4457, 4463
766 };
767 #define NUMSMALLPRIMES (sizeof(db_small_primes) / SIZEOFINTBIG)
768
769 /*
770 * Routine to initialize the prime number tables. Returns true on error.
771 */
db_primeinit(void)772 BOOLEAN db_primeinit(void)
773 {
774 REGISTER INTBIG i;
775
776 if (db_primearraytotal != 0) return(FALSE);
777
778 if (db_multiprocessing) emutexlock(db_primenumbermutex);
779 if (db_primearraytotal == 0)
780 {
781 db_primearray = (INTBIG *)emalloc(NUMSMALLPRIMES * SIZEOFINTBIG, db_cluster);
782 if (db_primearray == 0)
783 {
784 if (db_multiprocessing) emutexunlock(db_primenumbermutex);
785 return(TRUE);
786 }
787 for(i=0; i<NUMSMALLPRIMES; i++)
788 db_primearray[i] = db_small_primes[i];
789 db_primearraytotal = NUMSMALLPRIMES;
790 db_maxcheckableprime = db_primearray[NUMSMALLPRIMES-1] *
791 db_primearray[NUMSMALLPRIMES-1];
792 }
793 if (db_multiprocessing) emutexunlock(db_primenumbermutex);
794 return(FALSE);
795 }
796
797 /*
798 * Routine to extend the tables of prime numbers so that prime number "length" is
799 * present. Returns true on error.
800 */
db_extendprimetable(INTBIG length)801 BOOLEAN db_extendprimetable(INTBIG length)
802 {
803 REGISTER INTBIG newtotal, i, *newprimearray;
804
805 if (db_primeinit()) return(TRUE);
806 if (length >= db_primearraytotal)
807 {
808 if (db_multiprocessing) emutexlock(db_primenumbermutex);
809 newtotal = db_primearraytotal * 2;
810 if (length >= newtotal) newtotal = length + 100;
811 newprimearray = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, db_cluster);
812 if (newprimearray == 0)
813 {
814 if (db_multiprocessing) emutexunlock(db_primenumbermutex);
815 return(TRUE);
816 }
817 for(i=0; i<db_primearraytotal; i++)
818 newprimearray[i] = db_primearray[i];
819
820 /* fill the extra elements */
821 for(i=db_primearraytotal; i<newtotal; i++)
822 newprimearray[i] = pickprime(newprimearray[i-1] + 2);
823
824 efree((CHAR *)db_primearray);
825 db_primearray = newprimearray;
826 db_primearraytotal = newtotal;
827 db_maxcheckableprime = db_primearray[newtotal-1] *
828 db_primearray[newtotal-1];
829 if (db_maxcheckableprime <= 0) db_maxcheckableprime = MAXINTBIG;
830 if (db_multiprocessing) emutexunlock(db_primenumbermutex);
831 }
832 return(FALSE);
833 }
834
835 /*
836 * A fast and simple way to check if a number is prime - it
837 * shouldn't be divisible by any prime less than it's square
838 * root.
839 */
db_isprime(INTBIG n)840 BOOLEAN db_isprime(INTBIG n)
841 {
842 REGISTER INTBIG i, m;
843
844 if ((n % 2) == 0) return(FALSE);
845 if (db_primeinit()) return(FALSE);
846
847 /* if we can't check it, assume it is not prime */
848 if (n >= db_maxcheckableprime) return(FALSE);
849
850 for(i = 0; i < db_primearraytotal; i++)
851 {
852 m = db_primearray[i];
853 if (m * m >= n) break;
854 if (n % m == 0) return(FALSE);
855 }
856 return(TRUE);
857 }
858
859 /*
860 * Routine to return the "n"th prime number.
861 * Prime #0 is 2, #1 is 3, #2 is 5...
862 */
getprime(INTBIG n)863 INTBIG getprime(INTBIG n)
864 {
865 if (n >= db_primearraytotal)
866 {
867 if (db_extendprimetable(n)) return(0);
868 }
869 return(db_primearray[n]);
870 }
871
872 /*
873 * Returns the first prime over N, by checking all odd numbers
874 * over N till it finds one.
875 */
pickprime(INTBIG n)876 INTBIG pickprime(INTBIG n)
877 {
878 if (db_primeinit()) return(0);
879 if (n >= db_maxcheckableprime) return(0);
880 if (n % 2 == 0) n++;
881 while (!db_isprime(n))
882 {
883 n += 2;
884 }
885 return(n);
886 }
887
888 /************************* MISCELLANEOUS MATHEMATICS *************************/
889
890 /*
891 * integer square-root.
892 */
intsqrt(INTBIG val)893 INTBIG intsqrt(INTBIG val)
894 {
895 REGISTER INTBIG guess, i;
896
897 /* can only take square root of a positive number */
898 if (val <= 0) return(val);
899
900 /* compute initial guess of square root */
901 guess = 0;
902 i = val;
903 while (i != 0)
904 {
905 guess = (guess << 1) | 1;
906 i = i >> 2;
907 }
908
909 /* six iterations of Newton's approximation to square root */
910 for(i=0; i<6; i++) guess = (guess + val / guess) >> 1;
911
912 return(guess);
913 }
914
915 /*
916 * routine to compute the euclidean distance between point (x1,y1) and
917 * point (x2,y2). This may require determining the hypotenuse of a triangle
918 * by finding square roots, in which case an integer square-root subroutine
919 * that uses Newton's method is called.
920 */
computedistance(INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2)921 INTBIG computedistance(INTBIG x1,INTBIG y1, INTBIG x2,INTBIG y2)
922 {
923 REGISTER INTBIG dx, dy, res;
924 double fdx, fdy;
925
926 dx = abs(x1 - x2);
927 dy = abs(y1 - y2);
928 if (dx == 0 || dy == 0) return(dx + dy);
929
930 /* nonmanhattan distance: need to do square root */
931 if (dx <= 32767 && dy <= 32767) return(intsqrt(dx*dx + dy*dy));
932
933 /* do it in floating point */
934 fdx = dx; fdy = dy;
935 res = rounddouble(sqrt(fdx*fdx + fdy*fdy));
936 return(res);
937 }
938
939 /*
940 * routine to return true if the point (x,y) is on the line segment from
941 * (x1,y1) to (x2,y2)
942 */
isonline(INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,INTBIG x,INTBIG y)943 BOOLEAN isonline(INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2, INTBIG x, INTBIG y)
944 {
945 /* trivial rejection if point not in the bounding box of the line */
946 if (x < mini(x1,x2)) return(FALSE);
947 if (x > maxi(x1,x2)) return(FALSE);
948 if (y < mini(y1,y2)) return(FALSE);
949 if (y > maxi(y1,y2)) return(FALSE);
950
951 /* handle manhattan cases specially */
952 if (x1 == x2)
953 {
954 if (x == x1) return(TRUE);
955 return(FALSE);
956 }
957 if (y1 == y2)
958 {
959 if (y == y1) return(TRUE);
960 return(FALSE);
961 }
962
963 /* handle nonmanhattan */
964 if (muldiv(x-x1, y2-y1, x2-x1) == y-y1) return(TRUE);
965 return(FALSE);
966 }
967
968 /*
969 * routine to determine the intersection of two lines and return that point
970 * in (x,y). The first line is at "ang1" tenth-degrees and runs through (x1,y1)
971 * and the second line is at "ang2" tenth-degrees and runs through (x2,y2). The
972 * routine returns a negative value if the lines do not intersect.
973 */
intersect(INTBIG x1,INTBIG y1,INTBIG ang1,INTBIG x2,INTBIG y2,INTBIG ang2,INTBIG * x,INTBIG * y)974 INTBIG intersect(INTBIG x1, INTBIG y1, INTBIG ang1, INTBIG x2, INTBIG y2,
975 INTBIG ang2, INTBIG *x, INTBIG *y)
976 {
977 double fa1, fb1, fc1, fa2, fb2, fc2, fang1, fang2, fswap, fy;
978
979 /* cannot handle lines if they are at the same angle */
980 if (ang1 == ang2) return(-1);
981
982 /* also at the same angle if off by 180 degrees */
983 if (mini(ang1, ang2) + 1800 == maxi(ang1, ang2)) return(-1);
984
985 fang1 = ang1 / 1800.0 * EPI;
986 fang2 = ang2 / 1800.0 * EPI;
987 fa1 = sin(fang1); fb1 = -cos(fang1);
988 fc1 = -fa1 * ((double)x1) - fb1 * ((double)y1);
989 fa2 = sin(fang2); fb2 = -cos(fang2);
990 fc2 = -fa2 * ((double)x2) - fb2 * ((double)y2);
991 if (fabs(fa1) < fabs(fa2))
992 {
993 fswap = fa1; fa1 = fa2; fa2 = fswap;
994 fswap = fb1; fb1 = fb2; fb2 = fswap;
995 fswap = fc1; fc1 = fc2; fc2 = fswap;
996 }
997 fy = (fa2 * fc1 / fa1 - fc2) / (fb2 - fa2*fb1/fa1);
998 *y = rounddouble(fy);
999 *x = rounddouble((-fb1 * fy - fc1) / fa1);
1000 return(0);
1001 }
1002
1003 /*
1004 * routine to determine the intersection of two lines and return that point
1005 * in (x,y). The first line is at "ang1" radians and runs through (x1,y1)
1006 * and the second line is at "ang2" radians and runs through (x2,y2). The
1007 * routine returns a negative value if the lines do not intersect.
1008 */
fintersect(INTBIG x1,INTBIG y1,double fang1,INTBIG x2,INTBIG y2,double fang2,INTBIG * x,INTBIG * y)1009 INTBIG fintersect(INTBIG x1, INTBIG y1, double fang1, INTBIG x2, INTBIG y2,
1010 double fang2, INTBIG *x, INTBIG *y)
1011 {
1012 double fa1, fb1, fc1, fa2, fb2, fc2, fswap, fy, fmin, fmax;
1013
1014 /* cannot handle lines if they are at the same angle */
1015 if (doublesequal(fang1, fang2)) return(-1);
1016
1017 /* also at the same angle if off by 180 degrees */
1018 if (fang1 < fang2) { fmin = fang1; fmax = fang2; } else
1019 { fmin = fang2; fmax = fang1; }
1020 if (doublesequal(fmin + EPI, fmax)) return(-1);
1021
1022 fa1 = sin(fang1); fb1 = -cos(fang1);
1023 fc1 = -fa1 * ((double)x1) - fb1 * ((double)y1);
1024 fa2 = sin(fang2); fb2 = -cos(fang2);
1025 fc2 = -fa2 * ((double)x2) - fb2 * ((double)y2);
1026 if (fabs(fa1) < fabs(fa2))
1027 {
1028 fswap = fa1; fa1 = fa2; fa2 = fswap;
1029 fswap = fb1; fb1 = fb2; fb2 = fswap;
1030 fswap = fc1; fc1 = fc2; fc2 = fswap;
1031 }
1032 fy = (fa2 * fc1 / fa1 - fc2) / (fb2 - fa2*fb1/fa1);
1033 *y = rounddouble(fy);
1034 *x = rounddouble((-fb1 * fy - fc1) / fa1);
1035 return(0);
1036 }
1037
1038 /*
1039 * Routine to determine whether the line segment from (fx1,fy1) to (tx1,ty1)
1040 * intersects the line segment from (fx2,fy2) to (tx2,ty2). Returns true if
1041 * they do and sets the intersection point to (ix,iy).
1042 */
segintersect(INTBIG fx1,INTBIG fy1,INTBIG tx1,INTBIG ty1,INTBIG fx2,INTBIG fy2,INTBIG tx2,INTBIG ty2,INTBIG * ix,INTBIG * iy)1043 BOOLEAN segintersect(INTBIG fx1, INTBIG fy1, INTBIG tx1, INTBIG ty1,
1044 INTBIG fx2, INTBIG fy2, INTBIG tx2, INTBIG ty2, INTBIG *ix, INTBIG *iy)
1045 {
1046 REGISTER INTBIG ang1, ang2;
1047
1048 ang1 = figureangle(fx1, fy1, tx1, ty1);
1049 ang2 = figureangle(fx2, fy2, tx2, ty2);
1050 if (intersect(fx1, fy1, ang1, fx2, fy2, ang2, ix, iy) >= 0)
1051 {
1052 if (*ix < mini(fx1, tx1) || *ix > maxi(fx1, tx1) ||
1053 *iy < mini(fy1, ty1) || *iy > maxi(fy1, ty1)) return(FALSE);
1054 if (*ix < mini(fx2, tx2) || *ix > maxi(fx2, tx2) ||
1055 *iy < mini(fy2, ty2) || *iy > maxi(fy2, ty2)) return(FALSE);
1056 return(TRUE);
1057 }
1058 return(FALSE);
1059 }
1060
1061 /*
1062 * routine to find the intersection points between the circle at (icx,icy) with point (isx,isy)
1063 * and the line from (lx1,ly1) to (lx2,ly2). Returns the two points in (ix1,iy1) and (ix2,iy2).
1064 * Allows intersection tolerance of "tolerance".
1065 * Returns the number of intersection points (0 if none, 1 if tangent, 2 if intersecting).
1066 */
circlelineintersection(INTBIG icx,INTBIG icy,INTBIG isx,INTBIG isy,INTBIG lx1,INTBIG ly1,INTBIG lx2,INTBIG ly2,INTBIG * ix1,INTBIG * iy1,INTBIG * ix2,INTBIG * iy2,INTBIG tolerance)1067 INTBIG circlelineintersection(INTBIG icx, INTBIG icy, INTBIG isx, INTBIG isy,
1068 INTBIG lx1, INTBIG ly1, INTBIG lx2, INTBIG ly2, INTBIG *ix1, INTBIG *iy1,
1069 INTBIG *ix2, INTBIG *iy2, INTBIG tolerance)
1070 {
1071 double fx, fy, radius, adjacent, angle, intangle, a1, a2, segx, segy, m, b, mi, bi;
1072
1073 /*
1074 * construct a line that is perpendicular to the intersection line and passes
1075 * through the circle center. It meets the intersection line at (segx, segy)
1076 */
1077 if (ly1 == ly2)
1078 {
1079 segx = icx;
1080 segy = ly1;
1081 } else if (lx1 == lx2)
1082 {
1083 segx = lx1;
1084 segy = icy;
1085 } else
1086 {
1087 /* compute equation of the line */
1088 fx = lx1 - lx2; fy = ly1 - ly2;
1089 m = fy / fx;
1090 b = -lx1; b *= m; b += ly1;
1091
1092 /* compute perpendicular to line through the point */
1093 mi = -1.0/m;
1094 bi = -icx; bi *= mi; bi += icy;
1095
1096 /* compute intersection of the lines */
1097 segx = (bi-b) / (m-mi);
1098 segy = m * segx + b;
1099 }
1100
1101 /* special case when line passes through the circle center */
1102 if (segx == icx && segy == icy)
1103 {
1104 fx = isx - icx; fy = isy - icy;
1105 radius = sqrt(fx*fx + fy*fy);
1106
1107 fx = lx2 - lx1; fy = ly2 - ly1;
1108 if (fx == 0.0 && fy == 0.0)
1109 {
1110 ttyputerr(_("Domain error doing circle/line intersection"));
1111 return(0);
1112 }
1113 angle = atan2(fy, fx);
1114
1115 *ix1 = icx + rounddouble(cos(angle) * radius);
1116 *iy1 = icy + rounddouble(sin(angle) * radius);
1117
1118 *ix2 = icx + rounddouble(cos(-angle) * radius);
1119 *iy2 = icy + rounddouble(sin(-angle) * radius);
1120 } else
1121 {
1122 /*
1123 * construct a right triangle with the three points: (icx, icy), (segx, segy), and (ix1,iy1)
1124 * the right angle is at the point (segx, segy) and the hypotenuse is the circle radius
1125 * The unknown point is (ix1, iy1), the intersection of the line and the circle.
1126 * To find it, determine the angle at the point (icx, icy)
1127 */
1128 fx = isx - icx; fy = isy - icy;
1129 radius = sqrt(fx*fx + fy*fy);
1130
1131 fx = segx - icx; fy = segy - icy;
1132 adjacent = sqrt(fx*fx + fy*fy);
1133
1134 /* if they are within tolerance, accept */
1135 if (fabs(adjacent - radius) < tolerance)
1136 {
1137 *ix1 = rounddouble(segx);
1138 *iy1 = rounddouble(segy);
1139 return(1);
1140 }
1141
1142 /* if the point is outside of the circle, quit */
1143 if (adjacent > radius) return(0);
1144
1145 /* for zero radius, use circle center */
1146 if (radius == 0.0)
1147 {
1148 *ix1 = *ix2 = icx;
1149 *iy1 = *iy2 = icy;
1150 } else
1151 {
1152 /*
1153 * now determine the angle from the center to the point (segx, segy) and offset that angle
1154 * by "angle". Then project it by "radius" to get the two intersection points
1155 */
1156 angle = acos(adjacent / radius);
1157 fx = segx - icx; fy = segy - icy;
1158 if (fx == 0.0 && fy == 0.0)
1159 {
1160 ttyputerr(_("Domain error doing line/circle intersection"));
1161 return(0);
1162 }
1163 intangle = atan2(fy, fx);
1164 a1 = intangle - angle; a2 = intangle + angle;
1165 *ix1 = icx + rounddouble(cos(a1) * radius);
1166 *iy1 = icy + rounddouble(sin(a1) * radius);
1167
1168 *ix2 = icx + rounddouble(cos(a2) * radius);
1169 *iy2 = icy + rounddouble(sin(a2) * radius);
1170 }
1171 }
1172
1173 if (*ix1 == *ix2 && *iy1 == *iy2) return(1);
1174 return(2);
1175 }
1176
1177 /*
1178 * routine to find the two tangent points on a circle that connect to the point
1179 * (x,y). The circle is at (cx,cy) with a point at (sx,sy). The points are returned in
1180 * (ix1,iy1) and (ix2, iy2). Returns true if tangent points cannot be found
1181 * (if the point (x,y) is inside of the circle).
1182 */
circletangents(INTBIG x,INTBIG y,INTBIG cx,INTBIG cy,INTBIG sx,INTBIG sy,INTBIG * ix1,INTBIG * iy1,INTBIG * ix2,INTBIG * iy2)1183 BOOLEAN circletangents(INTBIG x, INTBIG y, INTBIG cx, INTBIG cy, INTBIG sx, INTBIG sy,
1184 INTBIG *ix1, INTBIG *iy1, INTBIG *ix2, INTBIG *iy2)
1185 {
1186 double in, offset, dang, ang1, ang2, dx, dy, hypotenuse, radius;
1187
1188 /* determine circle radius, make sure tangents can be determined */
1189 dx = sx - cx; dy = sy - cy;
1190 radius = sqrt(dx*dx + dy*dy);
1191 dx = x - cx; dy = y - cy;
1192 hypotenuse = sqrt(dx*dx + dy*dy);
1193 if (hypotenuse + 1.0 <= radius) return(TRUE);
1194 if (hypotenuse < radius) radius = hypotenuse;
1195
1196 /*
1197 * construct a right triangle, where:
1198 * the line from the circle center to the point (x,y) is the hypotenuse
1199 * the line from the circle center to an intersection point is side of length "r"
1200 * then the angle between these two lines is arccosine(r/hypotenuse)
1201 */
1202 in = radius / hypotenuse;
1203 offset = acos(in);
1204
1205 dx = (double)x-cx; dy = (double)y-cy;
1206 if (dx == 0.0 && dy == 0.0)
1207 {
1208 ttyputerr(_("Domain error doing circle tangents"));
1209 return(TRUE);
1210 }
1211 dang = atan2(dy, dx);
1212 ang1 = dang - offset;
1213 if (ang1 < 0.0) ang1 += EPI*2.0;
1214 ang2 = dang + offset;
1215 if (ang2 < 0.0) ang2 += EPI*2.0;
1216 if (ang2 >= EPI*2.0) ang2 -= EPI*2.0;
1217 *ix1 = cx + rounddouble(cos(ang1)*radius);
1218 *iy1 = cy + rounddouble(sin(ang1)*radius);
1219 *ix2 = cx + rounddouble(cos(ang2)*radius);
1220 *iy2 = cy + rounddouble(sin(ang2)*radius);
1221 return(FALSE);
1222 }
1223
1224 /*
1225 * routine to convert an arc to line segments. The arc goes counterclockwise from
1226 * (sx,sy) to (ex,ey), centered about the point (cx,cy). The polygon "poly" is loaded
1227 * with the line-approximation. There is an arc segment every "arcres" tenth-degrees and
1228 * no segment sags from its true curvature by more than "arcsag".
1229 */
arctopoly(INTBIG cx,INTBIG cy,INTBIG sx,INTBIG sy,INTBIG ex,INTBIG ey,POLYGON * poly,INTBIG arcres,INTBIG arcsag)1230 void arctopoly(INTBIG cx, INTBIG cy, INTBIG sx, INTBIG sy, INTBIG ex, INTBIG ey, POLYGON *poly,
1231 INTBIG arcres, INTBIG arcsag)
1232 {
1233 REGISTER INTBIG as, ae, ang, degreespersegment, segmentcount, pointcount,
1234 curangle, pointnum, angleincrement;
1235 REGISTER INTBIG radius;
1236 double fradius, sag;
1237
1238 radius = computedistance(cx, cy, sx, sy);
1239 as = figureangle(cx, cy, sx, sy);
1240 ae = figureangle(cx, cy, ex, ey);
1241 if (ae > as) ang = ae - as; else
1242 if (as > ae) ang = ae + 3600 - as; else
1243 ang = 0;
1244
1245 /* determine number of degrees per segment */
1246 fradius = radius;
1247 sag = arcsag;
1248 if (fradius - sag <= 0.0) degreespersegment = ang; else
1249 degreespersegment = rounddouble(2.0 * acos((fradius - sag) / fradius) * 1800.0 / EPI);
1250 if (degreespersegment > arcres) degreespersegment = arcres;
1251
1252 if (degreespersegment <= 0) degreespersegment = 1;
1253 segmentcount = ang / degreespersegment;
1254 if (segmentcount < 1) segmentcount = 1;
1255 angleincrement = ang / segmentcount;
1256 pointcount = segmentcount + 1;
1257 curangle = as;
1258
1259 if (poly->limit < pointcount) (void)extendpolygon(poly, pointcount);
1260 poly->count = pointcount;
1261 poly->style = OPENED;
1262
1263 for(pointnum = 0; pointnum < pointcount; pointnum++)
1264 {
1265 if (pointnum == 0)
1266 {
1267 poly->xv[pointnum] = sx;
1268 poly->yv[pointnum] = sy;
1269 } else if (pointnum == pointcount-1)
1270 {
1271 poly->xv[pointnum] = ex;
1272 poly->yv[pointnum] = ey;
1273 } else
1274 {
1275 poly->xv[pointnum] = cx + mult(cosine(curangle), radius);
1276 poly->yv[pointnum] = cy + mult(sine(curangle), radius);
1277 }
1278
1279 curangle += angleincrement;
1280 if (curangle >= 3600) curangle -= 3600;
1281 }
1282 }
1283
1284 /*
1285 * routine to convert a circle to line segments. The circle is at (cx,cy) and has radius
1286 * "radius". The polygon "poly" is loaded with the line-approximation. There is an arc
1287 * segment every "arcres" tenth-degrees and no segment sags from its true curvature by
1288 * more than "arcsag".
1289 */
circletopoly(INTBIG cx,INTBIG cy,INTBIG radius,POLYGON * poly,INTBIG arcres,INTBIG arcsag)1290 void circletopoly(INTBIG cx, INTBIG cy, INTBIG radius, POLYGON *poly, INTBIG arcres, INTBIG arcsag)
1291 {
1292 REGISTER INTBIG degreespersegment, segmentcount, pointcount,
1293 curangle, pointnum, angleincrement;
1294 REGISTER INTBIG sx, sy;
1295 double fradius, sag;
1296
1297 sx = cx + radius; sy = cy;
1298
1299 /* determine number of degrees per segment */
1300 fradius = radius;
1301 sag = arcsag;
1302 degreespersegment = rounddouble(2.0 * acos((fradius - sag) / fradius) * 1800.0 / EPI);
1303 if (degreespersegment > arcres) degreespersegment = arcres;
1304
1305 if (degreespersegment <= 0) degreespersegment = 1;
1306 segmentcount = 3600 / degreespersegment;
1307 if (segmentcount < 1) segmentcount = 1;
1308 angleincrement = 3600 / segmentcount;
1309 pointcount = segmentcount + 1;
1310
1311 if (poly->limit < pointcount) (void)extendpolygon(poly, pointcount);
1312 poly->count = pointcount;
1313 poly->style = OPENED;
1314
1315 curangle = 0;
1316 for(pointnum = 0; pointnum < pointcount; pointnum++)
1317 {
1318 if (pointnum == 0)
1319 {
1320 poly->xv[pointnum] = sx;
1321 poly->yv[pointnum] = sy;
1322 } else if (pointnum == pointcount-1)
1323 {
1324 poly->xv[pointnum] = sx;
1325 poly->yv[pointnum] = sy;
1326 } else
1327 {
1328 poly->xv[pointnum] = cx + mult(cosine(curangle), radius);
1329 poly->yv[pointnum] = cy + mult(sine(curangle), radius);
1330 }
1331
1332 curangle += angleincrement;
1333 if (curangle >= 3600) curangle -= 3600;
1334 }
1335 }
1336
1337 /*
1338 * Routine to determine whether an arc at angle "ang" can connect the two ports
1339 * whose bounding boxes are "lx1<=X<=hx1" and "ly1<=Y<=hy1" for port 1 and
1340 * "lx2<=X<=hx2" and "ly2<=Y<=hy2" for port 2. Returns true if a line can
1341 * be drawn at that angle between the two ports and returns connection points
1342 * in (x1,y1) and (x2,y2)
1343 */
arcconnects(INTBIG ang,INTBIG lx1,INTBIG hx1,INTBIG ly1,INTBIG hy1,INTBIG lx2,INTBIG hx2,INTBIG ly2,INTBIG hy2,INTBIG * x1,INTBIG * y1,INTBIG * x2,INTBIG * y2)1344 BOOLEAN arcconnects(INTBIG ang, INTBIG lx1, INTBIG hx1, INTBIG ly1, INTBIG hy1, INTBIG lx2,
1345 INTBIG hx2, INTBIG ly2, INTBIG hy2, INTBIG *x1, INTBIG *y1, INTBIG *x2, INTBIG *y2)
1346 {
1347 float a, b, d, lx, hx, ly, hy, low1, high1, low2, high2;
1348
1349 /* first try simple solutions */
1350 if ((ang%1800) == 0)
1351 {
1352 /* horizontal angle: simply test Y coordinates */
1353 if (ly1 > hy2 || ly2 > hy1) return(FALSE);
1354 *y1 = *y2 = (maxi(ly1, ly2) + mini(hy1, hy2)) / 2;
1355 *x1 = (lx1+hx1) / 2;
1356 *x2 = (lx2+hx2) / 2;
1357 return(TRUE);
1358 }
1359 if ((ang%1800) == 900)
1360 {
1361 /* vertical angle: simply test X coordinates */
1362 if (lx1 > hx2 || lx2 > hx1) return(FALSE);
1363 *x1 = *x2 = (maxi(lx1, lx2) + mini(hx1, hx2)) / 2;
1364 *y1 = (ly1+hy1) / 2;
1365 *y2 = (ly2+hy2) / 2;
1366 return(TRUE);
1367 }
1368
1369 /* construct an imaginary line at the proper angle that runs through (0,0) */
1370 a = (float)sine(ang); a /= 1073741824.0;
1371 b = (float)-cosine(ang); b /= 1073741824.0;
1372
1373 /* get the range of distances from the line to port 1 */
1374 lx = (float)lx1; hx = (float)hx1; ly = (float)ly1; hy = (float)hy1;
1375 d = lx*a + ly*b; low1 = high1 = d;
1376 d = hx*a + ly*b; if (d < low1) low1 = d; if (d > high1) high1 = d;
1377 d = hx*a + hy*b; if (d < low1) low1 = d; if (d > high1) high1 = d;
1378 d = lx*a + hy*b; if (d < low1) low1 = d; if (d > high1) high1 = d;
1379
1380 /* get the range of distances from the line to port 2 */
1381 lx = (float)lx2; hx = (float)hx2; ly = (float)ly2; hy = (float)hy2;
1382 d = lx*a + ly*b; low2 = high2 = d;
1383 d = hx*a + ly*b; if (d < low2) low2 = d; if (d > high2) high2 = d;
1384 d = hx*a + hy*b; if (d < low2) low2 = d; if (d > high2) high2 = d;
1385 d = lx*a + hy*b; if (d < low2) low2 = d; if (d > high2) high2 = d;
1386
1387 /* if the ranges do not overlap, a line cannot be drawn */
1388 if (low1 > high2 || low2 > high1) return(FALSE);
1389
1390 /* the line can be drawn: determine equation (aX + bY = d) */
1391 d = ((low1 > low2 ? low1 : low2) + (high1 < high2 ? high1 : high2)) / 2.0f;
1392
1393 /* determine intersection with polygon 1 */
1394 db_findconnectionpoint(lx1, hx1, ly1, hy1, a, b, d, x1, y1);
1395 db_findconnectionpoint(lx2, hx2, ly2, hy2, a, b, d, x2, y2);
1396 return(TRUE);
1397 }
1398
1399 /*
1400 * Routine to find a point inside the rectangle bounded by (lx<=X<=hx, ly<=Y<=hy)
1401 * that satisfies the equation aX + bY = d. Returns the point in (x,y).
1402 */
db_findconnectionpoint(INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,float a,float b,float d,INTBIG * x,INTBIG * y)1403 void db_findconnectionpoint(INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, float a, float b,
1404 float d, INTBIG *x, INTBIG *y)
1405 {
1406 float in, out;
1407
1408 if (a != 0.0)
1409 {
1410 in = (float)ly; *y = ly; out = (d - b * in) / a; *x = (INTBIG)out;
1411 if (*x >= lx && *x <= hx) return;
1412 in = (float)hy; *y = hy; out = (d - b * in) / a; *x = (INTBIG)out;
1413 if (*x >= lx && *x <= hx) return;
1414 }
1415 if (b != 0.0)
1416 {
1417 in = (float)lx; *x = lx; out = (d - a * in) / b; *y = (INTBIG)out;
1418 if (*y >= ly && *y <= hy) return;
1419 in = (float)hx; *x = hx; out = (d - a * in) / b; *y = (INTBIG)out;
1420 if (*y >= ly && *y <= hy) return;
1421 }
1422
1423 /* not the right solution, but nothing else works */
1424 *x = (lx+hx) / 2; *y = (ly+hy) / 2;
1425 }
1426
1427 /*
1428 * compute the quadrant of the point x,y 2 | 1
1429 * Standard quadrants are used: -----
1430 * 3 | 4
1431 */
db_quadrant(INTBIG x,INTBIG y)1432 INTBIG db_quadrant(INTBIG x, INTBIG y)
1433 {
1434 if (x > 0)
1435 {
1436 if (y >= 0) return(1);
1437 return(4);
1438 }
1439 if (y > 0) return(2);
1440 return(3);
1441 }
1442
1443 /*
1444 * routine to compute the bounding box of the arc that runs clockwise from
1445 * (xs,ys) to (xe,ye) and is centered at (xc,yc). The bounding box is
1446 * placed in the reference parameters "lx", "hx", "ly", and "hy".
1447 */
arcbbox(INTBIG xs,INTBIG ys,INTBIG xe,INTBIG ye,INTBIG xc,INTBIG yc,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy)1448 void arcbbox(INTBIG xs, INTBIG ys, INTBIG xe, INTBIG ye, INTBIG xc, INTBIG yc, INTBIG *lx,
1449 INTBIG *hx, INTBIG *ly, INTBIG *hy)
1450 {
1451 REGISTER INTBIG x1, y1, x2, y2, radius;
1452 REGISTER INTBIG q1, q2;
1453
1454 /* determine radius and compute bounds of full circle */
1455 radius = computedistance(xc, yc, xs, ys);
1456 *lx = xc - radius;
1457 *ly = yc - radius;
1458 *hx = xc + radius;
1459 *hy = yc + radius;
1460
1461 /* compute quadrant of two endpoints */
1462 x1 = xs - xc; x2 = xe - xc;
1463 y1 = ys - yc; y2 = ye - yc;
1464 q1 = db_quadrant(x1, y1);
1465 q2 = db_quadrant(x2, y2);
1466
1467 /* see if the two endpoints are in the same quadrant */
1468 if (q1 == q2)
1469 {
1470 /* if the arc runs a full circle, use the MBR of the circle */
1471 if (q1 == 1 || q1 == 2)
1472 {
1473 if (x1 > x2) return;
1474 } else
1475 {
1476 if (x1 < x2) return;
1477 }
1478
1479 /* use the MBR of the two arc points */
1480 *lx = mini(xs, xe);
1481 *hx = maxi(xs, xe);
1482 *ly = mini(ys, ye);
1483 *hy = maxi(ys, ye);
1484 return;
1485 }
1486
1487 switch (q1)
1488 {
1489 case 1: switch (q2)
1490 {
1491 case 2: /* 3 quadrants clockwise from Q1 to Q2 */
1492 *hy = maxi(y1,y2) + yc;
1493 break;
1494
1495 case 3: /* 2 quadrants clockwise from Q1 to Q3 */
1496 *lx = x2 + xc;
1497 *hy = y1 + yc;
1498 break;
1499
1500 case 4: /* 1 quadrant clockwise from Q1 to Q4 */
1501 *lx = mini(x1,x2) + xc;
1502 *ly = y2 + yc;
1503 *hy = y1 + yc;
1504 break;
1505 }
1506 break;
1507
1508 case 2: switch (q2)
1509 {
1510 case 1: /* 1 quadrant clockwise from Q2 to Q1 */
1511 *lx = x1 + xc;
1512 *ly = mini(y1,y2) + yc;
1513 *hx = x2 + xc;
1514 break;
1515
1516 case 3: /* 3 quadrants clockwise from Q2 to Q3 */
1517 *lx = mini(x1,x2) + xc;
1518 break;
1519
1520 case 4: /* 2 quadrants clockwise from Q2 to Q4 */
1521 *lx = x1 + xc;
1522 *ly = y2 + yc;
1523 break;
1524 }
1525 break;
1526
1527 case 3: switch (q2)
1528 {
1529 case 1: /* 2 quadrants clockwise from Q3 to Q1 */
1530 *ly = y1 + yc;
1531 *hx = x2 + xc;
1532 break;
1533
1534 case 2: /* 1 quadrant clockwise from Q3 to Q2 */
1535 *ly = y1 + yc;
1536 *hx = maxi(x1,x2) + xc;
1537 *hy = y2 + yc;
1538 break;
1539
1540 case 4: /* 3 quadrants clockwise from Q3 to Q4 */
1541 *ly = mini(y1,y2) + yc;
1542 break;
1543 }
1544 break;
1545
1546 case 4: switch (q2)
1547 {
1548 case 1: /* 3 quadrants clockwise from Q4 to Q1 */
1549 *hx = maxi(x1,x2) + xc;
1550 break;
1551
1552 case 2: /* 2 quadrants clockwise from Q4 to Q2 */
1553 *hx = x1 + xc;
1554 *hy = y2 + yc;
1555 break;
1556
1557 case 3: /* 1 quadrant clockwise from Q4 to Q3 */
1558 *lx = x2 + xc;
1559 *hx = x1 + xc;
1560 *hy = maxi(y1,y2) + yc;
1561 break;
1562 }
1563 break;
1564 }
1565 }
1566
1567 /*
1568 * Routine to find the two possible centers for a circle whose radius is
1569 * "r" and has two points (x01,y01) and (x02,y02) on the edge. The two
1570 * center points are returned in (x1,y1) and (x2,y2). The distance between
1571 * the points (x01,y01) and (x02,y02) is in "d". The routine returns
1572 * false if successful, true if there is no intersection. This code
1573 * was written by John Mohammed of Schlumberger.
1574 */
findcenters(INTBIG r,INTBIG x01,INTBIG y01,INTBIG x02,INTBIG y02,INTBIG d,INTBIG * x1,INTBIG * y1,INTBIG * x2,INTBIG * y2)1575 BOOLEAN findcenters(INTBIG r, INTBIG x01, INTBIG y01, INTBIG x02, INTBIG y02, INTBIG d,
1576 INTBIG *x1, INTBIG *y1, INTBIG *x2, INTBIG *y2)
1577 {
1578 float r2, delta_1, delta_12, delta_2;
1579
1580 /* quit now if the circles concentric */
1581 if (x01 == x02 && y01 == y02) return(TRUE);
1582
1583 /* find the intersections, if any */
1584 r2 = (float)r; r2 *= r;
1585 delta_1 = -d / 2.0f;
1586 delta_12 = delta_1 * delta_1;
1587
1588 /* quit if there are no intersections */
1589 if (r2 < delta_12) return(TRUE);
1590
1591 /* compute the intersection points */
1592 delta_2 = (float)sqrt(r2 - delta_12);
1593 *x1 = x02 + (INTBIG)(((delta_1 * (x02 - x01)) + (delta_2 * (y02 - y01))) / d);
1594 *y1 = y02 + (INTBIG)(((delta_1 * (y02 - y01)) + (delta_2 * (x01 - x02))) / d);
1595 *x2 = x02 + (INTBIG)(((delta_1 * (x02 - x01)) + (delta_2 * (y01 - y02))) / d);
1596 *y2 = y02 + (INTBIG)(((delta_1 * (y02 - y01)) + (delta_2 * (x02 - x01))) / d);
1597 return(FALSE);
1598 }
1599
1600 /*
1601 * routine to determine the point on the line segment that runs from
1602 * (x1,y1) to (x2,y2) that is closest to the point (*x,*y). The value in
1603 * (*x,*y) is adjusted to be that close point and the distance is returned.
1604 */
closestpointtosegment(INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,INTBIG * x,INTBIG * y)1605 INTBIG closestpointtosegment(INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2, INTBIG *x, INTBIG *y)
1606 {
1607 REGISTER INTBIG dist1, dist2;
1608 INTBIG xi, yi;
1609
1610 /* find closest point on line */
1611 db_closestpointtoline(x1,y1, x2,y2, *x,*y, &xi, &yi);
1612
1613 /* see if that intersection point is actually on the segment */
1614 if (xi >= mini(x1, x2) && xi <= maxi(x1, x2) &&
1615 yi >= mini(y1, y2) && yi <= maxi(y1, y2))
1616 {
1617 /* it is: get the distance and return this point */
1618 dist1 = computedistance(*x, *y, xi, yi);
1619 *x = xi; *y = yi;
1620 return(dist1);
1621 }
1622
1623 /* intersection not on segment: choose one endpoint as the closest */
1624 dist1 = computedistance(*x, *y, x1, y1);
1625 dist2 = computedistance(*x, *y, x2, y2);
1626 if (dist2 < dist1)
1627 {
1628 *x = x2; *y = y2; return(dist2);
1629 }
1630 *x = x1; *y = y1;
1631 return(dist1);
1632 }
1633
1634 /*
1635 * routine to determine the point on the line that runs from (x1,y1) to
1636 * (x2,y2) that is closest to the point (xp,yp). This point is returned
1637 * in (*xi,*yi).
1638 */
db_closestpointtoline(INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,INTBIG xp,INTBIG yp,INTBIG * xi,INTBIG * yi)1639 void db_closestpointtoline(INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2, INTBIG xp, INTBIG yp,
1640 INTBIG *xi, INTBIG *yi)
1641 {
1642 float m, b, mi, bi, t;
1643 INTBIG newx, newy;
1644
1645 /* special case for horizontal line */
1646 if (y1 == y2)
1647 {
1648 *xi = xp;
1649 *yi = y1;
1650 return;
1651 }
1652
1653 /* special case for vertical line */
1654 if (x1 == x2)
1655 {
1656 *xi = x1;
1657 *yi = yp;
1658 return;
1659 }
1660
1661 /* compute equation of the line */
1662 m = (float)(y1-y2); m /= x1-x2;
1663 b = (float)-x1; b *= m; b += y1;
1664
1665 /* compute perpendicular to line through the point */
1666 mi = -1.0f / m;
1667 bi = (float)-xp; bi *= mi; bi += yp;
1668
1669 /* compute intersection of the lines */
1670 t = (bi-b) / (m-mi);
1671 newx = (INTBIG)t;
1672 newy = (INTBIG)(m * t + b);
1673 *xi = newx; *yi = newy;
1674 }
1675
1676 /*
1677 * routine to compute the distance between point (x,y) and the line that runs
1678 * from (x1,y1) to (x2,y2).
1679 */
disttoline(INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,INTBIG x,INTBIG y)1680 INTBIG disttoline(INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2, INTBIG x, INTBIG y)
1681 {
1682 REGISTER INTBIG ang;
1683 REGISTER INTBIG dist, ix, iy;
1684 INTBIG oix, oiy;
1685
1686 /* get point on line from (x1,y1) to (x2,y2) close to (x,y) */
1687 if (x1 == x2 && y1 == y2)
1688 {
1689 return(computedistance(x, y, x1, y1));
1690 }
1691 ang = figureangle(x1,y1, x2,y2);
1692 (void)intersect(x1, y1, ang, x, y, (ang+900)%3600, &oix, &oiy);
1693 ix = oix; iy = oiy;
1694 if (x1 == x2) ix = x1;
1695 if (y1 == y2) iy = y1;
1696
1697 /* make sure (ix,iy) is on the segment from (x1,y1) to (x2,y2) */
1698 if (ix < mini(x1,x2) || ix > maxi(x1,x2) ||
1699 iy < mini(y1,y2) || iy > maxi(y1,y2))
1700 {
1701 if (abs(ix-x1) + abs(iy-y1) < abs(ix-x2) + abs(iy-y2))
1702 {
1703 ix = x1; iy = y1;
1704 } else
1705 {
1706 ix = x2; iy = y2;
1707 }
1708 }
1709 dist = computedistance(ix, iy, x, y);
1710 return(dist);
1711 }
1712
1713 /*
1714 * Routine to scale "value" from database units to the requested display unit "dispunit".
1715 */
scaletodispunit(INTBIG value,INTBIG dispunit)1716 float scaletodispunit(INTBIG value, INTBIG dispunit)
1717 {
1718 REGISTER float scalefactor;
1719
1720 scalefactor = db_getcurrentscale(el_units&INTERNALUNITS, dispunit,
1721 el_curlib->lambda[el_curtech->techindex]);
1722 return((float)value / scalefactor);
1723 }
1724
1725 /*
1726 * Routine to scale "value" from square database units to the requested square display unit "dispunit".
1727 */
scaletodispunitsq(INTBIG value,INTBIG dispunit)1728 float scaletodispunitsq(INTBIG value, INTBIG dispunit)
1729 {
1730 REGISTER float scalefactor;
1731
1732 scalefactor = db_getcurrentscale(el_units&INTERNALUNITS, dispunit,
1733 el_curlib->lambda[el_curtech->techindex]);
1734 return((float)value / scalefactor / scalefactor);
1735 }
1736
1737 /*
1738 * Routine to scale "value" from the requested display unit "dispunit" to database units.
1739 */
scalefromdispunit(float value,INTBIG dispunit)1740 INTBIG scalefromdispunit(float value, INTBIG dispunit)
1741 {
1742 REGISTER float scalefactor;
1743
1744 scalefactor = db_getcurrentscale(el_units&INTERNALUNITS, dispunit,
1745 el_curlib->lambda[el_curtech->techindex]);
1746 return(roundfloat(value * scalefactor));
1747 }
1748
1749 /*
1750 * Routine to return the scaling factor between database units and display units.
1751 * The current value of lambda is provided for use when that is the unit.
1752 */
db_getcurrentscale(INTBIG intunit,INTBIG dispunit,INTBIG lambda)1753 float db_getcurrentscale(INTBIG intunit, INTBIG dispunit, INTBIG lambda)
1754 {
1755 switch (intunit&INTERNALUNITS)
1756 {
1757 case INTUNITHNM:
1758 switch (dispunit&DISPLAYUNITS)
1759 {
1760 case DISPUNITINCH: return(50800000.0f);
1761 case DISPUNITCM: return(20000000.0f);
1762 case DISPUNITMM: return(2000000.0f);
1763 case DISPUNITMIL: return(50800.0f);
1764 case DISPUNITMIC: return(2000.0f);
1765 case DISPUNITCMIC: return(20.0f);
1766 case DISPUNITNM: return(2.0f);
1767 }
1768 break;
1769 case INTUNITHDMIC:
1770 switch (dispunit&DISPLAYUNITS)
1771 {
1772 case DISPUNITINCH: return(508000.0f);
1773 case DISPUNITCM: return(200000.0f);
1774 case DISPUNITMM: return(20000.0f);
1775 case DISPUNITMIL: return(508.0f);
1776 case DISPUNITMIC: return(20.0f);
1777 case DISPUNITCMIC: return(0.2f);
1778 case DISPUNITNM: return(0.02f);
1779 }
1780 break;
1781 }
1782 return((float)lambda);
1783 }
1784
db_getinternalunitscale(INTBIG * numerator,INTBIG * denominator,INTBIG oldunits,INTBIG newunits)1785 void db_getinternalunitscale(INTBIG *numerator, INTBIG *denominator, INTBIG oldunits, INTBIG newunits)
1786 {
1787 if ((newunits&INTERNALUNITS) == INTUNITHNM)
1788 {
1789 /* scaling from half-decimicrons to half-nanometers (multiply by 100) */
1790 *numerator = 100; *denominator = 1;
1791 } else
1792 {
1793 /* scaling from half-nanometers to half-decimicrons (divide by 100) */
1794 *numerator = 1; *denominator = 100;
1795 }
1796 }
1797
1798 /*
1799 * routine to crop the box in the reference parameters (lx-hx, ly-hy)
1800 * against the box in (bx-ux, by-uy). If the box is cropped into oblivion,
1801 * the routine returns 1. If the boxes overlap but cannot be cleanly cropped,
1802 * the routine returns -1. Otherwise the box is cropped and zero is returned
1803 */
cropbox(INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy,INTBIG bx,INTBIG ux,INTBIG by,INTBIG uy)1804 INTBIG cropbox(INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy, INTBIG bx, INTBIG ux, INTBIG by,
1805 INTBIG uy)
1806 {
1807 REGISTER INTBIG crops;
1808
1809 /* if the two boxes don't touch, just return */
1810 if (bx >= *hx || by >= *hy || ux <= *lx || uy <= *ly) return(0);
1811
1812 /* if the box to be cropped is within the other, say so */
1813 if (bx <= *lx && ux >= *hx && by <= *ly && uy >= *hy) return(1);
1814
1815 /* reduce (lx-hx,ly-hy) by (bx-ux,by-uy) */
1816 crops = 0;
1817 if (bx <= *lx && ux >= *hx)
1818 {
1819 /* it covers in X...crop in Y */
1820 if (uy >= *hy) *hy = by;
1821 if (by <= *ly) *ly = uy;
1822 crops++;
1823 }
1824 if (by <= *ly && uy >= *hy)
1825 {
1826 /* it covers in Y...crop in X */
1827 if (ux >= *hx) *hx = bx;
1828 if (bx <= *lx) *lx = ux;
1829 crops++;
1830 }
1831 if (crops == 0) return(-1);
1832 return(0);
1833 }
1834
1835 /************************* SIMPLE MATHEMATICS *************************/
1836
mini(INTBIG a,INTBIG b)1837 INTBIG mini(INTBIG a, INTBIG b)
1838 {
1839 return(a<b ? a : b);
1840 }
1841
maxi(INTBIG a,INTBIG b)1842 INTBIG maxi(INTBIG a, INTBIG b)
1843 {
1844 return(a>b ? a : b);
1845 }
1846
roundfloat(float a)1847 INTBIG roundfloat(float a)
1848 {
1849 if (a < 0.0) return((INTBIG)(a-0.5));
1850 return((INTBIG)(a+0.5));
1851 }
1852
rounddouble(double a)1853 INTBIG rounddouble(double a)
1854 {
1855 if (a < 0.0) return((INTBIG)(a-0.5));
1856 return((INTBIG)(a+0.5));
1857 }
1858
1859 /*
1860 * Routine to return true if "a" is equal to "b" within the epsilon of floating
1861 * point arithmetic.
1862 */
floatsequal(float a,float b)1863 BOOLEAN floatsequal(float a, float b)
1864 {
1865 if (fabs(a-b) <= FLT_EPSILON) return(TRUE);
1866 return(FALSE);
1867 }
1868
1869 /*
1870 * Routine to return true if "a" is equal to "b" within the epsilon of double floating
1871 * point arithmetic.
1872 */
doublesequal(double a,double b)1873 BOOLEAN doublesequal(double a, double b)
1874 {
1875 if (fabs(a-b) <= DBL_EPSILON) return(TRUE);
1876 return(FALSE);
1877 }
1878
1879 /*
1880 * Routine to return true if "a" is less than "b" within the epsilon of floating
1881 * point arithmetic.
1882 */
floatslessthan(float a,float b)1883 BOOLEAN floatslessthan(float a, float b)
1884 {
1885 if (a+FLT_EPSILON < b) return(TRUE);
1886 return(FALSE);
1887 }
1888
1889 /*
1890 * Routine to return true if "a" is less than "b" within the epsilon of double floating
1891 * point arithmetic.
1892 */
doubleslessthan(double a,double b)1893 BOOLEAN doubleslessthan(double a, double b)
1894 {
1895 if (a+DBL_EPSILON < b) return(TRUE);
1896 return(FALSE);
1897 }
1898
1899 /*
1900 * Routine to truncate "a" to the lowest integral value.
1901 */
floatfloor(float a)1902 float floatfloor(float a)
1903 {
1904 INTBIG i;
1905
1906 i = (INTBIG)(a + FLT_EPSILON);
1907 return((float)i);
1908 }
1909
1910 /*
1911 * Routine to truncate "a" to the lowest integral value.
1912 */
doublefloor(double a)1913 double doublefloor(double a)
1914 {
1915 INTBIG i;
1916
1917 i = (INTBIG)(a + DBL_EPSILON);
1918 return((float)i);
1919 }
1920
1921 /* routine to convert a floating value to integer by casting! */
castint(float a)1922 INTBIG castint(float a)
1923 {
1924 union {
1925 INTBIG i;
1926 float x;
1927 } cast;
1928
1929 cast.x = a;
1930 return(cast.i);
1931 }
1932
1933 /* routine to convert an integer value to floating point by casting! */
castfloat(INTBIG j)1934 float castfloat(INTBIG j)
1935 {
1936 union {
1937 INTBIG i;
1938 float x;
1939 } cast;
1940
1941 cast.i = j;
1942 return(cast.x);
1943 }
1944
1945 /************************* 3D MATHEMATICS *************************/
1946
vectoradd3d(float * a,float * b,float * sum)1947 void vectoradd3d(float *a, float *b, float *sum)
1948 {
1949 sum[0] = a[0] + b[0];
1950 sum[1] = a[1] + b[1];
1951 sum[2] = a[2] + b[2];
1952 }
1953
vectorsubtract3d(float * a,float * b,float * diff)1954 void vectorsubtract3d(float *a, float *b, float *diff)
1955 {
1956 diff[0] = a[0] - b[0];
1957 diff[1] = a[1] - b[1];
1958 diff[2] = a[2] - b[2];
1959 }
1960
vectormultiply3d(float * a,float b,float * res)1961 void vectormultiply3d(float *a, float b, float *res)
1962 {
1963 res[0] = a[0] * b;
1964 res[1] = a[1] * b;
1965 res[2] = a[2] * b;
1966 }
1967
vectordivide3d(float * a,float b,float * res)1968 void vectordivide3d(float *a, float b, float *res)
1969 {
1970 res[0] = a[0] / b;
1971 res[1] = a[1] / b;
1972 res[2] = a[2] / b;
1973 }
1974
vectormagnitude3d(float * a)1975 float vectormagnitude3d(float *a)
1976 {
1977 return((float)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]));
1978 }
1979
vectordot3d(float * a,float * b)1980 float vectordot3d(float *a, float *b)
1981 {
1982 return(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
1983 }
1984
vectornormalize3d(float * a)1985 void vectornormalize3d(float *a)
1986 {
1987 float mag;
1988
1989 mag = (float)sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
1990 if (mag > 1.0e-11f)
1991 {
1992 a[0] /= mag;
1993 a[1] /= mag;
1994 a[2] /= mag;
1995 }
1996 }
1997
vectorcross3d(float * a,float * b,float * res)1998 void vectorcross3d(float *a, float *b, float *res)
1999 {
2000 res[0] = a[1] * b[2] - b[1] * a[2];
2001 res[1] = a[2] * b[0] - b[2] * a[0];
2002 res[2] = a[0] * b[1] - b[0] * a[1];
2003 }
2004
matrixid3d(float xform[4][4])2005 void matrixid3d(float xform[4][4])
2006 {
2007 REGISTER INTBIG i, j;
2008
2009 for(i=0; i<4; i++)
2010 {
2011 for(j=0; j<4; j++)
2012 {
2013 if (i == j) xform[i][j] = 1.0; else
2014 xform[i][j] = 0.0;
2015 }
2016 }
2017 }
2018
matrixmult3d(float a[4][4],float b[4][4],float res[4][4])2019 void matrixmult3d(float a[4][4], float b[4][4], float res[4][4])
2020 {
2021 REGISTER INTBIG row, col, i;
2022
2023 for (row = 0; row < 4; row++)
2024 {
2025 for (col = 0; col < 4; col++)
2026 {
2027 res[row][col] = 0.0f;
2028 for (i = 0; i < 4; i++)
2029 {
2030 res[row][col] += a[i][col] * b[row][i];
2031 }
2032 }
2033 }
2034 }
2035
2036 /*
2037 * Routine to build the invert of the transformation. Returns nonzero if a
2038 * singularity is detected.
2039 */
matrixinvert3d(float in[4][4],float out[4][4])2040 void matrixinvert3d(float in[4][4], float out[4][4])
2041 {
2042 float a[4][8], temp;
2043 short i, j, k, l;
2044
2045 /* copy into the matrix */
2046 for(i=0; i<4; i++)
2047 {
2048 for(j=0; j<8; j++)
2049 {
2050 if (j < 4) a[i][j] = in[i][j]; else
2051 if (j == i+4) a[i][j] = 1.0; else
2052 a[i][j] = 0.0;
2053 }
2054 }
2055
2056 /* do the inversion */
2057 for(i=0; i<4; i++)
2058 {
2059 for(l=i; l<4; l++)
2060 if (a[l][i] != 0.0) break;
2061 if (l >= 4) return;
2062 if (l != i) for(k=0; k<8; k++)
2063 {
2064 temp = a[l][k];
2065 a[l][k] = a[i][k];
2066 a[i][k] = temp;
2067 }
2068
2069 for(k=7; k>=i; k--) a[i][k] = a[i][k] / a[i][i];
2070 for(l=0; l<4; l++)
2071 if (l != i)
2072 for(k=7; k>=i; k--) a[l][k] = a[l][k] - a[i][k] * a[l][i];
2073 }
2074
2075 /* copy back from the matrix */
2076 l = 0;
2077 for(i=0; i<4; i++) for(j=0; j<4; j++)
2078 out[i][j] = a[i][j+4];
2079 }
2080
matrixxform3d(float * vec,float mat[4][4],float * res)2081 void matrixxform3d(float *vec, float mat[4][4], float *res)
2082 {
2083 res[0] = mat[0][0] * vec[0] + mat[0][1] * vec[1] + mat[0][2] * vec[2] + mat[0][3] * vec[3];
2084 res[1] = mat[1][0] * vec[0] + mat[1][1] * vec[1] + mat[1][2] * vec[2] + mat[1][3] * vec[3];
2085 res[2] = mat[2][0] * vec[0] + mat[2][1] * vec[1] + mat[2][2] * vec[2] + mat[2][3] * vec[3];
2086 res[3] = mat[3][0] * vec[0] + mat[3][1] * vec[1] + mat[3][2] * vec[2] + mat[2][3] * vec[3];
2087 }
2088
2089 /************************* POLYGON MANIPULATION *************************/
2090
2091 /*
2092 * routine to allocate a polygon with "points" points from cluster "clus"
2093 * and return the address. Returns NOPOLYGON if an error occurs.
2094 */
2095 #ifdef DEBUGMEMORY
_allocpolygon(INTBIG points,CLUSTER * cluster,CHAR * filename,INTBIG lineno)2096 POLYGON *_allocpolygon(INTBIG points, CLUSTER *cluster, CHAR *filename, INTBIG lineno)
2097 #else
2098 POLYGON *allocpolygon(INTBIG points, CLUSTER *cluster)
2099 #endif
2100 {
2101 REGISTER POLYGON *poly;
2102
2103 if (db_multiprocessing) emutexlock(db_polygonmutex);
2104 poly = NOPOLYGON;
2105 if (db_freepolygons != NOPOLYGON)
2106 {
2107 poly = db_freepolygons;
2108 db_freepolygons = poly->nextpolygon;
2109 if (poly->count < points) (void)extendpolygon(poly, points);
2110 }
2111 if (db_multiprocessing) emutexunlock(db_polygonmutex);
2112
2113 if (poly == NOPOLYGON)
2114 {
2115 #ifdef DEBUGMEMORY
2116 poly = (POLYGON *)_emalloc((sizeof (POLYGON)), cluster, filename, lineno);
2117 if (poly == 0) return((POLYGON *)db_error(DBNOMEM|DBALLOCPOLYGON));
2118 poly->xv = _emalloc((SIZEOFINTBIG*points), cluster, filename, lineno);
2119 if (poly->xv == 0) return((POLYGON *)db_error(DBNOMEM|DBALLOCPOLYGON));
2120 poly->yv = _emalloc((SIZEOFINTBIG*points), cluster, filename, lineno);
2121 if (poly->yv == 0) return((POLYGON *)db_error(DBNOMEM|DBALLOCPOLYGON));
2122 #else
2123 poly = (POLYGON *)emalloc((sizeof (POLYGON)), cluster);
2124 if (poly == 0) return((POLYGON *)db_error(DBNOMEM|DBALLOCPOLYGON));
2125 poly->xv = emalloc((SIZEOFINTBIG*points), cluster);
2126 if (poly->xv == 0) return((POLYGON *)db_error(DBNOMEM|DBALLOCPOLYGON));
2127 poly->yv = emalloc((SIZEOFINTBIG*points), cluster);
2128 if (poly->yv == 0) return((POLYGON *)db_error(DBNOMEM|DBALLOCPOLYGON));
2129 #endif
2130 poly->cluster = cluster;
2131 poly->limit = points;
2132 }
2133
2134 poly->string = NOSTRING;
2135 poly->desc = NOGRAPHICS;
2136 poly->portproto = NOPORTPROTO;
2137 poly->count = 0;
2138 poly->style = FILLED;
2139 TDCLEAR(poly->textdescript);
2140 TDSETSIZE(poly->textdescript, TXTSETPOINTS(8));
2141 poly->tech = el_curtech;
2142 poly->layer = 0;
2143 poly->nextpolygon = NOPOLYGON;
2144 poly->numvar = 0;
2145 return(poly);
2146 }
2147
2148 /*
2149 * routine to ensure that polygon "poly" is valid and has "points" points.
2150 * If not allocated, it is created from cluster "clus" and remembered as a
2151 * static polygon to be freed later. Returns TRUE on error.
2152 */
needstaticpolygon(POLYGON ** poly,INTBIG points,CLUSTER * clus)2153 BOOLEAN needstaticpolygon(POLYGON **poly, INTBIG points, CLUSTER *clus)
2154 {
2155 /* if the polygon is already allocated, stop */
2156 if (*poly != NOPOLYGON)
2157 {
2158 if ((*poly)->count < points) (void)extendpolygon(*poly, points);
2159 return(FALSE);
2160 }
2161
2162 /* lock the allocation and saving of the pointers */
2163 if (db_multiprocessing) emutexlock(db_polygonmutex);
2164 if (*poly == NOPOLYGON)
2165 {
2166 *poly = allocpolygon(points, clus);
2167 if (*poly != NOPOLYGON)
2168 {
2169 (*poly)->nextpolygon = db_staticpolygons;
2170 db_staticpolygons = *poly;
2171 }
2172 }
2173 if (db_multiprocessing) emutexunlock(db_polygonmutex);
2174 if (*poly == NOPOLYGON) return(TRUE);
2175 if ((*poly)->count < points) (void)extendpolygon(*poly, points);
2176 return(FALSE);
2177 }
2178
2179 /*
2180 * routine to extend polygon "poly" to be "newcount" points. Returns
2181 * true if there is an allocation error
2182 */
extendpolygon(POLYGON * poly,INTBIG newcount)2183 BOOLEAN extendpolygon(POLYGON *poly, INTBIG newcount)
2184 {
2185 REGISTER INTBIG *oldxp, *oldyp, i;
2186
2187 /* if polygon can already handle this many points, quit */
2188 if (newcount <= poly->limit) return(FALSE);
2189
2190 /* save the old coordinates */
2191 oldxp = poly->xv; oldyp = poly->yv;
2192
2193 /* get space for the new ones */
2194 poly->xv = emalloc((SIZEOFINTBIG*newcount), poly->cluster);
2195 if (poly->xv == 0)
2196 return(db_error(DBNOMEM|DBEXTENDPOLYGON)!=0);
2197 poly->yv = emalloc((SIZEOFINTBIG*newcount), poly->cluster);
2198 if (poly->yv == 0)
2199 return(db_error(DBNOMEM|DBEXTENDPOLYGON)!=0);
2200
2201 for(i=0; i<poly->limit; i++)
2202 {
2203 poly->xv[i] = oldxp[i];
2204 poly->yv[i] = oldyp[i];
2205 }
2206
2207 poly->limit = newcount;
2208 efree((CHAR *)oldxp);
2209 efree((CHAR *)oldyp);
2210 return(FALSE);
2211 }
2212
2213 /*
2214 * routine to free the memory associated with polygon "poly"
2215 */
freepolygon(POLYGON * poly)2216 void freepolygon(POLYGON *poly)
2217 {
2218 if (db_multiprocessing) emutexlock(db_polygonmutex);
2219 poly->nextpolygon = db_freepolygons;
2220 db_freepolygons = poly;
2221 if (db_multiprocessing) emutexunlock(db_polygonmutex);
2222 }
2223
2224 #ifdef DEBUGMEMORY
_allocpolylist(CLUSTER * cluster,CHAR * filename,INTBIG lineno)2225 POLYLIST *_allocpolylist(CLUSTER *cluster, CHAR *filename, INTBIG lineno)
2226 #else
2227 POLYLIST *allocpolylist(CLUSTER *cluster)
2228 #endif
2229 {
2230 REGISTER POLYLIST *plist;
2231
2232 #ifdef DEBUGMEMORY
2233 plist = (POLYLIST *)_emalloc(sizeof(POLYLIST), cluster, filename, lineno);
2234 #else
2235 plist = (POLYLIST *)emalloc(sizeof(POLYLIST), cluster);
2236 #endif
2237 if (plist == 0) return(0);
2238 plist->polylisttotal = 0;
2239 return(plist);
2240 }
2241
2242 /*
2243 * routine to accumulate a list of polygons at least "tot" long in the
2244 * polygon structure "list". The routine returns true if there is no
2245 * more memory.
2246 */
2247 #ifdef DEBUGMEMORY
_ensurepolylist(POLYLIST * list,INTBIG tot,CLUSTER * cluster,CHAR * filename,INTBIG lineno)2248 BOOLEAN _ensurepolylist(POLYLIST *list, INTBIG tot, CLUSTER *cluster, CHAR *filename, INTBIG lineno)
2249 #else
2250 BOOLEAN ensurepolylist(POLYLIST *list, INTBIG tot, CLUSTER *cluster)
2251 #endif
2252 {
2253 REGISTER POLYGON **newpolylist;
2254 REGISTER INTBIG j, *newlx, *newhx, *newly, *newhy;
2255
2256 /* make sure the list is the right size */
2257 if (tot > list->polylisttotal)
2258 {
2259 #ifdef DEBUGMEMORY
2260 newpolylist = (POLYGON **)_emalloc(tot * (sizeof (POLYGON *)), dr_tool->cluster, filename, lineno);
2261 newlx = (INTBIG *)_emalloc(tot * SIZEOFINTBIG, dr_tool->cluster, filename, lineno);
2262 newhx = (INTBIG *)_emalloc(tot * SIZEOFINTBIG, dr_tool->cluster, filename, lineno);
2263 newly = (INTBIG *)_emalloc(tot * SIZEOFINTBIG, dr_tool->cluster, filename, lineno);
2264 newhy = (INTBIG *)_emalloc(tot * SIZEOFINTBIG, dr_tool->cluster, filename, lineno);
2265 #else
2266 newpolylist = (POLYGON **)emalloc(tot * (sizeof (POLYGON *)), dr_tool->cluster);
2267 newlx = (INTBIG *)emalloc(tot * SIZEOFINTBIG, dr_tool->cluster);
2268 newhx = (INTBIG *)emalloc(tot * SIZEOFINTBIG, dr_tool->cluster);
2269 newly = (INTBIG *)emalloc(tot * SIZEOFINTBIG, dr_tool->cluster);
2270 newhy = (INTBIG *)emalloc(tot * SIZEOFINTBIG, dr_tool->cluster);
2271 #endif
2272 if (newpolylist == 0 || newlx == 0 || newhx == 0 || newly == 0 || newhy == 0)
2273 {
2274 ttyputerr(_("DRC error allocating memory for polygons"));
2275 return(TRUE);
2276 }
2277 for(j=0; j<tot; j++) newpolylist[j] = NOPOLYGON;
2278 if (list->polylisttotal != 0)
2279 {
2280 for(j=0; j<list->polylisttotal; j++)
2281 newpolylist[j] = list->polygons[j];
2282 efree((CHAR *)list->polygons);
2283 efree((CHAR *)list->lx);
2284 efree((CHAR *)list->hx);
2285 efree((CHAR *)list->ly);
2286 efree((CHAR *)list->hy);
2287 }
2288 list->polygons = newpolylist;
2289 list->lx = newlx;
2290 list->hx = newhx;
2291 list->ly = newly;
2292 list->hy = newhy;
2293 list->polylisttotal = tot;
2294 }
2295
2296 /* make sure there is a polygon for each entry in the list */
2297 for(j=0; j<tot; j++) if (list->polygons[j] == NOPOLYGON)
2298 {
2299 #ifdef DEBUGMEMORY
2300 list->polygons[j] = _allocpolygon(4, cluster, filename, lineno);
2301 #else
2302 list->polygons[j] = allocpolygon(4, cluster);
2303 #endif
2304 }
2305 return(FALSE);
2306 }
2307
freepolylist(POLYLIST * list)2308 void freepolylist(POLYLIST *list)
2309 {
2310 REGISTER INTBIG i;
2311
2312 for(i=0; i<list->polylisttotal; i++)
2313 if (list->polygons[i] != NOPOLYGON)
2314 freepolygon(list->polygons[i]);
2315 if (list->polylisttotal > 0)
2316 {
2317 efree((CHAR *)list->polygons);
2318 efree((CHAR *)list->lx);
2319 efree((CHAR *)list->hx);
2320 efree((CHAR *)list->ly);
2321 efree((CHAR *)list->hy);
2322 }
2323 efree((CHAR *)list);
2324 }
2325
db_deallocatepolygon(POLYGON * poly)2326 void db_deallocatepolygon(POLYGON *poly)
2327 {
2328 efree((CHAR *)poly->xv);
2329 efree((CHAR *)poly->yv);
2330 efree((CHAR *)poly);
2331 }
2332
2333 /* routine to transform polygon "poly" through the transformation "trans" */
xformpoly(POLYGON * poly,XARRAY trans)2334 void xformpoly(POLYGON *poly, XARRAY trans)
2335 {
2336 REGISTER INTBIG i, x, y, det, t22, px, py;
2337
2338 t22 = trans[2][2];
2339 if (poly->style == FILLEDRECT || poly->style == CLOSEDRECT)
2340 {
2341 /* rectangles must be fleshed-out if nonmanhattan */
2342 if (t22 == P1) maketruerect(poly);
2343 } else if (poly->style == CIRCLEARC || poly->style == THICKCIRCLEARC)
2344 {
2345 /* special hack to reverse points in arcs if node is transposed */
2346 if (t22 != P1) det = db_determinant[t22]; else
2347 det = mult(trans[0][0], trans[1][1]) - mult(trans[0][1], trans[1][0]);
2348 if (det < 0) for(i=0; i<poly->count; i += 3)
2349 {
2350 x = poly->xv[i+1]; y = poly->yv[i+1];
2351 poly->xv[i+1] = poly->xv[i+2]; poly->yv[i+1] = poly->yv[i+2];
2352 poly->xv[i+2] = x; poly->yv[i+2] = y;
2353 }
2354 }
2355
2356 /* transform the polygon */
2357 px = trans[2][0]; py = trans[2][1];
2358 if (t22 != P1)
2359 {
2360 for(i=0; i<poly->count; i++)
2361 {
2362 x = poly->xv[i]; y = poly->yv[i];
2363 switch (t22)
2364 {
2365 case 0: poly->xv[i] = x + px; poly->yv[i] = y + py; break;
2366 case 1: poly->xv[i] = -y + px; poly->yv[i] = x + py; break;
2367 case 2: poly->xv[i] = -x + px; poly->yv[i] = -y + py; break;
2368 case 3: poly->xv[i] = y + px; poly->yv[i] = -x + py; break;
2369 case 4: poly->xv[i] = -y + px; poly->yv[i] = -x + py; break;
2370 case 5: poly->xv[i] = -x + px; poly->yv[i] = y + py; break;
2371 case 6: poly->xv[i] = y + px; poly->yv[i] = x + py; break;
2372 case 7: poly->xv[i] = x + px; poly->yv[i] = -y + py; break;
2373 }
2374 }
2375 } else
2376 {
2377 for(i=0; i<poly->count; i++)
2378 {
2379 x = poly->xv[i]; y = poly->yv[i];
2380 poly->xv[i] = mult(trans[0][0],x) + mult(trans[1][0],y) + px;
2381 poly->yv[i] = mult(trans[0][1],x) + mult(trans[1][1],y) + py;
2382 }
2383 }
2384 }
2385
2386 /*
2387 * routine to ensure that polygon "poly" has true vertices, and is not described
2388 * as a "rectangle" with only two diagonal points.
2389 */
maketruerect(POLYGON * poly)2390 void maketruerect(POLYGON *poly)
2391 {
2392 REGISTER INTBIG lx, ux, ly, uy;
2393
2394 if (poly->style != FILLEDRECT && poly->style != CLOSEDRECT) return;
2395
2396 if (poly->limit < 4) (void)extendpolygon(poly, 4);
2397 lx = poly->xv[0];
2398 ux = poly->xv[1];
2399 ly = poly->yv[0];
2400 uy = poly->yv[1];
2401
2402 poly->xv[0] = poly->xv[1] = lx;
2403 poly->xv[2] = poly->xv[3] = ux;
2404 poly->yv[0] = poly->yv[3] = ly;
2405 poly->yv[1] = poly->yv[2] = uy;
2406 poly->count = 4;
2407 if (poly->style == FILLEDRECT) poly->style = FILLED; else
2408 poly->style = CLOSED;
2409 }
2410
2411 /*
2412 * routine to return true if the polygon in "poly" is an orthogonal box.
2413 * If the polygon is an orthogonal box, the bounds of that box are placed
2414 * in the reference integers "xl", "xh", "yl", and "yh".
2415 */
isbox(POLYGON * poly,INTBIG * xl,INTBIG * xh,INTBIG * yl,INTBIG * yh)2416 BOOLEAN isbox(POLYGON *poly, INTBIG *xl, INTBIG *xh, INTBIG *yl, INTBIG *yh)
2417 {
2418 /* rectangular styles are always boxes */
2419 if (poly->style == FILLEDRECT || poly->style == CLOSEDRECT)
2420 {
2421 if (poly->xv[0] > poly->xv[1])
2422 {
2423 *xl = poly->xv[1];
2424 *xh = poly->xv[0];
2425 } else
2426 {
2427 *xl = poly->xv[0];
2428 *xh = poly->xv[1];
2429 }
2430 if (poly->yv[0] > poly->yv[1])
2431 {
2432 *yl = poly->yv[1];
2433 *yh = poly->yv[0];
2434 } else
2435 {
2436 *yl = poly->yv[0];
2437 *yh = poly->yv[1];
2438 }
2439 return(TRUE);
2440 }
2441
2442 /* closed boxes must have exactly four points */
2443 if (poly->count == 4)
2444 {
2445 /* only closed polygons and text can be boxes */
2446 if ((poly->style < TEXTCENT || poly->style > TEXTBOX) &&
2447 poly->style != CROSSED && poly->style != FILLED && poly->style != CLOSED) return(FALSE);
2448 } else if (poly->count == 5)
2449 {
2450 if (poly->style < OPENED || poly->style > OPENEDO1) return(FALSE);
2451 if (poly->xv[0] != poly->xv[4] || poly->yv[0] != poly->yv[4]) return(FALSE);
2452 } else return(FALSE);
2453
2454 /* make sure the polygon is rectangular and orthogonal */
2455 if (poly->xv[0] == poly->xv[1] && poly->xv[2] == poly->xv[3] &&
2456 poly->yv[0] == poly->yv[3] && poly->yv[1] == poly->yv[2])
2457 {
2458 if (poly->xv[0] < poly->xv[2])
2459 {
2460 *xl = poly->xv[0]; *xh = poly->xv[2];
2461 } else
2462 {
2463 *xl = poly->xv[2]; *xh = poly->xv[0];
2464 }
2465 if (poly->yv[0] < poly->yv[1])
2466 {
2467 *yl = poly->yv[0]; *yh = poly->yv[1];
2468 } else
2469 {
2470 *yl = poly->yv[1]; *yh = poly->yv[0];
2471 }
2472 return(TRUE);
2473 }
2474 if (poly->xv[0] == poly->xv[3] && poly->xv[1] == poly->xv[2] &&
2475 poly->yv[0] == poly->yv[1] && poly->yv[2] == poly->yv[3])
2476 {
2477 if (poly->xv[0] < poly->xv[1])
2478 {
2479 *xl = poly->xv[0]; *xh = poly->xv[1];
2480 } else
2481 {
2482 *xl = poly->xv[1]; *xh = poly->xv[0];
2483 }
2484 if (poly->yv[0] < poly->yv[2])
2485 {
2486 *yl = poly->yv[0]; *yh = poly->yv[2];
2487 } else
2488 {
2489 *yl = poly->yv[2]; *yh = poly->yv[0];
2490 }
2491 return(TRUE);
2492 }
2493 return(FALSE);
2494 }
2495
2496 /*
2497 * routine to return true if (X,Y) is inside of polygon "poly"
2498 */
isinside(INTBIG x,INTBIG y,POLYGON * poly)2499 BOOLEAN isinside(INTBIG x, INTBIG y, POLYGON *poly)
2500 {
2501 INTBIG xl, xh, yl, yh;
2502 REGISTER INTBIG ang, lastp, tang, thisp, startangle, endangle;
2503 REGISTER INTBIG i, odist, dist, angrange, startdist, enddist, wantdist;
2504
2505 switch (poly->style)
2506 {
2507 case FILLED:
2508 case CLOSED:
2509 case FILLEDRECT:
2510 case CLOSEDRECT:
2511 case CROSSED:
2512 case TEXTCENT:
2513 case TEXTTOP:
2514 case TEXTBOT:
2515 case TEXTLEFT:
2516 case TEXTRIGHT:
2517 case TEXTTOPLEFT:
2518 case TEXTBOTLEFT:
2519 case TEXTTOPRIGHT:
2520 case TEXTBOTRIGHT:
2521 case TEXTBOX:
2522 /* check rectangular case for containment */
2523 if (isbox(poly, &xl, &xh, &yl, &yh))
2524 {
2525 if (x < xl || x > xh || y < yl || y > yh) return(FALSE);
2526 return(TRUE);
2527 }
2528
2529 /* general polygon containment by summing angles to vertices */
2530 ang = 0;
2531 if (x == poly->xv[poly->count-1] && y == poly->yv[poly->count-1]) return(TRUE);
2532 lastp = figureangle(x, y, poly->xv[poly->count-1], poly->yv[poly->count-1]);
2533 for(i=0; i<poly->count; i++)
2534 {
2535 if (x == poly->xv[i] && y == poly->yv[i]) return(TRUE);
2536 thisp = figureangle(x, y, poly->xv[i], poly->yv[i]);
2537 tang = lastp - thisp;
2538 if (tang < -1800) tang += 3600;
2539 if (tang > 1800) tang -= 3600;
2540 ang += tang;
2541 lastp = thisp;
2542 }
2543 if (abs(ang) <= poly->count) return(FALSE);
2544 return(TRUE);
2545
2546 case CROSS:
2547 case BIGCROSS:
2548 /* polygon is only a single point */
2549 getcenter(poly, &xl, &yl);
2550 if (xl == x && yl == y) return(TRUE);
2551 return(FALSE);
2552
2553 case OPENED:
2554 case OPENEDT1:
2555 case OPENEDT2:
2556 case OPENEDT3:
2557 case VECTORS:
2558 /* first look for trivial inclusion by being a vertex */
2559 for(i=0; i<poly->count; i++)
2560 if (poly->xv[i] == x && poly->yv[i] == y) return(TRUE);
2561
2562 /* see if the point is on one of the edges */
2563 if (poly->style == VECTORS)
2564 {
2565 for(i=0; i<poly->count; i += 2)
2566 if (isonline(poly->xv[i],poly->yv[i], poly->xv[i+1], poly->yv[i+1], x, y))
2567 return(TRUE);
2568 } else
2569 {
2570 for(i=1; i<poly->count; i++)
2571 if (isonline(poly->xv[i-1],poly->yv[i-1], poly->xv[i], poly->yv[i], x, y))
2572 return(TRUE);
2573 }
2574 return(FALSE);
2575
2576 case CIRCLE: case THICKCIRCLE:
2577 case DISC:
2578 dist = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
2579 odist = computedistance(poly->xv[0], poly->yv[0], x, y);
2580 if (odist < dist) return(TRUE);
2581 return(FALSE);
2582
2583 case CIRCLEARC: case THICKCIRCLEARC:
2584 /* first see if the point is at the proper angle from the center of the arc */
2585 ang = figureangle(poly->xv[0], poly->yv[0], x, y);
2586 endangle = figureangle(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
2587 startangle = figureangle(poly->xv[0], poly->yv[0], poly->xv[2], poly->yv[2]);
2588 if (endangle > startangle)
2589 {
2590 if (ang < startangle || ang > endangle) return(FALSE);
2591 angrange = endangle - startangle;
2592 } else
2593 {
2594 if (ang < startangle && ang > endangle) return(FALSE);
2595 angrange = 3600 - startangle + endangle;
2596 }
2597
2598 /* now see if the point is the proper distance from the center of the arc */
2599 dist = computedistance(poly->xv[0], poly->yv[0], x, y);
2600 if (ang == startangle || angrange == 0)
2601 {
2602 wantdist = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
2603 } else if (ang == endangle)
2604 {
2605 wantdist = computedistance(poly->xv[0], poly->yv[0], poly->xv[2], poly->yv[2]);
2606 } else
2607 {
2608 startdist = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
2609 enddist = computedistance(poly->xv[0], poly->yv[0], poly->xv[2], poly->yv[2]);
2610 if (enddist == startdist) wantdist = startdist; else
2611 {
2612 wantdist = startdist + (ang - startangle) / angrange *
2613 (enddist - startdist);
2614 }
2615 }
2616 if (dist == wantdist) return(TRUE);
2617 return(FALSE);
2618 }
2619
2620 /* I give up */
2621 return(FALSE);
2622 }
2623
2624 /*
2625 * Routine to compute the minimum size of polygon "poly".
2626 * Only works with manhattan geometry.
2627 */
polyminsize(POLYGON * poly)2628 INTBIG polyminsize(POLYGON *poly)
2629 {
2630 INTBIG xl, xh, yl, yh;
2631
2632 if (isbox(poly, &xl, &xh, &yl, &yh))
2633 {
2634 if (xh-xl < yh-yl) return(xh-xl);
2635 return(yh-yl);
2636 }
2637 return(0);
2638 }
2639
2640 /*
2641 * Routine to determine whether polygon "poly" intersects the rectangle defined by
2642 * lx <= X <= hx and ly <= Y <= hy. Returns true if so.
2643 */
polyinrect(POLYGON * poly,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)2644 BOOLEAN polyinrect(POLYGON *poly, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
2645 {
2646 REGISTER INTBIG i, count;
2647 INTBIG sx, sy, ex, ey, plx, phx, ply, phy;
2648 REGISTER POLYGON *mypoly;
2649
2650 switch (poly->style)
2651 {
2652 case FILLED:
2653 if (isinside(lx, ly, poly)) return(TRUE);
2654 if (isinside(lx, hy, poly)) return(TRUE);
2655 if (isinside(hx, hy, poly)) return(TRUE);
2656 if (isinside(hx, ly, poly)) return(TRUE);
2657 /* FALLTHROUGH */
2658 case CLOSED:
2659 case OPENED:
2660 case OPENEDT1:
2661 case OPENEDT2:
2662 case OPENEDT3:
2663 case OPENEDO1:
2664 for(i=0; i<poly->count; i++)
2665 {
2666 if (i == 0)
2667 {
2668 if (poly->style != CLOSED) continue;
2669 sx = poly->xv[poly->count-1];
2670 sy = poly->yv[poly->count-1];
2671 } else
2672 {
2673 sx = poly->xv[i-1]; sy = poly->yv[i-1];
2674 }
2675 ex = poly->xv[i]; ey = poly->yv[i];
2676 if (!clipline(&sx, &sy, &ex, &ey, lx, hx, ly, hy)) return(TRUE);
2677 }
2678 return(FALSE);
2679 case VECTORS:
2680 for(i=0; i<poly->count; i += 2)
2681 {
2682 sx = poly->xv[i]; sy = poly->yv[i];
2683 ex = poly->xv[i+1]; ey = poly->yv[i+1];
2684 if (!clipline(&sx, &sy, &ex, &ey, lx, hx, ly, hy)) return(TRUE);
2685 }
2686 return(FALSE);
2687 case CIRCLE: case THICKCIRCLE:
2688 case DISC:
2689 case CIRCLEARC: case THICKCIRCLEARC:
2690 mypoly = allocpolygon(poly->count, db_cluster);
2691 mypoly->count = poly->count;
2692 mypoly->style = poly->style;
2693 for(i=0; i<poly->count; i++)
2694 {
2695 mypoly->xv[i] = poly->xv[i];
2696 mypoly->yv[i] = poly->yv[i];
2697 }
2698 cliparc(mypoly, lx, hx, ly, hy);
2699 count = mypoly->count;
2700 freepolygon(mypoly);
2701 if (count != 0) return(TRUE);
2702 return(FALSE);
2703 }
2704 getbbox(poly, &plx, &phx, &ply, &phy);
2705 if (phx < lx || plx > hx || phy < ly || ply > hy) return(FALSE);
2706 return(TRUE);
2707 }
2708
2709 /*
2710 * compute and return the area of the polygon in "poly". The calculation
2711 * may return a negative value if the polygon points are counter-clockwise
2712 */
areapoly(POLYGON * poly)2713 float areapoly(POLYGON *poly)
2714 {
2715 REGISTER INTBIG sign;
2716 float area;
2717 INTBIG xl, xh, yl, yh;
2718
2719 switch (poly->style)
2720 {
2721 case FILLED:
2722 case CLOSED:
2723 case FILLEDRECT:
2724 case CLOSEDRECT:
2725 case CROSSED:
2726 case TEXTCENT:
2727 case TEXTTOP:
2728 case TEXTBOT:
2729 case TEXTLEFT:
2730 case TEXTRIGHT:
2731 case TEXTTOPLEFT:
2732 case TEXTBOTLEFT:
2733 case TEXTTOPRIGHT:
2734 case TEXTBOTRIGHT:
2735 case TEXTBOX:
2736 if (isbox(poly, &xl, &xh, &yl, &yh))
2737 {
2738 area = (float)(xh-xl);
2739 area *= (float)(yh-yl);
2740
2741 /* now determine the sign of the area */
2742 if (poly->xv[0] == poly->xv[1])
2743 {
2744 /* first line is vertical */
2745 sign = (poly->xv[2] - poly->xv[1]) * (poly->yv[1] - poly->yv[0]);
2746 } else
2747 {
2748 /* first line is horizontal */
2749 sign = (poly->xv[1] - poly->xv[0]) * (poly->yv[1] - poly->yv[2]);
2750 }
2751 if (sign < 0) area = -area;
2752 return(area);
2753 }
2754
2755 return(areapoints(poly->count, poly->xv, poly->yv));
2756 }
2757 return(0.0);
2758 }
2759
2760 /*
2761 * reverse the edge order of a polygon
2762 */
reversepoly(POLYGON * poly)2763 void reversepoly(POLYGON *poly)
2764 {
2765 REGISTER INTBIG i, invi;
2766 REGISTER INTBIG mx, my;
2767
2768 for (i = 0, invi = poly->count-1; i<invi; i++, invi--)
2769 {
2770 mx = poly->xv[invi];
2771 my = poly->yv[invi];
2772 poly->xv[invi] = poly->xv[i];
2773 poly->yv[invi] = poly->yv[i];
2774 poly->xv[i] = mx;
2775 poly->yv[i] = my;
2776 }
2777 }
2778
2779 /*
2780 * Compute and return the area of the polygon in the "count" points (x,y).
2781 * The calculation may return a negative value if the polygon points are
2782 * counter-clockwise.
2783 */
areapoints(INTBIG count,INTBIG * x,INTBIG * y)2784 float areapoints(INTBIG count, INTBIG *x, INTBIG *y)
2785 {
2786 REGISTER INTBIG i, x0, y0, x1, y1;
2787 float p1, p2, partial, area;
2788
2789 area = 0.0;
2790 x0 = x[0];
2791 y0 = y[0];
2792 for (i=1; i<count; i++)
2793 {
2794 x1 = x[i];
2795 y1 = y[i];
2796
2797 /* triangulate around the polygon */
2798 p1 = (float)(x1 - x0);
2799 p2 = (float)(y0 + y1);
2800 partial = p1 * p2;
2801 area += partial / 2.0f;
2802 x0 = x1;
2803 y0 = y1;
2804 }
2805 p1 = (float)(x[0] - x0);
2806 p2 = (float)(y[0] + y1);
2807 partial = p1 * p2;
2808 area += partial / 2.0f;
2809 return(area);
2810 }
2811
2812 /*
2813 * routine to return the center point of polygon "poly" in "(x,y)"
2814 */
getcenter(POLYGON * poly,INTBIG * x,INTBIG * y)2815 void getcenter(POLYGON *poly, INTBIG *x, INTBIG *y)
2816 {
2817 REGISTER INTBIG i;
2818 INTBIG xl, xh, yl, yh;
2819
2820 switch (poly->style)
2821 {
2822 case FILLED:
2823 case FILLEDRECT:
2824 case CROSSED:
2825 case CROSS:
2826 case BIGCROSS:
2827 case TEXTCENT:
2828 case TEXTTOP:
2829 case TEXTBOT:
2830 case TEXTLEFT:
2831 case TEXTRIGHT:
2832 case TEXTTOPLEFT:
2833 case TEXTBOTLEFT:
2834 case TEXTTOPRIGHT:
2835 case TEXTBOTRIGHT:
2836 case TEXTBOX:
2837 if (isbox(poly, &xl, &xh, &yl, &yh))
2838 {
2839 *x = (xl + xh) / 2;
2840 *y = (yl + yh) / 2;
2841 return;
2842 }
2843
2844 *x = *y = 0;
2845 for(i=0; i<poly->count; i++)
2846 {
2847 *x += poly->xv[i]; *y += poly->yv[i];
2848 }
2849 *x /= poly->count; *y /= poly->count;
2850 return;
2851
2852 case CLOSED:
2853 /* merely use the center point */
2854 *x = poly->xv[poly->count/2]; *y = poly->yv[poly->count/2];
2855 return;
2856
2857 case CLOSEDRECT:
2858 /* merely use the first point */
2859 *x = poly->xv[0]; *y = poly->yv[0];
2860 return;
2861
2862 case OPENED:
2863 case OPENEDT1:
2864 case OPENEDT2:
2865 case OPENEDT3:
2866 /* if there are a odd number of lines, use center of middle one */
2867 if ((poly->count & 1) == 0)
2868 {
2869 *x = (poly->xv[poly->count/2] + poly->xv[poly->count/2-1]) / 2;
2870 *y = (poly->yv[poly->count/2] + poly->yv[poly->count/2-1]) / 2;
2871 return;
2872 }
2873 /* FALLTHROUGH */
2874
2875 case VECTORS:
2876 /* if there are a odd number of lines, use center of middle one */
2877 if ((poly->count & 3) == 0)
2878 {
2879 *x = (poly->xv[poly->count/2] + poly->xv[poly->count/2-1]) / 2;
2880 *y = (poly->yv[poly->count/2] + poly->yv[poly->count/2-1]) / 2;
2881 return;
2882 }
2883 *x = poly->xv[poly->count/2]; *y = poly->yv[poly->count/2];
2884 return;
2885
2886 case DISC:
2887 *x = poly->xv[0]; *y = poly->yv[0];
2888 return;
2889
2890 case CIRCLE: case THICKCIRCLE:
2891 case CIRCLEARC: case THICKCIRCLEARC:
2892 *x = poly->xv[1]; *y = poly->yv[1];
2893 return;
2894 }
2895 }
2896
2897 /*
2898 * routine to report the distance of point (x,y) to polygon "poly". The
2899 * routine returns a negative amount if the point is a direct hit on or in
2900 * the polygon (the more negative, the closer to the center)
2901 */
polydistance(POLYGON * poly,INTBIG x,INTBIG y)2902 INTBIG polydistance(POLYGON *poly, INTBIG x, INTBIG y)
2903 {
2904 INTBIG lx, hx, ly, hy;
2905 REGISTER INTBIG sty, pang, sang, eang;
2906 REGISTER INTBIG i, dist, cx, cy, bestdist, odist, sdist, edist;
2907
2908 /* handle single point polygons */
2909 sty = poly->style;
2910 if (sty == CROSS || sty == BIGCROSS || poly->count == 1)
2911 {
2912 getcenter(poly, &lx, &ly);
2913 if (lx == x && ly == y) return(-MAXINTBIG);
2914 return(computedistance(lx, ly, x, y));
2915 }
2916
2917 /* handle polygons that are filled in */
2918 if (sty == FILLED || sty == FILLEDRECT || sty == CROSSED ||
2919 (sty >= TEXTCENT && sty <= TEXTBOX))
2920 {
2921 /* give special returned value if point is a direct hit */
2922 if (isinside(x, y, poly))
2923 {
2924 getcenter(poly, &lx, &ly);
2925 return(computedistance(lx, ly, x, y) - MAXINTBIG);
2926 }
2927
2928 /* if polygon is a box, use M.B.R. information */
2929 if (isbox(poly, &lx, &hx, &ly, &hy))
2930 {
2931 if (x > hx) cx = x - hx; else if (x < lx) cx = lx - x; else cx = 0;
2932 if (y > hy) cy = y - hy; else if (y < ly) cy = ly - y; else cy = 0;
2933 if (cx == 0 || cy == 0) return(cx + cy);
2934 return(computedistance(0, 0, cx, cy));
2935 }
2936
2937 /* point is outside of irregular polygon: fall into to next case */
2938 if (sty == FILLEDRECT) sty = CLOSEDRECT; else sty = CLOSED;
2939 }
2940
2941 /* handle closed outline figures */
2942 if (sty == CLOSED)
2943 {
2944 bestdist = MAXINTBIG;
2945 for(i=0; i<poly->count; i++)
2946 {
2947 if (i == 0)
2948 {
2949 lx = poly->xv[poly->count-1];
2950 ly = poly->yv[poly->count-1];
2951 } else
2952 {
2953 lx = poly->xv[i-1];
2954 ly = poly->yv[i-1];
2955 }
2956 hx = poly->xv[i]; hy = poly->yv[i];
2957
2958 /* compute distance of close point to (x,y) */
2959 dist = disttoline(lx,ly, hx,hy, x,y);
2960 if (dist < bestdist) bestdist = dist;
2961 }
2962 return(bestdist);
2963 }
2964
2965 /* handle closed rectangle figures */
2966 if (sty == CLOSEDRECT)
2967 {
2968 bestdist = MAXINTBIG;
2969 for(i=0; i<4; i++)
2970 {
2971 lx = poly->xv[db_rectx[i]];
2972 ly = poly->yv[db_recty[i]];
2973 hx = poly->xv[db_rectx[(i+1)&3]];
2974 hy = poly->yv[db_recty[(i+1)&3]];
2975
2976 /* compute distance of close point to (x,y) */
2977 dist = disttoline(lx,ly, hx,hy, x,y);
2978 if (dist < bestdist) bestdist = dist;
2979 }
2980 return(bestdist);
2981 }
2982
2983 /* handle opened outline figures */
2984 if (sty >= OPENED && sty <= OPENEDO1)
2985 {
2986 bestdist = MAXINTBIG;
2987 for(i=1; i<poly->count; i++)
2988 {
2989 lx = poly->xv[i-1]; ly = poly->yv[i-1];
2990 hx = poly->xv[i]; hy = poly->yv[i];
2991
2992 /* compute distance of close point to (x,y) */
2993 dist = disttoline(lx,ly, hx,hy, x,y);
2994 if (dist < bestdist) bestdist = dist;
2995 }
2996 return(bestdist);
2997 }
2998
2999 /* handle outline vector lists */
3000 if (sty == VECTORS)
3001 {
3002 bestdist = MAXINTBIG;
3003 for(i=0; i<poly->count; i += 2)
3004 {
3005 lx = poly->xv[i]; ly = poly->yv[i];
3006 hx = poly->xv[i+1]; hy = poly->yv[i+1];
3007
3008 /* compute distance of close point to (x,y) */
3009 dist = disttoline(lx,ly, hx,hy, x,y);
3010 if (dist < bestdist) bestdist = dist;
3011 }
3012 return(bestdist);
3013 }
3014
3015 /* handle circular objects */
3016 if (sty == CIRCLE || sty == THICKCIRCLE || sty == DISC)
3017 {
3018 odist = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
3019 dist = computedistance(poly->xv[0], poly->yv[0], x, y);
3020 if (sty == DISC && dist < odist) return(dist-MAXINTBIG);
3021 return(abs(dist-odist));
3022 }
3023 if (sty == CIRCLEARC || sty == THICKCIRCLEARC)
3024 {
3025 /* determine closest point to ends of arc */
3026 sdist = computedistance(x, y, poly->xv[1], poly->yv[1]);
3027 edist = computedistance(x, y, poly->xv[2], poly->yv[2]);
3028 dist = mini(sdist,edist);
3029
3030 /* see if the point is in the segment of the arc */
3031 pang = figureangle(poly->xv[0], poly->yv[0], x, y);
3032 sang = figureangle(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
3033 eang = figureangle(poly->xv[0], poly->yv[0], poly->xv[2], poly->yv[2]);
3034 if (eang > sang)
3035 {
3036 if (pang < eang && pang > sang) return(dist);
3037 } else
3038 {
3039 if (pang < eang || pang > sang) return(dist);
3040 }
3041
3042 /* point in arc: determine distance */
3043 odist = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
3044 dist = computedistance(poly->xv[0], poly->yv[0], x, y);
3045 return(abs(dist-odist));
3046 }
3047
3048 /* grid polygons cover everything */
3049 if (sty == GRIDDOTS) return(-1);
3050
3051 /* can't figure out others: use distance to polygon center */
3052 getcenter(poly, &lx, &ly);
3053 return(computedistance(lx, ly, x, y));
3054 }
3055
3056 /*
3057 * Routine to return the distance between polygons "poly1" and "poly2".
3058 * Returns zero if they touch or overlap.
3059 */
polyseparation(POLYGON * poly1,POLYGON * poly2)3060 INTBIG polyseparation(POLYGON *poly1, POLYGON *poly2)
3061 {
3062 INTBIG cx, cy;
3063 REGISTER INTBIG i, pd, minpd;
3064
3065 /* stop now if they touch */
3066 if (polyintersect(poly1, poly2)) return(0);
3067
3068 /* look at all points on polygon 1 */
3069 for(i=0; i<poly1->count; i++)
3070 {
3071 cx = poly1->xv[i]; cy = poly1->yv[i];
3072 closestpoint(poly2, &cx, &cy);
3073 pd = computedistance(poly1->xv[i], poly1->yv[i], cx, cy);
3074 if (pd <= 0) return(0);
3075 if (i == 0) minpd = pd; else
3076 {
3077 if (pd < minpd) minpd = pd;
3078 }
3079 }
3080
3081 /* look at all points on polygon 2 */
3082 for(i=0; i<poly2->count; i++)
3083 {
3084 cx = poly2->xv[i]; cy = poly2->yv[i];
3085 closestpoint(poly1, &cx, &cy);
3086 pd = computedistance(poly2->xv[i], poly2->yv[i], cx, cy);
3087 if (pd <= 0) return(0);
3088 if (pd < minpd) minpd = pd;
3089 }
3090 return(minpd);
3091 }
3092
3093 /*
3094 * routine to return true if polygons "poly1" and "poly2" intersect (that is,
3095 * if any of their lines intersect).
3096 */
polyintersect(POLYGON * poly1,POLYGON * poly2)3097 BOOLEAN polyintersect(POLYGON *poly1, POLYGON *poly2)
3098 {
3099 INTBIG lx1, hx1, ly1, hy1, lx2, hx2, ly2, hy2;
3100 REGISTER INTBIG i, px, py, tx, ty;
3101
3102 /* quit now if bounding boxes don't overlap */
3103 getbbox(poly1, &lx1, &hx1, &ly1, &hy1);
3104 getbbox(poly2, &lx2, &hx2, &ly2, &hy2);
3105 if (hx1 < lx2 || hx2 < lx1 || hy1 < ly2 || hy2 < ly1) return(FALSE);
3106
3107 /* make sure these polygons are not the "RECT" type */
3108 maketruerect(poly1);
3109 maketruerect(poly2);
3110
3111 /* check each line in polygon 1 */
3112 for(i=0; i<poly1->count; i++)
3113 {
3114 if (i == 0)
3115 {
3116 if (poly1->style == OPENED || poly1->style == OPENEDT1 ||
3117 poly1->style == OPENEDT2 || poly1->style == OPENEDT3 ||
3118 poly1->style == VECTORS) continue;
3119 px = poly1->xv[poly1->count-1];
3120 py = poly1->yv[poly1->count-1];
3121 } else
3122 {
3123 px = poly1->xv[i-1];
3124 py = poly1->yv[i-1];
3125 }
3126 tx = poly1->xv[i];
3127 ty = poly1->yv[i];
3128 if (poly1->style == VECTORS && (i&1) != 0) i++;
3129 if (px == tx && py == ty) continue;
3130
3131 /* compare this line with polygon 2 */
3132 if (mini(px,tx) > hx2 || maxi(px,tx) < lx2 ||
3133 mini(py,ty) > hy2 || maxi(py,ty) < ly2) continue;
3134 if (db_lineintersect(px,py, tx,ty, poly2)) return(TRUE);
3135 }
3136 return(FALSE);
3137 }
3138
3139 /*
3140 * routine to return true if the line segment from (px1,py1) to (tx1,ty1)
3141 * intersects any line in polygon "poly"
3142 */
db_lineintersect(INTBIG px1,INTBIG py1,INTBIG tx1,INTBIG ty1,POLYGON * poly)3143 BOOLEAN db_lineintersect(INTBIG px1, INTBIG py1, INTBIG tx1, INTBIG ty1, POLYGON *poly)
3144 {
3145 REGISTER INTBIG i, px2, py2, tx2, ty2, ang, ang1, ang2;
3146 INTBIG ix, iy;
3147
3148 for(i=0; i<poly->count; i++)
3149 {
3150 if (i == 0)
3151 {
3152 if (poly->style == OPENED || poly->style == OPENEDT1 ||
3153 poly->style == OPENEDT2 || poly->style == OPENEDT3 ||
3154 poly->style == VECTORS) continue;
3155 px2 = poly->xv[poly->count-1];
3156 py2 = poly->yv[poly->count-1];
3157 } else
3158 {
3159 px2 = poly->xv[i-1];
3160 py2 = poly->yv[i-1];
3161 }
3162 tx2 = poly->xv[i];
3163 ty2 = poly->yv[i];
3164 if (poly->style == VECTORS && (i&1) != 0) i++;
3165 if (px2 == tx2 && py2 == ty2) continue;
3166
3167 /* special case: this line is vertical */
3168 if (px2 == tx2)
3169 {
3170 /* simple bounds check */
3171 if (mini(px1,tx1) > px2 || maxi(px1,tx1) < px2) continue;
3172
3173 if (px1 == tx1)
3174 {
3175 if (mini(py1,ty1) > maxi(py2,ty2) ||
3176 maxi(py1,ty1) < mini(py2,ty2)) continue;
3177 return(TRUE);
3178 }
3179 if (py1 == ty1)
3180 {
3181 if (mini(py2,ty2) > py1 || maxi(py2,ty2) < py1) continue;
3182 return(TRUE);
3183 }
3184 ang = figureangle(px1,py1, tx1,ty1);
3185 (void)intersect(px2,py2, 900, px1,py1, ang, &ix, &iy);
3186 if (ix != px2 || iy < mini(py2,ty2) || iy > maxi(py2,ty2)) continue;
3187 return(TRUE);
3188 }
3189
3190 /* special case: this line is horizontal */
3191 if (py2 == ty2)
3192 {
3193 /* simple bounds check */
3194 if (mini(py1,ty1) > py2 || maxi(py1,ty1) < py2) continue;
3195
3196 if (py1 == ty1)
3197 {
3198 if (mini(px1,tx1) > maxi(px2,tx2) ||
3199 maxi(px1,tx1) < mini(px2,tx2)) continue;
3200 return(TRUE);
3201 }
3202 if (px1 == tx1)
3203 {
3204 if (mini(px2,tx2) > px1 || maxi(px2,tx2) < px1) continue;
3205 return(TRUE);
3206 }
3207 ang = figureangle(px1,py1, tx1,ty1);
3208 (void)intersect(px2,py2, 0, px1,py1, ang, &ix, &iy);
3209 if (iy != py2 || ix < mini(px2,tx2) || ix > maxi(px2,tx2)) continue;
3210 return(TRUE);
3211 }
3212
3213 /* simple bounds check */
3214 if (mini(px1,tx1) > maxi(px2,tx2) || maxi(px1,tx1) < mini(px2,tx2) ||
3215 mini(py1,ty1) > maxi(py2,ty2) || maxi(py1,ty1) < mini(py2,ty2)) continue;
3216
3217 /* general case of line intersection */
3218 ang1 = figureangle(px1,py1, tx1,ty1);
3219 ang2 = figureangle(px2,py2, tx2,ty2);
3220 (void)intersect(px2, py2, ang2, px1, py1, ang1, &ix, &iy);
3221 if (ix < mini(px2,tx2) || ix > maxi(px2,tx2) ||
3222 iy < mini(py2,ty2) || iy > maxi(py2,ty2) ||
3223 ix < mini(px1,tx1) || ix > maxi(px1,tx1) ||
3224 iy < mini(py1,ty1) || iy > maxi(py1,ty1)) continue;
3225 return(TRUE);
3226 }
3227 return(FALSE);
3228 }
3229
3230 /*
3231 * routine to determine the closest point on polygon "poly" to the point
3232 * (*x, *y) and return that point in (*x, *y). Thus, the coordinate value
3233 * is adjusted to the closest point in or on the polygon
3234 */
closestpoint(POLYGON * poly,INTBIG * x,INTBIG * y)3235 void closestpoint(POLYGON *poly, INTBIG *x, INTBIG *y)
3236 {
3237 INTBIG lx, hx, ly, hy, nx, ny;
3238 REGISTER INTBIG i, dist, gx, gy, bestdist;
3239
3240 switch (poly->style)
3241 {
3242 case CROSS:
3243 case BIGCROSS:
3244 /* single point polygons simply use the center */
3245 getcenter(poly, x, y);
3246 return;
3247
3248 case FILLED:
3249 case FILLEDRECT:
3250 case CROSSED:
3251 case TEXTCENT:
3252 case TEXTTOP:
3253 case TEXTBOT:
3254 case TEXTLEFT:
3255 case TEXTRIGHT:
3256 case TEXTTOPLEFT:
3257 case TEXTBOTLEFT:
3258 case TEXTTOPRIGHT:
3259 case TEXTBOTRIGHT:
3260 case TEXTBOX:
3261 /* filled polygon: check for regularity first */
3262 if (isbox(poly, &lx, &hx, &ly, &hy))
3263 {
3264 if (*x < lx) *x = lx; if (*x > hx) *x = hx;
3265 if (*y < ly) *y = ly; if (*y > hy) *y = hy;
3266 return;
3267 }
3268 if (poly->style == FILLED || poly->style == FILLEDRECT)
3269 {
3270 if (isinside(*x, *y, poly)) return;
3271 }
3272
3273 /* FALLTHROUGH */
3274
3275 case CLOSED:
3276 /* check outline of description */
3277 bestdist = MAXINTBIG;
3278 for(i=0; i<poly->count; i++)
3279 {
3280 nx = *x; ny = *y;
3281 if (i == 0)
3282 {
3283 lx = poly->xv[poly->count-1];
3284 ly = poly->yv[poly->count-1];
3285 } else
3286 {
3287 lx = poly->xv[i-1]; ly = poly->yv[i-1];
3288 }
3289 dist = closestpointtosegment(lx,ly, poly->xv[i], poly->yv[i], &nx, &ny);
3290 if (dist > bestdist) continue;
3291 bestdist = dist;
3292 gx = nx; gy = ny;
3293 }
3294 *x = gx; *y = gy;
3295 return;
3296
3297 case CLOSEDRECT:
3298 /* check outline of description */
3299 bestdist = MAXINTBIG;
3300 for(i=0; i<4; i++)
3301 {
3302 nx = *x; ny = *y;
3303 lx = poly->xv[db_rectx[i]];
3304 ly = poly->yv[db_recty[i]];
3305 hx = poly->xv[db_rectx[(i+1)&3]];
3306 hy = poly->yv[db_recty[(i+1)&3]];
3307 dist = closestpointtosegment(lx,ly, hx, hy, &nx, &ny);
3308 if (dist > bestdist) continue;
3309 bestdist = dist;
3310 gx = nx; gy = ny;
3311 }
3312 *x = gx; *y = gy;
3313 return;
3314
3315 case OPENED:
3316 case OPENEDT1:
3317 case OPENEDT2:
3318 case OPENEDT3:
3319 /* check outline of description */
3320 bestdist = MAXINTBIG;
3321 for(i=1; i<poly->count; i++)
3322 {
3323 nx = *x; ny = *y;
3324 dist = closestpointtosegment(poly->xv[i-1], poly->yv[i-1],
3325 poly->xv[i], poly->yv[i], &nx, &ny);
3326 if (dist > bestdist) continue;
3327 bestdist = dist;
3328 gx = nx; gy = ny;
3329 }
3330 *x = gx; *y = gy;
3331 return;
3332
3333 case VECTORS:
3334 /* check outline of description */
3335 bestdist = MAXINTBIG;
3336 for(i=0; i<poly->count; i = i + 2)
3337 {
3338 nx = *x; ny = *y;
3339 dist = closestpointtosegment(poly->xv[i], poly->yv[i],
3340 poly->xv[i+1], poly->yv[i+1], &nx, &ny);
3341 if (dist > bestdist) continue;
3342 bestdist = dist;
3343 gx = nx; gy = ny;
3344 }
3345 *x = gx; *y = gy;
3346 return;
3347 }
3348 }
3349
3350 /*
3351 * routine to determine the minimum bounding rectangle of the polygon in
3352 * "poly" and return it in the reference parameters "lx", "hx", "ly", and "hy"
3353 */
getbbox(POLYGON * poly,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy)3354 void getbbox(POLYGON *poly, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy)
3355 {
3356 REGISTER INTBIG i, dist;
3357
3358 /* rectangular styles store information differently */
3359 if (poly->style == FILLEDRECT || poly->style == CLOSEDRECT)
3360 {
3361 *lx = mini(poly->xv[0], poly->xv[1]);
3362 *hx = maxi(poly->xv[0], poly->xv[1]);
3363 *ly = mini(poly->yv[0], poly->yv[1]);
3364 *hy = maxi(poly->yv[0], poly->yv[1]);
3365 return;
3366 }
3367
3368 /* special code for circles */
3369 if (poly->style == CIRCLE || poly->style == THICKCIRCLE || poly->style == DISC)
3370 {
3371 dist = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
3372 *lx = poly->xv[0] - dist;
3373 *hx = poly->xv[0] + dist;
3374 *ly = poly->yv[0] - dist;
3375 *hy = poly->yv[0] + dist;
3376 return;
3377 }
3378
3379 /* special code for arcs */
3380 if (poly->style == CIRCLEARC || poly->style == THICKCIRCLEARC)
3381 {
3382 arcbbox(poly->xv[1], poly->yv[1], poly->xv[2], poly->yv[2],
3383 poly->xv[0], poly->yv[0], lx, hx, ly, hy);
3384 return;
3385 }
3386
3387 /* just compute the bounds of the points */
3388 *lx = *hx = poly->xv[0]; *ly = *hy = poly->yv[0];
3389 for(i=1; i<poly->count; i++)
3390 {
3391 if (poly->xv[i] < *lx) *lx = poly->xv[i];
3392 if (poly->xv[i] > *hx) *hx = poly->xv[i];
3393 if (poly->yv[i] < *ly) *ly = poly->yv[i];
3394 if (poly->yv[i] > *hy) *hy = poly->yv[i];
3395 }
3396 }
3397
3398 /*
3399 * routine to compare two polygons and return true if they are the same
3400 */
polysame(POLYGON * poly1,POLYGON * poly2)3401 BOOLEAN polysame(POLYGON *poly1, POLYGON *poly2)
3402 {
3403 INTBIG xl1, xh1, yl1, yh1, xl2, xh2, yl2, yh2;
3404 REGISTER INTBIG i;
3405
3406 /* polygons must have the same number of points */
3407 if (poly1->count != poly2->count) return(FALSE);
3408
3409 /* if both are boxes, compare their extents */
3410 if (isbox(poly1, &xl1, &xh1, &yl1, &yh1))
3411 {
3412 if (isbox(poly2, &xl2, &xh2, &yl2, &yh2))
3413 {
3414 /* compare box extents */
3415 if (xl1 == xl2 && xh1 == xh2 && yl1 == yl2 && yh1 == yh2) return(TRUE);
3416 }
3417 return(FALSE);
3418 } else if (isbox(poly2, &xl2, &xh2, &yl2, &yh2)) return(FALSE);
3419
3420 /* compare these boxes the hard way */
3421 for(i=0; i<poly1->count; i++)
3422 if (poly1->xv[i] != poly2->xv[i] || poly1->yv[i] != poly2->yv[i]) return(FALSE);
3423 return(TRUE);
3424 }
3425
3426 /*
3427 * routine to copy polygon "spoly" to polygon "dpoly"
3428 */
polycopy(POLYGON * dpoly,POLYGON * spoly)3429 void polycopy(POLYGON *dpoly, POLYGON *spoly)
3430 {
3431 REGISTER INTBIG i;
3432
3433 if (dpoly->limit < spoly->count) (void)extendpolygon(dpoly, spoly->count);
3434 for(i=0; i<spoly->count; i++)
3435 {
3436 dpoly->xv[i] = spoly->xv[i];
3437 dpoly->yv[i] = spoly->yv[i];
3438 }
3439 dpoly->count = spoly->count;
3440 dpoly->style = spoly->style;
3441 dpoly->string = spoly->string;
3442 TDCOPY(dpoly->textdescript, spoly->textdescript);
3443 dpoly->tech = spoly->tech;
3444 dpoly->desc = spoly->desc;
3445 dpoly->layer = spoly->layer;
3446 dpoly->portproto = spoly->portproto;
3447 }
3448
3449 /*
3450 * routine to make a polygon that describes the rectangle running from
3451 * (lx,ly) to (hx,hy).
3452 */
makerectpoly(INTBIG lx,INTBIG ux,INTBIG ly,INTBIG uy,POLYGON * poly)3453 void makerectpoly(INTBIG lx, INTBIG ux, INTBIG ly, INTBIG uy, POLYGON *poly)
3454 {
3455 if (poly->limit < 4) (void)extendpolygon(poly, 4);
3456 poly->xv[0] = poly->xv[1] = lx;
3457 poly->xv[2] = poly->xv[3] = ux;
3458 poly->yv[0] = poly->yv[3] = ly;
3459 poly->yv[1] = poly->yv[2] = uy;
3460 poly->count = 4;
3461 }
3462
3463 /*
3464 * routine to make a rectangle polygon that describes the rectangle running from
3465 * (lx,ly) to (hx,hy).
3466 */
maketruerectpoly(INTBIG lx,INTBIG ux,INTBIG ly,INTBIG uy,POLYGON * poly)3467 void maketruerectpoly(INTBIG lx, INTBIG ux, INTBIG ly, INTBIG uy, POLYGON *poly)
3468 {
3469 if (poly->limit < 2) (void)extendpolygon(poly, 2);
3470 poly->xv[0] = lx;
3471 poly->xv[1] = ux;
3472 poly->yv[0] = ly;
3473 poly->yv[1] = uy;
3474 poly->count = 2;
3475 }
3476
3477 /*
3478 * routine to reduce polygon "poly" by the proper amount given that it is the
3479 * description of port "pp" on nodeinst "ni" and will be connected to an arc
3480 * with width "wid" (this arc width should be the offset width, not the actual
3481 * width). The angle of the arc is "angle" (negative if angle should not be
3482 * considered). The polygon is modified.
3483 */
reduceportpoly(POLYGON * poly,NODEINST * ni,PORTPROTO * pp,INTBIG wid,INTBIG angle)3484 void reduceportpoly(POLYGON *poly, NODEINST *ni, PORTPROTO *pp, INTBIG wid, INTBIG angle)
3485 {
3486 INTBIG lx, ly, hx, hy, cx, cy, bx, by, ux, uy, plx, phx, ply, phy;
3487 REGISTER INTBIG j, realwid, dist, swapi;
3488 XARRAY trans, localtran, t1;
3489
3490 /* find bottommost node */
3491 makerot(ni, trans);
3492 while (ni->proto->primindex == 0)
3493 {
3494 maketrans(ni, localtran);
3495 transmult(localtran, trans, t1);
3496 ni = pp->subnodeinst;
3497 pp = pp->subportproto;
3498 makerot(ni, localtran);
3499 transmult(localtran, t1, trans);
3500 }
3501
3502 /* do not reduce port if not filled */
3503 if (poly->style != FILLED && poly->style != FILLEDRECT &&
3504 poly->style != CROSSED && poly->style != DISC) return;
3505
3506 /* do not reduce port areas on polygonally defined nodes */
3507 if (gettrace(ni) != NOVARIABLE) return;
3508
3509 /* determine amount to reduce port */
3510 realwid = wid / 2;
3511
3512 /* get bounding box of port polygon */
3513 if (!isbox(poly, &bx, &ux, &by, &uy))
3514 {
3515 /* special case: nonrectangular port */
3516 if (poly->style == DISC)
3517 {
3518 /* shrink discs */
3519 dist = computedistance(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
3520 dist = maxi(0, dist-realwid);
3521 poly->xv[1] = poly->xv[0] + dist;
3522 poly->yv[1] = poly->yv[0];
3523 return;
3524 }
3525
3526 /* cannot handle polygons yet */
3527 return;
3528 }
3529
3530 /* determine the center of the port polygon */
3531 getcenter(poly, &cx, &cy);
3532
3533 /* compute the area of the nodeinst */
3534 nodesizeoffset(ni, &plx, &ply, &phx, &phy);
3535 xform(ni->lowx+plx, ni->lowy+ply, &lx, &ly, trans);
3536 xform(ni->highx-phx, ni->highy-phy, &hx, &hy, trans);
3537 if (lx > hx) { swapi = lx; lx = hx; hx = swapi; }
3538 if (ly > hy) { swapi = ly; ly = hy; hy = swapi; }
3539
3540 /* do not reduce in X if arc is horizontal */
3541 if (angle != 0 && angle != 1800)
3542 {
3543 /* determine reduced port area */
3544 lx = maxi(bx, lx + realwid); hx = mini(ux, hx - realwid);
3545 if (hx < lx) hx = lx = (hx + lx) / 2;
3546
3547 /* only clip in X if the port area is within of the reduced node X area */
3548 if (ux >= lx && bx <= hx)
3549 for(j=0; j<poly->count; j++)
3550 {
3551 if (poly->xv[j] < lx) poly->xv[j] = lx;
3552 if (poly->xv[j] > hx) poly->xv[j] = hx;
3553 }
3554 }
3555
3556 /* do not reduce in Y if arc is vertical */
3557 if (angle != 900 && angle != 2700)
3558 {
3559 /* determine reduced port area */
3560 ly = maxi(by, ly + realwid); hy = mini(uy, hy - realwid);
3561 if (hy < ly) hy = ly = (hy + ly) / 2;
3562
3563 /* only clip in Y if the port area is inside of the reduced node Y area */
3564 if (uy >= ly && by <= hy)
3565 for(j=0; j<poly->count; j++)
3566 {
3567 if (poly->yv[j] < ly) poly->yv[j] = ly;
3568 if (poly->yv[j] > hy) poly->yv[j] = hy;
3569 }
3570 }
3571 }
3572
3573 /*
3574 * Routine that splits the polygon "which" horizontally at "yl".
3575 * The part above is placed in "abovep" and the part below in "belowp"
3576 * Returns true on error.
3577 */
polysplithoriz(INTBIG yl,POLYGON * which,POLYGON ** abovep,POLYGON ** belowp)3578 BOOLEAN polysplithoriz(INTBIG yl, POLYGON *which, POLYGON **abovep, POLYGON **belowp)
3579 {
3580 INTBIG xt, yt, xn, yn, i, pind, x, y;
3581 POLYGON *above, *below;
3582
3583 /* create two new polygons and delete the original */
3584 above = allocpolygon(4, which->cluster);
3585 if (above == 0) return(TRUE);
3586 below = allocpolygon(4, which->cluster);
3587 if (below == 0) return(TRUE);
3588 above->count = below->count = 0;
3589
3590 /* run through points in polygon to be split */
3591 for(i=0; i<which->count; i++)
3592 {
3593 if (i == 0) pind = which->count-1; else pind = i-1;
3594 xt = which->xv[pind]; yt = which->yv[pind];
3595 xn = which->xv[i]; yn = which->yv[i];
3596
3597 /* if point is on line, put in both polygons */
3598 if (yn == yl)
3599 {
3600 if (db_addpointtopoly(xn, yn, above)) return(TRUE);
3601 if (db_addpointtopoly(xn, yn, below)) return(TRUE);
3602 continue;
3603 }
3604
3605 /* if both points are on same side, put in appropriate polygon */
3606 if (yn >= yl && yt >= yl)
3607 {
3608 if (db_addpointtopoly(xn, yn, above)) return(TRUE);
3609 continue;
3610 }
3611 if (yn <= yl && yt <= yl)
3612 {
3613 if (db_addpointtopoly(xn, yn, below)) return(TRUE);
3614 continue;
3615 }
3616
3617 /* lines cross, intersect them */
3618 y = yl;
3619 if (yn == yl) x = xn; else
3620 if (yt == yl) x = xt; else
3621 {
3622 x = xt + muldiv(y-yt, xn-xt, yn-yt);
3623 }
3624
3625 /* insert new point in polygons */
3626 if (yt <= yl && yn >= yl)
3627 {
3628 if (db_addpointtopoly(x, y, above)) return(TRUE);
3629 if (db_addpointtopoly(x, y, below)) return(TRUE);
3630 if (db_addpointtopoly(xn, yn, above)) return(TRUE);
3631 continue;
3632 }
3633 if (yt >= yl && yn <= yl)
3634 {
3635 if (db_addpointtopoly(x, y, above)) return(TRUE);
3636 if (db_addpointtopoly(x, y, below)) return(TRUE);
3637 if (db_addpointtopoly(xn, yn, below)) return(TRUE);
3638 continue;
3639 }
3640 }
3641
3642 *abovep = above;
3643 *belowp = below;
3644 return(FALSE);
3645 }
3646
3647 /*
3648 * Routine that splits the polygon "which" vertically at "xl".
3649 * The part to the left is placed in "leftp" and the part to the right in "rightp".
3650 * Returns true on error.
3651 */
polysplitvert(INTBIG xl,POLYGON * which,POLYGON ** leftp,POLYGON ** rightp)3652 BOOLEAN polysplitvert(INTBIG xl, POLYGON *which, POLYGON **leftp, POLYGON **rightp)
3653 {
3654 INTBIG xt, yt, xn, yn, i, pind, x, y;
3655 POLYGON *left, *right;
3656
3657 /* create two new polygons and delete the original */
3658 left = allocpolygon(4, which->cluster);
3659 if (left == 0) return(TRUE);
3660 right = allocpolygon(4, which->cluster);
3661 if (right == 0) return(TRUE);
3662 left->count = right->count = 0;
3663
3664 /* run through points in polygon to be split */
3665 for(i=0; i<which->count; i++)
3666 {
3667 if (i == 0) pind = which->count-1; else pind = i-1;
3668 xt = which->xv[pind]; yt = which->yv[pind];
3669 xn = which->xv[i]; yn = which->yv[i];
3670
3671 /* if point is on line, put in both polygons */
3672 if (xn == xl)
3673 {
3674 if (db_addpointtopoly(xn, yn, left)) return(TRUE);
3675 if (db_addpointtopoly(xn, yn, right)) return(TRUE);
3676 continue;
3677 }
3678
3679 /* if both points are on same side, put in appropriate polygon */
3680 if (xn <= xl && xt <= xl)
3681 {
3682 if (db_addpointtopoly(xn, yn, left)) return(TRUE);
3683 continue;
3684 }
3685 if (xn >= xl && xt >= xl)
3686 {
3687 if (db_addpointtopoly(xn, yn, right)) return(TRUE);
3688 continue;
3689 }
3690
3691 /* lines cross, intersect them */
3692 x = xl;
3693 if (xn == xl) y = yn; else
3694 if (xt == xl) y = yt; else
3695 {
3696 y = yt + muldiv(x-xt, yn-yt, xn-xt);
3697 }
3698
3699 /* insert new point in polygons */
3700 if (xt >= xl && xn <= xl)
3701 {
3702 if (db_addpointtopoly(x, y, left)) return(TRUE);
3703 if (db_addpointtopoly(x, y, right)) return(TRUE);
3704 if (db_addpointtopoly(xn, yn, left)) return(TRUE);
3705 continue;
3706 }
3707 if (xt <= xl && xn >= xl)
3708 {
3709 if (db_addpointtopoly(x, y, left)) return(TRUE);
3710 if (db_addpointtopoly(x, y, right)) return(TRUE);
3711 if (db_addpointtopoly(xn, yn, right)) return(TRUE);
3712 continue;
3713 }
3714 }
3715
3716 *leftp = left;
3717 *rightp = right;
3718 return(FALSE);
3719 }
3720
db_addpointtopoly(INTBIG x,INTBIG y,POLYGON * poly)3721 BOOLEAN db_addpointtopoly(INTBIG x, INTBIG y, POLYGON *poly)
3722 {
3723 if (poly->count >= poly->limit)
3724 {
3725 if (extendpolygon(poly, poly->limit*2)) return(TRUE);
3726 }
3727 poly->xv[poly->count] = x; poly->yv[poly->count] = y;
3728 poly->count++;
3729 return(FALSE);
3730 }
3731
3732 /************************* CLIPPING *************************/
3733
3734 /*
3735 * Routine to clip a line from (fx,fy) to (tx,ty) in the rectangle lx <= X <= hx and ly <= Y <= hy.
3736 * Returns true if the line is not visible.
3737 */
clipline(INTBIG * fx,INTBIG * fy,INTBIG * tx,INTBIG * ty,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)3738 BOOLEAN clipline(INTBIG *fx, INTBIG *fy, INTBIG *tx, INTBIG *ty, INTBIG lx, INTBIG hx,
3739 INTBIG ly, INTBIG hy)
3740 {
3741 REGISTER INTBIG t, fc, tc;
3742
3743 for(;;)
3744 {
3745 /* compute code bits for "from" point */
3746 fc = 0;
3747 if (*fx < lx) fc |= LEFT; else
3748 if (*fx > hx) fc |= RIGHT;
3749 if (*fy < ly) fc |= BOTTOM; else
3750 if (*fy > hy) fc |= TOP;
3751
3752 /* compute code bits for "to" point */
3753 tc = 0;
3754 if (*tx < lx) tc |= LEFT; else
3755 if (*tx > hx) tc |= RIGHT;
3756 if (*ty < ly) tc |= BOTTOM; else
3757 if (*ty > hy) tc |= TOP;
3758
3759 /* look for trivial acceptance or rejection */
3760 if (fc == 0 && tc == 0) return(FALSE);
3761 if (fc == tc || (fc & tc) != 0) return(TRUE);
3762
3763 /* make sure the "from" side needs clipping */
3764 if (fc == 0)
3765 {
3766 t = *fx; *fx = *tx; *tx = t;
3767 t = *fy; *fy = *ty; *ty = t;
3768 t = fc; fc = tc; tc = t;
3769 }
3770
3771 if ((fc&LEFT) != 0)
3772 {
3773 if (*tx == *fx) return(TRUE);
3774 t = muldiv(*ty - *fy, lx - *fx, *tx - *fx);
3775 *fy += t;
3776 *fx = lx;
3777 }
3778 if ((fc&RIGHT) != 0)
3779 {
3780 if (*tx == *fx) return(TRUE);
3781 t = muldiv(*ty - *fy, hx - *fx, *tx - *fx);
3782 *fy += t;
3783 *fx = hx;
3784 }
3785 if ((fc&BOTTOM) != 0)
3786 {
3787 if (*ty == *fy) return(TRUE);
3788 t = muldiv(*tx - *fx, ly - *fy, *ty - *fy);
3789 *fx += t;
3790 *fy = ly;
3791 }
3792 if ((fc&TOP) != 0)
3793 {
3794 if (*ty == *fy) return(TRUE);
3795 t = muldiv(*tx - *fx, hy - *fy, *ty - *fy);
3796 *fx += t;
3797 *fy = hy;
3798 }
3799 }
3800 }
3801
3802 typedef struct
3803 {
3804 double angle;
3805 INTBIG x, y;
3806 } ANGLELIST;
3807
3808 /*
3809 * Helper routine for "esort" that makes angles go in descending order (used by "cliparc()").
3810 */
db_anglelistdescending(const void * e1,const void * e2)3811 int db_anglelistdescending(const void *e1, const void *e2)
3812 {
3813 REGISTER ANGLELIST *c1, *c2;
3814 REGISTER double diff;
3815
3816 c1 = (ANGLELIST *)e1;
3817 c2 = (ANGLELIST *)e2;
3818 diff = c2->angle - c1->angle;
3819 if (diff < 0.0) return(-1);
3820 if (diff > 0.0) return(1);
3821 return(0);
3822 }
3823
3824 /*
3825 * Routine to clips curved polygon (CIRCLE, THICKCIRCLE, DISC, CIRCLEARC, or THICKCIRCLEARC)
3826 * against the rectangle lx <= X <= hx and ly <= Y <= hy.
3827 * Adjusts the polygon to contain the visible portions.
3828 */
cliparc(POLYGON * in,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)3829 void cliparc(POLYGON *in, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
3830 {
3831 INTBIG plx, ply, phx, phy, ix1, iy1, ix2, iy2;
3832 REGISTER INTBIG xc, yc, xp, yp, midx, midy;
3833 double radius, midangle, dx, dy;
3834 REGISTER INTBIG i, j, intcount, ints, initialcount, prev;
3835 ANGLELIST anglelist[10];
3836
3837 getbbox(in, &plx, &phx, &ply, &phy);
3838
3839 /* if not clipped, stop now */
3840 if (plx >= lx && phx <= hx && ply >= ly && phy <= hy) return;
3841
3842 /* if totally invisible, blank the polygon */
3843 if (plx > hx || phx < lx || ply > hy || phy < ly)
3844 {
3845 in->count = 0;
3846 return;
3847 }
3848
3849 /* initialize list of relevant points */
3850 xc = in->xv[0]; yc = in->yv[0];
3851 xp = in->xv[1]; yp = in->yv[1];
3852 intcount = 0;
3853
3854 if (in->style == CIRCLEARC || in->style == THICKCIRCLEARC)
3855 {
3856 /* include arc endpoints */
3857 anglelist[intcount].x = xp; anglelist[intcount].y = yp;
3858 dx = (double)(xp-xc); dy = (double)(yp-yc);
3859 if (dx == 0.0 && dy == 0.0)
3860 {
3861 ttyputerr(_("Domain error doing circle/circle tangents"));
3862 in->count = 0;
3863 return;
3864 }
3865 anglelist[intcount].angle = atan2(dy, dx);
3866 intcount++;
3867 anglelist[intcount].x = in->xv[2];
3868 anglelist[intcount].y = in->yv[2];
3869 dx = (double)(anglelist[intcount].x-xc);
3870 dy = (double)(anglelist[intcount].y-yc);
3871 if (dx == 0.0 && dy == 0.0)
3872 {
3873 ttyputerr(_("Domain error doing circle/circle tangents"));
3874 in->count = 0;
3875 return;
3876 }
3877 anglelist[intcount].angle = atan2(dy, dx);
3878 intcount++;
3879 }
3880 initialcount = intcount;
3881
3882 /* find intersection points along left edge */
3883 ints = circlelineintersection(xc, yc, xp, yp, lx, ly, lx, hy,
3884 &ix1, &iy1, &ix2, &iy2, 0);
3885 if (ints > 0) { anglelist[intcount].x = ix1; anglelist[intcount++].y = iy1; }
3886 if (ints > 1) { anglelist[intcount].x = ix2; anglelist[intcount++].y = iy2; }
3887
3888 /* find intersection points along top edge */
3889 ints = circlelineintersection(xc, yc, xp, yp, lx, hy, hx, hy,
3890 &ix1, &iy1, &ix2, &iy2, 0);
3891 if (ints > 0) { anglelist[intcount].x = ix1; anglelist[intcount++].y = iy1; }
3892 if (ints > 1) { anglelist[intcount].x = ix2; anglelist[intcount++].y = iy2; }
3893
3894 /* find intersection points along right edge */
3895 ints = circlelineintersection(xc, yc, xp, yp, hx, hy, hx, ly,
3896 &ix1, &iy1, &ix2, &iy2, 0);
3897 if (ints > 0) { anglelist[intcount].x = ix1; anglelist[intcount++].y = iy1; }
3898 if (ints > 1) { anglelist[intcount].x = ix2; anglelist[intcount++].y = iy2; }
3899
3900 /* find intersection points along bottom edge */
3901 ints = circlelineintersection(xc, yc, xp, yp, hx, ly, lx, ly,
3902 &ix1, &iy1, &ix2, &iy2, 0);
3903 if (ints > 0) { anglelist[intcount].x = ix1; anglelist[intcount++].y = iy1; }
3904 if (ints > 1) { anglelist[intcount].x = ix2; anglelist[intcount++].y = iy2; }
3905
3906 /* if there are no intersections, arc is invisible */
3907 if (intcount == initialcount) { in->count = 0; return; }
3908
3909 /* determine angle of intersection points */
3910 for(i=initialcount; i<intcount; i++)
3911 {
3912 if (anglelist[i].y == yc && anglelist[i].x == xc)
3913 {
3914 ttyputerr(_("Warning: instability ahead"));
3915 in->count = 0;
3916 return;
3917 }
3918 dx = (double)(anglelist[i].x-xc); dy = (double)(anglelist[i].y-yc);
3919 if (dx == 0.0 && dy == 0.0)
3920 {
3921 ttyputerr(_("Domain error doing circle/circle tangents"));
3922 in->count = 0;
3923 return;
3924 }
3925 anglelist[i].angle = atan2(dy, dx);
3926 }
3927
3928 /* reject points not on the arc */
3929 if (in->style == CIRCLEARC || in->style == THICKCIRCLEARC)
3930 {
3931 j = 2;
3932 for(i=2; i<intcount; i++)
3933 {
3934 if (anglelist[0].angle > anglelist[1].angle)
3935 {
3936 if (anglelist[i].angle > anglelist[0].angle ||
3937 anglelist[i].angle < anglelist[1].angle) continue;
3938 } else
3939 {
3940 if (anglelist[i].angle > anglelist[0].angle &&
3941 anglelist[i].angle < anglelist[1].angle) continue;
3942 }
3943 anglelist[j].x = anglelist[i].x;
3944 anglelist[j].y = anglelist[i].y;
3945 anglelist[j].angle = anglelist[i].angle;
3946 j++;
3947 }
3948 intcount = j;
3949
3950 /* make sure the start of the arc is the first point */
3951 for(i=0; i<intcount; i++)
3952 if (anglelist[i].angle > anglelist[0].angle)
3953 anglelist[i].angle -= EPI*2.0;
3954 } else
3955 {
3956 /* make sure all angles are negative */
3957 for(i=0; i<intcount; i++)
3958 if (anglelist[i].angle > 0.0) anglelist[i].angle -= EPI*2.0;
3959 }
3960
3961 /* sort by angle */
3962 esort(anglelist, intcount, sizeof (ANGLELIST), db_anglelistdescending);
3963
3964 /* for full circles, add in starting point to complete circle */
3965 if (in->style != CIRCLEARC && in->style != THICKCIRCLEARC)
3966 {
3967 anglelist[intcount].x = anglelist[0].x;
3968 anglelist[intcount].y = anglelist[0].y;
3969 anglelist[intcount].angle = anglelist[0].angle - EPI*2.0;
3970 intcount++;
3971 }
3972
3973 /* now examine each segment and add it, if it is in the window */
3974 radius = (double)computedistance(xc, yc, xp, yp);
3975 in->count = 0;
3976 for(i=1; i<intcount; i++)
3977 {
3978 prev = i-1;
3979 midangle = (anglelist[prev].angle + anglelist[i].angle) / 2.0;
3980 while (midangle < -EPI) midangle += EPI * 2.0;
3981 midx = xc + rounddouble(radius * cos(midangle));
3982 midy = yc + rounddouble(radius * sin(midangle));
3983 if (midx < lx || midx > hx || midy < ly || midy > hy) continue;
3984
3985 /* add this segment */
3986 if (in->limit < in->count+3) (void)extendpolygon(in, in->count+3);
3987 in->xv[in->count] = xc; in->yv[in->count++] = yc;
3988 in->xv[in->count] = anglelist[prev].x; in->yv[in->count++] = anglelist[prev].y;
3989 in->xv[in->count] = anglelist[i].x; in->yv[in->count++] = anglelist[i].y;
3990 }
3991 if (in->style == THICKCIRCLE) in->style = THICKCIRCLEARC; else
3992 if (in->style == CIRCLE) in->style = CIRCLEARC;
3993 }
3994
clippoly(POLYGON * in,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)3995 void clippoly(POLYGON *in, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
3996 {
3997 REGISTER INTBIG i;
3998 REGISTER INTBIG pre;
3999 REGISTER POLYGON *a, *b, *swap;
4000 REGISTER POLYGON *out;
4001
4002 /* see if any points are outside */
4003 pre = 0;
4004 for(i=0; i<in->count; i++)
4005 {
4006 if (in->xv[i] < lx) pre |= LEFT; else
4007 if (in->xv[i] > hx) pre |= RIGHT;
4008 if (in->yv[i] < ly) pre |= BOTTOM; else
4009 if (in->yv[i] > hy) pre |= TOP;
4010 }
4011 if (pre == 0) return;
4012
4013 /* get polygon */
4014 out = allocpolygon(4, db_cluster);
4015
4016 /* clip on all four sides */
4017 a = in; b = out;
4018 out->style = in->style;
4019
4020 if ((pre & LEFT) != 0)
4021 {
4022 db_clipedge(a, b, LEFT, lx);
4023 swap = a; a = b; b = swap;
4024 }
4025 if ((pre & RIGHT) != 0)
4026 {
4027 db_clipedge(a, b, RIGHT, hx);
4028 swap = a; a = b; b = swap;
4029 }
4030 if ((pre & TOP) != 0)
4031 {
4032 db_clipedge(a, b, TOP, hy);
4033 swap = a; a = b; b = swap;
4034 }
4035 if ((pre & BOTTOM) != 0)
4036 {
4037 db_clipedge(a, b, BOTTOM, ly);
4038 swap = a; a = b; b = swap;
4039 }
4040
4041 /* remove redundant points from polygon */
4042 for(pre=0, i=0; i<a->count; i++)
4043 {
4044 if (i > 0 && a->xv[i-1] == a->xv[i] && a->yv[i-1] == a->yv[i]) continue;
4045 if (pre >= b->limit) (void)extendpolygon(b, pre+1);
4046 b->xv[pre] = a->xv[i]; b->yv[pre++] = a->yv[i];
4047 }
4048
4049 /* if polygon is not opened, remove redundancy on wrap-around */
4050 if (in->style != OPENED)
4051 while (pre != 0 && b->xv[0] == b->xv[pre-1] && b->yv[0] == b->yv[pre-1]) pre--;
4052
4053 b->count = pre;
4054
4055 /* copy the polygon back if it in the wrong place */
4056 if (b != in)
4057 {
4058 if (in->limit < b->count) (void)extendpolygon(in, b->count);
4059 for(i=0; i<b->count; i++)
4060 {
4061 in->xv[i] = b->xv[i];
4062 in->yv[i] = b->yv[i];
4063 }
4064 in->count = b->count;
4065 }
4066 freepolygon(out);
4067 }
4068
4069 /*
4070 * routine to clip polygon "in" against line "edge" (1:left, 2:right,
4071 * 4:bottom, 8:top) and place clipped result in "out".
4072 */
db_clipedge(POLYGON * in,POLYGON * out,INTBIG edge,INTBIG value)4073 void db_clipedge(POLYGON *in, POLYGON *out, INTBIG edge, INTBIG value)
4074 {
4075 REGISTER INTBIG outcount;
4076 REGISTER INTBIG i, pre, firstx, firsty;
4077 INTBIG x1, y1, x2, y2;
4078
4079 /* look at all the lines */
4080 outcount = 0;
4081 if (in->style != OPENED)
4082 {
4083 for(i=0; i<in->count; i++)
4084 {
4085 if (i == 0) pre = in->count-1; else pre = i-1;
4086 x1 = in->xv[pre]; y1 = in->yv[pre];
4087 x2 = in->xv[i]; y2 = in->yv[i];
4088 if (db_clip(&x1, &y1, &x2, &y2, edge, value)) continue;
4089 if (outcount+1 >= out->limit) (void)extendpolygon(out, outcount+2);
4090 if (outcount != 0)
4091 {
4092 if (x1 != out->xv[outcount-1] || y1 != out->yv[outcount-1])
4093 {
4094 out->xv[outcount] = x1; out->yv[outcount++] = y1;
4095 }
4096 } else { firstx = x1; firsty = y1; }
4097 out->xv[outcount] = x2; out->yv[outcount++] = y2;
4098 }
4099 if (outcount != 0 && (out->xv[outcount-1] != firstx || out->yv[outcount-1] != firsty))
4100 {
4101 out->xv[outcount] = firstx; out->yv[outcount++] = firsty;
4102 }
4103 } else
4104 {
4105 for(i=0; i<in->count-1; i++)
4106 {
4107 x1 = in->xv[i]; y1 = in->yv[i];
4108 x2 = in->xv[i+1];y2 = in->yv[i+1];
4109 if (db_clip(&x1, &y1, &x2, &y2, edge, value)) continue;
4110 if (out->limit < outcount+2) (void)extendpolygon(out, outcount+2);
4111 out->xv[outcount] = x1; out->yv[outcount++] = y1;
4112 out->xv[outcount] = x2; out->yv[outcount++] = y2;
4113 }
4114 }
4115 out->count = outcount;
4116 }
4117
4118 /*
4119 * Routine to do clipping on the vector from (x1,y1) to (x2,y2).
4120 * If the vector is completely invisible, true is returned.
4121 */
db_clip(INTBIG * xp1,INTBIG * yp1,INTBIG * xp2,INTBIG * yp2,INTBIG codebit,INTBIG value)4122 BOOLEAN db_clip(INTBIG *xp1, INTBIG *yp1, INTBIG *xp2, INTBIG *yp2, INTBIG codebit, INTBIG value)
4123 {
4124 REGISTER INTBIG t, x1, y1, x2, y2, c1, c2;
4125 REGISTER BOOLEAN flip;
4126
4127 x1 = *xp1; y1 = *yp1;
4128 x2 = *xp2; y2 = *yp2;
4129
4130 c1 = c2 = 0;
4131 if (codebit == LEFT)
4132 {
4133 if (x1 < value) c1 = codebit;
4134 if (x2 < value) c2 = codebit;
4135 } else if (codebit == BOTTOM)
4136 {
4137 if (y1 < value) c1 = codebit;
4138 if (y2 < value) c2 = codebit;
4139 } else if (codebit == RIGHT)
4140 {
4141 if (x1 > value) c1 = codebit;
4142 if (x2 > value) c2 = codebit;
4143 } else if (codebit == TOP)
4144 {
4145 if (y1 > value) c1 = codebit;
4146 if (y2 > value) c2 = codebit;
4147 }
4148
4149 if (c1 == c2) return(c1 != 0);
4150 if (c1 == 0)
4151 {
4152 t = x1; x1 = x2; x2 = t;
4153 t = y1; y1 = y2; y2 = t;
4154 flip = TRUE;
4155 } else flip = FALSE;
4156 if (codebit == LEFT || codebit == RIGHT)
4157 {
4158 t = muldiv(y2-y1, value-x1, x2-x1);
4159 y1 += t;
4160 x1 = value;
4161 } else if (codebit == BOTTOM || codebit == TOP)
4162 {
4163 t = muldiv(x2-x1, value-y1, y2-y1);
4164 x1 += t;
4165 y1 = value;
4166 }
4167 if (flip)
4168 {
4169 *xp1 = x2; *yp1 = y2;
4170 *xp2 = x1; *yp2 = y1;
4171 } else
4172 {
4173 *xp1 = x1; *yp1 = y1;
4174 *xp2 = x2; *yp2 = y2;
4175 }
4176 return(0);
4177 }
4178
4179 /************************* WINDOWPART CONTROL *************************/
4180
4181 /*
4182 * routine to make a new window at location "l". If "protow" is not NOWINDOWPART,
4183 * use it for other information. Returns NOWINDOWPART upon error
4184 */
newwindowpart(CHAR * l,WINDOWPART * protow)4185 WINDOWPART *newwindowpart(CHAR *l, WINDOWPART *protow)
4186 {
4187 REGISTER WINDOWPART *w;
4188 REGISTER VARIABLE *var;
4189 REGISTER INTBIG lambda;
4190
4191 if (db_windowpartfree == NOWINDOWPART)
4192 {
4193 w = (WINDOWPART *)emalloc((sizeof (WINDOWPART)), db_cluster);
4194 if (w == 0)
4195 {
4196 db_donextchangequietly = FALSE;
4197 return(NOWINDOWPART);
4198 }
4199 } else
4200 {
4201 /* take window from free list */
4202 w = db_windowpartfree;
4203 db_windowpartfree = w->nextwindowpart;
4204 }
4205
4206 if (protow != NOWINDOWPART)
4207 {
4208 copywindowpart(w, protow);
4209 } else
4210 {
4211 lambda = el_curlib->lambda[el_curtech->techindex];
4212 w->uselx = -lambda * 10;
4213 w->usehx = lambda * 10;
4214 w->usely = -lambda * 10;
4215 w->usehy = lambda * 10;
4216 w->screenlx = -lambda * 10;
4217 w->screenhx = lambda * 10;
4218 w->screenly = -lambda * 10;
4219 w->screenhy = lambda * 10;
4220 w->hratio = w->vratio = 50;
4221 computewindowscale(w);
4222 w->curnodeproto = NONODEPROTO;
4223 w->topnodeproto = NONODEPROTO;
4224 w->inplacedepth = 0;
4225 transid(w->intocell);
4226 transid(w->outofcell);
4227 var = getval((INTBIG)us_tool, VTOOL, VFRACT|VISARRAY, x_("USER_default_grid"));
4228 if (var == NOVARIABLE)
4229 {
4230 w->gridx = w->gridy = WHOLE;
4231 } else
4232 {
4233 w->gridx = ((INTBIG *)var->addr)[0];
4234 w->gridy = ((INTBIG *)var->addr)[1];
4235 }
4236 w->state = DISPWINDOW;
4237 w->frame = getwindowframe(FALSE);
4238 w->charhandler = 0;
4239 w->buttonhandler = 0;
4240 w->changehandler = 0;
4241 w->termhandler = 0;
4242 w->redisphandler = 0;
4243 }
4244 if (allocstring(&w->location, l, db_cluster))
4245 {
4246 db_donextchangequietly = FALSE;
4247 return(NOWINDOWPART);
4248 }
4249 w->editor = NOEDITOR;
4250 w->expwindow = (void *)-1;
4251 w->numvar = 0;
4252
4253 if (db_enterwindowpart(w)) return(NOWINDOWPART);
4254
4255 /* handle change control and broadcast */
4256 if (!db_donextchangequietly && !db_dochangesquietly)
4257 {
4258 (void)db_change((INTBIG)w, OBJECTNEW, VWINDOWPART, 0, 0, 0, 0, 0);
4259 }
4260 db_donextchangequietly = FALSE;
4261 return(w);
4262 }
4263
4264 /*
4265 * Routine to enter window "w" into the database. Returns true on error.
4266 */
db_enterwindowpart(WINDOWPART * w)4267 BOOLEAN db_enterwindowpart(WINDOWPART *w)
4268 {
4269 WINDOWFRAME *wf;
4270
4271 /* make a new frame if requested */
4272 if ((w->state & HASOWNFRAME) != 0)
4273 {
4274 /* create a new frame */
4275 wf = newwindowframe(FALSE, 0);
4276 if (wf == NOWINDOWFRAME) wf = getwindowframe(FALSE);
4277 w->frame = wf;
4278 if (wf != NOWINDOWFRAME)
4279 {
4280 /* recreating old frame: set size */
4281 sizewindowframe(wf, w->framehx, w->framehy);
4282 }
4283 w->state &= ~HASOWNFRAME;
4284 }
4285
4286 /* insert window in linked list */
4287 w->nextwindowpart = el_topwindowpart;
4288 w->prevwindowpart = NOWINDOWPART;
4289 if (el_topwindowpart != NOWINDOWPART) el_topwindowpart->prevwindowpart = w;
4290 el_topwindowpart = w;
4291 return(FALSE);
4292 }
4293
computewindowscale(WINDOWPART * w)4294 void computewindowscale(WINDOWPART *w)
4295 {
4296 float denominator;
4297
4298 w->scalex = (float)(w->usehx - w->uselx);
4299 denominator = (float)w->screenhx;
4300 denominator -= (float)w->screenlx;
4301 if (denominator != 0.0) w->scalex /= denominator;
4302
4303 w->scaley = (float)(w->usehy - w->usely);
4304 denominator = (float)w->screenhy;
4305 denominator -= (float)w->screenly;
4306 if (denominator != 0.0) w->scaley /= denominator;
4307 }
4308
applyxscale(WINDOWPART * w,INTBIG val)4309 INTBIG applyxscale(WINDOWPART *w, INTBIG val)
4310 {
4311 return(roundfloat((float)val * w->scalex));
4312 }
4313
applyyscale(WINDOWPART * w,INTBIG val)4314 INTBIG applyyscale(WINDOWPART *w, INTBIG val)
4315 {
4316 return(roundfloat((float)val * w->scaley));
4317 }
4318
4319 /*
4320 * routine to kill window "w"
4321 */
killwindowpart(WINDOWPART * w)4322 void killwindowpart(WINDOWPART *w)
4323 {
4324 db_retractwindowpart(w);
4325
4326 /* handle change control and broadcast */
4327 if (!db_donextchangequietly && !db_dochangesquietly)
4328 {
4329 (void)db_change((INTBIG)w, OBJECTKILL, VWINDOWPART, 0, 0, 0, 0, 0);
4330 }
4331 db_donextchangequietly = FALSE;
4332 }
4333
db_retractwindowpart(WINDOWPART * w)4334 void db_retractwindowpart(WINDOWPART *w)
4335 {
4336 REGISTER WINDOWPART *ow;
4337
4338 if (w->termhandler != 0) (*w->termhandler)(w);
4339
4340 /* remove the window from the linked list */
4341 if (w->prevwindowpart != NOWINDOWPART)
4342 w->prevwindowpart->nextwindowpart = w->nextwindowpart;
4343 if (w->nextwindowpart != NOWINDOWPART)
4344 w->nextwindowpart->prevwindowpart = w->prevwindowpart;
4345 if (w == el_topwindowpart) el_topwindowpart = w->nextwindowpart;
4346
4347 /* see if this window lived by itself in a frame */
4348 for(ow = el_topwindowpart; ow != NOWINDOWPART; ow = ow->nextwindowpart)
4349 if (ow->frame == w->frame) break;
4350 if (ow == NOWINDOWPART)
4351 {
4352 /* delete the frame too */
4353 w->framelx = 0; w->framely = 0;
4354 getwindowframesize(w->frame, &w->framehx, &w->framehy);
4355 w->state |= HASOWNFRAME;
4356 killwindowframe(w->frame);
4357 }
4358 }
4359
4360 /*
4361 * routine to return window "w" to the pool of free windows
4362 */
freewindowpart(WINDOWPART * w)4363 void freewindowpart(WINDOWPART *w)
4364 {
4365 if ((w->state&WINDOWTYPE) == TEXTWINDOW ||
4366 (w->state&WINDOWTYPE) == POPTEXTWINDOW)
4367 {
4368 us_editorterm(w);
4369 } else if ((w->state&WINDOWTYPE) == EXPLORERWINDOW)
4370 {
4371 us_deleteexplorerstruct(w);
4372 }
4373 efree(w->location);
4374 w->nextwindowpart = db_windowpartfree;
4375 db_windowpartfree = w;
4376 }
4377
4378 /*
4379 * routine to copy the contents of window "from" to window "to"
4380 */
copywindowpart(WINDOWPART * to,WINDOWPART * from)4381 void copywindowpart(WINDOWPART *to, WINDOWPART *from)
4382 {
4383 REGISTER INTBIG i;
4384
4385 to->uselx = from->uselx; to->usehx = from->usehx;
4386 to->usely = from->usely; to->usehy = from->usehy;
4387 to->screenlx = from->screenlx; to->screenhx = from->screenhx;
4388 to->screenly = from->screenly; to->screenhy = from->screenhy;
4389 to->hratio = from->hratio; to->vratio = from->vratio;
4390 to->scalex = from->scalex; to->scaley = from->scaley;
4391 to->curnodeproto = from->curnodeproto;
4392 to->topnodeproto = from->topnodeproto;
4393 to->inplacedepth = from->inplacedepth;
4394 for(i=0; i<from->inplacedepth; i++) to->inplacestack[i] = from->inplacestack[i];
4395 transcpy(from->intocell, to->intocell);
4396 transcpy(from->outofcell, to->outofcell);
4397 to->gridx = from->gridx; to->gridy = from->gridy;
4398 to->state = from->state;
4399 to->frame = from->frame;
4400 to->editor = from->editor;
4401 to->expwindow = from->expwindow;
4402 to->buttonhandler = from->buttonhandler;
4403 to->charhandler = from->charhandler;
4404 to->changehandler = from->changehandler;
4405 to->termhandler = from->termhandler;
4406 to->redisphandler = from->redisphandler;
4407 }
4408
4409 /*************************************** INTBIG OBJECTS ***************************************/
4410
newintlistobj(CLUSTER * clus)4411 LISTINTBIG *newintlistobj(CLUSTER *clus)
4412 {
4413 REGISTER LISTINTBIG *li;
4414
4415 li = (LISTINTBIG *)emalloc(sizeof (LISTINTBIG), clus);
4416 if (li == 0) return(0);
4417 li->count = li->total = 0;
4418 li->cluster = clus;
4419 return(li);
4420 }
4421
killintlistobj(LISTINTBIG * li)4422 void killintlistobj(LISTINTBIG *li)
4423 {
4424 if (li->total > 0) efree((CHAR *)li->list);
4425 efree((CHAR *)li);
4426 }
4427
clearintlistobj(LISTINTBIG * li)4428 void clearintlistobj(LISTINTBIG *li)
4429 {
4430 li->count = 0;
4431 }
4432
getintlistobj(LISTINTBIG * li,INTBIG * count)4433 INTBIG *getintlistobj(LISTINTBIG *li, INTBIG *count)
4434 {
4435 *count = li->count;
4436 return(li->list);
4437 }
4438
4439 /*
4440 * Routine to ensure that the integer list "li" has "needed" entries in it. Returns TRUE on error.
4441 */
ensureintlistobj(LISTINTBIG * li,INTBIG needed)4442 BOOLEAN ensureintlistobj(LISTINTBIG *li, INTBIG needed)
4443 {
4444 if (needed > li->total)
4445 {
4446 if (li->total > 0) efree((CHAR *)li->list);
4447 li->total = 0;
4448 li->list = (INTBIG *)emalloc(needed * SIZEOFINTBIG, li->cluster);
4449 if (li->list == 0) return(TRUE);
4450 li->total = needed;
4451 }
4452 return(FALSE);
4453 }
4454
4455 /*
4456 * Routine to add value "i" to the end of the global list "li". If "unique" is TRUE,
4457 * does not add duplicate values. Returns true on error.
4458 */
addtointlistobj(LISTINTBIG * li,INTBIG value,BOOLEAN unique)4459 BOOLEAN addtointlistobj(LISTINTBIG *li, INTBIG value, BOOLEAN unique)
4460 {
4461 REGISTER INTBIG newtotal, m, *newqueue;
4462
4463 /* if a unique list is needed, check for duplications */
4464 if (unique)
4465 {
4466 for(m=0; m<li->count; m++)
4467 if (li->list[m] == value) return(FALSE);
4468 }
4469
4470 if (li->count >= li->total)
4471 {
4472 newtotal = li->total * 2;
4473 if (li->count >= newtotal) newtotal = li->count + 50;
4474 newqueue = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, li->cluster);
4475 if (newqueue == 0) return(TRUE);
4476 for(m=0; m < li->count; m++) newqueue[m] = li->list[m];
4477 if (li->total > 0) efree((CHAR *)li->list);
4478 li->total = newtotal;
4479 li->list = newqueue;
4480 }
4481 li->list[li->count++] = value;
4482 return(FALSE);
4483 }
4484
4485 /*************************************** STRING OBJECTS ***************************************/
4486
4487 /*
4488 * Routine to create a new string object from memory cluster "clus". Returns zero on error.
4489 */
newstringobj(CLUSTER * clus)4490 STRINGOBJ *newstringobj(CLUSTER *clus)
4491 {
4492 REGISTER STRINGOBJ *so;
4493
4494 so = (STRINGOBJ *)emalloc(sizeof (STRINGOBJ), clus);
4495 if (so == 0) return(0);
4496 so->total = 0;
4497 so->cluster = clus;
4498 return(so);
4499 }
4500
4501 /*
4502 * Routine to delete new string object "so".
4503 */
killstringobj(STRINGOBJ * so)4504 void killstringobj(STRINGOBJ *so)
4505 {
4506 if (so->total > 0) efree((CHAR *)so->string);
4507 efree((CHAR *)so);
4508 }
4509
4510 /*
4511 * Routine to clear the string in string object "so".
4512 */
clearstringobj(STRINGOBJ * so)4513 void clearstringobj(STRINGOBJ *so)
4514 {
4515 so->count = 0;
4516 }
4517
4518 /*
4519 * Routine to return the string in string object "so".
4520 */
getstringobj(STRINGOBJ * so)4521 CHAR *getstringobj(STRINGOBJ *so)
4522 {
4523 if (so->count == 0) return(x_(""));
4524 return(so->string);
4525 }
4526
4527 /*
4528 * Routine to add "string" to the string in string object "so".
4529 */
addstringtostringobj(CHAR * string,STRINGOBJ * so)4530 void addstringtostringobj(CHAR *string, STRINGOBJ *so)
4531 {
4532 REGISTER INTBIG len, newtotal;
4533 REGISTER CHAR *newstring;
4534
4535 len = estrlen(string);
4536 if (so->count + len >= so->total)
4537 {
4538 newtotal = so->total * 2;
4539 if (so->count + len > newtotal) newtotal = so->count + len + 10;
4540 newstring = (CHAR *)emalloc(newtotal * SIZEOFCHAR, so->cluster);
4541 if (newstring == 0) return;
4542 if (so->count > 0) strncpy(newstring, so->string, so->count);
4543 if (so->total > 0) efree((CHAR *)so->string);
4544 so->string = newstring;
4545 so->total = newtotal;
4546 }
4547 estrcpy(&so->string[so->count], string);
4548 so->count += len;
4549 }
4550
4551 /************************* MISCELLANEOUS *************************/
4552
4553 /*
4554 * routine to return the value of lambda to use for object "geom"
4555 */
figurelambda(GEOM * geom)4556 INTBIG figurelambda(GEOM *geom)
4557 {
4558 if (!geom->entryisnode)
4559 return(lambdaofarc(geom->entryaddr.ai));
4560 return(lambdaofnode(geom->entryaddr.ni));
4561 }
4562
4563 /*
4564 * Routine to determine the proper value of lambda to use, given that
4565 * the work involves NODEPROTO "np".
4566 */
lambdaofcell(NODEPROTO * np)4567 INTBIG lambdaofcell(NODEPROTO *np)
4568 {
4569 REGISTER TECHNOLOGY *tech;
4570 REGISTER LIBRARY *lib;
4571
4572 tech = np->tech;
4573 if (np->primindex != 0) return(el_curlib->lambda[tech->techindex]);
4574
4575 /* cell: figure out the proper technology and library */
4576 lib = np->lib;
4577 return(lib->lambda[tech->techindex]);
4578 }
4579
4580 /*
4581 * Routine to determine the proper value of lambda to use, given that
4582 * the work involves ARCINST "ai".
4583 */
lambdaofarc(ARCINST * ai)4584 INTBIG lambdaofarc(ARCINST *ai)
4585 {
4586 REGISTER TECHNOLOGY *tech;
4587 REGISTER LIBRARY *lib;
4588 REGISTER NODEPROTO *np;
4589
4590 np = ai->parent;
4591 if (np == NONODEPROTO) tech = ai->proto->tech; else
4592 {
4593 tech = np->tech;
4594 if (tech == NOTECHNOLOGY) tech = whattech(np);
4595 }
4596 if (ai->parent == NONODEPROTO) lib = el_curlib; else
4597 lib = ai->parent->lib;
4598 return(lib->lambda[tech->techindex]);
4599 }
4600
4601 /*
4602 * Routine to determine the proper value of lambda to use, given that
4603 * the work involves NODEINST "ni".
4604 */
lambdaofnode(NODEINST * ni)4605 INTBIG lambdaofnode(NODEINST *ni)
4606 {
4607 REGISTER TECHNOLOGY *tech;
4608 REGISTER LIBRARY *lib;
4609 REGISTER NODEPROTO *np;
4610 REGISTER INTBIG lambda;
4611
4612 np = ni->parent;
4613 if (np == NONODEPROTO) np = ni->proto;
4614 tech = np->tech;
4615 if (tech == NOTECHNOLOGY) tech = whattech(np);
4616 if (ni->parent == NONODEPROTO) lib = el_curlib; else
4617 lib = ni->parent->lib;
4618 lambda = lib->lambda[tech->techindex];
4619 return(lambda);
4620 }
4621
4622 /*
4623 * routine to determine the technology of a cell. Gives preference to
4624 * the layout technologies (i.e. ignores "schematic" and "artwork" unless they
4625 * are the only elements in the cell). Someday this code should be
4626 * generalized to read special codes on the technologies that indicate
4627 * "layout" versus "symbolic".
4628 */
4629 #define MAXTECHNOLOGIES 100 /* assumed maximum number of technologies (not hard limit) */
4630
whattech(NODEPROTO * cell)4631 TECHNOLOGY *whattech(NODEPROTO *cell)
4632 {
4633 REGISTER INTBIG best, bestlayout, usecountneed, i, *usecount, *allocatedusecount;
4634 REGISTER BOOLEAN foundicons;
4635 INTBIG staticusecount[MAXTECHNOLOGIES];
4636 REGISTER NODEPROTO *np, *onp, *cv, *cnp;
4637 REGISTER NODEINST *ni;
4638 REGISTER ARCINST *ai;
4639 REGISTER ARCPROTO *ap;
4640 REGISTER TECHNOLOGY *tech, *besttech, *bestlayouttech, *rettech;
4641
4642 /* primitives know their technology */
4643 if (cell->primindex != 0) return(cell->tech);
4644
4645 /* ensure proper memory for usage counts */
4646 usecountneed = 0;
4647 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
4648 if (tech->techindex > usecountneed) usecountneed = tech->techindex;
4649 usecountneed++;
4650 if (usecountneed > MAXTECHNOLOGIES)
4651 {
4652 allocatedusecount = (INTBIG *)emalloc(usecountneed * SIZEOFINTBIG, db_cluster);
4653 if (allocatedusecount == 0) return(gen_tech);
4654 usecount = allocatedusecount;
4655 } else
4656 {
4657 usecount = staticusecount;
4658 allocatedusecount = 0;
4659 }
4660
4661 /* zero counters for every technology */
4662 for(i=0; i<usecountneed; i++) usecount[i] = 0;
4663
4664 /* count technologies of all primitive nodes in the cell */
4665 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
4666 {
4667 np = ni->proto;
4668 if (np == NONODEPROTO) continue;
4669 if (np->primindex == 0)
4670 {
4671 cnp = contentsview(np);
4672 if (cnp != NONODEPROTO) np = cnp;
4673 }
4674 if (np->tech != NOTECHNOLOGY)
4675 usecount[np->tech->techindex]++;
4676 }
4677
4678 /* count technologies of all arcs in the cell */
4679 for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
4680 {
4681 ap = ai->proto;
4682 if (ap == NOARCPROTO) continue;
4683 usecount[ap->tech->techindex]++;
4684 }
4685
4686 /* find a concensus */
4687 best = 0; besttech = NOTECHNOLOGY;
4688 bestlayout = 0; bestlayouttech = NOTECHNOLOGY;
4689 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
4690 {
4691 /* always ignore the generic technology */
4692 if (tech == gen_tech) continue;
4693
4694 /* find the most popular of ALL technologies */
4695 if (usecount[tech->techindex] > best)
4696 {
4697 best = usecount[tech->techindex];
4698 besttech = tech;
4699 }
4700
4701 /* find the most popular of the layout technologies */
4702 if (tech == sch_tech || tech == art_tech) continue;
4703 if (usecount[tech->techindex] > bestlayout)
4704 {
4705 bestlayout = usecount[tech->techindex];
4706 bestlayouttech = tech;
4707 }
4708 }
4709
4710 /* presume generic */
4711 if (cell->cellview == el_iconview)
4712 {
4713 /* in icons, if there is any artwork, use it */
4714 if (usecount[art_tech->techindex] > 0) return(art_tech);
4715
4716 /* in icons, if there is nothing, presume artwork */
4717 if (besttech == NOTECHNOLOGY) return(art_tech);
4718
4719 /* use artwork as a default */
4720 rettech = art_tech;
4721 } else if (cell->cellview == el_schematicview)
4722 {
4723 /* in schematic, if there are any schematic components, use it */
4724 if (usecount[sch_tech->techindex] > 0) return(sch_tech);
4725
4726 /* in schematic, if there is nothing, presume schematic */
4727 if (besttech == NOTECHNOLOGY) return(sch_tech);
4728
4729 /* use schematic as a default */
4730 rettech = sch_tech;
4731 } else
4732 {
4733 /* use the current layout technology as the default */
4734 rettech = el_curlayouttech;
4735 }
4736
4737 /* if a layout technology was voted the most, return it */
4738 if (bestlayouttech != NOTECHNOLOGY) rettech = bestlayouttech; else
4739 {
4740 /* if any technology was voted the most, return it */
4741 if (besttech != NOTECHNOLOGY) rettech = besttech; else
4742 {
4743 /* if this is an icon, presume the technology of its contents */
4744 cv = contentsview(cell);
4745 if (cv != NONODEPROTO)
4746 {
4747 if (cv->tech == NOTECHNOLOGY)
4748 cv->tech = whattech(cv);
4749 rettech = cv->tech;
4750 } else
4751 {
4752 /* look at the contents of the sub-cells */
4753 foundicons = FALSE;
4754 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
4755 {
4756 np = ni->proto;
4757 if (np == NONODEPROTO) continue;
4758 if (np->primindex != 0) continue;
4759
4760 /* ignore recursive references (showing icon in contents) */
4761 if (isiconof(np, cell)) continue;
4762
4763 /* see if the cell has an icon */
4764 if (np->cellview == el_iconview) foundicons = TRUE;
4765
4766 /* do not follow into another library */
4767 if (np->lib != cell->lib) continue;
4768 onp = contentsview(np);
4769 if (onp != NONODEPROTO) np = onp;
4770 tech = whattech(np);
4771 if (tech == gen_tech) continue;
4772 rettech = tech;
4773 break;
4774 }
4775 if (ni == NONODEINST)
4776 {
4777 /* could not find instances that give information: were there icons? */
4778 if (foundicons) rettech = sch_tech;
4779 }
4780 }
4781 }
4782 }
4783 if (allocatedusecount != 0) efree((CHAR *)allocatedusecount);
4784
4785 /* give up and report the generic technology */
4786 return(rettech);
4787 }
4788
4789 /*
4790 * routine to return the parent node prototype of geometry object "g"
4791 */
geomparent(GEOM * g)4792 NODEPROTO *geomparent(GEOM *g)
4793 {
4794 if (g == NOGEOM) return(NONODEPROTO);
4795 if (g->entryisnode) return(g->entryaddr.ni->parent);
4796 return(g->entryaddr.ai->parent);
4797 }
4798
4799 /*
4800 * routine to recursively determine whether the nodeproto "parent" is
4801 * a descendant of nodeproto "child" (which would make the relationship
4802 * "child insideof parent" recursive). If the routine returns zero,
4803 * the parent is not a descendent of the child and all is well. If
4804 * true returned, recursion exists.
4805 */
isachildof(NODEPROTO * parent,NODEPROTO * child)4806 BOOLEAN isachildof(NODEPROTO *parent, NODEPROTO *child)
4807 {
4808 REGISTER NODEPROTO *np;
4809
4810 /* if the child is primitive there is no recursion */
4811 if (child->primindex != 0) return(FALSE);
4812
4813 /* special case: allow an icon to be inside of the contents for illustration */
4814 if (isiconof(child, parent))
4815 {
4816 if (child->cellview == el_iconview && parent->cellview != el_iconview)
4817 return(FALSE);
4818 }
4819
4820 /* make sure the child is not an icon */
4821 np = contentsview(child);
4822 if (np != NONODEPROTO) child = np;
4823
4824 return(db_isachildof(parent, child));
4825 }
4826
db_isachildof(NODEPROTO * parent,NODEPROTO * child)4827 BOOLEAN db_isachildof(NODEPROTO *parent, NODEPROTO *child)
4828 {
4829 REGISTER NODEINST *ni;
4830 REGISTER NODEPROTO *np;
4831
4832 /* if the child is primitive there is no recursion */
4833 if (child->primindex != 0) return(FALSE);
4834
4835 /* if they are the same, that is recursion */
4836 if (child == parent) return(TRUE);
4837
4838 /* look through every instance of the parent cell */
4839 for(ni = parent->firstinst; ni != NONODEINST; ni = ni->nextinst)
4840 {
4841 /* if two instances in a row have same parent, skip this one */
4842 if (ni->nextinst != NONODEINST && ni->nextinst->parent == ni->parent)
4843 continue;
4844
4845 /* recurse to see if the grandparent belongs to the child */
4846 if (db_isachildof(ni->parent, child)) return(TRUE);
4847 }
4848
4849 /* if this has an icon, look at it's instances */
4850 np = iconview(parent);
4851 if (np != NONODEPROTO)
4852 {
4853 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
4854 {
4855 /* if two instances in a row have same parent, skip this one */
4856 if (ni->nextinst != NONODEINST && ni->nextinst->parent == ni->parent)
4857 continue;
4858
4859 /* special case: allow an icon to be inside of the contents for illustration */
4860 if (isiconof(ni->proto, parent))
4861 {
4862 if (parent->cellview != el_iconview) continue;
4863 }
4864
4865 /* recurse to see if the grandparent belongs to the child */
4866 if (db_isachildof(ni->parent, child)) return(TRUE);
4867 }
4868 }
4869 return(FALSE);
4870 }
4871
4872 /*
4873 * routine to tell the nodeproto that connects arcs of type "ap"
4874 */
getpinproto(ARCPROTO * ap)4875 NODEPROTO *getpinproto(ARCPROTO *ap)
4876 {
4877 REGISTER NODEPROTO *np;
4878 REGISTER PORTPROTO *pp;
4879 REGISTER INTBIG i;
4880 static INTBIG defaultpinkey = 0;
4881 REGISTER VARIABLE *var;
4882
4883 if (ap == NOARCPROTO) return(NONODEPROTO);
4884
4885 /* see if there is a default on this arc proto */
4886 if (defaultpinkey == 0) defaultpinkey = makekey(x_("ARC_Default_Pin"));
4887 var = getvalkey((INTBIG)ap, VARCPROTO, VNODEPROTO, defaultpinkey);
4888 if (var != NOVARIABLE)
4889 {
4890 /* default found: test it for validity */
4891 np = (NODEPROTO *)var->addr;
4892 pp = np->firstportproto;
4893 for(i=0; pp->connects[i] != NOARCPROTO; i++)
4894 if (pp->connects[i] == ap) return(np);
4895 }
4896
4897 /* first look for nodeprotos that are actually declared as pins */
4898 for(np = ap->tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
4899 {
4900 if (((np->userbits & NFUNCTION) >> NFUNCTIONSH) != NPPIN) continue;
4901 pp = np->firstportproto;
4902 for(i=0; pp->connects[i] != NOARCPROTO; i++)
4903 if (pp->connects[i] == ap) return(np);
4904 }
4905
4906 /* now look for a nodeproto that can connect to this type of arc */
4907 for(np = ap->tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
4908 {
4909 pp = np->firstportproto;
4910 if (pp == NOPORTPROTO) continue;
4911 if (pp->nextportproto != NOPORTPROTO) continue;
4912 for(i=0; pp->connects[i] != NOARCPROTO; i++)
4913 if (pp->connects[i] == ap) return(np);
4914 }
4915 ttyputerr(_("No node to connect %s arcs"), describearcproto(ap));
4916 return(NONODEPROTO);
4917 }
4918
4919 /*
4920 * Routine to return TRUE if node "ni" is a pin that is between
4921 * two arcs such that it can be deleted without affecting the geometry of the two arcs.
4922 */
isinlinepin(NODEINST * ni,ARCINST *** thearcs)4923 BOOLEAN isinlinepin(NODEINST *ni, ARCINST ***thearcs)
4924 {
4925 static ARCINST *reconar[2];
4926 INTBIG dx[2], dy[2];
4927 REGISTER INTBIG i, j;
4928 REGISTER ARCINST *ai;
4929 REGISTER PORTARCINST *pi;
4930 REGISTER VARIABLE *var0, *var1;
4931
4932 if ((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH != NPPIN) return(FALSE);
4933
4934 /* see if the pin is connected to two arcs along the same slope */
4935 j = 0;
4936 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
4937 {
4938 if (j >= 2) { j = 0; break; }
4939 reconar[j] = ai = pi->conarcinst;
4940 for(i=0; i<2; i++) if (ai->end[i].nodeinst != ni)
4941 {
4942 dx[j] = ai->end[i].xpos - ai->end[1-i].xpos;
4943 dy[j] = ai->end[i].ypos - ai->end[1-i].ypos;
4944 }
4945 j++;
4946 }
4947 if (j != 2) return(FALSE);
4948
4949 /* must connect to two arcs of the same type and width */
4950 if (reconar[0]->proto != reconar[1]->proto) return(FALSE);
4951 if (reconar[0]->width != reconar[1]->width) return(FALSE);
4952
4953 /* arcs must be along the same angle, and not be curved */
4954 if (dx[0] != 0 || dy[0] != 0 || dx[1] != 0 || dy[1] != 0)
4955 {
4956 if ((dx[0] != 0 || dy[0] != 0) && (dx[1] != 0 || dy[1] != 0) &&
4957 figureangle(0, 0, dx[0], dy[0]) !=
4958 figureangle(dx[1], dy[1], 0, 0)) return(FALSE);
4959 }
4960 if (getvalkey((INTBIG)reconar[0], VARCINST, VINTEGER, el_arc_radius_key) != NOVARIABLE)
4961 return(FALSE);
4962 if (getvalkey((INTBIG)reconar[1], VARCINST, VINTEGER, el_arc_radius_key) != NOVARIABLE)
4963 return(FALSE);
4964
4965 /* the arcs must not have network names on them */
4966 var0 = getvalkey((INTBIG)reconar[0], VARCINST, VSTRING, el_arc_name_key);
4967 var1 = getvalkey((INTBIG)reconar[1], VARCINST, VSTRING, el_arc_name_key);
4968 if (var0 != NOVARIABLE && var1 != NOVARIABLE)
4969 {
4970 if ((var0->type&VDISPLAY) != 0 && (var1->type&VDISPLAY) != 0)
4971 return(FALSE);
4972 }
4973 thearcs = (ARCINST ***)reconar;
4974 return(TRUE);
4975 }
4976
4977 /*
4978 * Routine to return TRUE if node "ni" is an invisible pin that has text in a different
4979 * location. If so, (x,y) is set to the location of that text.
4980 */
invisiblepinwithoffsettext(NODEINST * ni,INTBIG * x,INTBIG * y,BOOLEAN repair)4981 BOOLEAN invisiblepinwithoffsettext(NODEINST *ni, INTBIG *x, INTBIG *y, BOOLEAN repair)
4982 {
4983 REGISTER INTBIG i, j, lambda;
4984 REGISTER PORTEXPINST *pe;
4985 REGISTER PORTPROTO *pp;
4986 REGISTER VARIABLE *var;
4987 static POLYGON *poly = NOPOLYGON;
4988
4989 /* get polygon */
4990 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
4991
4992 /* look for pins that are invisible and have text in different location */
4993 if ((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH != NPPIN) return(FALSE);
4994 if (ni->firstportarcinst != NOPORTARCINST) return(FALSE);
4995
4996 /* stop now if this isn't invisible */
4997 if (ni->proto != gen_invispinprim)
4998 {
4999 j = nodepolys(ni, 0, NOWINDOWPART);
5000 if (j > 0)
5001 {
5002 shapenodepoly(ni, 0, poly);
5003 if (poly->style != TEXTCENT && poly->style != TEXTTOP &&
5004 poly->style != TEXTBOT && poly->style != TEXTLEFT &&
5005 poly->style != TEXTRIGHT && poly->style != TEXTTOPLEFT &&
5006 poly->style != TEXTBOTLEFT && poly->style != TEXTTOPRIGHT &&
5007 poly->style != TEXTBOTRIGHT && poly->style != TEXTBOX) return(FALSE);
5008 }
5009 }
5010
5011 /* invisible: look for offset text */
5012 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
5013 {
5014 pp = pe->exportproto;
5015 if (TDGETXOFF(pp->textdescript) != 0 || TDGETYOFF(pp->textdescript) != 0)
5016 {
5017 lambda = lambdaofnode(ni);
5018 *x = (ni->lowx + ni->highx) / 2 + muldiv(TDGETXOFF(pp->textdescript), lambda, 4);
5019 *y = (ni->lowy + ni->highy) / 2 + muldiv(TDGETYOFF(pp->textdescript), lambda, 4);
5020 if (repair)
5021 {
5022 (void)startobjectchange((INTBIG)ni, VNODEINST);
5023 TDSETOFF(pp->textdescript, 0, 0);
5024 (void)setind((INTBIG)pp, VPORTPROTO, x_("textdescript"), 0, pp->textdescript[0]);
5025 (void)setind((INTBIG)pp, VPORTPROTO, x_("textdescript"), 1, pp->textdescript[1]);
5026 (void)endobjectchange((INTBIG)ni, VNODEINST);
5027 }
5028 return(TRUE);
5029 }
5030 }
5031 for(i=0; i<ni->numvar; i++)
5032 {
5033 var = &ni->firstvar[i];
5034 if ((var->type&VDISPLAY) != 0 &&
5035 (TDGETXOFF(var->textdescript) != 0 || TDGETYOFF(var->textdescript) != 0))
5036 {
5037 lambda = lambdaofnode(ni);
5038 *x = (ni->lowx + ni->highx) / 2 + muldiv(TDGETXOFF(var->textdescript), lambda, 4);
5039 *y = (ni->lowy + ni->highy) / 2 + muldiv(TDGETYOFF(var->textdescript), lambda, 4);
5040 if (repair)
5041 {
5042 (void)startobjectchange((INTBIG)ni, VNODEINST);
5043 TDSETOFF(var->textdescript, 0, 0);
5044 modifydescript((INTBIG)ni, VNODEINST, var, var->textdescript);
5045 (void)endobjectchange((INTBIG)ni, VNODEINST);
5046 }
5047 return(TRUE);
5048 }
5049 }
5050 return(FALSE);
5051 }
5052
5053 /*
5054 * routine to return the variable with "trace" information on nodeinst "ni".
5055 * Returns NOVARIABLE if there is no trace information
5056 */
gettrace(NODEINST * ni)5057 VARIABLE *gettrace(NODEINST *ni)
5058 {
5059 REGISTER VARIABLE *var;
5060
5061 /* now look for the variable */
5062 var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER|VISARRAY, el_trace_key);
5063 if (var == NOVARIABLE) return(NOVARIABLE);
5064
5065 /* return the trace variable */
5066 return(var);
5067 }
5068
5069 /*
5070 * routine to return the "grab point" of cell "np" and place it in the
5071 * reference integers (grabx, graby). The default is the lower-left corner
5072 */
grabpoint(NODEPROTO * np,INTBIG * grabx,INTBIG * graby)5073 void grabpoint(NODEPROTO *np, INTBIG *grabx, INTBIG *graby)
5074 {
5075 REGISTER VARIABLE *var;
5076
5077 *grabx = np->lowx;
5078 *graby = np->lowy;
5079 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
5080 if (var != NOVARIABLE)
5081 {
5082 *grabx = ((INTBIG *)var->addr)[0];
5083 *graby = ((INTBIG *)var->addr)[1];
5084 }
5085 }
5086
5087 /*
5088 * routine to determine the offset of the lower-left corner of nodeinst "ni"
5089 * (which may be NONODEINST), nodeproto "np" given that it is rotated "rot"
5090 * and transposed "trn". The offset from the actual corner to the effective
5091 * corner is placed in "x" and "y".
5092 */
corneroffset(NODEINST * ni,NODEPROTO * np,INTBIG rot,INTBIG trn,INTBIG * x,INTBIG * y,BOOLEAN centerbased)5093 void corneroffset(NODEINST *ni, NODEPROTO *np, INTBIG rot, INTBIG trn, INTBIG *x, INTBIG *y,
5094 BOOLEAN centerbased)
5095 {
5096 INTBIG lx, ly, hx, hy, tx, ty, bx, by, pxs, pys;
5097 XARRAY mat;
5098 REGISTER INTBIG px, py, cx, cy;
5099 REGISTER VARIABLE *var;
5100
5101 /* build transformation matrix */
5102 makeangle(rot, trn, mat);
5103
5104 /* see if there is a real grab-point */
5105 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
5106 if (var != NOVARIABLE)
5107 {
5108 /* use grab point if specified */
5109 cx = (np->lowx + np->highx) / 2;
5110 cy = (np->lowy + np->highy) / 2;
5111 px = np->lowx - cx; py = np->lowy - cy;
5112 xform(((INTBIG *)var->addr)[0]-cx, ((INTBIG *)var->addr)[1]-cy, &bx, &by, mat);
5113 } else
5114 {
5115 /* no grab point: find corner that is lowest and most to the left */
5116 if (ni == NONODEINST)
5117 {
5118 nodeprotosizeoffset(np, &lx, &ly, &hx, &hy, NONODEPROTO);
5119 if (np->primindex != 0)
5120 {
5121 defaultnodesize(np, &pxs, &pys);
5122 cx = cy = 0;
5123 px = -pxs/2; py = -pys/2;
5124 lx = lx - pxs/2; hx = pxs/2 - hx;
5125 ly = ly - pys/2; hy = pys/2 - hy;
5126 } else
5127 {
5128 cx = (np->lowx + np->highx) / 2;
5129 cy = (np->lowy + np->highy) / 2;
5130 px = np->lowx - cx; py = np->lowy - cy;
5131 lx = lx + np->lowx - cx; hx = np->highx - hx - cx;
5132 ly = ly + np->lowy - cy; hy = np->highy - hy - cy;
5133 }
5134 } else
5135 {
5136 nodesizeoffset(ni, &lx, &ly, &hx, &hy);
5137 cx = (ni->lowx + ni->highx) / 2;
5138 cy = (ni->lowy + ni->highy) / 2;
5139 px = ni->lowx - cx; py = ni->lowy - cy;
5140 lx = lx + ni->lowx - cx; hx = ni->highx - hx - cx;
5141 ly = ly + ni->lowy - cy; hy = ni->highy - hy - cy;
5142 }
5143 xform(lx, ly, &tx, &ty, mat);
5144 bx = tx; by = ty;
5145 xform(lx, hy, &tx, &ty, mat);
5146 if ((tx-bx) + (ty-by) < 0) { bx = tx; by = ty; }
5147 xform(hx, hy, &tx, &ty, mat);
5148 if ((tx-bx) + (ty-by) < 0) { bx = tx; by = ty; }
5149 xform(hx, ly, &tx, &ty, mat);
5150 if ((tx-bx) + (ty-by) < 0) { bx = tx; by = ty; }
5151 if (centerbased && np->primindex != 0)
5152 bx = by = 0;
5153 }
5154
5155 /* now compute offset between lower-left corner and this point */
5156 *x = bx - px; *y = by - py;
5157 }
5158
5159 #ifdef HAVE_QSORT
5160
5161 /*
5162 * Routine to sort "entries" objects in "data" that are "structsize" bytes large.
5163 * The routine "numericorder" is called with two elements and returns their ordering.
5164 */
esort(void * data,INTBIG entries,INTBIG structsize,int (* numericorder)(const void * e1,const void * e2))5165 void esort(void *data, INTBIG entries, INTBIG structsize,
5166 int (*numericorder)(const void *e1, const void *e2))
5167 {
5168 /* sort the data */
5169 qsort(data, entries, structsize, numericorder);
5170 }
5171
5172 #else /* for systems that don't have "qsort" */
5173 void db_sortquick(int start, int endv, int len, int structsize, void *data,
5174 int (*numericorder)(const void *e1, const void *e2));
5175
esort(void * data,INTBIG entries,INTBIG structsize,int (* numericorder)(const void * e1,const void * e2))5176 void esort(void *data, INTBIG entries, INTBIG structsize,
5177 int (*numericorder)(const void *e1, const void *e2))
5178 {
5179 db_sortquick(0, entries-1, entries-1, structsize, data, numericorder);
5180 }
5181
5182 /* Helper routine for "qsort" to order the list */
db_sortquick(int start,int endv,int len,int structsize,void * data,int (* numericorder)(const void * e1,const void * e2))5183 void db_sortquick(int start, int endv, int len, int structsize, void *data,
5184 int (*numericorder)(const void *e1, const void *e2))
5185 {
5186 REGISTER int endv1, i, j, inorder, mright, mleft;
5187 REGISTER UCHAR1 *d1, *d2, *dr, swap, *chrdata;
5188
5189 chrdata = (UCHAR1 *)data;
5190 if (endv-start > 9)
5191 {
5192 /* do a quicksort */
5193 mright = endv+1;
5194 mleft = start;
5195 dr = &chrdata[start*structsize];
5196 while (mleft < mright)
5197 {
5198 mleft = mleft+1;
5199 for(;;)
5200 {
5201 if (mleft >= len) break;
5202 d2 = &chrdata[mleft*structsize];
5203 if (numericorder(d2, dr) >= 0) break;
5204 mleft++;
5205 }
5206 mright--;
5207 for(;;)
5208 {
5209 if (mright <= 0) break;
5210 d2 = &chrdata[mright*structsize];
5211 if (numericorder(d2, dr) <= 0) break;
5212 mright--;
5213 }
5214 if (mleft < mright)
5215 {
5216 d1 = &chrdata[mleft*structsize];
5217 d2 = &chrdata[mright*structsize];
5218 for(j=0; j<structsize; j++)
5219 {
5220 swap = d1[j]; d1[j] = d2[j]; d2[j] = swap;
5221 }
5222 }
5223 }
5224 d1 = &chrdata[start*structsize];
5225 d2 = &chrdata[mright*structsize];
5226 for(j=0; j<structsize; j++)
5227 {
5228 swap = d1[j]; d1[j] = d2[j]; d2[j] = swap;
5229 }
5230 db_sortquick(start, mright-1, len, structsize, data, numericorder);
5231 db_sortquick(mleft, endv, len, structsize, data, numericorder);
5232 } else
5233 {
5234 /* do a bubble sort */
5235 inorder = 0;
5236 while (inorder == 0)
5237 {
5238 inorder = 1;
5239 endv1 = endv-1;
5240 for(i = start; i <= endv1; i++)
5241 {
5242 d1 = &chrdata[i*structsize];
5243 d2 = &chrdata[(i+1)*structsize];
5244 if (numericorder(d1, d2) <= 0) continue;
5245 for(j=0; j<structsize; j++)
5246 {
5247 swap = d1[j]; d1[j] = d2[j]; d2[j] = swap;
5248 }
5249 inorder = 0;
5250 }
5251 }
5252 }
5253 }
5254 #endif
5255
5256 /*
5257 * Helper routine for "esort" that makes big integers go in ascending order.
5258 */
sort_intbigascending(const void * e1,const void * e2)5259 int sort_intbigascending(const void *e1, const void *e2)
5260 {
5261 REGISTER INTBIG c1, c2;
5262
5263 c1 = *((INTBIG *)e1);
5264 c2 = *((INTBIG *)e2);
5265 return(c1 - c2);
5266 }
5267
5268 /*
5269 * Helper routine for "esort" that makes big integers go in ascending order.
5270 */
sort_intbigdescending(const void * e1,const void * e2)5271 int sort_intbigdescending(const void *e1, const void *e2)
5272 {
5273 REGISTER INTBIG c1, c2;
5274
5275 c1 = *((INTBIG *)e1);
5276 c2 = *((INTBIG *)e2);
5277 return(c2 - c1);
5278 }
5279
5280 /*
5281 * Helper routine for "esort" that makes strings go in ascending order.
5282 */
sort_stringascending(const void * e1,const void * e2)5283 int sort_stringascending(const void *e1, const void *e2)
5284 {
5285 REGISTER CHAR *c1, *c2;
5286
5287 c1 = *((CHAR **)e1);
5288 c2 = *((CHAR **)e2);
5289 return(namesame(c1, c2));
5290 }
5291
5292 /*
5293 * Helper routine for "esort" that makes cells go in ascending name order.
5294 */
sort_cellnameascending(const void * e1,const void * e2)5295 int sort_cellnameascending(const void *e1, const void *e2)
5296 {
5297 REGISTER NODEPROTO *c1, *c2;
5298
5299 c1 = *((NODEPROTO **)e1);
5300 c2 = *((NODEPROTO **)e2);
5301 return(namesame(nldescribenodeproto(c1), nldescribenodeproto(c2)));
5302 }
5303
5304 /*
5305 * Helper routine for "esort" that makes exports go in ascending name order.
5306 */
sort_exportnameascending(const void * e1,const void * e2)5307 int sort_exportnameascending(const void *e1, const void *e2)
5308 {
5309 REGISTER PORTPROTO *c1, *c2;
5310
5311 c1 = *((PORTPROTO **)e1);
5312 c2 = *((PORTPROTO **)e2);
5313 return(namesamenumeric(c1->protoname, c2->protoname));
5314 }
5315
5316 /*
5317 * Helper routine for "esort" that makes exports go in descending name order.
5318 */
sort_exportnamedescending(const void * e1,const void * e2)5319 int sort_exportnamedescending(const void *e1, const void *e2)
5320 {
5321 REGISTER PORTPROTO *c1, *c2;
5322
5323 c1 = *((PORTPROTO **)e1);
5324 c2 = *((PORTPROTO **)e2);
5325 return(namesamenumeric(c2->protoname, c1->protoname));
5326 }
5327
5328 /*
5329 * routine to initialize the database
5330 */
db_initdatabase(void)5331 void db_initdatabase(void)
5332 {
5333 REGISTER INTBIG x, y, i, j, k;
5334 INTBIG matc[2][2];
5335
5336 /* create interlocks */
5337 if (ensurevalidmutex(&db_polygonmutex, TRUE)) return;
5338 if (ensurevalidmutex(&db_primenumbermutex, TRUE)) return;
5339
5340 /* initialize change control */
5341 db_initializechanges();
5342
5343 /* miscellaneous initialization */
5344 db_windowpartfree = NOWINDOWPART;
5345 db_lasterror = DBNOERROR;
5346 el_curwindowpart = NOWINDOWPART;
5347 el_units = DISPUNITLAMBDA | INTUNITHNM;
5348 db_printerrors = TRUE;
5349 db_mrgdatainit();
5350
5351 /* setup disk file descriptors */
5352 el_filetypetext = setupfiletype(x_(""), x_("*.*"), MACFSTAG('TEXT'), FALSE, x_("text"), _("Text"));
5353
5354 /* prepare language translation */
5355 db_inittranslation();
5356
5357 /* transformation initialization */
5358 for(x=0; x<8; x++) for(y=0; y<8; y++)
5359 {
5360 for(i=0; i<2; i++) for(j=0; j<2; j++)
5361 for(k=0, matc[i][j]=0; k<2; k++)
5362 matc[i][j] += mult(db_matstyle[x][i][k], db_matstyle[y][k][j]);
5363 for(k=0; k<8; k++)
5364 {
5365 if (matc[0][0] != db_matstyle[k][0][0] ||
5366 matc[0][1] != db_matstyle[k][0][1] ||
5367 matc[1][0] != db_matstyle[k][1][0] ||
5368 matc[1][1] != db_matstyle[k][1][1]) continue;
5369 db_matmult[x][y] = k;
5370 break;
5371 }
5372 }
5373
5374 /* initialize variables */
5375 el_numnames = 0;
5376
5377 /* initialize globals that key to variables */
5378 el_node_name_key = makekey(x_("NODE_name"));
5379 el_arc_name_key = makekey(x_("ARC_name"));
5380 el_arc_radius_key = makekey(x_("ARC_radius"));
5381 el_trace_key = makekey(x_("trace"));
5382 el_cell_message_key = makekey(x_("FACET_message"));
5383 el_schematic_page_size_key = makekey(x_("FACET_schematic_page_size"));
5384 el_transistor_width_key = makekey(x_("transistor_width"));
5385 el_prototype_center_key = makekey(x_("prototype_center"));
5386 el_essential_bounds_key = makekey(x_("FACET_essentialbounds"));
5387 el_node_size_default_key = makekey(x_("NODE_size_default"));
5388 el_arc_width_default_key = makekey(x_("ARC_width_default"));
5389 el_attrkey_area = makekey(x_("ATTR_area"));
5390 el_attrkey_length = makekey(x_("ATTR_length"));
5391 el_attrkey_width = makekey(x_("ATTR_width"));
5392 el_attrkey_M = makekey(x_("ATTR_M"));
5393 el_techstate_key = makekey(x_("TECH_state"));
5394 db_tech_node_width_offset_key = makekey(x_("TECH_node_width_offset"));
5395 db_tech_layer_function_key = makekey(x_("TECH_layer_function"));
5396 db_tech_layer_names_key = makekey(x_("TECH_layer_names"));
5397 db_tech_arc_width_offset_key = makekey(x_("TECH_arc_width_offset"));
5398
5399 /* DRC keys need to be created early since they're used in "dbtech.c" */
5400 dr_max_distanceskey = makekey(x_("DRC_max_distances"));
5401 dr_wide_limitkey = makekey(x_("DRC_wide_limit"));
5402 dr_min_widthkey = makekey(x_("DRC_min_width"));
5403 dr_min_width_rulekey = makekey(x_("DRC_min_width_rule"));
5404 dr_min_node_sizekey = makekey(x_("DRC_min_node_size"));
5405 dr_min_node_size_rulekey = makekey(x_("DRC_min_node_size_rule"));
5406 dr_connected_distanceskey = makekey(x_("DRC_min_connected_distances"));
5407 dr_connected_distances_rulekey = makekey(x_("DRC_min_connected_distances_rule"));
5408 dr_unconnected_distanceskey = makekey(x_("DRC_min_unconnected_distances"));
5409 dr_unconnected_distances_rulekey = makekey(x_("DRC_min_unconnected_distances_rule"));
5410 dr_connected_distancesWkey = makekey(x_("DRC_min_connected_distances_wide"));
5411 dr_connected_distancesW_rulekey = makekey(x_("DRC_min_connected_distances_wide_rule"));
5412 dr_unconnected_distancesWkey = makekey(x_("DRC_min_unconnected_distances_wide"));
5413 dr_unconnected_distancesW_rulekey = makekey(x_("DRC_min_unconnected_distances_wide_rule"));
5414 dr_connected_distancesMkey = makekey(x_("DRC_min_connected_distances_multi"));
5415 dr_connected_distancesM_rulekey = makekey(x_("DRC_min_connected_distances_multi_rule"));
5416 dr_unconnected_distancesMkey = makekey(x_("DRC_min_unconnected_distances_multi"));
5417 dr_unconnected_distancesM_rulekey = makekey(x_("DRC_min_unconnected_distances_multi_rule"));
5418 dr_edge_distanceskey = makekey(x_("DRC_min_edge_distances"));
5419 dr_edge_distances_rulekey = makekey(x_("DRC_min_edge_distances_rule"));
5420 #ifdef SURROUNDRULES
5421 dr_surround_layer_pairskey = makekey(x_("DRC_surround_layer_pairs"));
5422 dr_surround_distanceskey = makekey(x_("DRC_surround_distances"));
5423 dr_surround_rulekey = makekey(x_("DRC_surround_rule"));
5424 #endif
5425
5426 /* create identity matrix */
5427 transid(el_matid);
5428
5429 /* initialize the views */
5430 el_views = NOVIEW;
5431 el_unknownview = db_makepermanentview(x_("unknown"), x_(""), 0);
5432 el_simsnapview = db_makepermanentview(x_("simulation-snapshot"), x_("sim"), 0);
5433 el_netlistnetlispview = db_makepermanentview(x_("netlist-netlisp-format"), x_("net-netlisp"), TEXTVIEW);
5434 el_netlistrsimview = db_makepermanentview(x_("netlist-rsim-format"), x_("net-rsim"), TEXTVIEW);
5435 el_netlistsilosview = db_makepermanentview(x_("netlist-silos-format"), x_("net-silos"), TEXTVIEW);
5436 el_netlistquiscview = db_makepermanentview(x_("netlist-quisc-format"), x_("net-quisc"), TEXTVIEW);
5437 el_netlistalsview = db_makepermanentview(x_("netlist-als-format"), x_("net-als"), TEXTVIEW);
5438 el_netlistview = db_makepermanentview(x_("netlist"), x_("net"), TEXTVIEW);
5439 el_vhdlview = db_makepermanentview(x_("VHDL"), x_("vhdl"), TEXTVIEW);
5440 el_verilogview = db_makepermanentview(x_("Verilog"), x_("ver"), TEXTVIEW);
5441 el_skeletonview = db_makepermanentview(x_("skeleton"), x_("sk"), 0);
5442 el_compview = db_makepermanentview(x_("compensated"), x_("comp"), 0);
5443 el_docview = db_makepermanentview(x_("documentation"), x_("doc"), TEXTVIEW);
5444 el_iconview = db_makepermanentview(x_("icon"), x_("ic"), 0);
5445 el_schematicview = db_makepermanentview(x_("schematic"), x_("sch"), 0);
5446 el_layoutview = db_makepermanentview(x_("layout"), x_("lay"), 0);
5447 }
5448
5449 /*
5450 * routine to build one of the permanent views by allocating it, giving it the full
5451 * name "fname" and abbreviation "sname", and including "state" in its "viewstate".
5452 */
db_makepermanentview(CHAR * fname,CHAR * sname,INTBIG state)5453 VIEW *db_makepermanentview(CHAR *fname, CHAR *sname, INTBIG state)
5454 {
5455 REGISTER VIEW *v;
5456
5457 /* create the view */
5458 v = allocview();
5459
5460 /* name it and assign state */
5461 (void)allocstring(&v->viewname, fname, db_cluster);
5462 (void)allocstring(&v->sviewname, sname, db_cluster);
5463 v->viewstate = state | PERMANENTVIEW;
5464
5465 /* link into the global list */
5466 v->nextview = el_views;
5467 el_views = v;
5468
5469 /* return the view */
5470 return(v);
5471 }
5472