Ilya Zakharevich on Wed, 29 Sep 1999 23:40:02 -0400 (EDT)


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

Plot strings justified


I was writing small docs to show how use graphing commands of PARI,
and found that a lot of time is spent in justifying strings on the
screen.  On the other hand, PARI can do it itself.

So I added this ability to PARI.

Enjoy,
Ilya

P.S.  I also updated comments, and fixed a bug in ps output: the
      strings to output should have contained balanced parens only.

      Tested with ps, gnuplot and X output only (not on sun).

--- ./src/gp/highlvl.c~	Thu Sep 16 09:50:18 1999
+++ ./src/gp/highlvl.c	Wed Sep 29 22:56:32 1999
@@ -202,7 +202,7 @@ entree functions_highlevel[]={
 {"plotrmove",35,(void*)rectrmove,10,"vLGG"},
 {"plotrpoint",35,(void*)rectrpoint,10,"vLGG"},
 {"plotscale",59,(void*)rectscale,10,"vLGGGG"},
-{"plotstring",57,(void*)rectstring,10,"vLs"},
+{"plotstring",57,(void*)rectstring3,10,"vLsD0,L,"},
 {"plotterm",16,(void*)term_set,10,"ls"},
 {"psdraw",99,(void*)postdraw,10,"vG"},
 {"psploth",99,(void*)postploth,10,"V=GGIpD0,L,D0,L,"},
@@ -242,7 +242,7 @@ 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): draw in rectwindow w the string corresponding to x",
+  "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)",
   "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)",
--- ./src/graph/plotport.c~	Thu Sep 16 09:50:20 1999
+++ ./src/graph/plotport.c	Wed Sep 29 23:34:26 1999
@@ -297,19 +297,19 @@ rectmove0(long ne, double x, double y, l
 }
 
 void
-rectmove(long ne, GEN x, GEN y) /* code = 0 */
+rectmove(long ne, GEN x, GEN y)
 {
   rectmove0(ne,gtodouble(x),gtodouble(y),0);
 }
 
 void
-rectrmove(long ne, GEN x, GEN y) /* code = 0 */
+rectrmove(long ne, GEN x, GEN y)
 {
   rectmove0(ne,gtodouble(x),gtodouble(y),1);
 }
 
 void
-rectpoint0(long ne, double x, double y,long relative) /* code = 1 */
+rectpoint0(long ne, double x, double y,long relative) /* code = ROt_MV/ROt_PT */
 {
   PariRect *e = check_rect_init(ne);
   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj1P));
@@ -329,13 +329,13 @@ rectpoint0(long ne, double x, double y,l
 }
 
 void
-rectpoint(long ne, GEN x, GEN y) /* code = 1 */
+rectpoint(long ne, GEN x, GEN y)
 {
   rectpoint0(ne,gtodouble(x),gtodouble(y),0);
 }
 
 void
-rectrpoint(long ne, GEN x, GEN y) /* code = 1 */
+rectrpoint(long ne, GEN x, GEN y)
 {
   rectpoint0(ne,gtodouble(x),gtodouble(y),1);
 }
@@ -349,7 +349,7 @@ rectcolor(long ne, long color)
 }
 
 void
-rectline0(long ne, double gx2, double gy2, long relative) /* code = 2 */
+rectline0(long ne, double gx2, double gy2, long relative) /* code = ROt_MV/ROt_LN */
 {
   long dx,dy,dxy,xmin,xmax,ymin,ymax,x1,y1,x2,y2;
   PariRect *e = check_rect_init(ne);
@@ -391,13 +391,13 @@ rectline0(long ne, double gx2, double gy
 }
 
 void
-rectline(long ne, GEN gx2, GEN gy2) /* code = 2 */
+rectline(long ne, GEN gx2, GEN gy2)
 {
   rectline0(ne, gtodouble(gx2), gtodouble(gy2),0);
 }
 
 void
-rectrline(long ne, GEN gx2, GEN gy2) /* code = 2 */
+rectrline(long ne, GEN gx2, GEN gy2)
 {
   rectline0(ne, gtodouble(gx2), gtodouble(gy2),1);
 }
@@ -430,13 +430,13 @@ rectbox0(long ne, double gx2, double gy2
 }
 
 void
-rectbox(long ne, GEN gx2, GEN gy2) /* code = 3 */
+rectbox(long ne, GEN gx2, GEN gy2)
 {
   rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 0);
 }
 
 void
-rectrbox(long ne, GEN gx2, GEN gy2) /* code = 3 */
+rectrbox(long ne, GEN gx2, GEN gy2)
 {
   rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 1);
 }
@@ -466,7 +466,7 @@ killrect(long ne)
 }
 
 void
