Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - graph - plotport.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.10.0 lcov report (development 20459-9710128) Lines: 784 1247 62.9 %
Date: 2017-04-29 05:33:44 Functions: 74 101 73.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11