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