-rectpoints0(long ne, double *listx, double *listy, long lx) /* code = 4 */
+rectpoints0(long ne, double *listx, double *listy, long lx) /* code = ROt_MP */
 {
   long *ptx,*pty,x,y,i,cp=0;
   PariRect *e = check_rect_init(ne);
@@ -491,7 +491,7 @@ rectpoints0(long ne, double *listx, doub
 }
 
 void
-rectpoints(long ne, GEN listx, GEN listy) /* code = 4 */
+rectpoints(long ne, GEN listx, GEN listy)
 {
   long i,lx, tx=typ(listx), ty=typ(listy);
   double *px,*py;
@@ -515,7 +515,7 @@ rectpoints(long ne, GEN listx, GEN listy
 }
 
 void
-rectlines0(long ne, double *x, double *y, long lx, long flag) /* code = 5 */
+rectlines0(long ne, double *x, double *y, long lx, long flag) /* code = ROt_ML */
 {
   long i,I,*ptx,*pty;
   PariRect *e = check_rect_init(ne);
@@ -542,7 +542,7 @@ rectlines0(long ne, double *x, double *y
 }
 
 void
-rectlines(long ne, GEN listx, GEN listy, long flag) /* code = 5 */
+rectlines(long ne, GEN listx, GEN listy, long flag)
 {
   long tx=typ(listx), ty=typ(listy), lx=lg(listx), i;
   double *x, *y;
@@ -566,14 +566,20 @@ rectlines(long ne, GEN listx, GEN listy,
 }
 
 static void
-put_string(long win, long x, long y, char *str)
+put_string(long win, long x, long y, char *str, long dir)
 {
-  rectmove0(win,(double)x,(double)y,0); rectstring(win,str);
+  rectmove0(win,(double)x,(double)y,0); rectstring3(win,str,dir);
+}
+
+void
+rectstring(long ne, char *str)
+{
+    rectstring3(ne,str,RoSTdirLEFT);
 }
 
 /* Allocate memory, then put string */
 void
-rectstring(long ne, char *str) /* code = 6 */
+rectstring3(long ne, char *str, long dir) /* code = ROt_ST */
 {
   PariRect *e = check_rect_init(ne);
   RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjST));
@@ -585,13 +591,14 @@ rectstring(long ne, char *str) /* code =
   RoSTl(z) = l; RoSTs(z) = s;
   RoSTx(z) = DTOL(RXscale(e)*RXcursor(e)+RXshift(e));
   RoSTy(z) = DTOL(RYscale(e)*RYcursor(e)+RYshift(e));
+  RoSTdir(z) = dir;
   if (!RHead(e)) RHead(e)=RTail(e)=z;
   else { RoNext(RTail(e))=z; RTail(e)=z; }
   RoCol(z)=current_color[ne];
 }
 
 void
-rectpointtype(long ne, long type) /* code = 0 */
+rectpointtype(long ne, long type) /* code = ROt_PTT */
 {
  if (ne == -1) {
      rectpoint_itype = type;
@@ -607,7 +614,7 @@ rectpointtype(long ne, long type) /* cod
 }
 
 void
-rectpointsize(long ne, GEN size) /* code = 0 */
+rectpointsize(long ne, GEN size) /* code = ROt_PTS */
 {
  if (ne == -1) {
      set_pointsize(gtodouble(size));	/* Immediate set */
@@ -678,7 +685,7 @@ rectcopy(long source, long dest, long xo
 	RoNext(tail) = next; tail = next;
 	break;
       case ROt_ST:
-	next = (RectObj*) gpmalloc(sizeof(RectObjMP));
+	next = (RectObj*) gpmalloc(sizeof(RectObjST));
 	memcpy(next,p1,sizeof(RectObjMP));
 	RoSTs(next) = (char*) gpmalloc(RoSTl(p1)+1);
 	memcpy(RoSTs(next),RoSTs(p1),RoSTl(p1)+1);
@@ -1493,16 +1500,19 @@ rectplothrawin(long stringrect, long dra
   if (WW)
   {
     char c1[16],c2[16],c3[16],c4[16];
+    int gap = rm + 2;
 
-    sprintf(c1,"%9.3f",ybig); sprintf(c2,"%9.3f",ysml);
-    sprintf(c3,"%9.3f",xsml); sprintf(c4,"%9.3f",xbig);
+    sprintf(c1,"%5.3f",ybig); sprintf(c2,"%5.3f",ysml);
+    sprintf(c3,"%5.3f",xsml); sprintf(c4,"%5.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);
+    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);
 
     if (flags & PLOT_POSTSCRIPT)
       postdraw0(w,wx,wy,2);
@@ -1650,7 +1660,7 @@ typedef struct 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);
+static void ps_string(FILE *psfile, int x, int y, char *c, long dir);
 
 #undef ISCR
 #undef JSCR
@@ -1708,7 +1718,7 @@ zmalloc(size_t x)
 void
 postdraw0(long *w, long *x, long *y, long lw)
 {
-  long *ptx,*pty,*numpoints,*numtexts,*xtexts,*ytexts;
+  long *ptx,*pty,*numpoints,*numtexts,*xtexts,*ytexts,*dirtexts;
   RectObj *p1;
   PariRect *e;
   long i,j,x0,y0;
@@ -1745,6 +1755,7 @@ postdraw0(long *w, long *x, long *y, lon
   numtexts=(long*) zmalloc(nd[ROt_ST]*sizeof(long));
   xtexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
   ytexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
+  dirtexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
   for (i=0; i<=ROt_MAX; i++) nd[i]=0;
 
   for (i=0; i<lw; i++)
@@ -1793,13 +1804,16 @@ postdraw0(long *w, long *x, long *y, lon
 	  numtexts[nd[ROt_ST]]=RoSTl(p1);
 	  xtexts[nd[ROt_ST]]=RoSTx(p1)+x0;
 	  ytexts[nd[ROt_ST]]=RoSTy(p1)+y0;
+	  dirtexts[nd[ROt_ST]]=RoSTdir(p1);
 	  nd[ROt_ST]++; break;
 	default: break;
       }
       p1=RoNext(p1);
     }
   }
+  /* 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,"/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");
   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++)
@@ -1819,7 +1833,7 @@ postdraw0(long *w, long *x, long *y, lon
     }
   }
   for (i=0; i<nd[ROt_ST]; i++)
-    ps_string(psfile,xtexts[i],ytexts[i],texts[i]);
+    ps_string(psfile,xtexts[i],ytexts[i],texts[i], dirtexts[i]);
   fprintf(psfile,"stroke showpage\n"); fclose(psfile);
 #define xfree(pointer) if (pointer) free(pointer)
   xfree(points); xfree(seg); xfree(rect); xfree(numpoints);
@@ -1847,7 +1861,19 @@ ps_rect(FILE *psfile, int x1, int y1, in
 }
 
 static void
-ps_string(FILE *psfile, int x, int y, char *c)
+ps_string(FILE *psfile, int x, int y, char *s, long dir)
 {
-  fprintf(psfile,"%d %d moveto 90 rotate\n(%s) show -90 rotate\n",y,x,c);
+    if (strpbrk(s, "(\\)")) {
+	fprintf(psfile,"(");
+	while (*s) {
+	    if ( *s=='(' || *s==')' || *s=='\\' )
+		fputc('\\', psfile);
+	    fputc(*s, psfile);
+	    s++;
+	}
+    } else
+	fprintf(psfile,"(%s", s);
+    fprintf(psfile,") %d %d %sshow\n",
+	    y, x, 
+	    (dir == RoSTdirLEFT ? "L" : (dir == RoSTdirRIGHT ? "R" : "C")));
 }
--- ./src/graph/plotgnuplot.c~	Thu Sep 16 09:50:20 1999
+++ ./src/graph/plotgnuplot.c	Wed Sep 29 23:30:41 1999
@@ -30,6 +30,7 @@ rectdraw0(long *w, long *x, long *y, lon
   int point_type = -1, line_type = 0;
   PariRect *e;
   RectObj *p1;
+  int strdir = RoSTdirLEFT, can_justify = 1, shift = 0, xstart, xend;
 
   PARI_get_plot(0);
 
@@ -100,12 +101,23 @@ rectdraw0(long *w, long *x, long *y, lon
 	  }
 	  break;
 	case ROt_ST:
-	  if (RoSTx(p1)+x0 < 0 || RoSTx(p1)+x0+RoSTl(p1)-1 >= w_width
+	  if (strdir != RoSTdir(p1)) {
+	      shift = (RoSTdir(p1) == RoSTdirLEFT ? 0 :
+		       (RoSTdir(p1) == RoSTdirRIGHT ? 2 : 1));
+
+	      can_justify = justify_text(shift); /* 1 for LEFT */
+	      strdir = RoSTdir(p1);
+	  }
+	  xstart = RoSTx(p1) + x0 
+	      - (can_justify ? 0 
+		 : ((RoSTl(p1) * pari_plot.fwidth - 1) * shift / 2));
+	  xend = xstart + (can_justify ? 0 : RoSTl(p1) * pari_plot.fwidth - 1);
+	  if (xstart < 0 || xend >= w_width
 	      || RoSTy(p1) + y0 < 0 || RoSTy(p1) + y0 >= w_height) {
 	  } else {
-	    put_text(RoSTx(p1)+x0,
-		     w_height - 1 - RoSTy(p1) - y0 + (f_height - 1)/2,
-		     RoSTs(p1));
+	      put_text(xstart,
+		       w_height - 1 - RoSTy(p1) - y0 + (f_height - 1)/2,
+		       RoSTs(p1));
 	  }
 	  break;
 	case ROt_PTT:
@@ -147,6 +159,7 @@ term_set(char *s)
   char *t, *size = NULL;
   double x, y;
 
+  setup_gpshim();
   if (*s == 0)
       s = pari_plot.name;
   t = s;
--- ./src/graph/plotX.c~	Thu Sep 16 09:50:19 1999
+++ ./src/graph/plotX.c	Wed Sep 29 22:44:23 1999
@@ -116,7 +116,7 @@ zmalloc(size_t x)
 void
 rectdraw0(long *w, long *x, long *y, long lw, long do_free)
 {
-  long *ptx,*pty,*c;
+  long *ptx,*pty,*c, shift;
   long *numpoints[MAX_COLORS],*numtexts[MAX_COLORS];
   long *xtexts[MAX_COLORS],*ytexts[MAX_COLORS];
   long rcolcnt[MAX_COLORS][ROt_MAX];
@@ -318,7 +318,12 @@ rectdraw0(long *w, long *x, long *y, lon
 	      case ROt_ST:
 		texts[col][c[ROt_ST]]=RoSTs(p1);
 		numtexts[col][c[ROt_ST]]=RoSTl(p1);
-		xtexts[col][c[ROt_ST]]= (long)((RoSTx(p1)+x0)*xs);
+		shift = (RoSTdir(p1) == RoSTdirLEFT ? 0 :
+			 (RoSTdir(p1) == RoSTdirRIGHT ? 2 : 1));
+		xtexts[col][c[ROt_ST]] 
+		    = (long)(( RoSTx(p1) + x0 
+			       - (strlen(RoSTs(p1)) * pari_plot.fwidth
+				  * shift)/2)*xs);
 		ytexts[col][c[ROt_ST]]= (long)((RoSTy(p1)+y0)*ys);
 		c[ROt_ST]++;break;
 	      default: break;
--- ./src/graph/plotsun.c~	Thu Sep 16 09:50:21 1999
+++ ./src/graph/plotsun.c	Wed Sep 29 22:46:32 1999
@@ -22,7 +22,7 @@ void
 rectdraw0(long *w, long *x, long *y, long lw, long do_free)
 {
   long *ptx,*pty,*numpoints,*numtexts,*xtexts,*ytexts;
-  long n,i,j,x0,y0;
+  long n,i,j,x0,y0,shift;
   long a,b,c,d,ne;
   long rcnt[ROt_MAX+1];
   char **texts;
@@ -111,7 +111,11 @@ rectdraw0(long *w, long *x, long *y, lon
 	  rcnt[ROt_ML]++;break;
         case ROt_ST:
 	  texts[rcnt[ROt_ST]]=RoSTs(p1); numtexts[rcnt[ROt_ST]]=RoSTl(p1);
-	  xtexts[rcnt[ROt_ST]]=RoSTx(p1)+x0; ytexts[rcnt[ROt_ST]]=RoSTy(p1)+y0;
+	  shift = (RoSTdir(p1) == RoSTdirLEFT ? 0 :
+		   (RoSTdir(p1) == RoSTdirRIGHT ? 2 : 1));
+	  xtexts[rcnt[ROt_ST]]=RoSTx(p1)+x0
+	      - (strlen(RoSTs(p1)) * pari_plot.fwidth * shift)/2;
+	  ytexts[rcnt[ROt_ST]]=RoSTy(p1)+y0;
 	  rcnt[ROt_ST]++;break;
 	default: break;
       }
--- ./src/graph/rect.h~	Thu Sep 16 09:50:21 1999
+++ ./src/graph/rect.h	Wed Sep 29 20:33:20 1999
@@ -73,7 +73,7 @@ typedef struct RectObjST {
   long code,color;
   long length;
   char *s;
-  long x,y;
+  long x,y,dir;
 } RectObjST;
 
 typedef struct RectObjPN {
@@ -168,6 +168,11 @@ typedef struct RectObjPS {
 #define RoSTl(rop) (RoST(rop)->length)
 #define RoSTx(rop) (RoST(rop)->x)
 #define RoSTy(rop) (RoST(rop)->y)
+#define RoSTdir(rop) (RoST(rop)->dir)
+
+#define RoSTdirLEFT	0
+#define RoSTdirCENTER	1
+#define RoSTdirRIGHT	2
 
 #define RoPTTpen(rop) (RoPTT(rop)->pen)
 #define RoLNTpen(rop) (RoLNT(rop)->pen)
@@ -228,6 +233,7 @@ void    rectrmove(long ne, GEN x, GEN y)
 void    rectrpoint(long ne, GEN x, GEN y);
 void    rectscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2);
 void    rectstring(long ne, char *x);
+void    rectstring3(long ne, char *x, long dir);
 void    rectclip(long rect);
 
 /* architecture-dependent plot file (plotX.c, plotsun.c, plognuplot.c...) */