ftp.nice.ch/pub/next/science/mathematics/hippoplotamus.2.0.s.tar.gz#/hippo2.0/hplotX11.c

This is hplotX11.c in view mode; [Download] [Up]

/*                               
 * hippoplotX.c -- Graphics code for producing pure X displays.
 *
 *
 * Author          : Tony Johnson
 * Created On      : 8 Feb 1992
 * Last Modified By: Tony Johnson
 * Last Modified On: 8 Feb 1992
 * Update Count    : 
 * Status          : Revision 1
 *
 * Copyright (C)  1991  The Board of Trustees of The Leland Stanford
 * Junior University.  All Rights Reserved.
 *
 * $Id: hplotX11.c,v 5.0 1993/08/17 21:56:10 rensing Exp $
 */ 


#include "hplotX11.h"

#include <stdio.h>
#include <string.h>
#include <math.h>

GLOB_QUAL const char hippoplotX11_c_rcsid[] = 
     "$Id: hplotX11.c,v 5.0 1993/08/17 21:56:10 rensing Exp $";

GLOB_QUAL const char hippoplotX11_h_rcsid[] = HIPPOPLOTX11_H_RCSID;

#define FontName\
  "-Adobe-New Century Schoolbook-Bold-R-Normal--*-*-*-*-*-*-*-*"
#define MAXFONTS 30
#define MAXCACHE 20

#define min(A,B) ((A>B) ? B : A)

/* These are for passing info from Histo class: */

static Display     *h_display;
static Drawable    h_drawable;
static GC          h_gc;
static Font        h_font[MAXFONTS];
static XFontStruct *h_fontStruct;
static int         h_nFonts;
static char        **h_fontNames;
static int         h_depth;
static int         h_color;
static Screen      *h_screen;

static init = 0;

/* All scaling info: */

static struct {
   float x;
   float y;
   int xMarg;
   int yMarg;
   float xOrig;
   float yOrig;
} Scale, Convert;

/* The Data-coords limits: */

static struct {
   float xmin;
   float xmax;
   float ymin;
   float ymax;
} Limit;

static void drawStipple2D_X11(int nXBins,
			      int nYBins,
			      float minBin,
			      float maxBin,
			      float bins[]);
static void ColorError();


static int XScale(float x)
{
   return (x - Scale.xOrig)*Scale.x + Scale.xMarg;
}
static int YScale(float y)
{
   return Scale.yMarg - (y - Scale.yOrig)*Scale.y;
}
static int XConvert(float x)
{
   return (x - Convert.xOrig)*Convert.x + Convert.xMarg;
}
static int YConvert(float y)
{
   return Convert.yMarg - (y - Convert.yOrig)*Convert.y;
}
void initPlot_X11(Display *disp, Screen *screen, Drawable drawable, GC gc)
{
   h_display   = disp;
   h_drawable  = drawable;
   h_gc        = gc;
   h_screen    = screen;

   if (!init)
     {
       int i;
       init = 1;
       h_fontNames = XListFontsWithInfo(disp,FontName,MAXFONTS,
                                        &h_nFonts,&h_fontStruct);

       for (i=0; i<h_nFonts; i++) h_font[i] = 0;

     }

   /* Are we in color? */

   h_color = (DefaultVisualOfScreen(h_screen)->class == PseudoColor);
}

static void ColorError()
{
   static Reported = 0;
   if (Reported++) return;
  
   printf("\nXHippo: Unable to allocate required colormap entries\n");
}

void setHistoCoords_X11(rectangle *draw,
                      rectangle *margin, 
                      rectangle *data)
{
   unsigned int width, height, border;
   int x,y;
   Window root;
    
   /* Get overall width and height from window. */

   XGetGeometry(h_display,h_drawable,&root,&x,&y,&width,
		&height,&border,&h_depth);   

   /* Remember margin is in points; data is in data coords. */

   Convert.x = width/draw->size.width;
   Convert.y = height/draw->size.height;
   Convert.xMarg = 0;
   Convert.yMarg = height;
   Convert.xOrig = draw->origin.x;
   Convert.yOrig = draw->origin.y;

   Scale.x = (Convert.x * margin->size.width)/(data->size.width);
   Scale.y = (Convert.y * margin->size.height)/(data->size.height);
   Scale.xMarg = XConvert(margin->origin.x);
   Scale.yMarg = YConvert(margin->origin.y);
   Scale.xOrig = data->origin.x;
   Scale.yOrig = data->origin.y;
   
   Limit.xmin = data->origin.x;
   Limit.xmax = data->size.width + data->origin.x;
   Limit.ymin = data->origin.y;
   Limit.ymax = data->size.height + data->origin.y;
   
#ifdef DEBUG
   printf ("setupX: X scale = %f, Y scale = %f\n", Scale.x, Scale.y);
#endif
}

