1 /*
2  * TransFig: Facility for Translating Fig code
3  * Copyright (c) 1999 by T. Sato
4  * Parts Copyright (c) 2002 by Anthony Starks
5  * Parts Copyright (c) 2002,2003,2004,2005,2006 by Martin Kroeker
6  * Parts Copyright (c) 2002 by Brian V. Smith
7  *
8  * Any party obtaining a copy of these files is granted, free of charge, a
9  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10  * nonexclusive right and license to deal in this software and
11  * documentation files (the "Software"), including without limitation the
12  * rights to use, copy, modify, merge, publish and/or distribute copies of
13  * the Software, and to permit persons who receive copies from any such
14  * party to do so, with the only requirement being that this copyright
15  * notice remain intact.
16  *
17  */
18 
19 /*
20  *
21  * SVG driver for fig2dev
22  *
23  *  from fig2svg -- convert FIG 3.2 to SVG
24  *
25  *  Original author:  Anthony Starks (ajstarks@home.com)
26  *  Created: 17 May 2000
27  *  Converted to gensvg by Brian Smith
28  *  Further modified by Martin Kroeker (martin@ruby.chemie.uni-freiburg.de)
29  *  incorporating changes by Philipp Hahn and Justus Piater
30  *
31  *  PH: Philipp Hahn
32  *  JP: Justus Piater
33  *  MK: Martin Kroeker
34  *  BS: Brian Smith
35  *  RE: Russell Edwards
36  *
37  *  MK 04-Dec-02: partial support for the symbol font, bigger fontscale, text alignment,
38  *  dashed and dotted lines, bugfix for missing % in stroke-color statement of arcs
39  *  FIXME: lacks support for arrowheads; fill patterns; percent grayscale fills
40  *  MK 08-Dec-02: rotated text; shades and tints of fill colors; filled circles
41  *  MK 11-Dec-02: scaling;proper font/slant/weight support; changed arc code
42  *  12-Dec-02: fixes by Brian Smith: scale factor, orientation, ellipse fills
43  *  MK 14-Dec-02: arc code rewrite, simplified line style handling,
44  *  arrowheads on arcs and lines (FIXME: not clipped), stroke->color command
45  *  is simply 'stroke'
46  *  MK 15-Dec-02: catch pattern fill flags, convert to tinted fills for now
47  *  MK 18-Dec-02: fill patterns; fixes by BS: arrowhead scale & position,
48  *  circle by diameter
49  *  PH 03-Feb-03: Fix CIRCLE_BY_DIA, color/fill styles, update SVG DTD
50  *  MK 10-Feb-03: do not encode space characters when in symbol font;
51  *                always encode characters '&', '<' and '>'. Leave non-
52  *		  alphabetic characters in the lower half of the symbol
53  *		  font unchanged.
54  *  MK 12-Feb-03: Added complete character conversion tables for the symbol
55  *		  and dingbat fonts (based on the information in Unicode
56  *		  Inc.'s symbol.txt and zdingbat.txt tables, version 0.2)
57  *  MK 18-Feb-03: Added cap and join style fields for line and arc
58  *  MK 24-Feb-03: Symbol and Dingbat fonts are no longer translated to
59  *		  font-family="Times" with both bold and italic flags set.
60  *  MK 17-Jun-03: Fix for rotation angle bug. Correct rendering of 'tinted'
61  *		  colors using code from www.cs.rit.edu. Added forgotten
62  *		  pattern fill option for ellipses (circles).
63  *  JP 21-Jan-04: Calculate proper bounding box instead of current paper
64  *                dimensions. Added missing semicolons in some property
65  *                strings, and proper linebreak characters in multi-line
66  *                format strings.
67  *  MK 23-Jan-04: Pattern-filled objects are now drawn twice - painting the
68  *                pattern over the fill color (if any). This solves the problem
69  *                of missing color support in pattern fills (as reported by JP)
70  *                Corrected filling of ellipses, which was still B/W only.
71  *                Fixed bad tiling of diagonal patterns 1 - 3 (the old formula
72  *                favoured exact angles over seamless tiling). Updated DTD.
73  *  MK 25-Jan-04: Endpoints of polylines are now truncated when arrowheads
74  *		  are drawn. Corrected rendering of type 0 (stick) arrowheads.
75  *  MK 28-Jan-04: Fix for arc arrowhead orientation.
76  *  MK 31-Jan-04: Corrected arc angle calculation (this time for good ?)
77  *  MK 22-Feb-04: Picture support
78  *  JP  1-Mar-04: Closed arrowheads should use polygons instead of polylines
79  *  JP  3-Mar-04: Corrected font family selection
80  *  JP 26-Mar-04: Corrected (and simplified) calculation of white-tinted
81  *                fill colors (and removed the HSV/RGB conversion code)
82  *  MK 29-Mar-04: Added code for rounded boxes (polyline subtype 4)
83  *  MK 30-Mar-04: Added code for boxes, explicit support for polygons
84  *  MK 10-Apr-04: Added xml-space:preserve qualifier on texts to preserve
85  *                whitespace. Rewrote fill pattern handling to generate
86  *                patterns as needed - adding support for penwidth and color.
87  *                Corrected tiling of all shingle patterns and reversal
88  *                of horizontal shingles.
89  *  RE  6-May-04: Changed degrees() to double for more precision
90  *                Added linewidth() to transform all line widths in the
91  *                 same way as genps.c : thin lines get thinner
92  *                Changed circle radius to use F_ellipse::radiuses.x instead
93  *                 of start and end (which seemed not to work correctly)
94  *                 Query: Is this broken for byradius or bydiameter??
95  *                Added rotation to ellipses
96  *                Changed back to mapping Symbol to Times, greeks look a bit
97  *                 better. Ultimately embedding PS fonts would be better.
98  *                Removed newlines inside <text> printf, otherwise they get
99  *                 rendered as spaces due to xml:space="preserve"
100  *                Removed extraneous comma between two halves of format
101  *                 string in gensvg_arc, fixes Seg fault.
102  *  MK  3-Aug-04  Split the multi-line format string in gensvg_arc in two to
103  *                get rid of (compiler version-dependant) segfaults for good.
104  *  MK 11-Sep-05: Added explicit stroke color to text to prevent black outline
105  *                on colored text.
106  *                Added support for latex-special formatted text, converting
107  *                sub- and superscripts to either baseline-shift=sub/super
108  *                (the intended way of doing this in SVG) or "dy" offsets
109  *                (less elegant, but more likely to be supported by browsers
110  *                and editors) depending on the NOSUPER define below.
111  *                Tested with Batik-1.6, konqueror-3.4, firefox-1.5b1,
112  *                inkscape-0.41
113  *  MK 15-Sep-05: Use a font-family list of "Times,Symbol" for symbol
114  *		  characters - the Times fontface does not contain all
115  *		  elements of the Symbol font on all platforms.
116  *  MK  4-Nov-05: Corrected length and appearance of stick-type arrows.
117  *  MK  2-Jan-06: Added support for filled arcs.
118  *  MK 26-Feb-06: Added support for dashed circles, ellipses and arcs.
119  *		  Dash/gap lengths are now drawn according to style_val.
120  *		  Fixed several glitches uncovered by splint.
121  *  MK 22-Apr-06: Corrected blue component of shaded colors (was always
122  *		  zero due to missing parentheses around typecast). Corrected
123  *		  arrowheads of large arrows by adding an increased miterlimit.
124  * 		  Corrected position of backward arrowheads on polylines with
125  *		  both forward and backward arrows.
126  *  MK  2-Jul-06: Patterns do not inherit their line width from the parent object
127  *                (which may be zero if no visible boundary is desired), so always
128  *                use linewidth:1
129  *  MK 22-Oct-06: Changed unicode variant of lowercase phi to match its X11 Symbol
130  *                counterpart.
131  *  *********************************************************************************
132  *  W3 recommendations for
133  *  1.3 SVG Namespace, Public Identifier and System Identifier
134  *
135  *  The following are the SVG 1.1 namespace, public identifier and system identifier:
136  *
137  *  SVG Namespace:
138  *      http://www.w3.org/2000/svg
139  *	xmlns:xlink="http://www.w3.org/1999/xlink"
140  *  Public Identifier for SVG 1.1:
141  *      PUBLIC "-//W3C//DTD SVG 1.1//EN"
142  *  System Identifier for the SVG 1.1 Recommendation:
143  *      http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd
144  *
145  *  The following is an example document type declaration for an SVG document:
146  *
147  *  <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
148  *           "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
149  *
150  *  Note that DTD listed in the System Identifier is a modularized DTD (ie. its
151  *  contents are spread over multiple files), which means that a validator may have
152  *  to fetch the multiple modules in order to validate. For that reason, there is
153  *  a single flattened DTD available that corresponds to the SVG 1.1 modularized DTD.
154  *  It can be found at http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-flat.dtd.
155  *  *********************************************************************************
156  */
157 
158 /*
159  * use a workaround for sub-/superscripting as long as most browsers do not
160  * support the baseline-shift=sub/super attribute
161  */
162 #define NOSUPER 1
163 
164 #include "fig2dev.h"
165 #include "object.h"
166 #include "bound.h"
167 #include "../../patchlevel.h"
168 
169 static void svg_arrow();
170 static void generate_tile(int);
171 static void svg_dash(int,double);
172 
173 #define PREAMBLE "<?xml version=\"1.0\" standalone=\"no\"?>\n"\
174 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"\
175 "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
176 const char   *joinstyle[] = { "miter","round","bevel"};
177 const char   *capstyle[] = { "butt","round", "square"};
178 static unsigned int symbolchar[256]=
179 {0,0,0,0,0,0,0,0,0,0,
180 0,0,0,0,0,0,0,0,0,0,
181 0,0,0,0,0,0,0,0,0,0,
182 0,0,0x0020,0x0021,0x2200,0x0023,0x2203,0x0025,
183 0x0026,0x220B,0x0028,0x0029,0x2217,0x002B,0x002C,0x2212,0x002E,0x002F,0x0030,
184 0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,
185 0x003C,0x003D,0x003E,0x003F,0x2245,0x0391,0x0392,0x03A7,0x0394,0x0395,
186 0x03A6,0x0393,0x0397,0x0399,0x03D1,0x039A,0x039B,0x039C,0x039D,0x039F,0x03A0,
187 0x0398,0x03A1,0x03A3,0x03A4,0x03A5,0x03C2,0x03A9,0x039E,0x03A8,0x0396,
188 0x005B,0x2234,0x005D,0x22A5,0x005F,0xF8E5,0x03B1,0x03B2,0x03C7,0x03B4,0x03B5,
189 0x03D5 /*0x03C6*/,0x03B3,0x03B7,0x03B9,0x03D5,0x03BA,0x03BB,0x03BC,0x03BD,0x03BF,
190 0x03C0,0x03B8,0x03C1,0x03C3,0x03C4,0x03C5,0x03D6,0x03C9,0x03BE,0x03C8,0x03B6,
191 0x007B,0x007C,0x007D,0x223C,0,0,0,0,0,0,0,0,0,
192 0,0,0,0,0,0,0,0,0,0,
193 0,0,0,0,0,0,0,0,0,0, 0,0,
194 0,0,0x20AC,0x03D2,0x2032,0x2264,0x2044,0x221E,
195 0x0192,0x2663,0x2666,0x2665,0x2660,0x2194,0x2190,0x2191,0x2192,0x2193,0x00B0,
196 0x00B1,0x2033,0x2265,0x00D7,0x221D,0x2202,0x2022,0x00F7,0x2260,0x2261,0x2248,
197 0x2026,0xF8E6,0xF8E7,0x21B5,0x2135,0x2111,0x211C,0x2118,0x2297,0x2295,0x2205,
198 0x2229,0x222A,0x2283,0x2287,0x2284,0x2282,0x2286,0x2208,0x2209,0x2220,0x2207,
199 0xF6DA,0xF6D9,0xF6DB,0x220F,0x221A,0x22C5,0x00AC,0x2227,0x2228,0x21D4,0x21D0,
200 0x21D1,0x21D2,0x21D3,0x25CA,0x2329,0xF8E8,0xF8E9,0xF8EA,0x2211,0xF8EB,0xF8EC,
201 0xF8ED,0xF8EE,0xF8EF,0xF8F0,0xF8F1,0xF8F2,0xF8F3,0xF8F4,0,0x232A,0x222B,0x2320,
202 0xF8F5,0x2321,0xF8F6,0xF8F7,0xF8F8,0xF8F9,0xF8FA,0xF8FB,0xF8FC,0xF8FD,0xF8FE,0
203 };
204 
205 static unsigned int dingbatchar[256]=
206 {0,0,0,0,0,0,0,0,0,0,
207 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0x0020,
208 0x2701,0x2702,0x2703,0x2704,0x260E,0x2706,0x2707,0x2708,0x2709,0x261B,
209 0x261E,0x270C,0x270D,0x270E,0x270F,0x2710,0x2711,0x2712,0x2713,0x2714,
210 0x2715,0x2716,0x2717,0x2718,0x2719,0x271A,0x271B,0x271C,0x271D,0x271E,
211 0x271F,0x2720,0x2721,0x2722,0x2723,0x2724,0x2725,0x2726,0x2727,0x2605,
212 0x2729,0x272A,0x272B,0x272C,0x272D,0x272E,0x272F,0x2730,0x2731,0x2732,
213 0x2733,0x2734,0x2735,0x2736,0x2737,0x2738,0x2739,0x273A,0x273B,0x273C,
214 0x273D,0x273E,0x273F,0x2740,0x2741,0x2742,0x2743,0x2744,0x2745,0x2746,
215 0x2747,0x2748,0x2749,0x274A,0x274B,0x25CF,0x274D,0x25A0,0x274F,0x2750,
216 0x2751,0x2752,0x25B2,0x25BC,0x25C6,0x2756,0x25D7,0x2758,0x2759,0x275A,
217 0x275B,0x275C,0x275D,0x275E,0,0xF8D7,0xF8D8,0xF8D9,0xF8DA,0xF8DB,
218 0xF8DC,0xF8DD,0xF8DE,0xF8DF,0xF8E0,0xF8E1,0xF8E2,0xF8E3,0xF8E4,0,0,
219 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
220 0,0x2761,0x2762,0x2763,
221 0x2764,0x2765,0x2766,0x2767,0x2663,0x2666,0x2665,0x2660,0x2460,0x2461,
222 0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,0x2776,0x2777,
223 0x2778,0x2779,0x277A,0x277B,0x277C,0x277D,0x277E,0x277F,0x2780,0x2781,
224 0x2782,0x2783,0x2784,0x2785,0x2786,0x2787,0x2788,0x2789,0x278A,0x278B,
225 0x278C,0x278D,0x278E,0x278F,0x2790,0x2791,0x2792,0x2793,0x2794,0x2192,
226 0x2194,0x2195,0x2798,0x2799,0x279A,0x279B,0x279C,0x279D,0x279E,0x279F,
227 0x27A0,0x27A1,0x27A2,0x27A3,0x27A4,0x27A5,0x27A6,0x27A7,0x27A8,0x27A9,
228 0x27AA,0x27AB,0x27AC,0x27AD,0x27AE,0x27AF,0,0x27B1,0x27B2,0x27B3,0x27B4,
229 0x27B5,0x27B6,0x27B7,0x27B8,0x27B9,0x27BA,0x27BB,0x27BC,0x27BD,0x27BE,0
230 };
231 
232 /* arrowhead arrays */
233 Point   points[50], fillpoints[50], clippoints[50];
234 int     npoints, nfillpoints, nclippoints;
235 int     arrowx1, arrowy1;	/* first point of object */
236 int     arrowx2, arrowy2;	/* second point of object */
237 
238 static int tileno=0; /* number of current tile */
239 
240 static F_point *p;
241 
242 static unsigned int
rgbColorVal(int colorIndex)243 rgbColorVal (int colorIndex)
244 {     				/* taken from genptk.c */
245     unsigned int rgb;
246     static unsigned int rgbColors[NUM_STD_COLS] = {
247       	0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff,
248       	0xffff00, 0xffffff, 0x00008f, 0x0000b0, 0x0000d1, 0x87cfff,
249       	0x008f00, 0x00b000, 0x00d100, 0x008f8f, 0x00b0b0, 0x00d1d1,
250       	0x8f0000, 0xb00000, 0xd10000, 0x8f008f, 0xb000b0, 0xd100d1,
251       	0x803000, 0xa14000, 0xb46100, 0xff8080, 0xffa1a1, 0xffbfbf,
252       	0xffe0e0, 0xffd600
253     };
254 
255     if (colorIndex == DEFAULT)
256       	rgb = rgbColors[0];
257     else if (colorIndex < NUM_STD_COLS)
258       	rgb = rgbColors[colorIndex];
259     else
260       	rgb = ((user_colors[colorIndex - NUM_STD_COLS].r & 0xff) << 16)
261       	    | ((user_colors[colorIndex - NUM_STD_COLS].g & 0xff) << 8)
262       	    | (user_colors[colorIndex - NUM_STD_COLS].b & 0xff);
263     return rgb;
264 }
265 
266 static unsigned int
rgbFillVal(int colorIndex,int area_fill)267 rgbFillVal (int colorIndex, int area_fill)
268 {
269     unsigned int rgb, r, g, b;
270     float t;
271     short   tintflag = 0;
272     static unsigned int rgbColors[NUM_STD_COLS] = {
273       	0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff,
274       	0xffff00, 0xffffff, 0x00008f, 0x0000b0, 0x0000d1, 0x87cfff,
275       	0x008f00, 0x00b000, 0x00d100, 0x008f8f, 0x00b0b0, 0x00d1d1,
276       	0x8f0000, 0xb00000, 0xd10000, 0x8f008f, 0xb000b0, 0xd100d1,
277       	0x803000, 0xa14000, 0xb46100, 0xff8080, 0xffa1a1, 0xffbfbf,
278       	0xffe0e0, 0xffd600
279     };
280 
281 
282     if (colorIndex == DEFAULT)
283           	rgb = rgbColors[0];
284     else if (colorIndex < NUM_STD_COLS)
285       	rgb = rgbColors[colorIndex];
286     else
287       	rgb = ((user_colors[colorIndex - NUM_STD_COLS].r & 0xff) << 16)
288       	    | ((user_colors[colorIndex - NUM_STD_COLS].g & 0xff) << 8)
289       	    | (user_colors[colorIndex - NUM_STD_COLS].b & 0xff);
290 
291     tintflag = 0;
292     if (area_fill > 20) {
293       	tintflag = 1;
294       	area_fill -= 20;
295     }
296     if (colorIndex > 0 && colorIndex != 7) {
297       	if (tintflag) {
298       	    r = ((rgb & ~0xFFFF) >> 16);
299       	    g = ((rgb & 0xFF00) >> 8);
300       	    b = (rgb & ~0xFFFF00) ;
301 
302 	    t= area_fill / 20.;
303 	    r += t * (0xFF-r);
304 	    g += t * (0xff-g);
305 	    b += t * (0xff-b);
306 
307       rgb = ((r &0xff) << 16) + ((g&0xff) << 8) + (b&0xff);
308       	}
309       	else
310       	    rgb = (((int) ((area_fill / 20.) * ((rgb & ~0xFFFF) >> 16)) << 16) +
311       		   ((int) ((area_fill / 20.) * ((rgb & 0xFF00) >> 8)) << 8)
312       		   + ((int) ((area_fill / 20.) * (rgb & ~0xFFFF00))) );
313     }
314     else {
315       	if (colorIndex == 0 || colorIndex == DEFAULT)
316       	    area_fill = 20 - area_fill;
317       	rgb =
318       	    ((area_fill * 255 / 20) << 16) + ((area_fill * 255 / 20) << 8) +
319       	    area_fill * 255 / 20;
320     }
321 
322     return rgb;
323 }
324 
325 static double
degrees(double angle)326 degrees (double angle)
327 {
328    return -angle / M_PI * 180.0;
329 }
330 
331 static int
linewidth_adj(int linewidth)332 linewidth_adj(int linewidth)
333 {
334    /* Adjustment as in genps.c */
335    return (double)linewidth <= THICK_SCALE ? linewidth/2 : linewidth-THICK_SCALE;
336 }
337 
338 
339 void
gensvg_option(opt,optarg)340 gensvg_option (opt, optarg)
341      char    opt;
342      char   *optarg;
343 {
344     switch (opt) {
345       	case 'L':		/* ignore language and magnif. */
346       	case 'm':
347       	    break;
348       	case 'z':
349       	    (void) strcpy (papersize, optarg);
350       	    paperspec = True;
351       	    break;
352       	default:
353       	    put_msg (Err_badarg, opt, "svg");
354       	    exit (1);
355     }
356 }
357 
358 void
gensvg_start(objects)359 gensvg_start (objects)
360      F_compound *objects;
361 {
362     struct paperdef *pd;
363     int     pagewidth = -1, pageheight = -1;
364     int     vx, vy, vw, vh;
365     time_t  when;
366     char    stime[80];
367 
368     fprintf (tfp, "%s\n", PREAMBLE);
369     fprintf (tfp, "<!-- Creator: %s Version %s Patchlevel %s -->\n",
370       	     prog, VERSION, PATCHLEVEL);
371 
372     (void) time (&when);
373     strcpy (stime, ctime (&when));
374     /* remove trailing newline from date/time */
375     stime[strlen (stime) - 1] = '\0';
376     fprintf (tfp, "<!-- CreationDate: %s -->\n", stime);
377     fprintf (tfp, "<!-- Magnification: %.3f -->\n", mag);
378 
379     /* convert paper size from ppi to inches */
380     for (pd = paperdef; pd->name != NULL; pd++)
381       	if (strcasecmp (papersize, pd->name) == 0) {
382       	    pagewidth = pd->width;
383 	    pageheight = pd->height;
384 	    strcpy (papersize, pd->name);	/* use the "nice" form */
385 	    break;
386 	}
387     if (pagewidth < 0 || pageheight < 0) {
388 	(void) fprintf (stderr, "Unknown paper size `%s'\n", papersize);
389 	exit (1);
390     }
391     if (landscape) {
392 	vw = pagewidth;
393 	pagewidth = pageheight;
394 	pageheight = vw;
395     }
396     vx = (int) (llx * mag);
397     vy = (int) (lly * mag);
398     vw = (int) ((urx - llx) * mag);
399     vh = (int) ((ury - lly) * mag);
400     fprintf (tfp,
401 	     "<svg\txmlns=\"http://www.w3.org/2000/svg\"\n\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\twidth=\"%.1fin\" height=\"%.1fin\"\n\tviewBox=\"%d %d %d %d\">\n",
402 	     vw / ppi, vh / ppi, vx, vy, vw, vh);
403 
404     if (objects->comments)
405 	print_comments ("<desc>", objects->comments, "</desc>");
406     fprintf (tfp, "<g style=\"stroke-width:.025in; fill:none\">\n");
407     /* only define the patterns if one is used */
408 
409 
410 }
411 
412 int
gensvg_end()413 gensvg_end ()
414 {
415     fprintf (tfp, "</g>\n</svg>\n");
416     return 0;
417 }
418 
419 void
gensvg_line(l)420 gensvg_line (l)
421      F_line *l;
422 {
423 int px,py,firstpoint;
424 int px2,py2,width,height,rotation;
425 double dx,dy,len,cosa,sina,cosa1,sina1;
426 double hl;
427 
428 
429     if (!l->points) return; /*safeguard against old, buggy fig files*/
430 
431     if (l->type ==5 ) {
432 	fprintf (tfp,"<!-- Image -->\n");
433 	fprintf (tfp,"<image xlink:href=\"file://%s\" preserveAspectRatio=\"none\"\n",l->pic->file);
434 	p=l->points;
435 	px=p->x;
436 	py=p->y;
437 	px2=p->next->next->x;
438 	py2=p->next->next->y;
439 	width=px2-px;
440 	height=py2-py;
441 	rotation=0;
442 	if (width<0 && height <0)
443 		rotation=180;
444 	else if (width <0 && height >=0)
445 		rotation=90;
446 	else if (width >=0 && height <0)
447 		rotation=270;
448 	if (l->pic->flipped) rotation-=90;
449 	height=abs(height);
450 	width=abs(width);
451 	px=(px<px2)?px:px2;
452 	py=(py<py2)?py:py2;
453 	px2=px+width/2;
454 	py2=py+height/2;
455 	if (l->pic->flipped) {
456 	fprintf (tfp,"transform=\"rotate(%d %d %d) scale(-1,1) translate(%d,%d)\"\n",
457 	rotation,px2,py2,-2*px2,0);
458 	} else if (rotation !=0) {
459 	fprintf (tfp,"transform=\"rotate(%d %d %d)\"\n",rotation,px2,py2);
460 	}
461 
462 	fprintf (tfp,"x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" />\n",
463 	(int)(px*mag), (int)(py*mag), (int)(width*mag), (int)(height*mag));
464     return;
465     }
466 
467     if (l->type == 2 || l->type == 4) /* box or arc box */
468     {
469     fprintf (tfp, "<!-- Line: box -->\n");
470     print_comments ("<!-- ", l->comments, " -->");
471 	px=l->points->x;
472 	py=l->points->y;
473 	px2=l->points->next->next->x;
474 	py2=l->points->next->next->y;
475 	width=abs(px2-px);
476 	height=abs(py2-py);
477 	px=(px<px2)?px:px2;
478 	py=(py<py2)?py:py2;
479 
480     fprintf (tfp, "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%d\" \n",
481     	(int)(px*mag),(int)(py*mag),(int)(width*mag),(int)(height*mag),
482         (l->type == 2 ? 0 : (int)(l->radius*mag)));
483     fprintf (tfp, "style=\"stroke:#%6.6x;stroke-width:%d;\n",
484 	     rgbColorVal (l->pen_color), (int) ceil (linewidth_adj(l->thickness) * mag));
485 
486 	fprintf (tfp, "stroke-linejoin:%s; stroke-linecap:%s;\n",
487 			joinstyle[l->join_style],capstyle[l->cap_style]);
488 
489         if (l->style > 0)
490 	    svg_dash(l->style,l->style_val);
491 
492     if (l->fill_style != -1 )
493 	fprintf (tfp, "fill:#%6.6x;\n", rgbFillVal (l->fill_color,
494 	(l->fill_style>40 ? 20 : l->fill_style)));
495     fprintf (tfp, "\"/>\n");
496 
497     if (l->fill_style > 40) { /*repeat object to paint pattern over fill */
498 
499 	fprintf (tfp, "<g style=\"stroke:#%6.6x; stroke-width:1\" >\n",
500 	rgbColorVal(l->pen_color));
501 	generate_tile(l->fill_style - 40);
502 	fprintf (tfp, "</g>\n");
503 
504     fprintf (tfp, "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%d\" \n",
505 	(int)(px*mag),(int)(py*mag),(int)(width*mag),(int)(height*mag),
506         (l->type == 2 ? 0 : (int)(l->radius*mag)));
507     fprintf (tfp, "style=\"stroke:#%6.6x;stroke-width:%d;\n",
508 	     rgbColorVal (l->pen_color), (int) ceil (linewidth_adj(l->thickness) * mag));
509 
510 	fprintf (tfp, "stroke-linejoin:%s; stroke-linecap:%s;\n",
511 			joinstyle[l->join_style],capstyle[l->cap_style]);
512 
513         if (l->style > 0)
514 	    svg_dash(l->style,l->style_val);
515 
516 	fprintf (tfp, "fill:url(#tile%d);\n", tileno);
517     fprintf (tfp, "\"/>\n");
518     }
519     return;
520     }
521 
522     fprintf (tfp, "<!-- Line -->\n");
523     print_comments ("<!-- ", l->comments, " -->");
524     fprintf (tfp, "<%s points=\"", (l->type == 1 ? "polyline" : "polygon"));
525 	px=py=-100000;
526 	firstpoint=0;
527     for (p = l->points; p; p = p->next) {
528 	if (px != -100000) {
529 		if (firstpoint && l->back_arrow) {
530 		dx=(double)(p->x-px);
531 		dy=(double)(p->y-py);
532 		len=sqrt(dx*dx+dy*dy);
533 		sina1= dy/len;
534 		cosa1= dx/len;
535 		if (l->back_arrow->type != 0 )
536 		hl= l->back_arrow->ht;
537 		else
538                   hl = 1.1 * l->thickness;
539 		px += (int)(hl * cosa1 +0.5);
540 		py += (int)(hl * sina1 +0.5);
541 		firstpoint=0;
542 		}
543 	fprintf(tfp, "%d,%d\n", (int) (px*mag), (int) (py*mag));
544 	}
545 	arrowx1 = arrowx2;
546 	arrowy1 = arrowy2;
547 	arrowx2 = p->x;
548 	arrowy2 = p->y;
549 	if (px == -100000) firstpoint=1;
550 	px=p->x;
551 	py=p->y;
552     }
553 	if (!l->for_arrow)
554 	   fprintf(tfp, "%d,%d\n", (int) (px*mag), (int) (py*mag));
555 	else {
556 	dx=(double)(arrowx2-arrowx1);
557 	dy=(double)(arrowy2-arrowy1);
558 	len=sqrt(dx*dx+dy*dy);
559 	sina= dy/len;
560 	cosa= dx/len;
561 		if (l->for_arrow->type != 0)
562 		hl= l->for_arrow->ht;
563 		else
564                 hl = 1.1*l->thickness;
565 	px = arrowx2 - (int)(hl * cosa +0.5);
566 	py = arrowy2 - (int)(hl * sina +0.5);
567 	   fprintf(tfp, "%d,%d\n", (int) (px*mag), (int) (py*mag));
568 	}
569     fprintf (tfp, "\" style=\"stroke:#%6.6x;stroke-width:%d;\n",
570 	     rgbColorVal (l->pen_color), (int) ceil (linewidth_adj(l->thickness) * mag));
571 
572 	fprintf (tfp, "stroke-linejoin:%s; stroke-linecap:%s;\n",
573 			joinstyle[l->join_style],capstyle[l->cap_style]);
574 
575         if (l->style > 0)
576 	    svg_dash(l->style,l->style_val);
577 
578     if (l->fill_style != -1 )
579 	fprintf (tfp, "fill:#%6.6x;\n", rgbFillVal (l->fill_color, (l->fill_style>40 ? 20 : l->fill_style)));
580     fprintf (tfp, "\"/>\n");
581 
582     if (l->fill_style > 40) { /*repeat object to paint pattern over fill */
583 
584 	fprintf (tfp, "<g style=\"stroke:#%6.6x; stroke-width:1\" >\n",
585 	rgbColorVal(l->pen_color) );
586 	generate_tile(l->fill_style - 40);
587 	fprintf (tfp, "</g>\n");
588 
589     fprintf (tfp, "<%s points=\"", (l->type == 1 ? "polyline" : "polygon"));
590     for (p = l->points; p; p = p->next) {
591 	fprintf (tfp, "%d,%d\n", (int) (p->x * mag), (int) (p->y * mag));
592     }
593 
594     fprintf (tfp, "\" style=\"stroke:#%6.6x;stroke-width:%d;\n",
595 	     rgbColorVal (l->pen_color), (int) ceil (linewidth_adj(l->thickness) * mag));
596 
597 	fprintf (tfp, "stroke-linejoin:%s; stroke-linecap:%s;\n",
598 			joinstyle[l->join_style],capstyle[l->cap_style]);
599 
600         if (l->style > 0)
601 	    svg_dash(l->style,l->style_val);
602 
603 	fprintf (tfp, "fill:url(#tile%d);\n", tileno);
604     fprintf (tfp, "\"/>\n");
605     }
606 
607 
608     if (l->for_arrow != NULL) {
609 	arrowx2+=l->thickness*cosa;
610 	arrowy2+=l->thickness*sina;
611 	svg_arrow(l, l->for_arrow, l->pen_color);
612     }
613     if (l->back_arrow != NULL) {
614 	p = l->points;
615 	if (!p) return; /*safeguard against old, buggy fig files*/
616 	arrowx2=p->x - l->thickness*cosa1  ;
617 	arrowy2=p->y - l->thickness*sina1 ;
618 	p = p->next;
619 	if (!p) return; /*safeguard against old, buggy fig files*/
620 	arrowx1 = p->x;
621 	arrowy1 = p->y;
622 	svg_arrow(l, l->back_arrow, l->pen_color);
623     }
624 }
625 
626 
627 void
gensvg_spline(s)628 gensvg_spline (s) /* not used by fig2dev */
629      F_spline *s;
630 {
631     fprintf (tfp, "<!-- Spline -->\n");
632     print_comments ("<!-- ", s->comments, " -->");
633 
634     fprintf (tfp, "<path style=\"stroke:#%6.6x;stroke-width:%d\" d=\"",
635 	     rgbColorVal (s->pen_color), (int) ceil (linewidth_adj(s->thickness) * mag));
636     fprintf (tfp, "M %d,%d \n C", (int) (s->points->x * mag), (int) (s->points->y * mag));
637     for (p = s->points++; p; p = p->next) {
638 	fprintf (tfp, "%d,%d\n", (int) (p->x * mag), (int) (p->y * mag));
639     }
640     fprintf (tfp, "\"/>\n");
641 }
642 
643 void
gensvg_arc(a)644 gensvg_arc (a)
645      F_arc  *a;
646 {
647     double     radius;
648     double  x, y, angle, dx, dy;
649 
650     fprintf (tfp, "<!-- Arc -->\n");
651     print_comments ("<!-- ", a->comments, " -->");
652 
653     dx = a->point[0].x - a->center.x;
654     dy = a->point[0].y - a->center.y;
655     radius = sqrt (dx * dx + dy * dy);
656 
657 
658 	x= (a->point[0].x-a->center.x) * (a->point[2].x-a->center.x)
659 	   +(a->point[0].y-a->center.y) * (a->point[2].y-a->center.y);
660 	y= (a->point[0].x-a->center.x) * (a->point[2].y-a->center.y)
661 	   -(a->point[0].y-a->center.y) * (a->point[2].x-a->center.x);
662 
663 	if (x == 0.0 && y == 0.0)
664 		angle=0.0;
665 	else
666 	angle = atan2(y,x);
667 
668 	if (angle <0.0) angle += 2.*M_PI;
669 
670 	angle *= 180./M_PI;
671 
672 	if (a->direction==1) angle = 360.-angle;
673 
674     fprintf (tfp, "<path style=\"stroke:#%6.6x;stroke-width:%d;stroke-linecap:%s;",
675     	     rgbColorVal (a->pen_color), (int) ceil (linewidth_adj(a->thickness) * mag),
676 	     capstyle[a->cap_style]);
677 
678         if (a->style > 0)
679 	    svg_dash(a->style,a->style_val);
680 
681     if (a->fill_style != -1)
682 	    fprintf (tfp, "fill:#%6.6x\"\n", rgbFillVal (a->fill_color, (a->fill_style > 40 ? 20 : a->fill_style)));
683     else
684             fprintf (tfp,"\"\n");
685 
686     fprintf (tfp, "d=\"M %d,%d A %d %d % d % d % d % d % d \" />\n",
687              (int) (a->point[0].x * mag),
688 	     (int) (a->point[0].y * mag),
689 	     (int) (radius * mag), (int) (radius * mag),
690 	     0,
691 	     (fabs(angle) >180. ) ? 1 : 0,
692 	     (fabs(angle) >0. && a->direction==0) ? 1 : 0,
693 	     (int) (a->point[2].x * mag), (int) (a->point[2].y * mag));
694 
695 	if (a->fill_style > 40) {
696 
697 	fprintf (tfp, "<g style=\"stroke:#%6.6x; stroke-width:1\" >\n",
698 	rgbColorVal(a->pen_color) );
699 	generate_tile(a->fill_style - 40);
700 	fprintf (tfp, "</g>\n");
701 
702     fprintf (tfp, "<path style=\"stroke:#%6.6x;stroke-width:%d;stroke-linecap:%s;fill:url(#tile%d);\"\n",
703 	     rgbColorVal (a->pen_color), (int) ceil (linewidth_adj(a->thickness) * mag),
704 	     capstyle[a->cap_style],tileno);
705     fprintf (tfp, "d=\"M %d,%d A %d %d % d % d % d % d % d \" />\n",
706              (int) (a->point[0].x * mag),
707 	     (int) (a->point[0].y * mag),
708 	     (int) (radius * mag), (int) (radius * mag),
709 	     0,
710 	     (fabs(angle) >180. ) ? 1 : 0,
711 	     (fabs(angle) >0. && a->direction==0) ? 1 : 0,
712 	     (int) (a->point[2].x * mag), (int) (a->point[2].y * mag));
713 	}
714 
715     if (a->for_arrow) {
716 	arrowx2 = a->point[2].x;
717 	arrowy2 = a->point[2].y;
718 	compute_arcarrow_angle (a->center.x, a->center.y,
719 				(double) arrowx2, (double) arrowy2,
720 				a->direction, a->for_arrow, &arrowx1, &arrowy1);
721 	svg_arrow(a, a->for_arrow, a->pen_color);
722     }
723 
724     if (a->back_arrow) {
725 	arrowx2 = a->point[0].x;
726 	arrowy2 = a->point[0].y;
727 	compute_arcarrow_angle (a->center.x, a->center.y,
728 				(double) arrowx2, (double) arrowy2,
729 				a->direction ^ 1, a->back_arrow, &arrowx1, &arrowy1);
730 	svg_arrow(a, a->back_arrow, a->pen_color);
731     }
732 }
733 
734 void
gensvg_ellipse(e)735 gensvg_ellipse (e)
736      F_ellipse *e;
737 {
738     int cx = (int) (e->center.x * mag);
739     int cy = (int) (e->center.y * mag);
740     if (e->type == T_CIRCLE_BY_RAD || e->type == T_CIRCLE_BY_DIA) {
741         int r = (int) (e->radiuses.x * mag);
742 	fprintf (tfp, "<!-- Circle -->\n");
743 	print_comments ("<!-- ", e->comments, " -->");
744 	fprintf (tfp, "<circle cx=\"%d\" cy=\"%d\" r=\"%d\"\n style=\"", cx, cy, r);
745 	if (e->fill_style != -1)
746 	    fprintf (tfp, "fill:#%6.6x;", rgbFillVal (e->fill_color, (e->fill_style > 40 ? 20 : e->fill_style)));
747         if (e->style > 0) {
748 	    svg_dash(e->style,e->style_val);
749 	}
750         fprintf (tfp, "stroke:#%6.6x;stroke-width:%d;\"/>\n",
751 	     rgbColorVal (e->pen_color), (int) ceil (linewidth_adj(e->thickness) * mag));
752 
753 	if (e->fill_style > 40) {
754 
755 	fprintf (tfp, "<g style=\"stroke:#%6.6x; stroke-width:1\" >\n",
756 	rgbColorVal(e->pen_color) );
757 	generate_tile(e->fill_style - 40);
758 	fprintf (tfp, "</g>\n");
759 
760 	fprintf (tfp, "<circle cx=\"%d\" cy=\"%d\" r=\"%d\"\n style=\"", cx, cy, r);
761         fprintf (tfp, "fill:url(#tile%d);\n", tileno);
762         fprintf (tfp, "stroke:#%6.6x;stroke-width:%d;\"/>\n",
763 	     rgbColorVal (e->pen_color), (int) ceil (linewidth_adj(e->thickness) * mag));
764 	}
765     }
766     else {
767 	int rx = (int) (e->radiuses.x * mag);
768 	int ry = (int) (e->radiuses.y * mag);
769 	fprintf (tfp, "<!-- Ellipse -->\n");
770 	print_comments ("<!-- ", e->comments, " -->");
771 	fprintf (tfp, "<ellipse transform=\"translate(%d,%d) rotate(%.8lf)\" rx=\"%d\" ry=\"%d\"\n style=\"",
772 		 cx, cy, degrees(e->angle), rx, ry);
773 	if (e->fill_style != -1)
774 	    fprintf (tfp, "fill:#%6.6x;", rgbFillVal (e->fill_color, (e->fill_style > 40 ? 20 : e->fill_style)));
775         if (e->style > 0)
776 	    svg_dash(e->style,e->style_val);
777 
778         fprintf (tfp, "stroke:#%6.6x;stroke-width:%d;\"/>\n",
779         	 rgbColorVal (e->pen_color), (int) ceil (linewidth_adj(e->thickness) * mag));
780 
781 	if (e->fill_style > 40) {
782 
783 	fprintf (tfp, "<g style=\"stroke:#%6.6x; stroke-width:1\" >\n",
784 	rgbColorVal(e->pen_color) );
785 	generate_tile(e->fill_style - 40);
786 	fprintf (tfp, "</g>\n");
787 	fprintf (tfp, "<ellipse transform=\"translate(%d,%d) rotate(%.8lf)\" rx=\"%d\" ry=\"%d\"\n style=\"",
788 		 cx, cy, degrees(e->angle), rx, ry);
789         fprintf (tfp, "fill:url(#tile%d);\n", tileno);
790         fprintf (tfp, "stroke:#%6.6x;stroke-width:%d;\"/>\n",
791 	         rgbColorVal (e->pen_color), (int) ceil (linewidth_adj(e->thickness) * mag));
792 	}
793     }
794 }
795 
796 void
gensvg_text(t)797 gensvg_text (t)
798      F_text *t;
799 {
800     unsigned char *cp;
801     int ch;
802     const char *anchor[3] = { "start", "middle", "end" };
803     static const char *family[9] = { "Times", "AvantGarde",
804 	"Bookman", "Courier", "Helvetica", "Helvetica Narrow",
805 	"New Century Schoolbook", "Palatino", "Times,Symbol"
806     };
807     int x = (int) (t->base_x * mag);
808     int y = (int) (t->base_y * mag);
809     int dy = 0;
810 
811     fprintf (tfp, "<!-- Text -->\n");
812     print_comments ("<!-- ", t->comments, " -->");
813 
814     if (t->angle != 0) {
815 	fprintf (tfp, "<g transform=\"translate(%d,%d) rotate(%.8lf)\" >\n",
816 		 x, y, degrees (t->angle));
817 	x = y = 0;
818     }
819     fprintf (tfp, "<text xml:space=\"preserve\" x=\"%d\" y=\"%d\" fill=\"#%6.6x\"  font-family=\"%s\" "\
820 	     "font-style=\"%s\" font-weight=\"%s\" font-size=\"%d\" text-anchor=\"%s\">",
821 	     x, y, rgbColorVal (t->color), family[t->font / 4],
822 	     ( (t->font % 2 == 0 || t->font >31) ? "normal" : "italic"),
823 	     ( (t->font % 4 < 2 || t->font >31) ? "normal" : "bold"), (int) (ceil (t->size * 12 * mag)),
824 	     anchor[t->type]);
825 
826     if (t->font == 32) {
827 	for (cp = (unsigned char *) t->cstring; *cp; cp++) {
828 		ch=*cp;
829 	    fprintf (tfp, "&#%d;", symbolchar[ch]);
830 	}
831     }
832     else if (t->font == 34) {
833 	for (cp = (unsigned char *) t->cstring; *cp; cp++) {
834 		ch=*cp;
835 	    fprintf (tfp, "&#%d;", dingbatchar[ch]);
836 	}
837     }
838     else if (special_text(t)) {
839     int supsub=0;
840     int old_dy=0;
841     dy=0;
842 	for (cp = (unsigned char *) t->cstring; *cp; cp++) {
843 	    ch = *cp;
844 	    if (( supsub == 2 &&ch == '}' ) || supsub==1) {
845 #ifdef NOSUPER
846 	        fprintf(tfp,"</tspan><tspan dy=\"%d\">",-dy);
847                 old_dy=-dy;
848 #else
849 	        fprintf(tfp,"</tspan>");
850 #endif
851 	        supsub=0;
852 	        if (ch == '}') {
853                   cp++;
854                   ch=*cp;
855                 }
856             }
857            if (ch == '_' || ch == '^') {
858                 supsub=1;
859 #ifdef NOSUPER
860                 if (dy != 0) fprintf(tfp,"</tspan>");
861                 if (ch == '_') dy=(int)(35.*mag);
862                 if (ch == '^') dy=(int)(-50.*mag);
863                 fprintf(tfp,"<tspan font-size=\"%d\" dy=\"%d\">",(int) (ceil (t->size * 8 * mag)),dy+old_dy);
864                 old_dy=0;
865 #else
866                 fprintf(tfp,"<tspan font-size=\"%d\" baseline-shift=\"",(int) (ceil (t->size * 8 * mag)));
867                 if (ch == '_') fprintf(tfp,"sub\">");
868                 if (ch == '^') fprintf(tfp,"super\">");
869 #endif
870                 cp++;
871                 ch=*cp;
872                 if (ch == '{' ) {
873                   supsub=2;
874                   cp++;
875                   ch=*cp;
876                 }
877             }
878 #ifdef NOSUPER
879                 else old_dy=0;
880 #endif
881 	    if (ch < 128 && ch != 38 && ch != 60 && ch != 62
882 	    && ch != '$')
883 		(void)fputc (ch, tfp);
884 	    else if (ch != '$')
885 		fprintf (tfp, "&#%d;", ch);
886     }
887     } else {
888 	for (cp = (unsigned char *) t->cstring; *cp; cp++) {
889 	    ch = *cp;
890 	    if (ch < 128 && ch != 38 && ch != 60 && ch != 62)
891 		(void)fputc (ch, tfp);
892 	    else
893 		fprintf (tfp, "&#%d;", ch);
894 	}
895     }
896 #ifdef NOSUPER
897     if (dy != 0) fprintf(tfp,"</tspan>");
898 #endif
899     fprintf (tfp, "</text>\n");
900     if (t->angle != 0)
901 	fprintf (tfp, "</g>");
902 }
903 
904 static void
svg_arrow(F_line * obj,F_arrow * arrow,int pen_color)905 svg_arrow(F_line *obj, F_arrow *arrow, int pen_color)
906 {
907     int     i;
908     if (arrow) {
909 	calc_arrow(arrowx1, arrowy1, arrowx2, arrowy2,
910 		    obj->thickness, arrow,
911 		    points, &npoints, fillpoints, &nfillpoints, clippoints, &nclippoints);
912 
913       fprintf (tfp, "<!-- Arrowhead on XXXpoint %d %d - %d %d-->\n",(int)(arrowx1*mag),(int)(arrowy1*mag),(int)(arrowx2*mag),(int)(arrowy2*mag));
914       fprintf (tfp, "<%s points=\"", (arrow->type == 0 ? "polyline" : "polygon"));
915       for (i = 0; i < npoints; i++) {
916           fprintf (tfp, "%d %d\n", (int) (points[i].x * mag),
917       	     (int) (points[i].y * mag));
918       }
919       if (arrow->type > 0)
920           fprintf (tfp, "\n");
921       fprintf (tfp, "\" style=\"stroke:#%6.6x;stroke-width:%d;stroke-miterlimit:8;\n",
922       	 rgbColorVal (pen_color), (int) ceil (linewidth_adj((int)arrow->thickness) * mag));
923       if (arrow->type > 0) {
924 	    if (arrow->style == 0 && nfillpoints == 0)
925 		fprintf (tfp, "fill:white;\"/>\n");
926 	    else {
927 		if (nfillpoints == 0)
928 		    fprintf (tfp, "fill:#%6.6x;\"/>\n", rgbColorVal (pen_color));
929 		else {
930 		    /* first fill with white */
931 		    fprintf (tfp, "fill:white;\"/>\n");
932 		    fprintf (tfp, "<!-- Just filled with white now fill special area -->\n");
933 		    /* now fill the special area */
934 		    fprintf (tfp, "<path d=\"M ");
935 		    for (i = 0; i < nfillpoints; i++) {
936 			fprintf (tfp, "%d %d\n", (int) (fillpoints[i].x * mag),
937 			     (int) (fillpoints[i].y * mag));
938 		    }
939 		    fprintf (tfp, "Z\n");
940 		    fprintf (tfp, "\" style=\"stroke:#%6.6x;stroke-width:%d;stroke-miterlimit:8;\n",
941 			 rgbColorVal (pen_color), (int) ceil (linewidth_adj((int)arrow->thickness) * mag));
942 		    fprintf (tfp, "fill:#%6.6x;\"/>\n", rgbColorVal (pen_color));
943 		}
944 	    }
945       } else
946           fprintf (tfp, "\"/>\n");
947     }
948 }
949 
generate_tile(int number)950 void generate_tile(int number) {
951 
952 	tileno++;
953 	fprintf (tfp, "<defs>\n");
954 	fprintf (tfp, "<pattern id=\"tile%d\" x=\"0\" y=\"0\" width=\"200\" height=\"200\"\n",
955 		tileno);
956 	fprintf (tfp, "         patternUnits=\"userSpaceOnUse\">\n");
957 
958 	switch(number) {
959 	case 1:
960 	    fprintf (tfp, "<path d=\"M 0 -100 200 20\" />\n");
961 	    fprintf (tfp, "<path d=\"M 0  -60 200 60\" />\n");
962 	    fprintf (tfp, "<path d=\"M 0  -20 200 100\" />\n");
963 	    fprintf (tfp, "<path d=\"M 0   20 200 140\" />\n");
964 	    fprintf (tfp, "<path d=\"M 0   60 200 180\" />\n");
965 	    fprintf (tfp, "<path d=\"M 0  100 200 220\" />\n");
966 	    fprintf (tfp, "<path d=\"M 0  140 200 260\" />\n");
967 	    fprintf (tfp, "<path d=\"M 0  180 200 300\" />\n");
968 	break;
969 
970 	case 2:
971 	    fprintf (tfp, "<path d=\"M 200 -100 0  20\" />\n");
972 	    fprintf (tfp, "<path d=\"M 200  -60 0  60\" />\n");
973 	    fprintf (tfp, "<path d=\"M 200  -20 0 100\" />\n");
974 	    fprintf (tfp, "<path d=\"M 200   20 0 140\" />\n");
975 	    fprintf (tfp, "<path d=\"M 200   60 0 180\" />\n");
976 	    fprintf (tfp, "<path d=\"M 200  100 0 220\" />\n");
977 	    fprintf (tfp, "<path d=\"M 200  140 0 260\" />\n");
978 	    fprintf (tfp, "<path d=\"M 200  180 0 300\" />\n");
979 	break;
980 
981 	case 3:
982         fprintf (tfp, "<path d=\"M 0 -100 200 20\" />\n");
983         fprintf (tfp, "<path d=\"M 200 -100 0 20\" />\n");
984         fprintf (tfp, "<path d=\"M 0 -60 200 60\" />\n");
985         fprintf (tfp, "<path d=\"M 200 -60 0 60\" />\n");
986         fprintf (tfp, "<path d=\"M 0 -20 200 100\" />\n");
987         fprintf (tfp, "<path d=\"M 200 -20 0 100\" />\n");
988         fprintf (tfp, "<path d=\"M 0 20 200 140\" />\n");
989         fprintf (tfp, "<path d=\"M 200 20 0 140\" />\n");
990         fprintf (tfp, "<path d=\"M 0 60 200 180\" />\n");
991         fprintf (tfp, "<path d=\"M 200 60 0 180\" />\n");
992         fprintf (tfp, "<path d=\"M 0 100 200 220\" />\n");
993         fprintf (tfp, "<path d=\"M 200 100 0 220\" />\n");
994         fprintf (tfp, "<path d=\"M 0 140 200 260\" />\n");
995         fprintf (tfp, "<path d=\"M 200 140 0 260\" />\n");
996         fprintf (tfp, "<path d=\"M 0 180 200 300\" />\n");
997         fprintf (tfp, "<path d=\"M 200 180 0 300\" />\n");
998 	break;
999 
1000 	case 4:
1001 	fprintf (tfp, "<path d=\"M 100 0 200 100\" />\n");
1002 	fprintf (tfp, "<path d=\"M 0 0 200 200\" />\n");
1003 	fprintf (tfp, "<path d=\"M 0 100 100 200\" />\n");
1004 	break;
1005 
1006 	case 5:
1007 	fprintf (tfp, "<path d=\"M 100 0 0 100\" />\n");
1008 	fprintf (tfp, "<path d=\"M 200 0 0 200\" />\n");
1009 	fprintf (tfp, "<path d=\"M 200 100 100 200\" />\n");
1010 	break;
1011 
1012 	case 6:
1013 	fprintf (tfp, "<path d=\"M 100 0 200 100\" />\n");
1014 	fprintf (tfp, "<path d=\"M 0 0 200 200\" />\n");
1015 	fprintf (tfp, "<path d=\"M 0 100 100 200\" />\n");
1016 	fprintf (tfp, "<path d=\"M 100 0 0 100\" />\n");
1017 	fprintf (tfp, "<path d=\"M 200 0 0 200\" />\n");
1018 	fprintf (tfp, "<path d=\"M 200 100 100 200\" />\n");
1019 	break;
1020 
1021 	case 7:
1022 	fprintf (tfp, "<path d=\"M 0 0 0 50\" />\n");
1023 	fprintf (tfp, "<path d=\"M 0 50 200 50\" />\n");
1024 	fprintf (tfp, "<path d=\"M 100 50 100 150\" />\n");
1025 	fprintf (tfp, "<path d=\"M 0 150 200 150\" />\n");
1026 	fprintf (tfp, "<path d=\"M 0 150 0 200\" />\n");
1027 	break;
1028 
1029 	case 8:
1030 	fprintf (tfp, "<path d=\"M 0 0 50 0\" />\n");
1031 	fprintf (tfp, "<path d=\"M 50 0 50 200\" />\n");
1032 	fprintf (tfp, "<path d=\"M 50 100 150 100\" />\n");
1033 	fprintf (tfp, "<path d=\"M 150 0 150 200\" />\n");
1034 	fprintf (tfp, "<path d=\"M 150 0 200 0\" />\n");
1035 	break;
1036 
1037 	case 9:
1038 	fprintf (tfp, "<path d=\"M 0 50 200 50\" />\n");
1039 	fprintf (tfp, "<path d=\"M 0 150 200 150\" />\n");
1040 	break;
1041 
1042 	case 10:
1043 	fprintf (tfp, "<path d=\"M 50 0 50 200\" />\n");
1044 	fprintf (tfp, "<path d=\"M 150 0 150 200\" />\n");
1045 	break;
1046 
1047 	case 11:
1048 	fprintf (tfp, "<path d=\"M 0 50 200 50\" />\n");
1049 	fprintf (tfp, "<path d=\"M 0 150 200 150\" />\n");
1050 	fprintf (tfp, "<path d=\"M 50 0 50 200\" />\n");
1051 	fprintf (tfp, "<path d=\"M 150 0 150 200\" />\n");
1052 	break;
1053 
1054 	case 12:
1055 	fprintf (tfp, "<path d=\"M 175 0 150 50\" />\n");
1056 	fprintf (tfp, "<path d=\"M 0 50 200 50\" />\n");
1057 	fprintf (tfp, "<path d=\"M 100 50 50 150\" />\n");
1058 	fprintf (tfp, "<path d=\"M 0 150 200 150\" />\n");
1059 	fprintf (tfp, "<path d=\"M 200 150 175 200\" />\n");
1060 	break;
1061 
1062 	case 13:
1063 	fprintf (tfp, "<path d=\"M 13 0 25 50\" />\n");
1064 	fprintf (tfp, "<path d=\"M 0 50 200 50\" />\n");
1065 	fprintf (tfp, "<path d=\"M 100 50 125 150\" />\n");
1066 	fprintf (tfp, "<path d=\"M 0 150 200 150\" />\n");
1067 	fprintf (tfp, "<path d=\"M 0 150 13 200\" />\n");
1068 	break;
1069 
1070 
1071 	case 14:
1072 	fprintf (tfp, "<path d=\"M 0 13 50 25\" />\n");
1073 	fprintf (tfp, "<path d=\"M 50 0 50 200\" />\n");
1074 	fprintf (tfp, "<path d=\"M 50 100 150 125\" />\n");
1075 	fprintf (tfp, "<path d=\"M 150 0 150 200\" />\n");
1076 	fprintf (tfp, "<path d=\"M 150 0 200 13\" />\n");
1077 	break;
1078 
1079 	case 15:
1080 	fprintf (tfp, "<path d=\"M 0 13 50 0\" />\n");
1081 	fprintf (tfp, "<path d=\"M 50 0 50 200\" />\n");
1082 	fprintf (tfp, "<path d=\"M 50 125 150 100\" />\n");
1083 	fprintf (tfp, "<path d=\"M 150 0 150 200\" />\n");
1084 	fprintf (tfp, "<path d=\"M 150 25 200 13\" />\n");
1085 	break;
1086 
1087 	case 16:
1088 	fprintf (tfp, "<path d=\"M 0 50 A 50 50 0 1 0 100 50\" />\n");
1089 	fprintf (tfp, "<path d=\"M 100 50 A 50 50 0 1 0 200 50\" />\n");
1090 	fprintf (tfp, "<path d=\"M 50 100 A 50 50 0 1 0 150 100\" />\n");
1091 	fprintf (tfp, "<path d=\"M 0 150 A 50 50 0 0 0 50 100\" />\n");
1092 	fprintf (tfp, "<path d=\"M 150 100 A 50 50 0 1 0 200 50\" />\n");
1093 	fprintf (tfp, "<path d=\"M 50 0 A 50 50 0 1 0 150 0\" />\n");
1094 	fprintf (tfp, "<path d=\"M 150 0 A 50 50 0 0 0 200 50\" />\n");
1095 	fprintf (tfp, "<path d=\"M 0 50 A 50 50 0 0 0 50 0\" />\n");
1096 	fprintf (tfp, "<path d=\"M 0 150 A 50 50 0 1 0 100 150\" />\n");
1097 	fprintf (tfp, "<path d=\"M 100 150 A 50 50 0 1 0 200 150\" />\n");
1098 	break;
1099 
1100 	case 17:
1101 	fprintf (tfp, "<g transform=\"scale(0.5)\" >\n");
1102 	fprintf (tfp, "<path d=\"M 0 50 A 50 50 0 1 0 100 50\" />\n");
1103 	fprintf (tfp, "<path d=\"M 100 50 A 50 50 0 1 0 200 50\" />\n");
1104 	fprintf (tfp, "<path d=\"M 50 100 A 50 50 0 1 0 150 100\" />\n");
1105 	fprintf (tfp, "<path d=\"M 0 150 A 50 50 0 0 0 50 100\" />\n");
1106 	fprintf (tfp, "<path d=\"M 150 100 A 50 50 0 1 0 200 50\" />\n");
1107 	fprintf (tfp, "<path d=\"M 50 0 A 50 50 0 1 0 150 0\" />\n");
1108 	fprintf (tfp, "<path d=\"M 150 0 A 50 50 0 0 0 200 50\" />\n");
1109 	fprintf (tfp, "<path d=\"M 0 50 A 50 50 0 0 0 50 0\" />\n");
1110 	fprintf (tfp, "<path d=\"M 0 150 A 50 50 0 1 0 100 150\" />\n");
1111 	fprintf (tfp, "<path d=\"M 100 150 A 50 50 0 1 0 200 150\" />\n");
1112 	fprintf (tfp, "</g>\n");
1113 	break;
1114 
1115 	case 18:
1116 	fprintf (tfp, "<circle cx=\"100\" cy=\"100\" r=\"100\" />\n");
1117 	break;
1118 
1119 	case 19:
1120 	fprintf (tfp, "<path d=\"M 0 50 45 0 105 0 140 50 200 50 \" />\n");
1121 	fprintf (tfp, "<path d=\"M 0 50 45 100 105 100 140 50 200 50\" />\n");
1122 	fprintf (tfp, "<path d=\"M 0 150 45 100 105 100 140 150 200 150\" />\n");
1123 	fprintf (tfp, "<path d=\"M 0 150 45 200 105 200 140 150 200 150\" />\n");
1124 	break;
1125 
1126 	case 20:
1127 	fprintf (tfp, "<path d=\"M 0 70 65 0 140 0 200 70 \" />\n");
1128 	fprintf (tfp, "<path d=\"M 0 70 0 130 65 200 140 200 200 130 200 70\" />\n");
1129 	break;
1130 
1131 	case 21:
1132 	fprintf (tfp, "<path d=\"M 50 0 75 25 100 0 M 150 0 175 25 200 0\" />\n");
1133 	fprintf (tfp, "<path d=\"M 0 50 25 25 75 75 125 25 175 75 200 50\" />\n");
1134 	fprintf (tfp, "<path d=\"M 0 100 25 75 75 125 125 75 175 125 200 100\" />\n");
1135 	fprintf (tfp, "<path d=\"M 0 150 25 125 75 175 125 125 175 175 200 150\" />\n");
1136 	fprintf (tfp, "<path d=\"M 0 200 25 175 75 225 125 175 175 225 200 200\" />\n");
1137 	break;
1138 
1139 	case 22:
1140 	fprintf (tfp, "<path d=\"M 0 50 25 75 0 100 M 0 150 25 175 0 200\" />\n");
1141 	fprintf (tfp, "<path d=\"M 50 0 25 25 75 75 25 125 75 175 50 200\" />\n");
1142 	fprintf (tfp, "<path d=\"M 100 0 75 25 125 75 75 125 125 175 100 200\" />\n");
1143 	fprintf (tfp, "<path d=\"M 150 0 125 25 175 75 125 125 175 175 150 200\" />\n");
1144 	fprintf (tfp, "<path d=\"M 200 0 175 25 225 75 175 125 225 175 200 200\" />\n");
1145 	break;
1146 
1147 	}
1148 	fprintf (tfp, "</pattern>\n");
1149 	fprintf (tfp, "</defs>\n");
1150 
1151 	return;
1152 
1153 } /* generate_tile */
1154 
svg_dash(int style,double val)1155 void svg_dash(int style, double val)
1156 {
1157 	    fprintf (tfp, "stroke-dasharray:");
1158 	    switch (style) {
1159 	      case 1:
1160 	      default:
1161 	          fprintf(tfp,"%d %d;",(int)(val*10*mag),(int)(val*10*mag));
1162 	          break;
1163              case 2:
1164                   fprintf(tfp,"10 %d;",(int)(val*10*mag));
1165                   break;
1166              case 3:
1167                   fprintf(tfp,"%d %d 10 %d;",(int)(val*10*mag),
1168                   (int)(val*5*mag),(int)(val*5*mag));
1169                   break;
1170              case 4:
1171                   fprintf(tfp,"%d %d 10 %d 10 %d;",(int)(val*10*mag),
1172                   (int)(val*3*mag),(int)(val*3*mag),(int)(val*3*mag));
1173                   break;
1174              case 5:
1175                   fprintf(tfp,"%d %d 10 %d 10 %d 10 %d;",(int)(val*10*mag),
1176                   (int)(val*3*mag),(int)(val*3*mag),(int)(val*3*mag),(int)(val*3*mag));
1177                   break;
1178              }
1179 }
1180 
1181 /* driver defs */
1182 
1183 struct driver dev_svg = {
1184     gensvg_option,
1185     gensvg_start,
1186     gendev_null,
1187     gensvg_arc,
1188     gensvg_ellipse,
1189     gensvg_line,
1190     gensvg_spline,
1191     gensvg_text,
1192     gensvg_end,
1193     INCLUDE_TEXT
1194 };
1195