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