/*  Put the message text at the indicated x-y position (Note, x and y
 *  are in points):
 */
 
void drawText_X11(char *message,
	        float x,
         	float y,
		float fontHeight,
		float angle,
		char xalign,
		char yalign)
{
   int xx = XConvert(x);
   int yy = YConvert(y);
   int width, dir, ascent, descent;
   int length = strlen(message);
   int i, n, size;
   double sinA = sin(angle), cosA = cos(angle);

   
   XCharStruct overall;

   /* Decide which font to use */

   int fontSize = min(Convert.x , Convert.y) * fontHeight;
   
   size = 0;
   for (i=0; i<h_nFonts; i++)
     {
       int h = h_fontStruct[i].ascent + h_fontStruct[i].descent;
       if (h <= fontSize && h > size) 
         { 
           size = h;
           n = i;
         }
     }
   if (size == 0)
     {
       size = 99999;
       for (i=0; i<h_nFonts; i++)
         {
           int h = h_fontStruct[i].ascent + h_fontStruct[i].descent;
           if (h < size)
             {
               size = h;
               n = i;
             }
         }
     }

   if (h_font[n] == 0) 
     {
       h_fontStruct[n] = *XLoadQueryFont(h_display,h_fontNames[n]);
       h_font[n] = h_fontStruct[n].fid;
     }
      
#ifdef DEBUG
   printf("fontHeight,Convert.x,Convert.y,angle,font %f,%f,%f,%f\n%s",
           fontHeight,Convert.x,Convert.y,angle,h_fontNames[n]);
#endif

   XSetFont(h_display,h_gc,h_font[n]);
   XTextExtents(&h_fontStruct[n],message,length,&dir,
		&ascent,&descent,&overall);
   width = overall.width;
   ascent = overall.ascent;
   descent = overall.descent;

   switch (xalign) 
     {
       case 'C':
       case 'c':
         xx -= cosA*width/2 + sinA*(ascent - descent)/2; 
         break;
       
       case 'R':
       case 'r':
         xx -= cosA*width + sinA*ascent;
         break;

       case 'L':
       case 'l':
       default:
         xx += sinA*ascent;
         break;
     }

   switch (yalign) 
     {
       case 'C':
       case 'c':
         yy += cosA*(ascent - descent)/2 - sinA*width/2;
         break;
       
       case 'T':
       case 't':
         yy += cosA*ascent - sinA*width;
         break;

       case 'B':
       case 'b':
       default:
         yy -= cosA*descent;
         break;
     }

   if (angle!=0)
/*
 *  There is no good way to deal with angled text prior to X11R5.
 *  The following is an inelegant work around. This can probably
 *  be done better with X11R5. This code is currently set up to rotate
 *  by a fixed 90 degress (ie angle is ignored).
 */
     {
       int height = ascent + descent;
       int i;
       static struct {
         char   *text;
         Pixmap  map;
         } cache[MAXCACHE];

       static int Ncache = 0;

       for (i=0; i<Ncache; i++)
         {
           if (strcmp(cache[i].text,message) == 0) break; 
         }
       if (i<Ncache)
         {
           XCopyArea(h_display,cache[i].map,h_drawable,
		     h_gc,0,0,height,width,xx,yy);
         }
       else
         {
           int i,j;
           XImage *image, *rimage; 
           XGCValues values;
         
           GC gc_temp = XCreateGC(h_display,h_drawable,0,&values);      

           Pixmap New = XCreatePixmap(h_display,h_drawable, 
                                      width,height,h_depth);
           Pixmap Rot = XCreatePixmap(h_display,h_drawable,
                                      height,width,h_depth);

           XGetGCValues(h_display,h_gc,GCBackground,&values); 
           values.foreground = values.background;
           XChangeGC(h_display,gc_temp,GCForeground,&values);
           XFillRectangle(h_display,New,gc_temp,0,0,width,height);
           XFreeGC(h_display,gc_temp);

           XDrawString(h_display,New,h_gc,0,ascent,message,length);
           image = XGetImage(h_display,New,0,0,width,height,
			     AllPlanes,XYPixmap);
           rimage = XGetImage(h_display,Rot,0,0,height,width,
			      AllPlanes,XYPixmap);
       
           for (i=0; i<width; i++) 
             for (j=0; j<height; j++)
               XPutPixel(rimage,j,width-i-1,XGetPixel(image,i,j));
       
           XPutImage(h_display,Rot,h_gc,rimage,0,0,0,0,height,width);

           XCopyArea(h_display,Rot,h_drawable,h_gc,0,0,height,width,xx,yy);

           XFreePixmap(h_display,New);
           XDestroyImage(image);
           XDestroyImage(rimage);
 
           if (Ncache == MAXCACHE)
             {
               XFreePixmap(h_display,cache[0].map);
               free(cache[0].text);
               for (i=1; i<MAXCACHE; i++) cache[i-1] = cache[i];   
               Ncache--;
             }
           cache[Ncache].map = Rot;
           cache[Ncache].text = strcpy(malloc(length+1),message);
           Ncache++;
         }
     } 
   else { XDrawString(h_display,h_drawable,h_gc,xx,yy,message,length); }     
}



