/*******************************************************************/ /* */ /* PLOT ROUTINES */ /* */ /*******************************************************************/ /* $Id: plotport.c,v 1.1.1.1 1999/09/16 13:47:44 karim Exp $ */ #include "pari.h" #include "rect.h" void push_val(entree *ep, GEN a); void pop_val(entree *ep); void postdraw0(long *w, long *x, long *y, long lw); void rectdraw0(long *w, long *x, long *y, long lw, long do_free); static void PARI_get_psplot(); static long current_color[NUMRECT]; PariRect **rectgraph = NULL; PARI_plot pari_plot, pari_psplot; long rectpoint_itype = 0; long rectline_itype = 0; #define STRINGRECT (NUMRECT-2) #define DRAWRECT (NUMRECT-1) #define PLOTH_NUMPOINTS 1000 #define PARAM_NUMPOINTS 1500 #define RECUR_NUMPOINTS 8 #define RECUR_MAXDEPTH 10 #define RECUR_PREC 0.001 #define PARAMR_MAXDEPTH 10 /********************************************************************/ /** **/ /** LOW-RES PLOT **/ /** **/ /********************************************************************/ #define ISCR 64 #define JSCR 22 #define BLANK ' ' #define ZERO1 ',' #define ZERO2 '-' #define ZERO3 '`' #define PICTZERO(j) ((j) % 3 ? ((j) % 3 == 2 ? ZERO3 : ZERO2) : ZERO1) #define YY '|' #define XX_UPPER '\'' #define XX_LOWER '.' #define FF1 '_' #define FF2 'x' #define FF3 '"' #define PICT(j) ((j) % 3 ? ((j) % 3 == 2 ? FF3 : FF2) : FF1) static char * dsprintf9(double d, char *buf) { int i = 10; while (--i >= 0) { sprintf(buf, "%9.*g", i, d); if (strlen(buf) <= 9) return buf; } return buf; /* Should not happen? */ } #define QUARK ((char*)NULL) /* Used as a special-case */ static GEN quark_gen; #define READ_EXPR(s) ((s)==QUARK? quark_gen : lisexpr(s)) void plot(entree *ep, GEN a, GEN b, char *ch, long prec) { long av = avma, av2,limite,jz,j,i,sig; int jnew, jpre = 0; /* for lint */ GEN p1,p2,ysml,ybig,x,diff,dyj,dx,y[ISCR+1]; unsigned char scr[ISCR+1][JSCR+1]; char buf[80], z; sig=gcmp(b,a); if (!sig) return; if (sig<0) { x=a; a=b; b=x; } x = cgetr(prec); gaffect(a,x); push_val(ep, x); for (i=1; i<=ISCR; i++) y[i]=cgetr(3); p1 = gdivgs(gsub(b,a), ISCR-1); dx = cgetr(prec); gaffect(p1, dx); ysml=gzero; ybig=gzero; for (j=1; j<=JSCR; j++) scr[1][j]=scr[ISCR][j]=YY; for (i=2; i0) ybig=y[i]; x = addrr(x,dx); if (low_stack(limite, stack_lim(av2,1))) { long tetpil=avma; if (DEBUGMEM>1) err(warnmem,"plot"); x = gerepile(av2,tetpil,rcopy(x)); } ep->value = (void*)x; } avma=av2; diff=gsub(ybig,ysml); if (gcmp0(diff)) { ybig=gaddsg(1,ybig); diff=gun; } dyj = gdivsg((JSCR-1)*3+2,diff); jz = 3-gtolong(gmul(ysml,dyj)); av2=avma; z = PICTZERO(jz); jz = jz/3; for (i=1; i<=ISCR; i++) { scr[i][jz]=z; j=3+gtolong(gmul(gsub(y[i],ysml),dyj)); jnew = j/3; if (i > 1) { int i_up, i_lo, mid = (jpre+jnew)/2, up, lo; int domid = 0; /* If the gap is 1, leave it as it is. */ if (jpre < jnew - 2) { up = jnew - 1; i_up = i; lo = jpre + 1; i_lo = i - 1; domid = 1; } else if (jnew < jpre - 2) { up = jpre - 1; i_up = i - 1; lo = jnew + 1; i_lo = i; domid = 1; } if (domid) { while (lo <= mid) scr[i_lo][lo++] = ':'; while (up > mid) scr[i_up][up--] = ':'; } } scr[i][jnew] = PICT(j); avma=av2; jpre = jnew; } p1=cgetr(3); gaffect(ybig,p1); pariputc('\n'); pariputsf("%s ", dsprintf9(rtodbl(p1), buf)); for (i=1; i<=ISCR; i++) pariputc(scr[i][JSCR]); pariputc('\n'); for (j=(JSCR-1); j>=2; j--) { pariputs(" "); for (i=1; i<=ISCR; i++) pariputc(scr[i][j]); pariputc('\n'); } p1=cgetr(3); gaffect(ysml,p1); pariputsf("%s ", dsprintf9(rtodbl(p1), buf)); for (i=1; i<=ISCR; i++) pariputc(scr[i][1]); pariputc('\n'); p1=cgetr(3); gaffect(a,p1); p2=cgetr(3); gaffect(b,p2); pariputsf("%10s%-9.7g%*.7g\n"," ",rtodbl(p1),ISCR-9,rtodbl(p2)); pop_val(ep); avma=av; } /********************************************************************/ /** **/ /** RECTPLOT FUNCTIONS **/ /** **/ /********************************************************************/ void init_graph() { int n; rectgraph = (PariRect**) gpmalloc(sizeof(PariRect*)*NUMRECT); for (n=0; nhead = e->tail = NULL; e->sizex = e->sizey = 0; current_color[n] = DEFAULT_COLOR; rectgraph[n] = e; } } void free_graph() { int i; for (i=0; i MAXDTOL) err(affer2); * return (long)t; * } */ #define DTOL(t) ((long)(t)) static void rectmove0(long ne, double x, double y, long relative) { PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj1P)); if (relative) { RXcursor(e) += x; RYcursor(e) += y; } else { RXcursor(e) = x; RYcursor(e) = y; } RoNext(z) = 0; RoType(z) = ROt_MV; RoMVx(z) = DTOL(RXcursor(e) * RXscale(e) + RXshift(e)); RoMVy(z) = DTOL(RYcursor(e) * RYscale(e) + RYshift(e)); if (!RHead(e)) RHead(e)=RTail(e)=z; else { RoNext(RTail(e))=z; RTail(e)=z; } } void rectmove(long ne, GEN x, GEN y) /* code = 0 */ { rectmove0(ne,gtodouble(x),gtodouble(y),0); } void rectrmove(long ne, GEN x, GEN y) /* code = 0 */ { rectmove0(ne,gtodouble(x),gtodouble(y),1); } void rectpoint0(long ne, double x, double y,long relative) /* code = 1 */ { PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj1P)); if (relative) { RXcursor(e) += x; RYcursor(e) += y; } else { RXcursor(e) = x; RYcursor(e) = y; } RoNext(z)=0; RoPTx(z) = DTOL(RXcursor(e)*RXscale(e) + RXshift(e)); RoPTy(z) = DTOL(RYcursor(e)*RYscale(e) + RYshift(e)); RoType(z) = ((RoPTx(z)<0)||(RoPTy(z)<0)||(RoPTx(z)>RXsize(e)) ||(RoPTy(z)>RYsize(e))) ? ROt_MV : ROt_PT; if (!RHead(e)) RHead(e)=RTail(e)=z; else { RoNext(RTail(e))=z; RTail(e)=z; } RoCol(z)=current_color[ne]; } void rectpoint(long ne, GEN x, GEN y) /* code = 1 */ { rectpoint0(ne,gtodouble(x),gtodouble(y),0); } void rectrpoint(long ne, GEN x, GEN y) /* code = 1 */ { rectpoint0(ne,gtodouble(x),gtodouble(y),1); } void rectcolor(long ne, long color) { check_rect(ne); if (!GOODCOLOR(color)) err(talker,"This is not a valid color"); current_color[ne]=color; } void rectline0(long ne, double gx2, double gy2, long relative) /* code = 2 */ { long dx,dy,dxy,xmin,xmax,ymin,ymax,x1,y1,x2,y2; PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P)); x1 = DTOL(RXcursor(e)*RXscale(e) + RXshift(e)); y1 = DTOL(RYcursor(e)*RYscale(e) + RYshift(e)); if (relative) { RXcursor(e)+=gx2; RYcursor(e)+=gy2; } else { RXcursor(e)=gx2; RYcursor(e)=gy2; } x2 = DTOL(RXcursor(e)*RXscale(e) + RXshift(e)); y2 = DTOL(RYcursor(e)*RYscale(e) + RYshift(e)); xmin = max(min(x1,x2),0); xmax = min(max(x1,x2),RXsize(e)); ymin = max(min(y1,y2),0); ymax = min(max(y1,y2),RYsize(e)); dxy = x1*y2 - y1*x2; dx = x2-x1; dy = y2-y1; if (dy) { if (dx*dy<0) { xmin = max(xmin,(dxy+RYsize(e)*dx)/dy); xmax=min(xmax,dxy/dy); } else { xmin=max(xmin,dxy/dy); xmax=min(xmax,(dxy+RYsize(e)*dx)/dy); } } if (dx) { if (dx*dy<0) { ymin=max(ymin,(RXsize(e)*dy-dxy)/dx); ymax=min(ymax,-dxy/dx); } else { ymin=max(ymin,-dxy/dx); ymax=min(ymax,(RXsize(e)*dy-dxy)/dx); } } RoNext(z)=0; RoLNx1(z) = xmin; RoLNx2(z) = xmax; if (dx*dy<0) { RoLNy1(z) = ymax; RoLNy2(z) = ymin; } else { RoLNy1(z) = ymin; RoLNy2(z) = ymax; } RoType(z) = ((xmin>xmax)||(ymin>ymax)) ? ROt_MV : ROt_LN; if (!RHead(e)) RHead(e)=RTail(e)=z; else { RoNext(RTail(e))=z; RTail(e)=z; } RoCol(z)=current_color[ne]; } void rectline(long ne, GEN gx2, GEN gy2) /* code = 2 */ { rectline0(ne, gtodouble(gx2), gtodouble(gy2),0); } void rectrline(long ne, GEN gx2, GEN gy2) /* code = 2 */ { rectline0(ne, gtodouble(gx2), gtodouble(gy2),1); } void rectbox0(long ne, double gx2, double gy2, long relative) { long x1,y1,x2,y2,xmin,ymin,xmax,ymax; double xx,yy; PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P)); x1 = DTOL(RXcursor(e)*RXscale(e) + RXshift(e)); y1 = DTOL(RYcursor(e)*RYscale(e) + RYshift(e)); if (relative) { xx = RXcursor(e)+gx2; yy = RYcursor(e)+gy2; } else { xx = gx2; yy = gy2; } x2=DTOL(xx*RXscale(e) + RXshift(e)); y2=DTOL(yy*RYscale(e) + RYshift(e)); xmin = max(min(x1,x2),0); xmax = min(max(x1,x2),RXsize(e)); ymin = max(min(y1,y2),0); ymax = min(max(y1,y2),RYsize(e)); RoNext(z)=0; RoType(z) = ROt_BX; RoBXx1(z) = xmin; RoBXy1(z) = ymin; RoBXx2(z) = xmax; RoBXy2(z) = ymax; if (!RHead(e)) RHead(e)=RTail(e)=z; else { RoNext(RTail(e))=z; RTail(e)=z; } RoCol(z)=current_color[ne]; } void rectbox(long ne, GEN gx2, GEN gy2) /* code = 3 */ { rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 0); } void rectrbox(long ne, GEN gx2, GEN gy2) /* code = 3 */ { rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 1); } void killrect(long ne) { RectObj *p1,*p2; PariRect *e = check_rect_init(ne); current_color[ne]=DEFAULT_COLOR; p1=RHead(e); RHead(e) = RTail(e) = NULL; RXsize(e) = RYsize(e) = 0; RXcursor(e) = RYcursor(e) = 0; RXscale(e) = RYscale(e) = 1; RXshift(e) = RYshift(e) = 0; while (p1) { if (RoType(p1)==ROt_MP || RoType(p1)==ROt_ML) { free(RoMPxs(p1)); free(RoMPys(p1)); } if (RoType(p1)==ROt_ST) free(RoSTs(p1)); p2=RoNext(p1); free(p1); p1=p2; } } void rectpoints0(long ne, double *listx, double *listy, long lx) /* code = 4 */ { long *ptx,*pty,x,y,i,cp=0; PariRect *e = check_rect_init(ne); RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjMP)); ptx=(long*) gpmalloc(lx*sizeof(long)); pty=(long*) gpmalloc(lx*sizeof(long)); for (i=0; i=0)&&(y>=0)&&(x<=RXsize(e))&&(y<=RYsize(e))) { ptx[cp]=x; pty[cp]=y; cp++; } } RoNext(z)=0; RoType(z) = ROt_MP; RoMPcnt(z) = cp; RoMPxs(z) = ptx; RoMPys(z) = pty; if (!RHead(e)) RHead(e)=RTail(e)=z; else { RoNext(RTail(e))=z; RTail(e)=z; } RoCol(z)=current_color[ne]; } void rectpoints(long ne, GEN listx, GEN listy) /* code = 4 */ { long i,lx, tx=typ(listx), ty=typ(listy); double *px,*py; if (!is_matvec_t(tx) || !is_matvec_t(ty)) { rectpoint(ne, listx, listy); return; } if (tx == t_MAT || ty == t_MAT) err(ploter4); lx=lg(listx); if (lg(listy)!=lx) err(ploter5); lx--; if (!lx) return; px = (double*) gpmalloc(lx*sizeof(double)); py = (double*) gpmalloc(lx*sizeof(double)); for (i=0; i xmax && x2 > xmax)) return 0; if (fabs(x1 - x2) < fabs(y1 - y2)) { /* Exchange x and y */ xy_exch = 1; t = xmin, xmin = ymin, ymin = t; t = xmax, xmax = ymax, ymax = t; t = x1, x1 = y1, y1 = t; t = x2, x2 = y2, y2 = t; } /* Build y as a function of x */ xi = x1, yi = y1; sl = ( (x1==x2) ? 0 : (y2 - yi)/(x2 - xi) ); xmn = x1, xmx = x2; if (x1 > x2) { x1_is_xmn = 0; xmn = x2, xmx = x1; } else x1_is_xmn = 1; if (xmn < xmin) { xmn = xmin; rc |= (x1_is_xmn ? CLIPLINE_CLIP_1 : CLIPLINE_CLIP_2); } if (xmx > xmax) { xmx = xmax; rc |= (x1_is_xmn ? CLIPLINE_CLIP_2 : CLIPLINE_CLIP_1); } if (xmn > xmx) return 0; ymn = yi + (xmn - xi)*sl; ymx = yi + (xmx - xi)*sl; if (sl < 0) t = ymn, ymn = ymx, ymx = t; if (ymn > ymax || ymx < ymin) return 0; if (rc & CLIPLINE_CLIP_1) x1 = (x1_is_xmn ? xmn : xmx); if (rc & CLIPLINE_CLIP_2) x2 = (x1_is_xmn ? xmx : xmn); /* Now we know there is an intersection, need to move x1 and x2 */ x1_is_ymn = ((sl >= 0) == (x1 < x2)); if (ymn < ymin) { double x = (ymin - yi)/sl + xi; /* slope != 0 ! */ if (x1_is_ymn) x1 = x, rc |= CLIPLINE_CLIP_1; else x2 = x, rc |= CLIPLINE_CLIP_2; } if (ymx > ymax) { double x = (ymax - yi)/sl + xi; /* slope != 0 ! */ if (x1_is_ymn) x2 = x, rc |= CLIPLINE_CLIP_2; else x1 = x, rc |= CLIPLINE_CLIP_1; } if (rc & CLIPLINE_CLIP_1) y1 = yi + (x1 - xi)*sl; if (rc & CLIPLINE_CLIP_2) y2 = yi + (x2 - xi)*sl; if (xy_exch) /* Exchange x and y */ *x1p = y1, *x2p = y2, *y1p = x1, *y2p = x2; else *x1p = x1, *x2p = x2, *y1p = y1, *y2p = y2; return rc; } void rectclip(long rect) { PariRect *s = check_rect_init(rect); RectObj *p1 = RHead(s); RectObj **prevp = &RHead(s); RectObj *next; double xmin = 0; double xmax = RXsize(s); double ymin = 0; double ymax = RYsize(s); while (p1) { int did_clip = 0; next = RoNext(p1); switch(RoType(p1)) { case ROt_PT: if ( RoPTx(p1) < xmin || RoPTx(p1) > xmax || RoPTy(p1) < ymin || RoPTy(p1) > ymax) { remove: *prevp = next; free(p1); break; } goto do_next; case ROt_BX: if (RoLNx1(p1) < xmin) RoLNx1(p1) = xmin, did_clip = 1; if (RoLNx2(p1) < xmin) RoLNx2(p1) = xmin, did_clip = 1; if (RoLNy1(p1) < ymin) RoLNy1(p1) = ymin, did_clip = 1; if (RoLNy2(p1) < ymin) RoLNy2(p1) = ymin, did_clip = 1; if (RoLNx1(p1) > xmax) RoLNx1(p1) = xmax, did_clip = 1; if (RoLNx2(p1) > xmax) RoLNx2(p1) = xmax, did_clip = 1; if (RoLNy1(p1) > ymax) RoLNy1(p1) = ymax, did_clip = 1; if (RoLNy2(p1) > ymax) RoLNy2(p1) = ymax, did_clip = 1; /* Remove zero-size clipped boxes */ if ( did_clip && RoLNx1(p1) == RoLNx2(p1) && RoLNy1(p1) == RoLNy2(p1) ) goto remove; goto do_next; case ROt_LN: if (!clipline(xmin, xmax, ymin, ymax, &RoLNx1(p1), &RoLNy1(p1), &RoLNx2(p1), &RoLNy2(p1))) goto remove; goto do_next; case ROt_MP: { int c = RoMPcnt(p1); int f = 0, t = 0; while (f < c) { if ( RoMPxs(p1)[f] >= xmin && RoMPxs(p1)[f] <= xmax && RoMPys(p1)[f] >= ymin && RoMPys(p1)[f] <= ymax) { if (t != f) { RoMPxs(p1)[t] = RoMPxs(p1)[f]; RoMPys(p1)[t] = RoMPys(p1)[f]; } t++; } f++; } if (t == 0) goto remove; RoMPcnt(p1) = t; goto do_next; } case ROt_ML: { /* Hard case. Here we need to break a multiline into several pieces if some part is clipped. */ int c = RoMPcnt(p1) - 1; int f = 0, t = 0, had_lines = 0, had_hole = 0, rc; long ox = RoMLxs(p1)[0], oy = RoMLys(p1)[0], oxn, oyn; while (f < c) { /* Endpoint of this segment is the startpoint of the next one, so we need to preserve it if it is clipped. */ oxn = RoMLxs(p1)[f + 1], oyn = RoMLys(p1)[f + 1]; rc = clipline(xmin, xmax, ymin, ymax, /* &RoMLxs(p1)[f], &RoMLys(p1)[f], */ &ox, &oy, &RoMLxs(p1)[f+1], &RoMLys(p1)[f+1]); RoMLxs(p1)[f] = ox; RoMLys(p1)[f] = oy; ox = oxn; oy = oyn; if (!rc) { if (had_lines) had_hole = 1; f++; continue; } if ( !had_lines || (!(rc & CLIPLINE_CLIP_1) && !had_hole) ) { /* Continuous */ had_lines = 1; if (t != f) { if (t == 0) { RoMPxs(p1)[t] = RoMPxs(p1)[f]; RoMPys(p1)[t] = RoMPys(p1)[f]; } RoMPxs(p1)[t+1] = RoMPxs(p1)[f+1]; RoMPys(p1)[t+1] = RoMPys(p1)[f+1]; } t++; f++; if ( rc & CLIPLINE_CLIP_2) had_hole = 1, RoMLcnt(p1) = t + 1; continue; } /* Is not continuous, automatically p1 is not free()ed. */ RoMLcnt(p1) = t + 1; if ( rc & CLIPLINE_CLIP_2) { /* Needs separate entry */ RectObj *n = (RectObj*) gpmalloc(sizeof(RectObj2P)); RoType(n) = ROt_LN; RoCol(n) = RoCol(p1); RoLNx1(n) = RoMLxs(p1)[f]; RoLNy1(n) = RoMLys(p1)[f]; RoLNx2(n) = RoMLxs(p1)[f+1]; RoLNy2(n) = RoMLys(p1)[f+1]; RoNext(n) = next; RoNext(p1) = n; /* Restore the unclipped value: */ RoMLxs(p1)[f + 1] = oxn; RoMLys(p1)[f + 1] = oyn; f++; prevp = &RoNext(n); } if (f + 1 < c) { /* Are other lines */ RectObj *n = (RectObj*) gpmalloc(sizeof(RectObjMP)); RoType(n) = ROt_ML; RoCol(n) = RoCol(p1); RoMLcnt(n) = c - f; RoMLxs(n) = (long*) gpmalloc(sizeof(long)*(c - f)); RoMLys(n) = (long*) gpmalloc(sizeof(long)*(c - f)); memcpy(RoMPxs(n),RoMPxs(p1) + f, sizeof(long)*(c - f)); memcpy(RoMPys(n),RoMPys(p1) + f, sizeof(long)*(c - f)); RoMPxs(n)[0] = oxn; RoMPys(n)[0] = oyn; RoNext(n) = next; RoNext(p1) = n; next = n; } goto do_next; } if (t == 0) goto remove; goto do_next; } #if 0 case ROt_ST: next = (RectObj*) gpmalloc(sizeof(RectObjMP)); memcpy(next,p1,sizeof(RectObjMP)); RoSTs(next) = (char*) gpmalloc(RoSTl(p1)+1); memcpy(RoSTs(next),RoSTs(p1),RoSTl(p1)+1); RoSTx(next) += xoff; RoSTy(next) += yoff; RoNext(tail) = next; tail = next; break; #endif default: { do_next: prevp = &RoNext(p1); break; } } p1 = next; } } /********************************************************************/ /** **/ /** HI-RES PLOT **/ /** **/ /********************************************************************/ static void Appendx(dblPointList *f, dblPointList *l,double x) { (l->d)[l->nb++]=x; if (x < f->xsml) f->xsml=x; else if (x > f->xbig) f->xbig=x; } static void Appendy(dblPointList *f, dblPointList *l,double y) { (l->d)[l->nb++]=y; if (y < f->ysml) f->ysml=y; else if (y > f->ybig) f->ybig=y; } /* Convert data from GEN to double before we call rectplothrawin */ static dblPointList* gtodblList(GEN data, long flags) { dblPointList *l; double xsml,xbig,ysml,ybig; long tx=typ(data), ty, nl=lg(data)-1, lx1,lx; register long i,j,u,v; long param=(flags & PLOT_PARAMETRIC); GEN x,y; if (! is_vec_t(tx)) err(talker,"not a vector in gtodblList"); if (!nl) return NULL; lx1=lg(data[1]); /* Allocate memory, then convert coord. to double */ l=(dblPointList*) gpmalloc(nl*sizeof(dblPointList)); for (i=0; ixbig) xbig=l[i].d[j]; if (l[u].d[j]ybig) ybig=l[u].d[j]; } } } else { l[0].nb=nl-1; for (j=0; jxbig) xbig=l[0].d[j]; } for (i=1; i<=l[0].nb; i++) { for (j=0; jybig) ybig=l[i].d[j]; } } } l[0].xsml=xsml; l[0].xbig=xbig; l[0].ysml=ysml; l[0].ybig=ybig; return l; } static void single_recursion(dblPointList *pl,char *ch,entree *ep,GEN xleft,GEN yleft, GEN xright,GEN yright,long depth) { GEN xx,yy; long av=avma; double dy=pl[0].ybig - pl[0].ysml; if (depth==RECUR_MAXDEPTH) return; yy=cgetr(3); xx=gmul2n(gadd(xleft,xright),-1); ep->value = (void*) xx; gaffect(READ_EXPR(ch), yy); if (dy) { if (fabs(rtodbl(yleft)+rtodbl(yright)-2*rtodbl(yy))/dy < RECUR_PREC) return; } single_recursion(pl,ch,ep, xleft,yleft, xx,yy, depth+1); Appendx(&pl[0],&pl[0],rtodbl(xx)); Appendy(&pl[0],&pl[1],rtodbl(yy)); single_recursion(pl,ch,ep, xx,yy, xright,yright, depth+1); avma=av; } static void param_recursion(dblPointList *pl,char *ch,entree *ep, GEN tleft,GEN xleft, GEN yleft, GEN tright,GEN xright,GEN yright, long depth) { GEN tt,xx,yy, p1; long av=avma; double dy=pl[0].ybig - pl[0].ysml; double dx=pl[0].xbig - pl[0].xsml; if (depth==PARAMR_MAXDEPTH) return; xx=cgetr(3); yy=cgetr(3); tt=gmul2n(gadd(tleft,tright),-1); ep->value = (void*)tt; p1=READ_EXPR(ch); gaffect((GEN)p1[1],xx); gaffect((GEN)p1[2],yy); if (dx && dy) { if (fabs(rtodbl(xleft)+rtodbl(xright)-2*rtodbl(xx))/dx < RECUR_PREC && fabs(rtodbl(yleft)+rtodbl(yright)-2*rtodbl(yy))/dy < RECUR_PREC) return; } param_recursion(pl,ch,ep, tleft,xleft,yleft, tt,xx,yy, depth+1); Appendx(&pl[0],&pl[0],rtodbl(xx)); Appendy(&pl[0],&pl[1],rtodbl(yy)); param_recursion(pl,ch,ep, tt,xx,yy, tright,xright,yright, depth+1); avma=av; } /* * Pure graphing. If testpoints is 0, it is set to the default. * Returns a dblPointList of (absolute) coordinates. */ static dblPointList * rectplothin(entree *ep, GEN a, GEN b, char *ch, long prec, ulong flags, long testpoints) { long single_c; long param=flags & PLOT_PARAMETRIC; long recur=flags & PLOT_RECURSIVE; GEN p1,dx,x,xleft,xright,yleft,yright,tleft,tright; dblPointList *pl; long tx,av = avma,av2,i,j,sig,nc,nl,nbpoints; double xsml,xbig,ysml,ybig,fx,fy; if (!testpoints) { if (recur) testpoints = RECUR_NUMPOINTS; else testpoints = param? PARAM_NUMPOINTS : PLOTH_NUMPOINTS; } if (recur) nbpoints = testpoints << (param? PARAMR_MAXDEPTH : RECUR_MAXDEPTH); else nbpoints = testpoints; sig=gcmp(b,a); if (!sig) return 0; if (sig<0) { x=a; a=b; b=x; } dx=gdivgs(gsub(b,a),testpoints-1); x = cgetr(prec); gaffect(a,x); push_val(ep, x); av2=avma; p1=READ_EXPR(ch); tx=typ(p1); if (!is_matvec_t(tx)) { xsml = gtodouble(a); xbig = gtodouble(b); ysml = ybig = gtodouble(p1); nc=1; nl=2; /* nc = nb of curves; nl = nb of coord. lists */ if (param) err(warner,"flag PLOT_PARAMETRIC ignored"); single_c=1; param=0; } else { if (tx != t_VEC) err(talker,"not a row vector in ploth"); nl=lg(p1)-1; if (!nl) { avma=av; return 0; } single_c=0; if (param) nc=nl/2; else { nc=nl; nl++; } if (recur && nc > 1) err(talker,"multi-curves cannot be plot recursively"); if (param) { xbig=xsml=gtodouble((GEN)p1[1]); ybig=ysml=gtodouble((GEN)p1[2]); for (i=3; i<=nl; i++) { fx=gtodouble((GEN)p1[i]); i++; fy=gtodouble((GEN)p1[i]); if (xsml>fx) xsml=fx; else if (xbigfy) ysml=fy; else if (ybigvalue = (void*)tleft; p1=READ_EXPR(ch); gaffect((GEN)p1[1],xleft); gaffect((GEN)p1[2],yleft); for (i=0; ivalue = (void*)tright; p1 = READ_EXPR(ch); if (lg(p1) != 3) err(talker,"inconsistent data in rectplothin"); gaffect((GEN)p1[1],xright); gaffect((GEN)p1[2],yright); Appendx(&pl[0],&pl[0],rtodbl(xleft)); Appendy(&pl[0],&pl[1],rtodbl(yleft)); param_recursion(pl,ch,ep, tleft,xleft,yleft, tright,xright,yright, 0); avma=av2; } Appendx(&pl[0],&pl[0],rtodbl(xright)); Appendy(&pl[0],&pl[1],rtodbl(yright)); } else /* single_c */ { av2=avma; gaffect(a,xleft); ep->value = (void*) xleft; gaffect(READ_EXPR(ch),yleft); for (i=0; ivalue = (void*) xright; gaffect(READ_EXPR(ch),yright); Appendx(&pl[0],&pl[0],rtodbl(xleft)); Appendy(&pl[0],&pl[1],rtodbl(yleft)); single_recursion(pl,ch,ep,xleft,yleft,xright,yright,0); avma=av2; gaffect(xright,xleft); gaffect(yright,yleft); } Appendx(&pl[0],&pl[0],rtodbl(xright)); Appendy(&pl[0],&pl[1],rtodbl(yright)); } } else /* non-recursive plot */ { if (single_c) for (i=0; i0) contains the number of points in the list * data[i].d (hopefully, data[2i].nb=data[2i+1].nb when i>0...) * * + If flags contain PLOT_PARAMETRIC, the array length should be * even, and successive pairs (data[2i].d, data[2i+1].d) represent * curves to plot. * * + If there is no such flag, the first element is an array with * x-coordinates and the following ones contain y-coordinates. * * Additional flags: PLOT_NO_AXE_X, PLOT_NO_AXE_Y, PLOT_NO_FRAME. */ static GEN rectplothrawin(long stringrect, long drawrect, dblPointList *data, long flags, PARI_plot *WW) { PARI_plot W; GEN res; dblPointList y,x; double xsml,xbig,ysml,ybig,tmp; long ltype=0, ltop=avma; long is,js,i,lm,rm,tm,bm,nc,nbpoints, w[2], wx[2], wy[2]; w[0]=stringrect; w[1]=drawrect; if (!data) return cgetg(1,t_VEC); x=data[0]; nc=x.nb; xsml=x.xsml; xbig=x.xbig; ysml=x.ysml; ybig=x.ybig; if (xbig-xsml < 1.e-9) { tmp=fabs(xsml)/10; if (!tmp) tmp=0.1; xbig+=tmp; xsml-=tmp; } if (ybig-ysml < 1.e-9) { tmp=fabs(ysml)/10; if (!tmp) tmp=0.1; ybig+=tmp; ysml-=tmp; } if (WW) /* no rectwindow has been supplied ==> ps or screen output */ { W = *WW; lm = W.fwidth*10; /* left margin */ rm = W.hunit-1; /* right margin */ tm = W.vunit-1; /* top margin */ bm = W.vunit+W.fheight-1; /* bottom margin */ is = W.width - (lm+rm); js = W.height - (tm+bm); wx[0]=wy[0]=0; wx[1]=lm; wy[1]=tm; /* * Window size (W.width x W.height) is given in pixels, and * correct pixels are 0..w_width-1. * * On the other hand, rect functions work with windows whose pixel * range is [0,width]. */ initrect(stringrect, W.width-1, W.height-1); if (drawrect != stringrect) initrect(drawrect, is-1, js-1); } if (!(flags & PLOT_NO_RESCALE)) rectscale0(drawrect, xsml, xbig, ysml, ybig); if (!(flags & PLOT_NO_FRAME)) { rectlinetype(drawrect, -2); /* Frame. */ current_color[drawrect]=BLACK; rectmove0(drawrect,xsml,ysml,0); rectbox0(drawrect,xbig,ybig,0); } if (!(flags & PLOT_NO_AXE_Y) && (xsml<=0 && xbig >=0)) { rectlinetype(drawrect, -1); /* Axes. */ current_color[drawrect]=BLUE; rectmove0(drawrect,0.0,ysml,0); rectline0(drawrect,0.0,ybig,0); } if (!(flags & PLOT_NO_AXE_X) && (ysml<=0 && ybig >=0)) { rectlinetype(drawrect, -1); /* Axes. */ current_color[drawrect]=BLUE; rectmove0(drawrect,xsml,0.0,0); rectline0(drawrect,xbig,0.0,0); } if (flags & PLOT_PARAMETRIC) i=0; else i=1; current_color[drawrect]=RED; for (; ltype < nc; ) { if (nc>1) { if (ltype & 1) current_color[drawrect]=RED; else current_color[drawrect]=SIENNA; } if (flags & PLOT_PARAMETRIC) x=data[i++]; y=data[i++]; nbpoints=y.nb; if ((flags & PLOT_POINTS_LINES) || (flags & PLOT_POINTS)) { rectlinetype(drawrect, rectpoint_itype + ltype); /* Graphs. */ rectpointtype(drawrect, rectpoint_itype + ltype); /* Graphs. */ rectpoints0(drawrect,x.d,y.d,nbpoints); } if ((flags & PLOT_POINTS_LINES) || !(flags & PLOT_POINTS)) { if (flags & PLOT_SPLINES) { /* rectsplines will call us back with ltype == 0 */ int old = rectline_itype; rectline_itype = rectline_itype + ltype; rectsplines(drawrect,x.d,y.d,nbpoints,flags); rectline_itype = old; } else { rectlinetype(drawrect, rectline_itype + ltype); /* Graphs. */ rectlines0(drawrect,x.d,y.d,nbpoints,0); } } ltype++; /* Graphs. */ } for (i--; i>=0; i--) free(data[i].d); free(data); if (WW) { char c1[16],c2[16],c3[16],c4[16]; sprintf(c1,"%9.3f",ybig); sprintf(c2,"%9.3f",ysml); sprintf(c3,"%9.3f",xsml); sprintf(c4,"%9.3f",xbig); rectlinetype(stringrect,-2); /* Frame */ current_color[stringrect]=BLACK; put_string(stringrect, 0, W.fheight - 1, c1); put_string(stringrect, 0, W.height - (bm+ 2 * W.vunit), c2); put_string(stringrect, lm-(W.fwidth*2), W.height-bm+W.fheight-1, c3); put_string(stringrect, W.width-(W.fwidth*10), W.height-bm+W.fheight-1,c4); if (flags & PLOT_POSTSCRIPT) postdraw0(w,wx,wy,2); else rectdraw0(w,wx,wy,2, 0); killrect(drawrect); if (stringrect != drawrect) killrect(stringrect); } avma=ltop; res = cgetg(5,t_VEC); res[1]=(long)dbltor(xsml); res[2]=(long)dbltor(xbig); res[3]=(long)dbltor(ysml); res[4]=(long)dbltor(ybig); return res; } /*************************************************************************/ /* */ /* HI-RES FUNCTIONS */ /* */ /*************************************************************************/ GEN rectploth(long drawrect,entree *ep,GEN a,GEN b,char *ch, long prec,ulong flags,long testpoints) { dblPointList *pl=rectplothin(ep, a,b, ch, prec, flags,testpoints); return rectplothrawin(0,drawrect, pl, flags,NULL); } GEN rectplothraw(long drawrect, GEN data, long flags) { dblPointList *pl=gtodblList(data,flags); return rectplothrawin(0,drawrect,pl,flags,NULL); } static PARI_plot* init_output(long flags) { if (flags & PLOT_POSTSCRIPT) { PARI_get_psplot(); return &pari_psplot; } else { PARI_get_plot(0); return &pari_plot; } } static GEN ploth0(long stringrect,long drawrect,entree *ep,GEN a,GEN b,char *ch, long prec,ulong flags,long testpoints) { PARI_plot *output = init_output(flags); dblPointList *pl=rectplothin(ep, a,b, ch, prec, flags,testpoints); return rectplothrawin(stringrect,drawrect, pl, flags, output); } static GEN plothraw0(long stringrect, long drawrect, GEN listx, GEN listy, long flags) { PARI_plot *output = init_output(flags); long data[] = {evaltyp(t_VEC) | m_evallg(3), 0, 0}; dblPointList *pl; data[1] = (long) listx; data[2] = (long) listy; pl=gtodblList(data,PLOT_PARAMETRIC); if (!pl) return cgetg(1,t_VEC); return rectplothrawin(stringrect,drawrect,pl,flags | PLOT_PARAMETRIC,output); } GEN plothraw(GEN listx, GEN listy, long flags) { flags=(flags)? 0: PLOT_POINTS; return plothraw0(STRINGRECT, DRAWRECT, listx, listy, flags); } GEN ploth(entree *ep, GEN a, GEN b, char *ch, long prec,long flags,long numpoints) { return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,flags,numpoints); } GEN ploth2(entree *ep, GEN a, GEN b, char *ch, long prec) { return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,PLOT_PARAMETRIC,0); } GEN plothmult(entree *ep, GEN a, GEN b, char *ch, long prec) { return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,0,0); } GEN postplothraw(GEN listx, GEN listy, long flags) { flags=(flags)? 0: PLOT_POINTS; return plothraw0(STRINGRECT, DRAWRECT, listx, listy, flags|PLOT_POSTSCRIPT); } GEN postploth(entree *ep, GEN a, GEN b, char *ch, long prec,long flags, long numpoints) { return ploth0(STRINGRECT,DRAWRECT,ep,a,b,ch,prec,flags|PLOT_POSTSCRIPT, numpoints); } GEN postploth2(entree *ep, GEN a, GEN b, char *ch, long prec, long numpoints) { return ploth0(STRINGRECT,DRAWRECT,ep,a,b,ch,prec, PLOT_PARAMETRIC|PLOT_POSTSCRIPT,numpoints); } GEN plothsizes() { GEN vect = cgetg(1+6,t_VEC); int i; PARI_get_plot(0); for (i=1; i<7; i++) vect[i]=lgeti(3); affsi(w_width,(GEN)vect[1]); affsi(w_height,(GEN)vect[2]); affsi(h_unit, (GEN)vect[3]); affsi(v_unit, (GEN)vect[4]); affsi(f_width,(GEN)vect[5]); affsi(f_height,(GEN)vect[6]); return vect; } /*************************************************************************/ /* */ /* POSTSCRIPT OUTPUT */ /* */ /*************************************************************************/ typedef struct spoint { int x,y; } SPoint; typedef struct ssegment { int x1,y1,x2,y2; } SSegment; typedef struct srectangle { int x,y,width,height; } SRectangle; static void ps_point(FILE *psfile, int x, int y); static void ps_line(FILE *psfile, int x1, int y1, int x2, int y2); static void ps_rect(FILE *psfile, int x1, int y1, int x2, int y2); static void ps_string(FILE *psfile, int x, int y, char *c); #undef ISCR #undef JSCR #define ISCR 1120 /* 1400 en haute resolution */ #define JSCR 800 /* 1120 en haute resolution */ static void PARI_get_psplot() { pari_psplot.height = JSCR - 60; pari_psplot.width = ISCR - 40; pari_psplot.fheight = 15; pari_psplot.fwidth = 6; pari_psplot.hunit = 5; pari_psplot.vunit = 5; } static void gendraw(GEN list,long ps) { long i,n,ne,*w,*x,*y; GEN x0,y0,win; if (typ(list) != t_VEC) err(talker,"not a vector in rectdraw"); n = lg(list)-1; if (n%3) err(talker,"incorrect number of components in rectdraw"); n = n/3; if (!n) return; w = (long*)gpmalloc(n*sizeof(long)); x = (long*)gpmalloc(n*sizeof(long)); y = (long*)gpmalloc(n*sizeof(long)); for (i=0; i