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