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