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

Generated by: LCOV version 2.0-1