Ilya Zakharevich on Mon, 11 Oct 1999 19:16:08 -0400 (EDT)


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[PATCH 2.0.17] Device-independent graphic


This patch:

  a) Adds optional arguments to plotcopy/plotdraw/plothsizes/plotinit/psdraw;
     These optional arguments allow one to make plots
     device-independently (sizes are given not in pixels, but in
     fractions of the screen size);

  b) The optional argument to psdraw() to inform it that the plotting
     is prepared device-independently. so psdraw() better rescale it
     to the expected size.  Without this psdraw is almost useless with
     gnuplot output (since it assumes some undocumented hardwired
     sizes for plottings).

  c) Improves string-positioning logic to allow for vertical alignment
     and insertion of gaps between the point and the string.  Now to
     annotate the rectangle of the plotting the same way as ploth()
     does you put strings *at the corners* specifying the gap
     positions: 
		right-top-align    +horizontal    gap for 7,
		right-bottom-align +hor-gap +vert-gap for 5,
		left-top-align	   +vertical      gap for -11
		right-top-align	   +vertical      gap for 567

          ___________________________
       	7 |			    |
       	  |			    |
       	  |			    |
       	  |			    |
        5 ___________________________
	  -11			  567

     Summary: you delegate the complexity of putting strings in a
     device-independent way to PARI via optional arguments to
     plotstring().

  d) What else?  Some minor cleanups. like some functions using
     rectangles without first checking that they are initialized.

Enjoy,
Ilya

P.S.  I tested ps/gnuplot/X11 output.  Could not compile sunview here:

../src/graph/plotsun.c:9: suntool/sunview.h: No such file or directory
../src/graph/plotsun.c:10: suntool/canvas.h: No such file or directory
../src/graph/plotsun.c:11: suntool/textsw.h: No such file or directory
../src/graph/plotsun.c:12: suntool/panel.h: No such file or directory

I was find()ing 5 levels deep, but did not find any suntool (Solaris
7, cc: WorkShop Compilers 5.0 98/12/15 C 5.0).