void drawMag_X11(float x, float y,
		 int mag, float fontsize)

/* x and y are in device coords (points). */
{
  char buffer[12];
  sprintf(buffer,"%d",mag);
  
  drawText_X11("x10",x,y,fontsize,0,'r','c'); 
  drawText_X11(buffer,x,y,fontsize,0,'l','b');
}



void drawXTicks_X11(float *x,
		    int nt,
		    float tickwidth,
		    int side)
{
   XSegment *segs = (XSegment *) malloc(nt*sizeof(XSegment));
   XSegment *ns = segs;
   int i;
   short y1, y2;
   
   if (side == 0)
     {
       y1 = YScale(Limit.ymin);
       y2 = y1 - Convert.y * tickwidth;
     }
   else
     {
       y1 = YScale(Limit.ymax) + 1;
       y2 = y1 + Convert.y * tickwidth;
     }

   for (i = 0; i < nt; i++)
     {
       ns->x1 = XScale(*x++);
       ns->x2 = ns->x1;
       ns->y1 = y1;
       ns->y2 = y2;
       ns++;
     }
   XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);

   XDrawSegments(h_display,h_drawable,h_gc,segs,nt);
   free(segs);
}

void drawYTicks_X11(float* y,
		  int nt,
		  float tickwidth,
		  int side)
{
   XSegment *segs = (XSegment *) malloc(nt*sizeof(XSegment));
   XSegment *ns = segs;
   int i;
   short x1, x2;
   
   if (side == 0)
     {
       x1 = XScale(Limit.xmin) + 1;
       x2 = x1 + Convert.x * tickwidth;
     }
   else
     {
       x1 = XScale(Limit.xmax);
       x2 = x1 - Convert.x * tickwidth;
     }

   for (i = 0; i < nt; i++)
     {
       ns->y1 = YScale(*y++);
       ns->y2 = ns->y1;
       ns->x1 = x1;
       ns->x2 = x2;
       ns++;
     }
   XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);

   XDrawSegments(h_display,h_drawable,h_gc,segs,nt);
   free(segs);
}

void drawRect_X11(float x, float y,
     	        float width, float height)

/* all args are in window coords */
{
      XDrawRectangle(h_display, h_drawable, h_gc, XConvert(x), YConvert(y),
                     XConvert(width), XConvert(height));

#ifdef DEBUG
   printf("drawRect_X11: rect at (%d, %d) size (%d, %d)\n",
	  XConvert(x), YConvert(y), XConvert(width),YConvert(height));
#endif
}

void drawFilledRect_X11(float x, float y,
        	      float width, float height,
	   	      float grey)

