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

Generated by: LCOV version 1.16