[BACK]Return to plotport.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari-2.2 / src / graph

Annotation of OpenXM_contrib/pari-2.2/src/graph/plotport.c, Revision 1.1

1.1     ! noro        1: /* $Id: plotport.c,v 1.15 2001/03/26 13:52:07 karim Exp $
        !             2:
        !             3: Copyright (C) 2000  The PARI group.
        !             4:
        !             5: This file is part of the PARI/GP package.
        !             6:
        !             7: PARI/GP is free software; you can redistribute it and/or modify it under the
        !             8: terms of the GNU General Public License as published by the Free Software
        !             9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
        !            10: ANY WARRANTY WHATSOEVER.
        !            11:
        !            12: Check the License for details. You should have received a copy of it, along
        !            13: with the package; see the file 'COPYING'. If not, write to the Free Software
        !            14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
        !            15:
        !            16: /*******************************************************************/
        !            17: /*                                                                 */
        !            18: /*                         PLOT ROUTINES                           */
        !            19: /*                                                                 */
        !            20: /*******************************************************************/
        !            21: #include "pari.h"
        !            22: #include "rect.h"
        !            23:
        !            24: extern void push_val(entree *ep, GEN a);
        !            25: extern void pop_val(entree *ep);
        !            26: extern void postdraw0(long *w, long *x, long *y, long lw);
        !            27: extern void postdraw00(long *w, long *x, long *y, long lw, long scale);
        !            28: extern void rectdraw0(long *w, long *x, long *y, long lw, long do_free);
        !            29: static void PARI_get_psplot();
        !            30:
        !            31: static long current_color[NUMRECT];
        !            32: PariRect **rectgraph = NULL;
        !            33: PARI_plot pari_plot, pari_psplot;
        !            34: long  rectpoint_itype = 0;
        !            35: long  rectline_itype  = 0;
        !            36:
        !            37: #define STRINGRECT (NUMRECT-2)
        !            38: #define DRAWRECT (NUMRECT-1)
        !            39:
        !            40: #define PLOTH_NUMPOINTS 1000
        !            41: #define PARAM_NUMPOINTS 1500
        !            42: #define RECUR_NUMPOINTS 8
        !            43:
        !            44: #define RECUR_MAXDEPTH 10
        !            45: #define RECUR_PREC 0.001
        !            46: #define PARAMR_MAXDEPTH 10
        !            47:
        !            48: /********************************************************************/
        !            49: /**                                                                **/
        !            50: /**                         LOW-RES PLOT                           **/
        !            51: /**                                                                **/
        !            52: /********************************************************************/
        !            53: #define ISCR 64
        !            54: #define JSCR 22
        !            55: #define BLANK ' '
        !            56: #define ZERO1 ','
        !            57: #define ZERO2 '-'
        !            58: #define ZERO3 '`'
        !            59: #define PICTZERO(j) ((j) % 3 ? ((j) % 3 == 2 ? ZERO3 : ZERO2) : ZERO1)
        !            60: #define YY '|'
        !            61: #define XX_UPPER '\''
        !            62: #define XX_LOWER '.'
        !            63: #define FF1 '_'
        !            64: #define FF2 'x'
        !            65: #define FF3 '"'
        !            66: #define PICT(j) ((j) % 3 ? ((j) % 3 == 2 ? FF3 : FF2) : FF1)
        !            67:
        !            68: static char *
        !            69: dsprintf9(double d, char *buf)
        !            70: {
        !            71:   int i = 10;
        !            72:
        !            73:   while (--i >= 0) {
        !            74:     sprintf(buf, "%9.*g", i, d);
        !            75:     if (strlen(buf) <= 9) return buf;
        !            76:   }
        !            77:   return buf; /* Should not happen? */
        !            78: }
        !            79:
        !            80: typedef unsigned char screen[ISCR+1][JSCR+1];
        !            81:
        !            82: static void
        !            83: fill_gap(screen scr, long i, int jnew, int jpre)
        !            84: {
        !            85:   int mid, i_up, i_lo, up, lo;
        !            86:
        !            87:   if (jpre < jnew - 2) {
        !            88:     up = jnew - 1; i_up = i;
        !            89:     lo = jpre + 1; i_lo = i - 1;
        !            90:   } else if (jnew < jpre - 2) {
        !            91:     up = jpre - 1; i_up = i - 1;
        !            92:     lo = jnew + 1; i_lo = i;
        !            93:   } else return; /* if gap < 2, leave it as it is. */
        !            94:
        !            95:   mid = (jpre+jnew)/2;
        !            96:   if (mid>JSCR) mid=JSCR; else if (mid<0) mid=0;
        !            97:   if (lo<0) lo=0;
        !            98:   if (lo<=JSCR) while (lo <= mid) scr[i_lo][lo++] = ':';
        !            99:   if (up>JSCR) up=JSCR;
        !           100:   if (up>=0) while (up > mid) scr[i_up][up--] = ':';
        !           101: }
        !           102:
        !           103: #define QUARK  ((char*)NULL) /* Used as a special-case */
        !           104: static GEN quark_gen;
        !           105:
        !           106: #define READ_EXPR(s)   ((s)==QUARK? quark_gen : lisexpr(s))
        !           107:
        !           108: void
        !           109: plot(entree *ep, GEN a, GEN b, char *ch,GEN ysmlu,GEN ybigu, long prec)
        !           110: {
        !           111:   long av = avma, av2,limite,jz,j,i,sig;
        !           112:   int jnew, jpre = 0; /* for lint */
        !           113:   GEN p1,p2,ysml,ybig,x,diff,dyj,dx,y[ISCR+1];
        !           114:   screen scr;
        !           115:   char buf[80], z;
        !           116:
        !           117:   sig=gcmp(b,a); if (!sig) return;
        !           118:   if (sig<0) { x=a; a=b; b=x; }
        !           119:   x = cgetr(prec); gaffect(a,x); push_val(ep, x);
        !           120:   for (i=1; i<=ISCR; i++) y[i]=cgetr(3);
        !           121:   p1 = gdivgs(gsub(b,a), ISCR-1);
        !           122:   dx = cgetr(prec); gaffect(p1, dx);
        !           123:   ysml=gzero; ybig=gzero;
        !           124:   for (j=1; j<=JSCR; j++) scr[1][j]=scr[ISCR][j]=YY;
        !           125:   for (i=2; i<ISCR; i++)
        !           126:   {
        !           127:     scr[i][1] = XX_LOWER;
        !           128:     scr[i][JSCR]=XX_UPPER;
        !           129:     for (j=2; j<JSCR; j++) scr[i][j]=BLANK;
        !           130:   }
        !           131:   av2=avma; limite=stack_lim(av2,1);
        !           132:   for (i=1; i<=ISCR; i++)
        !           133:   {
        !           134:     gaffect(READ_EXPR(ch),y[i]);
        !           135:     if (gcmp(y[i],ysml)<0) ysml=y[i];
        !           136:     if (gcmp(y[i],ybig)>0) ybig=y[i];
        !           137:     x = addrr(x,dx);
        !           138:     if (low_stack(limite, stack_lim(av2,1)))
        !           139:     {
        !           140:       long tetpil=avma;
        !           141:       if (DEBUGMEM>1) err(warnmem,"plot");
        !           142:       x = gerepile(av2,tetpil,rcopy(x));
        !           143:     }
        !           144:     ep->value = (void*)x;
        !           145:   }
        !           146:   if (ysmlu) ysml=ysmlu;
        !           147:   if (ybigu) ybig=ybigu;
        !           148:   avma=av2; diff=gsub(ybig,ysml);
        !           149:   if (gcmp0(diff)) { ybig=gaddsg(1,ybig); diff=gun; }
        !           150:   dyj = gdivsg((JSCR-1)*3+2,diff);
        !           151:   jz = 3-gtolong(gmul(ysml,dyj));
        !           152:   av2=avma; z = PICTZERO(jz); jz = jz/3;
        !           153:   for (i=1; i<=ISCR; i++)
        !           154:   {
        !           155:     if (0<=jz && jz<=JSCR) scr[i][jz]=z;
        !           156:     j = 3+gtolong(gmul(gsub(y[i],ysml),dyj));
        !           157:     jnew = j/3;
        !           158:     if (i > 1) fill_gap(scr, i, jnew, jpre);
        !           159:     if (0<=jnew && jnew<=JSCR) scr[i][jnew] = PICT(j);
        !           160:     avma = av2;
        !           161:     jpre = jnew;
        !           162:   }
        !           163:   p1=cgetr(3); gaffect(ybig,p1); pariputc('\n');
        !           164:   pariputsf("%s ", dsprintf9(rtodbl(p1), buf));
        !           165:   for (i=1; i<=ISCR; i++) pariputc(scr[i][JSCR]);
        !           166:   pariputc('\n');
        !           167:   for (j=(JSCR-1); j>=2; j--)
        !           168:   {
        !           169:     pariputs("          ");
        !           170:     for (i=1; i<=ISCR; i++) pariputc(scr[i][j]);
        !           171:     pariputc('\n');
        !           172:   }
        !           173:   p1=cgetr(3); gaffect(ysml,p1);
        !           174:   pariputsf("%s ", dsprintf9(rtodbl(p1), buf));
        !           175:   for (i=1; i<=ISCR; i++)  pariputc(scr[i][1]);
        !           176:   pariputc('\n');
        !           177:   p1=cgetr(3); gaffect(a,p1);
        !           178:   p2=cgetr(3); gaffect(b,p2);
        !           179:   pariputsf("%10s%-9.7g%*.7g\n"," ",rtodbl(p1),ISCR-9,rtodbl(p2));
        !           180:   pop_val(ep); avma=av;
        !           181: }
        !           182:
        !           183: /********************************************************************/
        !           184: /**                                                                **/
        !           185: /**                      RECTPLOT FUNCTIONS                        **/
        !           186: /**                                                                **/
        !           187: /********************************************************************/
        !           188: void
        !           189: init_graph()
        !           190: {
        !           191:   int n;
        !           192:
        !           193:   rectgraph = (PariRect**) gpmalloc(sizeof(PariRect*)*NUMRECT);
        !           194:   for (n=0; n<NUMRECT; n++)
        !           195:   {
        !           196:     PariRect *e = (PariRect*) gpmalloc(sizeof(PariRect));
        !           197:
        !           198:     e->head = e->tail = NULL;
        !           199:     e->sizex = e->sizey = 0;
        !           200:     current_color[n] = DEFAULT_COLOR;
        !           201:     rectgraph[n] = e;
        !           202:   }
        !           203: }
        !           204:
        !           205: void
        !           206: free_graph()
        !           207: {
        !           208:   int i;
        !           209:
        !           210:   for (i=0; i<NUMRECT; i++)
        !           211:   {
        !           212:     PariRect *e=rectgraph[i];
        !           213:
        !           214:     if (RHead(e)) killrect(i);
        !           215:     free((void *)e);
        !           216:   }
        !           217:   free((void *)rectgraph);
        !           218: }
        !           219:
        !           220: static PariRect *
        !           221: check_rect(long ne)
        !           222: {
        !           223:   if (!GOODRECT(ne))
        !           224:     err(talker,"not an rplot vector type in graphic function");
        !           225:   return rectgraph[ne];
        !           226: }
        !           227:
        !           228: static PariRect *
        !           229: check_rect_init(long ne)
        !           230: {
        !           231:   PariRect *e = check_rect(ne);
        !           232:   if (!RHead(e))
        !           233:     err(talker,"you must initialize the rectwindow first");
        !           234:   return e;
        !           235: }
        !           236:
        !           237: void
        !           238: initrect_gen(long ne, GEN x, GEN y, long flag)
        !           239: {
        !           240:   long xi, yi;
        !           241:   if (flag) {
        !           242:     double xd = gtodouble(x), yd = gtodouble(y);
        !           243:
        !           244:     PARI_get_plot(0);
        !           245:     xi = w_width - 1;  yi = w_height - 1;
        !           246:     if (xd)
        !           247:       xi = (long)(xd*xi + 0.5);
        !           248:     if (yd)
        !           249:       yi = (long)(yd*yi + 0.5);
        !           250:   } else {
        !           251:     xi = itos(x);  yi = itos(y);
        !           252:     if (!xi || !yi)
        !           253:       PARI_get_plot(0);
        !           254:     if (!xi)
        !           255:       xi = w_width - 1;
        !           256:     if (!yi)
        !           257:       yi = w_height - 1;
        !           258:   }
        !           259:   initrect(ne, xi, yi);
        !           260: }
        !           261:
        !           262: void
        !           263: initrect(long ne, long x, long y)
        !           264: {
        !           265:   PariRect *e;
        !           266:   RectObj *z;
        !           267:
        !           268:   if (x<=1 || y<=1) err(talker,"incorrect dimensions in initrect");
        !           269:   e = check_rect(ne); if (RHead(e)) killrect(ne);
        !           270:
        !           271:   z = (RectObj*) gpmalloc(sizeof(RectObj));
        !           272:   RoNext(z) = NULL;
        !           273:   RoType(z) = ROt_NULL;
        !           274:   RHead(e)=RTail(e)=z;
        !           275:   RXsize(e)=x; RYsize(e)=y;
        !           276:   RXcursor(e)=0; RYcursor(e)=0;
        !           277:   RXscale(e)=1; RXshift(e)=0;
        !           278:   RYscale(e)=1; RYshift(e)=0;
        !           279:   RHasGraph(e) = 0;
        !           280: }
        !           281:
        !           282: GEN
        !           283: rectcursor(long ne)
        !           284: {
        !           285:   PariRect *e = check_rect_init(ne);
        !           286:   GEN z=cgetg(3,t_VEC);
        !           287:
        !           288:   z[1] = lstoi((long)RXcursor(e)); z[2] = lstoi((long)RYcursor(e));
        !           289:   return z;
        !           290: }
        !           291:
        !           292: static void
        !           293: rectscale0(long ne, double x1, double x2, double y1, double y2)
        !           294: {
        !           295:   PariRect *e = check_rect_init(ne);
        !           296:   double p2,p3;
        !           297:
        !           298:   p2 = RXshift(e) + RXscale(e) * RXcursor(e);
        !           299:   p3 = RYshift(e) + RYscale(e) * RYcursor(e);
        !           300:   RXscale(e) = RXsize(e)/(x2-x1); RXshift(e) = -x1*RXscale(e);
        !           301:   RYscale(e) = RYsize(e)/(y1-y2); RYshift(e) = -y2*RYscale(e);
        !           302:   RXcursor(e) = (p2 - RXshift(e)) / RXscale(e);
        !           303:   RYcursor(e) = (p3 - RYshift(e)) / RYscale(e);
        !           304: }
        !           305:
        !           306: void
        !           307: rectscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2)
        !           308: {
        !           309:   rectscale0(ne, gtodouble(x1), gtodouble(x2), gtodouble(y1), gtodouble(y2));
        !           310: }
        !           311:
        !           312: /*
        !           313:  * #ifdef LONG_IS_64BIT
        !           314:  * #  define MAXDTOL 9223372036854775807.0
        !           315:  * #else
        !           316:  * #  define MAXDTOL 2147483647.0
        !           317:  * #endif
        !           318:  *
        !           319:  *
        !           320:  * long
        !           321:  * DTOL(double t)
        !           322:  * {
        !           323:  *   if (fabs(t) > MAXDTOL) err(affer2);
        !           324:  *   return (long)t;
        !           325:  * }
        !           326:  */
        !           327:
        !           328: static void
        !           329: rectmove0(long ne, double x, double y, long relative)
        !           330: {
        !           331:   PariRect *e = check_rect_init(ne);
        !           332:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj1P));
        !           333:
        !           334:   if (relative)
        !           335:    { RXcursor(e) += x; RYcursor(e) += y; }
        !           336:   else
        !           337:    { RXcursor(e) = x; RYcursor(e) = y; }
        !           338:   RoNext(z) = 0; RoType(z) = ROt_MV;
        !           339:   RoMVx(z) = RXcursor(e) * RXscale(e) + RXshift(e);
        !           340:   RoMVy(z) = RYcursor(e) * RYscale(e) + RYshift(e);
        !           341:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           342:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           343: }
        !           344:
        !           345: void
        !           346: rectmove(long ne, GEN x, GEN y)
        !           347: {
        !           348:   rectmove0(ne,gtodouble(x),gtodouble(y),0);
        !           349: }
        !           350:
        !           351: void
        !           352: rectrmove(long ne, GEN x, GEN y)
        !           353: {
        !           354:   rectmove0(ne,gtodouble(x),gtodouble(y),1);
        !           355: }
        !           356:
        !           357: void
        !           358: rectpoint0(long ne, double x, double y,long relative) /* code = ROt_MV/ROt_PT */
        !           359: {
        !           360:   PariRect *e = check_rect_init(ne);
        !           361:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj1P));
        !           362:
        !           363:   if (relative)
        !           364:    { RXcursor(e) += x; RYcursor(e) += y; }
        !           365:   else
        !           366:    { RXcursor(e) = x; RYcursor(e) = y; }
        !           367:   RoNext(z)=0;
        !           368:   RoPTx(z) = RXcursor(e)*RXscale(e) + RXshift(e);
        !           369:   RoPTy(z) = RYcursor(e)*RYscale(e) + RYshift(e);
        !           370:   RoType(z) = ( DTOL(RoPTx(z)) < 0
        !           371:                || DTOL(RoPTy(z)) < 0 || DTOL(RoPTx(z)) > RXsize(e)
        !           372:                || DTOL(RoPTy(z)) > RYsize(e) ) ? ROt_MV : ROt_PT;
        !           373:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           374:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           375:   RoCol(z)=current_color[ne];
        !           376: }
        !           377:
        !           378: void
        !           379: rectpoint(long ne, GEN x, GEN y)
        !           380: {
        !           381:   rectpoint0(ne,gtodouble(x),gtodouble(y),0);
        !           382: }
        !           383:
        !           384: void
        !           385: rectrpoint(long ne, GEN x, GEN y)
        !           386: {
        !           387:   rectpoint0(ne,gtodouble(x),gtodouble(y),1);
        !           388: }
        !           389:
        !           390: void
        !           391: rectcolor(long ne, long color)
        !           392: {
        !           393:   check_rect(ne);
        !           394:   if (!GOODCOLOR(color)) err(talker,"This is not a valid color");
        !           395:   current_color[ne]=color;
        !           396: }
        !           397:
        !           398: void
        !           399: rectline0(long ne, double gx2, double gy2, long relative) /* code = ROt_MV/ROt_LN */
        !           400: {
        !           401:   double dx,dy,dxy,xmin,xmax,ymin,ymax,x1,y1,x2,y2;
        !           402:   PariRect *e = check_rect_init(ne);
        !           403:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
        !           404:   const double c = 1 + 1e-10;
        !           405:
        !           406:   x1 = RXcursor(e)*RXscale(e) + RXshift(e);
        !           407:   y1 = RYcursor(e)*RYscale(e) + RYshift(e);
        !           408:   if (relative)
        !           409:     { RXcursor(e)+=gx2; RYcursor(e)+=gy2; }
        !           410:   else
        !           411:     { RXcursor(e)=gx2; RYcursor(e)=gy2; }
        !           412:   x2 = RXcursor(e)*RXscale(e) + RXshift(e);
        !           413:   y2 = RYcursor(e)*RYscale(e) + RYshift(e);
        !           414:   xmin = max(min(x1,x2),0); xmax = min(max(x1,x2),RXsize(e));
        !           415:   ymin = max(min(y1,y2),0); ymax = min(max(y1,y2),RYsize(e));
        !           416:   dxy = x1*y2 - y1*x2; dx = x2-x1; dy = y2-y1;
        !           417:   if (dy)
        !           418:   {
        !           419:     if (dx*dy<0)
        !           420:       { xmin = max(xmin,(dxy+RYsize(e)*dx)/dy); xmax=min(xmax,dxy/dy); }
        !           421:     else
        !           422:       { xmin=max(xmin,dxy/dy); xmax=min(xmax,(dxy+RYsize(e)*dx)/dy); }
        !           423:   }
        !           424:   if (dx)
        !           425:   {
        !           426:     if (dx*dy<0)
        !           427:       { ymin=max(ymin,(RXsize(e)*dy-dxy)/dx); ymax=min(ymax,-dxy/dx); }
        !           428:     else
        !           429:       { ymin=max(ymin,-dxy/dx); ymax=min(ymax,(RXsize(e)*dy-dxy)/dx); }
        !           430:   }
        !           431:   RoNext(z)=0;
        !           432:   RoLNx1(z) = xmin; RoLNx2(z) = xmax;
        !           433:   if (dx*dy<0) { RoLNy1(z) = ymax; RoLNy2(z) = ymin; }
        !           434:   else { RoLNy1(z) = ymin; RoLNy2(z) = ymax; }
        !           435:   RoType(z) = (xmin>xmax*c || ymin>ymax*c) ? ROt_MV : ROt_LN;
        !           436:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           437:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           438:   RoCol(z)=current_color[ne];
        !           439: }
        !           440:
        !           441: /* Given coordinates of ends of a line, and labels l1 l2 attached to the
        !           442:    ends, plot ticks where the label coordinate takes "round" values */
        !           443:
        !           444: static void
        !           445: rectticks(PARI_plot *WW, long ne,
        !           446:           double dx1, double dy1, double dx2, double dy2,
        !           447:           double l1, double l2, long flags)
        !           448: {
        !           449:   long dx,dy,dxy,dxy1,x1,y1,x2,y2,nticks,n,n1,dn;
        !           450:   double minstep, maxstep, step, l_min, l_max, minl, maxl, dl, dtx, dty, x, y;
        !           451:   double ddx, ddy;
        !           452:   const double mult[3] = { 2./1., 5./2., 10./5. };
        !           453:   PariRect *e = check_rect_init(ne);
        !           454:   int do_double = !(flags & TICKS_NODOUBLE);
        !           455:
        !           456:   x1 = DTOL(dx1*RXscale(e) + RXshift(e));
        !           457:   y1 = DTOL(dy1*RYscale(e) + RYshift(e));
        !           458:   x2 = DTOL(dx2*RXscale(e) + RXshift(e));
        !           459:   y2 = DTOL(dy2*RYscale(e) + RYshift(e));
        !           460:   dx = x2 - x1;
        !           461:   dy = y2 - y1;
        !           462:   if (dx < 0) dx = -dx;
        !           463:   if (dy < 0) dy = -dy;
        !           464:   dxy1 = max(dx, dy);
        !           465:   if (WW) {
        !           466:     dx /= WW->hunit;
        !           467:     dy /= WW->vunit;
        !           468:   }
        !           469:   else {
        !           470:     PARI_get_plot(0);
        !           471:     dx /= h_unit;
        !           472:     dy /= v_unit;
        !           473:   }
        !           474:   dxy = (long)sqrt(dx*dx + dy*dy);
        !           475:   nticks = (long) ((dxy + 2.5)/4);
        !           476:   if (!nticks) return;
        !           477:
        !           478:   /* Now we want to find nticks (or less) "round" numbers between l1 and l2.
        !           479:      For our purpose round numbers have "last significant" digit either
        !           480:        *) any;
        !           481:        *) even;
        !           482:        *) divisible by 5.
        !           483:      We need to choose which alternative is better.
        !           484:    */
        !           485:   if (l1 < l2)
        !           486:     l_min = l1, l_max = l2;
        !           487:   else
        !           488:     l_min = l2, l_max = l1;
        !           489:   minstep = (l_max - l_min)/(nticks + 1);
        !           490:   maxstep = 2.5*(l_max - l_min);
        !           491:   step = exp(log(10) * floor(log10(minstep)));
        !           492:   if (!(flags & TICKS_ENDSTOO)) {
        !           493:     double d = 2*(l_max - l_min)/dxy1; /* Two pixels off */
        !           494:
        !           495:     l_min += d;
        !           496:     l_max -= d;
        !           497:   }
        !           498:   for (n = 0; ; n++) {
        !           499:     if (step >= maxstep) return;
        !           500:
        !           501:     if (step >= minstep) {
        !           502:       minl = ceil(l_min/step);
        !           503:       maxl = floor(l_max/step);
        !           504:       if (minl <= maxl && maxl - minl + 1 <= nticks) {
        !           505:        nticks = (long) (maxl - minl + 1);
        !           506:         l_min = minl * step;
        !           507:         l_max = maxl * step; break;
        !           508:       }
        !           509:     }
        !           510:     step *= mult[ n % 3 ];
        !           511:   }
        !           512:   /* Where to position doubleticks, variants:
        !           513:      small: each 5, double: each 10    (n===2 mod 3)
        !           514:      small: each 2, double: each 10    (n===1  mod 3)
        !           515:      small: each 1, double: each  5 */
        !           516:   dn = (n % 3 == 2)? 2: 5;
        !           517:   n1 = ((long)minl) % dn; /* unused if do_double = FALSE */
        !           518:
        !           519:   /* now l_min and l_max keep min/max values of l with ticks, and nticks is
        !           520:      the number of ticks to draw. */
        !           521:   if (nticks == 1) ddx = ddy = 0; /* unused: for lint */
        !           522:   else {
        !           523:     dl = (l_max - l_min)/(nticks - 1);
        !           524:     ddx = (dx2 - dx1) * dl / (l2 - l1);
        !           525:     ddy = (dy2 - dy1) * dl / (l2 - l1);
        !           526:   }
        !           527:   x = dx1 + (dx2 - dx1) * (l_min - l1) / (l2 - l1);
        !           528:   y = dy1 + (dy2 - dy1) * (l_min - l1) / (l2 - l1);
        !           529:   /* assume h_unit and v_unit form a square.  For clockwise ticks: */
        !           530:   dtx = h_unit * dy/dxy * (y2 > y1 ? 1 : -1);  /* y-coord runs down */
        !           531:   dty = v_unit * dx/dxy * (x2 > x1 ? 1 : -1);
        !           532:   for (n = 0; n < nticks; n++) {
        !           533:     RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
        !           534:     double lunit = h_unit > 1 ? 1.5 : 2;
        !           535:     double l = (do_double && (n + n1) % dn == 0) ? lunit: 1;
        !           536:
        !           537:     RoNext(z) = 0;
        !           538:     RoLNx1(z) = RoLNx2(z) = x*RXscale(e) + RXshift(e);
        !           539:     RoLNy1(z) = RoLNy2(z) = y*RYscale(e) + RYshift(e);
        !           540:
        !           541:     if (flags & TICKS_CLOCKW) {
        !           542:       RoLNx1(z) += dtx*l;
        !           543:       RoLNy1(z) -= dty*l;              /* y-coord runs down */
        !           544:     }
        !           545:     if (flags & TICKS_ACLOCKW) {
        !           546:       RoLNx2(z) -= dtx*l;
        !           547:       RoLNy2(z) += dty*l;              /* y-coord runs down */
        !           548:     }
        !           549:     RoType(z) = ROt_LN;
        !           550:
        !           551:     if (!RHead(e))
        !           552:       RHead(e)=RTail(e)=z;
        !           553:     else {
        !           554:       RoNext(RTail(e))=z; RTail(e)=z;
        !           555:     }
        !           556:     RoCol(z)=current_color[ne];
        !           557:     x += ddx;
        !           558:     y += ddy;
        !           559:   }
        !           560: }
        !           561:
        !           562: void
        !           563: rectline(long ne, GEN gx2, GEN gy2)
        !           564: {
        !           565:   rectline0(ne, gtodouble(gx2), gtodouble(gy2),0);
        !           566: }
        !           567:
        !           568: void
        !           569: rectrline(long ne, GEN gx2, GEN gy2)
        !           570: {
        !           571:   rectline0(ne, gtodouble(gx2), gtodouble(gy2),1);
        !           572: }
        !           573:
        !           574: void
        !           575: rectbox0(long ne, double gx2, double gy2, long relative)
        !           576: {
        !           577:   double x1,y1,x2,y2,xmin,ymin,xmax,ymax;
        !           578:   double xx,yy;
        !           579:   PariRect *e = check_rect_init(ne);
        !           580:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
        !           581:
        !           582:   x1 = RXcursor(e)*RXscale(e) + RXshift(e);
        !           583:   y1 = RYcursor(e)*RYscale(e) + RYshift(e);
        !           584:   if (relative)
        !           585:   { xx = RXcursor(e)+gx2; yy = RYcursor(e)+gy2; }
        !           586:   else
        !           587:   {  xx = gx2; yy = gy2; }
        !           588:   x2 = xx*RXscale(e) + RXshift(e);
        !           589:   y2 = yy*RYscale(e) + RYshift(e);
        !           590:   xmin = max(min(x1,x2),0); xmax = min(max(x1,x2),RXsize(e));
        !           591:   ymin = max(min(y1,y2),0); ymax = min(max(y1,y2),RYsize(e));
        !           592:
        !           593:   RoNext(z)=0; RoType(z) = ROt_BX;
        !           594:   RoBXx1(z) = xmin; RoBXy1(z) = ymin;
        !           595:   RoBXx2(z) = xmax; RoBXy2(z) = ymax;
        !           596:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           597:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           598:   RoCol(z)=current_color[ne];
        !           599: }
        !           600:
        !           601: void
        !           602: rectbox(long ne, GEN gx2, GEN gy2)
        !           603: {
        !           604:   rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 0);
        !           605: }
        !           606:
        !           607: void
        !           608: rectrbox(long ne, GEN gx2, GEN gy2)
        !           609: {
        !           610:   rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 1);
        !           611: }
        !           612:
        !           613: void
        !           614: killrect(long ne)
        !           615: {
        !           616:   RectObj *p1,*p2;
        !           617:   PariRect *e = check_rect_init(ne);
        !           618:
        !           619:   current_color[ne]=DEFAULT_COLOR;
        !           620:   p1=RHead(e);
        !           621:   RHead(e) = RTail(e) = NULL;
        !           622:   RXsize(e) = RYsize(e) = 0;
        !           623:   RXcursor(e) = RYcursor(e) = 0;
        !           624:   RXscale(e) = RYscale(e) = 1;
        !           625:   RXshift(e) = RYshift(e) = 0;
        !           626:   while (p1)
        !           627:   {
        !           628:     if (RoType(p1)==ROt_MP || RoType(p1)==ROt_ML)
        !           629:     {
        !           630:       free(RoMPxs(p1)); free(RoMPys(p1));
        !           631:     }
        !           632:     if (RoType(p1)==ROt_ST) free(RoSTs(p1));
        !           633:     p2=RoNext(p1); free(p1); p1=p2;
        !           634:   }
        !           635: }
        !           636:
        !           637: void
        !           638: rectpoints0(long ne, double *listx, double *listy, long lx) /* code = ROt_MP */
        !           639: {
        !           640:   double *ptx, *pty, x, y;
        !           641:   long i, cp=0;
        !           642:   PariRect *e = check_rect_init(ne);
        !           643:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjMP));
        !           644:
        !           645:   ptx=(double*) gpmalloc(lx*sizeof(double));
        !           646:   pty=(double*) gpmalloc(lx*sizeof(double));
        !           647:   for (i=0; i<lx; i++)
        !           648:   {
        !           649:     x = RXscale(e)*listx[i] + RXshift(e);
        !           650:     y = RYscale(e)*listy[i] + RYshift(e);
        !           651:     if ((x>=0)&&(y>=0)&&(x<=RXsize(e))&&(y<=RYsize(e)))
        !           652:     {
        !           653:       ptx[cp]=x; pty[cp]=y; cp++;
        !           654:     }
        !           655:   }
        !           656:   RoNext(z)=0; RoType(z) = ROt_MP;
        !           657:   RoMPcnt(z) = cp; RoMPxs(z) = ptx; RoMPys(z) = pty;
        !           658:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           659:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           660:   RoCol(z)=current_color[ne];
        !           661: }
        !           662:
        !           663: void
        !           664: rectpoints(long ne, GEN listx, GEN listy)
        !           665: {
        !           666:   long i,lx, tx=typ(listx), ty=typ(listy);
        !           667:   double *px,*py;
        !           668:
        !           669:   if (!is_matvec_t(tx) || !is_matvec_t(ty))
        !           670:   {
        !           671:     rectpoint(ne, listx, listy); return;
        !           672:   }
        !           673:   if (tx == t_MAT || ty == t_MAT) err(ploter4);
        !           674:   lx=lg(listx); if (lg(listy)!=lx) err(ploter5);
        !           675:   lx--; if (!lx) return;
        !           676:
        !           677:   px = (double*) gpmalloc(lx*sizeof(double));
        !           678:   py = (double*) gpmalloc(lx*sizeof(double));
        !           679:   for (i=0; i<lx; i++)
        !           680:   {
        !           681:     px[i]=gtodouble((GEN)listx[i+1]); py[i]=gtodouble((GEN)listy[i+1]);
        !           682:   }
        !           683:   rectpoints0(ne,px,py,lx);
        !           684:   free(px); free(py);
        !           685: }
        !           686:
        !           687: void
        !           688: rectlines0(long ne, double *x, double *y, long lx, long flag) /* code = ROt_ML */
        !           689: {
        !           690:   long i,I;
        !           691:   double *ptx,*pty;
        !           692:   PariRect *e = check_rect_init(ne);
        !           693:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
        !           694:
        !           695:   I = flag ? lx+1 : lx;
        !           696:   ptx = (double*) gpmalloc(I*sizeof(double));
        !           697:   pty = (double*) gpmalloc(I*sizeof(double));
        !           698:   for (i=0; i<lx; i++)
        !           699:   {
        !           700:     ptx[i] = RXscale(e)*x[i] + RXshift(e);
        !           701:     pty[i] = RYscale(e)*y[i] + RYshift(e);
        !           702:   }
        !           703:   if (flag)
        !           704:   {
        !           705:     ptx[i] = RXscale(e)*x[0] + RXshift(e);
        !           706:     pty[i] = RYscale(e)*y[0] + RYshift(e);
        !           707:   }
        !           708:   RoNext(z)=0; RoType(z)=ROt_ML;
        !           709:   RoMLcnt(z)=lx; RoMLxs(z)=ptx; RoMLys(z)=pty;
        !           710:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           711:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           712:   RoCol(z) = current_color[ne];
        !           713: }
        !           714:
        !           715: void
        !           716: rectlines(long ne, GEN listx, GEN listy, long flag)
        !           717: {
        !           718:   long tx=typ(listx), ty=typ(listy), lx=lg(listx), i;
        !           719:   double *x, *y;
        !           720:
        !           721:   if (!is_matvec_t(tx) || !is_matvec_t(ty))
        !           722:   {
        !           723:     rectline(ne, listx, listy); return;
        !           724:   }
        !           725:   if (tx == t_MAT || ty == t_MAT) err(ploter4);
        !           726:   if (lg(listy)!=lx) err(ploter5);
        !           727:   lx--; if (!lx) return;
        !           728:
        !           729:   x = (double*) gpmalloc(lx*sizeof(double));
        !           730:   y = (double*) gpmalloc(lx*sizeof(double));
        !           731:   for (i=0; i<lx; i++)
        !           732:   {
        !           733:     x[i] = gtodouble((GEN)listx[i+1]); y[i] = gtodouble((GEN)listy[i+1]);
        !           734:   }
        !           735:   rectlines0(ne,x,y,lx,flag);
        !           736:   free(x); free(y);
        !           737: }
        !           738:
        !           739: static void
        !           740: put_string(long win, long x, long y, char *str, long dir)
        !           741: {
        !           742:   rectmove0(win,(double)x,(double)y,0); rectstring3(win,str,dir);
        !           743: }
        !           744:
        !           745: void
        !           746: rectstring(long ne, char *str)
        !           747: {
        !           748:     rectstring3(ne,str,RoSTdirLEFT);
        !           749: }
        !           750:
        !           751: /* Allocate memory, then put string */
        !           752: void
        !           753: rectstring3(long ne, char *str, long dir) /* code = ROt_ST */
        !           754: {
        !           755:   PariRect *e = check_rect_init(ne);
        !           756:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjST));
        !           757:   long l = strlen(str);
        !           758:   char *s = (char *) gpmalloc(l+1);
        !           759:
        !           760:   strcpy(s,str);
        !           761:   RoNext(z)=0; RoType(z) = ROt_ST;
        !           762:   RoSTl(z) = l; RoSTs(z) = s;
        !           763:   RoSTx(z) = RXscale(e)*RXcursor(e)+RXshift(e);
        !           764:   RoSTy(z) = RYscale(e)*RYcursor(e)+RYshift(e);
        !           765:   RoSTdir(z) = dir;
        !           766:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           767:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           768:   RoCol(z)=current_color[ne];
        !           769: }
        !           770:
        !           771: void
        !           772: rectpointtype(long ne, long type) /* code = ROt_PTT */
        !           773: {
        !           774:  if (ne == -1) {
        !           775:      rectpoint_itype = type;
        !           776:  } else {
        !           777:   PariRect *e = check_rect_init(ne);
        !           778:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjPN));
        !           779:
        !           780:   RoNext(z) = 0; RoType(z) = ROt_PTT;
        !           781:   RoPTTpen(z) = type;
        !           782:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           783:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           784:  }
        !           785: }
        !           786:
        !           787: void
        !           788: rectpointsize(long ne, GEN size) /* code = ROt_PTS */
        !           789: {
        !           790:  if (ne == -1) {
        !           791:      set_pointsize(gtodouble(size));   /* Immediate set */
        !           792:  } else {
        !           793:      PariRect *e = check_rect_init(ne);
        !           794:      RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjPS));
        !           795:
        !           796:      RoNext(z) = 0; RoType(z) = ROt_PTS;
        !           797:      RoPTSsize(z) = gtodouble(size);
        !           798:      if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           799:      else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           800:  }
        !           801: }
        !           802:
        !           803: void
        !           804: rectlinetype(long ne, long type)
        !           805: {
        !           806:  if (ne == -1) {
        !           807:      rectline_itype = type;
        !           808:  } else {
        !           809:   PariRect *e = check_rect_init(ne);
        !           810:   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjPN));
        !           811:
        !           812:   RoNext(z) = 0; RoType(z) = ROt_LNT;
        !           813:   RoLNTpen(z) = type;
        !           814:   if (!RHead(e)) RHead(e)=RTail(e)=z;
        !           815:   else { RoNext(RTail(e))=z; RTail(e)=z; }
        !           816:  }
        !           817: }
        !           818:
        !           819: void
        !           820: rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag)
        !           821: {
        !           822:   long xi, yi;
        !           823:   if (flag & RECT_CP_RELATIVE) {
        !           824:     double xd = gtodouble(xoff), yd = gtodouble(yoff);
        !           825:
        !           826:     PARI_get_plot(0);
        !           827:     xi = w_width - 1;  yi = w_height - 1;
        !           828:     xi = (long)(xd*xi + 0.5);
        !           829:     yi = (long)(yd*yi + 0.5);
        !           830:   } else {
        !           831:     xi = itos(xoff);  yi = itos(yoff);
        !           832:   }
        !           833:   if (flag & ~RECT_CP_RELATIVE) {
        !           834:     PariRect *s = check_rect_init(source), *d = check_rect_init(dest);
        !           835:
        !           836:     switch (flag & ~RECT_CP_RELATIVE) {
        !           837:       case RECT_CP_NW:
        !           838:        break;
        !           839:       case RECT_CP_SW:
        !           840:        yi = RYsize(d) - RYsize(s) - yi;
        !           841:        break;
        !           842:       case RECT_CP_SE:
        !           843:        yi = RYsize(d) - RYsize(s) - yi;
        !           844:        /* FALL THROUGH */
        !           845:       case RECT_CP_NE:
        !           846:        xi = RXsize(d) - RXsize(s) - xi;
        !           847:        break;
        !           848:     }
        !           849:   }
        !           850:   rectcopy(source, dest, xi, yi);
        !           851: }
        !           852:
        !           853: void
        !           854: rectcopy(long source, long dest, long xoff, long yoff)
        !           855: {
        !           856:   PariRect *s = check_rect_init(source), *d = check_rect_init(dest);
        !           857:   RectObj *p1 = RHead(s);
        !           858:   RectObj *tail = RTail(d);
        !           859:   RectObj *next;
        !           860:   int i;
        !           861:
        !           862:   while (p1)
        !           863:   {
        !           864:     switch(RoType(p1))
        !           865:     {
        !           866:       case ROt_PT:
        !           867:        next = (RectObj*) gpmalloc(sizeof(RectObj1P));
        !           868:        memcpy(next,p1,sizeof(RectObj1P));
        !           869:        RoPTx(next) += xoff; RoPTy(next) += yoff;
        !           870:        RoNext(tail) = next; tail = next;
        !           871:        break;
        !           872:       case ROt_LN: case ROt_BX:
        !           873:        next = (RectObj*) gpmalloc(sizeof(RectObj2P));
        !           874:        memcpy(next,p1,sizeof(RectObj2P));
        !           875:        RoLNx1(next) += xoff; RoLNy1(next) += yoff;
        !           876:        RoLNx2(next) += xoff; RoLNy2(next) += yoff;
        !           877:        RoNext(tail) = next; tail = next;
        !           878:        break;
        !           879:       case ROt_MP: case ROt_ML:
        !           880:        next = (RectObj*) gpmalloc(sizeof(RectObjMP));
        !           881:        memcpy(next,p1,sizeof(RectObjMP));
        !           882:        RoMPxs(next) = (double*) gpmalloc(sizeof(double)*RoMPcnt(next));
        !           883:        RoMPys(next) = (double*) gpmalloc(sizeof(double)*RoMPcnt(next));
        !           884:        memcpy(RoMPxs(next),RoMPxs(p1),sizeof(double)*RoMPcnt(next));
        !           885:        memcpy(RoMPys(next),RoMPys(p1),sizeof(double)*RoMPcnt(next));
        !           886:        for (i=0; i<RoMPcnt(next); i++)
        !           887:        {
        !           888:          RoMPxs(next)[i] += xoff; RoMPys(next)[i] += yoff;
        !           889:         }
        !           890:        RoNext(tail) = next; tail = next;
        !           891:        break;
        !           892:       case ROt_ST:
        !           893:        next = (RectObj*) gpmalloc(sizeof(RectObjST));
        !           894:        memcpy(next,p1,sizeof(RectObjMP));
        !           895:        RoSTs(next) = (char*) gpmalloc(RoSTl(p1)+1);
        !           896:        memcpy(RoSTs(next),RoSTs(p1),RoSTl(p1)+1);
        !           897:        RoSTx(next) += xoff; RoSTy(next) += yoff;
        !           898:        RoNext(tail) = next; tail = next;
        !           899:        break;
        !           900:       case ROt_PTT: case ROt_LNT: case ROt_PTS:
        !           901:        next = (RectObj*) gpmalloc(sizeof(RectObjPN));
        !           902:        memcpy(next,p1,sizeof(RectObjPN));
        !           903:        RoNext(tail) = next; tail = next;
        !           904:        break;
        !           905:     }
        !           906:     p1=RoNext(p1);
        !           907:   }
        !           908:   RoNext(tail) = NULL; RTail(d) = tail;
        !           909: }
        !           910:
        !           911: #define CLIPLINE_NONEMPTY      1
        !           912: #define CLIPLINE_CLIP_1                2
        !           913: #define CLIPLINE_CLIP_2                4
        !           914:
        !           915: /* A simpler way is to clip by 4 half-planes */
        !           916: static int
        !           917: clipline(double xmin, double xmax, double ymin, double ymax,
        !           918:          double *x1p, double *y1p, double *x2p, double *y2p)
        !           919: {
        !           920:     int xy_exch = 0, rc = CLIPLINE_NONEMPTY;
        !           921:     double t, sl;
        !           922:     double xi, xmn, xmx;
        !           923:     double yi, ymn, ymx;
        !           924:     int x1_is_ymn, x1_is_xmn;
        !           925:     double x1 = *x1p, x2 = *x2p, y1 = *y1p, y2 = *y2p;
        !           926:
        !           927:     if ((x1 < xmin &&  x2 < xmin) || (x1 > xmax && x2 > xmax))
        !           928:        return 0;
        !           929:     if (fabs(x1 - x2) < fabs(y1 - y2)) { /* Exchange x and y */
        !           930:        xy_exch = 1;
        !           931:        t = xmin; xmin = ymin; ymin = t;
        !           932:        t = xmax; xmax = ymax; ymax = t;
        !           933:        t = x1; x1 = y1; y1 = t;
        !           934:        t = x2; x2 = y2; y2 = t;
        !           935:     }
        !           936:
        !           937:     /* Build y as a function of x */
        !           938:     xi = x1, yi = y1;
        !           939:     sl = ( (x1==x2) ? 0 : (y2 - yi)/(x2 - xi) );
        !           940:
        !           941:     xmn = x1, xmx = x2;
        !           942:     if (x1 > x2) {
        !           943:        x1_is_xmn = 0;
        !           944:        xmn = x2, xmx = x1;
        !           945:     } else
        !           946:        x1_is_xmn = 1;
        !           947:
        !           948:     if (xmn < xmin) {
        !           949:        xmn = xmin;
        !           950:        rc |= (x1_is_xmn ? CLIPLINE_CLIP_1 : CLIPLINE_CLIP_2);
        !           951:     }
        !           952:
        !           953:     if (xmx > xmax) {
        !           954:        xmx = xmax;
        !           955:        rc |= (x1_is_xmn ? CLIPLINE_CLIP_2 : CLIPLINE_CLIP_1);
        !           956:     }
        !           957:
        !           958:     if (xmn > xmx)
        !           959:        return 0;
        !           960:
        !           961:     ymn = yi + (xmn - xi)*sl;
        !           962:     ymx = yi + (xmx - xi)*sl;
        !           963:
        !           964:     if (sl < 0)
        !           965:        t = ymn, ymn = ymx, ymx = t;
        !           966:     if (ymn > ymax || ymx < ymin)
        !           967:        return 0;
        !           968:
        !           969:     if (rc & CLIPLINE_CLIP_1)
        !           970:        x1 = (x1_is_xmn ? xmn : xmx);
        !           971:     if (rc & CLIPLINE_CLIP_2)
        !           972:        x2 = (x1_is_xmn ? xmx : xmn);
        !           973:
        !           974:     /* Now we know there is an intersection, need to move x1 and x2 */
        !           975:     x1_is_ymn = ((sl >= 0) == (x1 < x2));
        !           976:     if (ymn < ymin) {
        !           977:        double x = (ymin - yi)/sl + xi; /* slope != 0  ! */
        !           978:
        !           979:        if (x1_is_ymn)
        !           980:            x1 = x, rc |= CLIPLINE_CLIP_1;
        !           981:        else
        !           982:            x2 = x, rc |= CLIPLINE_CLIP_2;
        !           983:     }
        !           984:     if (ymx > ymax) {
        !           985:        double x = (ymax - yi)/sl + xi; /* slope != 0  ! */
        !           986:
        !           987:        if (x1_is_ymn)
        !           988:            x2 = x, rc |= CLIPLINE_CLIP_2;
        !           989:        else
        !           990:            x1 = x, rc |= CLIPLINE_CLIP_1;
        !           991:     }
        !           992:     if (rc & CLIPLINE_CLIP_1)
        !           993:        y1 = yi + (x1 - xi)*sl;
        !           994:     if (rc & CLIPLINE_CLIP_2)
        !           995:        y2 = yi + (x2 - xi)*sl;
        !           996:     if (xy_exch)                       /* Exchange x and y */
        !           997:        *x1p = y1, *x2p = y2, *y1p = x1, *y2p = x2;
        !           998:     else
        !           999:        *x1p = x1, *x2p = x2, *y1p = y1, *y2p = y2;
        !          1000:     return rc;
        !          1001: }
        !          1002:
        !          1003: void
        !          1004: rectclip(long rect)
        !          1005: {
        !          1006:   PariRect *s = check_rect_init(rect);
        !          1007:   RectObj *p1 = RHead(s);
        !          1008:   RectObj **prevp = &RHead(s);
        !          1009:   RectObj *next;
        !          1010:   double xmin = 0;
        !          1011:   double xmax = RXsize(s);
        !          1012:   double ymin = 0;
        !          1013:   double ymax = RYsize(s);
        !          1014:
        !          1015:   while (p1) {
        !          1016:       int did_clip = 0;
        !          1017:
        !          1018:       next = RoNext(p1);
        !          1019:       switch(RoType(p1)) {
        !          1020:       case ROt_PT:
        !          1021:          if ( DTOL(RoPTx(p1)) < xmin || DTOL(RoPTx(p1)) > xmax
        !          1022:               || DTOL(RoPTy(p1)) < ymin || DTOL(RoPTy(p1)) > ymax) {
        !          1023:                 remove:
        !          1024:              *prevp = next;
        !          1025:              free(p1);
        !          1026:              break;
        !          1027:          }
        !          1028:          goto do_next;
        !          1029:       case ROt_BX:
        !          1030:          if (RoLNx1(p1) < xmin)
        !          1031:              RoLNx1(p1) = xmin, did_clip = 1;
        !          1032:          if (RoLNx2(p1) < xmin)
        !          1033:              RoLNx2(p1) = xmin, did_clip = 1;
        !          1034:          if (RoLNy1(p1) < ymin)
        !          1035:              RoLNy1(p1) = ymin, did_clip = 1;
        !          1036:          if (RoLNy2(p1) < ymin)
        !          1037:              RoLNy2(p1) = ymin, did_clip = 1;
        !          1038:          if (RoLNx1(p1) > xmax)
        !          1039:              RoLNx1(p1) = xmax, did_clip = 1;
        !          1040:          if (RoLNx2(p1) > xmax)
        !          1041:              RoLNx2(p1) = xmax, did_clip = 1;
        !          1042:          if (RoLNy1(p1) > ymax)
        !          1043:              RoLNy1(p1) = ymax, did_clip = 1;
        !          1044:          if (RoLNy2(p1) > ymax)
        !          1045:              RoLNy2(p1) = ymax, did_clip = 1;
        !          1046:          /* Remove zero-size clipped boxes */
        !          1047:          if ( did_clip
        !          1048:               && RoLNx1(p1) == RoLNx2(p1) && RoLNy1(p1) == RoLNy2(p1) )
        !          1049:              goto remove;
        !          1050:          goto do_next;
        !          1051:       case ROt_LN:
        !          1052:          if (!clipline(xmin, xmax, ymin, ymax,
        !          1053:                        &RoLNx1(p1), &RoLNy1(p1), &RoLNx2(p1), &RoLNy2(p1)))
        !          1054:              goto remove;
        !          1055:          goto do_next;
        !          1056:       case ROt_MP:
        !          1057:       {
        !          1058:          int c = RoMPcnt(p1);
        !          1059:          int f = 0, t = 0;
        !          1060:
        !          1061:          while (f < c) {
        !          1062:              if ( DTOL(RoMPxs(p1)[f]) >= xmin && DTOL(RoMPxs(p1)[f]) <= xmax
        !          1063:                   && DTOL(RoMPys(p1)[f]) >= ymin
        !          1064:                   && DTOL(RoMPys(p1)[f]) <= ymax) {
        !          1065:                  if (t != f) {
        !          1066:                      RoMPxs(p1)[t] = RoMPxs(p1)[f];
        !          1067:                      RoMPys(p1)[t] = RoMPys(p1)[f];
        !          1068:                  }
        !          1069:                  t++;
        !          1070:              }
        !          1071:              f++;
        !          1072:          }
        !          1073:          if (t == 0)
        !          1074:              goto remove;
        !          1075:          RoMPcnt(p1) = t;
        !          1076:          goto do_next;
        !          1077:       }
        !          1078:       case ROt_ML:
        !          1079:       {
        !          1080:          /* Hard case.  Here we need to break a multiline into
        !          1081:             several pieces if some part is clipped. */
        !          1082:          int c = RoMPcnt(p1) - 1;
        !          1083:          int f = 0, t = 0, had_lines = 0, had_hole = 0, rc;
        !          1084:          double ox = RoMLxs(p1)[0], oy = RoMLys(p1)[0], oxn, oyn;
        !          1085:
        !          1086:          while (f < c) {
        !          1087:              /* Endpoint of this segment is the startpoint of the
        !          1088:                 next one, so we need to preserve it if it is clipped. */
        !          1089:              oxn = RoMLxs(p1)[f + 1], oyn = RoMLys(p1)[f + 1];
        !          1090:              rc = clipline(xmin, xmax, ymin, ymax,
        !          1091:                            /* &RoMLxs(p1)[f], &RoMLys(p1)[f], */
        !          1092:                            &ox, &oy,
        !          1093:                            &RoMLxs(p1)[f+1], &RoMLys(p1)[f+1]);
        !          1094:              RoMLxs(p1)[f] = ox; RoMLys(p1)[f] = oy;
        !          1095:              ox = oxn; oy = oyn;
        !          1096:              if (!rc) {
        !          1097:                  if (had_lines)
        !          1098:                      had_hole = 1;
        !          1099:                  f++;
        !          1100:                  continue;
        !          1101:              }
        !          1102:
        !          1103:              if ( !had_lines || (!(rc & CLIPLINE_CLIP_1) && !had_hole) ) {
        !          1104:                  /* Continuous */
        !          1105:                  had_lines = 1;
        !          1106:                  if (t != f) {
        !          1107:                      if (t == 0) {
        !          1108:                          RoMPxs(p1)[t] = RoMPxs(p1)[f];
        !          1109:                          RoMPys(p1)[t] = RoMPys(p1)[f];
        !          1110:                      }
        !          1111:                      RoMPxs(p1)[t+1] = RoMPxs(p1)[f+1];
        !          1112:                      RoMPys(p1)[t+1] = RoMPys(p1)[f+1];
        !          1113:                  }
        !          1114:                  t++;
        !          1115:                  f++;
        !          1116:                  if ( rc & CLIPLINE_CLIP_2)
        !          1117:                      had_hole = 1, RoMLcnt(p1) = t + 1;
        !          1118:                  continue;
        !          1119:              }
        !          1120:              /* Is not continuous, automatically p1 is not free()ed.  */
        !          1121:              RoMLcnt(p1) = t + 1;
        !          1122:              if ( rc & CLIPLINE_CLIP_2) { /* Needs separate entry */
        !          1123:                  RectObj *n = (RectObj*) gpmalloc(sizeof(RectObj2P));
        !          1124:
        !          1125:                  RoType(n) = ROt_LN;
        !          1126:                  RoCol(n) = RoCol(p1);
        !          1127:                  RoLNx1(n) = RoMLxs(p1)[f];    RoLNy1(n) = RoMLys(p1)[f];
        !          1128:                  RoLNx2(n) = RoMLxs(p1)[f+1];  RoLNy2(n) = RoMLys(p1)[f+1];
        !          1129:                  RoNext(n) = next;
        !          1130:                  RoNext(p1) = n;
        !          1131:                  /* Restore the unclipped value: */
        !          1132:                  RoMLxs(p1)[f + 1] = oxn;      RoMLys(p1)[f + 1] = oyn;
        !          1133:                  f++;
        !          1134:                  prevp = &RoNext(n);
        !          1135:              }
        !          1136:              if (f + 1 < c) {          /* Are other lines */
        !          1137:                  RectObj *n = (RectObj*) gpmalloc(sizeof(RectObjMP));
        !          1138:                  RoType(n) = ROt_ML;
        !          1139:                  RoCol(n) = RoCol(p1);
        !          1140:                  RoMLcnt(n) = c - f;
        !          1141:                  RoMLxs(n) = (double*) gpmalloc(sizeof(double)*(c - f));
        !          1142:                  RoMLys(n) = (double*) gpmalloc(sizeof(double)*(c - f));
        !          1143:                  memcpy(RoMPxs(n),RoMPxs(p1) + f, sizeof(double)*(c - f));
        !          1144:                  memcpy(RoMPys(n),RoMPys(p1) + f, sizeof(double)*(c - f));
        !          1145:                  RoMPxs(n)[0] = oxn; RoMPys(n)[0] = oyn;
        !          1146:                  RoNext(n) = next;
        !          1147:                  RoNext(p1) = n;
        !          1148:                  next = n;
        !          1149:              }
        !          1150:              goto do_next;
        !          1151:          }
        !          1152:          if (t == 0)
        !          1153:              goto remove;
        !          1154:          goto do_next;
        !          1155:       }
        !          1156: #if 0
        !          1157:       case ROt_ST:
        !          1158:          next = (RectObj*) gpmalloc(sizeof(RectObjMP));
        !          1159:          memcpy(next,p1,sizeof(RectObjMP));
        !          1160:          RoSTs(next) = (char*) gpmalloc(RoSTl(p1)+1);
        !          1161:          memcpy(RoSTs(next),RoSTs(p1),RoSTl(p1)+1);
        !          1162:          RoSTx(next) += xoff; RoSTy(next) += yoff;
        !          1163:          RoNext(tail) = next; tail = next;
        !          1164:          break;
        !          1165: #endif
        !          1166:       default: {
        !          1167:        do_next:
        !          1168:              prevp = &RoNext(p1);
        !          1169:              break;
        !          1170:          }
        !          1171:       }
        !          1172:       p1 = next;
        !          1173:   }
        !          1174: }
        !          1175:
        !          1176: /********************************************************************/
        !          1177: /**                                                                **/
        !          1178: /**                        HI-RES PLOT                             **/
        !          1179: /**                                                                **/
        !          1180: /********************************************************************/
        !          1181:
        !          1182: static void
        !          1183: Appendx(dblPointList *f, dblPointList *l,double x)
        !          1184: {
        !          1185:   (l->d)[l->nb++]=x;
        !          1186:   if (x < f->xsml) f->xsml=x;
        !          1187:   else if (x > f->xbig) f->xbig=x;
        !          1188: }
        !          1189:
        !          1190: static void
        !          1191: Appendy(dblPointList *f, dblPointList *l,double y)
        !          1192: {
        !          1193:   (l->d)[l->nb++]=y;
        !          1194:   if (y < f->ysml) f->ysml=y;
        !          1195:   else if (y > f->ybig) f->ybig=y;
        !          1196: }
        !          1197:
        !          1198: /* Convert data from GEN to double before we call rectplothrawin */
        !          1199: static dblPointList*
        !          1200: gtodblList(GEN data, long flags)
        !          1201: {
        !          1202:   dblPointList *l;
        !          1203:   double xsml,xbig,ysml,ybig;
        !          1204:   long tx=typ(data), ty, nl=lg(data)-1, lx1,lx;
        !          1205:   register long i,j,u,v;
        !          1206:   long param=(flags & PLOT_PARAMETRIC);
        !          1207:   GEN x,y;
        !          1208:
        !          1209:   if (! is_vec_t(tx)) err(talker,"not a vector in gtodblList");
        !          1210:   if (!nl) return NULL;
        !          1211:   lx1=lg(data[1]);
        !          1212:
        !          1213:   /* Allocate memory, then convert coord. to double */
        !          1214:   l=(dblPointList*) gpmalloc(nl*sizeof(dblPointList));
        !          1215:   for (i=0; i<nl-1; i+=2)
        !          1216:   {
        !          1217:     u=i+1;
        !          1218:     x=(GEN)data[u]; tx = typ(x);
        !          1219:     y=(GEN)data[u+1]; ty = typ(y);
        !          1220:     if (!is_vec_t(tx) || !is_vec_t(ty)) err(ploter4);
        !          1221:     lx=lg(x); if (lg(y)!=lx) err(ploter5);
        !          1222:     if (!param && lx != lx1) err(ploter5);
        !          1223:     lx--;
        !          1224:
        !          1225:     if (lx)
        !          1226:     {
        !          1227:       l[i].d = (double*) gpmalloc(lx*sizeof(double));
        !          1228:       l[u].d = (double*) gpmalloc(lx*sizeof(double));
        !          1229:
        !          1230:       for (j=0; j<lx; j=v)
        !          1231:       {
        !          1232:        v=j+1;
        !          1233:        l[i].d[j]=gtodouble((GEN)x[v]);
        !          1234:        l[u].d[j]=gtodouble((GEN)y[v]);
        !          1235:       }
        !          1236:     }
        !          1237:     l[i].nb=l[u].nb=lx;
        !          1238:   }
        !          1239:
        !          1240:   xsml=xbig=l[0].d[0]; ysml=ybig=l[1].d[0];
        !          1241:
        !          1242:   /* Now compute extremas */
        !          1243:   if (param)
        !          1244:   {
        !          1245:     l[0].nb=nl/2;
        !          1246:     for (i=0; i<l[0].nb; i+=2)
        !          1247:     {
        !          1248:       u=i+1;
        !          1249:       for (j=0; j<l[u].nb; j++)
        !          1250:       {
        !          1251:        if (l[i].d[j]<xsml)
        !          1252:          xsml=l[i].d[j];
        !          1253:        else
        !          1254:          if (l[i].d[j]>xbig) xbig=l[i].d[j];
        !          1255:
        !          1256:        if (l[u].d[j]<ysml)
        !          1257:          ysml=l[u].d[j];
        !          1258:        else
        !          1259:          if (l[u].d[j]>ybig) ybig=l[u].d[j];
        !          1260:       }
        !          1261:     }
        !          1262:   }
        !          1263:   else
        !          1264:   {
        !          1265:     l[0].nb=nl-1;
        !          1266:     for (j=0; j<l[1].nb; j++)
        !          1267:     {
        !          1268:       if (l[0].d[j]<xsml)
        !          1269:        xsml=l[0].d[j];
        !          1270:       else
        !          1271:        if (l[0].d[j]>xbig) xbig=l[0].d[j];
        !          1272:     }
        !          1273:     for (i=1; i<=l[0].nb; i++)
        !          1274:     {
        !          1275:       for (j=0; j<l[i].nb; j++)
        !          1276:       {
        !          1277:        if (l[i].d[j]<ysml)
        !          1278:          ysml=l[i].d[j];
        !          1279:        else
        !          1280:          if (l[i].d[j]>ybig) ybig=l[i].d[j];
        !          1281:       }
        !          1282:     }
        !          1283:   }
        !          1284:   l[0].xsml=xsml; l[0].xbig=xbig;
        !          1285:   l[0].ysml=ysml; l[0].ybig=ybig;
        !          1286:   return l;
        !          1287: }
        !          1288:
        !          1289: static void
        !          1290: single_recursion(dblPointList *pl,char *ch,entree *ep,GEN xleft,GEN yleft,
        !          1291:   GEN xright,GEN yright,long depth)
        !          1292: {
        !          1293:   GEN xx,yy;
        !          1294:   long av=avma;
        !          1295:   double dy=pl[0].ybig - pl[0].ysml;
        !          1296:
        !          1297:   if (depth==RECUR_MAXDEPTH) return;
        !          1298:
        !          1299:   yy=cgetr(3); xx=gmul2n(gadd(xleft,xright),-1);
        !          1300:   ep->value = (void*) xx; gaffect(READ_EXPR(ch), yy);
        !          1301:
        !          1302:   if (dy)
        !          1303:   {
        !          1304:     if (fabs(rtodbl(yleft)+rtodbl(yright)-2*rtodbl(yy))/dy < RECUR_PREC)
        !          1305:       return;
        !          1306:   }
        !          1307:   single_recursion(pl,ch,ep, xleft,yleft, xx,yy, depth+1);
        !          1308:
        !          1309:   Appendx(&pl[0],&pl[0],rtodbl(xx));
        !          1310:   Appendy(&pl[0],&pl[1],rtodbl(yy));
        !          1311:
        !          1312:   single_recursion(pl,ch,ep, xx,yy, xright,yright, depth+1);
        !          1313:
        !          1314:   avma=av;
        !          1315: }
        !          1316:
        !          1317: static void
        !          1318: param_recursion(dblPointList *pl,char *ch,entree *ep, GEN tleft,GEN xleft,
        !          1319:   GEN yleft, GEN tright,GEN xright,GEN yright, long depth)
        !          1320: {
        !          1321:   GEN tt,xx,yy, p1;
        !          1322:   long av=avma;
        !          1323:   double dy=pl[0].ybig - pl[0].ysml;
        !          1324:   double dx=pl[0].xbig - pl[0].xsml;
        !          1325:
        !          1326:   if (depth==PARAMR_MAXDEPTH) return;
        !          1327:
        !          1328:   xx=cgetr(3); yy=cgetr(3); tt=gmul2n(gadd(tleft,tright),-1);
        !          1329:   ep->value = (void*)tt; p1=READ_EXPR(ch);
        !          1330:   gaffect((GEN)p1[1],xx); gaffect((GEN)p1[2],yy);
        !          1331:
        !          1332:   if (dx && dy)
        !          1333:   {
        !          1334:     if (fabs(rtodbl(xleft)+rtodbl(xright)-2*rtodbl(xx))/dx < RECUR_PREC &&
        !          1335:        fabs(rtodbl(yleft)+rtodbl(yright)-2*rtodbl(yy))/dy < RECUR_PREC)
        !          1336:         return;
        !          1337:   }
        !          1338:   param_recursion(pl,ch,ep, tleft,xleft,yleft, tt,xx,yy, depth+1);
        !          1339:
        !          1340:   Appendx(&pl[0],&pl[0],rtodbl(xx));
        !          1341:   Appendy(&pl[0],&pl[1],rtodbl(yy));
        !          1342:
        !          1343:   param_recursion(pl,ch,ep, tt,xx,yy, tright,xright,yright, depth+1);
        !          1344:
        !          1345:   avma=av;
        !          1346: }
        !          1347:
        !          1348: /*
        !          1349:  *  Pure graphing. If testpoints is 0, it is set to the default.
        !          1350:  *  Returns a dblPointList of (absolute) coordinates.
        !          1351:  */
        !          1352: static dblPointList *
        !          1353: rectplothin(entree *ep, GEN a, GEN b, char *ch, long prec, ulong flags,
        !          1354:             long testpoints)
        !          1355: {
        !          1356:   long single_c;
        !          1357:   long param=flags & PLOT_PARAMETRIC;
        !          1358:   long recur=flags & PLOT_RECURSIVE;
        !          1359:   GEN p1,dx,x,xleft,xright,yleft,yright,tleft,tright;
        !          1360:   dblPointList *pl;
        !          1361:   long tx,av = avma,av2,i,j,sig,nc,nl,nbpoints;
        !          1362:   double xsml,xbig,ysml,ybig,fx,fy;
        !          1363:
        !          1364:   if (!testpoints)
        !          1365:   {
        !          1366:     if (recur)
        !          1367:       testpoints = RECUR_NUMPOINTS;
        !          1368:     else
        !          1369:       testpoints = param? PARAM_NUMPOINTS : PLOTH_NUMPOINTS;
        !          1370:   }
        !          1371:   if (recur)
        !          1372:     nbpoints = testpoints << (param? PARAMR_MAXDEPTH : RECUR_MAXDEPTH);
        !          1373:   else
        !          1374:     nbpoints = testpoints;
        !          1375:
        !          1376:   sig=gcmp(b,a); if (!sig) return 0;
        !          1377:   if (sig<0) { x=a; a=b; b=x; }
        !          1378:   dx=gdivgs(gsub(b,a),testpoints-1);
        !          1379:
        !          1380:   x = cgetr(prec); gaffect(a,x); push_val(ep, x);
        !          1381:   av2=avma; p1=READ_EXPR(ch); tx=typ(p1);
        !          1382:   if (!is_matvec_t(tx))
        !          1383:   {
        !          1384:     xsml = gtodouble(a);
        !          1385:     xbig = gtodouble(b);
        !          1386:     ysml = ybig = gtodouble(p1);
        !          1387:     nc=1; nl=2; /* nc = nb of curves; nl = nb of coord. lists */
        !          1388:     if (param)
        !          1389:       err(warner,"flag PLOT_PARAMETRIC ignored");
        !          1390:     single_c=1; param=0;
        !          1391:   }
        !          1392:   else
        !          1393:   {
        !          1394:     if (tx != t_VEC) err(talker,"not a row vector in ploth");
        !          1395:     nl=lg(p1)-1; if (!nl) { avma=av; return 0; }
        !          1396:     single_c=0;
        !          1397:     if (param) nc=nl/2; else { nc=nl; nl++; }
        !          1398:     if (recur && nc > 1) err(talker,"multi-curves cannot be plot recursively");
        !          1399:
        !          1400:     if (param)
        !          1401:     {
        !          1402:       xbig=xsml=gtodouble((GEN)p1[1]);
        !          1403:       ybig=ysml=gtodouble((GEN)p1[2]);
        !          1404:       for (i=3; i<=nl; i++)
        !          1405:       {
        !          1406:        fx=gtodouble((GEN)p1[i]); i++;
        !          1407:         fy=gtodouble((GEN)p1[i]);
        !          1408:        if (xsml>fx) xsml=fx; else if (xbig<fx) xbig=fx;
        !          1409:        if (ysml>fy) ysml=fy; else if (ybig<fy) ybig=fy;
        !          1410:       }
        !          1411:     }
        !          1412:     else
        !          1413:     {
        !          1414:       xsml=gtodouble(a); xbig=gtodouble(b);
        !          1415:       ysml=gtodouble(vecmin(p1)); ybig=gtodouble(vecmax(p1));
        !          1416:     }
        !          1417:   }
        !          1418:
        !          1419:   pl=(dblPointList*) gpmalloc(nl*sizeof(dblPointList));
        !          1420:   for (i = 0; i < nl; i++)
        !          1421:   {
        !          1422:     pl[i].d = (double*) gpmalloc((nbpoints+1)*sizeof(dblPointList));
        !          1423:     pl[i].nb=0;
        !          1424:   }
        !          1425:   pl[0].xsml=xsml; pl[0].ysml=ysml; pl[0].xbig=xbig; pl[0].ybig=ybig;
        !          1426:
        !          1427:   if (recur) /* recursive plot */
        !          1428:   {
        !          1429:     xleft=cgetr(3); xright=cgetr(3); yleft=cgetr(3); yright=cgetr(3);
        !          1430:     if (param)
        !          1431:     {
        !          1432:       tleft=cgetr(prec); tright=cgetr(prec);
        !          1433:       av2=avma;
        !          1434:       gaffect(a,tleft); ep->value = (void*)tleft; p1=READ_EXPR(ch);
        !          1435:       gaffect((GEN)p1[1],xleft); gaffect((GEN)p1[2],yleft);
        !          1436:       for (i=0; i<testpoints-1; i++)
        !          1437:       {
        !          1438:        if (i) {
        !          1439:          gaffect(tright,tleft); gaffect(xright,xleft); gaffect(yright,yleft);
        !          1440:         }
        !          1441:        gaddz(tleft,dx,tright); ep->value = (void*)tright;
        !          1442:         p1 = READ_EXPR(ch);
        !          1443:         if (lg(p1) != 3) err(talker,"inconsistent data in rectplothin");
        !          1444:         gaffect((GEN)p1[1],xright); gaffect((GEN)p1[2],yright);
        !          1445:
        !          1446:        Appendx(&pl[0],&pl[0],rtodbl(xleft));
        !          1447:        Appendy(&pl[0],&pl[1],rtodbl(yleft));
        !          1448:
        !          1449:        param_recursion(pl,ch,ep, tleft,xleft,yleft, tright,xright,yright, 0);
        !          1450:        avma=av2;
        !          1451:       }
        !          1452:       Appendx(&pl[0],&pl[0],rtodbl(xright));
        !          1453:       Appendy(&pl[0],&pl[1],rtodbl(yright));
        !          1454:     }
        !          1455:     else /* single_c */
        !          1456:     {
        !          1457:       av2=avma;
        !          1458:       gaffect(a,xleft); ep->value = (void*) xleft;
        !          1459:       gaffect(READ_EXPR(ch),yleft);
        !          1460:       for (i=0; i<testpoints-1; i++)
        !          1461:       {
        !          1462:         gaddz(xleft,dx,xright); ep->value = (void*) xright;
        !          1463:        gaffect(READ_EXPR(ch),yright);
        !          1464:
        !          1465:        Appendx(&pl[0],&pl[0],rtodbl(xleft));
        !          1466:        Appendy(&pl[0],&pl[1],rtodbl(yleft));
        !          1467:
        !          1468:         single_recursion(pl,ch,ep,xleft,yleft,xright,yright,0);
        !          1469:         avma=av2;
        !          1470:         gaffect(xright,xleft); gaffect(yright,yleft);
        !          1471:       }
        !          1472:       Appendx(&pl[0],&pl[0],rtodbl(xright));
        !          1473:       Appendy(&pl[0],&pl[1],rtodbl(yright));
        !          1474:     }
        !          1475:   }
        !          1476:   else /* non-recursive plot */
        !          1477:   {
        !          1478:     if (single_c)
        !          1479:       for (i=0; i<testpoints; i++)
        !          1480:       {
        !          1481:        p1 = READ_EXPR(ch);
        !          1482:        pl[0].d[i]=gtodouble(x);
        !          1483:        Appendy(&pl[0],&pl[1],gtodouble(p1));
        !          1484:        gaddz(x,dx,x); avma=av2;
        !          1485:       }
        !          1486:     else if (param)
        !          1487:     {
        !          1488:       long k;
        !          1489:       double z;
        !          1490:
        !          1491:       for (i=0; i<testpoints; i++)
        !          1492:       {
        !          1493:        p1 = READ_EXPR(ch);
        !          1494:         if (lg(p1) != nl+1) err(talker,"inconsistent data in rectplothin");
        !          1495:        for (j=0; j<nl; j=k)
        !          1496:        {
        !          1497:          k=j+1; z=gtodouble((GEN)p1[k]);
        !          1498:          Appendx(&pl[0], &pl[j],z);
        !          1499:
        !          1500:          j=k; k++; z=gtodouble((GEN)p1[k]);
        !          1501:          Appendy(&pl[0], &pl[j],z);
        !          1502:         }
        !          1503:        gaddz(x,dx,x); avma=av2;
        !          1504:       }
        !          1505:     }
        !          1506:     else /* plothmult */
        !          1507:       for (i=0; i<testpoints; i++)
        !          1508:       {
        !          1509:        p1 = READ_EXPR(ch);
        !          1510:         if (lg(p1) != nl) err(talker,"inconsistent data in rectplothin");
        !          1511:        pl[0].d[i]=gtodouble(x);
        !          1512:        for (j=1; j<nl; j++) { Appendy(&pl[0],&pl[j],gtodouble((GEN)p1[j])); }
        !          1513:        gaddz(x,dx,x); avma=av2;
        !          1514:       }
        !          1515:   }
        !          1516:   pl[0].nb=nc; pop_val(ep); avma = av;
        !          1517:   return pl;
        !          1518: }
        !          1519:
        !          1520: extern GEN polint_i(GEN xa, GEN ya, GEN x, long n, GEN *ptdy);
        !          1521:
        !          1522: /* Uses highlevel plotting functions to implement splines as
        !          1523:    a low-level plotting function.
        !          1524:    Most probably one does not need to make varn==0 into pure variable,
        !          1525:    since plotting functions should take care of this. */
        !          1526: static void
        !          1527: rectsplines(long ne, double *x, double *y, long lx, long flag)
        !          1528: {
        !          1529:   long i, j, oldavma = avma;
        !          1530:   GEN tas, xa = cgetg(lx+1, t_VEC), ya = cgetg(lx+1, t_VEC);
        !          1531:   entree *var0 = varentries[ordvar[0]];
        !          1532:
        !          1533:   if (lx < 4)
        !          1534:       err(talker, "Too few points (%ld) for spline plot", lx);
        !          1535:   for (i = 1; i <= lx; i++) {
        !          1536:       xa[i] = (long) dbltor(x[i-1]);
        !          1537:       ya[i] = (long) dbltor(y[i-1]);
        !          1538:   }
        !          1539:   if (flag & PLOT_PARAMETRIC) {
        !          1540:       tas = new_chunk(4);
        !          1541:       for (j = 1; j <= 4; j++) tas[j-1] = lstoi(j);
        !          1542:       quark_gen = cgetg(2 + 1, t_VEC);
        !          1543:   }
        !          1544:   else tas = NULL; /* for lint */
        !          1545:   for (i = 0; i <= lx - 4; i++) {
        !          1546:       long oavma = avma;
        !          1547:
        !          1548:       xa++; ya++;
        !          1549:       if (flag & PLOT_PARAMETRIC) {
        !          1550:          quark_gen[1] = (long)polint_i(tas, xa, polx[0], 4, NULL);
        !          1551:          quark_gen[2] = (long)polint_i(tas, ya, polx[0], 4, NULL);
        !          1552:       } else {
        !          1553:          quark_gen = polint_i(xa, ya, polx[0], 4, NULL);
        !          1554:           tas = xa;
        !          1555:       }
        !          1556:       rectploth(ne, var0,
        !          1557:                  (GEN)(i==0 ? tas[0] : tas[1]),
        !          1558:                  (GEN)(i==lx-4 ? tas[3] : tas[2]),
        !          1559:                  QUARK,
        !          1560:                 DEFAULTPREC,           /* XXXX precision */
        !          1561:                 PLOT_RECURSIVE
        !          1562:                    | PLOT_NO_RESCALE
        !          1563:                    | PLOT_NO_FRAME
        !          1564:                   | PLOT_NO_AXE_Y
        !          1565:                    | PLOT_NO_AXE_X
        !          1566:                    | (flag & PLOT_PARAMETRIC),
        !          1567:                 2);                    /* Start with 3 points */
        !          1568:       avma = oavma;
        !          1569:   }
        !          1570:   avma = oldavma;
        !          1571: }
        !          1572:
        !          1573: /*
        !          1574:  * Plot a dblPointList. Complete with axes, bounding box, etc.
        !          1575:  * We use two drawing rectangles: one for strings, another
        !          1576:  * for graphs.
        !          1577:  *
        !          1578:  * data is an array of structs. Its meaning depends on flags :
        !          1579:  *
        !          1580:  * + data[0] contains global extremas, the number of curves to plot
        !          1581:  *   (data[0].nb) and a list of doubles (first set of x-coordinates).
        !          1582:  *
        !          1583:  * + data[i].nb (i>0) contains the number of points in the list
        !          1584:  *   data[i].d (hopefully, data[2i].nb=data[2i+1].nb when i>0...)
        !          1585:  *
        !          1586:  * + If flags contain PLOT_PARAMETRIC, the array length should be
        !          1587:  *   even, and successive pairs (data[2i].d, data[2i+1].d) represent
        !          1588:  *   curves to plot.
        !          1589:  *
        !          1590:  * + If there is no such flag, the first element is an array with
        !          1591:  *   x-coordinates and the following ones contain y-coordinates.
        !          1592:  *
        !          1593:  * Additional flags: PLOT_NO_AXE_X, PLOT_NO_AXE_Y, PLOT_NO_FRAME.
        !          1594:  */
        !          1595:
        !          1596: static GEN
        !          1597: rectplothrawin(long stringrect, long drawrect, dblPointList *data,
        !          1598:                long flags, PARI_plot *WW)
        !          1599: {
        !          1600:   GEN res;
        !          1601:   dblPointList y,x;
        !          1602:   double xsml,xbig,ysml,ybig,tmp;
        !          1603:   long ltype, ltop=avma;
        !          1604:   long i,nc,nbpoints, w[2], wx[2], wy[2];
        !          1605:
        !          1606:   w[0]=stringrect; w[1]=drawrect;
        !          1607:   if (!data) return cgetg(1,t_VEC);
        !          1608:   x = data[0]; nc = x.nb;
        !          1609:   xsml = x.xsml; xbig = x.xbig;
        !          1610:   ysml = x.ysml; ybig = x.ybig;
        !          1611:   if (xbig-xsml < 1.e-9)
        !          1612:   {
        !          1613:     tmp=fabs(xsml)/10; if (!tmp) tmp=0.1;
        !          1614:     xbig+=tmp; xsml-=tmp;
        !          1615:   }
        !          1616:   if (ybig-ysml < 1.e-9)
        !          1617:   {
        !          1618:     tmp=fabs(ysml)/10; if (!tmp) tmp=0.1;
        !          1619:     ybig+=tmp; ysml-=tmp;
        !          1620:   }
        !          1621:
        !          1622:   if (WW)
        !          1623:   { /* no rectwindow supplied ==> ps or screen output */
        !          1624:     char c1[16],c2[16],c3[16],c4[16];
        !          1625:     PARI_plot W = *WW;
        !          1626:     long lm = W.fwidth*10; /* left margin   */
        !          1627:     long rm = W.hunit-1; /* right margin  */
        !          1628:     long tm = W.vunit-1; /* top margin    */
        !          1629:     long bm = W.vunit+W.fheight-1; /* bottom margin */
        !          1630:     long is = W.width - (lm+rm);
        !          1631:     long js = W.height - (tm+bm);
        !          1632:
        !          1633:     wx[0]=wy[0]=0; wx[1]=lm; wy[1]=tm;
        !          1634:    /* Window size (W.width x W.height) is given in pixels, and
        !          1635:     * correct pixels are 0..w_width-1.
        !          1636:     * On the other hand, rect functions work with windows whose pixel
        !          1637:     * range is [0,width]. */
        !          1638:     initrect(stringrect, W.width-1, W.height-1);
        !          1639:     if (drawrect != stringrect) initrect(drawrect, is-1, js-1);
        !          1640:
        !          1641:     /* draw labels on stringrect */
        !          1642:     sprintf(c1,"%.5g",ybig); sprintf(c2,"%.5g",ysml);
        !          1643:     sprintf(c3,"%.5g",xsml); sprintf(c4,"%.5g",xbig);
        !          1644:
        !          1645:     rectlinetype(stringrect,-2); /* Frame */
        !          1646:     current_color[stringrect]=BLACK;
        !          1647:     put_string( stringrect, lm, 0, c1,
        !          1648:                RoSTdirRIGHT | RoSTdirHGAP | RoSTdirTOP);
        !          1649:     put_string(stringrect, lm, W.height - bm, c2,
        !          1650:                RoSTdirRIGHT | RoSTdirHGAP | RoSTdirVGAP);
        !          1651:     put_string(stringrect, lm, W.height - bm, c3,
        !          1652:                RoSTdirLEFT | RoSTdirTOP);
        !          1653:     put_string(stringrect, W.width - rm - 1, W.height - bm, c4,
        !          1654:                RoSTdirRIGHT | RoSTdirTOP);
        !          1655:   }
        !          1656:   RHasGraph(check_rect(drawrect)) = 1;
        !          1657:
        !          1658:   if (!(flags & PLOT_NO_RESCALE))
        !          1659:     rectscale0(drawrect, xsml, xbig, ysml, ybig);
        !          1660:
        !          1661:   if (!(flags & PLOT_NO_FRAME))
        !          1662:   {
        !          1663:     int do_double = (flags & PLOT_NODOUBLETICK) ? TICKS_NODOUBLE : 0;
        !          1664:
        !          1665:     rectlinetype(drawrect, -2);                /* Frame. */
        !          1666:     current_color[drawrect]=BLACK;
        !          1667:     rectmove0(drawrect,xsml,ysml,0);
        !          1668:     rectbox0(drawrect,xbig,ybig,0);
        !          1669:     if (!(flags & PLOT_NO_TICK_X)) {
        !          1670:       rectticks(WW, drawrect, xsml, ysml, xbig, ysml, xsml, xbig,
        !          1671:        TICKS_CLOCKW | do_double);
        !          1672:       rectticks(WW, drawrect, xbig, ybig, xsml, ybig, xbig, xsml,
        !          1673:        TICKS_CLOCKW | do_double);
        !          1674:     }
        !          1675:     if (!(flags & PLOT_NO_TICK_Y)) {
        !          1676:       rectticks(WW, drawrect, xbig, ysml, xbig, ybig, ysml, ybig,
        !          1677:        TICKS_CLOCKW | do_double);
        !          1678:       rectticks(WW, drawrect, xsml, ybig, xsml, ysml, ybig, ysml,
        !          1679:        TICKS_CLOCKW | do_double);
        !          1680:     }
        !          1681:   }
        !          1682:
        !          1683:   if (!(flags & PLOT_NO_AXE_Y) && (xsml<=0 && xbig >=0))
        !          1684:   {
        !          1685:     rectlinetype(drawrect, -1);                /* Axes. */
        !          1686:     current_color[drawrect]=BLUE;
        !          1687:     rectmove0(drawrect,0.0,ysml,0);
        !          1688:     rectline0(drawrect,0.0,ybig,0);
        !          1689:   }
        !          1690:
        !          1691:   if (!(flags & PLOT_NO_AXE_X) && (ysml<=0 && ybig >=0))
        !          1692:   {
        !          1693:     rectlinetype(drawrect, -1);                /* Axes. */
        !          1694:     current_color[drawrect]=BLUE;
        !          1695:     rectmove0(drawrect,xsml,0.0,0);
        !          1696:     rectline0(drawrect,xbig,0.0,0);
        !          1697:   }
        !          1698:
        !          1699:   i = (flags & PLOT_PARAMETRIC)? 0: 1;
        !          1700:   for (ltype = 0; ltype < nc; ltype++)
        !          1701:   {
        !          1702:     current_color[drawrect] = ltype&1 ? SIENNA: RED;
        !          1703:     if (flags & PLOT_PARAMETRIC) x = data[i++];
        !          1704:
        !          1705:     y=data[i++]; nbpoints=y.nb;
        !          1706:     if ((flags & PLOT_POINTS_LINES) || (flags & PLOT_POINTS)) {
        !          1707:        rectlinetype(drawrect, rectpoint_itype + ltype);        /* Graphs. */
        !          1708:        rectpointtype(drawrect, rectpoint_itype + ltype);       /* Graphs. */
        !          1709:        rectpoints0(drawrect,x.d,y.d,nbpoints);
        !          1710:     }
        !          1711:     if ((flags & PLOT_POINTS_LINES) || !(flags & PLOT_POINTS)) {
        !          1712:        if (flags & PLOT_SPLINES) {
        !          1713:            /* rectsplines will call us back with ltype == 0 */
        !          1714:            int old = rectline_itype;
        !          1715:
        !          1716:            rectline_itype = rectline_itype + ltype;
        !          1717:            rectsplines(drawrect,x.d,y.d,nbpoints,flags);
        !          1718:            rectline_itype = old;
        !          1719:        } else {
        !          1720:            rectlinetype(drawrect, rectline_itype + ltype);     /* Graphs. */
        !          1721:            rectlines0(drawrect,x.d,y.d,nbpoints,0);
        !          1722:        }
        !          1723:     }
        !          1724:   }
        !          1725:   for (i--; i>=0; i--) free(data[i].d);
        !          1726:   free(data);
        !          1727:
        !          1728:   if (WW)
        !          1729:   {
        !          1730:     if (flags & PLOT_POSTSCRIPT)
        !          1731:       postdraw0(w,wx,wy,2);
        !          1732:     else
        !          1733:       rectdraw0(w,wx,wy,2, 0);
        !          1734:
        !          1735:     killrect(drawrect); if (stringrect != drawrect) killrect(stringrect);
        !          1736:   }
        !          1737:
        !          1738:   avma=ltop;
        !          1739:   res = cgetg(5,t_VEC);
        !          1740:   res[1]=(long)dbltor(xsml); res[2]=(long)dbltor(xbig);
        !          1741:   res[3]=(long)dbltor(ysml); res[4]=(long)dbltor(ybig);
        !          1742:   return res;
        !          1743: }
        !          1744:
        !          1745: /*************************************************************************/
        !          1746: /*                                                                       */
        !          1747: /*                          HI-RES FUNCTIONS                             */
        !          1748: /*                                                                       */
        !          1749: /*************************************************************************/
        !          1750:
        !          1751: GEN
        !          1752: rectploth(long drawrect,entree *ep,GEN a,GEN b,char *ch,
        !          1753:           long prec,ulong flags,long testpoints)
        !          1754: {
        !          1755:   dblPointList *pl=rectplothin(ep, a,b, ch, prec, flags,testpoints);
        !          1756:   return rectplothrawin(0,drawrect, pl, flags,NULL);
        !          1757: }
        !          1758:
        !          1759: GEN
        !          1760: rectplothraw(long drawrect, GEN data, long flags)
        !          1761: {
        !          1762:   dblPointList *pl=gtodblList(data,flags);
        !          1763:   return rectplothrawin(0,drawrect,pl,flags,NULL);
        !          1764: }
        !          1765:
        !          1766: static PARI_plot*
        !          1767: init_output(long flags)
        !          1768: {
        !          1769:   if (flags & PLOT_POSTSCRIPT)
        !          1770:     { PARI_get_psplot(); return &pari_psplot; }
        !          1771:   else
        !          1772:     { PARI_get_plot(0); return &pari_plot; }
        !          1773: }
        !          1774:
        !          1775: static GEN
        !          1776: ploth0(long stringrect,long drawrect,entree *ep,GEN a,GEN b,char *ch,
        !          1777:              long prec,ulong flags,long testpoints)
        !          1778: {
        !          1779:   PARI_plot *output = init_output(flags);
        !          1780:   dblPointList *pl=rectplothin(ep, a,b, ch, prec, flags,testpoints);
        !          1781:   return rectplothrawin(stringrect,drawrect, pl, flags, output);
        !          1782: }
        !          1783:
        !          1784: static GEN
        !          1785: plothraw0(long stringrect, long drawrect, GEN listx, GEN listy, long flags)
        !          1786: {
        !          1787:   PARI_plot *output = init_output(flags);
        !          1788:   long data[] = {evaltyp(t_VEC) | m_evallg(3), 0, 0};
        !          1789:   dblPointList *pl;
        !          1790:
        !          1791:   data[1] = (long) listx;
        !          1792:   data[2] = (long) listy;
        !          1793:   pl=gtodblList(data,PLOT_PARAMETRIC);
        !          1794:   if (!pl) return cgetg(1,t_VEC);
        !          1795:   return rectplothrawin(stringrect,drawrect,pl,flags | PLOT_PARAMETRIC,output);
        !          1796: }
        !          1797:
        !          1798: GEN
        !          1799: plothraw(GEN listx, GEN listy, long flags)
        !          1800: {
        !          1801:   flags = (flags > 1 ? flags : (flags ? 0: PLOT_POINTS));
        !          1802:   return plothraw0(STRINGRECT, DRAWRECT, listx, listy, flags);
        !          1803: }
        !          1804:
        !          1805: GEN
        !          1806: ploth(entree *ep, GEN a, GEN b, char *ch, long prec,long flags,long numpoints)
        !          1807: {
        !          1808:   return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,flags,numpoints);
        !          1809: }
        !          1810:
        !          1811: GEN
        !          1812: ploth2(entree *ep, GEN a, GEN b, char *ch, long prec)
        !          1813: {
        !          1814:   return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,PLOT_PARAMETRIC,0);
        !          1815: }
        !          1816:
        !          1817: GEN
        !          1818: plothmult(entree *ep, GEN a, GEN b, char *ch, long prec)
        !          1819: {
        !          1820:   return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,0,0);
        !          1821: }
        !          1822:
        !          1823: GEN
        !          1824: postplothraw(GEN listx, GEN listy, long flags)
        !          1825: {
        !          1826:   flags=(flags)? 0: PLOT_POINTS;
        !          1827:   return plothraw0(STRINGRECT, DRAWRECT, listx, listy, flags|PLOT_POSTSCRIPT);
        !          1828: }
        !          1829:
        !          1830: GEN
        !          1831: postploth(entree *ep, GEN a, GEN b, char *ch, long prec,long flags,
        !          1832:            long numpoints)
        !          1833: {
        !          1834:   return ploth0(STRINGRECT,DRAWRECT,ep,a,b,ch,prec,flags|PLOT_POSTSCRIPT,
        !          1835:                 numpoints);
        !          1836: }
        !          1837:
        !          1838: GEN
        !          1839: postploth2(entree *ep, GEN a, GEN b, char *ch, long prec,
        !          1840:            long numpoints)
        !          1841: {
        !          1842:   return ploth0(STRINGRECT,DRAWRECT,ep,a,b,ch,prec,
        !          1843:                PLOT_PARAMETRIC|PLOT_POSTSCRIPT,numpoints);
        !          1844: }
        !          1845:
        !          1846: GEN
        !          1847: plothsizes()
        !          1848: {
        !          1849:   return plothsizes_flag(0);
        !          1850: }
        !          1851:
        !          1852: GEN
        !          1853: plothsizes_flag(long flag)
        !          1854: {
        !          1855:   GEN vect = cgetg(1+6,t_VEC);
        !          1856:
        !          1857:   PARI_get_plot(0);
        !          1858:   vect[1] = lstoi(w_width);
        !          1859:   vect[2] = lstoi(w_height);
        !          1860:   if (flag) {
        !          1861:     vect[3] = (long)dbltor(h_unit*1.0/w_width);
        !          1862:     vect[4] = (long)dbltor(v_unit*1.0/w_height);
        !          1863:     vect[5] = (long)dbltor(f_width*1.0/w_width);
        !          1864:     vect[6] = (long)dbltor(f_height*1.0/w_height);
        !          1865:   } else {
        !          1866:     vect[3] = lstoi(h_unit);
        !          1867:     vect[4] = lstoi(v_unit);
        !          1868:     vect[5] = lstoi(f_width);
        !          1869:     vect[6] = lstoi(f_height);
        !          1870:   }
        !          1871:   return vect;
        !          1872: }
        !          1873:
        !          1874: /*************************************************************************/
        !          1875: /*                                                                       */
        !          1876: /*                         POSTSCRIPT OUTPUT                             */
        !          1877: /*                                                                       */
        !          1878: /*************************************************************************/
        !          1879:
        !          1880: typedef struct spoint {
        !          1881:   int x,y; } SPoint;
        !          1882: typedef struct ssegment {
        !          1883:   int x1,y1,x2,y2; } SSegment;
        !          1884: typedef struct srectangle {
        !          1885:   int x,y,width,height; } SRectangle;
        !          1886:
        !          1887: static void ps_point(FILE *psfile, int x, int y);
        !          1888: static void ps_line(FILE *psfile, int x1, int y1, int x2, int y2);
        !          1889: static void ps_rect(FILE *psfile, int x1, int y1, int x2, int y2);
        !          1890: static void ps_string(FILE *psfile, int x, int y, char *c, long dir);
        !          1891:
        !          1892: #undef ISCR
        !          1893: #undef JSCR
        !          1894: #define ISCR 1120 /* 1400 en haute resolution */
        !          1895: #define JSCR 800  /* 1120 en haute resolution */
        !          1896:
        !          1897: static void
        !          1898: PARI_get_psplot()
        !          1899: {
        !          1900:   pari_psplot.height = JSCR - 60;
        !          1901:   pari_psplot.width  = ISCR - 40;
        !          1902:   pari_psplot.fheight = 15;
        !          1903:   pari_psplot.fwidth = 6;
        !          1904:   pari_psplot.hunit = 5;
        !          1905:   pari_psplot.vunit = 5;
        !          1906: }
        !          1907:
        !          1908: static void
        !          1909: gendraw(GEN list, long ps, long flag)
        !          1910: {
        !          1911:   long i,n,ne,*w,*x,*y;
        !          1912:   GEN x0,y0,win;
        !          1913:
        !          1914:   if (typ(list) != t_VEC) err(talker,"not a vector in rectdraw");
        !          1915:   n = lg(list)-1;
        !          1916:   if (n%3) err(talker,"incorrect number of components in rectdraw");
        !          1917:   n = n/3; if (!n) return;
        !          1918:   w = (long*)gpmalloc(n*sizeof(long));
        !          1919:   x = (long*)gpmalloc(n*sizeof(long));
        !          1920:   y = (long*)gpmalloc(n*sizeof(long));
        !          1921:   if (flag)
        !          1922:     PARI_get_plot(0);
        !          1923:   for (i=0; i<n; i++)
        !          1924:   {
        !          1925:     win=(GEN)list[3*i+1]; x0=(GEN)list[3*i+2]; y0=(GEN)list[3*i+3];
        !          1926:     if (typ(win)!=t_INT || (!flag && (typ(x0)!=t_INT || typ(y0)!= t_INT)))
        !          1927:       err(talker, "not an integer type in rectdraw");
        !          1928:     if (flag) {
        !          1929:       double xd = gtodouble(x0), yd = gtodouble(y0);
        !          1930:       long xi, yi;
        !          1931:
        !          1932:       xi = w_width - 1;  yi = w_height - 1;
        !          1933:       xi = (long)(xd*xi + 0.5);
        !          1934:       yi = (long)(yd*yi + 0.5);
        !          1935:       x[i] = xi; y[i] = yi;
        !          1936:     } else {
        !          1937:       x[i]=itos(x0); y[i]=itos(y0);
        !          1938:     }
        !          1939:     ne=itos(win); check_rect(ne);
        !          1940:     w[i]=ne;
        !          1941:   }
        !          1942:   if (ps) postdraw00(w,x,y,n,flag); else rectdraw0(w,x,y,n, 1);
        !          1943:   free(x); free(y); free(w);
        !          1944: }
        !          1945:
        !          1946: void
        !          1947: postdraw(GEN list) { gendraw(list, 1, 0); }
        !          1948:
        !          1949: void
        !          1950: rectdraw(GEN list) { gendraw(list, 0, 0); }
        !          1951:
        !          1952: void
        !          1953: postdraw_flag(GEN list, long flag) { gendraw(list, 1, flag); }
        !          1954:
        !          1955: void
        !          1956: rectdraw_flag(GEN list, long flag) { gendraw(list, 0, flag); }
        !          1957:
        !          1958: static char*
        !          1959: zmalloc(size_t x)
        !          1960: {
        !          1961:   return x? gpmalloc(x): NULL;
        !          1962: }
        !          1963:
        !          1964: void
        !          1965: postdraw0(long *w, long *x, long *y, long lw)
        !          1966: {
        !          1967:   postdraw00(w, x, y, lw, 0);
        !          1968: }
        !          1969:
        !          1970: void
        !          1971: postdraw00(long *w, long *x, long *y, long lw, long scale)
        !          1972: {
        !          1973:   double *ptx,*pty;
        !          1974:   long *numpoints,*numtexts,*xtexts,*ytexts,*dirtexts;
        !          1975:   RectObj *p1;
        !          1976:   PariRect *e;
        !          1977:   long i,j,x0,y0;
        !          1978:   long a,b,c,d,nd[ROt_MAX+1];
        !          1979:   char **texts;
        !          1980:   FILE *psfile;
        !          1981:   double xscale = 0.65, yscale = 0.65;
        !          1982:   long fontsize = 16, xtick = 5, ytick = 5;
        !          1983:
        !          1984:   SPoint *points, **lines, *SLine;
        !          1985:   SSegment *seg;
        !          1986:   SRectangle *rect, SRec;
        !          1987:
        !          1988:   if (scale) {
        !          1989:     double postxsize, postysize;
        !          1990:
        !          1991:     PARI_get_psplot();
        !          1992:     postxsize = pari_psplot.width;
        !          1993:     postysize = pari_psplot.height;
        !          1994:     PARI_get_plot(0);
        !          1995:     xscale *= postxsize * 1.0/w_width;
        !          1996:     fontsize = (long) (fontsize/(postxsize * 1.0/w_width));
        !          1997:     yscale *= postysize * 1.0/w_height;
        !          1998:     xtick = h_unit;  ytick = v_unit;
        !          1999:   }
        !          2000:   psfile = fopen(current_psfile, "a");
        !          2001:   if (!psfile)
        !          2002:     err(openfiler,"postscript",current_psfile);
        !          2003:
        !          2004:   for (i=0; i<=ROt_MAX; i++) nd[i]=0;
        !          2005:
        !          2006:   for (i=0; i<lw; i++)
        !          2007:   {
        !          2008:     e = check_rect_init(w[i]); p1=RHead(e);
        !          2009:     while (p1)
        !          2010:     {
        !          2011:       if (RoType(p1) != ROt_MP) nd[RoType(p1)]++;
        !          2012:       else nd[ROt_PT]+=RoMPcnt(p1);
        !          2013:       p1=RoNext(p1);
        !          2014:     }
        !          2015:   }
        !          2016:   points=(SPoint*) zmalloc(nd[ROt_PT]*sizeof(SPoint));
        !          2017:   seg=(SSegment*) zmalloc(nd[ROt_LN]*sizeof(SSegment));
        !          2018:   rect=(SRectangle*) zmalloc(nd[ROt_BX]*sizeof(SRectangle));
        !          2019:   lines=(SPoint**) zmalloc(nd[ROt_ML]*sizeof(SPoint*));
        !          2020:   numpoints=(long*) zmalloc(nd[ROt_ML]*sizeof(long));
        !          2021:   texts=(char**) zmalloc(nd[ROt_ST]*sizeof(char*));
        !          2022:   numtexts=(long*) zmalloc(nd[ROt_ST]*sizeof(long));
        !          2023:   xtexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
        !          2024:   ytexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
        !          2025:   dirtexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
        !          2026:   for (i=0; i<=ROt_MAX; i++) nd[i]=0;
        !          2027:
        !          2028:   for (i=0; i<lw; i++)
        !          2029:   {
        !          2030:     e=rectgraph[w[i]]; p1=RHead(e); x0=x[i]; y0=y[i];
        !          2031:     while (p1)
        !          2032:     {
        !          2033:       switch(RoType(p1))
        !          2034:       {
        !          2035:        case ROt_PT:
        !          2036:          points[nd[ROt_PT]].x = DTOL(RoPTx(p1)+x0);
        !          2037:          points[nd[ROt_PT]].y = DTOL(RoPTy(p1)+y0);
        !          2038:          nd[ROt_PT]++; break;
        !          2039:        case ROt_LN:
        !          2040:          seg[nd[ROt_LN]].x1 = DTOL(RoLNx1(p1)+x0);
        !          2041:          seg[nd[ROt_LN]].y1 = DTOL(RoLNy1(p1)+y0);
        !          2042:          seg[nd[ROt_LN]].x2 = DTOL(RoLNx2(p1)+x0);
        !          2043:          seg[nd[ROt_LN]].y2 = DTOL(RoLNy2(p1)+y0);
        !          2044:          nd[ROt_LN]++; break;
        !          2045:        case ROt_BX:
        !          2046:          a=rect[nd[ROt_BX]].x = DTOL(RoBXx1(p1)+x0);
        !          2047:          b=rect[nd[ROt_BX]].y = DTOL(RoBXy1(p1)+y0);
        !          2048:          rect[nd[ROt_BX]].width = DTOL(RoBXx2(p1)+x0-a);
        !          2049:          rect[nd[ROt_BX]].height = DTOL(RoBXy2(p1)+y0-b);
        !          2050:          nd[ROt_BX]++; break;
        !          2051:        case ROt_MP:
        !          2052:          ptx = RoMPxs(p1); pty = RoMPys(p1);
        !          2053:          for (j=0; j<RoMPcnt(p1); j++)
        !          2054:          {
        !          2055:            points[nd[ROt_PT]+j].x = DTOL(ptx[j]+x0);
        !          2056:            points[nd[ROt_PT]+j].y = DTOL(pty[j]+y0);
        !          2057:          }
        !          2058:          nd[ROt_PT]+=RoMPcnt(p1); break;
        !          2059:        case ROt_ML:
        !          2060:          ptx=RoMLxs(p1); pty=RoMLys(p1);
        !          2061:          numpoints[nd[ROt_ML]]=RoMLcnt(p1);
        !          2062:          lines[nd[ROt_ML]]=(SPoint*)gpmalloc(RoMLcnt(p1)*sizeof(SPoint));
        !          2063:          for (j=0; j<RoMLcnt(p1); j++)
        !          2064:          {
        !          2065:            lines[nd[ROt_ML]][j].x = DTOL(ptx[j]+x0);
        !          2066:            lines[nd[ROt_ML]][j].y = DTOL(pty[j]+y0);
        !          2067:          }
        !          2068:          nd[ROt_ML]++; break;
        !          2069:        case ROt_ST:
        !          2070:          texts[nd[ROt_ST]] = RoSTs(p1);
        !          2071:          numtexts[nd[ROt_ST]] = RoSTl(p1);
        !          2072:          xtexts[nd[ROt_ST]] = DTOL(RoSTx(p1)+x0);
        !          2073:          ytexts[nd[ROt_ST]] = DTOL(RoSTy(p1)+y0);
        !          2074:          dirtexts[nd[ROt_ST]] = RoSTdir(p1);
        !          2075:          nd[ROt_ST]++; break;
        !          2076:        default: break;
        !          2077:       }
        !          2078:       p1=RoNext(p1);
        !          2079:     }
        !          2080:   }
        !          2081:   /* Definitions taken from post terminal of Gnuplot. */
        !          2082:   fprintf(psfile,"%%!\n50 50 translate\n/Times-Roman findfont %ld scalefont setfont\n%g %g scale\n", fontsize, yscale,xscale);
        !          2083:   fprintf(psfile,"/Lshow { moveto 90 rotate show -90 rotate } def\n/Rshow { 3 -1 roll dup 4 1 roll stringwidth pop sub Lshow } def\n/Cshow { 3 -1 roll dup 4 1 roll stringwidth pop 2 div sub Lshow } def\n");
        !          2084:   fprintf(psfile,"/Xgap %ld def\n/Ygap %ld def\n", xtick, ytick);
        !          2085:   fprintf(psfile,"/Bbox { gsave newpath 0 0 moveto true charpath pathbbox grestore } def\n");
        !          2086:   fprintf(psfile,"/Height { Bbox 4 1 roll pop pop pop } def\n");
        !          2087:   fprintf(psfile,"/TopAt { 3 -1 roll dup 4 1 roll Height 3 -1 roll add exch } def\n");
        !          2088:   fprintf(psfile,"/VCenter { 3 -1 roll dup 4 1 roll Height 2 div 3 -1 roll add exch } def\n");
        !          2089:   fprintf(psfile,"/Tgap { exch Ygap add exch } def\n");
        !          2090:   fprintf(psfile,"/Bgap { exch Ygap sub exch } def\n");
        !          2091:   fprintf(psfile,"/Lgap { Xgap add } def\n");
        !          2092:   fprintf(psfile,"/Rgap { Xgap sub } def\n");
        !          2093:
        !          2094:   for (i=0; i<nd[ROt_PT]; i++)
        !          2095:     ps_point(psfile,points[i].x,points[i].y);
        !          2096:   for (i=0; i<nd[ROt_LN]; i++)
        !          2097:     ps_line(psfile,seg[i].x1,seg[i].y1,seg[i].x2,seg[i].y2);
        !          2098:   for (i=0; i<nd[ROt_BX]; i++)
        !          2099:   {
        !          2100:     SRec=rect[i]; a=SRec.x; b=SRec.y; c=a+SRec.width;
        !          2101:     d=b+SRec.height; ps_rect(psfile,a,b,c,d);
        !          2102:   }
        !          2103:   for (i=0; i<nd[ROt_ML]; i++)
        !          2104:   {
        !          2105:     SLine=lines[i];
        !          2106:     for (j=0; j<numpoints[i]; j++)
        !          2107:     {
        !          2108:       if (!j) fprintf(psfile,"%d %d moveto\n",SLine[0].y,SLine[0].x);
        !          2109:       else fprintf(psfile,"%d %d lineto\n",SLine[j].y,SLine[j].x);
        !          2110:     }
        !          2111:   }
        !          2112:   for (i=0; i<nd[ROt_ST]; i++)
        !          2113:     ps_string(psfile,xtexts[i],ytexts[i],texts[i], dirtexts[i]);
        !          2114:   fprintf(psfile,"stroke showpage\n"); fclose(psfile);
        !          2115: #define xfree(pointer) if (pointer) free(pointer)
        !          2116:   xfree(points); xfree(seg); xfree(rect); xfree(numpoints);
        !          2117:   for (i=0; i<nd[ROt_ML]; i++) xfree(lines[i]);
        !          2118:   xfree(lines); xfree(texts); xfree(numtexts); xfree(xtexts); xfree(ytexts);
        !          2119: #undef xfree
        !          2120: }
        !          2121:
        !          2122: static void
        !          2123: ps_point(FILE *psfile, int x, int y)
        !          2124: {
        !          2125:   fprintf(psfile,"%d %d moveto\n0 2 rlineto 2 0 rlineto 0 -2 rlineto closepath fill\n",y,x);
        !          2126: }
        !          2127:
        !          2128: static void
        !          2129: ps_line(FILE *psfile, int x1, int y1, int x2, int y2)
        !          2130: {
        !          2131:   fprintf(psfile,"%d %d moveto\n%d %d lineto\n",y1,x1,y2,x2);
        !          2132: }
        !          2133:
        !          2134: static void
        !          2135: ps_rect(FILE *psfile, int x1, int y1, int x2, int y2)
        !          2136: {
        !          2137:   fprintf(psfile,"%d %d moveto\n%d %d lineto\n%d %d lineto\n%d %d lineto\nclosepath\n",y1,x1,y1,x2,y2,x2,y2,x1);
        !          2138: }
        !          2139:
        !          2140: static void
        !          2141: ps_string(FILE *psfile, int x, int y, char *s, long dir)
        !          2142: {
        !          2143:     if (strpbrk(s, "(\\)")) {
        !          2144:        fprintf(psfile,"(");
        !          2145:        while (*s) {
        !          2146:            if ( *s=='(' || *s==')' || *s=='\\' )
        !          2147:                fputc('\\', psfile);
        !          2148:            fputc(*s, psfile);
        !          2149:            s++;
        !          2150:        }
        !          2151:     } else
        !          2152:        fprintf(psfile,"(%s", s);
        !          2153:     fprintf(psfile,") %d %d %s%s%s%sshow\n",
        !          2154:            y, x,
        !          2155:            ((dir & RoSTdirVGAP)
        !          2156:             ? ((dir & RoSTdirVPOS_mask) == RoSTdirTOP ? "Tgap " : "Bgap ")
        !          2157:             : ""),
        !          2158:            ((dir & RoSTdirHGAP)
        !          2159:             ? ((dir & RoSTdirHPOS_mask) == RoSTdirRIGHT ? "Rgap " : "Lgap ")
        !          2160:             : ""),
        !          2161:            ((dir & RoSTdirVPOS_mask) == RoSTdirBOTTOM ? ""
        !          2162:             : (dir & RoSTdirVPOS_mask) == RoSTdirTOP ? "TopAt " : "VCenter "),
        !          2163:            ((dir & RoSTdirHPOS_mask) == RoSTdirLEFT ? "L"
        !          2164:             : ((dir & RoSTdirHPOS_mask) == RoSTdirRIGHT ? "R" : "C")));
        !          2165: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>