--- ./src/gp/highlvl.c.orig	Mon Oct 11 18:19:15 1999
+++ ./src/gp/highlvl.c	Mon Oct 11 18:19:33 1999
@@ -180,14 +180,14 @@ entree functions_highlevel[]={
 {"plotbox",35,(void*)rectbox,10,"vLGG"},
 {"plotclip",99,(void*)rectclip,10,"vL"},
 {"plotcolor",19,(void*)rectcolor,10,"vLL"},
-{"plotcopy",99,(void*)rectcopy,10,"vLLLL"},
+{"plotcopy",99,(void*)rectcopy_gen,10,"vLLGGD0,L,"},
 {"plotcursor",11,(void*)rectcursor,10,"L"},
-{"plotdraw",99,(void*)rectdraw,10,"vG"},
+{"plotdraw",99,(void*)rectdraw_flag,10,"vGD0,L,"},
 {"plotfile",16,(void*)plot_outfile_set,10,"ls"},
 {"ploth",99,(void*)ploth,10,"V=GGIpD0,L,D0,L,"},
 {"plothraw",25,(void*)plothraw,10,"GGD0,L,"},
-{"plothsizes",0,(void*)plothsizes,10,""},
-{"plotinit",34,(void*)initrect,10,"vLLL"},
+{"plothsizes",0,(void*)plothsizes_flag,10,"D0,L,"},
+{"plotinit",34,(void*)initrect_gen,10,"vLD0,G,D0,G,D0,L,"},
 {"plotkill",99,(void*)killrect,10,"vL"},
 {"plotlines",99,(void*)rectlines,10,"vLGGD0,L,"},
 {"plotlinetype",19,(void*)rectlinetype,10,"vLL"},
@@ -204,7 +204,7 @@ entree functions_highlevel[]={
 {"plotscale",59,(void*)rectscale,10,"vLGGGG"},
 {"plotstring",57,(void*)rectstring3,10,"vLsD0,L,"},
 {"plotterm",16,(void*)term_set,10,"ls"},
-{"psdraw",99,(void*)postdraw,10,"vG"},
+{"psdraw",99,(void*)postdraw_flag,10,"vGD0,L,"},
 {"psploth",99,(void*)postploth,10,"V=GGIpD0,L,D0,L,"},
 {"psplothraw",25,(void*)postplothraw,10,"GGD0,L,"},
 {"type",99,(void*)type0,11,"GD\"\",r,"},
@@ -220,14 +220,14 @@ char *helpmessages_highlevel[]={
   "plotbox(w,x2,y2): if the cursor is at position (x1,y1), draw a box with diagonal (x1,y1) and (x2,y2) in rectwindow w (cursor does not move)",
   "plotclip(w): clip the contents of the rectwindow to the bounding box (except strings)",
   "plotcolor(w,c): in rectwindow w, set default color to c. Possible values for c are 1=black, 2=blue, 3=sienna, 4=red, 5=cornsilk, 6=grey, 7=gainsborough",
-  "plotcopy(sourcew,destw,dx,dy): copy the contents of rectwindow sourcew to rectwindow destw with offset (dx,dy)",
+  "plotcopy(sourcew,destw,dx,dy,{flag=0}): copy the contents of rectwindow sourcew to rectwindow destw with offset (dx,dy). If flag's bit 1 is set, dx and dy express fractions of the size of the current output device, otherwise dx and dy are in pixels.  dx and dy are relative positions of northwest corners if other bits of flag vanish, otherwise of: 2: southwest, 4: southeast, 6: northeast corners",
   "plotcursor(w): current position of cursor in rectwindow w",
-  "plotdraw(list): draw vector of rectwindows list at indicated x,y positions; list is a vector w1,x1,y1,w2,x2,y2,etc. . ",
+  "plotdraw(list, {flag=0}): draw vector of rectwindows list at indicated x,y positions; list is a vector w1,x1,y1,w2,x2,y2,etc. . If flag!=0, x1, y1 etc. express fractions of the size of the current output device",
   "plotfile(filename): set the output file for plotting output. \"-\" redirects to the same place as PARI output",
   "ploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean : 1 parametric plot, 2 recursive plot, 8 omit x-axis, 16 omit y-axis, 32 omit frame, 64 do not join points, 128 plot both lines and points, 256 use cubic splines. n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box",
   "plothraw(listx,listy,{flag=0}): plot in high resolution points whose x (resp. y) coordinates are in listx (resp. listy). If flag is non zero, join points",
-  "plothsizes(): returns array of 6 elements: terminal width and height, sizes for ticks in horizontal and vertical directions (in pixels), width and height of characters",
-  "plotinit(w,x,y): initialize rectwindow w to size x,y",
+  "plothsizes({flag=0}): returns array of 6 elements: terminal width and height, sizes for ticks in horizontal and vertical directions, width and height of characters.  If flag=0, sizes of ticks and characters are in pixels, otherwise are fractions of the screen size",
+  "plotinit(w,{x=0},{y=0},{flag=0}): initialize rectwindow w to size x,y. If flag!=0, x and y express fractions of the size of the current output device. x=0 or y=0 means use the full size of the device",
   "plotkill(w): erase the rectwindow w",
   "plotlines(w,listx,listy,{flag=0}): draws an open polygon in rectwindow w where listx and listy contain the x (resp. y) coordinates of the vertices. If listx and listy are both single values (i.e not vectors), draw the corresponding line (and move cursor). If (optional) flag is non-zero, close the polygon",
   "plotlinetype(w,type): change the type of following lines in rectwindow w. type -2 corresponds to frames, -1 to axes, larger values may correspond to something else. w=-1 changes highlevel plotting",
@@ -242,9 +242,9 @@ char *helpmessages_highlevel[]={
   "plotrmove(w,dx,dy): move cursor to position (dx,dy) relative to the present position in the rectwindow w",
   "plotrpoint(w,dx,dy): draw a point (and move cursor) at position dx,dy relative to present position of the cursor in rectwindow w",
   "plotscale(w,x1,x2,y1,y2): scale the coordinates in rectwindow w so that x goes from x1 to x2 and y from y1 to y2 (y2<y1 is allowed)",
-  "plotstring(w,x,{flags=0}): draw in rectwindow w the string corresponding to x, justify left if flag is 0, right if it is 2, center if 1",
-  "plotterm(\"termname\"): set terminal to plot in high resolution to. Ignored by some drivers. In gnuplot driver possible terminals are the same as in gnuplot. Positive value means success",
-  "psdraw(list): same as plotdraw, except that the output is a postscript program in psfile (pari.ps by default)",
+  "plotstring(w,x,{flags=0}): draw in rectwindow w the string corresponding to x.  Bits 1 and 2 of flag regulate horizontal alignment: left if 0, right if 2, center if 1.  Bits 4 and 8 regulate vertical alignment: bottom if 0, top if 8, v-center if 4. Can insert additional gap between point and string: horizontal if bit 16 is set, vertical if bit 32 is set",
+  "plotterm(\"termname\"): set terminal to plot in high resolution to. Ignored by some drivers. In gnuplot driver possible terminals are the same as in gnuplot, terminal options can be put after the terminal name and space; terminal size can be put immediately after the name, as in \"gif=300,200\". If term is \"?\", lists possible values. Positive return value means success",
+  "psdraw(list, {flag=0}): same as plotdraw, except that the output is a postscript program in psfile (pari.ps by default), and flag!=0 scales the plot from size of the current output device to the standard postscript plotting size",
   "psploth(X=a,b,expr,{flags=0},{n=0}): same as ploth, except that the output is a postscript program in psfile (pari.ps by default)",
   "psplothraw(listx,listy,{flag=0}): same as plothraw, except that the output is a postscript program in psfile (pari.ps by default)",
   "type(x,{t}): if t is not present, output the type of the GEN x. Else make a copy of x with type t. Use with extreme care, usually with t = t_FRACN or t = t_RFRACN). Try \\t for a list of types",
--- ./src/graph/plotgnuplot.c.orig	Mon Oct 11 18:19:15 1999
+++ ./src/graph/plotgnuplot.c	Mon Oct 11 18:19:34 1999
@@ -25,7 +25,7 @@ void
 rectdraw0(long *w, long *x, long *y, long lw, long do_free)
 {
   long *ptx,*pty;
-  long i,j,x0,y0;
+  long i,j,x0,y0, hjust, vjust, hgap, vgap, hgapsize, vgapsize;
   long good, seen_graph = 0;
   int point_type = -1, line_type = 0;
   PariRect *e;
@@ -34,6 +34,9 @@ rectdraw0(long *w, long *x, long *y, lon
 
   PARI_get_plot(0);
 
+  hgapsize = h_unit;  vgapsize = v_unit;
+  if (hgapsize == 1)
+    hgapsize = 2;	/* Vertical direction is subjectively different! */
   /* Find the info about the *actual* x and y-coords of the
      rectangles.  Use the first rectangle with has_graph attribute. */
 
@@ -133,14 +136,23 @@ rectdraw0(long *w, long *x, long *y, lon
 	  }
 	  break;
 	case ROt_ST:
-	  if (strdir != RoSTdir(p1)) {
-	      shift = (RoSTdir(p1) == RoSTdirLEFT ? 0 :
-		       (RoSTdir(p1) == RoSTdirRIGHT ? 2 : 1));
-
+	  hjust = RoSTdir(p1) & RoSTdirHPOS_mask;
+	  vjust = RoSTdir(p1) & RoSTdirVPOS_mask;
+	  hgap = RoSTdir(p1) & RoSTdirHGAP;
+	  if (hgap)
+	    hgap = (hjust == RoSTdirLEFT) ? hgapsize : -hgapsize;
+	  vgap = RoSTdir(p1) & RoSTdirVGAP;
+	  if (vgap)
+	    vgap = (vjust == RoSTdirBOTTOM) ? vgapsize : -vgapsize;
+	  if (vjust != RoSTdirVCENTER)
+	    vgap += ((vjust == RoSTdirTOP) ? -1 : 1) * (f_height - 1)/2;
+	  if (strdir != hjust) {
+	      shift = (hjust == RoSTdirLEFT ? 0 :
+		       (hjust == RoSTdirRIGHT ? 2 : 1));
 	      can_justify = justify_text(shift); /* 1 for LEFT */
 	      strdir = RoSTdir(p1);
 	  }
-	  xstart = RoSTx(p1) + x0 
+	  xstart = RoSTx(p1) + x0 + hgap
 	      - (can_justify ? 0 
 		 : ((RoSTl(p1) * pari_plot.fwidth - 1) * shift / 2));
 	  xend = xstart + (can_justify ? 0 : RoSTl(p1) * pari_plot.fwidth - 1);
@@ -148,7 +160,7 @@ rectdraw0(long *w, long *x, long *y, lon
 	      || RoSTy(p1) + y0 < 0 || RoSTy(p1) + y0 >= w_height) {
 	  } else {
 	      put_text(xstart,
-		       w_height - 1 - RoSTy(p1) - y0 + (f_height - 1)/2,
+		       w_height - 1 - RoSTy(p1) - y0 + vgap,
 		       RoSTs(p1));
 	  }
 	  break;
--- ./src/graph/plotport.c.orig	Mon Oct 11 18:19:15 1999
+++ ./src/graph/plotport.c	Mon Oct 11 18:19:34 1999
@@ -10,6 +10,7 @@
 void push_val(entree *ep, GEN a);
 void pop_val(entree *ep);
 void postdraw0(long *w, long *x, long *y, long lw);
+void postdraw00(long *w, long *x, long *y, long lw, long scale);
 void rectdraw0(long *w, long *x, long *y, long lw, long do_free);
 static void PARI_get_psplot();
 
@@ -213,6 +214,31 @@ check_rect_init(long ne)
 }
 
 void
+initrect_gen(long ne, GEN x, GEN y, long flag)
+{
+  long xi, yi;
+  if (flag) {
+    double xd = gtodouble(x), yd = gtodouble(y);
+
+    PARI_get_plot(0);
+    xi = w_width - 1;  yi = w_height - 1;
+    if (xd)
+      xi = xd*xi + 0.5;
+    if (yd)
+      yi = yd*yi + 0.5;
+  } else {
+    xi = itos(x);  yi = itos(y);
+    if (!xi || !yi)
+      PARI_get_plot(0);
+    if (!xi)
+      xi = w_width - 1;
+    if (!yi)
+      yi = w_height - 1;
+  }
+  initrect(ne, xi, yi);
+}
+
+void
 initrect(long ne, long x, long y)
 {
   PariRect *e;
@@ -647,6 +673,40 @@ rectlinetype(long ne, long type)
 }
 
 void
+rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag)
+{
+  long xi, yi;
+  if (flag & RECT_CP_RELATIVE) {
+    double xd = gtodouble(xoff), yd = gtodouble(yoff);
+
+    PARI_get_plot(0);
+    xi = w_width - 1;  yi = w_height - 1;
+    xi = xd*xi + 0.5;
+    yi = yd*yi + 0.5;
+  } else {
+    xi = itos(xoff);  yi = itos(yoff);
+  }
+  if (flag & ~RECT_CP_RELATIVE) {
+    PariRect *s = check_rect_init(source), *d = check_rect_init(dest);
+
+    switch (flag & ~RECT_CP_RELATIVE) {
+      case RECT_CP_NW:
+	break;
+      case RECT_CP_SW:
+	yi = RYsize(d) - RYsize(s) - yi;
+	break;
+      case RECT_CP_SE:
+	yi = RYsize(d) - RYsize(s) - yi;
+	/* FALL THROUGH */
+      case RECT_CP_NE:
+	xi = RXsize(d) - RXsize(s) - xi;
+	break;
+    }
+  }
+  rectcopy(source, dest, xi, yi);
+}
+
+void
 rectcopy(long source, long dest, long xoff, long yoff)
 {
   PariRect *s = check_rect_init(source), *d = check_rect_init(dest);
@@ -1509,12 +1569,14 @@ rectplothrawin(long stringrect, long dra
 
     rectlinetype(stringrect,-2); /* Frame */
     current_color[stringrect]=BLACK;
-    put_string(stringrect, lm - gap, W.fheight - 1, c1, RoSTdirRIGHT);
-    put_string(stringrect, lm - gap, W.height - (bm+ 2 * W.vunit), c2, RoSTdirRIGHT);
-    put_string(stringrect, lm, W.height - bm + W.fheight - 1,
-	       c3, RoSTdirLEFT);
-    put_string(stringrect, W.width - rm - 1, W.height - bm + W.fheight - 1,
-	       c4, RoSTdirRIGHT);
+    put_string( stringrect, lm, 0, c1,
+		RoSTdirRIGHT | RoSTdirHGAP | RoSTdirTOP);
+    put_string(stringrect, lm, W.height - bm, c2,
+		RoSTdirRIGHT | RoSTdirHGAP | RoSTdirVGAP);
+    put_string(stringrect, lm, W.height - bm, c3,
+		RoSTdirLEFT | RoSTdirTOP);
+    put_string(stringrect, W.width - rm - 1, W.height - bm, c4,
+		RoSTdirRIGHT | RoSTdirTOP);
 
     if (flags & PLOT_POSTSCRIPT)
       postdraw0(w,wx,wy,2);
@@ -1635,14 +1697,28 @@ postploth2(entree *ep, GEN a, GEN b, cha
 GEN
 plothsizes()
 {
+  return plothsizes_flag(0);
+}
+
+GEN
+plothsizes_flag(long flag)
+{
   GEN vect = cgetg(1+6,t_VEC);
   int i;
 
   PARI_get_plot(0);
-  for (i=1; i<7; i++) vect[i]=lgeti(3);
+  for (i=1; i<=2; 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]);
+  if (flag) {
+    vect[3] = (long)dbltor(h_unit*1.0/w_width);
+    vect[4] = (long)dbltor(v_unit*1.0/w_height);
+    vect[5] = (long)dbltor(f_width*1.0/w_width);
+    vect[6] = (long)dbltor(f_height*1.0/w_height);
+  } else {
+    for (; i <= 6; i++) vect[i]=lgeti(3);
+    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;
 }	
 
@@ -1681,7 +1757,7 @@ PARI_get_psplot()
 }
 
 static void
-gendraw(GEN list,long ps)
+gendraw(GEN list, long ps, long flag)
 {
   long i,n,ne,*w,*x,*y;
   GEN x0,y0,win;
@@ -1693,23 +1769,42 @@ gendraw(GEN list,long ps)
   w = (long*)gpmalloc(n*sizeof(long));
   x = (long*)gpmalloc(n*sizeof(long));
   y = (long*)gpmalloc(n*sizeof(long));
+  if (flag)
+    PARI_get_plot(0);
   for (i=0; i<n; i++)
   {
     win=(GEN)list[3*i+1]; x0=(GEN)list[3*i+2]; y0=(GEN)list[3*i+3];
-    if (typ(win)!=t_INT || typ(x0)!=t_INT || typ(y0)!= t_INT)
+    if (typ(win)!=t_INT || (!flag && (typ(x0)!=t_INT || typ(y0)!= t_INT)))
       err(talker, "not an integer type in rectdraw");
+    if (flag) {
+      double xd = gtodouble(x0), yd = gtodouble(y0);
+      long xi, yi;
+
+      xi = w_width - 1;  yi = w_height - 1;
+      xi = xd*xi + 0.5;
+      yi = yd*yi + 0.5;
+      x[i] = xi; y[i] = yi;
+    } else {
+      x[i]=itos(x0); y[i]=itos(y0);
+    }
     ne=itos(win); check_rect(ne);
-    x[i]=itos(x0); y[i]=itos(y0); w[i]=ne;
+    w[i]=ne;
   }
-  if (ps) postdraw0(w,x,y,n); else rectdraw0(w,x,y,n, 1);
+  if (ps) postdraw00(w,x,y,n,flag); else rectdraw0(w,x,y,n, 1);
   free(x); free(y); free(w);
 }
 
 void
-postdraw(GEN list) { gendraw(list,1); }
+postdraw(GEN list) { gendraw(list, 1, 0); }
+
+void
+rectdraw(GEN list) { gendraw(list, 0, 0); }
 
 void
-rectdraw(GEN list) { gendraw(list,0); }
+postdraw_flag(GEN list, long flag) { gendraw(list, 1, flag); }
+
+void
+rectdraw_flag(GEN list, long flag) { gendraw(list, 0, flag); }
 
 static char*
 zmalloc(size_t x)
@@ -1720,6 +1815,12 @@ zmalloc(size_t x)
 void
 postdraw0(long *w, long *x, long *y, long lw)
 {
+  postdraw00(w, x, y, lw, 0);
+}
+
+void
+postdraw00(long *w, long *x, long *y, long lw, long scale)
+{
   long *ptx,*pty,*numpoints,*numtexts,*xtexts,*ytexts,*dirtexts;
   RectObj *p1;
   PariRect *e;
@@ -1727,11 +1828,25 @@ postdraw0(long *w, long *x, long *y, lon
   long a,b,c,d,nd[ROt_MAX+1];
   char **texts;
   FILE *psfile;
+  double xscale = 0.65, yscale = 0.65;
+  long fontsize = 16, xtick = 5, ytick = 5;
 
   SPoint *points, **lines, *SLine;
   SSegment *seg;
   SRectangle *rect, SRec;
 
+  if (scale) {
+    double termxsize, termysize, postxsize, postysize;
+
+    PARI_get_psplot(); 
+    postxsize = pari_psplot.width;
+    postysize = pari_psplot.height;
+    PARI_get_plot(0);
+    xscale *= pari_psplot.width  * 1.0/w_width;
+    fontsize = fontsize/(pari_psplot.width  * 1.0/w_width);
+    yscale *= pari_psplot.height * 1.0/w_height;
+    xtick = h_unit;  ytick = v_unit;
+  }
   psfile = fopen(current_psfile, "a");
   if (!psfile)
     err(openfiler,"postscript",current_psfile);
@@ -1740,7 +1855,7 @@ postdraw0(long *w, long *x, long *y, lon
 
   for (i=0; i<lw; i++)
   {
-    e=rectgraph[w[i]]; p1=RHead(e);
+    e = check_rect_init(w[i]); p1=RHead(e);
     while (p1)
     {
       if (RoType(p1) != ROt_MP) nd[RoType(p1)]++;
@@ -1814,8 +1929,18 @@ postdraw0(long *w, long *x, long *y, lon
     }
   }
   /* Definitions taken from post terminal of Gnuplot. */
-  fprintf(psfile,"%%!\n50 50 translate\n/Times-Roman findfont 16 scalefont setfont\n0.65 0.65 scale\n");
+  fprintf(psfile,"%%!\n50 50 translate\n/Times-Roman findfont %ld scalefont setfont\n%g %g scale\n", fontsize, yscale,xscale);
   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");
+  fprintf(psfile,"/Xgap %ld def\n/Ygap %ld def\n", xtick, ytick);
+  fprintf(psfile,"/Bbox { gsave newpath 0 0 moveto true charpath pathbbox grestore } def\n");
+  fprintf(psfile,"/Height { Bbox 4 1 roll pop pop pop } def\n");
+  fprintf(psfile,"/TopAt { 3 -1 roll dup 4 1 roll Height 3 -1 roll add exch } def\n");
+  fprintf(psfile,"/VCenter { 3 -1 roll dup 4 1 roll Height 2 div 3 -1 roll add exch } def\n");
+  fprintf(psfile,"/Tgap { exch Ygap add exch } def\n");
+  fprintf(psfile,"/Bgap { exch Ygap sub exch } def\n");
+  fprintf(psfile,"/Lgap { Xgap add } def\n");
+  fprintf(psfile,"/Rgap { Xgap sub } def\n");
+
   for (i=0; i<nd[ROt_PT]; i++)
     ps_point(psfile,points[i].x,points[i].y);
   for (i=0; i<nd[ROt_LN]; i++)
@@ -1875,7 +2000,16 @@ ps_string(FILE *psfile, int x, int y, ch
 	}
     } else
 	fprintf(psfile,"(%s", s);
-    fprintf(psfile,") %d %d %sshow\n",
-	    y, x, 
-	    (dir == RoSTdirLEFT ? "L" : (dir == RoSTdirRIGHT ? "R" : "C")));
+    fprintf(psfile,") %d %d %s%s%s%sshow\n",
+	    y, x,
+	    ((dir & RoSTdirVGAP)
+	     ? ((dir & RoSTdirVPOS_mask) == RoSTdirTOP ? "Tgap " : "Bgap ")
+	     : ""),
+	    ((dir & RoSTdirHGAP)
+	     ? ((dir & RoSTdirHPOS_mask) == RoSTdirRIGHT ? "Rgap " : "Lgap ")
+	     : ""),
+	    ((dir & RoSTdirVPOS_mask) == RoSTdirBOTTOM ? ""
+	     : (dir & RoSTdirVPOS_mask) == RoSTdirTOP ? "TopAt " : "VCenter "),
+	    ((dir & RoSTdirHPOS_mask) == RoSTdirLEFT ? "L"
+	     : ((dir & RoSTdirHPOS_mask) == RoSTdirRIGHT ? "R" : "C")));
 }
--- ./src/graph/plotsun.c.orig	Mon Oct 11 18:19:15 1999
+++ ./src/graph/plotsun.c	Mon Oct 11 18:28:28 1999
@@ -23,7 +23,7 @@ rectdraw0(long *w, long *x, long *y, lon
 {
   long *ptx,*pty,*numpoints,*numtexts,*xtexts,*ytexts;
   long n,i,j,x0,y0,shift;
-  long a,b,c,d,ne;
+  long a,b,c,d,ne, hjust, vjust, hgap, vgap, hgapsize, vgapsize;
   long rcnt[ROt_MAX+1];
   char **texts;
   PariRect *e;
@@ -42,6 +42,7 @@ rectdraw0(long *w, long *x, long *y, lon
   /* child process goes on */
   freeall();  /* PARI stack isn't needed anymore, keep rectgraph */
   PARI_get_plot(1);
+  hgapsize = h_unit;  vgapsize = v_unit;
 
   rcnt[ROt_MV]=rcnt[ROt_PT]=rcnt[ROt_LN]=0;
   rcnt[ROt_BX]=rcnt[ROt_MP]=rcnt[ROt_ML]=0;
@@ -110,12 +111,22 @@ rectdraw0(long *w, long *x, long *y, lon
 	  }
 	  rcnt[ROt_ML]++;break;
         case ROt_ST:
+	  hjust = RoSTdir(p1) & RoSTdirHPOS_mask;
+	  vjust = RoSTdir(p1) & RoSTdirVPOS_mask;
+	  hgap = RoSTdir(p1) & RoSTdirHGAP;
+	  if (hgap)
+	    hgap = (hjust == RoSTdirLEFT) ? hgapsize : -hgapsize;
+	  vgap = RoSTdir(p1) & RoSTdirVGAP;
+	  if (vgap)
+	    vgap = (vjust == RoSTdirBOTTOM) ? 2*vgapsize : -2*vgapsize;
+	  if (vjust != RoSTdirBOTTOM)
+	    vgap -= ((vjust == RoSTdirTOP) ? 2 : 1)*(f_height - 1);
 	  texts[rcnt[ROt_ST]]=RoSTs(p1); numtexts[rcnt[ROt_ST]]=RoSTl(p1);
-	  shift = (RoSTdir(p1) == RoSTdirLEFT ? 0 :
-		   (RoSTdir(p1) == RoSTdirRIGHT ? 2 : 1));
-	  xtexts[rcnt[ROt_ST]]=RoSTx(p1)+x0
+	  shift = (hjust == RoSTdirLEFT ? 0 :
+		   (hjust == RoSTdirRIGHT ? 2 : 1));
+	  xtexts[rcnt[ROt_ST]]=RoSTx(p1)+x0+hgap
 	      - (strlen(RoSTs(p1)) * pari_plot.fwidth * shift)/2;
-	  ytexts[rcnt[ROt_ST]]=RoSTy(p1)+y0;
+	  ytexts[rcnt[ROt_ST]]=RoSTy(p1)+y0-vgap/2;
 	  rcnt[ROt_ST]++;break;
 	default: break;
       }
--- ./src/graph/plotX.c.orig	Mon Oct 11 18:19:15 1999
+++ ./src/graph/plotX.c	Mon Oct 11 18:25:19 1999
@@ -121,7 +121,7 @@ rectdraw0(long *w, long *x, long *y, lon
   long *xtexts[MAX_COLORS],*ytexts[MAX_COLORS];
   long rcolcnt[MAX_COLORS][ROt_MAX];
   long col,i,j,x0,y0,a,b,oldwidth,oldheight,force;
-  long rcnt[ROt_MAX+1];
+  long rcnt[ROt_MAX+1], hjust, vjust, hgap, vgap, hgapsize, vgapsize;
   char **texts[MAX_COLORS];
   PariRect *e;
   RectObj *p1;
@@ -148,6 +148,7 @@ rectdraw0(long *w, long *x, long *y, lon
   display = XOpenDisplay(NULL);
   font_info = XLoadQueryFont(display, "9x15");
   if (!font_info) exiterr("cannot open 9x15 font");
+  hgapsize = h_unit;  vgapsize = v_unit;
 
   XSetErrorHandler(Xerror);
   XSetIOErrorHandler(IOerror);
@@ -316,15 +317,25 @@ rectdraw0(long *w, long *x, long *y, lon
 		}
 		c[ROt_ML]++;break;
 	      case ROt_ST:
+		hjust = RoSTdir(p1) & RoSTdirHPOS_mask;
+		vjust = RoSTdir(p1) & RoSTdirVPOS_mask;
+		hgap = RoSTdir(p1) & RoSTdirHGAP;
+		if (hgap)
+		  hgap = (hjust == RoSTdirLEFT) ? hgapsize : -hgapsize;
+		vgap = RoSTdir(p1) & RoSTdirVGAP;
+		if (vgap)
+		  vgap = (vjust == RoSTdirBOTTOM) ? 2*vgapsize : -2*vgapsize;
+		if (vjust != RoSTdirBOTTOM)
+		  vgap -= ((vjust == RoSTdirTOP) ? 2 : 1)*(f_height - 1);
 		texts[col][c[ROt_ST]]=RoSTs(p1);
 		numtexts[col][c[ROt_ST]]=RoSTl(p1);
-		shift = (RoSTdir(p1) == RoSTdirLEFT ? 0 :
-			 (RoSTdir(p1) == RoSTdirRIGHT ? 2 : 1));
+		shift = (hjust == RoSTdirLEFT ? 0 :
+			 (hjust == RoSTdirRIGHT ? 2 : 1));
 		xtexts[col][c[ROt_ST]] 
-		    = (long)(( RoSTx(p1) + x0 
+		    = (long)(( RoSTx(p1) + x0 + hgap
 			       - (strlen(RoSTs(p1)) * pari_plot.fwidth
 				  * shift)/2)*xs);
-		ytexts[col][c[ROt_ST]]= (long)((RoSTy(p1)+y0)*ys);
+		ytexts[col][c[ROt_ST]]= (long)((RoSTy(p1)+y0-vgap/2)*ys);
 		c[ROt_ST]++;break;
 	      default: break;
 	    }
--- ./src/graph/rect.h.orig	Mon Oct 11 18:19:16 1999
+++ ./src/graph/rect.h	Mon Oct 11 18:19:34 1999
@@ -173,9 +173,19 @@ typedef struct RectObjPS {
 #define RoSTy(rop) (RoST(rop)->y)
 #define RoSTdir(rop) (RoST(rop)->dir)
 
-#define RoSTdirLEFT	0
-#define RoSTdirCENTER	1
-#define RoSTdirRIGHT	2
+#define RoSTdirLEFT	  0x00
+#define RoSTdirCENTER	  0x01
+#define RoSTdirRIGHT	  0x02
+#define RoSTdirHPOS_mask  0x03
+
+#define RoSTdirBOTTOM	  0x00
+#define RoSTdirVCENTER	  0x04
+#define RoSTdirTOP	  0x08
+#define RoSTdirVPOS_mask  0x0c
+
+#define RoSTdirHGAP	  0x10
+#define RoSTdirVGAP	  0x20
+
 
 #define RoPTTpen(rop) (RoPTT(rop)->pen)
 #define RoLNTpen(rop) (RoLNT(rop)->pen)
@@ -197,6 +207,12 @@ typedef struct RectObjPS {
 
 #define PLOT_POSTSCRIPT   0x80000
 
+#define RECT_CP_RELATIVE  0x1
+#define RECT_CP_NW        0x0
+#define RECT_CP_SW        0x2
+#define RECT_CP_SE        0x4
+#define RECT_CP_NE        0x6
+
 extern PariRect  **rectgraph;
 extern long  rectpoint_itype;
 extern long  rectline_itype;
@@ -204,6 +220,7 @@ extern long  rectline_itype;
 /* plotport.c */
 
 void    initrect(long ne, long x, long y);
+void    initrect_gen(long ne, GEN x, GEN y, long flag);
 void    killrect(long ne);
 void    plot(entree *ep, GEN a, GEN b, char *ch, long prec);
 GEN     ploth(entree *ep, GEN a, GEN b, char *ch, long prec, long flag, long numpoints);
@@ -211,15 +228,19 @@ GEN     ploth2(entree *ep, GEN a, GEN b,
 GEN     plothmult(entree *ep, GEN a, GEN b, char *ch, long prec);
 GEN     plothraw(GEN listx, GEN listy, long flag);
 GEN     plothsizes();
+GEN     plothsizes_flag(long flag);
 void    postdraw(GEN list);
+void    postdraw_flag(GEN list, long flag);
 GEN     postploth(entree *ep,GEN a,GEN b,char *ch,long prec,long flag,long numpoints);
 GEN     postploth2(entree *ep,GEN a,GEN b,char *ch,long prec,long numpoints);
 GEN     postplothraw(GEN listx, GEN listy, long flag);
 void    rectbox(long ne, GEN gx2, GEN gy2);
 void    rectcolor(long ne, long color);
 void    rectcopy(long source, long dest, long xoff, long yoff);
+void    rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag);
 GEN     rectcursor(long ne);
 void    rectdraw(GEN list);
+void    rectdraw_flag(GEN list, long flag);
 void    rectline(long ne, GEN gx2, GEN gy2);
 void    rectlines(long ne, GEN listx, GEN listy, long flag);
 void    rectlinetype(long ne, long t);