/* all args are in window coords */
{

    int xx = XConvert(x);
    int yy = YConvert(y);
    int ww = Convert.x * width;
    int hh = Convert.y * height;
    int color = 256*grey;

    XSetForeground(h_display, h_gc, color);
    XFillRectangle(h_display, h_drawable, h_gc, xx, yy, ww, hh); 
    
#ifdef DEBUG
   printf("drawFilledRect_X11: rect at (%d, %d) size (%d, %d) color (%d)\n",
	  xx, yy, ww, hh, color);
#endif
}

void shade_X11(float xlow, float xhigh,
             float ylow, float yhigh )

/* all args are in data coords */
{

   int xx = XConvert(xlow);
   int yy = YConvert(yhigh);
   int ww = XConvert(xhigh) - xx;
   int hh = YConvert(ylow) - yy;

   Pixmap Stipple;
   static char data[] = {0x02, 0x01};
   
   Stipple = XCreatePixmapFromBitmapData(h_display,h_drawable,data,2,2,0,1,1);

   XSetStipple(h_display, h_gc, Stipple);
   XSetFillStyle(h_display,h_gc,FillStippled);   
   XFillRectangle(h_display, h_drawable, h_gc, xx, yy, ww, hh); 
   XSetFillStyle(h_display,h_gc,FillSolid);   
   XFreePixmap(h_display,Stipple);

#ifdef DEBUG
   printf("drawFilledRect_X11: rect at (%f, %f) to (%f, %f)\n",
 	  xlow, ylow, xhigh,yhigh);
#endif
}

void drawLine_X11(float *xy, int nxy, linestyle_t ls)
{
   XPoint *points = (XPoint *) malloc(nxy*sizeof(XPoint));
   XPoint *np = points;
   int i;
   for (i = 0; i < nxy; i++)
     {
       np->x = XScale(*xy++);
       np->y = YScale(*xy++);
       np++;
     }

   switch (ls)
     {
       char dashlist[4];
  
       case SOLID:
       default:
         XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
         break;
       case DASH:
         dashlist[0] = 4;
         dashlist[1] = 4;
         XSetDashes(h_display,h_gc,0,dashlist,2);
         XSetLineAttributes(h_display,h_gc,0,LineOnOffDash,CapButt,JoinMiter);
         break;
       case DOT:
         dashlist[0] = 1;
         dashlist[1] = 2;
         XSetDashes(h_display,h_gc,0,dashlist,2);
         XSetLineAttributes(h_display,h_gc,0,LineOnOffDash,CapButt,JoinMiter);
         break;
       case DOTDASH:
         dashlist[0] = 4;
         dashlist[1] = 2;
         dashlist[2] = 1;
         dashlist[3] = 2;
         XSetDashes(h_display,h_gc,0,dashlist,4);
         XSetLineAttributes(h_display,h_gc,0,LineOnOffDash,CapButt,JoinMiter);
         break;
     }

   XDrawLines(h_display,h_drawable,h_gc,points,nxy,CoordModeOrigin);
   free(points);
}

void drawPoints_X11(float xy[],
		  int nxy,
		  int symbol,
		  float symbolsize)
{
  XRectangle *recs, *r;
  XSegment   *segs, *s;
  int i;
  short simsize = min(Convert.x , Convert.y) * symbolsize/2;
  short width = 4, height = 4, halfwidth=2, halfheight=2;

  if (simsize<1) simsize=1;
  halfwidth = simsize;
  halfheight = simsize;
  width = simsize*2;
  height = simsize*2;
  
  switch (symbol) 
    {
      case SQUARE:
      case SOLIDSQUARE:
      default:

        recs = (XRectangle *) malloc(nxy*sizeof(XRectangle));
        r = recs;
  
        for (i=0; i<nxy; i++)
          {
            r->x = XScale(*xy++) - halfwidth;
            r->y = YScale(*xy++) - halfheight;
            r->width = width;
            r->height = height;
            r++;
          }
        if (symbol == SOLIDSQUARE) XFillRectangles(h_display,h_drawable,
						   h_gc,recs,nxy);
        else                       XDrawRectangles(h_display,h_drawable,
						   h_gc,recs,nxy);
        free(recs);
        break;
      
      case PLUS:
      case TIMES:

        segs = (XSegment *) malloc(nxy*sizeof(XSegment)*2);
        s = segs;
  
        if (symbol==TIMES)
          for (i=0; i<nxy; i++)
            {
              short x = XScale(*xy++);
              short y = YScale(*xy++);
              s->x1 = x-halfwidth;
              s->x2 = x+halfwidth;
              s->y1 = y-halfheight;
              s->y2 = y+halfheight;
              s++;
              s->x1 = x-halfwidth;
              s->x2 = x+halfwidth;
              s->y1 = y+halfheight;
              s->y2 = y-halfheight;
              s++;
            }
        else
          for (i=0; i<nxy; i++)
            {
              short x = XScale(*xy++);
              short y = YScale(*xy++);
              s->x1 = x-halfwidth;
              s->x2 = x+halfwidth;
              s->y1 = y;
              s->y2 = y;
              s++;
              s->x1 = x;
              s->x2 = x;
              s->y1 = y-halfheight;
              s->y2 = y+halfheight;
              s++;
            }
        XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
        XDrawSegments(h_display,h_drawable,h_gc,segs,nxy*2);
        free(segs);
    }    
} 

