[Contents, Next, Previous].

Example code

Two C programs are listed below: ex1.c and ex2.c.

Here's some sample output from ex1.c:

Repetition value 14
x             x             x             x             x             x         
L*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mve
u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`<
?yC9CyK@?5C7by?yC9CyK@?5C7by?yC9CyK@?5C7byyC9CyK@?5C77byyC9CyK@?5C77byyC9CyK@?5C
f$THP@)ckf[HIsf$THP@)ckf[HIsf$THP@)ckf[Isf$THP@)ckf[Isf$$THP@)ckf[Isf$$THP@)ckf[
(J@nWG5Wl&OH:S(J@nWG5Wl&OH:S(J@nWG5WlOH:S(J@nWG5WlOH:S(J@nnWG5WlOH:S(J@nnWG5WlOH
ixl6Y$5}1x(QEXixl6Y$5}1x(QEXixl6Y$51x(QEXixl6Y$51x(QEXixl6Y$$51x(QEXixl6Y$$51x(Q
3"Dag6CSGn1(*`3"Dag6CSGn1(*`3"DagCSGn1(*`3"DagCSGn1(*`3"DagCSGGn1(*`3"DagCSGGn1(
s$*4RQ+8@jqB!#s$*4RQ+8@jqB!#s$*4Q+8@jqB!#s$*4Q+8@jqB!#s$*4Q+8@jjqB!#s$*4Q+8@jjqB
D1HZHI\nAI=d:YD1HZHI\nAI=d:YD1HHI\nAI=d:YD1HI\nAI=@d:YD1HI\nAI=@@d:YD1HI\nAI=@@d
T+JO(!PT32SRrTT+JO(!PT32SRrTT+O(!PT32SRrT+O(!PT32SRrTT+O(!PT32SRrrTT+O(!PT32SRrr
co#802+u~,Y&&#co#802+u~,Y&&#c#802+u~,Y&#c#802+u~,Y&#c#8Y02+u~,Y&#cc#8Y02+u~,Y&#c
Zfr9Jrd;N@@=bAZfr9Jrd;N@@=bAfr9Jrd;N@=bAfr9Jrd;N@=bAfr9JrXd;N@=bAfrr9JrXd;N@=bAf
_=G>h>*R&&7D1K_=G>h>*R&&7D1K=G>h>*R&7D1K=G>h>*R&7D1K=G>h>*)R&7D1K=GG>h>*)R&7D1K=
#KICd&eMMu:9fW#KICd&eMMu:9f#KICd&eMu:9f#KICd&eMu:9f#KICd&eMpu:9f#KICCd&eMpu:9f#K
M~<\H7[[5TCk$yM~<\H7[[5TCk$M~<\H7[5TCk$M~<\H7[5TCk$M~<\H7[5TWCk$M~<\\H7[5TWCk$M~
1;$.FJJ8oQyKUh1;$.FJJ8oQyKh1;$.FJ8oQyKh1;$.FJ8oQyKh1;$.FJ8oQy7Kh1;$.FFJ8oQy7Kh1;
9B=TT==t7F-:zY9B=TT==t7F-:Y9B=TT=t7F-:Y9B=TT=t7F-:Y9B=TT=t7F-?:Y9B=TTT=t7F-?:Y9B
FIJbIIN<WnzEa_FIJbIIN<Wnza_FIJbIN<Wnza_FIJbIN<Wnza_FIJbIN<WnzaO_FIJbINN<WnzaO_FI
<G?_##nY9iyG>P<G?_##nY9iy>P<G?_#nY9iy>P<G?_#nY9iy>P<G?_#nY9iy>_P<G?_#nnY9iy>_P<G
MCZ@@OZ0;\AvoZMCZ@@OZ0;\AoZMCZ@OZ0;\AoZMCZ@OZ0;\AoZMCZ@OZ0;\AoZuMCZ@OZZ0;\AoZuMC
LcDKKO&0O$^`9GLcDKKO&0O$`9GLcDKO&0O$`9GLcDKO&0O$`9GLcDKO&0O$`9G%LcDKO&00O$`9G%Lc
K%\AA}LF!^i=-1K%\AA}LF!^=-1K%\A}LF!^=-1K%\A}LF!^=-1K%\A}LF!^=-1-K%\A}LFF!^=-1-K%
dz''KCWXv?]X@@dz''KCWXv?X@@dz'KCWXv?X@@dz'KCWXv?X@@dz'KCWXv?X@@d)z'KCWXXv?X@@d)z
2oII{p)_qL@^\L2oII{p)_qL^\L2oI{p)_qL^\L2oI{p)_qL^\L2oI{p)_qL^\L2UoI{p)__qL^\L2Uo
K\RR-_l$!cm8Y>K\RR-_l$!c8Y>K\R-_l$!c8Y>K\R-_l$!c8Y>K\R-_l$!c8Y>K&\R-_l$$!c8Y>K&\
dF**'[8E9\(zb,dF**'[8E9\zb,dF*'[8E9\zb,dF*'[8E9\zb,dF*'[8E9\zb,dcF*'[8EE9\zb,dcF
M*44sPW]Z>}S~_M*44sPW]Z>S~_M*4sPW]Z>S~_M*4sPW]Z>S~_M*4sPW]Z>S~_MC*4sPW]]Z>S~_MC*
o[JJ?UY5o]Ak+_o[JJ?UY5o]k+_o[J?UY5o]k+_o[J?UY5o]k+_o[J?UY5o]k+_oM[J?UY55o]k+_oM[
E,uu.;;"^*^e`uE,uu.;;"^*e`uE,u.;;"^*e`uE,u.;;"^*e`uE,u.;;"^*e`uE),u.;;""^*e`uE),
b(VLL!bz@~V?[gb(VLL!bz@~?[gb(VL!bz@~?[gb(VL!bz@~?[gb(VL!bz@~?[g+b(VL!bzz@~?[g+b(
ASOvv-("M04\'+ASOvv-("M0\'+ASOv-("M0\'+ASOv-("M0\'+ASOv-("M0\'+CASOv-(""M0\'+CAS
J&G~~*uZ(b_Ey<J&G~~*uZ(b_y<J&G~*uZ(b_y<J&G~*uZ(b_y<J&G~*uZ(b_y<OJ&G~*uuZ(b_y<OJ&
"E=EssII>Tk,FS"E=EssII>TkFS"E=EsII>TkFS"E=EsII>TkFS"E=EsII>TkF?S"E=EsIII>TkF?S"E
2O0`dd=D<Mv*J,2O0`dd=D<MvJ,2O0`d=D<MvJ,2O0`d=D<MvJ,2O0`d=D<MvJl,2O0`d==D<MvJl,2O
~M>=2BB)0A]&>O~M>=2BB)0A]&O~M>=2B)0A]&O~M>=2B)0A]&O~M>=2B)0A]Q&O~M>=22B)0A]Q&O~M
I%O_}EE.l@8%W7I%O_}EE.l@8%7I%O_}E.l@8%7I%O_}E.l@8%7I%O_}E.l@8M%7I%O_}}E.l@8M%7I%
7%6^%)))[#PNd;7%6^%)))[#PNd7%6^%))[#PNd7%6^%))[#PNd7%6^%))[#PPNd7%6^^%))[#PPNd7%
yE13sH!**WE`!DyE13sH!**WE`!yE13sH!*WE`!yE13sH!*WE`!yE13sH!*ZWE`!yE133sH!*ZWE`!yE
aJG'[Y45PP)LDWaJG'[Y45PP)LDWJG'[Y45P)LDWJG'[Y45P)LDWJG'[Y4Z5P)LDWJGG'[Y4Z5P)LDWJ
c0at^0\&`jj'5<c0at^0\&`jj'5<0at^0\&`j'5<0at^0\&`j'5<0at^0.\&`j'5<0aat^0.\&`j'5<0
x6\6TOU%/X"@@1x6\6TOU%/X"@@1x\6TOU%/X"@1x\6TOU%/X"@1x\6(TOU%/X"@1xx\6(TOU%/X"@1x
!#<(z6'E%;?'%!!#<(z6'E%;?'%!!#(z6'E%;?'%!#(z6'E%;?'%!|#(z6'E%;?'%%!|#(z6'E%;?'%%
3v7+78bg]tXTZK3v7+78bg]tXTZK3v778bg]tXTZK3v78bg]tXcTZK3v78bg]tXccTZK3v78bg]tXccT
W:&^"_Ra1eHssyW:&^"_Ra1eHssyW:&^_Ra1eHssyW:&^_Ra1eHssyW:&^_Ra1eeHssyW:&^_Ra1eeHs
W#\|wg1_k_yrzAW#\|wg1_k_yrzAW#\|w1_k_yrzAW#\|w1_k_yrzAW#\|w1_kk_yrzAW#\|w1_kk_yr
^_Fg,X+aAg/-Vy^_Fg,X+aAg/-Vy^_Fg,X+Ag/-Vy^_Fg,X+Ag/-Vy^_Fg,XX+Ag/-Vy^_Fg,XX+Ag/-
S`9%>>E]7(492AS`9%>>E]7(492AS`9%>>E]7492AS`9%>>E]7492AS`9%%>>E]7492AS`9%%>>E]749
/J:@3-vDU;.%=3/J:@3-vDU;.%=3/J:@3-vDU;.=3/J:@3-vDU;.=3/JJ:@3-vDU;.=3/JJ:@3-vDU;.
'\n/-DhREKk{E#'\n/-DhREKk{E#'\n/-DhREKk{E#\n/-DhREKk{{E#\n/-DhREKk{{E#\n/-DhREKk
^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w

ex1.c

/*
 * Example C code 1, for simple SIRDS scheme
 * 
 * (C) Copyright 1994 By Peter Chang <Peter.Chang at nottingham.ac.uk>
 * 
 * The output is a SIRTS (single image random text stereogram)
 * of a sphere, though the aspect ratio of text characters
 * will make this look like an ellipsoid.
 * 
 * Due to the limited resolution of using text characters, the result
 * will be very layered.
 * It looks like a pile of discs of decreasing size.
 * 
 * To compile under UNIX, use something like this:
 *   cc -ansi -O ex1.c -lm
 * 
 * Things to be done by you, the reader, include putting in
 * the graphics stuff, some error checking and a user interface --
 * whether it be a straightforward command line interface or
 * a fancy GUI.
 * 
 * It is assumed that the graphics library uses the following
 * coordinate system: upper left is the origin (0,0) and x,y increase
 * in the rightward and downward direction, respectively.
 * 
 * Possible problems include the restrictive memory architecture
 * of personal computers and their operating systems.
 * For example, the IBM PC and its clones running {MS,DR,PC}-DOS
 * only allow a program to access 640K of memory directly.
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define VD  (300.0*pmm) /* Viewing distance from screen (in pixels) */
#define ES  (65.0*pmm)  /* Eye separation */
#define OS  (150.0*pmm) /* Offset into screen */
 
#define MYLOW -32000
#define MYHIGH 32000

/*
 * This define statement controls the number of different text
 * characters used by the program to make the SIRTS
 * If you want to use just two characters ('!' and '"')
 * then comment it out.
 */
#define MANYCHARS

typedef struct {
   int t;
   int f;
} Llist; /* Link list structure, contains 'to' and 'from' indices */

int width, height; /* dimensions of final picture, in pixels */

/*
 * this is set for ASCII text output with a fixed width of 6 pixels
 * (ie. an xterm with 'fixed' font) on a monitor with 100dpi resolution
 */
float pmm = 0.656;   /* resolution in pixels per mm */

unsigned int *dtos = NULL;
                     /* pointer to lookup table for depth to separation */
int density = 127; /* density of dots, out of 255 */


int main()
{
   int **ztop = NULL; /* z-buffer */

   void zfillall(int **zbuf);
   void drawsirds(int **zbuf);
   int **zmema(void);
   void zmemf(int **zbuf);

   width = 80; /* set these two values to whatever you want */
   height = 50;
   ztop = zmema();
   zfillall(ztop);
   drawsirds(ztop);
   zmemf(ztop);
   exit(EXIT_SUCCESS);
}


/*
 * Defines z-values for all objects using discretised height fields
 */
void zfillall(int **zbuf)
{
   int x, y;
   int *zll;
   int bv, iv;

   void drawobj(int **zbuf);

   iv = MYLOW;

   for (y=0; y<height; y++) { /* set background to const initially */
      zll = zbuf[y];
      for (x=0; x<width; x++) {
         *zll++ = iv;
      }
   }

   drawobj(zbuf);

   bv = 0;
   for (y=0; y<height; y++) { /* reset background to 0 */
      zll = zbuf[y];
      for (x=0; x<width; x++, zll++) {
         if (*zll == iv) *zll = bv;
      }
   }
}


/*
 * as an example, let's fill in the z-values of hemisphere of radius
 * height/2
 */
void drawobj(int **zbuf)
{
   int ox, x, y, z, t;
   register int oy, tx, ty;
   int *zline;

   int hemisphere(register int tx, register int ty, register int oy);

   ox = width/2;
   oy = height/2;

   ty = oy;
   for (y=0; y<height; y++, ty--) {
      zline = zbuf[y];
      tx = -ox;
      for (x=0; x<width; x++, tx++, zline++) {
         z = *zline;
         t = hemisphere(tx, ty, oy);
/* this line is all important, it's the essence of a z buffer */
         if (t > z) *zline = t;
      }
   }
}


/*
 * a hemisphere function,
 * you can try one of your own instead
 */
int hemisphere(register int tx, register int ty, register int oy)
{
   float tt;

   tt = oy*oy - tx*tx - ty*ty;
   return (tt > 0.0) ? (int) sqrt(tt) : 0;
}


/*
 * generate and output SIRDS
 */
void drawsirds(int **zbuf)
{
   int x, y, pixpos;
   int *zline;
   Llist *same; /* doubly-linked list of matching points */
   unsigned char *pixarray; /* holds the colours of a row */
   unsigned int *nowdtos = NULL; /* pointer of somewhere in lookup table */
   unsigned int colour;

   unsigned int *lookup (void );
   void sirdssimp(int *zline, Llist *same, unsigned int *nowdtos);
   /* generic graphics routine */
   void DrawPoint(int x, int y, unsigned int colour);

   srand(time(NULL));
   same = (Llist *) malloc(width*sizeof(Llist));
   pixarray = (unsigned char *) malloc(width*sizeof(char));

   nowdtos = lookup();

   /* this is to show the repetition of the background */
   y = *nowdtos;
   printf("Repetition value %d\n", y);
   for (x=0; x<width; x++) {
      printf(((x%y) == 0) ? "x" : " ");
   }
   printf("\n");

   for (y=0; y<height; y++) {
      zline = zbuf[y];
      for (x=0; x<width; x++) { /* initialise matching list */
         same[x].t = x;
         same[x].f = x;
      }
      sirdssimp(zline, same, nowdtos);
      for (x=0; x<width; x++) {
         pixpos = same[x].f;
         colour = (pixpos != x) ? pixarray[pixpos] :
#ifdef MANYCHARS
         /* get a random value from 0 to 255 */
            (rand() & 0xff);
#else
         /* use this for two colours, at a set density */
            ((rand() & 0xff) > density);
#endif
         pixarray[x] = colour;
         DrawPoint(x, y, colour);
      }
   }
   free(same);
   free(pixarray);
   free(dtos);
}


/*
 * a lookup table for calculating the depth to shift info
 */
unsigned int *lookup (void )
{
   int i, range;
   unsigned int *look;
   float qfac, oss, vd;

   oss = 2.0*OS;
   qfac = ES;
   range = (int) (oss+0.5);
   vd = VD + oss;
   if (dtos != NULL) free(dtos);
   dtos = (unsigned int *) malloc (range*sizeof(int));

   look = dtos;
   for (i=0; i<range; i++, look++) {
      *look = (unsigned int) (qfac*(oss-i)/(vd-i)+0.5);
   }
   return dtos+(range/2); /* return pointer to lookup table */
}


/*
 * simple SIRDS scheme, no hidden surface removal
 * 
 * the algorithm derives from the Thimbleby paper
 */
void sirdssimp(int *zline, Llist *same, unsigned int *nowdtos)
{
   register int x, z0, s;
   register short left, right;
   register short st, sl, sr;

   for (x=0; x<width; x++) {
      z0 = *zline++;
      /* works out separation from depth using lookup table */
      s = *(nowdtos+z0);
      left = x - s/2;
      right = left + s;
      if (left >= 0 && right < width) {
         /* now we put in to & from pointers for matching points */
         sl = left;
         sr = right;
         for (st=same[sr].f; st!=sl && st!=sr; st=same[sr].f) {
            if (st > sl) {
               sr = st;
            } else {
               same[sl].t = sr;
               same[sr].f = sl;
               sr = sl;
               sl = st;
            }
         }
         same[sl].t = sr;
         same[sr].f = sl;
      }
   }
}


/* memory (de)allocation for zbuffer */
int **zmema(void)
{
   int i;
   int **zbuf;

   zbuf = (int **) malloc(height*sizeof(int *));
   for (i=0; i<height; i++)
      zbuf[i] = (int *) malloc(width*sizeof(int));
   return zbuf;
}


void zmemf(int **zbuf)
{
   int i;

   if (zbuf != NULL) {
      for(i=0; i<height; i++) free(zbuf[i]);
      free(zbuf);
   }
}

/*
 * Draw a point of a given colour
 * 
 * This is just ASCII output at the moment, ie. a SIRTS output
 */
void DrawPoint(int x, int y, unsigned int colour)
{
   int c;

   /* there are 94 printable ASCII characters from '!' to '~' inclusive */
   c = (colour % 94) + '!';
   printf("%c", c);
   if (x==width-1) printf("\n"); /* fudge to go to next line */
}

ex2.c

/*
 * Example C code 2, for correct-geometry SIRDS scheme
 * 
 * (C) Copyright 1994 By Peter Chang <Peter.Chang at nottingham.ac.uk>
 * 
 * This is incomplete code showing a sketch of the ideas
 * introduced in the text.
 * 
 * Only the elements that differ from ex1.c are given.
 * More importantly, filltriangle() is also missing.
 * 
 * The main deviation from the text is that the two buffers store
 * values of s, which decrease with increasing z.
 * So the buffer fills done by filltriangle() must update each slot
 * only if the new s is less than the old value.
 */

/* sets the tolerance for the comparison of s values */
#define TOLERANCE 1

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define VD  (300.0*pmm) /* Viewing distance from screen (in pixels) */
#define ES  (65.0*pmm)  /* Eye separation */
#define OS  (150.0*pmm) /* Offset into screen */
 
#define MYLOW -32000
#define MYHIGH 32000

#define MANYCHARS

typedef struct {
   int t;
   int f;
} Llist; /* Link list structure, contains 'to' and 'from' indices */

int width, height; /* dimensions of final picture, in pixels */
float pmm = 0.656;   /* resolution in pixels per mm */
int density = 127; /* density of dots, out of 255 */


int main()
{
   int **ztopl = NULL, **ztopr = NULL; /* s-buffers */

   void sfillall(int **zbufl, int **zbufr);
   void drawsirds(int **zbufl, int **zbufr);
   int **zmema(void);
   void zmemf(int **zbuf);

   width = 80; /* set these two values to whatever you want */
   height = 50;
   ztopl = zmema();
   ztopr = zmema();
   sfillall(ztopl, ztopr);
   drawsirds(ztopl, ztopr);
   zmemf(ztopl);
   zmemf(ztopr);
   exit(EXIT_SUCCESS);
}

/*
 * fills s-values for all objects
 */
void sfillall(int **zbufl, int **zbufr)
{
   int x, y;
   int *zll, *zlr;
   int bv, iv;

   void sdrawobj(int **zbufl, int **zbufr);

   iv = MYHIGH;

   for (y=0; y<height; y++) { /* set background to const initially */
      zll = zbufl[y];
      zlr = zbufr[y];
      for (x=0; x<width; x++) {
         *zll++ = iv;
         *zlr++ = iv;
      }
   }

   sdrawobj(zbufl, zbufr);

   /* z-buffer now contains values of s */
   bv = (int) ES*(OS+height/2.0)/(VD+OS+height/2.0); /* z = 0 */

   for (y=0; y<height; y++) { /* reset background */
      zll = zbufl[y];
      zlr = zbufr[y];
      for (x=0; x<width; x++, zll++, zlr++) {
         if (*zll == iv) *zll = bv;
         if (*zlr == iv) *zlr = bv;
      }
   }
}


/*
 * this time let's do a triangle
 * notice that we have two buffers
 */
void sdrawobj(int **zbufl, int **zbufr)
{
   int xa, ya, xb, yb, xc, yc;
   float sa, sb, sc, za, zb, zc;
   float es, oy, vd, vdos;
   float ax, ay, az;
   float bx, by, bz;
   float cx, cy, cz;

   /*
    * The interpolated z-buffer fill is done by this function.
    * Its inputs are the coordinates of the vertices of a triangle
    * and the z-buffer.
    */
   int filltriangle(int x1, int y1, float z1, int x2, int y2, float z2,
               int x3, int y3, float z3, int **zbuffer);

   es = ES;
   vd = VD;
   vdos = vd + OS;
   oy = height/2.0;

   /* let's do an isoceles triangle */
   ax = 0.8*oy; ay = 0.0*oy; az = 0.0*oy;
   bx = -0.7*oy; by = 0.6*oy; bz = 0.3*oy;
   cx = -0.7*oy; cy = -0.6*oy; cz = -0.3*oy;

   za = vd/(vdos - az); /* z' */
   xa = za*ax; /* x' */
   ya = za*ay; /* y' */
   sa = es*(1 - za); /* s */
   xa -= sa/2; /* xL */

   zb = vd/(vdos - bz);
   xb = zb*bx;
   yb = zb*by;
   sb = es*(1 - zb);
   xb -= sb/2;

   zc = vd/(vdos - cz);
   xc = zc*cx;
   yc = zc*cy;
   sc = es*(1 - zc);
   xc -= sc/2;

   /* fill left buffer then right */
   filltriangle(xa, ya, sa, xb, yb, sb, xc, yc, sc, zbufl);
   filltriangle((xa+sa), ya, sa, (xb+sb), yb, sb, (xc+sc), yc, sc, zbufr);
}


/*
 * generate and output SIRDS
 */
void drawsirds(int **zbufl, int **zbufr)
{
   int x, y, pixpos;
   int *zll, *zlr;
   Llist *same; /* doubly-linked list of matching points */
   unsigned char *pixarray; /* holds the colours of a row */
   unsigned int colour;

   void sirdsnew(int *zll, int *zlr, Llist *same);
   /* generic graphics routine */
   void DrawPoint(int x, int y, unsigned int colour);

   srand(time(NULL));
   same = (Llist *) malloc(width*sizeof(Llist));
   pixarray = (unsigned char *) malloc(width*sizeof(char));

   /* no need for lookup table */

   for (y=0; y<height; y++) {
      zll = zbufl[y];
      zlr = zbufr[y];
      for (x=0; x<width; x++) { /* initialise matching list */
         same[x].t = x;
         same[x].f = x;
      }
      sirdsnew(zll, zlr, same);
      for (x=0; x<width; x++) {
	 pixpos = same[x].f;
	 colour = (pixpos != x) ? pixarray[pixpos] :
#ifdef MANYCHARS
	 /* get a random value from 0 to 255 */
	    (rand() & 0xff);
#else
	 /* use this for two colours, at a set density */
	    ((rand() & 0xff) > density);
#endif
	 pixarray[x] = colour;
	 DrawPoint(x, y, colour);
      }
   }
   free(same);
   free(pixarray);
}


/*
 * new SIRDS scheme, with hidden surface removal
 * 
 * the new algorithm discussed in the paper
 */
void sirdsnew(int *zll, int *zlr, Llist *same)
{
   register int s;
   register short left, right;
   register short st, sl, sr;

   for (left=0; left<width; left++) {
      s = *zll++;
      right = left + s;
      if (right < width) {
	 s -= zlr[right];
	 /* check that both eyes can see the point */
	 if (s <= TOLERANCE && s >= -TOLERANCE) {
	    /* now we put in to & from pointers for matching points */
	    sl = left;
	    sr = right;
	    for (st=same[sr].f; st!=sl && st!=sr; st=same[sr].f) {
	       if (st > sl) {
		  sr = st;
	       } else {
		  same[sl].t = sr;
		  same[sr].f = sl;
		  sr = sl;
		  sl = st;
	       }
	    }
	    same[sl].t = sr;
	    same[sr].f = sl;
	 }
      }
   }
}

[Contents, Next, Previous].
Peter Chang: Peter.Chang at nottingham.ac.uk