Line data Source code
1 : /* Copyright (C) 2000 The PARI group.
2 :
3 : This file is part of the PARI/GP package.
4 :
5 : PARI/GP is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 2 of the License, or (at your option) any later
8 : version. It is distributed in the hope that it will be useful, but WITHOUT
9 : ANY WARRANTY WHATSOEVER.
10 :
11 : Check the License for details. You should have received a copy of it, along
12 : with the package; see the file 'COPYING'. If not, write to the Free Software
13 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 :
15 : /*******************************************************************/
16 : /* */
17 : /* PLOT ROUTINES */
18 : /* */
19 : /*******************************************************************/
20 : #include "pari.h"
21 : #include "paripriv.h"
22 : #include "rect.h"
23 :
24 : static void (*pari_get_plot)(PARI_plot *);
25 :
26 : /* no need for THREAD: OK to share this */
27 : static hashtable *rgb_colors = NULL;
28 :
29 : THREAD PariRect rectgraph[18]; /*NUMRECT*/
30 : static THREAD long current_color[18]; /*NUMRECT*/
31 :
32 : static long plotpoint_itype = 0, rectline_itype = 0;
33 :
34 : const long NUMRECT = 18;
35 : const long RECUR_MAXDEPTH = 10;
36 : const double RECUR_PREC = 0.001;
37 : const long DEFAULT_COLOR = 1, AXIS_COLOR = 2;
38 :
39 : enum {
40 : ROt_MV = 1, /* Move */
41 : ROt_PT, /* Point */
42 : ROt_LN, /* Line */
43 : ROt_BX, /* Box */
44 : ROt_FBX, /* Filled Box */
45 : ROt_MP, /* Multiple point */
46 : ROt_ML, /* Multiple lines */
47 : ROt_ST, /* String */
48 : ROt_PTT, /* Point type change */
49 : ROt_LNT, /* Line type change */
50 : ROt_PTS, /* Point size change */
51 : ROt_NULL, /* To be the start of the chain */
52 : };
53 :
54 : /* string justification */
55 : #define RoSTdirLEFT 0x00
56 : #define RoSTdirRIGHT 0x02
57 : #define RoSTdirHPOS_mask 0x03
58 : #define RoSTdirBOTTOM 0x00
59 : #define RoSTdirTOP 0x08
60 : #define RoSTdirVPOS_mask 0x0c
61 : #define RoSTdirHGAP 0x10
62 : #define RoSTdirVGAP 0x20
63 :
64 : /* ploth flags */
65 : #define PLOT_PARAMETRIC 0x00001
66 : #define PLOT_RECURSIVE 0x00002
67 : #define PLOT_NO_RESCALE 0x00004
68 : #define PLOT_NO_AXE_X 0x00008
69 : #define PLOT_NO_AXE_Y 0x00010
70 : #define PLOT_NO_FRAME 0x00020
71 : #define PLOT_POINTS 0x00040
72 : #define PLOT_POINTS_LINES 0x00080
73 : #define PLOT_SPLINES 0x00100
74 : #define PLOT_NO_TICK_X 0x00200
75 : #define PLOT_NO_TICK_Y 0x00400
76 : #define PLOT_NODOUBLETICK 0x00800
77 : #define PLOT_COMPLEX 0x01000
78 : #define PLOT_NOMINMAX 0x02000
79 :
80 : #define PLOT_PARA 0x80000
81 :
82 :
83 : INLINE long
84 158839 : DTOL(double t) { return (long)(t + 0.5); }
85 :
86 : static const long PS_WIDTH = 1120 - 60; /* 1400 - 60 for hi-res */
87 : static const long PS_HEIGH = 800 - 40; /* 1120 - 60 for hi-res */
88 : static const long PS_SCALE = 1000; /* Allowing 64x zoom on 500ppi */
89 :
90 : static void
91 0 : _psdraw_scale(PARI_plot *T, GEN w, GEN x, GEN y)
92 : {
93 0 : pari_sp av = avma;
94 0 : FILE *F = fopen(current_psfile, "a");
95 0 : if (!F) pari_err_FILE("postscript file",current_psfile);
96 0 : fputs(rect2ps(w,x,y,T), F);
97 0 : fclose(F); set_avma(av);
98 0 : }
99 : static void
100 0 : _psdraw(PARI_plot *T, GEN w, GEN x, GEN y)
101 0 : { (void)T; _psdraw_scale(NULL,w,x,y); }
102 : static void
103 49 : pari_get_psplot(PARI_plot *T)
104 : {
105 49 : T->width = PS_WIDTH;
106 49 : T->height = PS_HEIGH;
107 49 : T->fheight= 15;
108 49 : T->fwidth = 6;
109 49 : T->hunit = 5;
110 49 : T->vunit = 5;
111 49 : T->dwidth = 0;
112 49 : T->dheight= 0;
113 49 : T->draw = NULL;
114 49 : }
115 : static void
116 86 : pari_get_svgplot(PARI_plot *T)
117 : {
118 86 : T->width = 480;
119 86 : T->height = 320;
120 86 : T->fheight = 12;
121 86 : T->fwidth = 6;
122 86 : T->hunit = 3;
123 86 : T->vunit = 3;
124 86 : T->dwidth = 0;
125 86 : T->dheight = 0;
126 86 : T->draw = NULL;
127 86 : }
128 :
129 : /********************************************************************/
130 : /** **/
131 : /** RECTPLOT FUNCTIONS **/
132 : /** **/
133 : /********************************************************************/
134 : void
135 1816 : pari_init_graphics(void) { pari_get_plot = &pari_get_svgplot; }
136 :
137 : void
138 1806 : pari_set_plot_engine(void (*plot)(PARI_plot *))
139 : {
140 : long n;
141 1806 : pari_get_plot = plot;
142 34314 : for (n = 0; n < NUMRECT; n++)
143 : {
144 32508 : PariRect *e = &rectgraph[n];
145 32508 : RHead(e) = RTail(e) = NULL;
146 32508 : RXsize(e) = RYsize(e) = 0;
147 : }
148 1806 : }
149 :
150 : void
151 1806 : pari_kill_plot_engine(void)
152 : {
153 : int i;
154 34314 : for (i=0; i<NUMRECT; i++)
155 : {
156 32508 : PariRect *e = &rectgraph[i];
157 32508 : if (RHead(e)) plotkill(i);
158 : }
159 1806 : if (rgb_colors)
160 : {
161 25 : pari_free((void*)rgb_colors->table);
162 25 : pari_free((void*)rgb_colors);
163 : }
164 1806 : }
165 :
166 : static PariRect *
167 24830 : check_rect(long ne)
168 : {
169 24830 : const char *f = "graphic function";
170 24830 : const long m = NUMRECT-1;
171 24830 : if (ne < 0)
172 8 : pari_err_DOMAIN(f, "rectwindow", "<", gen_0, stoi(ne));
173 24822 : else if (ne > m)
174 4 : pari_err_DOMAIN(f, "rectwindow", ">", stoi(m), stoi(ne));
175 : else
176 24818 : return &rectgraph[ne];
177 : return NULL;/*LCOV_EXCL_LINE*/
178 : }
179 :
180 : static PariRect *
181 24522 : check_rect_init(long ne)
182 : {
183 24522 : PariRect *e = check_rect(ne);
184 24514 : if (!RHead(e)) pari_err_TYPE("graphic function [use plotinit()]", stoi(ne));
185 24514 : return e;
186 : }
187 : static void
188 35743 : Rchain(PariRect *e, RectObj *z)
189 : {
190 35743 : if (!RHead(e)) RHead(e) = z; else RoNext(RTail(e)) = z;
191 35743 : RTail(e) = z;
192 35743 : RoNext(z) = NULL;
193 35743 : }
194 :
195 : static long
196 11174 : rgb_to_long(long r, long g, long b)
197 11174 : { return (r << 16) | (g << 8) | b; }
198 : /* c from graphcolormap */
199 : static long
200 11170 : colormap_to_color(long i)
201 : {
202 11170 : GEN c = GP_DATA->colormap;
203 11170 : long k = i+1, l = lg(c)-1;
204 : int r, g, b;
205 11170 : if (k > l)
206 4 : pari_err_COMPONENT("graphcolormap",">", stoi(l), stoi(k));
207 11166 : color_to_rgb(gel(c, k), &r,&g,&b);
208 11166 : return rgb_to_long(r, g, b);
209 : }
210 :
211 : static void
212 300 : initrect_i(long ne, long x, long y)
213 : {
214 : PariRect *e;
215 : RectObj *z;
216 :
217 300 : if (x <= 1) pari_err_DOMAIN("plotinit", "x", "<=", gen_1, stoi(x));
218 300 : if (y <= 1) pari_err_DOMAIN("plotinit", "y", "<=", gen_1, stoi(y));
219 300 : e = check_rect(ne); if (RHead(e)) plotkill(ne);
220 :
221 296 : current_color[ne] = colormap_to_color(DEFAULT_COLOR);
222 296 : z = (RectObj*) pari_malloc(sizeof(RectObj));
223 296 : RoType(z) = ROt_NULL;
224 296 : Rchain(e, z);
225 296 : RXsize(e) = x; RXcursor(e) = 0; RXscale(e) = 1; RXshift(e) = 0;
226 296 : RYsize(e) = y; RYcursor(e) = 0; RYscale(e) = 1; RYshift(e) = 0;
227 296 : }
228 : static long
229 180 : initrect_get_arg(GEN x, long dft)
230 : {
231 180 : if (!x) return dft;
232 110 : if (typ(x) != t_INT) pari_err_TYPE("plotinit",x);
233 110 : return itos(x);
234 : }
235 : void
236 90 : plotinit(long ne, GEN x, GEN y, long flag)
237 : {
238 90 : const long m = NUMRECT-3;
239 : long xi, yi;
240 : PARI_plot T;
241 :
242 90 : if (flag)
243 : {
244 0 : pari_get_plot(&T);
245 0 : xi = T.width -1; if (x) xi = DTOL(xi * gtodouble(x));
246 0 : yi = T.height-1; if (y) yi = DTOL(yi * gtodouble(y));
247 : }
248 : else
249 : {
250 90 : if (!x || !y) pari_get_plot(&T);
251 90 : xi = initrect_get_arg(x, T.width -1);
252 90 : yi = initrect_get_arg(y, T.height-1);
253 : }
254 90 : if (ne > m) pari_err_DOMAIN("plotinit", "rectwindow", ">", stoi(m), stoi(ne));
255 86 : initrect_i(ne, xi, yi);
256 82 : }
257 :
258 : GEN
259 47 : plotcursor(long ne)
260 : {
261 47 : PariRect *e = check_rect_init(ne);
262 47 : return mkvec2s((long)RXcursor(e), (long)RYcursor(e));
263 : }
264 :
265 : static void
266 164 : plotscale0(long ne, double x1, double x2, double y1, double y2)
267 : {
268 164 : PariRect *e = check_rect_init(ne);
269 : double x, y;
270 :
271 164 : x = RXshift(e) + RXscale(e) * RXcursor(e);
272 164 : y = RYshift(e) + RYscale(e) * RYcursor(e);
273 164 : RXscale(e) = RXsize(e)/(x2-x1); RXshift(e) = -x1*RXscale(e);
274 164 : RYscale(e) = RYsize(e)/(y1-y2); RYshift(e) = -y2*RYscale(e);
275 164 : RXcursor(e) = (x - RXshift(e)) / RXscale(e);
276 164 : RYcursor(e) = (y - RYshift(e)) / RYscale(e);
277 164 : }
278 : void
279 34 : plotscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2)
280 34 : { plotscale0(ne, gtodouble(x1), gtodouble(x2), gtodouble(y1), gtodouble(y2)); }
281 :
282 : static void
283 909 : plotmove0(long ne, double x, double y, long relative)
284 : {
285 909 : PariRect *e = check_rect_init(ne);
286 901 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj1P));
287 :
288 901 : if (relative) { RXcursor(e) += x; RYcursor(e) += y; }
289 883 : else { RXcursor(e) = x; RYcursor(e) = y; }
290 901 : RoType(z) = ROt_MV;
291 901 : RoMVx(z) = RXcursor(e) * RXscale(e) + RXshift(e);
292 901 : RoMVy(z) = RYcursor(e) * RYscale(e) + RYshift(e);
293 901 : Rchain(e, z);
294 901 : }
295 : static void
296 772 : _move(long ne, double x, double y)
297 772 : { plotmove0(ne,x,y,0); }
298 : void
299 119 : plotmove(long ne, GEN x, GEN y)
300 119 : { plotmove0(ne,gtodouble(x),gtodouble(y),0); }
301 : void
302 18 : plotrmove(long ne, GEN x, GEN y)
303 18 : { plotmove0(ne,gtodouble(x),gtodouble(y),1); }
304 :
305 : /* ROt_MV/ROt_PT */
306 : static void
307 36 : plotpoint0(long ne, double x, double y,long relative)
308 : {
309 36 : PariRect *e = check_rect_init(ne);
310 36 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj1P));
311 :
312 36 : if (relative) { RXcursor(e) += x; RYcursor(e) += y; }
313 18 : else { RXcursor(e) = x; RYcursor(e) = y; }
314 36 : RoPTx(z) = RXcursor(e)*RXscale(e) + RXshift(e);
315 36 : RoPTy(z) = RYcursor(e)*RYscale(e) + RYshift(e);
316 36 : RoType(z) = ( DTOL(RoPTx(z)) < 0
317 36 : || DTOL(RoPTy(z)) < 0 || DTOL(RoPTx(z)) > RXsize(e)
318 72 : || DTOL(RoPTy(z)) > RYsize(e) ) ? ROt_MV : ROt_PT;
319 36 : Rchain(e, z);
320 36 : RoCol(z) = current_color[ne];
321 36 : }
322 : static void
323 18 : plotpoint(long ne, GEN x, GEN y)
324 18 : { plotpoint0(ne,gtodouble(x),gtodouble(y),0); }
325 : void
326 18 : plotrpoint(long ne, GEN x, GEN y)
327 18 : { plotpoint0(ne,gtodouble(x),gtodouble(y),1); }
328 :
329 : GEN
330 8 : plotcolor(long ne, GEN c)
331 : {
332 8 : long t = typ(c), n = lg(GP_DATA->colormap)-2;
333 : int r, g, b;
334 8 : check_rect(ne);
335 8 : if (t == t_INT)
336 : {
337 8 : long i = itos(c);
338 8 : if (i < 0) pari_err_DOMAIN("plotcolor", "color", "<", gen_0, c);
339 8 : if (i > n) pari_err_DOMAIN("plotcolor", "color", ">", stoi(n), c);
340 8 : c = gel(GP_DATA->colormap,i+1);
341 : }
342 : else
343 : {
344 0 : if (t == t_VEC) { c = ZV_to_zv(c); t = typ(c); }
345 0 : if (t != t_VECSMALL && t != t_STR) pari_err_TYPE("plotcolor",c);
346 : }
347 8 : color_to_rgb(c, &r,&g,&b);
348 8 : current_color[ne] = rgb_to_long(r,g,b);
349 8 : return mkvec3s(r, g, b);
350 : }
351 :
352 : /* ROt_MV/ROt_LN */
353 : static void
354 250 : rectline0(long ne, double gx2, double gy2, long relative)
355 : {
356 : double dx, dy, dxy, xmin, xmax, ymin, ymax, x1, y1, x2, y2;
357 250 : PariRect *e = check_rect_init(ne);
358 250 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj2P));
359 250 : const double c = 1 + 1e-10;
360 :
361 250 : x1 = RXcursor(e)*RXscale(e) + RXshift(e);
362 250 : y1 = RYcursor(e)*RYscale(e) + RYshift(e);
363 250 : if (relative)
364 18 : { RXcursor(e)+=gx2; RYcursor(e)+=gy2; }
365 : else
366 232 : { RXcursor(e)=gx2; RYcursor(e)=gy2; }
367 250 : x2 = RXcursor(e)*RXscale(e) + RXshift(e);
368 250 : y2 = RYcursor(e)*RYscale(e) + RYshift(e);
369 250 : xmin = maxdd(mindd(x1,x2),0); xmax = mindd(maxdd(x1,x2),RXsize(e));
370 250 : ymin = maxdd(mindd(y1,y2),0); ymax = mindd(maxdd(y1,y2),RYsize(e));
371 250 : dxy = x1*y2 - y1*x2; dx = x2-x1; dy = y2-y1;
372 250 : if (dy)
373 : {
374 141 : double a = (dxy + RYsize(e)*dx) / dy, b = dxy / dy;
375 141 : if (dx*dy < 0)
376 18 : { xmin=maxdd(xmin,a); xmax=mindd(xmax,b); }
377 : else
378 123 : { xmin=maxdd(xmin,b); xmax=mindd(xmax,a); }
379 : }
380 250 : if (dx)
381 : {
382 145 : double a = (RXsize(e)*dy - dxy) / dx, b = -dxy / dx;
383 145 : if (dx*dy < 0)
384 18 : { ymin=maxdd(ymin,a); ymax=mindd(ymax,b); }
385 : else
386 127 : { ymin=maxdd(ymin,b); ymax=mindd(ymax,a); }
387 : }
388 250 : RoLNx1(z) = xmin;
389 250 : RoLNx2(z) = xmax;
390 250 : if (dx*dy < 0) { RoLNy1(z) = ymax; RoLNy2(z) = ymin; }
391 232 : else { RoLNy1(z) = ymin; RoLNy2(z) = ymax; }
392 250 : RoType(z) = (xmin>xmax*c || ymin>ymax*c) ? ROt_MV : ROt_LN;
393 250 : Rchain(e, z);
394 250 : RoCol(z) = current_color[ne];
395 250 : }
396 : static void
397 214 : _line(long ne, double x, double y)
398 214 : { rectline0(ne, x, y, 0); }
399 : void
400 18 : plotline(long ne, GEN gx2, GEN gy2)
401 18 : { rectline0(ne, gtodouble(gx2), gtodouble(gy2),0); }
402 : void
403 18 : plotrline(long ne, GEN gx2, GEN gy2)
404 18 : { rectline0(ne, gtodouble(gx2), gtodouble(gy2),1); }
405 :
406 : enum {
407 : TICKS_CLOCKW = 1, /* Draw in clockwise direction */
408 : TICKS_ACLOCKW = 2, /* Draw in anticlockwise direction */
409 : TICKS_ENDSTOO = 4, /* Draw at endspoints if needed */
410 : TICKS_NODOUBLE = 8 /* Do not draw double-length ticks */
411 : };
412 :
413 : /* Given coordinates of ends of a line, and labels l1 l2 attached to the
414 : * ends, plot ticks where the label coordinate takes "round" values */
415 : static void
416 520 : rectticks(PARI_plot *WW, long ne, double dx1, double dy1, double dx2,
417 : double dy2, double l1, double l2, long flags)
418 : {
419 : long dx, dy, dxy, dxy1, x1, y1, x2, y2, nticks, n, n1, dn;
420 : double minstep, maxstep, step, l_min, l_max, minl, maxl, dl, dtx, dty, x, y;
421 : double ddx, ddy;
422 520 : const double mult[3] = { 2./1., 5./2., 10./5. };
423 520 : PariRect *e = check_rect_init(ne);
424 520 : int do_double = !(flags & TICKS_NODOUBLE);
425 :
426 520 : x1 = DTOL(dx1*RXscale(e) + RXshift(e));
427 520 : y1 = DTOL(dy1*RYscale(e) + RYshift(e));
428 520 : x2 = DTOL(dx2*RXscale(e) + RXshift(e));
429 520 : y2 = DTOL(dy2*RYscale(e) + RYshift(e));
430 520 : dx = x2 - x1; if (dx < 0) dx = -dx;
431 520 : dy = y2 - y1; if (dy < 0) dy = -dy;
432 520 : dxy1 = maxss(dx, dy);
433 520 : dx /= WW->hunit;
434 520 : dy /= WW->vunit;
435 520 : if (dx > 1000 || dy > 1000)
436 0 : dxy = 1000; /* avoid overflow */
437 : else
438 520 : dxy = usqrt(dx*dx + dy*dy);
439 520 : nticks = (long) ((dxy + 2.5)/4);
440 520 : if (!nticks) return;
441 :
442 : /* Find nticks (or less) "round" numbers between l1 and l2. For our purpose
443 : * round numbers have "last significant" decimal digit either
444 : * - any;
445 : * - even;
446 : * - divisible by 5.
447 : * We need to choose which alternative is better. */
448 520 : if (l1 < l2)
449 260 : l_min = l1, l_max = l2;
450 : else
451 260 : l_min = l2, l_max = l1;
452 520 : minstep = (l_max - l_min)/(nticks + 1);
453 520 : maxstep = 2.5*(l_max - l_min);
454 520 : step = exp(log(10.) * floor(log10(minstep)));
455 520 : if (!(flags & TICKS_ENDSTOO)) {
456 520 : double d = 2*(l_max - l_min)/dxy1; /* Two pixels off */
457 520 : l_min += d;
458 520 : l_max -= d;
459 : }
460 520 : for (n = 0; ; n++)
461 : {
462 1648 : if (step >= maxstep) return;
463 :
464 1648 : if (step >= minstep) {
465 520 : minl = ceil(l_min/step);
466 520 : maxl = floor(l_max/step);
467 520 : if (minl <= maxl && maxl - minl + 1 <= nticks) {
468 520 : nticks = (long) (maxl - minl + 1);
469 520 : l_min = minl * step;
470 520 : l_max = maxl * step; break;
471 : }
472 : }
473 1128 : step *= mult[ n % 3 ];
474 : }
475 : /* Where to position doubleticks. Variants:
476 : * small: each 5, double: each 10 ; n=2 mod 3
477 : * small: each 2, double: each 10 ; n=1 mod 3
478 : * small: each 1, double: each 5 */
479 520 : dn = (n % 3 == 2)? 2: 5;
480 520 : n1 = ((long)minl) % dn; /* unused if do_double = FALSE */
481 :
482 : /* now l_min and l_max keep min/max values of l with ticks, and nticks is
483 : the number of ticks to draw. */
484 520 : if (nticks == 1) ddx = ddy = 0; /* -Wall */
485 : else {
486 520 : dl = (l_max - l_min)/(nticks - 1);
487 520 : ddx = (dx2 - dx1) * dl / (l2 - l1);
488 520 : ddy = (dy2 - dy1) * dl / (l2 - l1);
489 : }
490 520 : x = dx1 + (dx2 - dx1) * (l_min - l1) / (l2 - l1);
491 520 : y = dy1 + (dy2 - dy1) * (l_min - l1) / (l2 - l1);
492 : /* assume hunit and vunit form a square. For clockwise ticks: */
493 520 : dtx = WW->hunit * dy/dxy * (y2 > y1 ? 1 : -1); /* y-coord runs down */
494 520 : dty = WW->vunit * dx/dxy * (x2 > x1 ? 1 : -1);
495 12716 : for (n = 0; n < nticks; n++, x += ddx, y += ddy) {
496 12196 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj2P));
497 12196 : double lunit = WW->hunit > 1 ? 1.5 : 2;
498 12196 : double l = (do_double && (n + n1) % dn == 0) ? lunit: 1;
499 : double x1, x2, y1, y2;
500 12196 : x1 = x2 = x*RXscale(e) + RXshift(e);
501 12196 : y1 = y2 = y*RYscale(e) + RYshift(e);
502 12196 : if (flags & TICKS_CLOCKW) { x1 += dtx*l; y1 -= dty*l; }
503 12196 : if (flags & TICKS_ACLOCKW) { x2 -= dtx*l; y2 += dty*l; }
504 12196 : RoLNx1(z) = x1; RoLNy1(z) = y1;
505 12196 : RoLNx2(z) = x2; RoLNy2(z) = y2;
506 12196 : RoType(z) = ROt_LN;
507 12196 : Rchain(e, z);
508 12196 : RoCol(z) = current_color[ne];
509 : }
510 : }
511 :
512 : static void
513 166 : rectbox0(long ne, double gx2, double gy2, long relative, long filled)
514 : {
515 : double xx, yy, x1, y1, x2, y2, xmin, ymin, xmax, ymax;
516 166 : PariRect *e = check_rect_init(ne);
517 166 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj2P));
518 :
519 166 : x1 = RXcursor(e)*RXscale(e) + RXshift(e);
520 166 : y1 = RYcursor(e)*RYscale(e) + RYshift(e);
521 166 : if (relative)
522 18 : { xx = RXcursor(e)+gx2; yy = RYcursor(e)+gy2; }
523 : else
524 148 : { xx = gx2; yy = gy2; }
525 166 : x2 = xx*RXscale(e) + RXshift(e);
526 166 : y2 = yy*RYscale(e) + RYshift(e);
527 166 : xmin = maxdd(mindd(x1,x2),0); xmax = mindd(maxdd(x1,x2),RXsize(e));
528 166 : ymin = maxdd(mindd(y1,y2),0); ymax = mindd(maxdd(y1,y2),RYsize(e));
529 :
530 166 : RoType(z) = filled ? ROt_FBX: ROt_BX;
531 166 : RoBXx1(z) = xmin; RoBXy1(z) = ymin;
532 166 : RoBXx2(z) = xmax; RoBXy2(z) = ymax;
533 166 : Rchain(e, z);
534 166 : RoCol(z) = current_color[ne];
535 166 : }
536 : static void
537 130 : _box(long ne, double x, double y)
538 130 : { rectbox0(ne, x, y, 0, 0); }
539 : void
540 18 : plotbox(long ne, GEN gx2, GEN gy2, long f)
541 18 : { rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 0, f); }
542 : void
543 18 : plotrbox(long ne, GEN gx2, GEN gy2, long f)
544 18 : { rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 1, f); }
545 :
546 : static void
547 36063 : freeobj(RectObj *z) {
548 36063 : switch(RoType(z)) {
549 10594 : case ROt_MP: case ROt_ML:
550 10594 : pari_free(RoMPxs(z));
551 10594 : pari_free(RoMPys(z)); break;
552 504 : case ROt_ST:
553 504 : pari_free(RoSTs(z)); break;
554 : }
555 36063 : pari_free(z);
556 36063 : }
557 :
558 : void
559 296 : plotkill(long ne)
560 : {
561 : RectObj *z, *t;
562 296 : PariRect *e = check_rect_init(ne);
563 :
564 296 : z = RHead(e);
565 296 : RHead(e) = RTail(e) = NULL;
566 296 : RXsize(e) = RYsize(e) = 0;
567 296 : RXcursor(e) = RYcursor(e) = 0;
568 296 : RXscale(e) = RYscale(e) = 1;
569 296 : RXshift(e) = RYshift(e) = 0;
570 36315 : while (z) { t = RoNext(z); freeobj(z); z = t; }
571 296 : }
572 :
573 : /* ROt_MP */
574 : static void
575 36 : plotpoints0(long ne, double *X, double *Y, long lx)
576 : {
577 : double *px, *py;
578 36 : long i, cp=0;
579 36 : PariRect *e = check_rect_init(ne);
580 36 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObjMP));
581 :
582 36 : RoMPxs(z) = px = (double*) pari_malloc(lx*sizeof(double));
583 36 : RoMPys(z) = py = (double*) pari_malloc(lx*sizeof(double));
584 3620 : for (i=0; i<lx; i++)
585 : {
586 3584 : double x = RXscale(e)*X[i] + RXshift(e);
587 3584 : double y = RYscale(e)*Y[i] + RYshift(e);
588 3584 : if (x >= 0 && y >= 0 && x <= RXsize(e) && y <= RYsize(e))
589 : {
590 3582 : px[cp] = x; py[cp] = y; cp++;
591 : }
592 : }
593 36 : RoType(z) = ROt_MP;
594 36 : RoMPcnt(z) = cp;
595 36 : Rchain(e, z);
596 36 : RoCol(z) = current_color[ne];
597 36 : }
598 : void
599 36 : plotpoints(long ne, GEN X, GEN Y)
600 : {
601 36 : pari_sp av = avma;
602 : double *px, *py;
603 : long i, lx;
604 :
605 36 : if (!is_vec_t(typ(X)) || !is_vec_t(typ(Y))) { plotpoint(ne, X, Y); return; }
606 18 : lx = lg(X); if (lg(Y) != lx) pari_err_DIM("plotpoints");
607 18 : lx--; if (!lx) return;
608 :
609 18 : px = (double*)stack_malloc_align(lx*sizeof(double), sizeof(double)); X++;
610 18 : py = (double*)stack_malloc_align(lx*sizeof(double), sizeof(double)); Y++;
611 198 : for (i=0; i<lx; i++)
612 : {
613 180 : px[i] = gtodouble(gel(X,i));
614 180 : py[i] = gtodouble(gel(Y,i));
615 : }
616 18 : plotpoints0(ne,px,py,lx); set_avma(av);
617 : }
618 :
619 : /* ROt_ML */
620 : static void
621 10518 : rectlines0(long ne, double *x, double *y, long lx, long flag)
622 : {
623 : long i,I;
624 : double *ptx,*pty;
625 10518 : PariRect *e = check_rect_init(ne);
626 10518 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObj2P));
627 :
628 10518 : I = flag ? lx+1 : lx;
629 10518 : ptx = (double*) pari_malloc(I*sizeof(double));
630 10518 : pty = (double*) pari_malloc(I*sizeof(double));
631 226436 : for (i=0; i<lx; i++)
632 : {
633 215918 : ptx[i] = RXscale(e)*x[i] + RXshift(e);
634 215918 : pty[i] = RYscale(e)*y[i] + RYshift(e);
635 : }
636 10518 : if (flag)
637 : {
638 0 : ptx[i] = RXscale(e)*x[0] + RXshift(e);
639 0 : pty[i] = RYscale(e)*y[0] + RYshift(e);
640 : }
641 10518 : Rchain(e, z);
642 10518 : RoType(z) = ROt_ML;
643 10518 : RoMLcnt(z) = I;
644 10518 : RoMLxs(z) = ptx;
645 10518 : RoMLys(z) = pty;
646 10518 : RoCol(z) = current_color[ne];
647 10518 : }
648 : void
649 36 : plotlines(long ne, GEN X, GEN Y, long flag)
650 : {
651 36 : pari_sp av = avma;
652 : double *x, *y;
653 : long i, lx;
654 :
655 36 : if (!is_vec_t(typ(X)) || !is_vec_t(typ(Y))) { plotline(ne, X, Y); return; }
656 18 : lx = lg(X); if (lg(Y) != lx) pari_err_DIM("plotlines");
657 18 : lx--; if (!lx) return;
658 :
659 18 : x = (double*)stack_malloc_align(lx*sizeof(double), sizeof(double)); X++;
660 18 : y = (double*)stack_malloc_align(lx*sizeof(double), sizeof(double)); Y++;
661 108 : for (i=0; i<lx; i++)
662 : {
663 90 : x[i] = gtodouble(gel(X,i));
664 90 : y[i] = gtodouble(gel(Y,i));
665 : }
666 18 : rectlines0(ne,x,y,lx,flag); set_avma(av);
667 : }
668 :
669 : /* ROt_ST */
670 : void
671 464 : plotstring(long ne, char *str, long dir)
672 : {
673 464 : PariRect *e = check_rect_init(ne);
674 464 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObjST));
675 464 : long l = strlen(str);
676 464 : char *s = (char *) pari_malloc(l+1);
677 :
678 464 : memcpy(s,str,l+1);
679 464 : RoType(z) = ROt_ST;
680 464 : RoSTl(z) = l;
681 464 : RoSTs(z) = s;
682 464 : RoSTx(z) = RXscale(e)*RXcursor(e)+RXshift(e);
683 464 : RoSTy(z) = RYscale(e)*RYcursor(e)+RYshift(e);
684 464 : RoSTdir(z) = dir;
685 464 : Rchain(e, z);
686 464 : RoCol(z) = current_color[ne];
687 464 : }
688 :
689 : /* ROt_PTT */
690 : void
691 18 : plotpointtype(long ne, long type)
692 : {
693 18 : if (ne == -1) plotpoint_itype = type;
694 : else {
695 18 : PariRect *e = check_rect_init(ne);
696 18 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObjPN));
697 18 : RoType(z) = ROt_PTT;
698 18 : RoPTTpen(z) = type;
699 18 : Rchain(e, z);
700 : }
701 18 : }
702 :
703 : /* ROt_PTS. FIXME: this function is a noop, since no graphic driver implement
704 : * this code. ne == -1 (change globally). */
705 : void
706 0 : plotpointsize(long ne, GEN size)
707 : {
708 0 : if (ne == -1) { /*do nothing*/ }
709 : else {
710 0 : PariRect *e = check_rect_init(ne);
711 0 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObjPS));
712 0 : RoType(z) = ROt_PTS;
713 0 : RoPTSsize(z) = gtodouble(size);
714 0 : Rchain(e, z);
715 : }
716 0 : }
717 :
718 : void
719 10862 : plotlinetype(long ne, long type)
720 : {
721 10862 : if (ne == -1) rectline_itype = type;
722 : else {
723 10862 : PariRect *e = check_rect_init(ne);
724 10862 : RectObj *z = (RectObj*) pari_malloc(sizeof(RectObjPN));
725 10862 : RoType(z) = ROt_LNT;
726 10862 : RoLNTpen(z) = type;
727 10862 : Rchain(e, z);
728 : }
729 10862 : }
730 :
731 : #define RECT_CP_RELATIVE 0x1
732 : #define RECT_CP_NW 0x0
733 : #define RECT_CP_SW 0x2
734 : #define RECT_CP_SE 0x4
735 : #define RECT_CP_NE 0x6
736 :
737 : static double*
738 0 : cpd(double* R, size_t t)
739 0 : { void *o = pari_malloc(t * sizeof(double)); memcpy(o,R,t); return (double*)o; }
740 : static void*
741 460 : cp(void* R, size_t t)
742 460 : { void *o = pari_malloc(t); memcpy(o,R,t); return o; }
743 : void
744 36 : plotcopy(long source, long dest, GEN xoff, GEN yoff, long flag)
745 : {
746 36 : PariRect *s = check_rect_init(source), *d = check_rect_init(dest);
747 36 : RectObj *R, *tail = RTail(d);
748 : long i, x, y;
749 36 : if (flag & RECT_CP_RELATIVE) {
750 32 : double xd = gtodouble(xoff), yd = gtodouble(yoff);
751 : PARI_plot T;
752 32 : if (xd > 1) pari_err_DOMAIN("plotcopy","dx",">",gen_1,xoff);
753 28 : if (xd < 0) pari_err_DOMAIN("plotcopy","dx","<",gen_0,xoff);
754 24 : if (yd > 1) pari_err_DOMAIN("plotcopy","dy",">",gen_1,yoff);
755 20 : if (yd < 0) pari_err_DOMAIN("plotcopy","dy","<",gen_0,yoff);
756 16 : pari_get_plot(&T);
757 16 : x = DTOL(xd * (T.width-1));
758 16 : y = DTOL(yd * (T.height-1));
759 : } else {
760 4 : if (typ(xoff) != t_INT) pari_err_TYPE("plotcopy",xoff);
761 4 : if (typ(yoff) != t_INT) pari_err_TYPE("plotcopy",yoff);
762 4 : x = itos(xoff);
763 4 : y = itos(yoff);
764 : }
765 20 : switch (flag & ~RECT_CP_RELATIVE)
766 : {
767 8 : case RECT_CP_NW: break;
768 4 : case RECT_CP_SW: y = RYsize(d) - RYsize(s) - y; break;
769 4 : case RECT_CP_SE: y = RYsize(d) - RYsize(s) - y; /* fall through */
770 8 : case RECT_CP_NE: x = RXsize(d) - RXsize(s) - x; break;
771 : }
772 360 : for (R = RHead(s); R; R = RoNext(R))
773 : {
774 : RectObj *o;
775 340 : switch(RoType(R))
776 : {
777 40 : case ROt_PT:
778 40 : o = (RectObj*)cp(R, sizeof(RectObj1P));
779 40 : RoPTx(o) += x; RoPTy(o) += y;
780 40 : break;
781 80 : case ROt_LN: case ROt_BX: case ROt_FBX:
782 80 : o = (RectObj*)cp(R, sizeof(RectObj2P));
783 80 : RoLNx1(o) += x; RoLNy1(o) += y;
784 80 : RoLNx2(o) += x; RoLNy2(o) += y;
785 80 : break;
786 40 : case ROt_MP: case ROt_ML:
787 40 : o = (RectObj*)cp(R, sizeof(RectObjMP));
788 40 : RoMPxs(o) = (double*)cp(RoMPxs(R), sizeof(double)*RoMPcnt(o));
789 40 : RoMPys(o) = (double*)cp(RoMPys(R), sizeof(double)*RoMPcnt(o));
790 340 : for (i=0; i<RoMPcnt(o); i++) { RoMPxs(o)[i] += x; RoMPys(o)[i] += y; }
791 40 : break;
792 40 : case ROt_ST:
793 40 : o = (RectObj*)cp(R, sizeof(RectObjST));
794 40 : RoSTs(o) = (char*)cp(RoSTs(R),RoSTl(R)+1);
795 40 : RoSTx(o) += x; RoSTy(o) += y;
796 40 : break;
797 140 : default: /* ROt_PTT, ROt_LNT, ROt_PTS */
798 140 : o = (RectObj*)cp(R, sizeof(RectObjPN));
799 140 : break;
800 : }
801 340 : RoNext(tail) = o; tail = o;
802 : }
803 20 : RoNext(tail) = NULL; RTail(d) = tail;
804 20 : }
805 :
806 : enum {CLIPLINE_NONEMPTY = 1, CLIPLINE_CLIP_1 = 2, CLIPLINE_CLIP_2 = 4};
807 : /* A simpler way is to clip by 4 half-planes */
808 : static int
809 120 : clipline(double xmin, double xmax, double ymin, double ymax,
810 : double *x1p, double *y1p, double *x2p, double *y2p)
811 : {
812 120 : int xy_exch = 0, rc = CLIPLINE_NONEMPTY;
813 : double t, sl;
814 : double xi, xmn, xmx;
815 : double yi, ymn, ymx;
816 : int x1_is_ymn, x1_is_xmn;
817 120 : double x1 = *x1p, x2 = *x2p, y1 = *y1p, y2 = *y2p;
818 :
819 120 : if ((x1 < xmin && x2 < xmin) || (x1 > xmax && x2 > xmax))
820 40 : return 0;
821 80 : if (fabs(x1 - x2) < fabs(y1 - y2)) { /* Exchange x and y */
822 24 : xy_exch = 1;
823 24 : dswap(xmin, ymin); dswap(x1, y1);
824 24 : dswap(xmax, ymax); dswap(x2, y2);
825 : }
826 :
827 : /* Build y as a function of x */
828 80 : xi = x1;
829 80 : yi = y1;
830 80 : sl = x1==x2? 0: (y2 - yi)/(x2 - xi);
831 :
832 80 : if (x1 > x2) {
833 24 : x1_is_xmn = 0;
834 24 : xmn = x2;
835 24 : xmx = x1;
836 : } else {
837 56 : x1_is_xmn = 1;
838 56 : xmn = x1;
839 56 : xmx = x2;
840 : }
841 :
842 80 : if (xmn < xmin) {
843 8 : xmn = xmin;
844 8 : rc |= x1_is_xmn? CLIPLINE_CLIP_1: CLIPLINE_CLIP_2;
845 : }
846 80 : if (xmx > xmax) {
847 12 : xmx = xmax;
848 12 : rc |= x1_is_xmn? CLIPLINE_CLIP_2: CLIPLINE_CLIP_1;
849 : }
850 80 : if (xmn > xmx) return 0;
851 :
852 80 : ymn = yi + (xmn - xi)*sl;
853 80 : ymx = yi + (xmx - xi)*sl;
854 :
855 80 : if (sl < 0) t = ymn, ymn = ymx, ymx = t;
856 80 : if (ymn > ymax || ymx < ymin) return 0;
857 :
858 80 : if (rc & CLIPLINE_CLIP_1) x1 = x1_is_xmn? xmn: xmx;
859 80 : if (rc & CLIPLINE_CLIP_2) x2 = x1_is_xmn? xmx: xmn;
860 :
861 : /* Now we know there is an intersection, need to move x1 and x2 */
862 80 : x1_is_ymn = ((sl >= 0) == (x1 < x2));
863 80 : if (ymn < ymin) {
864 4 : double x = (ymin - yi)/sl + xi; /* slope != 0 ! */
865 4 : if (x1_is_ymn) x1 = x, rc |= CLIPLINE_CLIP_1;
866 0 : else x2 = x, rc |= CLIPLINE_CLIP_2;
867 : }
868 80 : if (ymx > ymax) {
869 4 : double x = (ymax - yi)/sl + xi; /* slope != 0 ! */
870 4 : if (x1_is_ymn) x2 = x, rc |= CLIPLINE_CLIP_2;
871 0 : else x1 = x, rc |= CLIPLINE_CLIP_1;
872 : }
873 80 : if (rc & CLIPLINE_CLIP_1) y1 = yi + (x1 - xi)*sl;
874 80 : if (rc & CLIPLINE_CLIP_2) y2 = yi + (x2 - xi)*sl;
875 80 : if (xy_exch) /* Exchange x and y */
876 24 : *x1p = y1, *x2p = y2, *y1p = x1, *y2p = x2;
877 : else
878 56 : *x1p = x1, *x2p = x2, *y1p = y1, *y2p = y2;
879 80 : return rc;
880 : }
881 :
882 : void
883 20 : plotclip(long rect)
884 : {
885 20 : PariRect *s = check_rect_init(rect);
886 20 : RectObj *next, *R = RHead(s), **prevp = &RHead(s);
887 20 : double xmin = 0, xmax = RXsize(s);
888 20 : double ymin = 0, ymax = RYsize(s);
889 :
890 380 : for (; R; R = next) {
891 360 : int did_clip = 0;
892 : #define REMOVE() { *prevp = next; freeobj(R); break; }
893 : #define NEXT() { prevp = &RoNext(R); break; }
894 :
895 360 : next = RoNext(R);
896 360 : switch(RoType(R)) {
897 40 : case ROt_PT:
898 40 : if ( DTOL(RoPTx(R)) < xmin || DTOL(RoPTx(R)) > xmax
899 40 : || DTOL(RoPTy(R)) < ymin || DTOL(RoPTy(R)) > ymax) REMOVE();
900 24 : NEXT();
901 40 : case ROt_BX: case ROt_FBX:
902 40 : if (RoLNx1(R) < xmin) RoLNx1(R) = xmin, did_clip = 1;
903 40 : if (RoLNx2(R) < xmin) RoLNx2(R) = xmin, did_clip = 1;
904 40 : if (RoLNy1(R) < ymin) RoLNy1(R) = ymin, did_clip = 1;
905 40 : if (RoLNy2(R) < ymin) RoLNy2(R) = ymin, did_clip = 1;
906 40 : if (RoLNx1(R) > xmax) RoLNx1(R) = xmax, did_clip = 1;
907 40 : if (RoLNx2(R) > xmax) RoLNx2(R) = xmax, did_clip = 1;
908 40 : if (RoLNy1(R) > ymax) RoLNy1(R) = ymax, did_clip = 1;
909 40 : if (RoLNy2(R) > ymax) RoLNy2(R) = ymax, did_clip = 1;
910 : /* Remove zero-size clipped boxes */
911 40 : if (did_clip && RoLNx1(R) == RoLNx2(R)
912 8 : && RoLNy1(R) == RoLNy2(R)) REMOVE();
913 36 : NEXT();
914 40 : case ROt_LN:
915 40 : if (!clipline(xmin, xmax, ymin, ymax,
916 : &RoLNx1(R), &RoLNy1(R),
917 8 : &RoLNx2(R), &RoLNy2(R))) REMOVE();
918 32 : NEXT();
919 20 : case ROt_MP: {
920 20 : int c = RoMPcnt(R), f = 0, t = 0;
921 :
922 220 : while (f < c) {
923 200 : if ( DTOL(RoMPxs(R)[f]) >= xmin && DTOL(RoMPxs(R)[f]) <= xmax
924 120 : && DTOL(RoMPys(R)[f]) >= ymin && DTOL(RoMPys(R)[f]) <= ymax) {
925 120 : if (t != f) {
926 0 : RoMPxs(R)[t] = RoMPxs(R)[f];
927 0 : RoMPys(R)[t] = RoMPys(R)[f];
928 : }
929 120 : t++;
930 : }
931 200 : f++;
932 : }
933 20 : if (t == 0) REMOVE();
934 12 : RoMPcnt(R) = t;
935 12 : NEXT();
936 : }
937 20 : case ROt_ML: {
938 : /* Hard case. Break a multiline into several pieces
939 : * if some part is clipped. */
940 20 : int c = RoMPcnt(R) - 1;
941 20 : int f = 0, t = 0, had_lines = 0, had_hole = 0, rc;
942 20 : double ox = RoMLxs(R)[0], oy = RoMLys(R)[0], oxn, oyn;
943 :
944 100 : while (f < c) {
945 : /* Endpoint of this segment is startpoint of next one: need to
946 : * preserve it if it is clipped. */
947 80 : oxn = RoMLxs(R)[f+1];
948 80 : oyn = RoMLys(R)[f+1];
949 80 : rc = clipline(xmin, xmax, ymin, ymax,
950 : &ox, &oy, /* &RoMLxs(R)[f], &RoMLys(R)[f], */
951 80 : &RoMLxs(R)[f+1], &RoMLys(R)[f+1]);
952 80 : RoMLxs(R)[f] = ox; ox = oxn;
953 80 : RoMLys(R)[f] = oy; oy = oyn;
954 80 : if (!rc) {
955 32 : if (had_lines) had_hole = 1;
956 32 : f++; continue;
957 : }
958 :
959 48 : if (!had_lines || (!(rc & CLIPLINE_CLIP_1) && !had_hole) ) {
960 : /* Continuous */
961 48 : had_lines = 1;
962 48 : if (t != f) {
963 0 : if (t == 0) {
964 0 : RoMPxs(R)[t] = RoMPxs(R)[f];
965 0 : RoMPys(R)[t] = RoMPys(R)[f];
966 : }
967 0 : RoMPxs(R)[t+1] = RoMPxs(R)[f+1];
968 0 : RoMPys(R)[t+1] = RoMPys(R)[f+1];
969 : }
970 48 : t++;
971 48 : f++;
972 48 : if (rc & CLIPLINE_CLIP_2) had_hole = 1, RoMLcnt(R) = t+1;
973 48 : continue;
974 : }
975 : /* Is not continuous, automatically R is not pari_free()ed. */
976 0 : t++;
977 0 : RoMLcnt(R) = t;
978 0 : if (rc & CLIPLINE_CLIP_2) { /* Needs separate entry */
979 0 : RectObj *n = (RectObj*) pari_malloc(sizeof(RectObj2P));
980 0 : RoType(n) = ROt_LN;
981 0 : RoCol(n) = RoCol(R);
982 0 : RoLNx1(n) = RoMLxs(R)[f]; RoLNy1(n) = RoMLys(R)[f];
983 0 : RoLNx2(n) = RoMLxs(R)[f+1]; RoLNy2(n) = RoMLys(R)[f+1];
984 0 : RoNext(n) = next;
985 0 : RoNext(R) = n;
986 : /* Restore the unclipped value: */
987 0 : RoMLxs(R)[f+1] = oxn; RoMLys(R)[f+1] = oyn;
988 0 : f++;
989 0 : prevp = &RoNext(n);
990 : }
991 0 : if (f + 1 < c) { /* Are other lines */
992 0 : RectObj *n = (RectObj*) pari_malloc(sizeof(RectObjMP));
993 0 : RoType(n) = ROt_ML;
994 0 : RoCol(n) = RoCol(R);
995 0 : RoMLcnt(n) = c - f;
996 0 : RoMLxs(n) = cpd(RoMPxs(R) + f, c-f);
997 0 : RoMLys(n) = cpd(RoMPys(R) + f, c-f);
998 0 : RoMPxs(n)[0] = oxn;
999 0 : RoMPys(n)[0] = oyn;
1000 0 : RoNext(n) = next;
1001 0 : RoNext(R) = n;
1002 0 : next = n;
1003 : }
1004 0 : break;
1005 : }
1006 20 : if (t == 0) REMOVE();
1007 12 : NEXT();
1008 : }
1009 : }
1010 : #undef REMOVE
1011 : #undef NEXT
1012 360 : }
1013 20 : }
1014 :
1015 : /********************************************************************/
1016 : /** **/
1017 : /** HI-RES PLOT **/
1018 : /** **/
1019 : /********************************************************************/
1020 : static void
1021 178796 : set_xrange(dblPointList *f, double x)
1022 178796 : { if (x < f->xsml) f->xsml = x;
1023 178796 : if (x > f->xbig) f->xbig = x; }
1024 : static void
1025 170176 : Appendx(dblPointList *f, dblPointList *l, double x)
1026 170176 : { (l->d)[l->nb++] = x; set_xrange(f,x); }
1027 : static void
1028 245388 : set_yrange(dblPointList *f, double y)
1029 245388 : { if (y < f->ysml) f->ysml = y;
1030 245388 : if (y > f->ybig) f->ybig = y; }
1031 : static void
1032 235176 : Appendy(dblPointList *f, dblPointList *l, double y)
1033 235176 : { (l->d)[l->nb++] = y; set_yrange(f,y); }
1034 :
1035 : static void
1036 138192 : get_xy(long cplx, GEN t, double *x, double *y)
1037 : {
1038 : GEN a, b;
1039 138192 : if (cplx)
1040 : {
1041 0 : if (typ(t) == t_VEC)
1042 : {
1043 0 : if (lg(t) != 2) pari_err_DIM("get_xy");
1044 0 : t = gel(t,1);
1045 : }
1046 0 : a = real_i(t); b = imag_i(t);
1047 : }
1048 : else
1049 : {
1050 138192 : if (typ(t) != t_VEC || lg(t) != 3) pari_err_DIM("get_xy");
1051 138192 : a = gel(t,1); b = gel(t,2);
1052 : }
1053 138192 : *x = gtodouble(a);
1054 138192 : *y = gtodouble(b);
1055 138192 : }
1056 : /* t a t_VEC (possibly a scalar if cplx), get next (x,y) coordinate starting
1057 : * at index *i [update i] */
1058 : static void
1059 40256 : get_xy_from_vec(long cplx, GEN t, long *i, double *x, double *y)
1060 : {
1061 : GEN a, b;
1062 40256 : if (cplx)
1063 : {
1064 0 : if (typ(t) == t_VEC) t = gel(t,*i);
1065 0 : a = real_i(t); b = imag_i(t); (*i)++;
1066 : }
1067 : else
1068 : {
1069 40256 : a = gel(t, (*i)++);
1070 40256 : b = gel(t, (*i)++);
1071 : }
1072 40256 : *x = gtodouble(a);
1073 40256 : *y = gtodouble(b);
1074 40256 : }
1075 :
1076 : static void
1077 504 : dblV_from_RgV(dblPointList *L, GEN x)
1078 : {
1079 504 : long j, l = lg(x);
1080 504 : double *X = (double*)pari_malloc(l*sizeof(double));
1081 20936 : for (j = 1; j < l; j++) X[j-1] = gtodouble(gel(x,j));
1082 504 : L->d = X; L->nb = l-1;
1083 504 : }
1084 :
1085 : /* Convert data from GEN to double before we call plotrecthrawin. */
1086 : static dblPointList*
1087 42 : gtodblList(GEN data, long flags)
1088 : {
1089 : dblPointList *l, *L;
1090 : double *X, *Y;
1091 42 : long nl = lg(data)-1, i, j;
1092 42 : const long param = (flags & (PLOT_PARAMETRIC|PLOT_COMPLEX));
1093 42 : const long cplx = (flags & PLOT_COMPLEX);
1094 :
1095 42 : if (! is_vec_t(typ(data))) pari_err_TYPE("gtodblList",data);
1096 42 : if (!nl) return NULL;
1097 :
1098 42 : if (nl == 1 && !cplx) pari_err_DIM("gtodblList");
1099 538 : for (i = 1; i <= nl; i++)
1100 : { /* Check input first */
1101 496 : GEN x = gel(data,i);
1102 496 : if (!is_vec_t(typ(x))) pari_err_TYPE("gtodblList",x);
1103 : }
1104 42 : if (flags & PLOT_PARAMETRIC)
1105 : {
1106 30 : if (odd(nl))
1107 0 : pari_err_TYPE("gtodbllist [odd #components in parametric plot]", data);
1108 64 : for (i = 1; i < nl; i += 2)
1109 : {
1110 34 : GEN x = gel(data,i), y = gel(data,i+1);
1111 34 : if (lg(y) != lg(x)) pari_err_DIM("gtodblList");
1112 : }
1113 : }
1114 12 : else if (!cplx)
1115 : {
1116 8 : long l1 = lg(gel(data,1)); if (l1 == 1) return NULL;
1117 420 : for (i = 2; i <= nl; i++)
1118 412 : if (lg(gel(data,i)) != l1) pari_err_DIM("gtodblList");
1119 : }
1120 :
1121 : /* Now allocate memory and convert coord. to double */
1122 42 : if (cplx)
1123 : {
1124 4 : l = (dblPointList*)pari_malloc((2*nl)*sizeof(dblPointList));
1125 12 : for (i = 0; i < nl; i++)
1126 : {
1127 8 : pari_sp av = avma;
1128 8 : GEN x = gel(data,i+1);
1129 8 : dblV_from_RgV(&l[2*i], real_i(x));
1130 8 : dblV_from_RgV(&l[2*i+1], imag_i(x)); set_avma(av);
1131 : }
1132 : }
1133 38 : else if (param)
1134 : {
1135 30 : l = (dblPointList*)pari_malloc(nl*sizeof(dblPointList));
1136 64 : for (i = 1; i < nl; i += 2)
1137 : {
1138 34 : dblV_from_RgV(&l[i-1], gel(data,i));
1139 34 : dblV_from_RgV(&l[i], gel(data,i+1));
1140 : }
1141 : }
1142 : else
1143 : {
1144 8 : l = (dblPointList*)pari_malloc(nl*sizeof(dblPointList));
1145 8 : dblV_from_RgV(&l[0], gel(data,1));
1146 420 : for (i = 2; i <= nl; i++) dblV_from_RgV(&l[i-1], gel(data, i));
1147 : }
1148 : /* Compute extremas */
1149 42 : L = &l[0];
1150 42 : if (param)
1151 : {
1152 34 : L->nb = cplx? nl: nl/2;
1153 34 : for (i=0; i < L->nb; i+=2)
1154 34 : if (l[i+1].nb) break;
1155 34 : if (i >= L->nb) { pari_free(l); return NULL; }
1156 34 : L->xsml = L->xbig = l[i ].d[0];
1157 34 : L->ysml = L->ybig = l[i+1].d[0];
1158 68 : for (; i < L->nb; i+=2)
1159 : {
1160 34 : long nbi = l[i+1].nb; X = l[i].d; Y = l[i+1].d;
1161 8246 : for (j = 0; j < nbi; j++) { set_xrange(L, X[j]); set_yrange(L, Y[j]); }
1162 : }
1163 : }
1164 : else
1165 : {
1166 8 : L->nb = nl-1;
1167 8 : X = L->d; L->xsml = L->xbig = X[0];
1168 8 : Y = l[1].d; L->ysml = L->ybig = Y[0];
1169 416 : for (j=0; j < l[1].nb; j++) set_xrange(L, X[j]);
1170 420 : for (i=1; i <= L->nb; i++)
1171 : {
1172 412 : long nbi = l[i].nb; Y = l[i].d;
1173 2412 : for (j = 0; j < nbi; j++) set_yrange(L, Y[j]);
1174 : }
1175 : }
1176 42 : return l;
1177 : }
1178 :
1179 : /* x,y t_REAL; return (x+y)/2, */
1180 : static GEN
1181 208940 : rmiddle(GEN x, GEN y) { GEN z = addrr(x,y); shiftr_inplace(z,-1); return z; }
1182 :
1183 : static void
1184 91404 : single_recursion(void *E, GEN(*eval)(void*,GEN), dblPointList *pl,
1185 : GEN xl,double yl, GEN xr,double yr,long depth)
1186 : {
1187 : GEN xx;
1188 91404 : pari_sp av = avma;
1189 91404 : double yy, dy=pl[0].ybig - pl[0].ysml;
1190 :
1191 91404 : if (depth==RECUR_MAXDEPTH) return;
1192 :
1193 83124 : xx = rmiddle(xl,xr);
1194 83124 : yy = gtodouble(eval(E,xx));
1195 :
1196 83124 : if (dy && fabs(yl+yr-2*yy) < dy*RECUR_PREC) return;
1197 43708 : single_recursion(E,eval, pl,xl,yl, xx,yy, depth+1);
1198 43708 : Appendx(&pl[0],&pl[0],rtodbl(xx));
1199 43708 : Appendy(&pl[0],&pl[1],yy);
1200 43708 : single_recursion(E,eval, pl,xx,yy, xr,yr, depth+1);
1201 43708 : set_avma(av);
1202 : }
1203 :
1204 : static void
1205 138104 : param_recursion(void *E,GEN(*eval)(void*,GEN), long cplx, dblPointList *pl,
1206 : GEN tl,double xl, double yl, GEN tr,double xr,double yr, long depth)
1207 : {
1208 : GEN t;
1209 138104 : pari_sp av = avma;
1210 138104 : double xx, dy=pl[0].ybig - pl[0].ysml;
1211 138104 : double yy, dx=pl[0].xbig - pl[0].xsml;
1212 :
1213 198060 : if (depth==RECUR_MAXDEPTH) return;
1214 :
1215 125816 : t = rmiddle(tl,tr);
1216 125816 : get_xy(cplx, eval(E,t), &xx,&yy);
1217 :
1218 125816 : if (dx && dy && fabs(xl+xr-2*xx) < dx*RECUR_PREC
1219 62848 : && fabs(yl+yr-2*yy) < dy*RECUR_PREC) return;
1220 65860 : param_recursion(E,eval, cplx, pl, tl,xl,yl, t,xx,yy, depth+1);
1221 65860 : Appendx(&pl[0],&pl[0],xx);
1222 65860 : Appendy(&pl[0],&pl[1],yy);
1223 65860 : param_recursion(E,eval,cplx, pl, t,xx,yy, tr,xr,yr, depth+1);
1224 65860 : set_avma(av);
1225 : }
1226 :
1227 : /* Graph 'code' for parameter values in [a,b], using 'N' sample points
1228 : * (0 = use a default value); code is either a t_CLOSURE or a t_POL or a
1229 : * t_VEC of two t_POLs from rectsplines. Returns a dblPointList of
1230 : * (absolute) coordinates. */
1231 : static dblPointList *
1232 10080 : plotrecthin(void *E, GEN(*eval)(void*, GEN), GEN a, GEN b, ulong flags,
1233 : long N, long prec)
1234 : {
1235 10080 : const double INF = 1.0/0.0;
1236 10080 : const long param = flags & (PLOT_PARAMETRIC|PLOT_COMPLEX);
1237 10080 : const long recur = flags & PLOT_RECURSIVE;
1238 10080 : const long cplx = flags & PLOT_COMPLEX;
1239 : GEN t, dx, x;
1240 : dblPointList *pl;
1241 10080 : long tx, i, j, sig, nc, nl, ncoords, nbpoints, non_vec = 0;
1242 :
1243 10080 : sig = gcmp(b,a); if (!sig) return NULL;
1244 10080 : if (sig < 0) swap(a, b);
1245 10080 : if (N == 1) pari_err_DOMAIN("ploth", "#points", "<", gen_2, stoi(N));
1246 10076 : if (!N) N = recur? 8: (param? 1500: 1000);
1247 : /* compute F(a) to determine nc = #curves; nl = #coord. lists */
1248 10076 : x = gtofp(a, prec);
1249 10076 : t = eval(E, x); tx = typ(t);
1250 10076 : if (cplx) nc = nl = (tx == t_VEC)? lg(t)-1: 1;
1251 10076 : else if (param)
1252 : {
1253 6043 : if (tx != t_VEC) pari_err_TYPE("ploth [not a t_VEC in parametric plot]", t);
1254 6039 : nl = lg(t)-1; nc = nl >> 1;
1255 6039 : if (odd(nl)) pari_err_TYPE("ploth [odd #components in parametric plot]",t);
1256 : }
1257 4033 : else if (!is_matvec_t(tx)) { nl = 2; non_vec = 1; nc = 1; }
1258 : else
1259 : {
1260 12 : if (tx != t_VEC) pari_err_TYPE("ploth [not a t_VEC]",t);
1261 12 : nl = lg(t);
1262 12 : nc = nl-1;
1263 : }
1264 10072 : if (!nc) return NULL;
1265 10072 : if (recur && nc > 1) pari_err_TYPE("ploth [multi-curves + recursive]",t);
1266 :
1267 10068 : ncoords = cplx? 2*nl: nl;
1268 10068 : nbpoints = recur? N << RECUR_MAXDEPTH: N;
1269 10068 : pl=(dblPointList*) pari_malloc(ncoords*sizeof(dblPointList));
1270 : /* set [xy]sml,[xy]big to default values */
1271 10068 : if (param)
1272 : {
1273 6039 : pl[0].xsml = INF;
1274 6039 : pl[0].xbig =-INF;
1275 : } else {
1276 4029 : pl[0].xsml = gtodouble(a);
1277 4029 : pl[0].xbig = gtodouble(b);
1278 : }
1279 10068 : pl[0].ysml = INF;
1280 10068 : pl[0].ybig =-INF;
1281 30228 : for (i = 0; i < ncoords; i++)
1282 : {
1283 20160 : pl[i].d = (double*)pari_malloc((nbpoints+1)*sizeof(double));
1284 20160 : pl[i].nb=0;
1285 : }
1286 10068 : dx = divru(gtofp(gsub(b,a),prec), N-1);
1287 10068 : if (recur)
1288 : { /* recursive plot */
1289 9980 : double yl, yr = 0;
1290 9980 : if (param)
1291 : {
1292 5992 : GEN tl = cgetr(prec), tr = cgetr(prec);
1293 5992 : double xl, xr = 0;
1294 5992 : pari_sp av2 = avma;
1295 5992 : affgr(a, tl);
1296 5992 : t = eval(E, tl);
1297 5992 : get_xy(cplx,t, &xl,&yl);
1298 12376 : for (i=0; i<N-1; i++, set_avma(av2))
1299 : {
1300 6384 : if (i) { affrr(tr,tl); xl = xr; yl = yr; }
1301 6384 : addrrz(tl,dx,tr);
1302 6384 : t = eval(E, tr);
1303 6384 : get_xy(cplx,t, &xr,&yr);
1304 6384 : Appendx(&pl[0],&pl[0],xl);
1305 6384 : Appendy(&pl[0],&pl[1],yl);
1306 6384 : param_recursion(E,eval, cplx, pl, tl,xl,yl, tr,xr,yr, 0);
1307 : }
1308 5992 : Appendx(&pl[0],&pl[0],xr);
1309 5992 : Appendy(&pl[0],&pl[1],yr);
1310 : }
1311 : else /* single curve */
1312 : {
1313 3988 : GEN xl = cgetr(prec), xr = cgetr(prec);
1314 3988 : pari_sp av2 = avma;
1315 3988 : affgr(a,xl);
1316 3988 : yl = gtodouble(eval(E,xl));
1317 7976 : for (i=0; i<N-1; i++, set_avma(av2))
1318 : {
1319 3988 : addrrz(xl,dx,xr);
1320 3988 : yr = gtodouble(eval(E,xr));
1321 3988 : Appendx(&pl[0],&pl[0],rtodbl(xl));
1322 3988 : Appendy(&pl[0],&pl[1],yl);
1323 3988 : single_recursion(E,eval, pl,xl,yl,xr,yr,0);
1324 3988 : affrr(xr,xl); yl = yr;
1325 : }
1326 3988 : Appendx(&pl[0],&pl[0],rtodbl(xr));
1327 3988 : Appendy(&pl[0],&pl[1],yr);
1328 : }
1329 : }
1330 : else /* nonrecursive plot */
1331 : {
1332 88 : GEN V, X = cgetg(N+1, t_VEC);
1333 86388 : for (i = 1; i <= N; i++) { gel(X,i) = x; x = addrr(x,dx); }
1334 88 : if (flags & PLOT_PARA && eval == gp_call)
1335 14 : {
1336 14 : GEN worker = snm_closure(is_entry("_parapply_slice_worker"),
1337 : mkvec((GEN)E));
1338 14 : V = gen_parapply_slice(worker, X, mt_nbthreads());
1339 : }
1340 : else
1341 : {
1342 74 : V = cgetg(N+1, t_VEC);
1343 68874 : for (i = 1; i <= N; i++) gel(V,i) = eval(E,gel(X,i));
1344 : }
1345 88 : if (param)
1346 : {
1347 40303 : for (i = 1; i <= N; i++)
1348 : {
1349 : long nt, k, j;
1350 40260 : t = gel(V,i);
1351 40260 : if (typ(t) != t_VEC)
1352 : {
1353 4 : if (cplx) nt = 1;
1354 4 : else nt = 0; /* trigger error */
1355 : }
1356 : else
1357 40256 : nt = lg(t)-1;
1358 40260 : if (nt != nl) pari_err_DIM("plotrecth");
1359 40256 : k = 0; j = 1;
1360 80512 : while (j <= nl)
1361 : {
1362 : double xx, yy;
1363 40256 : get_xy_from_vec(cplx, t, &j, &xx, &yy);
1364 40256 : Appendx(&pl[0], &pl[k++], xx);
1365 40256 : Appendy(&pl[0], &pl[k++], yy);
1366 : }
1367 : }
1368 : }
1369 41 : else if (non_vec)
1370 33033 : for (i = 1; i <= N; i++)
1371 : {
1372 33000 : Appendy(&pl[0], &pl[1], gtodouble(gel(V,i)));
1373 33000 : pl[0].d[i-1] = gtodouble(gel(X,i));
1374 : }
1375 : else /* vector of nonparametric curves */
1376 8008 : for (i = 1; i <= N; i++)
1377 : {
1378 8000 : t = gel(V,i);
1379 8000 : if (typ(t) != t_VEC || lg(t) != nl) pari_err_DIM("plotrecth");
1380 40000 : for (j = 1; j < nl; j++) Appendy(&pl[0], &pl[j], gtodouble(gel(t,j)));
1381 8000 : pl[0].d[i-1] = gtodouble(gel(X,i));
1382 : }
1383 : }
1384 10064 : pl[0].nb = nc; return pl;
1385 : }
1386 :
1387 : static GEN
1388 234176 : spline_eval(void* E, GEN x) { return gsubst((GEN)E,0,x); }
1389 :
1390 : /* Uses highlevel plotting functions to implement splines as
1391 : a low-level plotting function. */
1392 : static void
1393 8 : rectsplines(long ne, double *x, double *y, long lx, long flag)
1394 : {
1395 : long i, j;
1396 8 : pari_sp av0 = avma;
1397 8 : GEN X = pol_x(0), xa = cgetg(lx+1, t_VEC), ya = cgetg(lx+1, t_VEC);
1398 : GEN tas, pol3;
1399 8 : long param = flag & PLOT_PARAMETRIC;
1400 8 : const long fl = param | PLOT_RECURSIVE | PLOT_NO_RESCALE | PLOT_NO_FRAME
1401 : | PLOT_NO_AXE_Y | PLOT_NO_AXE_X;
1402 :
1403 8 : if (lx < 4) pari_err(e_MISC, "Too few points (%ld) for spline plot", lx);
1404 10008 : for (i = 1; i <= lx; i++) {
1405 10000 : gel(xa,i) = dbltor(x[i-1]);
1406 10000 : gel(ya,i) = dbltor(y[i-1]);
1407 : }
1408 8 : if (param) {
1409 4 : tas = new_chunk(4);
1410 20 : for (j = 1; j <= 4; j++) gel(tas,j-1) = utoipos(j);
1411 4 : pol3 = cgetg(3, t_VEC);
1412 : }
1413 : else
1414 4 : tas = pol3 = NULL; /* gcc -Wall */
1415 9984 : for (i = 0; i <= lx - 4; i++) {
1416 9976 : pari_sp av = avma;
1417 :
1418 9976 : xa++; ya++;
1419 9976 : if (param) {
1420 5988 : gel(pol3,1) = polintspec(tas, xa, X, 4, NULL);
1421 5988 : gel(pol3,2) = polintspec(tas, ya, X, 4, NULL);
1422 : } else {
1423 3988 : pol3 = polintspec(xa, ya, X, 4, NULL);
1424 3988 : tas = xa;
1425 : }
1426 : /* Start with 3 points */
1427 9976 : plotrecth((void*)pol3, &spline_eval, ne,
1428 : i== 0 ? gel(tas,0) : gel(tas,1),
1429 9976 : i==lx-4 ? gel(tas,3) : gel(tas,2),
1430 : fl, 2, DEFAULTPREC);
1431 9976 : set_avma(av);
1432 : }
1433 8 : set_avma(av0);
1434 8 : }
1435 :
1436 : static void
1437 71 : pari_get_fmtplot(GEN fmt, PARI_plot *T)
1438 : {
1439 71 : char *f = GSTR(fmt);
1440 71 : if (!strcmp(f, "svg")) pari_get_svgplot(T);
1441 21 : else if (!strcmp(f, "ps")) pari_get_psplot(T);
1442 0 : else pari_err_TYPE("plotexport [unknown format]", fmt);
1443 71 : }
1444 : static GEN
1445 135 : fmt_convert(GEN fmt, GEN w, GEN x, GEN y, PARI_plot *T)
1446 : {
1447 135 : char *f, *s = NULL;
1448 135 : if (typ(fmt) != t_STR) pari_err_TYPE("plotexport",fmt);
1449 135 : f = GSTR(fmt);
1450 135 : if (!strcmp(f, "svg"))
1451 86 : s = rect2svg(w,x,y,T);
1452 49 : else if (!strcmp(f, "ps"))
1453 49 : s = rect2ps(w,x,y,T);
1454 : else
1455 0 : pari_err_TYPE("plotexport [unknown format]", fmt);
1456 135 : return strtoGENstr(s);
1457 : }
1458 :
1459 : static void
1460 76 : Draw(PARI_plot *T, GEN w, GEN x, GEN y)
1461 : {
1462 76 : if (!T->draw) pari_err(e_MISC,"high resolution graphics disabled");
1463 76 : T->draw(T, w,x,y);
1464 76 : }
1465 : static void
1466 20212 : set_range(double m, double M, double *sml, double *big)
1467 : {
1468 20212 : if (M - m < 1.e-9)
1469 : {
1470 4 : double d = fabs(m)/10; if (!d) d = 0.1;
1471 4 : M += d; m -= d;
1472 : }
1473 20212 : *sml = m; *big = M;
1474 20212 : }
1475 : /* Plot a dblPointList. Complete with axes, bounding box, etc.
1476 : *
1477 : * data is an array of structs. Its meaning depends on flags :
1478 : *
1479 : * + data[0] contains global extremas, the number of curves to plot
1480 : * (data[0].nb) and a list of doubles (first set of x-coordinates).
1481 : *
1482 : * + data[i].nb (i>0) contains the number of points in the list
1483 : * data[i].d (hopefully, data[2i].nb=data[2i+1].nb when i>0...)
1484 : *
1485 : * + If flags contain PLOT_PARAMETRIC, the array length should be
1486 : * even, and successive pairs (data[2i].d, data[2i+1].d) represent
1487 : * curves to plot.
1488 : *
1489 : * + If there is no such flag, the first element is an array with
1490 : * x-coordinates and the following ones contain y-coordinates.
1491 : * If W != NULL, output wrt this PARI_plot using two drawing rectangles:
1492 : * one for labels, another for graphs. Else draw to rectwindow ne without
1493 : * labels.
1494 : * If fmt != NULL (requires W != NULL), output is a t_STR containing the
1495 : * converted picture, else a bounding box */
1496 : static GEN
1497 10106 : plotrecthrawin(GEN fmt, PARI_plot *W, long ne, dblPointList *data, long flags)
1498 : {
1499 10106 : const long param = flags & (PLOT_PARAMETRIC|PLOT_COMPLEX);
1500 10106 : const long max_graphcolors = lg(GP_DATA->graphcolors)-1;
1501 10106 : const pari_sp av = avma;
1502 : dblPointList x, y;
1503 : double xsml, xbig, ysml, ybig;
1504 : long ltype, i, nc, w[3], wx[3], wy[3];
1505 :
1506 10106 : if (!data) return cgetg(1,t_VEC);
1507 10106 : x = data[0]; nc = x.nb;
1508 10106 : set_range(x.xsml, x.xbig, &xsml, &xbig);
1509 10106 : set_range(x.ysml, x.ybig, &ysml, &ybig);
1510 10106 : if (W)
1511 : { /* actual output; else output to rectwindow: no labels */
1512 : char YBIG[16], YSML[16], XSML[16], XBIG[16];
1513 107 : long lm = W->hunit-1, rm = W->hunit-1, tm = W->vunit-1;
1514 107 : long bm = W->vunit+W->fheight-1;
1515 : /* left/right/top/bottom margin */
1516 107 : if (!(flags&PLOT_NOMINMAX))
1517 : {
1518 107 : sprintf(YSML,"%.5g", ysml); sprintf(YBIG,"%.5g", ybig);
1519 107 : sprintf(XSML,"%.5g", xsml); sprintf(XBIG,"%.5g", xbig);
1520 : /* left margin has y labels with hgap on both sides of text */
1521 107 : lm = maxss(strlen(YSML), strlen(YBIG)) * W->fwidth + 2*W->hunit-1;
1522 : }
1523 107 : w[0] = evaltyp(t_VECSMALL) | _evallg((flags&PLOT_NOMINMAX)? 2: 3);
1524 107 : wx[0] = wy[0] = w[0];
1525 107 : w[1] = ne; wx[1] = lm; wy[1] = tm;
1526 : /* Window (width x height) is given in pixels, correct pixels are 0..n-1,
1527 : * whereas rect functions work with windows whose pixel range is [0,n] */
1528 107 : initrect_i(ne, W->width - (lm+rm) - 1, W->height - (tm+bm) - 1);
1529 107 : if (!(flags&PLOT_NOMINMAX))
1530 : { /* draw labels on se */
1531 107 : const long se = NUMRECT-2;
1532 107 : w[2] = se; wx[2] = 0; wy[2] = 0;
1533 107 : initrect_i(se, W->width - 1, W->height - 1);
1534 107 : _move(se,lm,0); plotstring(se, YBIG, RoSTdirRIGHT|RoSTdirHGAP|RoSTdirTOP);
1535 107 : _move(se,lm,W->height-bm); plotstring(se,YSML, RoSTdirRIGHT|RoSTdirHGAP|RoSTdirVGAP);
1536 107 : _move(se,lm,W->height-bm); plotstring(se, XSML, RoSTdirLEFT|RoSTdirTOP);
1537 107 : _move(se,W->width-rm-1, W->height-bm); plotstring(se, XBIG, RoSTdirRIGHT|RoSTdirTOP);
1538 : }
1539 : }
1540 10106 : if (!(flags & PLOT_NO_RESCALE)) plotscale0(ne, xsml, xbig, ysml, ybig);
1541 10106 : if (!(flags & PLOT_NO_FRAME))
1542 : {
1543 260 : long fl = (flags & PLOT_NODOUBLETICK)? TICKS_CLOCKW|TICKS_NODOUBLE
1544 130 : : TICKS_CLOCKW;
1545 : PARI_plot T, *pl;
1546 130 : if (W) pl = W; else { pl = &T; pari_get_plot(pl); }
1547 130 : plotlinetype(ne, -2); /* frame */
1548 130 : current_color[ne] = colormap_to_color(DEFAULT_COLOR);
1549 130 : _move(ne,xsml,ysml);
1550 130 : _box(ne,xbig,ybig);
1551 130 : if (!(flags & PLOT_NO_TICK_X)) {
1552 130 : rectticks(pl, ne, xsml, ysml, xbig, ysml, xsml, xbig, fl);
1553 130 : rectticks(pl, ne, xbig, ybig, xsml, ybig, xbig, xsml, fl);
1554 : }
1555 130 : if (!(flags & PLOT_NO_TICK_Y)) {
1556 130 : rectticks(pl, ne, xbig, ysml, xbig, ybig, ysml, ybig, fl);
1557 130 : rectticks(pl, ne, xsml, ybig, xsml, ysml, ybig, ysml, fl);
1558 : }
1559 : }
1560 10106 : if (!(flags & PLOT_NO_AXE_Y) && (xsml<=0 && xbig >=0))
1561 : {
1562 105 : plotlinetype(ne, -1); /* axes */
1563 105 : current_color[ne] = colormap_to_color(AXIS_COLOR);
1564 105 : _move(ne,0.0,ysml);
1565 105 : _line(ne,0.0,ybig);
1566 : }
1567 10106 : if (!(flags & PLOT_NO_AXE_X) && (ysml<=0 && ybig >=0))
1568 : {
1569 109 : plotlinetype(ne, -1); /* axes */
1570 109 : current_color[ne] = colormap_to_color(AXIS_COLOR);
1571 109 : _move(ne,xsml,0.0);
1572 109 : _line(ne,xbig,0.0);
1573 : }
1574 :
1575 10106 : if (param) {
1576 6069 : i = 0;
1577 6069 : flags |= PLOT_PARAMETRIC;
1578 6069 : flags &= (~PLOT_COMPLEX); /* turn COMPLEX to PARAMETRIC*/
1579 4037 : } else i = 1;
1580 20632 : for (ltype = 0; ltype < nc; ltype++)
1581 : {
1582 10530 : long c = GP_DATA->graphcolors[1+(ltype%max_graphcolors)];
1583 10530 : current_color[ne] = colormap_to_color(c);
1584 10526 : if (param) x = data[i++];
1585 :
1586 10526 : y = data[i++];
1587 10526 : if (flags & (PLOT_POINTS_LINES|PLOT_POINTS)) {
1588 18 : plotlinetype(ne, plotpoint_itype + ltype); /* Graphs */
1589 18 : plotpointtype(ne,plotpoint_itype + ltype); /* Graphs */
1590 18 : plotpoints0(ne, x.d, y.d, y.nb);
1591 18 : if (!(flags & PLOT_POINTS_LINES)) continue;
1592 : }
1593 :
1594 10508 : if (flags & PLOT_SPLINES) {
1595 : /* rectsplines will call us back with ltype == 0 */
1596 8 : int old = rectline_itype;
1597 8 : rectline_itype = rectline_itype + ltype;
1598 8 : rectsplines(ne, x.d, y.d, y.nb, flags);
1599 8 : rectline_itype = old;
1600 : } else {
1601 10500 : plotlinetype(ne, rectline_itype + ltype); /* Graphs */
1602 10500 : rectlines0(ne, x.d, y.d, y.nb, 0);
1603 : }
1604 : }
1605 30730 : for (i--; i>=0; i--) pari_free(data[i].d);
1606 10102 : pari_free(data);
1607 :
1608 10102 : if (W)
1609 : {
1610 103 : GEN s = NULL;
1611 103 : if (fmt) s = fmt_convert(fmt, w, wx, wy, W); else Draw(W, w,wx,wy);
1612 309 : for (i = 1; i < lg(w); i++) plotkill(w[i]);
1613 103 : if (fmt) return s;
1614 : }
1615 10031 : set_avma(av);
1616 10031 : retmkvec4(dbltor(xsml), dbltor(xbig), dbltor(ysml), dbltor(ybig));
1617 : }
1618 :
1619 : /*************************************************************************/
1620 : /* */
1621 : /* HI-RES FUNCTIONS */
1622 : /* */
1623 : /*************************************************************************/
1624 : /* If T != NULL, draw using the attached graphic (using rectwindow ne as a temp)
1625 : * Else write to rectwindow 'ne'.
1626 : * Graph y=f(x), x=a..b, use n points */
1627 : static GEN
1628 10080 : plotrecth_i(GEN fmt, void *E, GEN(*f)(void*,GEN), PARI_plot *T, long ne,
1629 : GEN a,GEN b, ulong flags,long n, long prec)
1630 : {
1631 10080 : pari_sp av = avma;
1632 10080 : dblPointList *pl = plotrecthin(E,f, a,b, flags, n, prec);
1633 10064 : set_avma(av); return plotrecthrawin(fmt, T, ne, pl, flags);
1634 : }
1635 : GEN
1636 9983 : plotrecth(void *E, GEN(*f)(void*,GEN), long ne, GEN a,GEN b,
1637 : ulong flags, long n, long prec)
1638 9983 : { return plotrecth_i(NULL, E,f, NULL, ne, a,b, flags&~PLOT_PARA, n, prec); }
1639 : GEN
1640 7 : plotrecth0(long ne, GEN a,GEN b,GEN code,ulong flags,long n, long prec)
1641 7 : { EXPR_WRAP(code, plotrecth(EXPR_ARG, ne, a,b, flags, n, prec)); }
1642 : static GEN
1643 44 : _ploth(void *E, GEN(*f)(void*,GEN), GEN a, GEN b,long flags, long n, long prec)
1644 : {
1645 44 : PARI_plot T; pari_get_plot(&T);
1646 44 : return plotrecth_i(NULL, E,f, &T, NUMRECT-1, a,b, flags,n, prec);
1647 : }
1648 : GEN
1649 44 : ploth(void *E, GEN(*f)(void*,GEN), GEN a, GEN b,long flags, long n, long prec)
1650 44 : { return _ploth(E, f, a, b, flags&~PLOT_PARA, n, prec); }
1651 : GEN
1652 0 : parploth(GEN a, GEN b, GEN code, long flags, long n, long prec)
1653 0 : { return _ploth(code, gp_call, a, b, flags|PLOT_PARA, n, prec); }
1654 : GEN
1655 44 : ploth0(GEN a, GEN b, GEN code, long flags,long n, long prec)
1656 44 : { EXPR_WRAP(code, ploth(EXPR_ARG, a,b,flags,n, prec)); }
1657 :
1658 : GEN
1659 0 : psploth(void *E, GEN(*f)(void*,GEN), GEN a,GEN b, long flags, long n, long prec)
1660 : {
1661 0 : PARI_plot T; pari_get_psplot(&T); T.draw = &_psdraw;
1662 0 : return plotrecth_i(NULL, E,f, &T, NUMRECT-1, a,b, flags&~PLOT_PARA,n, prec);
1663 : }
1664 : GEN
1665 0 : psploth0(GEN a, GEN b, GEN code, long flags, long n, long prec)
1666 0 : { EXPR_WRAP(code, psploth(EXPR_ARG, a, b, flags, n, prec)); }
1667 :
1668 : static GEN
1669 53 : _plothexport(GEN fmt, void *E, GEN(*f)(void*,GEN), GEN a,GEN b, long flags,
1670 : long n, long prec)
1671 : {
1672 53 : pari_sp av = avma;
1673 : GEN s;
1674 53 : PARI_plot T; pari_get_fmtplot(fmt, &T);
1675 53 : s = plotrecth_i(fmt, E,f, &T, NUMRECT-1, a,b, flags,n, prec);
1676 53 : return gerepileuptoleaf(av, s);
1677 : }
1678 : GEN
1679 39 : plothexport(GEN fmt, void *E, GEN(*f)(void*,GEN), GEN a,GEN b, long flags,
1680 : long n, long prec)
1681 39 : { return _plothexport(fmt, E, f, a, b, flags&~PLOT_PARA, n, prec); }
1682 : GEN
1683 39 : plothexport0(GEN fmt, GEN a, GEN b, GEN code, long flags, long n, long prec)
1684 39 : { EXPR_WRAP(code, plothexport(fmt, EXPR_ARG, a, b, flags, n, prec)); }
1685 : GEN
1686 14 : parplothexport(GEN fmt, GEN a, GEN b, GEN code, long flags, long n, long prec)
1687 14 : { return _plothexport(fmt, code, gp_call, a, b, flags|PLOT_PARA, n, prec); }
1688 :
1689 : /* Draw list of points */
1690 : static GEN
1691 42 : plotrecthraw_i(GEN fmt, PARI_plot *T, long ne, GEN data, long flags)
1692 : {
1693 42 : dblPointList *pl = gtodblList(data,flags);
1694 42 : return plotrecthrawin(fmt, T, ne, pl, flags);
1695 : }
1696 : static GEN
1697 26 : plothraw_i(GEN fmt, PARI_plot *T, GEN X, GEN Y, long flag)
1698 : {
1699 26 : pari_sp av = avma;
1700 26 : switch (flag) {
1701 18 : case 0: flag = PLOT_PARAMETRIC|PLOT_POINTS; break;
1702 8 : case 1: flag = PLOT_PARAMETRIC; break;
1703 0 : default: flag |= PLOT_PARAMETRIC; break;
1704 : }
1705 26 : return gerepileupto(av, plotrecthraw_i(fmt, T, NUMRECT-1, mkvec2(X,Y), flag));
1706 : }
1707 : GEN
1708 8 : plothraw(GEN X, GEN Y, long flags)
1709 8 : { PARI_plot T; pari_get_plot(&T); return plothraw_i(NULL,&T,X,Y,flags); }
1710 : GEN
1711 0 : psplothraw(GEN X, GEN Y, long flags)
1712 0 : { PARI_plot T; pari_get_psplot(&T); T.draw = &_psdraw;
1713 0 : return plothraw_i(NULL,&T,X,Y,flags); }
1714 : GEN
1715 16 : plotrecthraw(long ne, GEN data, long flags)
1716 16 : { return plotrecthraw_i(NULL, NULL, ne, data, flags); }
1717 : GEN
1718 18 : plothrawexport(GEN fmt, GEN X, GEN Y, long flags)
1719 18 : { PARI_plot T; pari_get_fmtplot(fmt,&T); return plothraw_i(fmt,&T,X,Y,flags); }
1720 :
1721 : GEN
1722 8 : plothsizes(long flag)
1723 : {
1724 8 : GEN vect = cgetg(1+8,t_VEC);
1725 : PARI_plot T;
1726 :
1727 8 : pari_get_plot(&T);
1728 8 : gel(vect,1) = stoi(T.width);
1729 8 : gel(vect,2) = stoi(T.height);
1730 8 : if (flag) {
1731 0 : gel(vect,3) = dbltor(T.hunit*1.0/T.width);
1732 0 : gel(vect,4) = dbltor(T.vunit*1.0/T.height);
1733 0 : gel(vect,5) = dbltor(T.fwidth*1.0/T.width);
1734 0 : gel(vect,6) = dbltor(T.fheight*1.0/T.height);
1735 : } else {
1736 8 : gel(vect,3) = stoi(T.hunit);
1737 8 : gel(vect,4) = stoi(T.vunit);
1738 8 : gel(vect,5) = stoi(T.fwidth);
1739 8 : gel(vect,6) = stoi(T.fheight);
1740 : }
1741 8 : gel(vect,7) = stoi(T.dwidth);
1742 8 : gel(vect,8) = stoi(T.dheight);
1743 8 : return vect;
1744 : }
1745 :
1746 : /*************************************************************************/
1747 : /* */
1748 : /* POSTSCRIPT OUTPUT */
1749 : /* */
1750 : /*************************************************************************/
1751 : static long
1752 108 : wxy_n(GEN wxy)
1753 : {
1754 : long n;
1755 108 : switch(typ(wxy))
1756 : {
1757 38 : case t_INT: return 1;
1758 70 : case t_VEC:
1759 70 : n = lg(wxy)-1;
1760 70 : if (n%3) pari_err_DIM("plotdraw");
1761 70 : return n/3;
1762 : }
1763 0 : pari_err_TYPE("plotdraw",wxy);
1764 : return 0;/*LCOV_EXCL_LINE*/
1765 : }
1766 : static void
1767 108 : wxy_init(GEN wxy, GEN *pW, GEN *pX, GEN *pY, PARI_plot *T)
1768 : {
1769 108 : long i, n = wxy_n(wxy);
1770 : GEN W, X, Y;
1771 108 : *pW = W = cgetg(n+1, t_VECSMALL); /* win number */
1772 108 : *pX = X = cgetg(n+1, t_VECSMALL);
1773 108 : *pY = Y = cgetg(n+1, t_VECSMALL); /* (x,y)-offset */
1774 108 : if (typ(wxy) == t_INT)
1775 : {
1776 38 : W[1] = itos(wxy); check_rect_init(W[1]);
1777 38 : X[1] = 0;
1778 38 : Y[1] = 0; return;
1779 : }
1780 140 : for (i = 1; i <= n; i++)
1781 : {
1782 70 : GEN w = gel(wxy,3*i-2), x = gel(wxy,3*i-1), y = gel(wxy,3*i);
1783 70 : if (typ(w) != t_INT) pari_err_TYPE("plotdraw",w);
1784 70 : W[i] = itos(w); check_rect_init(W[i]);
1785 70 : if (T) {
1786 0 : X[i] = DTOL(gtodouble(x)*(T->width - 1));
1787 0 : Y[i] = DTOL(gtodouble(y)*(T->height - 1));
1788 : } else {
1789 70 : X[i] = gtos(x);
1790 70 : Y[i] = gtos(y);
1791 : }
1792 : }
1793 : }
1794 : /* if flag is set, rescale wrt T */
1795 : static void
1796 44 : gendraw(PARI_plot *T, GEN wxy, long flag)
1797 : {
1798 : GEN w, x, y, W, X, Y;
1799 : long i, l;
1800 44 : wxy_init(wxy, &w,&x,&y, flag? T: NULL);
1801 44 : l = lg(w);
1802 : /* malloc mandatory in case draw() forks then pari_close(). Done after
1803 : * wxy_init to avoid leak on error */
1804 44 : W = cgetalloc(l, t_VECSMALL);
1805 44 : X = cgetalloc(l, t_VECSMALL);
1806 44 : Y = cgetalloc(l, t_VECSMALL);
1807 88 : for (i = 1; i < l; i++) { W[i] = w[i]; X[i] = x[i]; Y[i] = y[i]; }
1808 44 : Draw(T,W,X,Y);
1809 44 : pari_free(W); pari_free(X); pari_free(Y);
1810 44 : }
1811 : void
1812 0 : psdraw(GEN wxy, long flag)
1813 0 : { PARI_plot T; pari_get_psplot(&T); T.draw = flag? &_psdraw: &_psdraw_scale;
1814 0 : gendraw(&T, wxy, flag); }
1815 : void
1816 44 : plotdraw(GEN wxy, long flag)
1817 44 : { PARI_plot T; pari_get_plot(&T); gendraw(&T, wxy, flag); }
1818 : GEN
1819 64 : plotexport(GEN fmt, GEN wxy, long flag)
1820 : {
1821 64 : pari_sp av = avma;
1822 : GEN w, x, y;
1823 64 : PARI_plot _T, *T = flag? &_T: NULL;
1824 64 : if (T) pari_get_plot(T);
1825 64 : wxy_init(wxy, &w, &x, &y, T);
1826 64 : return gerepileuptoleaf(av, fmt_convert(fmt, w, x, y, T));
1827 : }
1828 :
1829 : /* may be called after pari_close(): don't use the PARI stack */
1830 : void
1831 135 : gen_draw(struct plot_eng *eng, GEN w, GEN x, GEN y, double xs, double ys)
1832 : {
1833 135 : void *data = eng->data;
1834 135 : long i, j, lw = lg(w);
1835 135 : long hgapsize = eng->pl->hunit, fheight = eng->pl->fheight;
1836 135 : long vgapsize = eng->pl->vunit, fwidth = eng->pl->fwidth;
1837 341 : for(i = 1; i < lw; i++)
1838 : {
1839 206 : PariRect *e = &rectgraph[w[i]];
1840 : RectObj *R;
1841 206 : long x0 = x[i], y0 = y[i];
1842 9776 : for (R = RHead(e); R; R = RoNext(R))
1843 : {
1844 9570 : long col = RoCol(R);
1845 9570 : switch(RoType(R))
1846 : {
1847 64 : case ROt_PT:
1848 64 : eng->sc(data,col);
1849 64 : eng->pt(data, DTOL((RoPTx(R)+x0)*xs), DTOL((RoPTy(R)+y0)*ys));
1850 64 : break;
1851 7670 : case ROt_LN:
1852 7670 : eng->sc(data,col);
1853 7670 : eng->ln(data, DTOL((RoLNx1(R)+x0)*xs), DTOL((RoLNy1(R)+y0)*ys),
1854 7670 : DTOL((RoLNx2(R)+x0)*xs), DTOL((RoLNy2(R)+y0)*ys));
1855 7670 : break;
1856 160 : case ROt_BX:
1857 160 : eng->sc(data,col);
1858 160 : eng->bx(data,
1859 160 : DTOL((RoBXx1(R)+x0)*xs),
1860 160 : DTOL((RoBXy1(R)+y0)*ys),
1861 160 : DTOL((RoBXx2(R)-RoBXx1(R))*xs),
1862 160 : DTOL((RoBXy2(R)-RoBXy1(R))*ys));
1863 160 : break;
1864 0 : case ROt_FBX:
1865 0 : eng->sc(data,col);
1866 0 : eng->fb(data,
1867 0 : DTOL((RoBXx1(R)+x0)*xs),
1868 0 : DTOL((RoBXy1(R)+y0)*ys),
1869 0 : DTOL((RoBXx2(R)-RoBXx1(R))*xs),
1870 0 : DTOL((RoBXy2(R)-RoBXy1(R))*ys));
1871 0 : break;
1872 53 : case ROt_MP:
1873 : {
1874 53 : double *ptx = RoMPxs(R);
1875 53 : double *pty = RoMPys(R);
1876 53 : long nb = RoMPcnt(R);
1877 : struct plot_points *points =
1878 53 : (struct plot_points *) pari_malloc(sizeof(*points)*nb);
1879 1841 : for(j=0;j<nb;j++)
1880 : {
1881 1788 : points[j].x = DTOL((ptx[j]+x0)*xs);
1882 1788 : points[j].y = DTOL((pty[j]+y0)*ys);
1883 : }
1884 53 : eng->sc(data,col);
1885 53 : eng->mp(data, nb, points);
1886 53 : pari_free(points);
1887 53 : break;
1888 : }
1889 103 : case ROt_ML:
1890 : {
1891 103 : double *ptx = RoMLxs(R);
1892 103 : double *pty = RoMLys(R);
1893 103 : long nb = RoMLcnt(R);
1894 : struct plot_points *points =
1895 103 : (struct plot_points *) pari_malloc(sizeof(*points)*nb);
1896 60202 : for(j=0;j<nb;j++)
1897 : {
1898 60099 : points[j].x = DTOL((ptx[j]+x0)*xs);
1899 60099 : points[j].y = DTOL((pty[j]+y0)*ys);
1900 : }
1901 103 : eng->sc(data,col);
1902 103 : eng->ml(data, nb, points);
1903 103 : pari_free(points);
1904 103 : break;
1905 : }
1906 320 : case ROt_ST:
1907 : {
1908 320 : long dir = RoSTdir(R);
1909 320 : long h = dir & RoSTdirHPOS_mask, hgap = 0;
1910 320 : long v = dir & RoSTdirVPOS_mask, vgap = 0;
1911 320 : long x, y, l = RoSTl(R);
1912 320 : long shift = (h == RoSTdirLEFT ? 0 : (h == RoSTdirRIGHT? 2: 1));
1913 320 : long vshift= (v == RoSTdirBOTTOM? 0: (v == RoSTdirTOP? 2: 1));
1914 320 : if (dir & RoSTdirHGAP)
1915 142 : hgap = (h == RoSTdirLEFT) ? hgapsize : -hgapsize;
1916 320 : if (dir & RoSTdirVGAP)
1917 71 : vgap = (v == RoSTdirBOTTOM) ? 2*vgapsize : -2*vgapsize;
1918 320 : x = DTOL(xs * (RoSTx(R) + x0 + hgap - (l * fwidth * shift)/2));
1919 320 : y = DTOL(ys * (RoSTy(R) + y0 - (vgap - vshift*(fheight-1))/2));
1920 320 : eng->sc(data,col);
1921 320 : eng->st(data, x, y, RoSTs(R), l);
1922 320 : break;
1923 : }
1924 1200 : default:
1925 1200 : break;
1926 : }
1927 : }
1928 : }
1929 135 : }
1930 : /*************************************************************************/
1931 : /* SVG */
1932 : /*************************************************************************/
1933 :
1934 : struct svg_data {
1935 : pari_str str;
1936 : char hexcolor[8]; /* "#rrggbb\0" */
1937 : };
1938 : #define data_str(d) (&((struct svg_data*)(d))->str)
1939 : #define data_hexcolor(d) (((struct svg_data*)(d))->hexcolor)
1940 :
1941 : /* Work with precision 1/scale */
1942 : static const float SVG_SCALE = 1024.0;
1943 :
1944 : static float
1945 127122 : svg_rescale(float x) { return x / SVG_SCALE; }
1946 :
1947 : static void
1948 992 : svg_point(void *data, long x, long y)
1949 : {
1950 992 : pari_str *S = data_str(data);
1951 :
1952 992 : str_printf(S, "<circle cx='%.2f' cy='%.2f' r='0.5' ",
1953 992 : svg_rescale(x), svg_rescale(y));
1954 992 : str_printf(S, "style='fill:%s;stroke:none;'/>", data_hexcolor(data));
1955 992 : }
1956 :
1957 : static void
1958 4905 : svg_line(void *data, long x1, long y1, long x2, long y2)
1959 : {
1960 4905 : pari_str *S = data_str(data);
1961 :
1962 4905 : str_printf(S, "<line x1='%.2f' y1='%.2f' x2='%.2f' y2='%.2f' ",
1963 4905 : svg_rescale(x1), svg_rescale(y1), svg_rescale(x2), svg_rescale(y2));
1964 4905 : str_printf(S, "style='fill:none;stroke:%s;'/>", data_hexcolor(data));
1965 4905 : }
1966 :
1967 : static void
1968 104 : svg_rect(void *data, long x, long y, long w, long h)
1969 : {
1970 104 : pari_str *S = data_str(data);
1971 :
1972 104 : str_printf(S, "<rect x='%.2f' y='%.2f' width='%.2f' height='%.2f' ",
1973 104 : svg_rescale(x), svg_rescale(y), svg_rescale(w), svg_rescale(h));
1974 104 : str_printf(S, "style='fill:none;stroke:%s;'/>", data_hexcolor(data));
1975 104 : }
1976 :
1977 : static void
1978 0 : svg_fillrect(void *data, long x, long y, long w, long h)
1979 : {
1980 0 : pari_str *S = data_str(data);
1981 0 : const char * color = data_hexcolor(data);
1982 0 : str_printf(S, "<rect x='%.2f' y='%.2f' width='%.2f' height='%.2f' ",
1983 0 : svg_rescale(x), svg_rescale(y), svg_rescale(w), svg_rescale(h));
1984 0 : str_printf(S, "style='fill:%s;stroke:%s;'/>", color, color);
1985 0 : }
1986 :
1987 : static void
1988 32 : svg_points(void *data, long nb, struct plot_points *p)
1989 : {
1990 : long i;
1991 981 : for (i = 0; i < nb; i++)
1992 949 : svg_point(data, p[i].x, p[i].y);
1993 32 : }
1994 :
1995 : static void
1996 5467 : svg_color(void *data, long col)
1997 : {
1998 : static const char hex[] = "0123456789abcdef";
1999 5467 : char *c = data_hexcolor(data);
2000 : int r, g, b;
2001 5467 : long_to_rgb(col, &r, &g, &b);
2002 5467 : c[0] = '#';
2003 5467 : c[1] = hex[r / 16];
2004 5467 : c[2] = hex[r & 15];
2005 5467 : c[3] = hex[g / 16];
2006 5467 : c[4] = hex[g & 15];
2007 5467 : c[5] = hex[b / 16];
2008 5467 : c[6] = hex[b & 15];
2009 5467 : c[7] = '\0';
2010 5467 : }
2011 :
2012 : static void
2013 75 : svg_lines(void *data, long nb, struct plot_points *p)
2014 : {
2015 : long i;
2016 75 : pari_str *S = data_str(data);
2017 :
2018 75 : str_printf(S, "<polyline points='");
2019 52404 : for (i = 0; i < nb; i++)
2020 : {
2021 52329 : if (i > 0) str_printf(S, " ");
2022 52329 : str_printf(S, "%.2f,%.2f", svg_rescale(p[i].x), svg_rescale(p[i].y));
2023 : }
2024 75 : str_printf(S, "' style='fill:none;stroke:%s;'/>", data_hexcolor(data));
2025 75 : }
2026 :
2027 : static void
2028 222 : svg_text(void *data, long x, long y, char *text, long numtext)
2029 : {
2030 222 : pari_str *S = data_str(data);
2031 : (void)numtext;
2032 222 : str_printf(S, "<text x='%.5f' y='%.5f' font-size='%ld' style='fill:%s;'>%s</text>",
2033 222 : svg_rescale(x),svg_rescale(y), 12, data_hexcolor(data), text);
2034 222 : }
2035 :
2036 : static void
2037 86 : svg_head(PARI_plot *T, pari_str *S)
2038 : {
2039 86 : str_printf(S, "<svg width='%ld' height='%ld' version='1.1' xmlns='http://www.w3.org/2000/svg'>", T->width, T->height);
2040 86 : }
2041 :
2042 : static void
2043 86 : svg_tail(pari_str *S)
2044 : {
2045 86 : str_printf(S, "</svg>");
2046 86 : }
2047 :
2048 : char *
2049 86 : rect2svg(GEN w, GEN x, GEN y, PARI_plot *T)
2050 : {
2051 : struct plot_eng pl;
2052 : struct svg_data data;
2053 : PARI_plot U;
2054 :
2055 86 : str_init(&data.str, 1);
2056 86 : svg_color(&data, 0);
2057 86 : if (!T)
2058 : {
2059 36 : long i, l = lg(w), xmax = 0, ymax = 0;
2060 36 : T = &U; pari_get_svgplot(T);
2061 72 : for (i = 1; i < l; i++)
2062 : {
2063 36 : PariRect *e = check_rect_init(w[i]);
2064 36 : xmax = maxss(xmax, RXsize(e) + x[i]);
2065 36 : ymax = maxss(ymax, RYsize(e) + y[i]);
2066 : }
2067 36 : T->width = xmax;
2068 36 : T->height = ymax;
2069 : }
2070 86 : pl.data = &data;
2071 86 : pl.sc = &svg_color;
2072 86 : pl.pt = &svg_point;
2073 86 : pl.ln = &svg_line;
2074 86 : pl.bx = &svg_rect;
2075 86 : pl.fb = &svg_fillrect;
2076 86 : pl.mp = &svg_points;
2077 86 : pl.ml = &svg_lines;
2078 86 : pl.st = &svg_text;
2079 86 : pl.pl = T;
2080 :
2081 86 : svg_head(T, &data.str);
2082 86 : gen_draw(&pl, w, x, y, SVG_SCALE, SVG_SCALE);
2083 86 : svg_tail(&data.str);
2084 :
2085 86 : return data.str.string;
2086 : }
2087 :
2088 : /*************************************************************************/
2089 : /* POSTSCRIPT */
2090 : /*************************************************************************/
2091 : static void
2092 2989 : ps_sc(void *data, long col)
2093 : {
2094 2989 : pari_str *S = (pari_str*)data;
2095 2989 : int r, g, b; long_to_rgb(col, &r, &g, &b);
2096 2989 : if (!r && !g && !b)
2097 2940 : str_puts(S,"c0\n");
2098 : else
2099 49 : str_printf(S,"%.6f %.6f %.6f c\n", r/255., g/255., b/255.);
2100 2989 : }
2101 :
2102 : static void
2103 860 : ps_point(void *data, long x, long y)
2104 : {
2105 860 : pari_str *S = (pari_str*)data;
2106 860 : str_printf(S,"%ld %ld p\n",y,x);
2107 860 : }
2108 :
2109 : static void
2110 2765 : ps_line(void *data, long x1, long y1, long x2, long y2)
2111 : {
2112 2765 : pari_str *S = (pari_str*)data;
2113 2765 : str_printf(S,"%ld %ld m %ld %ld l\n",y1,x1,y2,x2);
2114 2765 : str_printf(S,"stroke\n");
2115 2765 : }
2116 :
2117 : static void
2118 56 : ps_rect(void *data, long x, long y, long w, long h)
2119 : {
2120 56 : pari_str *S = (pari_str*)data;
2121 56 : str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath currentlinejoin 0 setlinejoin stroke setlinejoin\n",
2122 : y,x, y,x+w, y+h,x+w, y+h,x);
2123 56 : }
2124 :
2125 : static void
2126 0 : ps_fillrect(void *data, long x, long y, long w, long h)
2127 : {
2128 0 : pari_str *S = (pari_str*)data;
2129 0 : str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath currentlinejoin 0 setlinejoin fill setlinejoin\n",
2130 : y,x, y,x+w, y+h,x+w, y+h,x);
2131 0 : }
2132 :
2133 : static void
2134 21 : ps_points(void *data, long nb, struct plot_points *p)
2135 : {
2136 : long i;
2137 860 : for (i=0; i<nb; i++) ps_point(data, p[i].x, p[i].y);
2138 21 : }
2139 :
2140 : static void
2141 28 : ps_lines(void *data, long nb, struct plot_points *p)
2142 : {
2143 28 : pari_str *S = (pari_str*)data;
2144 : long i;
2145 28 : str_printf(S,"%ld %ld m\n",p[0].y,p[0].x);
2146 7770 : for (i=1; i<nb; i++) str_printf(S, "%ld %ld l\n", p[i].y, p[i].x);
2147 28 : str_printf(S,"stroke\n");
2148 28 : }
2149 :
2150 : static void
2151 98 : ps_string(void *data, long x, long y, char *s, long length)
2152 : {
2153 98 : pari_str *S = (pari_str*)data;
2154 : (void)length;
2155 98 : if (strpbrk(s, "(\\)")) {
2156 7 : str_printf(S,"(");
2157 42 : while (*s) {
2158 35 : if ( *s=='(' || *s==')' || *s=='\\' ) str_putc(S,'\\');
2159 35 : str_putc(S, *s);
2160 35 : s++;
2161 : }
2162 : } else
2163 91 : str_printf(S,"(%s", s);
2164 98 : str_printf(S,") %ld %ld m 90 rotate show -90 rotate\n", y, x);
2165 98 : }
2166 :
2167 : char *
2168 49 : rect2ps_i(GEN w, GEN x, GEN y, PARI_plot *T, int plotps)
2169 : {
2170 : struct plot_eng pl;
2171 : PARI_plot U;
2172 : pari_str S;
2173 49 : double xs = 0.65*PS_SCALE, ys = 0.65*PS_SCALE;
2174 49 : if (T) /* res wrt T dimens */
2175 : {
2176 21 : if (plotps)
2177 0 : xs = ys = PS_SCALE;
2178 : else
2179 : {
2180 21 : xs *= ((double)PS_WIDTH) / T->width;
2181 21 : ys *= ((double)PS_HEIGH) / T->height;
2182 : }
2183 : }
2184 : else
2185 : {
2186 28 : T = &U; pari_get_psplot(T);
2187 : }
2188 49 : str_init(&S, 1);
2189 : /* Definitions taken from post terminal of Gnuplot. */
2190 49 : str_printf(&S, "%%!\n\
2191 : 50 50 translate\n\
2192 : 1 %d div 1 %d div scale\n\
2193 : 1 setlinejoin\n\
2194 : /p {moveto 0 2 rlineto 2 0 rlineto 0 -2 rlineto closepath fill} def\n\
2195 : /c0 {0 0 0 setrgbcolor} def\n\
2196 : /c {setrgbcolor} def\n\
2197 : /l {lineto} def\n\
2198 : /m {moveto} def\n"
2199 : "/Times-Roman findfont %ld scalefont setfont\n",
2200 49 : PS_SCALE, PS_SCALE, DTOL(T->fheight * xs));
2201 :
2202 49 : pl.sc = &ps_sc;
2203 49 : pl.pt = &ps_point;
2204 49 : pl.ln = &ps_line;
2205 49 : pl.bx = &ps_rect;
2206 49 : pl.fb = &ps_fillrect;
2207 49 : pl.mp = &ps_points;
2208 49 : pl.ml = &ps_lines;
2209 49 : pl.st = &ps_string;
2210 49 : pl.pl = T;
2211 49 : pl.data = (void*)&S;
2212 :
2213 49 : if (plotps) str_printf(&S,"0 %ld translate -90 rotate\n", (T->height - 50)*PS_SCALE);
2214 49 : gen_draw(&pl, w, x, y, xs, ys);
2215 49 : str_puts(&S,"stroke showpage\n");
2216 49 : *S.cur = 0; return S.string;
2217 : }
2218 : char *
2219 49 : rect2ps(GEN w, GEN x, GEN y, PARI_plot *T)
2220 49 : { return rect2ps_i(w,x,y,T,0); }
2221 :
2222 : void
2223 0 : pari_plot_by_file(const char *env, const char *suf, const char *img)
2224 : {
2225 0 : const char *cmd, *s = pari_unique_filename_suffix("plotfile", suf);
2226 0 : FILE *f = fopen(s, "w");
2227 0 : if (!f) pari_err_FILE("image file", s);
2228 0 : fputs(img, f); (void)fclose(f);
2229 0 : cmd = os_getenv(env);
2230 : #ifdef GP_MIME_OPEN
2231 0 : if (!cmd) cmd = GP_MIME_OPEN;
2232 : #else
2233 : if (!cmd) cmd = "open -W";
2234 : #endif
2235 0 : cmd = pari_sprintf("%s \"%s\" 2>/dev/null", cmd, s);
2236 0 : gpsystem(cmd);
2237 0 : pari_unlink(s);
2238 0 : pari_free((char*)s);
2239 0 : }
2240 :
2241 : /*************************************************************************/
2242 : /* */
2243 : /* RGB COLORS */
2244 : /* */
2245 : /*************************************************************************/
2246 : /* generated from /etc/X11/rgb.txt by the following perl script
2247 : #!/usr/bin/perl
2248 : while(<>)
2249 : {
2250 : ($hex, $name) = split(/\t\t/, $_);
2251 : $hex =~ s/^ +//; chomp($name); $name =~ s, *,,g;
2252 : $hex = sprintf("0x%02x%02x%02x", split(/\s+/, $hex));
2253 : $name = lc($name); next if ($done{$name});
2254 : $done{$name} = 1;
2255 : print "COL(\"$name\", $hex),\n";
2256 : }
2257 : */
2258 :
2259 : #define COL(x,y) {(void*)x,(void*)y,0,NULL}
2260 : static hashentry col_list[] = {
2261 : COL("", 0x000000),
2262 : COL("snow", 0xfffafa),
2263 : COL("ghostwhite", 0xf8f8ff),
2264 : COL("whitesmoke", 0xf5f5f5),
2265 : COL("gainsboro", 0xdcdcdc),
2266 : COL("floralwhite", 0xfffaf0),
2267 : COL("oldlace", 0xfdf5e6),
2268 : COL("linen", 0xfaf0e6),
2269 : COL("antiquewhite", 0xfaebd7),
2270 : COL("papayawhip", 0xffefd5),
2271 : COL("blanchedalmond", 0xffebcd),
2272 : COL("bisque", 0xffe4c4),
2273 : COL("peachpuff", 0xffdab9),
2274 : COL("navajowhite", 0xffdead),
2275 : COL("moccasin", 0xffe4b5),
2276 : COL("cornsilk", 0xfff8dc),
2277 : COL("ivory", 0xfffff0),
2278 : COL("lemonchiffon", 0xfffacd),
2279 : COL("seashell", 0xfff5ee),
2280 : COL("honeydew", 0xf0fff0),
2281 : COL("mintcream", 0xf5fffa),
2282 : COL("azure", 0xf0ffff),
2283 : COL("aliceblue", 0xf0f8ff),
2284 : COL("lavender", 0xe6e6fa),
2285 : COL("lavenderblush", 0xfff0f5),
2286 : COL("mistyrose", 0xffe4e1),
2287 : COL("white", 0xffffff),
2288 : COL("black", 0x000000),
2289 : COL("darkslategray", 0x2f4f4f),
2290 : COL("darkslategrey", 0x2f4f4f),
2291 : COL("dimgray", 0x696969),
2292 : COL("dimgrey", 0x696969),
2293 : COL("slategray", 0x708090),
2294 : COL("slategrey", 0x708090),
2295 : COL("lightslategray", 0x778899),
2296 : COL("lightslategrey", 0x778899),
2297 : COL("gray", 0xbebebe),
2298 : COL("grey", 0xbebebe),
2299 : COL("lightgrey", 0xd3d3d3),
2300 : COL("lightgray", 0xd3d3d3),
2301 : COL("midnightblue", 0x191970),
2302 : COL("navy", 0x000080),
2303 : COL("navyblue", 0x000080),
2304 : COL("cornflowerblue", 0x6495ed),
2305 : COL("darkslateblue", 0x483d8b),
2306 : COL("slateblue", 0x6a5acd),
2307 : COL("mediumslateblue", 0x7b68ee),
2308 : COL("lightslateblue", 0x8470ff),
2309 : COL("mediumblue", 0x0000cd),
2310 : COL("royalblue", 0x4169e1),
2311 : COL("blue", 0x0000ff),
2312 : COL("dodgerblue", 0x1e90ff),
2313 : COL("deepskyblue", 0x00bfff),
2314 : COL("skyblue", 0x87ceeb),
2315 : COL("lightskyblue", 0x87cefa),
2316 : COL("steelblue", 0x4682b4),
2317 : COL("lightsteelblue", 0xb0c4de),
2318 : COL("lightblue", 0xadd8e6),
2319 : COL("powderblue", 0xb0e0e6),
2320 : COL("paleturquoise", 0xafeeee),
2321 : COL("darkturquoise", 0x00ced1),
2322 : COL("mediumturquoise", 0x48d1cc),
2323 : COL("turquoise", 0x40e0d0),
2324 : COL("cyan", 0x00ffff),
2325 : COL("lightcyan", 0xe0ffff),
2326 : COL("cadetblue", 0x5f9ea0),
2327 : COL("mediumaquamarine", 0x66cdaa),
2328 : COL("aquamarine", 0x7fffd4),
2329 : COL("darkgreen", 0x006400),
2330 : COL("darkolivegreen", 0x556b2f),
2331 : COL("darkseagreen", 0x8fbc8f),
2332 : COL("seagreen", 0x2e8b57),
2333 : COL("mediumseagreen", 0x3cb371),
2334 : COL("lightseagreen", 0x20b2aa),
2335 : COL("palegreen", 0x98fb98),
2336 : COL("springgreen", 0x00ff7f),
2337 : COL("lawngreen", 0x7cfc00),
2338 : COL("green", 0x00ff00),
2339 : COL("chartreuse", 0x7fff00),
2340 : COL("mediumspringgreen", 0x00fa9a),
2341 : COL("greenyellow", 0xadff2f),
2342 : COL("limegreen", 0x32cd32),
2343 : COL("yellowgreen", 0x9acd32),
2344 : COL("forestgreen", 0x228b22),
2345 : COL("olivedrab", 0x6b8e23),
2346 : COL("darkkhaki", 0xbdb76b),
2347 : COL("khaki", 0xf0e68c),
2348 : COL("palegoldenrod", 0xeee8aa),
2349 : COL("lightgoldenrodyellow", 0xfafad2),
2350 : COL("lightyellow", 0xffffe0),
2351 : COL("yellow", 0xffff00),
2352 : COL("gold", 0xffd700),
2353 : COL("lightgoldenrod", 0xeedd82),
2354 : COL("goldenrod", 0xdaa520),
2355 : COL("darkgoldenrod", 0xb8860b),
2356 : COL("rosybrown", 0xbc8f8f),
2357 : COL("indianred", 0xcd5c5c),
2358 : COL("saddlebrown", 0x8b4513),
2359 : COL("sienna", 0xa0522d),
2360 : COL("peru", 0xcd853f),
2361 : COL("burlywood", 0xdeb887),
2362 : COL("beige", 0xf5f5dc),
2363 : COL("wheat", 0xf5deb3),
2364 : COL("sandybrown", 0xf4a460),
2365 : COL("tan", 0xd2b48c),
2366 : COL("chocolate", 0xd2691e),
2367 : COL("firebrick", 0xb22222),
2368 : COL("brown", 0xa52a2a),
2369 : COL("darksalmon", 0xe9967a),
2370 : COL("salmon", 0xfa8072),
2371 : COL("lightsalmon", 0xffa07a),
2372 : COL("orange", 0xffa500),
2373 : COL("darkorange", 0xff8c00),
2374 : COL("coral", 0xff7f50),
2375 : COL("lightcoral", 0xf08080),
2376 : COL("tomato", 0xff6347),
2377 : COL("orangered", 0xff4500),
2378 : COL("red", 0xff0000),
2379 : COL("hotpink", 0xff69b4),
2380 : COL("deeppink", 0xff1493),
2381 : COL("pink", 0xffc0cb),
2382 : COL("lightpink", 0xffb6c1),
2383 : COL("palevioletred", 0xdb7093),
2384 : COL("maroon", 0xb03060),
2385 : COL("mediumvioletred", 0xc71585),
2386 : COL("violetred", 0xd02090),
2387 : COL("magenta", 0xff00ff),
2388 : COL("violet", 0xee82ee),
2389 : COL("plum", 0xdda0dd),
2390 : COL("orchid", 0xda70d6),
2391 : COL("mediumorchid", 0xba55d3),
2392 : COL("darkorchid", 0x9932cc),
2393 : COL("darkviolet", 0x9400d3),
2394 : COL("blueviolet", 0x8a2be2),
2395 : COL("purple", 0xa020f0),
2396 : COL("mediumpurple", 0x9370db),
2397 : COL("thistle", 0xd8bfd8),
2398 : COL("snow1", 0xfffafa),
2399 : COL("snow2", 0xeee9e9),
2400 : COL("snow3", 0xcdc9c9),
2401 : COL("snow4", 0x8b8989),
2402 : COL("seashell1", 0xfff5ee),
2403 : COL("seashell2", 0xeee5de),
2404 : COL("seashell3", 0xcdc5bf),
2405 : COL("seashell4", 0x8b8682),
2406 : COL("antiquewhite1", 0xffefdb),
2407 : COL("antiquewhite2", 0xeedfcc),
2408 : COL("antiquewhite3", 0xcdc0b0),
2409 : COL("antiquewhite4", 0x8b8378),
2410 : COL("bisque1", 0xffe4c4),
2411 : COL("bisque2", 0xeed5b7),
2412 : COL("bisque3", 0xcdb79e),
2413 : COL("bisque4", 0x8b7d6b),
2414 : COL("peachpuff1", 0xffdab9),
2415 : COL("peachpuff2", 0xeecbad),
2416 : COL("peachpuff3", 0xcdaf95),
2417 : COL("peachpuff4", 0x8b7765),
2418 : COL("navajowhite1", 0xffdead),
2419 : COL("navajowhite2", 0xeecfa1),
2420 : COL("navajowhite3", 0xcdb38b),
2421 : COL("navajowhite4", 0x8b795e),
2422 : COL("lemonchiffon1", 0xfffacd),
2423 : COL("lemonchiffon2", 0xeee9bf),
2424 : COL("lemonchiffon3", 0xcdc9a5),
2425 : COL("lemonchiffon4", 0x8b8970),
2426 : COL("cornsilk1", 0xfff8dc),
2427 : COL("cornsilk2", 0xeee8cd),
2428 : COL("cornsilk3", 0xcdc8b1),
2429 : COL("cornsilk4", 0x8b8878),
2430 : COL("ivory1", 0xfffff0),
2431 : COL("ivory2", 0xeeeee0),
2432 : COL("ivory3", 0xcdcdc1),
2433 : COL("ivory4", 0x8b8b83),
2434 : COL("honeydew1", 0xf0fff0),
2435 : COL("honeydew2", 0xe0eee0),
2436 : COL("honeydew3", 0xc1cdc1),
2437 : COL("honeydew4", 0x838b83),
2438 : COL("lavenderblush1", 0xfff0f5),
2439 : COL("lavenderblush2", 0xeee0e5),
2440 : COL("lavenderblush3", 0xcdc1c5),
2441 : COL("lavenderblush4", 0x8b8386),
2442 : COL("mistyrose1", 0xffe4e1),
2443 : COL("mistyrose2", 0xeed5d2),
2444 : COL("mistyrose3", 0xcdb7b5),
2445 : COL("mistyrose4", 0x8b7d7b),
2446 : COL("azure1", 0xf0ffff),
2447 : COL("azure2", 0xe0eeee),
2448 : COL("azure3", 0xc1cdcd),
2449 : COL("azure4", 0x838b8b),
2450 : COL("slateblue1", 0x836fff),
2451 : COL("slateblue2", 0x7a67ee),
2452 : COL("slateblue3", 0x6959cd),
2453 : COL("slateblue4", 0x473c8b),
2454 : COL("royalblue1", 0x4876ff),
2455 : COL("royalblue2", 0x436eee),
2456 : COL("royalblue3", 0x3a5fcd),
2457 : COL("royalblue4", 0x27408b),
2458 : COL("blue1", 0x0000ff),
2459 : COL("blue2", 0x0000ee),
2460 : COL("blue3", 0x0000cd),
2461 : COL("blue4", 0x00008b),
2462 : COL("dodgerblue1", 0x1e90ff),
2463 : COL("dodgerblue2", 0x1c86ee),
2464 : COL("dodgerblue3", 0x1874cd),
2465 : COL("dodgerblue4", 0x104e8b),
2466 : COL("steelblue1", 0x63b8ff),
2467 : COL("steelblue2", 0x5cacee),
2468 : COL("steelblue3", 0x4f94cd),
2469 : COL("steelblue4", 0x36648b),
2470 : COL("deepskyblue1", 0x00bfff),
2471 : COL("deepskyblue2", 0x00b2ee),
2472 : COL("deepskyblue3", 0x009acd),
2473 : COL("deepskyblue4", 0x00688b),
2474 : COL("skyblue1", 0x87ceff),
2475 : COL("skyblue2", 0x7ec0ee),
2476 : COL("skyblue3", 0x6ca6cd),
2477 : COL("skyblue4", 0x4a708b),
2478 : COL("lightskyblue1", 0xb0e2ff),
2479 : COL("lightskyblue2", 0xa4d3ee),
2480 : COL("lightskyblue3", 0x8db6cd),
2481 : COL("lightskyblue4", 0x607b8b),
2482 : COL("slategray1", 0xc6e2ff),
2483 : COL("slategray2", 0xb9d3ee),
2484 : COL("slategray3", 0x9fb6cd),
2485 : COL("slategray4", 0x6c7b8b),
2486 : COL("lightsteelblue1", 0xcae1ff),
2487 : COL("lightsteelblue2", 0xbcd2ee),
2488 : COL("lightsteelblue3", 0xa2b5cd),
2489 : COL("lightsteelblue4", 0x6e7b8b),
2490 : COL("lightblue1", 0xbfefff),
2491 : COL("lightblue2", 0xb2dfee),
2492 : COL("lightblue3", 0x9ac0cd),
2493 : COL("lightblue4", 0x68838b),
2494 : COL("lightcyan1", 0xe0ffff),
2495 : COL("lightcyan2", 0xd1eeee),
2496 : COL("lightcyan3", 0xb4cdcd),
2497 : COL("lightcyan4", 0x7a8b8b),
2498 : COL("paleturquoise1", 0xbbffff),
2499 : COL("paleturquoise2", 0xaeeeee),
2500 : COL("paleturquoise3", 0x96cdcd),
2501 : COL("paleturquoise4", 0x668b8b),
2502 : COL("cadetblue1", 0x98f5ff),
2503 : COL("cadetblue2", 0x8ee5ee),
2504 : COL("cadetblue3", 0x7ac5cd),
2505 : COL("cadetblue4", 0x53868b),
2506 : COL("turquoise1", 0x00f5ff),
2507 : COL("turquoise2", 0x00e5ee),
2508 : COL("turquoise3", 0x00c5cd),
2509 : COL("turquoise4", 0x00868b),
2510 : COL("cyan1", 0x00ffff),
2511 : COL("cyan2", 0x00eeee),
2512 : COL("cyan3", 0x00cdcd),
2513 : COL("cyan4", 0x008b8b),
2514 : COL("darkslategray1", 0x97ffff),
2515 : COL("darkslategray2", 0x8deeee),
2516 : COL("darkslategray3", 0x79cdcd),
2517 : COL("darkslategray4", 0x528b8b),
2518 : COL("aquamarine1", 0x7fffd4),
2519 : COL("aquamarine2", 0x76eec6),
2520 : COL("aquamarine3", 0x66cdaa),
2521 : COL("aquamarine4", 0x458b74),
2522 : COL("darkseagreen1", 0xc1ffc1),
2523 : COL("darkseagreen2", 0xb4eeb4),
2524 : COL("darkseagreen3", 0x9bcd9b),
2525 : COL("darkseagreen4", 0x698b69),
2526 : COL("seagreen1", 0x54ff9f),
2527 : COL("seagreen2", 0x4eee94),
2528 : COL("seagreen3", 0x43cd80),
2529 : COL("seagreen4", 0x2e8b57),
2530 : COL("palegreen1", 0x9aff9a),
2531 : COL("palegreen2", 0x90ee90),
2532 : COL("palegreen3", 0x7ccd7c),
2533 : COL("palegreen4", 0x548b54),
2534 : COL("springgreen1", 0x00ff7f),
2535 : COL("springgreen2", 0x00ee76),
2536 : COL("springgreen3", 0x00cd66),
2537 : COL("springgreen4", 0x008b45),
2538 : COL("green1", 0x00ff00),
2539 : COL("green2", 0x00ee00),
2540 : COL("green3", 0x00cd00),
2541 : COL("green4", 0x008b00),
2542 : COL("chartreuse1", 0x7fff00),
2543 : COL("chartreuse2", 0x76ee00),
2544 : COL("chartreuse3", 0x66cd00),
2545 : COL("chartreuse4", 0x458b00),
2546 : COL("olivedrab1", 0xc0ff3e),
2547 : COL("olivedrab2", 0xb3ee3a),
2548 : COL("olivedrab3", 0x9acd32),
2549 : COL("olivedrab4", 0x698b22),
2550 : COL("darkolivegreen1", 0xcaff70),
2551 : COL("darkolivegreen2", 0xbcee68),
2552 : COL("darkolivegreen3", 0xa2cd5a),
2553 : COL("darkolivegreen4", 0x6e8b3d),
2554 : COL("khaki1", 0xfff68f),
2555 : COL("khaki2", 0xeee685),
2556 : COL("khaki3", 0xcdc673),
2557 : COL("khaki4", 0x8b864e),
2558 : COL("lightgoldenrod1", 0xffec8b),
2559 : COL("lightgoldenrod2", 0xeedc82),
2560 : COL("lightgoldenrod3", 0xcdbe70),
2561 : COL("lightgoldenrod4", 0x8b814c),
2562 : COL("lightyellow1", 0xffffe0),
2563 : COL("lightyellow2", 0xeeeed1),
2564 : COL("lightyellow3", 0xcdcdb4),
2565 : COL("lightyellow4", 0x8b8b7a),
2566 : COL("yellow1", 0xffff00),
2567 : COL("yellow2", 0xeeee00),
2568 : COL("yellow3", 0xcdcd00),
2569 : COL("yellow4", 0x8b8b00),
2570 : COL("gold1", 0xffd700),
2571 : COL("gold2", 0xeec900),
2572 : COL("gold3", 0xcdad00),
2573 : COL("gold4", 0x8b7500),
2574 : COL("goldenrod1", 0xffc125),
2575 : COL("goldenrod2", 0xeeb422),
2576 : COL("goldenrod3", 0xcd9b1d),
2577 : COL("goldenrod4", 0x8b6914),
2578 : COL("darkgoldenrod1", 0xffb90f),
2579 : COL("darkgoldenrod2", 0xeead0e),
2580 : COL("darkgoldenrod3", 0xcd950c),
2581 : COL("darkgoldenrod4", 0x8b6508),
2582 : COL("rosybrown1", 0xffc1c1),
2583 : COL("rosybrown2", 0xeeb4b4),
2584 : COL("rosybrown3", 0xcd9b9b),
2585 : COL("rosybrown4", 0x8b6969),
2586 : COL("indianred1", 0xff6a6a),
2587 : COL("indianred2", 0xee6363),
2588 : COL("indianred3", 0xcd5555),
2589 : COL("indianred4", 0x8b3a3a),
2590 : COL("sienna1", 0xff8247),
2591 : COL("sienna2", 0xee7942),
2592 : COL("sienna3", 0xcd6839),
2593 : COL("sienna4", 0x8b4726),
2594 : COL("burlywood1", 0xffd39b),
2595 : COL("burlywood2", 0xeec591),
2596 : COL("burlywood3", 0xcdaa7d),
2597 : COL("burlywood4", 0x8b7355),
2598 : COL("wheat1", 0xffe7ba),
2599 : COL("wheat2", 0xeed8ae),
2600 : COL("wheat3", 0xcdba96),
2601 : COL("wheat4", 0x8b7e66),
2602 : COL("tan1", 0xffa54f),
2603 : COL("tan2", 0xee9a49),
2604 : COL("tan3", 0xcd853f),
2605 : COL("tan4", 0x8b5a2b),
2606 : COL("chocolate1", 0xff7f24),
2607 : COL("chocolate2", 0xee7621),
2608 : COL("chocolate3", 0xcd661d),
2609 : COL("chocolate4", 0x8b4513),
2610 : COL("firebrick1", 0xff3030),
2611 : COL("firebrick2", 0xee2c2c),
2612 : COL("firebrick3", 0xcd2626),
2613 : COL("firebrick4", 0x8b1a1a),
2614 : COL("brown1", 0xff4040),
2615 : COL("brown2", 0xee3b3b),
2616 : COL("brown3", 0xcd3333),
2617 : COL("brown4", 0x8b2323),
2618 : COL("salmon1", 0xff8c69),
2619 : COL("salmon2", 0xee8262),
2620 : COL("salmon3", 0xcd7054),
2621 : COL("salmon4", 0x8b4c39),
2622 : COL("lightsalmon1", 0xffa07a),
2623 : COL("lightsalmon2", 0xee9572),
2624 : COL("lightsalmon3", 0xcd8162),
2625 : COL("lightsalmon4", 0x8b5742),
2626 : COL("orange1", 0xffa500),
2627 : COL("orange2", 0xee9a00),
2628 : COL("orange3", 0xcd8500),
2629 : COL("orange4", 0x8b5a00),
2630 : COL("darkorange1", 0xff7f00),
2631 : COL("darkorange2", 0xee7600),
2632 : COL("darkorange3", 0xcd6600),
2633 : COL("darkorange4", 0x8b4500),
2634 : COL("coral1", 0xff7256),
2635 : COL("coral2", 0xee6a50),
2636 : COL("coral3", 0xcd5b45),
2637 : COL("coral4", 0x8b3e2f),
2638 : COL("tomato1", 0xff6347),
2639 : COL("tomato2", 0xee5c42),
2640 : COL("tomato3", 0xcd4f39),
2641 : COL("tomato4", 0x8b3626),
2642 : COL("orangered1", 0xff4500),
2643 : COL("orangered2", 0xee4000),
2644 : COL("orangered3", 0xcd3700),
2645 : COL("orangered4", 0x8b2500),
2646 : COL("red1", 0xff0000),
2647 : COL("red2", 0xee0000),
2648 : COL("red3", 0xcd0000),
2649 : COL("red4", 0x8b0000),
2650 : COL("debianred", 0xd70751),
2651 : COL("deeppink1", 0xff1493),
2652 : COL("deeppink2", 0xee1289),
2653 : COL("deeppink3", 0xcd1076),
2654 : COL("deeppink4", 0x8b0a50),
2655 : COL("hotpink1", 0xff6eb4),
2656 : COL("hotpink2", 0xee6aa7),
2657 : COL("hotpink3", 0xcd6090),
2658 : COL("hotpink4", 0x8b3a62),
2659 : COL("pink1", 0xffb5c5),
2660 : COL("pink2", 0xeea9b8),
2661 : COL("pink3", 0xcd919e),
2662 : COL("pink4", 0x8b636c),
2663 : COL("lightpink1", 0xffaeb9),
2664 : COL("lightpink2", 0xeea2ad),
2665 : COL("lightpink3", 0xcd8c95),
2666 : COL("lightpink4", 0x8b5f65),
2667 : COL("palevioletred1", 0xff82ab),
2668 : COL("palevioletred2", 0xee799f),
2669 : COL("palevioletred3", 0xcd6889),
2670 : COL("palevioletred4", 0x8b475d),
2671 : COL("maroon1", 0xff34b3),
2672 : COL("maroon2", 0xee30a7),
2673 : COL("maroon3", 0xcd2990),
2674 : COL("maroon4", 0x8b1c62),
2675 : COL("violetred1", 0xff3e96),
2676 : COL("violetred2", 0xee3a8c),
2677 : COL("violetred3", 0xcd3278),
2678 : COL("violetred4", 0x8b2252),
2679 : COL("magenta1", 0xff00ff),
2680 : COL("magenta2", 0xee00ee),
2681 : COL("magenta3", 0xcd00cd),
2682 : COL("magenta4", 0x8b008b),
2683 : COL("orchid1", 0xff83fa),
2684 : COL("orchid2", 0xee7ae9),
2685 : COL("orchid3", 0xcd69c9),
2686 : COL("orchid4", 0x8b4789),
2687 : COL("plum1", 0xffbbff),
2688 : COL("plum2", 0xeeaeee),
2689 : COL("plum3", 0xcd96cd),
2690 : COL("plum4", 0x8b668b),
2691 : COL("mediumorchid1", 0xe066ff),
2692 : COL("mediumorchid2", 0xd15fee),
2693 : COL("mediumorchid3", 0xb452cd),
2694 : COL("mediumorchid4", 0x7a378b),
2695 : COL("darkorchid1", 0xbf3eff),
2696 : COL("darkorchid2", 0xb23aee),
2697 : COL("darkorchid3", 0x9a32cd),
2698 : COL("darkorchid4", 0x68228b),
2699 : COL("purple1", 0x9b30ff),
2700 : COL("purple2", 0x912cee),
2701 : COL("purple3", 0x7d26cd),
2702 : COL("purple4", 0x551a8b),
2703 : COL("mediumpurple1", 0xab82ff),
2704 : COL("mediumpurple2", 0x9f79ee),
2705 : COL("mediumpurple3", 0x8968cd),
2706 : COL("mediumpurple4", 0x5d478b),
2707 : COL("thistle1", 0xffe1ff),
2708 : COL("thistle2", 0xeed2ee),
2709 : COL("thistle3", 0xcdb5cd),
2710 : COL("thistle4", 0x8b7b8b),
2711 : COL("gray0", 0x000000),
2712 : COL("grey0", 0x000000),
2713 : COL("gray1", 0x030303),
2714 : COL("grey1", 0x030303),
2715 : COL("gray2", 0x050505),
2716 : COL("grey2", 0x050505),
2717 : COL("gray3", 0x080808),
2718 : COL("grey3", 0x080808),
2719 : COL("gray4", 0x0a0a0a),
2720 : COL("grey4", 0x0a0a0a),
2721 : COL("gray5", 0x0d0d0d),
2722 : COL("grey5", 0x0d0d0d),
2723 : COL("gray6", 0x0f0f0f),
2724 : COL("grey6", 0x0f0f0f),
2725 : COL("gray7", 0x121212),
2726 : COL("grey7", 0x121212),
2727 : COL("gray8", 0x141414),
2728 : COL("grey8", 0x141414),
2729 : COL("gray9", 0x171717),
2730 : COL("grey9", 0x171717),
2731 : COL("gray10", 0x1a1a1a),
2732 : COL("grey10", 0x1a1a1a),
2733 : COL("gray11", 0x1c1c1c),
2734 : COL("grey11", 0x1c1c1c),
2735 : COL("gray12", 0x1f1f1f),
2736 : COL("grey12", 0x1f1f1f),
2737 : COL("gray13", 0x212121),
2738 : COL("grey13", 0x212121),
2739 : COL("gray14", 0x242424),
2740 : COL("grey14", 0x242424),
2741 : COL("gray15", 0x262626),
2742 : COL("grey15", 0x262626),
2743 : COL("gray16", 0x292929),
2744 : COL("grey16", 0x292929),
2745 : COL("gray17", 0x2b2b2b),
2746 : COL("grey17", 0x2b2b2b),
2747 : COL("gray18", 0x2e2e2e),
2748 : COL("grey18", 0x2e2e2e),
2749 : COL("gray19", 0x303030),
2750 : COL("grey19", 0x303030),
2751 : COL("gray20", 0x333333),
2752 : COL("grey20", 0x333333),
2753 : COL("gray21", 0x363636),
2754 : COL("grey21", 0x363636),
2755 : COL("gray22", 0x383838),
2756 : COL("grey22", 0x383838),
2757 : COL("gray23", 0x3b3b3b),
2758 : COL("grey23", 0x3b3b3b),
2759 : COL("gray24", 0x3d3d3d),
2760 : COL("grey24", 0x3d3d3d),
2761 : COL("gray25", 0x404040),
2762 : COL("grey25", 0x404040),
2763 : COL("gray26", 0x424242),
2764 : COL("grey26", 0x424242),
2765 : COL("gray27", 0x454545),
2766 : COL("grey27", 0x454545),
2767 : COL("gray28", 0x474747),
2768 : COL("grey28", 0x474747),
2769 : COL("gray29", 0x4a4a4a),
2770 : COL("grey29", 0x4a4a4a),
2771 : COL("gray30", 0x4d4d4d),
2772 : COL("grey30", 0x4d4d4d),
2773 : COL("gray31", 0x4f4f4f),
2774 : COL("grey31", 0x4f4f4f),
2775 : COL("gray32", 0x525252),
2776 : COL("grey32", 0x525252),
2777 : COL("gray33", 0x545454),
2778 : COL("grey33", 0x545454),
2779 : COL("gray34", 0x575757),
2780 : COL("grey34", 0x575757),
2781 : COL("gray35", 0x595959),
2782 : COL("grey35", 0x595959),
2783 : COL("gray36", 0x5c5c5c),
2784 : COL("grey36", 0x5c5c5c),
2785 : COL("gray37", 0x5e5e5e),
2786 : COL("grey37", 0x5e5e5e),
2787 : COL("gray38", 0x616161),
2788 : COL("grey38", 0x616161),
2789 : COL("gray39", 0x636363),
2790 : COL("grey39", 0x636363),
2791 : COL("gray40", 0x666666),
2792 : COL("grey40", 0x666666),
2793 : COL("gray41", 0x696969),
2794 : COL("grey41", 0x696969),
2795 : COL("gray42", 0x6b6b6b),
2796 : COL("grey42", 0x6b6b6b),
2797 : COL("gray43", 0x6e6e6e),
2798 : COL("grey43", 0x6e6e6e),
2799 : COL("gray44", 0x707070),
2800 : COL("grey44", 0x707070),
2801 : COL("gray45", 0x737373),
2802 : COL("grey45", 0x737373),
2803 : COL("gray46", 0x757575),
2804 : COL("grey46", 0x757575),
2805 : COL("gray47", 0x787878),
2806 : COL("grey47", 0x787878),
2807 : COL("gray48", 0x7a7a7a),
2808 : COL("grey48", 0x7a7a7a),
2809 : COL("gray49", 0x7d7d7d),
2810 : COL("grey49", 0x7d7d7d),
2811 : COL("gray50", 0x7f7f7f),
2812 : COL("grey50", 0x7f7f7f),
2813 : COL("gray51", 0x828282),
2814 : COL("grey51", 0x828282),
2815 : COL("gray52", 0x858585),
2816 : COL("grey52", 0x858585),
2817 : COL("gray53", 0x878787),
2818 : COL("grey53", 0x878787),
2819 : COL("gray54", 0x8a8a8a),
2820 : COL("grey54", 0x8a8a8a),
2821 : COL("gray55", 0x8c8c8c),
2822 : COL("grey55", 0x8c8c8c),
2823 : COL("gray56", 0x8f8f8f),
2824 : COL("grey56", 0x8f8f8f),
2825 : COL("gray57", 0x919191),
2826 : COL("grey57", 0x919191),
2827 : COL("gray58", 0x949494),
2828 : COL("grey58", 0x949494),
2829 : COL("gray59", 0x969696),
2830 : COL("grey59", 0x969696),
2831 : COL("gray60", 0x999999),
2832 : COL("grey60", 0x999999),
2833 : COL("gray61", 0x9c9c9c),
2834 : COL("grey61", 0x9c9c9c),
2835 : COL("gray62", 0x9e9e9e),
2836 : COL("grey62", 0x9e9e9e),
2837 : COL("gray63", 0xa1a1a1),
2838 : COL("grey63", 0xa1a1a1),
2839 : COL("gray64", 0xa3a3a3),
2840 : COL("grey64", 0xa3a3a3),
2841 : COL("gray65", 0xa6a6a6),
2842 : COL("grey65", 0xa6a6a6),
2843 : COL("gray66", 0xa8a8a8),
2844 : COL("grey66", 0xa8a8a8),
2845 : COL("gray67", 0xababab),
2846 : COL("grey67", 0xababab),
2847 : COL("gray68", 0xadadad),
2848 : COL("grey68", 0xadadad),
2849 : COL("gray69", 0xb0b0b0),
2850 : COL("grey69", 0xb0b0b0),
2851 : COL("gray70", 0xb3b3b3),
2852 : COL("grey70", 0xb3b3b3),
2853 : COL("gray71", 0xb5b5b5),
2854 : COL("grey71", 0xb5b5b5),
2855 : COL("gray72", 0xb8b8b8),
2856 : COL("grey72", 0xb8b8b8),
2857 : COL("gray73", 0xbababa),
2858 : COL("grey73", 0xbababa),
2859 : COL("gray74", 0xbdbdbd),
2860 : COL("grey74", 0xbdbdbd),
2861 : COL("gray75", 0xbfbfbf),
2862 : COL("grey75", 0xbfbfbf),
2863 : COL("gray76", 0xc2c2c2),
2864 : COL("grey76", 0xc2c2c2),
2865 : COL("gray77", 0xc4c4c4),
2866 : COL("grey77", 0xc4c4c4),
2867 : COL("gray78", 0xc7c7c7),
2868 : COL("grey78", 0xc7c7c7),
2869 : COL("gray79", 0xc9c9c9),
2870 : COL("grey79", 0xc9c9c9),
2871 : COL("gray80", 0xcccccc),
2872 : COL("grey80", 0xcccccc),
2873 : COL("gray81", 0xcfcfcf),
2874 : COL("grey81", 0xcfcfcf),
2875 : COL("gray82", 0xd1d1d1),
2876 : COL("grey82", 0xd1d1d1),
2877 : COL("gray83", 0xd4d4d4),
2878 : COL("grey83", 0xd4d4d4),
2879 : COL("gray84", 0xd6d6d6),
2880 : COL("grey84", 0xd6d6d6),
2881 : COL("gray85", 0xd9d9d9),
2882 : COL("grey85", 0xd9d9d9),
2883 : COL("gray86", 0xdbdbdb),
2884 : COL("grey86", 0xdbdbdb),
2885 : COL("gray87", 0xdedede),
2886 : COL("grey87", 0xdedede),
2887 : COL("gray88", 0xe0e0e0),
2888 : COL("grey88", 0xe0e0e0),
2889 : COL("gray89", 0xe3e3e3),
2890 : COL("grey89", 0xe3e3e3),
2891 : COL("gray90", 0xe5e5e5),
2892 : COL("grey90", 0xe5e5e5),
2893 : COL("gray91", 0xe8e8e8),
2894 : COL("grey91", 0xe8e8e8),
2895 : COL("gray92", 0xebebeb),
2896 : COL("grey92", 0xebebeb),
2897 : COL("gray93", 0xededed),
2898 : COL("grey93", 0xededed),
2899 : COL("gray94", 0xf0f0f0),
2900 : COL("grey94", 0xf0f0f0),
2901 : COL("gray95", 0xf2f2f2),
2902 : COL("grey95", 0xf2f2f2),
2903 : COL("gray96", 0xf5f5f5),
2904 : COL("grey96", 0xf5f5f5),
2905 : COL("gray97", 0xf7f7f7),
2906 : COL("grey97", 0xf7f7f7),
2907 : COL("gray98", 0xfafafa),
2908 : COL("grey98", 0xfafafa),
2909 : COL("gray99", 0xfcfcfc),
2910 : COL("grey99", 0xfcfcfc),
2911 : COL("gray100", 0xffffff),
2912 : COL("grey100", 0xffffff),
2913 : COL("darkgrey", 0xa9a9a9),
2914 : COL("darkgray", 0xa9a9a9),
2915 : COL("darkblue", 0x00008b),
2916 : COL("darkcyan", 0x008b8b),
2917 : COL("darkmagenta", 0x8b008b),
2918 : COL("darkred", 0x8b0000),
2919 : COL("lightgreen", 0x90ee90),
2920 : COL(NULL,0) /* sentinel */
2921 : };
2922 : #undef COL
2923 :
2924 : void
2925 19630 : long_to_rgb(long c, int *r, int *g, int *b)
2926 : {
2927 19630 : *b = c & 0xff; c >>= 8;
2928 19630 : *g = c & 0xff; c >>= 8;
2929 19630 : *r = c;
2930 19630 : }
2931 : static int
2932 0 : hex2(const char *s)
2933 : {
2934 0 : int m = 0, c = 0, i;
2935 0 : for (i = 0; i < 2; i++, s++)
2936 : {
2937 0 : if (*s >= '0' && *s <= '9')
2938 0 : c = *s - '0';
2939 0 : else if (*s >= 'A' && *s <= 'F')
2940 0 : c = *s - 'A' + 10;
2941 0 : else if (*s >= 'a' && *s <= 'f')
2942 0 : c = *s - 'a' + 10;
2943 0 : else pari_err(e_MISC,"incorrect hexadecimal number: %s", s);
2944 0 : m = 16*m + c;
2945 : }
2946 0 : return m;
2947 : }
2948 : void
2949 11174 : colorname_to_rgb(const char *s, int *r, int *g, int *b)
2950 : {
2951 11174 : if (!rgb_colors) rgb_colors = hashstr_import_static(col_list, 1000);
2952 11174 : if (*s == '#' && strlen(s) == 7)
2953 : {
2954 0 : *r = hex2(s+1);
2955 0 : *g = hex2(s+3);
2956 0 : *b = hex2(s+5);
2957 : }
2958 : else
2959 : {
2960 11174 : hashentry *ep = hash_search(rgb_colors, (void*)s);
2961 11174 : if (!ep) pari_err(e_MISC, "unknown color %s", s);
2962 11174 : long_to_rgb((long)ep->val, r,g,b);
2963 : }
2964 11174 : }
2965 :
2966 : static void
2967 0 : chk_8bit(int v, GEN c)
2968 0 : { if (v & ~0xff) pari_err(e_MISC, "invalid RGB code: %Ps", c); }
2969 : void
2970 11174 : color_to_rgb(GEN c, int *r, int *g, int *b)
2971 : {
2972 11174 : switch(typ(c))
2973 : {
2974 11174 : case t_STR:
2975 11174 : colorname_to_rgb(GSTR(c), r,g,b);
2976 11174 : break;
2977 0 : default: /* t_VECSMALL: */
2978 0 : *r = c[1]; chk_8bit(*r, c);
2979 0 : *g = c[2]; chk_8bit(*g, c);
2980 0 : *b = c[3]; chk_8bit(*b, c);
2981 0 : break;
2982 : }
2983 11174 : }
|