void drawXError_X11(float xy[],
		  float errs[],
		  int npts)
{
   XSegment *segs = (XSegment *) malloc(3*npts*sizeof(XSegment));
   XSegment *ns = segs;
   int i;
   short halfwidth = 2;
   
   for (i = 0; i < npts; i++)
     {
       short y, xhi, xlo;
       xy++; /* ignore x value */
       y   = YScale(*xy++);
       xhi = XScale(*errs++);
       xlo = XScale(*errs++);

       ns->y1 = y;
       ns->y2 = y;
       ns->x1 = xlo;
       ns->x2 = xhi;
       ns++;
       ns->y1 = y+halfwidth;
       ns->y2 = y-halfwidth;
       ns->x1 = xlo;
       ns->x2 = xlo;
       ns++;
       ns->y1 = y+halfwidth;
       ns->y2 = y-halfwidth;
       ns->x1 = xhi;
       ns->x2 = xhi;
       ns++;
     }
   XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);

   XDrawSegments(h_display,h_drawable,h_gc,segs,3*npts);
   free(segs);
}


void drawYError_X11(float xy[],
		  float errs[],
		  int npts)
{
   XSegment *segs = (XSegment *) malloc(3*npts*sizeof(XSegment));
   XSegment *ns = segs;
   int i;
   short halfwidth = 2;
   
   for (i = 0; i < npts; i++)
     {
       short x, yhi, ylo;
       x   = XScale(*xy++);
       xy++; /* ignore y value */
       yhi = YScale(*errs++);
       ylo = YScale(*errs++);

       ns->x1 = x;
       ns->x2 = x;
       ns->y1 = ylo;
       ns->y2 = yhi;
       ns++;
       ns->x1 = x+halfwidth;
       ns->x2 = x-halfwidth;
       ns->y1 = ylo;
       ns->y2 = ylo;
       ns++;
       ns->x1 = x+halfwidth;
       ns->x2 = x-halfwidth;
       ns->y1 = yhi;
       ns->y2 = yhi;
       ns++;
     }
   XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);

   XDrawSegments(h_display,h_drawable,h_gc,segs,3*npts);
   free(segs);
}

