1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: tecart.c
6  * Artwork technology description
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 "egraphics.h"
34 #include "tech.h"
35 #include "tecart.h"
36 #include "efunction.h"
37 #include <math.h>
38 
39 #define SPLINEGRAIN   20		/* number of line segments in each spline section */
40 
41 /* the options table */
42 static KEYWORD artopt[] =
43 {
44 	{x_("arrows-filled"),     0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
45 	{x_("arrows-outline"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
46 	TERMKEY
47 };
48 COMCOMP art_parse = {artopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
49 	0, x_(" \t"), M_("ARTWORK option"), M_("show current option")};
50 
51 typedef struct
52 {
53 	INTBIG col, bits;
54 	VARIABLE *colorvar, *patternvar;
55 } ARTPOLYLOOP;
56 
57 ARTPOLYLOOP art_oneprocpolyloop;
58 
59        TECHNOLOGY *art_tech;
60 static INTBIG      art_state;			/* state bits */
61        INTBIG      art_messagekey;		/* key for "ART_message" */
62        INTBIG      art_colorkey;		/* key for "ART_color" */
63        INTBIG      art_degreeskey;		/* key for "ART_degrees" */
64        INTBIG      art_patternkey;		/* key for "ART_pattern" */
65        NODEPROTO  *art_pinprim;
66        NODEPROTO  *art_openedpolygonprim;
67        NODEPROTO  *art_boxprim;
68        NODEPROTO  *art_crossedboxprim;
69        NODEPROTO  *art_filledboxprim;
70        NODEPROTO  *art_circleprim;
71        NODEPROTO  *art_thickcircleprim;
72        NODEPROTO  *art_filledcircleprim;
73        NODEPROTO  *art_splineprim;
74        NODEPROTO  *art_triangleprim;
75        NODEPROTO  *art_filledtriangleprim;
76        NODEPROTO  *art_arrowprim;
77        NODEPROTO  *art_openeddottedpolygonprim;
78        NODEPROTO  *art_openeddashedpolygonprim;
79        NODEPROTO  *art_openedthickerpolygonprim;
80        NODEPROTO  *art_closedpolygonprim;
81        NODEPROTO  *art_filledpolygonprim;
82        ARCPROTO   *art_solidarc;
83        ARCPROTO   *art_dottedarc;
84        ARCPROTO   *art_dashedarc;
85        ARCPROTO   *art_thickerarc;
86 
87 /* prototypes for local routines */
88 static void   art_getgraphics(INTBIG, INTBIG, ARTPOLYLOOP*);
89 static void   art_fillellipse(INTBIG, INTBIG, INTBIG, INTBIG, double, double, INTBIG, POLYGON*);
90 static void   art_fillspline(INTBIG *points, INTBIG count, INTBIG cx, INTBIG cy, POLYGON *poly, INTBIG steps);
91 static void   art_setstate(INTBIG newstate);
92 static void   art_fillnodebox(NODEINST *ni, INTBIG box, POLYGON *poly);
93 static INTBIG art_intnodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win, POLYLOOP *pl,
94 				ARTPOLYLOOP *artpl);
95 static void   art_intshapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly, POLYLOOP *pl, ARTPOLYLOOP *artpl);
96 static INTBIG art_intarcpolys(ARCINST *ai, WINDOWPART *win, POLYLOOP *pl, ARTPOLYLOOP *artpl);
97 static void   art_intshapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly, POLYLOOP *pl, ARTPOLYLOOP *artpl);
98 
99 /******************** LAYERS ********************/
100 
101 #define MAXLAYERS  1		/* total layers below */
102 #define LOPAQUE    0		/* solid graphics     */
103 
104 static GRAPHICS art_o_lay = {LAYERO, MENGLY, SOLIDC, SOLIDC,
105 /* graphics layer */		{0xFFFF,0xFFFF,0xFFFF,0xFFFF,
106 							0xFFFF,0xFFFF,0xFFFF,0xFFFF,
107 							0xFFFF,0xFFFF,0xFFFF,0xFFFF,
108 							0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
109 static GRAPHICS art_st_lay= {LAYERO, MENGLY, PATTERNED, PATTERNED,
110 							{0xFFFF,0xFFFF,0xFFFF,0xFFFF,
111 							0xFFFF,0xFFFF,0xFFFF,0xFFFF,
112 							0xFFFF,0xFFFF,0xFFFF,0xFFFF,
113 							0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
114 
115 /* these tables must be updated together */
116 GRAPHICS *art_layers[MAXLAYERS+1] = {&art_o_lay, NOGRAPHICS};
117 static CHAR *art_layer_names[MAXLAYERS] = {x_("Graphics")};
118 static CHAR *art_dxf_layers[MAXLAYERS] = {x_("OBJECT")};
119 static INTBIG art_layer_function[MAXLAYERS] = {LFART};
120 static CHAR *art_layer_letters[MAXLAYERS] = {x_("g")};
121 static CHAR *art_gds_layers[MAXLAYERS] = {x_("1")};
122 
123 /******************** ARCS ********************/
124 
125 #define ARCPROTOCOUNT  4
126 #define ASOLID         0
127 #define ADOTTED        1
128 #define ADASHED        2
129 #define ATHICKER       3
130 
131 /* solid arc */
132 static TECH_ARCLAY art_al_s[] = {{LOPAQUE, 0, FILLED}};
133 static TECH_ARCS art_a_s = {
134 	x_("Solid"),0,ASOLID,NOARCPROTO,								/* name */
135 	1,art_al_s,														/* layers */
136 	(APNONELEC<<AFUNCTIONSH)|CANWIPE|CANCURVE|(0<<AANGLEINCSH)};	/* userbits */
137 
138 /* dotted arc */
139 static TECH_ARCLAY art_al_d1[] = {{LOPAQUE, 0, FILLED}};
140 static TECH_ARCS art_a_d1 = {
141 	x_("Dotted"),0,ADOTTED,NOARCPROTO,								/* name */
142 	1,art_al_d1,													/* layers */
143 	(APNONELEC<<AFUNCTIONSH)|CANWIPE|CANCURVE|(0<<AANGLEINCSH)};	/* userbits */
144 
145 /* dashed arc */
146 static TECH_ARCLAY art_al_d2[] = {{LOPAQUE, 0, FILLED}};
147 static TECH_ARCS art_a_d2 = {
148 	x_("Dashed"),0,ADASHED,NOARCPROTO,								/* name */
149 	1,art_al_d2,													/* layers */
150 	(APNONELEC<<AFUNCTIONSH)|CANWIPE|CANCURVE|(0<<AANGLEINCSH)};	/* userbits */
151 
152 /* thicker arc */
153 static TECH_ARCLAY art_al_d3[] = {{LOPAQUE, 0, FILLED}};
154 static TECH_ARCS art_a_d3 = {
155 	x_("Thicker"),0,ATHICKER,NOARCPROTO,							/* name */
156 	1,art_al_d3,													/* layers */
157 	(APNONELEC<<AFUNCTIONSH)|CANWIPE|CANCURVE|(0<<AANGLEINCSH)};	/* userbits */
158 
159 TECH_ARCS *art_arcprotos[ARCPROTOCOUNT+1] = {&art_a_s, &art_a_d1,
160 	&art_a_d2, &art_a_d3, ((TECH_ARCS *)-1)};
161 
162 /******************** PORTINST CONNECTIONS ********************/
163 
164 /* these values are replaced with actual arcproto addresses */
165 static INTBIG art_pc_d[] = {-1, ASOLID, ADOTTED, ADASHED, ATHICKER, ALLGEN, -1};
166 
167 /******************** NODES ********************/
168 
169 #define NODEPROTOCOUNT 17
170 #define NPIN            1		/* point */
171 #define NBOX            2		/* rectangular box */
172 #define NCBOX           3		/* crossed rectangular box */
173 #define NFBOX           4		/* filled rectangular box */
174 #define NCIRCLE         5		/* circle */
175 #define NFCIRCLE        6		/* filled circle */
176 #define NSPLINE         7		/* spline curve */
177 #define NTRIANGLE       8		/* triangle */
178 #define NFTRIANGLE      9		/* filled triangle */
179 #define NARROW         10		/* arrow head */
180 #define NOPENED        11		/* opened solid polygon */
181 #define NOPENEDT1      12		/* opened dotted polygon */
182 #define NOPENEDT2      13		/* opened dashed polygon */
183 #define NOPENEDT3      14		/* opened thicker polygon */
184 #define NCLOSED        15		/* closed polygon */
185 #define NFILLED        16		/* filled polygon */
186 #define NTCIRCLE       17		/* thick circle */
187 
188 #define EI   (WHOLE/8)
189 static INTBIG art_fullbox[8]  = {LEFTEDGE, LEFTEDGE, RIGHTEDGE, TOPEDGE};
190 static INTBIG art_circ[8]     = {CENTER, CENTER,     RIGHTEDGE, CENTER};
191 static INTBIG art_opnd[16]    = {LEFTEDGE, BOTEDGE,  -EI,0,TOPEDGE,
192 								EI,0,BOTEDGE,       RIGHTEDGE,TOPEDGE};
193 static INTBIG art_clsd[16]    = {LEFTEDGE, CENTER,   CENTER,TOPEDGE,
194 								RIGHTEDGE, BOTEDGE, CENTER, BOTEDGE};
195 static INTBIG art_tri[12]     = {LEFTEDGE, BOTEDGE,  RIGHTEDGE, BOTEDGE,
196 								CENTER, TOPEDGE};
197 static INTBIG art_arr[12]     = {LEFTEDGE, TOPEDGE,  RIGHTEDGE, CENTER,
198 								LEFTEDGE, BOTEDGE};
199 static INTBIG art_arr1[12]    = {LEFTEDGE, TOPEDGE,  RIGHTEDGE, CENTER,
200 								CENTER, CENTER};
201 static INTBIG art_arr2[12]    = {LEFTEDGE, BOTEDGE,  RIGHTEDGE, CENTER,
202 								CENTER, CENTER};
203 
204 /* Pin */
205 static TECH_PORTS art_pin_p[] = {					/* ports */
206 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
207 		CENTER, CENTER, CENTER, CENTER}};
208 static TECH_POLYGON art_pin_l[] = {					/* layers */
209 	{LOPAQUE, -1, 2, DISC, POINTS, art_circ}};
210 static TECH_NODES art_pin = {
211 	x_("Pin"),NPIN,NONODEPROTO,						/* name */
212 	K1,K1,											/* size */
213 	1,art_pin_p,									/* ports */
214 	1,art_pin_l,									/* layers */
215 	(NPPIN<<NFUNCTIONSH)|ARCSWIPE,					/* userbits */
216 	0,0,0,0,0,0,0,0,0};								/* characteristics */
217 
218 /* Box */
219 static TECH_PORTS art_box_p[] = {					/* ports */
220 	{art_pc_d, x_("box"),    NOPORTPROTO, (180<<PORTANGLESH),
221 		LEFTEDGE, TOPEDGE, RIGHTEDGE, BOTEDGE}};
222 static TECH_POLYGON art_box_l[] = {					/* layers */
223 	{LOPAQUE, -1, 4, CLOSEDRECT, BOX, art_fullbox}};
224 static TECH_NODES art_box = {
225 	x_("Box"),NBOX,NONODEPROTO,						/* name */
226 	K6,K6,											/* size */
227 	1,art_box_p,									/* ports */
228 	1,art_box_l,									/* layers */
229 	(NPART<<NFUNCTIONSH)|NEDGESELECT,				/* userbits */
230 	0,0,0,0,0,0,0,0,0};								/* characteristics */
231 
232 /* Crossed Box */
233 static TECH_PORTS art_cbox_p[] = {					/* ports */
234 	{art_pc_d, x_("fbox"),    NOPORTPROTO, (180<<PORTANGLESH),
235 		LEFTEDGE, TOPEDGE, RIGHTEDGE, BOTEDGE}};
236 static TECH_POLYGON art_cbox_l[] = {				/* layers */
237 	{LOPAQUE, -1, 4, CROSSED, BOX, art_fullbox}};
238 static TECH_NODES art_cbox = {
239 	x_("Crossed-Box"),NCBOX,NONODEPROTO,			/* name */
240 	K6,K6,											/* size */
241 	1,art_cbox_p,									/* ports */
242 	1,art_cbox_l,									/* layers */
243 	(NPART<<NFUNCTIONSH),							/* userbits */
244 	0,0,0,0,0,0,0,0,0};								/* characteristics */
245 
246 /* Filled Box */
247 static TECH_PORTS art_fbox_p[] = {					/* ports */
248 	{art_pc_d, x_("fbox"),    NOPORTPROTO, (180<<PORTANGLESH),
249 		LEFTEDGE, TOPEDGE, RIGHTEDGE, BOTEDGE}};
250 static TECH_POLYGON art_fbox_l[] = {				/* layers */
251 	{LOPAQUE, -1, 4, FILLEDRECT, BOX, art_fullbox}};
252 static TECH_NODES art_fbox = {
253 	x_("Filled-Box"),NFBOX,NONODEPROTO,				/* name */
254 	K6,K6,											/* size */
255 	1,art_fbox_p,									/* ports */
256 	1,art_fbox_l,									/* layers */
257 	(NPART<<NFUNCTIONSH)|NEDGESELECT,				/* userbits */
258 	0,0,0,0,0,0,0,0,0};								/* characteristics */
259 
260 /* Circle (or Arc or Ellipse) */
261 static TECH_PORTS art_circle_p[] = {				/* ports */
262 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
263 		CENTER, CENTER, CENTER, CENTER}};
264 static TECH_POLYGON art_circle_l[] = {				/* layers */
265 	{LOPAQUE, -1, 2, CIRCLE, POINTS, art_circ}};
266 static TECH_NODES art_circle = {
267 	x_("Circle"),NCIRCLE,NONODEPROTO,				/* name */
268 	K6,K6,											/* size */
269 	1,art_circle_p,									/* ports */
270 	1,art_circle_l,									/* layers */
271 	(NPART<<NFUNCTIONSH)|NEDGESELECT,				/* userbits */
272 	0,0,0,0,0,0,0,0,0};								/* characteristics */
273 
274 /* Filled Circle */
275 static TECH_PORTS art_fcircle_p[] = {				/* ports */
276 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
277 		CENTER, CENTER, CENTER, CENTER}};
278 static TECH_POLYGON art_fcircle_l[] = {				/* layers */
279 	{LOPAQUE, -1, 2, DISC, POINTS, art_circ}};
280 static TECH_NODES art_fcircle = {
281 	x_("Filled-Circle"),NFCIRCLE,NONODEPROTO,		/* name */
282 	K6,K6,											/* size */
283 	1,art_fcircle_p,								/* ports */
284 	1,art_fcircle_l,								/* layers */
285 	(NPART<<NFUNCTIONSH)|NSQUARE|NEDGESELECT,		/* userbits */
286 	0,0,0,0,0,0,0,0,0};								/* characteristics */
287 
288 /* Spline Curve */
289 static TECH_PORTS art_spline_p[] = {				/* ports */
290 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
291 		CENTER, CENTER, CENTER, CENTER}};
292 static TECH_POLYGON art_spline_l[] = {				/* layers */
293 	{LOPAQUE, -1, 4, OPENED, POINTS, art_opnd}};
294 static TECH_NODES art_spline = {
295 	x_("Spline"),NSPLINE,NONODEPROTO,				/* name */
296 	K6,K6,											/* size */
297 	1,art_spline_p,									/* ports */
298 	1,art_spline_l,									/* layers */
299 	(NPART<<NFUNCTIONSH)|HOLDSTRACE|NEDGESELECT,	/* userbits */
300 	0,0,0,0,0,0,0,0,0};								/* characteristics */
301 
302 /* Triangle */
303 static TECH_PORTS art_triangle_p[] = {				/* ports */
304 	{art_pc_d, x_("triangle"),    NOPORTPROTO, (180<<PORTANGLESH),
305 		LEFTEDGE, TOPEDGE, RIGHTEDGE, BOTEDGE}};
306 static TECH_POLYGON art_triangle_l[] = {			/* layers */
307 	{LOPAQUE, -1, 3, CLOSED, POINTS, art_tri}};
308 static TECH_NODES art_triangle = {
309 	x_("Triangle"),NTRIANGLE,NONODEPROTO,			/* name */
310 	K6,K6,											/* size */
311 	1,art_triangle_p,								/* ports */
312 	1,art_triangle_l,								/* layers */
313 	(NPART<<NFUNCTIONSH)|NEDGESELECT,				/* userbits */
314 	0,0,0,0,0,0,0,0,0};								/* characteristics */
315 
316 /* Filled Triangle */
317 static TECH_PORTS art_ftriangle_p[] = {				/* ports */
318 	{art_pc_d, x_("ftriangle"),    NOPORTPROTO, (180<<PORTANGLESH),
319 		LEFTEDGE, TOPEDGE, RIGHTEDGE, BOTEDGE}};
320 static TECH_POLYGON art_ftriangle_l[] = {			/* layers */
321 	{LOPAQUE, -1, 3, FILLED, POINTS, art_tri}};
322 static TECH_NODES art_ftriangle = {
323 	x_("Filled-Triangle"),NFTRIANGLE,NONODEPROTO,	/* name */
324 	K6,K6,											/* size */
325 	1,art_ftriangle_p,								/* ports */
326 	1,art_ftriangle_l,								/* layers */
327 	(NPART<<NFUNCTIONSH)|NEDGESELECT,				/* userbits */
328 	0,0,0,0,0,0,0,0,0};								/* characteristics */
329 
330 /* Arrow Head */
331 static TECH_PORTS art_arrow_p[] = {					/* ports */
332 	{art_pc_d, x_("arrow"), NOPORTPROTO, (180<<PORTARANGESH),
333 		 RIGHTEDGE, CENTER, RIGHTEDGE, CENTER}};
334 static TECH_POLYGON art_arrow_l[] = {				/* layers */
335 	{LOPAQUE, -1, 3, OPENED, POINTS, art_arr},
336 	{LOPAQUE, -1, 3, FILLED, POINTS, art_arr2}};
337 static TECH_NODES art_arrow = {
338 	x_("Arrow"),NARROW,NONODEPROTO,					/* name */
339 	K2,K2,											/* size */
340 	1,art_arrow_p,									/* ports */
341 	1,art_arrow_l,									/* layers */
342 	(NPART<<NFUNCTIONSH)|NEDGESELECT,				/* userbits */
343 	0,0,0,0,0,0,0,0,0};								/* characteristics */
344 
345 /* Opened Solid Polygon */
346 static TECH_PORTS art_freeform_p[] = {				/* ports */
347 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
348 		CENTER, CENTER, CENTER, CENTER}};
349 static TECH_POLYGON art_freeform_l[] = {			/* layers */
350 	{LOPAQUE, -1, 4, OPENED, POINTS, art_opnd}};
351 static TECH_NODES art_freeform = {
352 	x_("Opened-Polygon"),NOPENED,NONODEPROTO,		/* name */
353 	K6,K6,											/* size */
354 	1,art_freeform_p,								/* ports */
355 	1,art_freeform_l,								/* layers */
356 	(NPART<<NFUNCTIONSH)|HOLDSTRACE|NEDGESELECT,	/* userbits */
357 	0,0,0,0,0,0,0,0,0};								/* characteristics */
358 
359 /* Opened Dotted Polygon */
360 static TECH_PORTS art_freeformdot_p[] = {			/* ports */
361 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
362 		CENTER, CENTER, CENTER, CENTER}};
363 static TECH_POLYGON art_freeformdot_l[] = {			/* layers */
364 	{LOPAQUE, -1, 4, OPENEDT1, POINTS, art_opnd}};
365 static TECH_NODES art_freeformdot = {
366 	x_("Opened-Dotted-Polygon"),NOPENEDT1,NONODEPROTO,	/* name */
367 	K6,K6,											/* size */
368 	1,art_freeformdot_p,							/* ports */
369 	1,art_freeformdot_l,							/* layers */
370 	(NPART<<NFUNCTIONSH)|HOLDSTRACE|NEDGESELECT,	/* userbits */
371 	0,0,0,0,0,0,0,0,0};								/* characteristics */
372 
373 /* Opened Dashed Polygon */
374 static TECH_PORTS art_freeformdash_p[] = {			/* ports */
375 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
376 		CENTER, CENTER, CENTER, CENTER}};
377 static TECH_POLYGON art_freeformdash_l[] = {		/* layers */
378 	{LOPAQUE, -1, 4, OPENEDT2, POINTS, art_opnd}};
379 static TECH_NODES art_freeformdash = {
380 	x_("Opened-Dashed-Polygon"),NOPENEDT2,NONODEPROTO,	/* name */
381 	K6,K6,											/* size */
382 	1,art_freeformdash_p,							/* ports */
383 	1,art_freeformdash_l,							/* layers */
384 	(NPART<<NFUNCTIONSH)|HOLDSTRACE|NEDGESELECT,	/* userbits */
385 	0,0,0,0,0,0,0,0,0};								/* characteristics */
386 
387 /* Opened Thicker Polygon */
388 static TECH_PORTS art_freeformfdot_p[] = {			/* ports */
389 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
390 		CENTER, CENTER, CENTER, CENTER}};
391 static TECH_POLYGON art_freeformfdot_l[] = {		/* layers */
392 	{LOPAQUE, -1, 4, OPENEDT3, POINTS, art_opnd}};
393 static TECH_NODES art_freeformfdot = {
394 	x_("Opened-Thicker-Polygon"),NOPENEDT3,NONODEPROTO,	/* name */
395 	K6,K6,											/* size */
396 	1,art_freeformfdot_p,							/* ports */
397 	1,art_freeformfdot_l,							/* layers */
398 	(NPART<<NFUNCTIONSH)|HOLDSTRACE|NEDGESELECT,	/* userbits */
399 	0,0,0,0,0,0,0,0,0};								/* characteristics */
400 
401 /* Closed Polygon */
402 static TECH_PORTS art_closed_p[] = {				/* ports */
403 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
404 		CENTER, CENTER, CENTER, CENTER}};
405 static TECH_POLYGON art_closed_l[] = {				/* layers */
406 	{LOPAQUE, -1, 4, CLOSED, POINTS, art_clsd}};
407 static TECH_NODES art_closed = {
408 	x_("Closed-Polygon"),NCLOSED,NONODEPROTO,		/* name */
409 	K6,K6,											/* size */
410 	1,art_closed_p,									/* ports */
411 	1,art_closed_l,									/* layers */
412 	(NPART<<NFUNCTIONSH)|HOLDSTRACE|NEDGESELECT,	/* userbits */
413 	0,0,0,0,0,0,0,0,0};								/* characteristics */
414 
415 /* Filled Polygon */
416 static TECH_PORTS art_polygon_p[] = {				/* ports */
417 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
418 		CENTER, CENTER, CENTER, CENTER}};
419 static TECH_POLYGON art_polygon_l[] = {				/* layers */
420 	{LOPAQUE, -1, 4, FILLED, POINTS, art_clsd}};
421 static TECH_NODES art_polygon = {
422 	x_("Filled-Polygon"),NFILLED,NONODEPROTO,		/* name */
423 	K6,K6,											/* size */
424 	1,art_polygon_p,								/* ports */
425 	1,art_polygon_l,								/* layers */
426 	(NPART<<NFUNCTIONSH)|HOLDSTRACE|NEDGESELECT,	/* userbits */
427 	0,0,0,0,0,0,0,0,0};								/* characteristics */
428 
429 /* Thick Circle (or Arc or Ellipse) */
430 static TECH_PORTS art_tcircle_p[] = {				/* ports */
431 	{art_pc_d, x_("site"), NOPORTPROTO, (180<<PORTARANGESH),
432 		CENTER, CENTER, CENTER, CENTER}};
433 static TECH_POLYGON art_tcircle_l[] = {				/* layers */
434 	{LOPAQUE, -1, 2, THICKCIRCLE, POINTS, art_circ}};
435 static TECH_NODES art_tcircle = {
436 	x_("Thick-Circle"),NTCIRCLE,NONODEPROTO,		/* name */
437 	K6,K6,											/* size */
438 	1,art_tcircle_p,								/* ports */
439 	1,art_tcircle_l,								/* layers */
440 	(NPART<<NFUNCTIONSH)|NEDGESELECT,				/* userbits */
441 	0,0,0,0,0,0,0,0,0};								/* characteristics */
442 
443 TECH_NODES *art_nodeprotos[NODEPROTOCOUNT+1] = {&art_pin,
444 	&art_box, &art_cbox, &art_fbox, &art_circle, &art_fcircle, &art_spline,
445 	&art_triangle, &art_ftriangle, &art_arrow, &art_freeform, &art_freeformdot,
446 	&art_freeformdash, &art_freeformfdot, &art_closed, &art_polygon, &art_tcircle,
447 	((TECH_NODES *)-1)};
448 
449 /******************** VARIABLE AGGREGATION ********************/
450 
451 TECH_VARIABLES art_variables[] =
452 {
453 	/* set general information about the technology */
454 	{x_("TECH_layer_names"), (CHAR *)art_layer_names, 0.0,
455 		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
456 	{x_("TECH_layer_function"), (CHAR *)art_layer_function, 0.0,
457 		VINTEGER|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
458 
459 	/* set information for the USER tool */
460 	{x_("USER_layer_letters"), (CHAR *)art_layer_letters, 0.0,
461 		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
462 
463 	/* set information for the IO tool */
464 	{x_("IO_dxf_layer_names"), (CHAR *)art_dxf_layers, 0.0,
465 		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
466 	{x_("IO_gds_layer_numbers"), (CHAR *)art_gds_layers, 0.0,
467 		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
468 	{NULL, NULL, 0.0, 0}
469 };
470 
471 /******************** ROUTINES ********************/
472 
art_initprocess(TECHNOLOGY * tech,INTBIG pass)473 BOOLEAN art_initprocess(TECHNOLOGY *tech, INTBIG pass)
474 {
475 	if (pass == 0)
476 	{
477 		/* initialize the technology variable */
478 		art_tech = tech;
479 	} else if (pass == 1)
480 	{
481 		art_pinprim = getnodeproto(x_("artwork:Pin"));
482 		art_boxprim = getnodeproto(x_("artwork:Box"));
483 		art_crossedboxprim = getnodeproto(x_("artwork:Crossed-Box"));
484 		art_filledboxprim = getnodeproto(x_("artwork:Filled-Box"));
485 		art_circleprim = getnodeproto(x_("artwork:Circle"));
486 		art_thickcircleprim = getnodeproto(x_("artwork:Thick-Circle"));
487 		art_filledcircleprim = getnodeproto(x_("artwork:Filled-Circle"));
488 		art_splineprim = getnodeproto(x_("artwork:Spline"));
489 		art_triangleprim = getnodeproto(x_("artwork:Triangle"));
490 		art_filledtriangleprim = getnodeproto(x_("artwork:Filled-Triangle"));
491 		art_arrowprim = getnodeproto(x_("artwork:Arrow"));
492 		art_openedpolygonprim = getnodeproto(x_("artwork:Opened-Polygon"));
493 		art_openeddottedpolygonprim = getnodeproto(x_("artwork:Opened-Dotted-Polygon"));
494 		art_openeddashedpolygonprim = getnodeproto(x_("artwork:Opened-Dashed-Polygon"));
495 		art_openedthickerpolygonprim = getnodeproto(x_("artwork:Opened-Thicker-Polygon"));
496 		art_closedpolygonprim = getnodeproto(x_("artwork:Closed-Polygon"));
497 		art_filledpolygonprim = getnodeproto(x_("artwork:Filled-Polygon"));
498 
499 		art_solidarc = getarcproto(x_("Artwork:Solid"));
500 		art_dottedarc = getarcproto(x_("Artwork:Dotted"));
501 		art_dashedarc = getarcproto(x_("Artwork:Dashed"));
502 		art_thickerarc = getarcproto(x_("Artwork:Thicker"));
503 
504 		art_messagekey = makekey(x_("ART_message"));
505 		art_colorkey = makekey(x_("ART_color"));
506 		art_degreeskey = makekey(x_("ART_degrees"));
507 		art_patternkey = makekey(x_("ART_pattern"));
508 		art_state = 0;
509 		nextchangequiet();
510 		setvalkey((INTBIG)art_tech, VTECHNOLOGY, el_techstate_key, art_state,
511 			VINTEGER|VDONTSAVE);
512 	}
513 	return(FALSE);
514 }
515 
art_setmode(INTBIG count,CHAR * par[])516 void art_setmode(INTBIG count, CHAR *par[])
517 {
518 	REGISTER INTBIG l;
519 	REGISTER CHAR *pp;
520 
521 	if (count == 0)
522 	{
523 		if (art_arrow.layercount == 2)
524 			ttyputmsg(M_("Artwork arrow heads are filled")); else
525 				ttyputmsg(M_("Artwork arrow heads are outlines"));
526 		return;
527 	}
528 
529 	l = estrlen(pp = par[0]);
530 	if (namesamen(pp, x_("arrows-filled"), l) == 0)
531 	{
532 		/* set the arrow heads to be fancy */
533 		art_setstate(art_state | ARTWORKFILLARROWHEADS);
534 		ttyputverbose(M_("Artwork arrow heads will be filled"));
535 		return;
536 	}
537 	if (namesamen(pp, x_("arrows-outline"), l) == 0)
538 	{
539 		/* set the arrow heads to be simple */
540 		art_setstate(art_state & ~ARTWORKFILLARROWHEADS);
541 		ttyputverbose(M_("Artwork arrow heads will be outline"));
542 		return;
543 	}
544 	ttyputbadusage(x_("technology tell artwork"));
545 }
546 
art_request(CHAR * command,va_list ap)547 INTBIG art_request(CHAR *command, va_list ap)
548 {
549 	if (namesame(command, x_("has-state")) == 0) return(1);
550 	if (namesame(command, x_("get-state")) == 0)
551 	{
552 		return(art_state);
553 	}
554 	if (namesame(command, x_("set-state")) == 0)
555 	{
556 		art_setstate(va_arg(ap, INTBIG));
557 		return(0);
558 	}
559 	return(0);
560 }
561 
art_setstate(INTBIG newstate)562 void art_setstate(INTBIG newstate)
563 {
564 	art_state = newstate;
565 
566 	if ((art_state&ARTWORKFILLARROWHEADS) != 0)
567 	{
568 		/* set filled arrow heads */
569 		art_arrow.layercount = 2;
570 		art_arrow_l[0].style = FILLED;
571 		art_arrow_l[0].points = art_arr1;
572 	} else
573 	{
574 		/* set outline arrow heads */
575 		art_arrow.layercount = 1;
576 		art_arrow_l[0].style = OPENED;
577 		art_arrow_l[0].points = art_arr;
578 	}
579 }
580 
art_nodepolys(NODEINST * ni,INTBIG * reasonable,WINDOWPART * win)581 INTBIG art_nodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
582 {
583 	return(art_intnodepolys(ni, reasonable, win, &tech_oneprocpolyloop, &art_oneprocpolyloop));
584 }
585 
art_intnodepolys(NODEINST * ni,INTBIG * reasonable,WINDOWPART * win,POLYLOOP * pl,ARTPOLYLOOP * artpl)586 INTBIG art_intnodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win, POLYLOOP *pl,
587 	ARTPOLYLOOP *artpl)
588 {
589 	REGISTER INTBIG pindex, count;
590 	Q_UNUSED( win );
591 
592 	pindex = ni->proto->primindex;
593 
594 	art_getgraphics((INTBIG)ni, VNODEINST, artpl);
595 
596 	/* default count of polygons in the node */
597 	count = art_nodeprotos[pindex-1]->layercount;
598 
599 	/* zero the count if this node is not to be displayed */
600 	if ((ni->userbits&WIPED) != 0) count = 0;
601 
602 	/* add in displayable variables */
603 	pl->realpolys = count;
604 	count += tech_displayablenvars(ni, pl->curwindowpart, pl);
605 	if (reasonable != 0) *reasonable = count;
606 	return(count);
607 }
608 
art_shapenodepoly(NODEINST * ni,INTBIG box,POLYGON * poly)609 void art_shapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
610 {
611 	art_intshapenodepoly(ni, box, poly, &tech_oneprocpolyloop, &art_oneprocpolyloop);
612 }
613 
art_intshapenodepoly(NODEINST * ni,INTBIG box,POLYGON * poly,POLYLOOP * pl,ARTPOLYLOOP * artpl)614 void art_intshapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly, POLYLOOP *pl, ARTPOLYLOOP *artpl)
615 {
616 	/* handle displayable variables */
617 	if (box >= pl->realpolys)
618 	{
619 		(void)tech_filldisplayablenvar(ni, poly, pl->curwindowpart, 0, pl);
620 		return;
621 	}
622 
623 	art_fillnodebox(ni, box, poly);
624 
625 	/* use stipple pattern if specified */
626 	if (artpl->patternvar == NOVARIABLE) poly->desc = &art_o_lay; else
627 		poly->desc = &art_st_lay;
628 
629 	poly->desc->col = artpl->col;
630 	poly->desc->bits = artpl->bits;
631 }
632 
art_allnodepolys(NODEINST * ni,POLYLIST * plist,WINDOWPART * win,BOOLEAN onlyreasonable)633 INTBIG art_allnodepolys(NODEINST *ni, POLYLIST *plist, WINDOWPART *win, BOOLEAN onlyreasonable)
634 {
635 	REGISTER INTBIG tot, j;
636 	INTBIG reasonable;
637 	REGISTER NODEPROTO *np;
638 	REGISTER POLYGON *poly;
639 	POLYLOOP mypl;
640 	ARTPOLYLOOP myartpl;
641 
642 	np = ni->proto;
643 	mypl.curwindowpart = win;
644 	tot = art_intnodepolys(ni, &reasonable, win, &mypl, &myartpl);
645 	if (onlyreasonable) tot = reasonable;
646 	if (mypl.realpolys < tot) tot = mypl.realpolys;
647 	if (ensurepolylist(plist, tot, db_cluster)) return(-1);
648 	for(j = 0; j < tot; j++)
649 	{
650 		poly = plist->polygons[j];
651 		poly->tech = art_tech;
652 		art_intshapenodepoly(ni, j, poly, &mypl, &myartpl);
653 	}
654 	return(tot);
655 }
656 
art_nodeEpolys(NODEINST * ni,INTBIG * reasonable,WINDOWPART * win)657 INTBIG art_nodeEpolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
658 {
659 	Q_UNUSED( ni );
660 	Q_UNUSED( win );
661 
662 	if (reasonable != 0) *reasonable = 0;
663 	return(0);
664 }
665 
art_shapeEnodepoly(NODEINST * ni,INTBIG box,POLYGON * poly)666 void art_shapeEnodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
667 {
668 	Q_UNUSED( ni );
669 	Q_UNUSED( box );
670 	Q_UNUSED( poly );
671 }
672 
art_allnodeEpolys(NODEINST * ni,POLYLIST * plist,WINDOWPART * win,BOOLEAN onlyreasonable)673 INTBIG art_allnodeEpolys(NODEINST *ni, POLYLIST *plist, WINDOWPART *win, BOOLEAN onlyreasonable)
674 {
675 	Q_UNUSED( ni );
676 	Q_UNUSED( plist );
677 	Q_UNUSED( win );
678 	Q_UNUSED( onlyreasonable );
679 	return(0);
680 }
681 
art_shapeportpoly(NODEINST * ni,PORTPROTO * pp,POLYGON * poly,XARRAY trans,BOOLEAN purpose)682 void art_shapeportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, XARRAY trans,
683 	BOOLEAN purpose)
684 {
685 	REGISTER INTBIG pindex;
686 	Q_UNUSED( purpose );
687 
688 	pindex = ni->proto->primindex;
689 	if (pindex == NPIN || pindex == NARROW)
690 	{
691 		tech_fillportpoly(ni, pp, poly, trans, art_nodeprotos[pindex-1], CLOSED, lambdaofnode(ni));
692 		return;
693 	}
694 
695 	/* just use first graphic polygon as the port */
696 	art_fillnodebox(ni, 0, poly);
697 	xformpoly(poly, trans);
698 }
699 
art_arcpolys(ARCINST * ai,WINDOWPART * win)700 INTBIG art_arcpolys(ARCINST *ai, WINDOWPART *win)
701 {
702 	return(art_intarcpolys(ai, win, &tech_oneprocpolyloop, &art_oneprocpolyloop));
703 }
704 
art_intarcpolys(ARCINST * ai,WINDOWPART * win,POLYLOOP * pl,ARTPOLYLOOP * artpl)705 INTBIG art_intarcpolys(ARCINST *ai, WINDOWPART *win, POLYLOOP *pl, ARTPOLYLOOP *artpl)
706 {
707 	REGISTER INTBIG def;
708 
709 	art_getgraphics((INTBIG)ai, VARCINST, artpl);
710 
711 	def = tech_initcurvedarc(ai, art_arcprotos[ai->proto->arcindex]->laycount, pl);
712 
713 	/* add in displayable variables */
714 	pl->realpolys = def;
715 	def += tech_displayableavars(ai, win, pl);
716 	return(def);
717 }
718 
art_shapearcpoly(ARCINST * ai,INTBIG box,POLYGON * poly)719 void art_shapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly)
720 {
721 	art_intshapearcpoly(ai, box, poly, &tech_oneprocpolyloop, &art_oneprocpolyloop);
722 }
723 
art_intshapearcpoly(ARCINST * ai,INTBIG box,POLYGON * poly,POLYLOOP * pl,ARTPOLYLOOP * artpl)724 void art_intshapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly, POLYLOOP *pl, ARTPOLYLOOP *artpl)
725 {
726 	REGISTER INTBIG aindex;
727 	REGISTER INTBIG realwid;
728 	REGISTER TECH_ARCLAY *thista;
729 
730 	/* handle displayable variables */
731 	if (box >= pl->realpolys)
732 	{
733 		(void)tech_filldisplayableavar(ai, poly, pl->curwindowpart, 0, pl);
734 		return;
735 	}
736 
737 	/* handle curved arcs */
738 	aindex = ai->proto->arcindex;
739 	thista = &art_arcprotos[aindex]->list[0];
740 	realwid = ai->width - thista->off*lambdaofarc(ai)/WHOLE;
741 	if (tech_curvedarcpiece(ai, box, poly, art_arcprotos, pl))
742 	{
743 		/* standard arc: compute polygon in normal way */
744 		makearcpoly(ai->length, realwid, ai, poly, thista->style);
745 		poly->layer = thista->lay;
746 	}
747 
748 	/* use stipple pattern if specified */
749 	if (artpl->patternvar == NOVARIABLE)
750 	{
751 		poly->desc = &art_o_lay;
752 		if (realwid == 0 && poly->style != CIRCLEARC) switch (ai->proto->arcindex)
753 		{
754 			case ADOTTED:  poly->style = OPENEDT1;   break;
755 			case ADASHED:  poly->style = OPENEDT2;   break;
756 			case ATHICKER: poly->style = OPENEDT3;   break;
757 		}
758 	} else poly->desc = &art_st_lay;
759 
760 	poly->desc->col = artpl->col;
761 	poly->desc->bits = artpl->bits;
762 }
763 
art_allarcpolys(ARCINST * ai,POLYLIST * plist,WINDOWPART * win)764 INTBIG art_allarcpolys(ARCINST *ai, POLYLIST *plist, WINDOWPART *win)
765 {
766 	REGISTER INTBIG tot, j;
767 	POLYLOOP mypl;
768 	ARTPOLYLOOP myartpl;
769 
770 	mypl.curwindowpart = win;
771 	tot = art_intarcpolys(ai, win, &mypl, &myartpl);
772 	if (ensurepolylist(plist, tot, db_cluster)) return(-1);
773 	for(j = 0; j < tot; j++)
774 	{
775 		art_intshapearcpoly(ai, j, plist->polygons[j], &mypl, &myartpl);
776 	}
777 	return(tot);
778 }
779 
780 /*
781  * Helper routine to fill in polygon "box" of node "ni" into polygon "poly".
782  */
art_fillnodebox(NODEINST * ni,INTBIG box,POLYGON * poly)783 void art_fillnodebox(NODEINST *ni, INTBIG box, POLYGON *poly)
784 {
785 	REGISTER INTBIG sty;
786 	REGISTER INTBIG pindex, dist, cx, cy, sx, sy, count;
787 	REGISTER VARIABLE *var;
788 	double startoffset, endangle;
789 	INTBIG dummypoints[8];
790 
791 	pindex = ni->proto->primindex;
792 	if (pindex == NCIRCLE || pindex == NTCIRCLE)
793 	{
794 		/* handle ellipses */
795 		getarcdegrees(ni, &startoffset, &endangle);
796 		if (ni->highx - ni->lowx != ni->highy - ni->lowy)
797 		{
798 			art_fillellipse(ni->lowx, ni->lowy, ni->highx, ni->highy, startoffset, endangle, pindex, poly);
799 			poly->layer = art_nodeprotos[pindex-1]->layerlist[box].layernum;
800 		} else
801 		{
802 			tech_fillpoly(poly, &art_nodeprotos[pindex-1]->layerlist[box], ni,
803 				lambdaofnode(ni), FILLED);
804 
805 			/* if there is arc information here, make it an arc of a circle */
806 			if (startoffset != 0.0 || endangle != 0.0)
807 			{
808 				/* fill an arc of a circle here */
809 				if (poly->limit < 3) (void)extendpolygon(poly, 3);
810 				dist = poly->xv[1] - poly->xv[0];
811 				poly->xv[2] = poly->xv[0] + rounddouble(cos(startoffset) * (double)dist);
812 				poly->yv[2] = poly->yv[0] + rounddouble(sin(startoffset) * (double)dist);
813 				poly->xv[1] = poly->xv[0] + rounddouble(cos(startoffset+endangle) * (double)dist);
814 				poly->yv[1] = poly->yv[0] + rounddouble(sin(startoffset+endangle) * (double)dist);
815 				poly->count = 3;
816 				if (pindex == NCIRCLE) poly->style = CIRCLEARC; else
817 					poly->style = THICKCIRCLEARC;
818 			}
819 		}
820 	} else if (pindex == NSPLINE)
821 	{
822 		poly->layer = art_nodeprotos[pindex-1]->layerlist[box].layernum;
823 		cx = (ni->highx + ni->lowx) / 2;   cy = (ni->highy + ni->lowy) / 2;
824 		var = gettrace(ni);
825 		if (var != NOVARIABLE)
826 		{
827 			count = getlength(var) / 2;
828 			art_fillspline((INTBIG *)var->addr, count, cx, cy, poly, SPLINEGRAIN);
829 		} else
830 		{
831 			sx = ni->highx - ni->lowx;   sy = ni->highy - ni->lowy;
832 			dummypoints[0] = -sx / 2;   dummypoints[1] = -sy / 2;
833 			dummypoints[2] = -sx / 8;   dummypoints[3] =  sy / 2;
834 			dummypoints[4] =  sx / 8;   dummypoints[5] = -sy / 2;
835 			dummypoints[6] =  sx / 2;   dummypoints[7] =  sy / 2;
836 			art_fillspline(dummypoints, 4, cx, cy, poly, SPLINEGRAIN);
837 		}
838 	} else
839 	{
840 		switch (pindex)
841 		{
842 			case NOPENED:   sty = OPENED;    break;
843 			case NOPENEDT1: sty = OPENEDT1;  break;
844 			case NOPENEDT2: sty = OPENEDT2;  break;
845 			case NOPENEDT3: sty = OPENEDT3;  break;
846 			case NCLOSED:   sty = CLOSED;    break;
847 			default:        sty = FILLED;    break;
848 		}
849 
850 		tech_fillpoly(poly, &art_nodeprotos[pindex-1]->layerlist[box], ni,
851 			lambdaofnode(ni), sty);
852 	}
853 }
854 
art_getgraphics(INTBIG addr,INTBIG type,ARTPOLYLOOP * artpl)855 void art_getgraphics(INTBIG addr, INTBIG type, ARTPOLYLOOP *artpl)
856 {
857 	REGISTER INTBIG i, sty, len;
858 
859 	/* get the color information */
860 	artpl->colorvar = getvalkey(addr, type, VINTEGER, art_colorkey);
861 	if (artpl->colorvar == NOVARIABLE)
862 	{
863 		artpl->col = BLACK;
864 		artpl->bits = LAYERO;
865 	} else
866 	{
867 		switch (artpl->colorvar->addr)
868 		{
869 			case LAYERT1: artpl->col = COLORT1;  artpl->bits = LAYERT1;  break;
870 			case LAYERT2: artpl->col = COLORT2;  artpl->bits = LAYERT2;  break;
871 			case LAYERT3: artpl->col = COLORT3;  artpl->bits = LAYERT3;  break;
872 			case LAYERT4: artpl->col = COLORT4;  artpl->bits = LAYERT4;  break;
873 			case LAYERT5: artpl->col = COLORT5;  artpl->bits = LAYERT5;  break;
874 			default:
875 				if ((artpl->colorvar->addr&(LAYERG|LAYERH|LAYEROE)) == LAYEROE) artpl->bits = LAYERO; else
876 					artpl->bits = LAYERA;
877 				artpl->col = artpl->colorvar->addr;
878 				break;
879 		}
880 	}
881 
882 	/* get the stipple pattern information */
883 	artpl->patternvar = getvalkey(addr, type, -1, art_patternkey);
884 	if (artpl->patternvar != NOVARIABLE)
885 	{
886 		len = getlength(artpl->patternvar);
887 		if ((len != 8 && len != 16) ||
888 			((artpl->patternvar->type&VTYPE) != VINTEGER && (artpl->patternvar->type&VTYPE) != VSHORT))
889 		{
890 			ttyputerr(_("'ART_pattern' must be a 16-member INTEGER or SHORT array"));
891 			artpl->patternvar = NOVARIABLE;
892 			return;
893 		}
894 
895 		sty = PATTERNED;
896 		if ((artpl->patternvar->type&VTYPE) == VINTEGER)
897 		{
898 			for(i=0; i<len; i++)
899 				art_st_lay.raster[i] = (UINTSML)(((INTBIG *)artpl->patternvar->addr)[i]);
900 		} else
901 		{
902 			for(i=0; i<len; i++)
903 				art_st_lay.raster[i] = ((INTSML *)artpl->patternvar->addr)[i];
904 			sty |= OUTLINEPAT;
905 		}
906 		if (len == 8)
907 		{
908 			for(i=0; i<8; i++) art_st_lay.raster[i+8] = art_st_lay.raster[i];
909 		}
910 
911 		/* set the outline style (outlined if SHORT used) */
912 		art_st_lay.colstyle = art_st_lay.bwstyle = (INTSML)sty;
913 	}
914 }
915 
916 /******************** CURVE DRAWING ********************/
917 
918 /*
919  * routine to fill polygon "poly" with the vectors for the ellipse whose
920  * bounding box is given by the rectangle (lx-hx) and (ly-hy).
921  */
art_fillellipse(INTBIG lx,INTBIG ly,INTBIG hx,INTBIG hy,double startoffset,double endangle,INTBIG pindex,POLYGON * poly)922 void art_fillellipse(INTBIG lx, INTBIG ly, INTBIG hx, INTBIG hy, double startoffset,
923 	double endangle, INTBIG pindex, POLYGON *poly)
924 {
925 	double cx, cy, a, b, p, s2, s3, c2, c3, t1;
926 	REGISTER INTBIG m, pts;
927 	REGISTER BOOLEAN closed;
928 
929 	/* ensure that the polygon can hold the vectors */
930 	if (startoffset == 0.0 && endangle == 0.0)
931 	{
932 		/* full ellipse */
933 		closed = TRUE;
934 		endangle = EPI * 2.0;
935 		if (pindex == NCIRCLE) poly->style = CLOSED; else
936 			poly->style = OPENEDT3;
937 	} else
938 	{
939 		/* partial ellipse */
940 		closed = FALSE;
941 		if (pindex == NCIRCLE) poly->style = OPENED; else
942 			poly->style = OPENEDT3;
943 	}
944 	pts = (INTBIG)(endangle * ELLIPSEPOINTS / (EPI * 2.0));
945 	if (closed && pindex != NCIRCLE) pts++;
946 	if (poly->limit < pts) (void)extendpolygon(poly, pts);
947 	poly->count = pts;
948 
949 	/* get center of ellipse */
950 	cx = (lx + hx) / 2;
951 	cy = (ly + hy) / 2;
952 
953 	/* compute the length of the semi-major and semi-minor axes */
954 	a = (hx - lx) / 2;
955 	b = (hy - ly) / 2;
956 
957 	if (closed)
958 	{
959 		/* more efficient algorithm used for full ellipse drawing */
960 		p = 2.0 * EPI / (ELLIPSEPOINTS-1);
961 		c2 = cos(p);    s2 = sin(p);
962 		c3 = 1.0;       s3 = 0.0;
963 		for(m=0; m<ELLIPSEPOINTS; m++)
964 		{
965 			poly->xv[m] = rounddouble(cx + a * c3);
966 			poly->yv[m] = rounddouble(cy + b * s3);
967 			t1 = c3*c2 - s3*s2;
968 			s3 = s3*c2 + c3*s2;
969 			c3 = t1;
970 		}
971 		if (pindex != NCIRCLE)
972 		{
973 			poly->xv[m] = poly->xv[0];
974 			poly->yv[m] = poly->yv[0];
975 		}
976 	} else
977 	{
978 		/* less efficient algorithm for partial ellipse drawing */
979 		for(m=0; m<pts; m++)
980 		{
981 			p = startoffset + m * endangle / (pts-1);
982 			c2 = cos(p);   s2 = sin(p);
983 			poly->xv[m] = rounddouble(cx + a * c2);
984 			poly->yv[m] = rounddouble(cy + b * s2);
985 		}
986 	}
987 }
988 
989 #define SPLINEPOLYX(i) (points[(i)*2] + cx)
990 #define SPLINEPOLYY(i) (points[(i)*2+1] + cy)
991 
992 /*
993  * Routine to convert the "count" spline control points in "points" that are centered at (cx,cy)
994  * to a line approximation in "poly".  Uses "steps" lines per spline segment.
995  */
art_fillspline(INTBIG * points,INTBIG count,INTBIG cx,INTBIG cy,POLYGON * poly,INTBIG steps)996 void art_fillspline(INTBIG *points, INTBIG count, INTBIG cx, INTBIG cy, POLYGON *poly, INTBIG steps)
997 {
998 	REGISTER INTBIG i, k, out, outpoints;
999 	double t, t1, t2, t3, t4, x1, y1, x2, y2, x3, y3, x4, y4, x, y, tsq, splinestep;
1000 
1001 	outpoints = (count - 1) * steps + 1;
1002 	if (poly->limit < outpoints) (void)extendpolygon(poly, outpoints);
1003 	out = 0;
1004 
1005 	splinestep = 1.0 / (double)steps;
1006 	x2 = SPLINEPOLYX(0)*2 - SPLINEPOLYX(1);
1007 	y2 = SPLINEPOLYY(0)*2 - SPLINEPOLYY(1);
1008 	x3 = SPLINEPOLYX(0);
1009 	y3 = SPLINEPOLYY(0);
1010 	x4 = SPLINEPOLYX(1);
1011 	y4 = SPLINEPOLYY(1);
1012 	for(k = 2; k <= count; k++)
1013 	{
1014 		x1 = x2;   x2 = x3;   x3 = x4;
1015 		y1 = y2;   y2 = y3;   y3 = y4;
1016 		if (k == count)
1017 		{
1018 		   x4 = SPLINEPOLYX(k-1)*2 - SPLINEPOLYX(k-2);
1019 		   y4 = SPLINEPOLYY(k-1)*2 - SPLINEPOLYY(k-2);
1020 		} else
1021 		{
1022 		   x4 = SPLINEPOLYX(k);
1023 		   y4 = SPLINEPOLYY(k);
1024 		}
1025 
1026 		for(t=0.0, i=0; i<steps; i++, t+= splinestep)
1027 		{
1028 			tsq = t * t;
1029 			t4 = tsq * t;
1030 			t3 = -3.0*t4 + 3.0*tsq + 3.0*t + 1.0;
1031 			t2 = 3.0*t4 - 6.0*tsq + 4.0;
1032 			t1 = -t4 + 3.0*tsq - 3.0*t + 1.0;
1033 
1034 			x = (x1*t1 + x2*t2 + x3*t3 + x4*t4) / 6.0;
1035 			y = (y1*t1 + y2*t2 + y3*t3 + y4*t4) / 6.0;
1036 			poly->xv[out] = rounddouble(x);
1037 			poly->yv[out++] = rounddouble(y);
1038 		}
1039 	}
1040 
1041 	/* close the spline */
1042 	poly->xv[out] = SPLINEPOLYX(count-1);
1043 	poly->yv[out++] = SPLINEPOLYY(count-1);
1044 	poly->style = OPENED;
1045 	poly->count = out;
1046 }
1047