static void drawStipple2D_X11(int nXBins,
			      int nYBins,
			      float minBin,
			      float maxBin,
			      float bins[])
{
   float xBinWidth = (Limit.xmax - Limit.xmin)/nXBins;
   float yBinWidth = (Limit.ymax - Limit.ymin)/nYBins;
   float x = Limit.xmin;
   float y = Limit.ymin;

   float scale = 15.0 / (maxBin - minBin);
   int i,j;
   int xx = XScale(Limit.xmin);
   int yy = YScale(Limit.ymin);
   int ww, hh;
   unsigned long mask = GCForeground | GCBackground | GCFillStyle | GCStipple;
   XGCValues values;
   Pixmap Stipple[16];
   GC temp_gc[16];

   static char data[16][4] = {
   {0x0f, 0x0f, 0x0f, 0x0f},
   {0x0f, 0x0e, 0x0f, 0x0f},
   {0x0f, 0x0e, 0x07, 0x0f},
   {0x0d, 0x0e, 0x07, 0x0f},
   {0x0d, 0x0e, 0x07, 0x0b},
   {0x0d, 0x0e, 0x05, 0x0b},
   {0x05, 0x0e, 0x05, 0x0b},
   {0x05, 0x0a, 0x05, 0x0b},
   {0x05, 0x0a, 0x05, 0x0a},
   {0x05, 0x0a, 0x01, 0x0a},
   {0x01, 0x0a, 0x01, 0x0a},
   {0x01, 0x0a, 0x00, 0x0a},
   {0x00, 0x0a, 0x00, 0x0a},
   {0x00, 0x02, 0x00, 0x0a},
   {0x00, 0x02, 0x00, 0x08},
   {0x00, 0x02, 0x00, 0x00}};

   for (i=0; i<16; i++)
     Stipple[i] = XCreatePixmapFromBitmapData(h_display,h_drawable,
					      data[i],4,4,0,1,1);

   values.foreground = BlackPixelOfScreen(h_screen);
   values.background = WhitePixelOfScreen(h_screen);
   values.fill_style = FillOpaqueStippled;
   
   for (i=0; i<16; i++)
     {
       values.stipple = Stipple[i];
       temp_gc[i] = XCreateGC(h_display,h_drawable,mask,&values);
     }

   XFillRectangle(h_display,h_drawable,temp_gc[0],xx,YScale(Limit.ymax),
                  (XScale(Limit.xmax)-xx),(yy-YScale(Limit.ymax)));

   for (i=0; i<nXBins; i++)
     {
       x += xBinWidth;
       ww = XScale(x) - xx;
       for (j=0; j<nYBins; j++)
         {
           int ss = scale * (*bins++ - minBin);
           y += yBinWidth;
           hh = yy - YScale(y);
           yy -= hh;
           if (ss!=0) 
             XFillRectangle(h_display,h_drawable,temp_gc[ss],xx,yy,ww,hh);
         }
       xx += ww;
       yy = YScale(Limit.ymin);
       y = Limit.ymin;
     }           
   for (i=0; i<16; i++) 
     { 
       XFreePixmap(h_display,Stipple[i]);
       XFreeGC(h_display,temp_gc[i]);
     }
}

void drawColor2D_X11(int nXBins,
		   int nYBins,
		   float minBin,
		   float maxBin,
		   float bins[],
                   int fullColor)
{
   float xBinWidth = (Limit.xmax - Limit.xmin)/nXBins;
   float yBinWidth = (Limit.ymax - Limit.ymin)/nYBins;
   float x = Limit.xmin;
   float y = Limit.ymin;
   float scale = 90.0 / (maxBin - minBin);
   int i,j;
   int xx = XScale(Limit.xmin);
   int yy = YScale(Limit.ymin);
   int ww, hh;
 
   static int GotColorMap = 0; 
   static int GotGreyMap  = 0;
   Colormap Map;
   static XColor Color[91];
   static XColor Grey[91];
   XColor *ColorsUsed;
   GC temp_gc;

   static struct {
      int red;
      int green;
      int blue;
          }  
                  rainbow[10]    ={{0    ,     0,     0},     /* black   */
                                   {33422, 15728,   553},     /* brown   */
                                   {23912, 14548, 33947},     /* violet  */
                                   {15217, 17377, 41142},     /* indigo  */
                                   {    0,     0, 55049},     /* blue    */
                                   {    0, 50078,   199},     /* green   */
                                   {62193, 60816,     0},     /* yellow  */
                                   {65535, 28180,  1310},     /* orange  */
                                   {65535,  1310,     0},     /* red     */
                                   {65535, 65535, 65535}};    /* white   */   

   if (!h_color)
     {
       drawStipple2D_X11(nXBins,nYBins,minBin,maxBin,bins);
       return;
     } 

   temp_gc = XCreateGC(h_display,h_drawable,NULL,0);

   if (fullColor != 0 && GotColorMap++ == 0)
     {
       int i, j, k=0;
       Map = DefaultColormapOfScreen(h_screen);
         
       for (i=0; i<9; i++)
         {
           for (j=0; j<10; j++)
             {
               Color[k].red   = rainbow[i].red*(10-j)/10   + 
		    rainbow[i+1].red*j/10;
               Color[k].blue  = rainbow[i].blue*(10-j)/10  + 
		    rainbow[i+1].blue*j/10;
               Color[k].green = rainbow[i].green*(10-j)/10 +
		    rainbow[i+1].green*j/10;
               if (!XAllocColor(h_display,Map,&Color[k])) ColorError();
               k++;
             } 
         }
       Color[k].red   = rainbow[9].red;
       Color[k].blue  = rainbow[9].blue;
       Color[k].green = rainbow[9].green;
       if (!XAllocColor(h_display,Map,&Color[k])) ColorError();
     }
   else if (fullColor == 0 && GotGreyMap++ ==0)
     {
       int i; 
       Map = DefaultColormapOfScreen(h_screen);
 
       for (i=0; i<=90; i++)
         {
           int color = 65535-i*65535/90;
           Grey[i].red = color;
           Grey[i].blue = color;
           Grey[i].green = color;
           if (!XAllocColor(h_display,Map,&Grey[i])) ColorError();
         }
     }

   if (fullColor == 0) ColorsUsed = Grey;
   else                ColorsUsed = Color; 

   XSetForeground(h_display,temp_gc,ColorsUsed[0].pixel);
   XFillRectangle(h_display,h_drawable,temp_gc,xx,YScale(Limit.ymax),
                  (XScale(Limit.xmax)-xx),(yy-YScale(Limit.ymax)));

   for (i=0; i<nXBins; i++)
     {
       x += xBinWidth;
       ww = XScale(x) - xx;
       for (j=0; j<nYBins; j++)
         {
           int color = scale * (*bins++ - minBin);
           y += yBinWidth;
           hh = yy - YScale(y);
           yy -= hh;
           if (color==0) continue;
           XSetForeground(h_display,temp_gc,ColorsUsed[color].pixel);
           XFillRectangle(h_display,h_drawable,temp_gc,xx,yy,ww,hh);
         }
       xx += ww;
       yy = YScale(Limit.ymin);
       y = Limit.ymin;
     }           
   XFreeGC(h_display,temp_gc);
}

void drawLego2D_X11(display disp)
{
   float angle = 45; /* degrees */
   float sin45 = 1./sqrt(2.);
   float cos45 = sin45;

   float xBinWidth = (Limit.xmax - Limit.xmin)/disp->bins.xAxis.nBins;
   float yBinWidth = cos45*(Limit.ymax - Limit.ymin)/disp->bins.yAxis.nBins;
   float x = Limit.xmax;
   float y = Limit.ymax;
   float scale = (YScale(Limit.ymax) - YScale(Limit.ymin)) * ( 1 - cos45 ) 
                 / (disp->bins.binMax - disp->bins.binMin);
   int i,j;
   int xx = XScale(Limit.xmax);
   int yy = YScale(Limit.ymax);
   int ww, hh, oo, xxx, yyy;
   XPoint points[5];

   static XColor bright, medium, dark;
   static int GotColors = 0;
   static Pixmap Medium;
   static int GotPixmap = 0;
   GC bright_gc, medium_gc, dark_gc;

   bright_gc = XCreateGC(h_display,h_drawable,0,NULL);
   medium_gc = XCreateGC(h_display,h_drawable,0,NULL);
   dark_gc   = XCreateGC(h_display,h_drawable,0,NULL);

   if (h_color && GotColors++ == 0)
     {
       Colormap Map = DefaultColormapOfScreen(h_screen);
       bright.red   = 55000;
       bright.blue  = 55000;
       bright.green = 55000;
       if (!XAllocColor(h_display,Map,&bright)) ColorError();

       medium.red   = 35000;
       medium.blue  = 35000;
       medium.green = 35000;
       if (!XAllocColor(h_display,Map,&medium)) ColorError();

       dark.red   = 10000;
       dark.blue  = 10000;
       dark.green = 10000;
       if (!XAllocColor(h_display,Map,&dark)) ColorError();

     }
   else if (!h_color && GotPixmap++ == 0)
     {
       static char medium_data[] = {0x02, 0x01};
       Medium = XCreatePixmapFromBitmapData(h_display,h_drawable,
					    medium_data,2,2,0,1,1);
     } 
   if (h_color)
     {
       XSetForeground(h_display,medium_gc,medium.pixel);
       XSetForeground(h_display,bright_gc,bright.pixel);
       XSetForeground(h_display,dark_gc  ,dark.pixel);
     }
   else
     {
       XSetFillStyle(h_display,medium_gc,FillOpaqueStippled);
       XSetStipple(h_display,medium_gc,Medium);

       XSetForeground(h_display,bright_gc,WhitePixelOfScreen(h_screen));
       XSetForeground(h_display,medium_gc,WhitePixelOfScreen(h_screen));
       XSetForeground(h_display,dark_gc  ,BlackPixelOfScreen(h_screen));
       XSetBackground(h_display,medium_gc,BlackPixelOfScreen(h_screen));
     }

   points[0].x = xx - (YScale(Limit.ymin) - YScale(Limit.ymax))*cos45;
   points[0].y = yy + (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);
   points[1].x = XScale(Limit.xmin) - (YScale(Limit.ymin) - 
				       YScale(Limit.ymax))*cos45;
   points[1].y = yy + (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);
   points[2].x = XScale(Limit.xmin);
   points[2].y = YScale(Limit.ymin);
   points[3].x = xx;
   points[3].y = YScale(Limit.ymin);
   points[4].x = xx - (YScale(Limit.ymin) - YScale(Limit.ymax))*cos45;
   points[4].y = yy + (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);
   XFillPolygon(h_display,h_drawable,medium_gc,points,5,
		Convex,CoordModeOrigin);

   xxx = -(YScale(Limit.ymin) - YScale(Limit.ymax))*cos45;
   yyy = (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);

   for (j=0; j<disp->bins.yAxis.nBins; j++)
     {
       y -= yBinWidth;
       hh = cos45*(YScale(y) - yy);
       oo = sin45*(yy - YScale(y));

       yy += hh;
       disp->bins.data += disp->bins.xAxis.nBins*disp->bins.yAxis.nBins - 1;
      
       for (i=0; i<disp->bins.xAxis.nBins; i++)
         {
           int size = scale * (*disp->bins.data - disp->bins.binMin);
           disp->bins.data -= disp->bins.yAxis.nBins;

           x -= xBinWidth;
           ww = xx - XScale(x);

           xx -= ww;

           if (size == 0) continue;

           points[0].x = xx + xxx;
           points[0].y = yy + yyy + size;
           points[1].x = xx + xxx + ww;
           points[1].y = yy + yyy + size;
           points[2].x = xx + xxx + ww + oo;
           points[2].y = yy + yyy - hh + size;
           points[3].x = xx + xxx + oo;
           points[3].y = yy + yyy - hh + size;
           points[4].x = xx + xxx;
           points[4].y = yy + yyy + size;
           XFillPolygon(h_display,h_drawable,medium_gc,points,5,
			Convex,CoordModeOrigin);

           points[0].x = xx + xxx;
           points[0].y = yy + yyy;
           points[1].x = xx + xxx;
           points[1].y = yy + yyy + size;
           points[2].x = xx + xxx + oo;
           points[2].y = yy + yyy - hh + size;
           points[3].x = xx + xxx + oo;
           points[3].y = yy + yyy - hh;
           points[4].x = xx + xxx;
           points[4].y = yy + yyy;
           XFillPolygon(h_display,h_drawable,bright_gc,points,5,
			Convex,CoordModeOrigin);

           points[0].x = xx + xxx;
           points[0].y = yy + yyy;
           points[1].x = xx + xxx + ww;
           points[1].y = yy + yyy;
           points[2].x = xx + xxx + ww;
           points[2].y = yy + yyy + size;
           points[3].x = xx + xxx;
           points[3].y = yy + yyy + size;
           points[4].x = xx + xxx;
           points[4].y = yy + yyy;
           XFillPolygon(h_display,h_drawable,dark_gc,points,5,
			Convex,CoordModeOrigin);
         }

       xxx -= oo;
       xx = XScale(Limit.xmax);
       x = Limit.xmax;
     }           

   XFreeGC(h_display,bright_gc);
   XFreeGC(h_display,dark_gc);
   XFreeGC(h_display,medium_gc);
}

void drawScatter3D_X11(display disp, float *coords, int nCoords)
{
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.