Article 2717 of comp.sources.unix:
Path: nntpd.lkg.dec.com!crl.dec.com!crl.dec.com!decwrl!spool.mu.edu!howland.reston.ans.net!vixen.cso.uiuc.edu!newsfeed.internetmci.com!in1.uu.net!vixie!vixie!not-for-mail
From: wolf@prosun.first.gmd.de (Wolfgang Koehler)
Newsgroups: comp.sources.unix
Subject: v29i056: grafix-1.2 - a C++ library for easy X11 GUI apps, Part02/05
Date: 1 Dec 1995 11:59:07 -0800
Organization: Vixie Enterprises
Lines: 2982
Sender: vixie@vix.com
Approved: vixie@gw.home.vix.com
Message-ID: <49nmqb$965@gw.home.vix.com>
References: <1.817847834.9257@gw.home.vix.com>
NNTP-Posting-Host: gw.home.vix.com

Submitted-By: wolf@prosun.first.gmd.de (Wolfgang Koehler)
Posting-Number: Volume 29, Issue 56
Archive-Name: grafix-1.2/part02

#!/bin/sh
# This is part 02 of Grafix
# ============= lat_man.c ==============
if test -f 'lat_man.c' -a X"$1" != X"-c"; then
	echo 'x - skipping lat_man.c (File already exists)'
else
echo 'x - extracting lat_man.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'lat_man.c' &&
// File lat_man.c :  lattice_manager - class
X
#include "lattice.h"
extern window root_window;
X 
// to display infos in the lattice_window with Button3 in a moving window
class display_cursor : public window {
public:
X  char val[50];
X  Window ll; // ein Window fuer eine simple vertikale Linie
X  display_cursor(window &parent) : window(root_window,60,20,0,0,1) {
X    // it must be defined as child of root to disable clipping !
X    mainw = (main_window*) this; 
X    XSetWindowAttributes attr; 
X    attr.override_redirect = TRUE; attr.save_under = TRUE;
X
X    XChangeWindowAttributes(display, Win, 
X			    CWOverrideRedirect | CWSaveUnder, 
X			    &attr);
X   
X    ll = XCreateSimpleWindow(display, parent.Win,0,0,2,10,0,0,1);
X    XSelectInput(display, Win, ExposureMask);
X  }
X  void Move(XPoint p, XPoint wpos) { 
X    width = 7*strlen(val); 
X    XMoveResizeWindow(display,Win,p.x-width/2 + wpos.x,p.y-30 + wpos.y,
X		      width, height);     
X    XMoveWindow(display,ll,p.x,p.y-8); 
X    XMapWindow(display,ll); 
X    redraw(); XMapWindow(display,Win);
X  }
X  virtual void redraw() { // clear(); 
X    extern GC button_fg_gc;
X    XFillRectangle(display, Win, button_fg_gc, 0, 0, width, height);
X    PlaceText(val);
X  }
X  void hide() { Unmap(); XUnmapWindow(display,ll); }
};
X
// *************** lattice_manager *************
// class lattice_manager : public lattice_window 
// generates a lattice_window and the buttons to manage it
X
void lattice_manager::set_defaults() { 
X  set_angles(40/grd2rad, 55/grd2rad, 1, 0); 
X  set_toggles(1,1,1,0);
X  init_region();
}
X
void lattice_manager::draw_interior() 
{ char headline[200]; 
X  // WatchCursor(); // show watch cursor here   
X  alpha = fmod(alpha, 2.0*M_PI); // normalization of alpha
X  make_body(nx, ny, qptr, alpha, beta, gamma, z0, opaque, dist, 
X	    a_light,b_light);
X  
X  //  make_lattice(nx, ny, qptr, alpha, beta, gamma, z0, opaque, dist);
X  // ResetCursor(); and reset it again
X  sprintf(headline,"alpha = %d beta = %d gamma = %g d =%5.2f",
X	  (int) (alpha*grd2rad), (int) (beta*grd2rad), gamma,dist); 
X  PlaceText(headline,0,height - 10); 
X  // unterer Rand,
}
X
// draws with-moving display-window in original[ x,y,z ]
static display_cursor *dpcur = NULL;
X
static int ixdp, iydp;
void lattice_manager::show_infos (XButtonEvent *ev) { 
X  // back transformation for a point in the   x,y-plane
X  // mouse-coordinates (px,py) -> index-coordinates (ix,iy)
X  /*  float xs = x_org(ev->x), ys = y_org(ev->y)/cb,
X      x = ca*xs + sa*ys + xp, y = ca*ys - sa*xs + yp;
X      int ix = (int) (x+0.5) + ixstart, iy = (int) (y+0.5) + iystart;  
X   */
X  XPoint (*scp)[ny] = (XPoint (*)[ny]) scptr; // array of grid values
X  float (*ff)[ny] = (float (*) [ny]) qptr; // array of function values
X
X  // new : search for next grid point to cursor pos (real height)
X  int ix = ixstart, iy = iystart, delta, delmin = 1000000;
X  for (int ixt = ixstart; ixt < ixend; ixt++) 
X    for (int iyt = iystart; iyt < iyend; iyt++) {    
X      XPoint sxy = scp[ixt][iyt];
X      delta = SQR(ev->x - sxy.x) + SQR(ev->y - sxy.y);
X      if (delta < delmin) { delmin = delta; ix = ixt; iy = iyt; }
X    }
X  if (dpcur == NULL) dpcur = new display_cursor(*this);
X  if (ix < ixstart || ix >= ixend || iy < iystart || iy >= iyend) return; 
X
X  if (ix != ixdp || iy != iydp) {
X    ixdp = ix; iydp = iy;
X    sprintf(dpcur->val,"x: %d y: %d z: %g",ix,iy,ff[ix][iy]); 
X    // wpos : absolute coords of window (rel to root)
X    XPoint wpos = { ev->x_root - ev->x, ev->y_root - ev->y };
X    dpcur->Move(scp[ix][iy], wpos);    
X  } 
}
X
/* move the lattice with mouse pointer :
X   an arbitrary point (to be thought in the co-ordinate plane z=0)
X   can be clicked on with left button (usually the origin)
X   then it can be drawn with the pointer and the new reference frame
X   moves along with it.
*/
static int xctr,yctr; 
static float phi, yzs, r2; // parameter for computing new alpha, beta
static XPoint scoord[6];
static Bool clear_old;
X
void lattice_manager::BPress_1_CB(XButtonEvent ev) {  
X  xctr = width/2; yctr = height/2; // centred co-oordinates, start values
X  int xs = ev.x - xctr, ys = ev.y - yctr; 
X  float xsf = xs/float(width); // norming because aspect-verzerrung
X  yzs = ys/cb/height; r2 = SQR(yzs) + SQR(xsf);
X  phi = alpha + atan2(yzs,xsf); 
X  clear_old = False;
}
X
void lattice_manager::BPress_3_CB(XButtonEvent ev) {
X  ixdp = -1; // make sure it is new point
X  show_infos(&ev);
}
X
void lattice_manager::BRelease_CB(XButtonEvent ev) 
{ if (ev.state & Button1Mask) redraw(); else
X    if (ev.state & Button3Mask) dpcur->hide();
}
X
// draws the pulled co-ordinate system 
void temp_coord(Window Win, int /* body */, XPoint scoord[]) {
X  int i;
X  for (i=0; i<3; i++) XDrawLines(display,Win,gc_rubber,
X				 scoord + 2*i, 2, CoordModeOrigin);
}
X
void lattice_manager::Motion_CB(XMotionEvent ev) { 
X if (ev.state & Button1Mask) { // button 1 is pressed
X   int xss = ev.x - xctr, yss = ev.y - yctr;
X   if (SQR(xss) + SQR(yss) < 10) return; // too indifferent
X   float xsf = xss/float(width), ysf = yss/float(height);
X   float nom = r2 - SQR(ysf) - SQR(xsf);
X   if (nom < 0) return; // oder : beta = 0;
X   beta = atan2(sqrt(nom), fabs(ysf)); 
X   // if ysf is used instead of fabs(ysf) -> the bottom view is shown
X   // instead of rear view
X   alpha = phi  - atan2(ysf/cos(beta),xsf); 
X   
X   if (clear_old) temp_coord(Win,body,scoord); // delete old frame
X   clear_old = True;
X   ca = cos(alpha); sa = sin(alpha); cb = cos(beta); sb = sin(beta);
X     
X   scoord[0] = scoord[2] = scoord[4] = screen_project(0,0,0);
X   scoord[1] = screen_project(0,0,zmax); 
X   scoord[3] = screen_project(xspan,0,0);
X   scoord[5] = screen_project(0,yspan,0);
X   temp_coord(Win,body,scoord);
X } else if (ev.state & Button3Mask) show_infos((XButtonEvent*) &ev); 
}
X
// the arrow-keys turn the image for 5 grd
void lattice_manager::KeyPress_CB(XKeyEvent ev) 
{ KeySym keysym = XLookupKeysym(&ev,0);
X  /*char * sym = XKeysymToString(keysym);
X    printf("0x%x sym = '%s'\n", keysym,sym);
X    */
X  int change = TRUE;
X  switch (keysym) {
X  case XK_Left:  alpha -= 0.1; break;
X  case XK_Right: alpha += 0.1; break;  
X  case XK_Up:    beta += 0.1; break;
X  case XK_Down:  beta -= 0.1; break;
X  default: change = FALSE;
X  }
X  if (change) redraw();
}
X
// makes button with special callback-function for changing a T-value 
// with the pointer "T *ref" and the passed value "T val"
template <class T>
class modifier_button : public button { 
lattice_manager * lat; 
void (lattice_manager::*callback)(T*,T);
T *v1, v2;
public:
X  modifier_button(menu_bar &parent,char * Name, 
X		  void (lattice_manager::*cb)(T*,T), 
X		  lattice_manager *lm, T *ref, T val) :
X    button(parent,Name) { callback = cb; lat = lm; v1 = ref; v2 = val;}
X  virtual void BRelease_1_action() { (lat->*callback)(v1,v2); }
};
X
X
static char *lattice_help[] = { 
X "To toggle between the grid- and body-mode use the 'body' button", 
X "To change the viewpoint use the mouse pointer :",
X "By clicking an arbitrary point in the xy-plane (test first with origin)",
X "with the left mouse button and pulling it, a temporary co-ordinate system",
X "is shown which will become the new cs when the button is released","",
X "The other buttons in the two bottom rows are used to change the view :",
X "a+/-  : rotate the x,y-plane (horizontal) for 5 grd",
X "b+/-  : rotate the y,z-plene (vertical 'tilting') for 5 grd",
X "Additionally the 4 arrow keys can be used to rotate the lattice","", 
X "z+/-  : enlarges/reduces height for 25 percent",
X "z0+/- : shifting the zero level of the displayed lattice",
X "d+/-  : shift perspective projection distance for +/- 1%","",
X "                          Toggle Buttons ",
X "rand     : show the lines on the border ",
X "opaque   : toggle to show hidden lines (in grid-mode)",
X "           and toggle illumination mode (in body-mode)", 
X "body     : toggle between the grid- and body-mode",
X "flat     : toggle between 'flat' and 3d-perspective",
X "dump     : makes X-Window dump-file 'lattice.dump' of the actual picture",
X "hardcopy : analogue dump directly to lpr","",
X "region   : pops up a window to define an displayed part (zooming)",
X "palette  : popup for setting the color palette (for body-mode)",
X "light    : popup for setting the incidence angle of light source (body-mode)",
X "clone    : make a copy of the lattice which maps the same array, and thus",
X "           will be also be updated (if part of an integration)", 
X 0 };
X
lattice_manager::lattice_manager(window & parent, int w, int h, int x, int y,
X				 int nxp, int nyp, float * q) : 
lattice_window(parent,w,h-40,x,y), nx(nxp), ny(nyp), qptr(q)
{ 
X  selection_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
X                    KeyPressMask;  // enable Keypress events
X  set_defaults(); z0 = 0;
X  int bh = 20;
X  
X  // the menu-bars are placed on the lattice-window (bottom)
X  mb1 = new menu_bar(parent, w, bh, x, y+h-40, 30, 100, 0);
X  mb2 = new menu_bar(parent, w, bh, x, y+h-20, 30, 100, 0);
X  // there is only one global palette also if there are many lattice manager
X  if (pal_win == NULL) 
X    pal_win = new palette_popup(ncolors); // popup for palette
X  light_win = new light_popup(this,240);
X  region_win = new main_window("region manager",200,222);
X  region_int = new region_manager(*region_win,this);
X  clone_lm = NULL;
X
X  new modifier_button <float> (*mb1,"a+", inc_float,this,&alpha,0.1);
X  new modifier_button <float> (*mb2,"a-", inc_float,this,&alpha,-0.1);
X
X  new modifier_button <float> (*mb1,"b+", inc_float,this,&beta,0.1);
X  new modifier_button <float> (*mb2,"b-", inc_float,this,&beta,-0.1); 
X
X  new modifier_button <float> (*mb1,"z+", mult_float, this, &gamma, 1.25); 
X  new modifier_button <float> (*mb2,"z-", mult_float, this, &gamma, 0.80); 
X  
X  new modifier_button <float> (*mb1,"z0+", inc_z0, this, &z0, -0.1); 
X  new modifier_button <float> (*mb2,"z0-", inc_z0, this, &z0, 0.1); 
X    
X  new modifier_button <float> (*mb1,"d+", inc_float, this, &dist, 0.01);   
X  new modifier_button <float> (*mb2,"d-", inc_float, this, &dist, -0.01);  
X
X  new toggle_redraw_button(*mb1," rand ",&rand,this);
X  new toggle_redraw_button(*mb2,"opaque",&opaque,this);
X    
X  new toggle_redraw_button(*mb1," body ",&body,this); 
X  new toggle_redraw_button(*mb2," flat ",&flat_mode,this);
X
X  // hardcopy of the inner window !
X  new xwd_button(*mb1,"  dump  ","-out lattice.dump",this);
X  new xwd_button(*mb2,"hardcopy"," | xpr | lpr",this);
X 
X  new popup_button (*mb1,  pal_win,"palette");
X  new popup_button (*mb2,light_win," light ");
X  new instance_button <lattice_manager> (*mb1,"default",
X  					 &lattice_manager::default_draw,this);
X  // new instance_button <lattice_manager> (*mb1,"rotate",
X  //                                        &lattice_manager::rotate,this);
X  
X  new instance_button <lattice_manager> (*mb2," clone ",
X					 &lattice_manager::make_clone, this);
X  new popup_button (*mb1,region_win,"region");
X  new help_button (*mb2,            " help ",lattice_help);
X 
}
X
lattice_manager::~lattice_manager() { 
X  safe_delete(light_win); // safe_delete checks first if the windows are deleted
X  safe_delete(region_win); // already implicitely from root_window before del.
X  if (clone_lm) safe_delete(clone_lm);
}
X
lattice_manager* lattice_manager::make_popup(char * Name,float *q) {
X  main_window *pp = new main_window(Name,width,height+20);
X  lattice_manager* lm = new lattice_manager(*pp,width,height,0,20,nx,ny,q);
X  lm->set_toggles(body, rand, opaque, flat_mode);
X  lm->set_angles(alpha, beta, gamma, dist);  
X  return lm;
}
X
void lattice_manager::delete_clone() {
X  clone_lm->mainw->Unmap();
X  delete clone_lm->mainw;
X  clone_lm = NULL;
}  
X
void lattice_manager::make_clone() { 
X  if (clone_lm) return; // only one clone possible, but it may be chained
X  clone_lm = make_popup("clone",qptr);  
X  main_window *pp = clone_lm->mainw;  // for accessing the popup-Window
X
X  // the button for deleting the clone is on the popup of the clone 
X  new instance_button <lattice_manager> (*pp, "delete",
X		      &lattice_manager::delete_clone, this, 100, 20,0,0);
X  pp->do_popup(0,0);
}
X
SHAR_EOF
chmod 0644 lat_man.c ||
echo 'restore of lat_man.c failed'
Wc_c="`wc -c < 'lat_man.c'`"
test 12071 -eq "$Wc_c" ||
	echo 'lat_man.c: original size 12071, current size' "$Wc_c"
fi
# ============= reg_man.c ==============
if test -f 'reg_man.c' -a X"$1" != X"-c"; then
	echo 'x - skipping reg_man.c (File already exists)'
else
echo 'x - extracting reg_man.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'reg_man.c' &&
// reg_man.c : region_manager class && light_popup - window
//    auxiliary objects for lattice_manager
X
#include "lattice.h"
X
int sqabs(XPoint p1, XPoint p2) {
X  int dx = p1.x - p2.x, dy = p1.y - p2.y;
X  return (dx*dx + dy*dy);
}
X
// ********************** Region manager *********************
X
#define LOWER(x) ((x > 0) ? (x--) : 0)
#define HIGHER(x,nx) ((x < nx) ? (x++) : nx)
X 
void region_manager::init_region() { 
X   lm->init_region(); 
X   lm->redraw();
X }
X
void region_manager::rise() { 
X  int i; 
X  int xb = lm->xspan;
X  for (i=0; i< xb/10 + 1; i++) { 
X    LOWER(lm->ixstart);  LOWER(lm->iystart); 
X  }
X  int yb = lm->yspan;
X  for (i=0; i< yb/10 + 1; i++) { 
X    HIGHER(lm->ixend,nx); HIGHER(lm->iyend,ny);
X  }
X  lm->redraw();
}
X
void region_manager::shrink() { 
X  int xb,yb;
X  xb = lm->xspan;
X  zc.x = (lm->ixend + lm->ixstart)/2;
X  zc.y = (lm->iyend + lm->iystart)/2;
X  if (xb > 4) { // Schrumpfen auf 6/7 dh. -15%
X    lm->ixstart = MAX(zc.x - (3*xb)/7, 0);  
X    lm->ixend = MIN(zc.x + (3*xb)/7, nx);
X  } 
X  yb = lm->yspan;
X  if (yb > 4) { 
X    lm->iystart = MAX(zc.y - (3*yb)/7, 0);  
X    lm->iyend = MIN(zc.y + (3*yb)/7, ny);
X  }   
X  lm->redraw();
}
X
region_manager::region_manager(window &parent, lattice_manager *lm) : 
X  coord_window(parent,parent.width,parent.height-20,0,20,5,5,5,5), 
X  nx(lm->nx), ny(lm->ny), lm(lm) {
X   
X    selection_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
X    menu_bar *mb = new menu_bar(parent,parent.width,20,0,0,50,100,0);
X  
X    new instance_button <region_manager>(*mb,"complete",
X					 &region_manager::init_region,this);
X    new instance_button <region_manager>(*mb,">>",
X					 &region_manager::rise, this);
X    new instance_button <region_manager>(*mb,"<<",
X					 &region_manager::shrink, this);
X    new unmap_button(*mb,"close",&parent);     
X    zc.x = (nx-1)/2; zc.y = (ny-1)/2;
X  }
X
void region_manager::draw_interior() {
X  xmax = nx-1; ymax = ny-1; 
X  int nn = (nx > ny) ? nx : ny; // to get a quadratic grid
X  define_coord(0,0,nn-1,nn-1);
X
X  int xstart = x_window(lm->ixstart), xend = x_window(lm->ixend - 1),
X      ystart = y_window(lm->iystart), yend = y_window(lm->iyend - 1);
X  
X  static XGCValues values = {0,0, pal_win->color_cells[80].pixel }; 
X  static GC gccol = CreateGC(GCForeground, &values);
X  XFillRectangle(display,pix,gccol,xstart,yend,xend-xstart,ystart-yend);
X  int i, di = MAX( (4*nn)/width + 1, 1); // printf("di = %d\n",di);
X  for (i=0; i<ny; i+=di) wline(0,i,xmax,i);
X  for (i=0; i<nx; i+=di) wline(i,0,i,ymax);
}
X
// returns grid index of mouse pointer in [(xo,yo),(xo+1,yo+1)]
XXPoint region_manager::raster(int x, int y) {
X  int xo = (int) x_org(x), yo = (int) y_org(y); // truncated part
X  XPoint pp = { (xo < 0) ? 0 : (xo > nx-2) ? nx-2 : xo, 
X		(yo < 0) ? 0 : (yo > ny-2) ? ny-2 : yo };
X  return pp;
}
X
XXPoint region_manager::p_window(float x, float y) {
X  XPoint pp = { x_window(x), y_window(y) }; 
X  return pp; 
} 
X
// draws rectangle (inverting) in real world-coordinates 
// with [(x,y) (x+dx,y+dy)] directly into display-window (temporaer)
void region_manager::mark_rect(float x0, float y0, float dx, float dy) {
X  static XGCValues val; 
X  val.foreground = black; val.line_width = 2;
X  static GC gc_thick = CreateGC(GCForeground | GCLineWidth ,  &val); 
X  XPoint z1 = p_window(x0,y0+dy); // linke OBERE Ecke
X  int w = int(xf*dx + 0.5), h = int(yf*dy + 0.5); 
X  XDrawRectangle(display,Win,gc_thick, z1.x, z1.y, w, h);
}
X
// draws rectanle in integer world-coordinates (temporaer)
void region_manager::Rectangle(GC gc, XPoint p1, XPoint p2) {
X  XPoint z1 = p_window(p1.x,p1.y), z2 = p_window(p2.x,p2.y);
X  XDrawRectangle(display,Win,gc,z1.x-1, z2.y-1,  
X		 z2.x - z1.x + 2, z1.y - z2.y + 2);
X  /*  Anzeige des Ausschnitts im Originalbild : */
X  // if (! lm->body) return; // not yet ready !!
X  int xn = p2.x-p1.x+1, yn = p2.y-p1.y+1;
X  int i,x,y,pi;
X  // das Feld der Gitterwerte
X  XPoint (*scp)[lm->ny] = (XPoint (*)[lm->ny]) lm->scptr;
X  XPoint p[xn + yn]; 
X  int xb[2] = {MAX(p1.x, lm->ixstart), MIN(p2.x, lm->ixend-1)}, 
X      yb[2] = {MAX(p1.y, lm->iystart), MIN(p2.y, lm->iyend-1)};
X  // printf(" %d %d %d %d \n",xb[0],xb[1],yb[0],yb[1]);
X  for (i = 0; i< 2; i++) {
X    y = yb[i]; 
X    if (y >= lm->iystart &&  y < lm->iyend) {
X      for (x= xb[0], pi=0; x <= xb[1]; x++, pi++) p[pi] = scp[x][y];
X      if (pi>0) XDrawLines(display,lm->Win,gc,p,pi,0); 
X    } 
X    x = xb[i]; 
X    if (x >= lm->ixstart &&  x < lm->ixend) {
X      for (y= yb[0], pi=0; y <= yb[1]; y++, pi++) p[pi] = scp[x][y];
X      if (pi>0) XDrawLines(display,lm->Win,gc,p,pi,0); 
X    }
X  }
}
X
void region_manager::BPress_1_CB(XButtonEvent ev) {
X  pstart = raster(ev.x, ev.y); 
X  pmin = pstart; pmax.x = pmin.x+1; pmax.y = pmin.y+1;
X  Rectangle(gc_rubber,pmin,pmax);
X  pact = pstart;
}
X
void region_manager::BRelease_CB(XButtonEvent) {    
X  Rectangle(gc_rubber,pmin,pmax);
X  if ( 100 * sqabs(pmax,pmin) < 800 + SQR(lm->xspan) + SQR(lm->yspan)) return; 
X  // region too small if not 10% + 2x2 grids
X  lm->ixstart = pmin.x; lm->ixend = pmax.x+1;
X  lm->iystart = pmin.y; lm->iyend = pmax.y+1;
X  redraw(); lm->redraw();
}
X
void region_manager::Motion_CB(XMotionEvent ev) { 
X  if (ev.state & Button1Mask) { // Button 1 gedrueckt
X    XPoint pp = raster(ev.x,ev.y); 
X    if (pp.x != pact.x || pp.y != pact.y) {
X      pact = pp; 
X      Rectangle(gc_rubber,pmin,pmax);
X      pmin.x = MIN(pstart.x,pp.x); pmin.y = MIN(pstart.y,pp.y);
X      pmax.x = MAX(pstart.x,pp.x) + 1; pmax.y = MAX(pstart.y,pp.y) + 1;
X      Rectangle(gc_rubber,pmin,pmax);
X    }
X  }
}
X
// ********** the light popup window *************
// setting the incidence angle of the light source
X
static void update_light(light_popup * lp) { 
X  lp->lm->a_light = lp->sc_alpha->value/grd2rad;
X  lp->lm->b_light = lp->sc_beta->value/grd2rad;
X  if (lp->immediate) lp->lm->redraw();
}
X
light_popup::light_popup(lattice_manager *latm, int w) 
: main_window("light",w+10,100) {    
X  lm = latm; 
X  immediate = FALSE;
X  int y = 5;
X  sc_alpha = new scrollbar(*this, update_light, this, w,20,5,y,0,360,30); 
X  y+= 30;
X  sc_beta  = new scrollbar(*this, update_light, this, w,20,5,y,0,180,5); 
X  y+= 40;
X  int x = 5, wb = w/3; 
X  
X  new instance_button <pixmap_window> 
X    (*this,"redraw",&pixmap_window::redraw,lm,wb,20,x,y);  
X  x+= wb;
X  new toggle_button(*this,"immediate",&immediate,wb,20,x,y); x+= wb;
X  new unmap_button(*this,"close",wb,20,x,y);
X  update_light(this); // init values
}
X
X
SHAR_EOF
chmod 0644 reg_man.c ||
echo 'restore of reg_man.c failed'
Wc_c="`wc -c < 'reg_man.c'`"
test 6420 -eq "$Wc_c" ||
	echo 'reg_man.c: original size 6420, current size' "$Wc_c"
fi
# ============= lattice.h ==============
if test -f 'lattice.h' -a X"$1" != X"-c"; then
	echo 'x - skipping lattice.h (File already exists)'
else
echo 'x - extracting lattice.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'lattice.h' &&
#include <stdlib.h>
#include <math.h>
#include "window.h"
#include "palette.h"
X
#define SQR(x) ((x)*(x))
X
extern "C" double sqrt(double);
extern int sqabs(XPoint p1, XPoint p2);
X
extern float grd2rad;            // conversion grad -> radiant	
extern palette_popup *pal_win;   // the palette_window
X
class lattice_window : public coord_window {
X  int *y_bot, *y_top;
protected:
X  float ca,sa,cb,sb,dist,xp,yp,zmax,znorm;
X  int *external_colors;     // if to use own colors for painting the surfaces n
X                            // instead of computing them from light source   
X
X  int ncolors;  // number of colors for body && palette
X  Bool flat_mode; // no 3-dim perspective
X
X  void pline(XPoint a, XPoint b) // draws lines uncoditionally
X   { line(a.x,a.y,b.x,b.y); }
X
X  void cline(XPoint a, XPoint b, int lastp);
X  void fill(XPoint a, XPoint b, int lastp, int inside);
X
X  void xline(XPoint a, XPoint b, int lastp) { 
X    if (opaque) cline(a,b, lastp);  else pline(a,b); }
X  struct XPoint screen_project(float x, float y, float z);
X
public:
X  struct XPoint *scptr; // array of transformed grid points as  [nx][ny] 
X  int ixstart,iystart,// the start indicees for the representation from qq-array
X      ixend, iyend;
X  int xspan, yspan;  // the max values of x,y in org.
X  int opaque; 
X  int rand;  // 0 : with border lines
X  int body;  // toggle between lattice and body display
X
X  lattice_window(window & parent, int w, int h, int x, int y);
X
X  virtual ~lattice_window() { delete[] scptr;}
X 
X  // alpha, beta : rotation angles (here rad!), gamma : z-factor,
X
X  void make_body(int nx, int ny, float *FF, 
X		 float alpha, float beta, float gamma,  float z0, int opaque, 
X		 float distance, float al, float bl);
};
X
class lattice_manager;
X
class region_manager : public coord_window {
X  int &nx,&ny;     //  references to  lm->nx, lm->ny !!
X  float xmax,ymax;
public:
X  lattice_manager * lm;
X  XPoint zc;   // zoom centre
X
X  void init_region();
X  void rise();
X  void shrink();
X
X  region_manager(window &parent, lattice_manager *lm);
X  virtual ~region_manager() {}
X  virtual void draw_interior();
X
X  XPoint raster(int x, int y);
X  XPoint p_window(float x, float y) ;
X  void mark_rect(float x0, float y0, float dx, float dy) ;
X  void Rectangle(GC gc, XPoint p1, XPoint p2); 
X
X  XPoint pstart, pact, pmin, pmax;
X  virtual void BPress_1_CB(XButtonEvent ev);
X  virtual void BRelease_CB(XButtonEvent ev);
X  virtual void Motion_CB(XMotionEvent ev);
};
X
// generates a lattice_window and the buttons to manage it
class lattice_manager : public lattice_window {
private:
X  menu_bar *mb1,*mb2; // the two menu  lines at the bottom
protected:
X  main_window *light_win, // the popup for light incidence angles
X              *region_win;  // popup for  region_manager 
X  region_manager *region_int;  // the region_manager (for redraw-ops)
X  lattice_manager * clone_lm;  // a list of clone copies (resp. NULL)
X
public:
X  int nx, ny; // the grid dimensions
X  float *qptr; // pointer to 2-d array with grid values of the function
X  float alpha, beta, a_light, b_light;
X  float dist, gamma, z0;
X
X  void init_region() { ixstart = 0; ixend = nx; iystart = 0; iyend = ny; }
X
X  void set_toggles(int pbody, int prand, int popaque, int pflat) 
X    { body = pbody; rand = prand; opaque = popaque; flat_mode = pflat; } 
X
X  void set_angles(float palhpa, float pbeta, float pgamma, float pdist)
X    { alpha = palhpa; beta = pbeta; gamma = pgamma; dist = pdist; }
X
X  void set_defaults();
X
X  lattice_manager(window & parent, int w, int h, int x, int y, int nx, int ny,
X		  float * q);
X    
X  virtual ~lattice_manager();
X
X  // changing the grid 
X  void respace(int nxp, int nyp) { 
X    nx = nxp; ny = nyp;  
X    init_region(); 
X    if (clone_lm) clone_lm->respace(nxp,nyp);
X  }
X
X  void default_draw() { // for default button
X     set_defaults(); redraw();
X  } 
X
X  virtual void redraw() {
X    lattice_window::redraw(); region_int->redraw(); 
X  }
X  void redraw_clones() {
X    redraw(); if (clone_lm) clone_lm->redraw_clones();
X  }
X  void show_infos(XButtonEvent*);
X  void draw_interior();
X  void action(char*, char* ) { }
X
X  void rotate_alpha(float delta) { alpha += delta; redraw(); }
X
X  // Callback-functions for display buttons 
X  void mult_float(float *val, float increment) { *val *= increment; redraw();}
X  void inc_int(int *val, int increment)   { *val += increment; redraw(); }
X  void inc_float(float *val, float increment) { *val += increment; redraw(); }
X  void inc_z0(float *val, float increment) // used for z0 shifting
X    { *val += increment/gamma; redraw(); }
X
X  void toggle(int *ref, int v) { *ref ^= v; redraw();}
X  
X  // Mouse drawing of the cordinate system, for quick change of viewpoint
X  virtual void BPress_1_CB(XButtonEvent ev);
X  virtual void BPress_3_CB(XButtonEvent ev);
X
X  virtual void Motion_CB(XMotionEvent ev);
X  virtual void BRelease_CB(XButtonEvent ev);
X
X  // the arrow-keys turn the image for 5 grd
X  virtual void KeyPress_CB(XKeyEvent ev);
X
X  // produces a popup with the same parameters as actual
X  lattice_manager* make_popup(char *Name, float *q);
X
X  // produces an identical copy of the picture with same array
X  void make_clone();
X  void delete_clone();
};
X
class light_popup : public main_window {
X public:
X  lattice_manager *lm; // the corresponding lattice_manager
X  int immediate;
X  scrollbar *sc_alpha, *sc_beta;
X  light_popup(lattice_manager *latm, int w);
};
X
// to display the headline in an lattice_manager window : 
// uses pixmap_window to avoid flickering
class head_line : public pixmap_window { 
public:
X  char str[200];
X  head_line(window &parent, int w, int h, int x, int y) :
X    pixmap_window(parent,w,h,x,y,0) { }
X  virtual void draw_interior()  { PlaceText( str ); }
};
X
SHAR_EOF
chmod 0644 lattice.h ||
echo 'restore of lattice.h failed'
Wc_c="`wc -c < 'lattice.h'`"
test 5700 -eq "$Wc_c" ||
	echo 'lattice.h: original size 5700, current size' "$Wc_c"
fi
# ============= palette.c ==============
if test -f 'palette.c' -a X"$1" != X"-c"; then
	echo 'x - skipping palette.c (File already exists)'
else
echo 'x - extracting palette.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'palette.c' &&
#include "window.h"
#include "palette.h"
X
unsigned palette_popup::palind(int min, int max, int i) {
X  if (ncolors == 0) return 0;
X  float f = (((float) i) * (max-min)) / ncolors;  
X  int xi =  min + (int) f;
X  if (xi < 0) return 0;
X  if (xi > 0xffff) return 0xffff; else return xi;
}
X
// not very efficient : if all scrollbars are set, this is called 3 times !!
void palette_popup::paint() { 
X  for (int i = 0; i < ncolors; i++) { 
X    XColor *xcol = &color_cells[i];
X    unsigned r = palind(smin[0]->value,smax[0]->value,i);
X    unsigned b = palind(smin[1]->value,smax[1]->value,i);
X    unsigned g = palind(smin[2]->value,smax[2]->value,i);
X    if (True_Color_Visual) xcol->pixel = alloc_color(r,g,b); 
X    else {
X      xcol->red = r; xcol->blue = b; xcol->green = g;
X      XStoreColor(display,def_cmap,xcol);
X    }
X  }
X  if (True_Color_Visual && redraw_win)  { // this should be really a list !
X    redraw_win->redraw(); // printf("%x\n",redraw_win);
X  }
}
X
// a window to display color bars
class palette_display : public window {
X  GC gc;  
X  XGCValues values; 
X  palette_popup *pp;
public:
X  palette_display(window &parent, int w, int h, int x, int y, 
X		  palette_popup *pp) : 
X  window(parent,w,h,x,y), pp(pp) { 
X    values.foreground = 0;
X    gc = CreateGC(GCForeground, &values); 
X    pp->redraw_win = this; // I will be redrawed !!
X  }
X  virtual void redraw() { 
X    int i, x = 0, nc = pp->ncolors; if (nc == 0) return;
X    int dx = width/nc + 1;
X    for (i = 0; i < nc; i++) { 
X      values.foreground = pp->color_cells[i].pixel; 
X      XChangeGC(display,gc, GCForeground, &values); 
X      x = int(i*width/float(nc));
X      XFillRectangle(display,Win,gc,x,0,dx,height); 
X    }
X  }
};
X
char * colstr[] = { "red", "blue", "green"};
X
class pal_text_win : public window {
public: 
X  pal_text_win(window &parent, int h, int x, int y) : 
X    window(parent, 70,h ,x,y,0) {}
X  virtual void redraw() { 
X    int x = 5, y = 15, i;
X    for (i = 0; i<3; i++) { 
X      DrawString(x+30,y+12,colstr[i]);
X      DrawString(x,y,"xmin"); y+= 25; 
X      DrawString(x,y,"xmax"); y+= 40; 
X    } }
};
X 
void set_pal(palette_popup * pp, int limits[2][3]) { 
X  int i; 
X  for (i=0; i< 3; i++) { 
X    pp->smin[i]->change(limits[0][i]*1000); 
X    pp->smax[i]->change(limits[1][i]*1000); }
}
X
struct palstr { char * Name; int limits[2][3];  };
X
// must be static !
struct palstr fbar[] = { { "brown ", { {21, 4, 0 }, { 65, 65, 55} } },
X			 { "rainbow", { { 0, 65, 0}, { 65, 0 , 22} } },
X			 { "yellow", { {0,0,0}, { 65, 0, 65} } },
X			 { "steel",  { {0,0,0}, {0,65,65} } },
X			 { "violet", { {37,37,0}, {65,65,65} } },
X			 { "gray", { {0,0,0}, {65,65,65} } }
X                       };
X
static void pal_paint(palette_popup * pp) { pp->paint(); };
X
// 1. constructor for palette_popup : creates a color palette and
// a popup for displaying and manipulate the palettes   
palette_popup::palette_popup(int ncol) : main_window("palette",375,330) {
X  redraw_win = NULL; // will be set in init_palette
X  init_palette(ncol);
X  long unsigned plane_mask; 
X  if (! True_Color_Visual)
X    for (int i = 0; i < ncol; i++) {
X      // printf(" %d",i); fflush(stdout);
X      if (0 == XAllocColorCells(display,def_cmap,TRUE,&plane_mask,0,
X				&(color_cells[i].pixel),1)) {
X	printf("warning : only %d color cells of %d free on display\n",i,ncol);
X	ncolors = i; return;
X      }
X      color_cells[i].flags = DoRed | DoGreen | DoBlue;
X      // cout << color_cells[i].pixel <<" "; 
X    } 
X  set_pal(this,fbar[0].limits);  // initialization  
}
X
// 2. constructor : the ColorCells are already present  (pixels)
palette_popup::palette_popup(int ncol, long unsigned *pixels) : 
X  main_window("palette",375,330) {
X  init_palette(ncol);
X  for (int i = 0; i < ncolors; i++) {
X    color_cells[i].pixel = pixels[i];
X    color_cells[i].flags = DoRed | DoGreen | DoBlue;
X  }
}
X
// used by the constructors     
void palette_popup::init_palette(int ncol) {
X  ncolors = ncol;
X
X  int ci,i,y = 5, w = 300, x= 5; 
X  new pal_text_win(*this,180,w+x,y);
X  for (ci = 0; ci<3; ci++) {
X    smin[ci] = new scrollbar(*this,pal_paint,this,w,20,x,y,0,0xffff); y+= 25;
X    smax[ci] = new scrollbar(*this,pal_paint,this,w,20,x,y,0,0xffff); y+= 40;
X  }
X
X  menu_bar *mb = new menu_bar(*this,370,20,x,y,50,100,0); y+= 25;
X  int nbar = sizeof(fbar)/sizeof(palstr); // Elementzahl von fbar
X  
X  for (i=0; i < nbar; i++)
X    new function_button(*mb,fbar[i].Name,(CB) set_pal, this, fbar[i].limits);
X
X  new palette_display(*this,370,50,x,y,this); y+= 60;
X  new unmap_button(*this,"close",100,20,130,y);
X  color_cells = new XColor[ncolors];   
}
X
SHAR_EOF
chmod 0644 palette.c ||
echo 'restore of palette.c failed'
Wc_c="`wc -c < 'palette.c'`"
test 4571 -eq "$Wc_c" ||
	echo 'palette.c: original size 4571, current size' "$Wc_c"
fi
# ============= palette.h ==============
if test -f 'palette.h' -a X"$1" != X"-c"; then
	echo 'x - skipping palette.h (File already exists)'
else
echo 'x - extracting palette.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'palette.h' &&
class palette_popup : public main_window {
public:
X  XColor *color_cells;
X  scrollbar *smin[3], *smax[3];
X  int ncolors;
X  window *redraw_win; // the window to redraw when palette changes
X  palette_popup(int ncol);  // 1. constructor allocates new ColorCells
X    // second constructor : use it if ColorCells are already allocated
X  palette_popup(int ncol, long unsigned *pixels); 
X  void paint();
private:
X  unsigned palind(int min, int max, int i);
X  void init_palette(int ncol);
};
SHAR_EOF
chmod 0644 palette.h ||
echo 'restore of palette.h failed'
Wc_c="`wc -c < 'palette.h'`"
test 484 -eq "$Wc_c" ||
	echo 'palette.h: original size 484, current size' "$Wc_c"
fi
# ============= files.c ==============
if test -f 'files.c' -a X"$1" != X"-c"; then
	echo 'x - skipping files.c (File already exists)'
else
echo 'x - extracting files.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'files.c' &&
// files.c : interactively opening files
//           wolf 12/94
#include "window.h"
#include "files.h"
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
X
#define CONFIRM_UNDEF 0
#define CONFIRM_YES 1
#define CONFIRM_NO 2
X
// simply set a variable of type T to value 
template <class T>
class variable_button : public button {
X  T value;
X  T* variable;
public:
X  variable_button(window &parent, char *Name, T *variable, T value, 
X		  int w, int h, int x, int y) :
X    button(parent,Name,w,h,x,y), value(value), variable(variable) { }
X  void BRelease_CB(XButtonEvent) { *variable = value; }
};
X
// popup window with two buttons, special loop handler,
// can be used as stack object    
class confirm_box : public main_window {
char **text;
int status;
public:  
X  confirm_box(char *Name, int w, int h, char **text ) :
X    main_window(Name,w,h,2), text(text) { // 2 means centre window !
X    status = CONFIRM_UNDEF;
X    int y = h - 25, x0 = 10, x1 = w/2 + 10, wb = w/2 - 20; 
X  
X    new variable_button <int> (*this,"Yes",&status, CONFIRM_YES,wb,20,x0,y);
X    new variable_button <int> (*this,"No",&status, CONFIRM_NO, wb, 20,x1,y);
X    
X  }
X  void Expose_CB(XExposeEvent /* ev */) {
X    int ln = 0, y = 10;
X    while (text[ln]) { y+= 15; PlaceText(text[ln++],0,y); }
X  }  
X  
X  int local_loop() {
X    RealizeChildren(); 
X    do { 
X      XEvent event;   
X      XNextEvent(display, &event);
X      // only handle events for myself and my children windows
X      // events for others are flushed !
X      unsigned wid = event.xany.window; 
X      if ( wid == Win ) { handle_event(event); continue; }
X      win_list *ch = children;
X      while (ch) {
X        if (wid == ch->child->Win) { handle_event(event); break; }
X	ch = ch->next;
X      }
X    } while (status == CONFIRM_UNDEF);
X    Unmap();
X    return(status);
X  }
};
X
// for opening output files (type = "w") with overwrite test
// if it already exists opens confirmation box "yes" , "no" 
// in case "no" returns NULL, else FILE-pointer to opened file
FILE *fopen_test(char *fina) {
X  FILE *ff = fopen(fina,"r");
X  if (ff) { // file exists
X    fclose(ff);
X    char *text[] = {"File exists :",fina,"","Overwrite it ?",0};
X    // there exists only one instance cbox per application (ressources) !
X    static confirm_box *cbox = new confirm_box("Existing File",150,120,text); 
X    // klappt nicht : XMoveWindow(display,cbox.Win,400,400);
X    int stat = cbox->local_loop();
X    if (stat == CONFIRM_NO) return (NULL);
X  }
X  return fopen(fina,"w");
}
X
class file_window;
X
// class for entering filenames
class fina_edit : public edit_window {
X  void (file_window::*meth)();
X  file_window *inst;
public: 
X  fina_edit(window &parent, char *defname, void (file_window::*meth)(), 
X            file_window *inst, int w, int h, int x, int y) : 
X    edit_window(parent,defname,w,h,x,y), meth(meth), inst(inst) {}
X  virtual void enter() {
X    (inst->*meth)(); // also calls ok-method like the button
X   // else format_error();
X  } 
};
X
// opens a popup window to enter a filename (with defname)
// ok-button tries to open it, depending on mode
// MODE_WRITE : if file already exists then popup a confirmation box 
// MODE_READ : no more used -> replaced by file_selection_box
class file_window : public main_window {
public: 
X  FILE *fptr;
X  char *fname;
X  int mode;
private:
X  fina_edit *name_ed;
X  void ok() { 
X    switch (mode) {
X    case MODE_WRITE: fptr = fopen_test(fname); break;
X    case MODE_READ: fptr = fopen(fname,"r"); break;
X    case MODE_OVWRT: fptr = fopen(fname,"w"); break;
X    }
X    if (fptr) exit_flag = True; else printf("error opening file %s\n",fname);
X  }
X
public:
X  file_window() : 
X    main_window("open file",200,100) {
X    name_ed = new fina_edit(*this,"",&file_window::ok,this,180,20,10,10);
X    fname = name_ed->value; 
X    new instance_button <file_window> 
X      (*this,"Ok",&file_window::ok,this,60,20,20,50);     
X    // simply exits main_loop since sets exit_flag
X    new variable_button <int> (*this,"Abort",&exit_flag,True,60,20,120,50);
X  }  
X // calls main_loop, returns name and opened file
X FILE* file_input_loop(char *defname, int amode, char *name_ret) {
X    fptr = NULL; // initial value -> for Abort
X    mode = amode; strcpy(name_ed->value,defname);
X    main_loop();
X    strcpy(name_ret,fname);
X    return fptr;
X  }
};
X
typedef void (*VPCP)(void *, char *);
X
class file_display : public plate { // plate for filename display
public:
X  char *val;
X  file_display(window &parent, int w, int h, int x, int y) :
X    plate (parent, w,h,x,y, down3d) { val = NULL; }
X  virtual void redraw() { 
X    plate::redraw(); 
X    // if string too long cut it *lefthand* !! charwidth = 6 !!
X    int offset =  (int(strlen(val)) - (width-6)/6 ) >? 0; 
X    PlaceText(val+offset); 
X  }
X  void set_val(char *x) { val = x; redraw(); }
};
X
// class for entering filename masks calls enter_cb 
class mask_edit : public edit_window {
X  VPCP cb;
X  void *wptr;
public: 
X  mask_edit(window &parent, VPCP enter_cb, void *inst, 
X	    int w,int h, int x, int y) : 
X    edit_window(parent,"",w,h,x,y) { cb = enter_cb; wptr = inst;}
X  virtual void enter() { cb(wptr,value); } 
};
X
// class for item in selector :
// 2 callbacks : enter_cb on enter, and act_cb on bpress
class select_item : public plate {
X  VPCP ecb, acb;
X  void *wptr;
X
public: 
X  char * value;
X  select_item(window &parent, VPCP enter_cb, VPCP act_cb, void *wp,
X	      int w, int h, int x, int y) :
X    plate(parent,w,h,x,y,flat3d) { 
X    static char empty = 0; value = &empty;
X    ecb = enter_cb; acb = act_cb, wptr = wp;
X    selection_mask |= ButtonPressMask | ButtonReleaseMask;
X  }
X
X  virtual void redraw() { 
X    if (!hidden) { 
X      plate::redraw(); 
X      if (value) PlaceText(value); else error("select_item == 0"); 
X    } 
X  }
X  virtual void Enter_CB(XCrossingEvent) {  frame3d(up3d); ecb(wptr,value); }
X  
X  virtual void Leave_CB(XCrossingEvent) { default_frame(); }
X  virtual void BPress_CB(XButtonEvent) { frame3d(down3d); acb(wptr,value); }
X 
X  virtual void BRelease_CB(XButtonEvent) { default_frame(); }
X  void enable(char *x) { value = x; hidden = False; redraw(); }
X  void disable() { hidden = True; }
};
//  ************* vert_scrollbar ***********
//  vertical scrollbar with re-definable behaviour :
//  defines virtual functions for move (button 2) and jmp (button 1 &3)
//  
X
vert_scrollbar::vert_scrollbar(window &parent, int w, int h, int x, int y, 
X			       int sh) :
plate (parent,w,h,x,y,down3d), sh(sh) { 
X  set_backing_store(); 
X  selection_mask |= PointerMotionMask | ButtonPressMask; 
X  set_vars();
X  bar = new plate(*this,sw,sh,sx,sy,up3d);
X  XDefineCursor(display,Win,vs_cursor); 
}  
X
void vert_scrollbar::set_vars() {
X  sx = 3; sw = width - 2*sx; sy = 2; yact = sy;  
X  yspan = height - 2*sy - sh; 
}
X
// jump on mouse click
void vert_scrollbar::BPress_CB(XButtonEvent ev) {
X  switch (ev.button) {
X  case 1: jmp_callback(False); break;
X  case 2: move_callback(ev.y); break;  
X  case 3: jmp_callback(True); break;
X  }
}
// draw if button 2 pressed
void vert_scrollbar::Motion_CB(XMotionEvent ev) { 
X  if (ev.state & Button2Mask) { move_callback(ev.y); }
}
X
void vert_scrollbar::set_slider(int y) {  // set slider y = 0..yspan
X  y = MAX(0, MIN(yspan,y)); 
X  yact = y;
X  XMoveWindow(display,bar->Win,sx,y + sy); 
}
X
// called from resize && others 
void vert_scrollbar::slider_adapt(int shp) { // adaptate to new slider height
X  sh = shp; 
X  set_vars(); 
X  bar->resize(sw,sh); set_slider(0);
}
X
void vert_scrollbar::resize(int w, int h) {
X  //    if (width == w && height == h) return; // only once
X  width = w; height = h; 
X  XResizeWindow(display,Win,width,height); 
X  slider_adapt(sh);
}
X
void vert_scrollbar::adapt(int h, int shp) { 
X  // adapt scrollbar to new height & slider height
X  height = h; XResizeWindow(display,Win,width,height); 
X  slider_adapt(shp);
}
X
class selector;
X
// select_scrollbar : specialized vert_scrollbar for selector windows
class select_scrollbar : public vert_scrollbar {
X  selector *sel;
public:
X  select_scrollbar(window &parent, int w, int h, int x, int y, int sh,
X		   selector *sel) :
X    vert_scrollbar(parent, w, h, x, y, sh), sel(sel) { }  
X  virtual void move_callback(int y); // called from draw (Button 2)
X  virtual void jmp_callback(Bool up); // called from pg (Button 1 & 3)
};
X
// makes a plate with (max) nits select_items -> selection box
// not all are neseccarily drawn
// this should be completed with a scrollbar
class selector : public plate {
X  select_item **pits;
X  char **itptr;
X  int itot; // total number of items in **pits
X  int ishift; // index of first displayed item
X  window *interior; // the inner part w/o boundary
X  select_scrollbar *vs; // the attached scrollbar
public:
X  int itdsp; // number of actually displayable items 
X  selector(window &parent, int nits, VPCP show_cb, VPCP act_cb,
X           int w, int h, int x, int y, int hi) :
X    plate (parent, w - 15,h,x,y,down3d) {
X    selection_mask |= KeyPressMask; // catch key events
X    itdsp = nits; 
X    interior = new window(*this,width-6,height-6,3,3,0); // 3 pixels boundary
X    vs = new select_scrollbar(parent,15,h,x+w-15,y,100,this);
X    int yp = 0; int i;
X    pits = new select_item* [nits];
X    for (i=0; i < nits; i++) {
X      pits[i] = new select_item(*interior,show_cb,act_cb,&parent,width-6,hi,
X				0,yp);
X      yp += hi;
X    }
X  }
X  
X  void set_items(char **items, int nits) { 
X    int i; itptr = items; itot = nits; ishift = 0;
X    for (i=0; i < itdsp; i++) { 
X      if (i < nits) pits[i]->enable(items[i]); else pits[i]->disable();
X     }
X  }
X  
X  ~selector() { delete[] pits; }
X
X  void redraw() { 
X    if (itot > 0) plate::redraw(); 
X    else { // makes no sense to see empty windows
X      XUnmapWindow(display,Win); XUnmapWindow(display,vs->Win); 
X    }
X  }
X  void resize(int w, int h) { 
X    if (width == w && height == h) return; // only once
X    height = h; // only height can be changed
X    XResizeWindow(display,Win,width,h);
X    int sh;  
X    if (itot > 0) { // at least 1 item 
X      XResizeWindow(display,interior->Win,width-6,h-6); 
X      RealizeChildren();  
X      // printf(" %d %d %d\n",itdsp,itot,h);
X      sh = h-4; // max slider height
X      if (itdsp < itot) sh = (sh*itdsp)/itot; // more than displayable
X      vs->adapt(h,sh); // adapt scrollbar
X      vs->RealizeChildren(); 
X    }
X  }
X
X  void shift(int ip) { // set ishift to ip, set slider, redraw
X    ip = ip >? 0; ip = ip <? ispan(); // limit to range [0..ispan]
X    if (ip != ishift) {
X      ishift = ip;
X      vs->set_slider_rel(ishift/float(itot-itdsp)); 
X      int i;
X      for (i=0;i < itdsp; i++) pits[i]->enable(itptr[i+ishift]);
X    } 
X  }
X  void shift_rel(int di) {   // shift rel to current pos
X    int ish = ishift + di; 
X    ish = MAX(0, MIN(ish, itot-itdsp));
X    shift(ish);
X  }
X  // intervall for ishift
X  int ispan() { return (itot - itdsp); } 
X
X  void KeyPress_CB(XKeyEvent ev) {
X    KeySym ks = XLookupKeysym(&ev,ev.state);
X    switch (ks) { 
X      case XK_Up: 	shift_rel(-1); break;	   
X      case XK_Down: 	shift_rel(1); break;	 
X      case XK_Prior:	shift_rel(-itdsp); break;	 
X      case XK_Next: 	shift_rel(itdsp); break;
X    }
X  }
};
X
// methods for class select_scrollbar 
void select_scrollbar::move_callback(int y) { // called from draw (Button 2)
X  int ispan = sel->ispan();
X  int ip = (yspan > 0) ? (irint((y * ispan) / float(yspan))) : 0;
X  sel->shift(ip);
}
X
void select_scrollbar::jmp_callback(Bool up) { // called from pg (Button 1 & 3)
X  sel->shift_rel( ((up) ? -1 : 1) * sel->itdsp);
} 
X
// recursively parses filename against mask, recons only *, but yet no ?
// see also "test-compare.c"
int filter(const char *mask, const char *fina) {
X  // printf("%s %s\n",mask,fina);
X  if (*mask == 0) return (*fina == 0); else
X    if (*mask == '*') { 
X      int i; 
X      // compare all tail-strings of fina with mask part following "*"
X      for (i = strlen(fina); i >= 0; i--) // end 0 is included !
X        if (filter(mask+1,fina+i)) return (1);
X      return (0); // no match found
X    } else 
X      if (*mask == *fina) return (filter(mask+1,fina+1)); else return (0);
}
X
#define ITMAX 200  // max # of items in each selector
#define BHEIGHT 18 // button height
#define ITDISP 20  // max of displayed items in selectors
X
// compare function for qsort
int qcomp(char **e1, char **e2) { 
X  return (strcmp(*e1,*e2));  //  compare strings pointed to, not the pointers
}
X
typedef int (*IVPVP)(const void *,const void *); // the correct type for qsort
X
// interactively open files for reading (scanning directory)
// after completion fptr is either the opened FILE* (Ok) or NULL (Abort)
// functions: 
//   selection mask = edit_window (*.c), enter-key (Mask)
//   selectors - BPress (Ok), Enter (display)
//   buttons : Ok, Mask, Abort  
class file_selection_box : public main_window {
public: 
X  FILE *fptr;
X  char *fname;
X  char strings[10000]; // all names in one field
X  char *fitems[ITMAX],*ditems[ITMAX]; // max 200 entries into this field
X  char pwd[100]; // current directory path
X  int fits, dits;
private:
X  edit_window *mask_ed;
X  file_display *fdsp;
X  selector *fsel,*dsel;
X  button *okb, *abortb, *chb;
X
X  // searches pwd for matching files and displays them in fsel
X  void make_select(char *mask) {
X    DIR *dirp = opendir(".");
X    struct dirent *dp; 
X    fits = dits = 0; int nstrp = 0; 
X    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X      struct stat st; 
X      stat(dp->d_name,&st);
X      Bool regfi = (st.st_mode & S_IFREG), dirfi = (st.st_mode & S_IFDIR);
X      if ((dirfi && (dits < ITMAX)) || 
X          (regfi && filter(mask,dp->d_name) && (fits < ITMAX))) {	 
X	int nl = strlen(dp->d_name) + 1; 
X	if ((nl + nstrp) >= 4000) error("too long name strings");
X        char *strent = strings + nstrp; // entry point in strings
X	strcpy(strent,dp->d_name); 
X      
X        if (regfi) fitems[fits++] = strent; else ditems[dits++] = strent;
X        nstrp += nl;
X      }
X    }   
X    qsort(fitems,fits,4,(IVPVP) qcomp); // sorting the pointers 
X    qsort(ditems,dits,4,(IVPVP) qcomp); // not the strings !
X    fsel->set_items(fitems, fits);
X    dsel->set_items(ditems, dits);
X    int ffits = MIN(fits,ITDISP), ddits =  MIN(dits,ITDISP);   
X    int wh = MAX(ffits, ddits) * BHEIGHT + 6; 
X    XResizeWindow(display,Win,220,wh+110);
X    dsel->resize(80,ddits*BHEIGHT + 6);
X    fsel->resize(110,ffits*BHEIGHT + 6); 
X
X    // printf("window %d %d\n",Win,wh+110);
X  }
X   
X  void ok() { 
X    fptr = fopen(fname,"r");
X    if (fptr) exit_flag = True; else printf("error opening file %s\n",fname);
X  }
X
X  void fsel_cb(char *val) { fname = val; fdsp->set_val(val);  }
X  // callback for dsel enter 
X  void dsel_cb(char *val) { 
X    //  getcwd(pwd,100); 
X    int lpwd = strlen(pwd);
X    sprintf(pwd+lpwd,"/%s",val); // append val to pwd
X    fdsp->set_val(pwd);  
X    pwd[lpwd] = 0; // reset pwd
X  }
X
X  void chmask() { // callback for change mask
X    make_select(mask_ed->value);
X  }
X  void cd_cb(char *val) { 
X    chdir(val); 
X    getcwd(pwd,100); fdsp->set_val(pwd);  
X    make_select(mask_ed->value); 
X }
public:
X  file_selection_box() : 
X    main_window("file selection box",220,250) {
X    
X    char empty = 0; fname = &empty; 
X    fdsp = new file_display(*this,200,20,10,10);
X    new text_win(*this,"selection mask",200,20,10,30);
X    mask_ed = new mask_edit(*this, (VPCP) &make_select, this,200,20,10,50);
X    // directory selector 
X    dsel = new selector(*this, ITDISP, (VPCP) &dsel_cb, (VPCP) &cd_cb,
X		       80,0,10,80,BHEIGHT);
X    // file selector
X    fsel = new selector(*this, ITDISP, (VPCP) &fsel_cb, (VPCP) &ok,
X		       110,100,100,80,BHEIGHT);
X    okb = new instance_button <file_selection_box> 
X                 (*this,"Ok",&file_selection_box::ok,this,50,20,0,0);
X    chb = new instance_button <file_selection_box> 
X                 (*this,"Mask",&file_selection_box::chmask,this,50,20,0,0);
X    abortb =
X       new variable_button <int> (*this,"Abort",&exit_flag,True,50,20,0,0);
X
X  }   
X 
X  void resize(int w, int h) { 
X    if (width == w && height == h) return; // only once
X    // printf("resize %x ->  %d %d\n",Win,w,h); 
X    width = w; height = h;
X    XMoveWindow(display,okb->Win,10,height-25);  
X    XMoveWindow(display,chb->Win,75,height-25);
X    XMoveWindow(display,abortb->Win,140,height-25);
X  } 
X  ~file_selection_box() { }
X
X  // calls main_loop, returns selected filename and opened file
X  FILE* file_input_loop(char *defname, char *name_ret) {
X    fptr = NULL; // initial value -> for Abort
X    strcpy(mask_ed->value, defname);
X    getcwd(pwd,100); fdsp->val = pwd; 
X    fname = NULL;
X    make_select(mask_ed->value);
X    main_loop();
X    if (fptr) strcpy(name_ret,fname);
X    return fptr;
X  }
};
X
// simple interface function
// creates popup window and calls its main_loop 
// the opened FILE* is returned and its filename (with strcpy)
FILE *open_file_interactive(char *defname, char *name_ret, int mode) {
X  // extern int debug_create; debug_create = True;
X  if (mode == MODE_READ) {
X    // there should only exist one instance of this fsb per application !
X    static file_selection_box fsb;
X    return (fsb.file_input_loop(defname, name_ret));
X  } else {
X    static file_window ofw;   
X    return (ofw.file_input_loop(defname, mode, name_ret));
X  }
}
X
static int lhgt = 13; // line height in pixels
X
// window to display a clipped portion of text
class text_window : public window {
X  int zd,ishift; 
X  char *bufstart;
X  char *lptr[10000]; // the vector of linestarts max 10000 lines
public:
X  int zz; // zz number of total lines
X  // nc = number of chars : not yet used !!
X  text_window(window &parent, int w, int h, int x, int y, char *buf, int nc):
X    window (parent,w,h,x,y) { zd = h/lhgt; ishift = 0; init(buf); }
X
X  void DrawTextLine(int y, char *lp) {
X    char temp[210], *tp = temp, ch; // copy to temp to expand tabs !! 
X    while ((ch = *lp++) != '\n') { 
X      if (ch == 0) return; // buffer end
X      if (ch == '\t') for (int i=0; i < 8; i++) *tp++ = ' '; // tab => 8 sp.
X      else *tp++ = ch;
X      if (tp-temp > 200) break;
X    }
X    XDrawString(display,Win,text_gc,2,y, temp,tp-temp);
X  }
X  void redraw() {
X    int i, y = lhgt, ip; 
X    for (i = 0, ip = ishift; i < zd && ip < zz; i++,ip++) {  
X      DrawTextLine(y,lptr[ip]); y+= lhgt; 
X    }
X  }
X  void init(char *buf) { // compute linepointer vector
X    bufstart = buf; zz = 0;
X    do {
X      lptr[zz++] = ++buf;
X      buf = strchr(buf,'\n');
X    } while (buf);
X  }
X  void reset(char *buf, int nc) { 
X    init(buf);
X    clear(); redraw();
X  }
X
X  void shift(int i) { // shift starting line and redraw
X    i = i >? 0; i = i <? zz-zd; // limit ishift to range [0..zz-zd]
X    if (i == ishift) return;
X    ishift = i; clear(); redraw();
X  }
X  float move(float z) { // z in [0..1]
X    shift(int(z * (zz - zd))); 
X    return (ishift/(zz - zd + 0.0001)); // return actual position !
X  }
X  float jmp(Bool up) { // called from scrollbar on pgup/down
X   if (up) shift( MAX(0,ishift - zd) ); else shift( MIN(zz,ishift + zd) );
X   return (ishift/(zz - zd + 0.0001)); // return actual position !
X  }
};
X
// scrollbar with specialized callback for text scrolling
class text_scrollbar : public vert_scrollbar {
X  text_window *tw;
public:
X  text_scrollbar(window &parent, int w, int h, int x, int y, int sh, 
X                text_window *tw) :
X     vert_scrollbar(parent, w, h, x, y, sh), tw(tw) {}
X  // replaces callback form vert_scrollbar
X  // 1. moves the text window, then sets the slider relative
X  virtual void move_callback(int y) { 
X    set_slider_rel( tw->move(y/float(yspan)) ); 
X  } 
X  virtual void jmp_callback(Bool up) { 
X    set_slider_rel( tw->jmp(up) );
X  }
};
X
// class text_viewer :
// text_window with an attached scrollbar
X
int text_viewer::slider_height(int zz) {   
X  int heff = height-4; // eff height in scrollbar
X  int sh = height*heff/(lhgt * MAX(zz,1));
X  return MIN(heff,sh); // slider height
}
X
void text_viewer::reset(char *buf, int nc) {
X  tw->reset(buf,nc); 
X  vs->slider_adapt(slider_height(tw->zz));
}
X
text_viewer::text_viewer(window &parent, int w, int h, int x, int y, 
X			 char *buf, int nc, int bw):
X  window(parent,w,h,x,y,bw) {
X    tw = new text_window(*this, width - 15, height, 0, 0, buf, nc);
X    int sh = slider_height(tw->zz);
X    vs = new text_scrollbar(*this, 15, height, width-15, 0, sh, tw);
X    selection_mask |= KeyPressMask; // catch key events
}
X
void text_viewer::KeyPress_CB(XKeyEvent ev) {
X  KeySym ks = XLookupKeysym(&ev,ev.state);
X  switch (ks) { 
X      case XK_Up: 	break;	   
X      case XK_Down: 	break;	 
X      case XK_Prior:	vs->jmp_callback(True); break;	 
X      case XK_Next: 	vs->jmp_callback(False); break;
X    }
}
X
SHAR_EOF
chmod 0644 files.c ||
echo 'restore of files.c failed'
Wc_c="`wc -c < 'files.c'`"
test 20582 -eq "$Wc_c" ||
	echo 'files.c: original size 20582, current size' "$Wc_c"
fi
# ============= files.h ==============
if test -f 'files.h' -a X"$1" != X"-c"; then
	echo 'x - skipping files.h (File already exists)'
else
echo 'x - extracting files.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'files.h' &&
#define MODE_READ 0  // only read
#define MODE_WRITE 1 // test if already exists
#define MODE_OVWRT 2 // always overwrite old file, no test
X
FILE *open_file_interactive(char *defname, char *name_ret, int mode);
FILE *fopen_test(char *fina);
X
class window;
class text_scrollbar;
class text_window;
X
// text_window with an attached scrollbar
class text_viewer : public window {
X  text_scrollbar *vs;
X  text_window *tw;
public: 
X  int slider_height(int zz);
X  void reset(char *buf, int nc);
X  text_viewer(window &parent, int w, int h, int x, int y, char *buf, 
X	      int nc, int bw = 0);
X  virtual void KeyPress_CB(XKeyEvent ev);
};
X
//  ************* vert_scrollbar ***********
//  vertical scrollbar with re-definable behaviour :
//  defines virtual functions for move (button 2) and jmp (button 1 &3)
//  should actually shift to window.h
X
class vert_scrollbar : public plate {
X  plate *bar;
protected:
X  int sw,sh,sx,sy,yspan; // span width for movement y = [0..yspan]
public:
X  int yact; // actual position (0..yspan)
X  void set_vars();
X  // sh : height of slider
X  vert_scrollbar(window &parent, int w, int h, int x, int y, int sh);
protected:
X  virtual void move_callback(int y) { // called from draw (Button 2)
X    set_slider(y - sy); 
X  }
X  virtual void jmp_callback(Bool up) { // called from pg (Button 1 & 3)
X    set_slider( yact + (up) ? (-sh) : sh); // jmp +/- one sh
X  } 
X  // jump on mouse click
X  virtual void BPress_CB(XButtonEvent ev);
X  // draw if button 2 pressed
X  virtual void Motion_CB(XMotionEvent ev);
public: 
X  void set_slider(int y);
X  // set slider in [0.0 .. 1.0] : 
X  void set_slider_rel(float z) { set_slider(irint(z * yspan));}
X  // called from resize && others 
X  void slider_adapt(int shp); // adaptate to new slider height
X  void resize(int w, int h);
X  void adapt(int h, int shp);
};
SHAR_EOF
chmod 0644 files.h ||
echo 'restore of files.h failed'
Wc_c="`wc -c < 'files.h'`"
test 1819 -eq "$Wc_c" ||
	echo 'files.h: original size 1819, current size' "$Wc_c"
fi
# ============= smolark.c ==============
if test -f 'smolark.c' -a X"$1" != X"-c"; then
	echo 'x - skipping smolark.c (File already exists)'
else
echo 'x - extracting smolark.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'smolark.c' &&
#include "smolark.h"
X
int nq = NQ;
X
/* qadve1.c Smolarkievicz advection method
X   from ~mieth/reich93/source/
X   */ 
X  
#define EPS 1.e-15
#define SC 1.08
X  
#define f(psi,psip,uu) ((uu)*(((uu)>0.)?(psi):(psip)))
X
void qadve_1(float *qp, float *up, float *vp, float dt, int nx, int ny,
X	     int mi1, int mni1, int mj1, int mnj1, float sc);
X
void smolark(float *qp, float *up, float *vp, float dt, int nx, int ny, 
X	     int mi1, int mni1, int mj1, int mnj1)
{ qadve_1(qp, up, vp, dt, nx, ny, mi1, mni1, mj1, mnj1, SC); }
X
void simple(float *qp, float *up, float *vp, float dt, int nx, int ny, int mi1,
X	    int mni1, int mj1, int mnj1)
{ qadve_1(qp, up, vp, dt, nx, ny, mi1, mni1, mj1, mnj1, 0); }
X
/* general smolarkievicz solver : 
X   sc = 0 -> simple upstream
*/
X
void qadve_1(float *qp, float *up, float *vp, float dt, int nx, int ny,
X	     int mi1, int mni1, int mj1, int mnj1, float sc)
{ float (*q)[ny][nq] = (float (*) [ny][nq]) qp;
X  float (*u)[ny] = (float (*) [ny]) up;
X  float (*v)[ny] = (float (*) [ny]) vp;
X
X  float mx = 1.0, my = 1.0, dx = 1.0, dy = 1.0;
X  int i,j,lq,mi2,mni2,mj2,mnj2,im1,jm1,ip1,jp1;
X  float qq[nx][ny][nq];
X  float u0,v0,upl[nx][ny],vpl[nx][ny],umi[nx][ny],vmi[nx][ny],uplsn,vplsn,umisn,vmisn;
X  float t0,t1,t2,t3,t4,hilfx,hilfy;
X
X  hilfx=.5*mx*dt/dx; hilfy=.5*my*dt/dy;
X   
X  mi2=mi1+1; mj2=mj1+1; mni2=mni1-1; mnj2=mnj1-1; 
X
X  /* for(k=0;k<1;k++) { */ 
X    for(i = mi2; i < mni2 ; i++) {
X      im1 = i-1; ip1 = i+1; 
X      for(j = mj2; j < mnj2; j++) { 
X	jm1 = j-1; jp1 = j+1; 
X
X	u0=u[i][j]; v0=v[i][j];
X	uplsn=(u0+u[ip1][j])*hilfx;
X	umisn=(u0+u[im1][j])*hilfx;
X	vplsn=(v0+v[i][jp1])*hilfy;
X	vmisn=(v0+v[i][jm1])*hilfy;
X	if(uplsn>0.){
X	  if(umisn>0.){
X	    if(vplsn>0.){
X	      if(vmisn>0.){
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(umisn*(q[im1][j][lq]-t0)+vmisn*(q[i][jm1][lq]-t0));
X		}
X	      }
X	      else{
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+umisn*(-t0+q[im1][j][lq]);
X		}
X	      }
X	    }
X	    else{
X	      if(vmisn>0.){
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+
X		    (umisn*(q[im1][j][lq]-t0)-vplsn*(q[i][jp1][lq]-t0)+vmisn*(q[i][jm1][lq]-t0));
X		}
X	      }
X	      else{
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(umisn*(q[im1][j][lq]-t0)-vplsn*(q[i][jp1][lq]-t0));
X		}
X	      }
X	    }
X	  }
X	  else{
X	    if(vplsn>0.){
X	      if(vmisn>0.){
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+vmisn*(-t0+q[i][jm1][lq]);
X		}
X	      }
X	      else{
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++) qq[i][j][lq]=q[i][j][lq];
X	      }
X	    }
X	    else{
X	      if(vmisn>0.){
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(-vplsn*(q[i][jp1][lq]-t0)+vmisn*(q[i][jm1][lq]-t0));
X		}
X	      }
X	      else{
X		upl[i][j]=uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+vplsn*(t0-q[i][jp1][lq]);
X		}
X	      }
X	    }
X	  }
X	}
X	else{
X	  if(umisn>0.){
X	    if(vplsn>0.){
X	      if(vmisn>0.){
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+
X		    (-uplsn*(q[ip1][j][lq]-t0)+umisn*(q[im1][j][lq]-t0)+vmisn*(q[i][jm1][lq]-t0));
X		}
X	      }
X	      else{
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(-uplsn*(q[ip1][j][lq]-t0)+umisn*(q[im1][j][lq]-t0));
X		}
X	      }
X	    }
X	    else{
X	      if(vmisn>0.){
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(-uplsn*(q[ip1][j][lq]-t0)+umisn*(q[im1][j][lq]-t0)
X				   -vplsn*(q[i][jp1][lq]-t0)+vmisn*(q[i][jm1][lq]-t0));
X		}
X	      }
X	      else{
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+
X		    (-uplsn*(q[ip1][j][lq]-t0)+umisn*(q[im1][j][lq]-t0)-vplsn*(q[i][jp1][lq]-t0));
X		}
X	      }
X	    }
X	  }
X	  else{
X	    if(vplsn>0.){
X	      if(vmisn>0.){
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(-uplsn*(q[ip1][j][lq]-t0)+vmisn*(q[i][jm1][lq]-t0));
X		}
X	      }
X	      else{
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+uplsn*(t0-q[ip1][j][lq]);
X		}
X	      }
X	    }
X	    else{
X	      if(vmisn>0.){
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(-uplsn*(q[ip1][j][lq]-t0)
X				   -vplsn*(q[i][jp1][lq]-t0)+vmisn*(q[i][jm1][lq]-t0));
X		}
X	      }
X	      else{
X		upl[i][j]=-uplsn-uplsn*uplsn;
X		umi[i][j]=-umisn-umisn*umisn;
X		vpl[i][j]=-vplsn-vplsn*vplsn;
X		vmi[i][j]=-vmisn-vmisn*vmisn;
X		for(lq=0;lq<nq;lq++){
X		  t0=q[i][j][lq];
X		  qq[i][j][lq]=t0+(-uplsn*(q[ip1][j][lq]-t0)-vplsn*(q[i][jp1][lq]-t0));
X		}
X	      }
X	    }
X	  }
X	}
X      }
X    }
X
X    for(lq=0;lq<nq;lq++){
X      for(i=mi1;i<mni1;i++){
X	qq[i][mj1][lq]=q[i][mj1][lq];
X	qq[i][mnj2][lq]=q[i][mnj2][lq];
X      }
X      for (j=mj2;j<mnj2;j++) {
X	qq[mi1][j][lq]=q[mi1][j][lq];
X	qq[mni2][j][lq]=q[mni2][j][lq];
X      }
X    }
X
X  for(i=mi2;i<mni2;i++) {
X    im1=i-1; ip1=i+1;  
X    for(j=mj2; j<mnj2; j++) {
X      jm1=j-1; jp1=j+1; 
X      
X      for (lq=0;lq<nq;lq++) {
X	  t0=qq[i][j][lq]; t1=qq[im1][j][lq];
X	  t2=qq[ip1][j][lq]; t3=qq[i][jm1][lq]; t4=qq[i][jp1][lq];
X	  uplsn=upl[i][j]*(t2-t0)/(t0+t2+EPS);
X	  umisn=umi[i][j]*(t0-t1)/(t1+t0+EPS);
X	  vplsn=vpl[i][j]*(t4-t0)/(t4+t0+EPS);
X	  vmisn=vmi[i][j]*(t0-t3)/(t3+t0+EPS);
X	  q[i][j][lq]=t0+sc*((-f(t0,t2,uplsn)+f(t1,t0,umisn))+(-f(t0,t4,vplsn)+f(t3,t0,vmisn)));
X      }
X    }
X  }
}
X
X
X
X 	
SHAR_EOF
chmod 0644 smolark.c ||
echo 'restore of smolark.c failed'
Wc_c="`wc -c < 'smolark.c'`"
test 7088 -eq "$Wc_c" ||
	echo 'smolark.c: original size 7088, current size' "$Wc_c"
fi
# ============= smolark.h ==============
if test -f 'smolark.h' -a X"$1" != X"-c"; then
	echo 'x - skipping smolark.h (File already exists)'
else
echo 'x - extracting smolark.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'smolark.h' &&
#define NQ 1
X
void smolark(float *qp, float *up, float *vp, float dt, int nx, int ny, 
X	     int mi1, int mni1, int mj1, int mnj1);
X
void simple(float *qp, float *up, float *vp, float dt, int nx, int ny, 
X	    int mi1, int mni1, int mj1, int mnj1);
SHAR_EOF
chmod 0644 smolark.h ||
echo 'restore of smolark.h failed'
Wc_c="`wc -c < 'smolark.h'`"
test 249 -eq "$Wc_c" ||
	echo 'smolark.h: original size 249, current size' "$Wc_c"
fi
# ============= solver.c ==============
if test -f 'solver.c' -a X"$1" != X"-c"; then
	echo 'x - skipping solver.c (File already exists)'
else
echo 'x - extracting solver.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'solver.c' &&
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
X
#define f(psi,psip,uu) ((uu)*(((uu)>0.)?(psi):(psip)))
X
int nx;
double *u, *q;
double dx, dt;
X
// general advection scheme -> for Smolarkievicz && simple upstream 
// Smolarkievicz method : set SC = 1.08
// simple upstream : SC = 0.0
// used globals are : u, q, dt, dx, nx
X
void general(int mi1, int mni1, double SC) 
{
X  double EPS = 1.e-15;
X  int i,mi2,mni2,im1,ip1;
X  double qq[nx];
X  double u0,upl[nx],umi[nx],uplsn,umisn;
X  double t0,t1,t2,hilfx;
X  
X  hilfx =.5*dt/dx;
X  mi2 = mi1+1; mni2 = mni1-1;
X  for(i = mi2; i < mni2; i++) {
X    im1 = i-1; ip1 = i+1; u0 = u[i];
X    uplsn=(u0 + u[ip1])*hilfx;
X    umisn=(u0 + u[im1])*hilfx;
X
X    upl[i]= fabs(uplsn) - uplsn*uplsn;
X    umi[i]= fabs(umisn) - umisn*umisn;
X    
X    if(uplsn > 0.) {
X      if(umisn > 0.) {
X	
X	t0 = q[i];
X	qq[i] = t0 + umisn*(q[im1] - t0);
X      } else qq[i] = q[i];
X    } else {
X      if (umisn > 0.) {
X	t0 = q[i];
X	qq[i] = t0 - uplsn*(q[ip1] - t0) + umisn*(q[im1] - t0);
X      } else {
X	t0 = q[i];
X	qq[i] = t0 - uplsn*(q[ip1] - t0);
X      }
X    }
X  }
X 
X  qq[mi1]=q[mi1];
X  qq[mni2]=q[mni2];
X
X  for(i=mi2;i<mni2;i++) {
X    t0=qq[i]; t1=qq[i-1]; t2=qq[i+1];
X
X    uplsn=upl[i] * (t2 - t0) / (t0+t2+EPS);
X    umisn=umi[i] * (t0 - t1) / (t1+t0+EPS);
X    q[i] = t0 + SC*(  - f(t0,t2,uplsn) + f(t1,t0,umisn) );
X  }
}
// general advection scheme -> for Smolarkievicz && simple upstream 
// Smolarkievicz method : set SC = 1.08
// simple upstream : SC = 0.0
// used globals are : u, q, dt, dx, nx
// !! simplified : only for case u > 0 !!
// it uses zyklical boundary conditions : x[0] == x[nx]
void general2(int mi1, int mni1, double SC) 
{
X  double EPS = 1.e-15;
X  int i,im1,ip1;
X  double qq[nx];
X  double u0,upl[nx],umi[nx],uplsn,umisn;
X  double t0,t1,t2,hilfx;
X  
X  hilfx =.5*dt/dx;
X
X  for(i = mi1; i < mni1; i++) {
X    im1 = i-1; if (im1 < 0) im1= nx-1; // wrap around at i == 0 && i == nx-1
X    ip1 = i+1; if (ip1 == nx) ip1 = 0;
X    u0 = u[i];
X    uplsn=(u0 + u[ip1])*hilfx;
X    umisn=(u0 + u[im1])*hilfx;
X
X    upl[i]= fabs(uplsn) - uplsn*uplsn;
X    umi[i]= fabs(umisn) - umisn*umisn;
X    
X	
X    t0 = q[i];
X    qq[i] = t0 + umisn*(q[im1] - t0);
X  }
X 
X  for(i=mi1; i< mni1; i++) { 
X    im1 = i-1; if (im1 < 0) im1= nx-1; // wrap around at i == 0 && i == nx-1
X    ip1 = i+1; if (ip1 == nx) ip1 = 0;
X  
X    t0=qq[i]; t1=qq[im1]; t2=qq[ip1];
X
X    uplsn=upl[i] * (t2 - t0) / (t0+t2+EPS);
X    umisn=umi[i] * (t0 - t1) / (t1+t0+EPS);
X    q[i] = t0 + SC*(  - f(t0,t2,uplsn) + f(t1,t0,umisn) );
X  }
}
X
// globals : u,q,dx,dt,nx
void lax_wendroff(int x1,int x2)
{  double alpha, y,yp,ym;
X   double qq[nx];
X   int i,ip,im;
X   for (i= x1; i < x2; i++)
X     { alpha = u[i] * dt/dx; 
X       // zyklischer Rand
X       ip = (i < nx-1) ? (i+1) : 0; im = (i > 0) ? (i - 1) : (nx - 1); 
X       y= q[i]; yp = q[ip];  ym = q[im];
X       qq[i] = y - alpha/2 * (yp - ym - alpha * (yp + ym - 2.0*y)) ;
X     }
X   for (i=x1; i < x2; i++) q[i] = qq[i];
}
X
void smolarkievicz(int i, int j) { general2(i,j,1.08); }
void simple(int i, int j) { general2(i,j,0); }
X
void diffusion(double diff, int x1, int x2 ) 
{ int i, ip, im;
X  double dq[nx], beta; 
X  beta = diff * dt / (dx * dx);
X  for (i=x1; i<x2; i++) 
X    {  // zyklischer Rand
X       ip = (i < nx-1) ? (i+1) : 0; im = (i > 0) ? (i - 1) : (nx - 1); 
X       dq[i] = beta * (q[ip] - 2.0*q[i] + q[im]);
X    }
X  for (i=x1; i < x2; i++) q[i] += dq[i];
}
SHAR_EOF
chmod 0644 solver.c ||
echo 'restore of solver.c failed'
Wc_c="`wc -c < 'solver.c'`"
test 3405 -eq "$Wc_c" ||
	echo 'solver.c: original size 3405, current size' "$Wc_c"
fi
# ============= animator.h ==============
if test -f 'animator.h' -a X"$1" != X"-c"; then
	echo 'x - skipping animator.h (File already exists)'
else
echo 'x - extracting animator.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'animator.h' &&
// animator.h
//     wolf   5/95
// class to store time sequences of grid values (nx*ny) in a file 
// and to enable animated playback of them (program "replay.c")
// the arrays are arranged in separate columns, which are connected
// with menu-buttons for the lattice class
X
#include "lattice.h"
X
// a displayable array with description fields, 
// darr and farr are used exclusively : "darr" for compuation, 
// "farr" for write/read and display of the saved arrays
// gamma and z0 are only for display fitting
X
union realp { double *darr; float *farr; };
struct d2disp { char *name; union realp array; float gamma,z0;
X		int array_mode;
X	      };
X
// a column connected with a vector of items, if write = True save in video
struct column { char *name; int nitems; Bool write; d2disp *items;  };
X
// modes for array indexing (array_mode) = 0..3 ( a | b)
#define ARRAY_NY_NX  1 // esp. for FORTRAN programs
#define ARRAY_NX_NY  0
#define ARRAY_DOUBLE 2 // the used precision for arrays in the hooked program
#define ARRAY_FLOAT  0
X
// at creation time use the call sequence: 
//    1. constructor, 2. add_column... , 3. init_write, 4. write_step ...
// at read time :
//    1. constructor, 2. init_read, 3. read_step ...
class animator {
X  long data;   // the start position of data in the file 
X  long rec_length; // record length (in bytes), computed from read_step !!
X  long fp_old; // last file pointer (for write error checking only)
public:
X  unsigned nsteps; // number of steps saved in the file (read)
X  FILE *fvideo;   // the file stream
X  char wina[200]; // its filename (for window WM name)
X  Bool eof; // for reading only (beyond end of file)
X  int ncols, nx, ny;
X  column columns[10]; // max 10 columns
X  animator();
X  animator(char *name);
X
X  // add a column (bound to a menu button) for write ops
X  void add_column(char *name, int nitems, d2disp *items);
X
X  // create a new file-stream for fina
X  // write initial values into fvideo, possibly called more than once
X  void init_write(char *fina, char *str, int nxp, int nyp);
X      
X  // write one time step to file : the arrays are transformed to float
X  // for FORTRAN they are rearranged into C ordering, ie NX_NY
X  void write_step(int itime);
X 
X  // read a column description from file
X  int get_column(column *colp, Bool alloc);
X
X  void init_read(char *fina, Bool alloc);
X  void init_read(FILE *fp, Bool alloc);
X
X  int fsize(); // determine step number of the video file
X
X  // read sequentially one time step from file 
X  int read_step();
X  
X  // set file pointer for read ops to beginning of record number "step"
X  // set eof if an error occurs
X  void seek(int step);
X  
X  // make a radion_menu from a d2disp-column 
X  void menu_from_column(window *parent, char *Name, window *action_win,
X			int nitems, d2disp *items);
X
X  // combine menu creation with saving to file (add_column)
X  void make_saved_menu(window *parent, char *Name, window *action_win,
X		       int nitems, d2disp *items);
X  
X  // create all menus stored in the columns (as read from the file) 
X  void make_all_menus(window *parent, window *action_win);
X
X  // translate menu-enries into corresponding d2disp-pointer, 
X  // by comparing the string addresses !
X  // mainly used for action methods in menus
X  d2disp *find(char *menu, char *name);
X
};
X
// class time_lat : a lattice manager for display time sequences of arrays
// with selector menus, clock and spawning feature
// the "action" method must be defined in derived classes (see replay_lat) !
class time_lat : public lattice_manager {
X  head_line *headline;
X  clock_win *clck;
X  int& itime;
X  d2disp *dsel; // actually selected display descriptor (array,name,gamma,...)
public:
X
X  time_lat *spawned_from;
X  struct splist { time_lat *spawned; splist *next;} *spl; 
X
X  time_lat(window &parent, int w, int h, int x, int y, int nx, int ny, 
X	   d2disp *dstart, int *tptr);
X  ~time_lat();
X  void install_spawned(time_lat *gsp); // hook a new spawned gl into chain
X
X  virtual void redraw();
X  virtual void draw_interior(); // recompute array do draw from member "array"
X  void redraw_spawned(); // redraws all spawned windows; parsing the spl list
X  void setsel(d2disp *ddp);
X  virtual void action(char * menu, char * value) = 0;
};
X
// play_lat : a time_lat with animator and action 
// used for replay and integrators
class play_lat : public time_lat {
X  animator *animp;
public:
X  play_lat(window &parent, int w, int h, int x, int y, 
X	     animator *animp, int *tptr);
X  virtual void action(char * menu, char * value);
};
X
// a main window with menubar and play_lat-window 
// it is bound to an animator, which columns are displayable
// a spawn-method can be bound to a button which spawns a new play_main
class play_main : public main_window {
X  int *tptr; 
X  int wh, ly, bh, sh, by; // geometry parameters of windows
protected:
X  animator *animp;
public:
X  menu_bar *mb;
X  play_lat *lat;    
X  void spawn();
X  // if top = True : reserve additional place for scrollbar on top
X  play_main(animator *animp, int *tptr, Bool centre = False, Bool top = False);
X  void init_lat(); // must be called after animator generation !!
};
X
// class player has two handlers to switch
// between play and stop; to be used as primer window
class player : public play_main {
protected:
X  Bool rot_mode;  // both modes work independently, they switch on a
X  Bool step_mode; // special polling handler 
X  void pmset() { polling_mode = rot_mode || step_mode; }
public:
X  player(animator *animp, int *tptr, Bool top = False);
X  void play();
X  void stop(); // two button callbacks to toggle step_mode;
private:
X  virtual void step_handler() {} // the handler invoked for step_mode
X  virtual void polling_handler();
X  void rotate(); // button callback to toggle rot_mode
};
X
// class integrator : general purpose interface to invoke any program
// that solves time step integrations, creates an animator (and video file)
// the members init_solver, step_solver, exit_solver must be defined by app
class integrator : public player {
X  char *video_file;
X  int animt; // number of seconds for video file time step 
protected:
X  char *header; // to be written in the video file
X  int nx,ny;
public: 
X  animator anim;
X  int itime; 
X
X  integrator(char *name, char *video_file, int nx, int ny, int animt);
X
X  virtual void init_solver() = 0;
X  virtual void step_solver() = 0;
X  virtual void exit_solver() = 0;
X
X  void reinit();
X  void start();
X  virtual void step_handler();
X  
X  void add_column(char *menu, int nitems, d2disp *items);
};
X
// classes to make up a synchronous driven pipe 
// the "master" creates a pipe which should be given a command with "...-pipe"
// the "slave" process then polls from stdin integer indexes for which it 
// invokes "make_step" and sends an USR1 signal upon completion to wake up 
// the master
// istep = -1 is used to terminate the slave process
X
class master {
protected:
X  static FILE *spipe; // only one per process !!
X  static void sig_pipe(int) { spipe = 0; } // delete on signal SIGPIPE
public:
X  master() { spipe = 0; }
X  ~master() { spipe = 0; }
X  void start_synchron(char *command, int istep);
X  void synchronize(int istep);
X  void cleanup();
};
X
class slave {
public:
X  slave();
X  virtual int make_step(int i) = 0; // actually perform time step 
X  void pstep(); // used as poll handler for synchronized processes
};
SHAR_EOF
chmod 0644 animator.h ||
echo 'restore of animator.h failed'
Wc_c="`wc -c < 'animator.h'`"
test 7329 -eq "$Wc_c" ||
	echo 'animator.h: original size 7329, current size' "$Wc_c"
fi
# ============= animator.c ==============
if test -f 'animator.c' -a X"$1" != X"-c"; then
	echo 'x - skipping animator.c (File already exists)'
else
echo 'x - extracting animator.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'animator.c' &&
// animator.C
//     wolf   5/95
// class to store time sequences of grid values (nx*ny) in a file 
// and to enable animated playback of them (program "replay.C")
// the arrays are arranged in separate columns, which are connected
// with menu-buttons
X
#include "animator.h"
#include "files.h"
#include <sys/types.h>
#include <sys/stat.h>
X
animator::animator() { 
X  fvideo = NULL; ncols = 0;
}
X
animator::animator(char *name) { 
X  strcpy(wina, name);
X  fvideo = NULL; ncols = 0;
}
X
// add a column (bound to a menu button) for write ops
void animator::add_column(char *name, int nitems, d2disp *items) {
X  column* colp = columns+ncols; // the actual column pointer 
X  ncols++; 
X  colp->name = name; colp->nitems = nitems;
X  colp->items = items;
}
X
// create a new file-stream for fina
// write initial values into fvideo, possibly called more than once
// str is a description string, put in the first line of file
void animator::init_write(char *fina, char *str, int nxp, int nyp) {  
X  nx = nxp; ny = nyp;
X  if (fvideo == NULL) { 
X    fvideo = fopen_test(fina); //  fopen(fina,"w"); 
X    if (fvideo == NULL) exit(0);  
X  }
X  else fvideo = fopen(fina,"w");  // -> re-init 
X  fprintf(fvideo,"%s\n%d %d %d\n",str,nx,ny,ncols);
X  int ic,ii,ntot = 0;
X  for (ic=0; ic < ncols; ic++) {
X    column* colp = columns + ic;
X    fprintf(fvideo,"%s\n%d\n",colp->name,colp->nitems);
X    d2disp* itp = colp->items; 
X    ntot += colp->nitems;
X    for (ii=0; ii < colp->nitems; ii++) {
X      fprintf(fvideo,"%s\n%g %g\n",itp[ii].name,itp[ii].gamma,itp[ii].z0);
X    }
X  }  
X  rec_length = sizeof(int) + ntot*nx*ny*sizeof(float) ; 
X  fp_old = 0;
}
X
void animator::write_step(int itime) { 
X  // write one time step to file : the arrays are transformed to float
X  // for FORTRAN they are rearranged into C ordering
X  long fp = ftell(fvideo);
X  if (fp_old > 0) { 
X    if (fp != fp_old + rec_length) 
X      printf("error write video file %d %ld\n",itime,fp-fp_old);
X  } 
X  fp_old = fp;
X  if (fwrite(&itime,sizeof(int),1,fvideo) != 1) error("video file it"); 
X
X  for (int ic = 0; ic < ncols; ic++) {
X    column* colp = columns+ic;
X    for (int ii = 0; ii < colp->nitems; ii++) {
X      d2disp *cii = &(colp->items[ii]); // shortcut
X      double (*fptr)[nx] = (double (*) [nx]) cii->array.darr; 
X      double (*cptr)[ny] = (double (*) [ny]) cii->array.darr; 
X      int array_mode = cii->array_mode;
X      for (int ix=0; ix<nx; ix++) for (int iy=0; iy<ny; iy++) {
X	float ff;
X	if (array_mode & ARRAY_NY_NX) // swap x <-> y
X	  ff = fptr[iy][ix]; else ff = cptr[ix][iy];
X	if (fwrite(&ff, sizeof(float), 1, fvideo) != 1)
X	  error("write video file ff"); 
X      }
X      // fprintf(fvideo," %g ",colp->items[ii].darr[0]); -> test
X    }
X  }
X  fflush(fvideo);
}
X
// read a column description from file into colp element
// and allocate the needed arrays (items, strings) with new
// return number of items (fields)
int animator::get_column(column *colp, Bool alloc) { 
X  if (alloc) colp->name = new char[51]; 
X  char *cname = colp->name; 
X  fgets(cname,51,fvideo); // = the menu name 
X  cname[strlen(cname)-1] = 0; // suppress the newline in the string
X  int nits;
X  if (fscanf(fvideo,"%d%*c",&nits) != 1) error("format 'nitems'");
X  // "%*c" to skip the newline after %d
X
X  if (alloc) colp->nitems = nits; 
X  else if (nits != colp->nitems) error("incompatible records");
X
X  // printf("cname = %s\n",cname); printf("nitems = %d\n",nits);
X  if (alloc) colp->items = new d2disp[nits];
X  for (int ii = 0; ii < nits; ii++) {
X    d2disp *cii = &(colp->items[ii]); // shortcut
X    if (alloc) cii->name = new char[81]; 
X    char *itn = cii->name; fgets(itn,81,fvideo);
X    itn[strlen(itn)-1] = 0; // suppress the newline in the string
X    if (fscanf(fvideo,"%g%g%*c",&cii->gamma,&cii->z0) 
X	!= 2) error("format 'gamma z0'");
X    // the place to read arrays into
X    if (alloc) cii->array.farr = new float[nx*ny];
X    cii->array_mode = ARRAY_FLOAT; 
X    // printf("%s %s %g %g\n",cname,itn,cii->gamma,cii->z0);
X  }
X  return nits;
}
X
// read header from fp and arrange columns accordingly
// if alloc = TRUE : allocate the space (only first time)
void animator::init_read(FILE *fp, Bool alloc) {
X  fvideo = fp;
X 
X  char dummy[200];
X  fgets(dummy,200,fvideo); // not used yet
X  if (fscanf(fvideo,"%d%d%d",&nx,&ny,&ncols) != 3) error("not a video file");
X  printf("header = %snx = %d ny = %d ncols = %d\n",dummy,nx,ny,ncols); 
X  fgets(dummy,10,fvideo); // skip the newline
X  int i, ntot = 0;  
X  // count all items :
X  for (i=0; i < ncols; i++) ntot += get_column(columns+i, alloc);
X  // columns+i = actual column pointer
X  data = ftell(fvideo); // now data arrays begin
X  //           the itime   +   record of ntot grids
X  
X  rec_length = sizeof(int) + ntot*nx*ny*sizeof(float) ; 
X
X  fsize(); // compute nsteps
}
X
void animator::init_read(char *fina, Bool alloc) {
X  strcpy(wina, fina);
X  fvideo = fopen(wina,"r");
X  if (fvideo == NULL) { // 
X    char *defname = "*.video"; 
X    fvideo = open_file_interactive(defname,wina,MODE_READ);
X  } 
X  if (fvideo == 0) exit(0);
X  init_read(fvideo, alloc); 
}  
X
// determine step number of the video file (independently of init_read)
// for reading new files
int animator::fsize() {
X  struct stat buf;
X  fstat(fileno(fvideo), &buf);
X  nsteps = (buf.st_size - data)/rec_length;
X  printf("rec length = %ld nsteps = %d \n", rec_length,nsteps);
X  return nsteps;
}
X
X
int animator::read_step() { // read sequentially one time step from file 
X  int itime; 
X  if (fread(&itime,sizeof(int),1,fvideo) < 1) { 
X    eof = TRUE; return -1; // EOF 
X  }
X  int ic,ii;
X  for (ic=0; ic < ncols; ic++) {
X    column* colp = columns+ic;
X    for (ii=0; ii < colp->nitems; ii++) 
X      if (fread(colp->items[ii].array.farr, sizeof(float), nx*ny, fvideo) 
X	  < (unsigned) nx*ny) return -1; // EOF
X    // fprintf(fvideo," %g ",colp->items[ii].array[0]); -> test
X  }
X  return itime;
}
X
void animator::seek(int step) { 
X  // set file pointer for read ops to, set eof=TRUE if it failed
X  // beginning of record number "step"
X  eof = (fseek(fvideo,data + step*rec_length,0) != 0); // SEEK_SET = 0
}
X
X
// make a radion_menu from a d2disp-column 
void animator::menu_from_column(window *parent, char *Name, window *action_win,
X				int nitems, d2disp *items) {
X  int i;
X  char **sel_list = new char* [nitems+1]; 
X  for (i=0; i<nitems; i++) sel_list[i] = items[i].name;
X  sel_list[nitems] = 0;
X  make_radio_menu(*parent, Name, sel_list, action_win);		   
X  
}
X
// combine menu creation with saving to file (add_column)
void animator::make_saved_menu(window *parent, char *Name, window *action_win,
X			       int nitems, d2disp *items) {
X  menu_from_column(parent, Name, action_win, nitems, items);
X  add_column(Name, nitems, items);
}
X
// create all menus stored in the columns (as read from the file) 
void animator::make_all_menus(window *parent, window *action_win) {
X  int i;
X  for (i=0; i < ncols; i++) { 
X    column *col = columns+i; // printf("%s \n",col->name); 
X    menu_from_column(parent, col->name, action_win, col->nitems, col->items);
X  }
}
X
// translate menu-enries into corresponding d2disp-pointer, 
// by comparing the string addresses !
// mainly used for action methods in menus
d2disp* animator::find(char *menu, char *name) {
X  int i,ic;
X  for (ic=0; ic < ncols; ic++) {
X    column *colp = columns+ic; 
X    if (menu == colp->name) {
X      d2disp *ddp = colp->items;
X      for (i=0; i < colp->nitems; i++) if (name == ddp[i].name) return ddp+i;
X    }
X  }
X  return 0; // not found
}
X
//************************************************************************//
// class time_lat : a lattice manager for display time sequences of arrays
// with selector menues, clock and spawning feature
X
time_lat::time_lat(window &parent, int w, int h, int x, int y, 
X		   int nx, int ny, d2disp *dstart, int *tptr) : 
X  lattice_manager(parent, w, h-20,x, y+20, nx, ny, NULL), itime(*tptr) {
X    headline = new head_line(parent,w,20,x,y);
X    qptr = new float[nx*ny]; 
X    setsel(dstart);
X    body = False;  
X    spl = NULL; spawned_from = NULL;
X    clck = new clock_win(*this, tptr,50,50,w-55,h-120);
X  }
X
time_lat::~time_lat() { 
X  delete qptr; 
X  if (spawned_from == NULL) return;
X  // inhibit redrawing initiated from the spawner of myself 
X  splist *spx = spawned_from->spl; 
X  // printf("delete %x\n",this);
X  // instead of compilcated re-arranging the list simply set spawned = 0
X  while (spx) { 
X    if (spx->spawned == this) { spx->spawned = NULL; }
X    spx = spx->next;
X  }
}
X
// hook a new spawned gl into chain
void time_lat::install_spawned(time_lat *gsp) { 
X  splist *sn = new splist; 
X  sn->next = spl; sn->spawned = gsp;
X  spl = sn; 
X  gsp->spawned_from = this;  // remember my spawner for destructor !
X  // printf("installing %x from %x\n",gsp,this);
X  gsp->dsel = dsel; // use selected display also
X  gsp->gamma = gamma; gsp->z0 = z0; // but the actual values here
X
}
X
void time_lat::redraw() { lattice_manager::redraw(); clck->redraw(); }
X
void time_lat::draw_interior() { 
X  // make a copy from member "array" to array "qptr", depending on type 
X  float (*lptr)[ny] = (float (*) [ny]) qptr; // ptr to the array to draw "qptr"
X
X  realp array = dsel->array;
X  double (*dnx)[nx] = (double (*) [nx]) array.darr; // 4 accessors to "array"
X  double (*dny)[ny] = (double (*) [ny]) array.darr; // for different precis.
X  float (*fnx)[nx] = (float (*) [nx]) array.farr;   // and orderings
X  float (*fny)[ny] = (float (*) [ny]) array.farr; 
X  int array_mode = dsel->array_mode;
X  int x,y; 
X  for (x=0; x<nx; x++)  for (y=0; y<ny; y++) {
X    // !! indexing of array[ny][nx] !! 
X    if (array_mode & ARRAY_NY_NX) 
X      // indexing of array = [ny][nx] -> reverse
X      lptr[x][y] = (array_mode & ARRAY_DOUBLE) ? dnx[y][x] : fnx[y][x];
X    else //  indexing of array = [nx][ny] 
X      lptr[x][y] = (array_mode & ARRAY_DOUBLE) ? dny[x][y] : fny[x][y];
X    
X  } 
X  // old: for (i=0; i<nx*ny; i++) qptr[i] = array[i];
X  // printf("draw_int %s %g %g %g\n",dsel->name,gamma,z0,lptr[0][0]);
X
X  sprintf(headline->str,"%s t= %ds %d:%02dh",dsel->name, itime,
X	  itime/3600, (itime % 3600)/60);
X  headline->redraw();
X  lattice_manager::draw_interior();
}
X
// redraws all spawned windows; parsing the spl list
void time_lat::redraw_spawned() {
X  redraw(); // first redraw myself
X  splist *spx = spl;
X  while (spx) { 
X    time_lat *gsp = spx->spawned; if (gsp) gsp->redraw(); 
X    spx = spx->next; 
X  }
}
X
void time_lat::setsel(d2disp *ddp) {
X  gamma = ddp->gamma; z0 = ddp->z0;
X  dsel = ddp;
X  // printf("setsel %g %g %x\n",gamma,z0,ddp->array.darr);
}
X
/**************************************************************************/
// play_lat : a time_lat with animator and action 
// used for replay and integrators
X
play_lat::play_lat(window &parent, int w, int h, int x, int y, 
X		   animator *animp, int *tptr) : animp(animp),
X  time_lat(parent,w,h,x,y,animp->nx,animp->ny,animp->columns[0].items, tptr)
{ } // start with first array of column 0
X
void play_lat::action(char * menu, char * value) { 
X  d2disp *ddp = animp->find(menu,value);
X  setsel(ddp);
X  redraw();
}
X
/******************** play_main *****************************/
// a main window with menubar and play_lat-window 
// it is bound to an animator, which columns are displayable
// a spawn-method can be bound to a button which spawns a new play_main
X
// initialize lattice and menues from animator, must be called after constr.
void play_main::init_lat() {
X  lat = new play_lat(*this, width, wh, 0, ly, animp, tptr); 
X  animp->make_all_menus(mb, lat); 
}
X
// if top = True : reserve additional place for scrollbar on top
// and place the window in centre of screen
play_main::play_main(animator *animp, int *tptr, Bool centre, Bool top) 
: main_window(animp->wina, 510, 520 + ((top) ? 40 : 0), (centre) ? 2 : 0), 
X  tptr(tptr), animp(animp) {
X    // printf("play %s\n",animp->wina);
X    bh = 20; sh = 40; by = 0;
X    wh = height-bh; ly = bh; 
X    if (top) { wh -= sh; ly+= sh; by += sh; }
X    mb = new menu_bar(*this,width,bh,0,by,40,100,0);
X  }
X
void play_main::spawn() {
X  play_main *rsm = new play_main(animp,tptr,False);
X  rsm->init_lat();
X  lat->install_spawned(rsm->lat); // hook into redraw chain
X  new delete_button(*(rsm->mb),rsm);
X  rsm->RealizeChildren();   
X  rsm->lat->redraw();
}
X
/************************************************************************/
// class player has two handlers to switch
// between play and stop; to be used as primer window
player::player(animator *animp, int *tptr, Bool top) :
X  play_main(animp,tptr,True,top) { // to be centred
X    new instance_button <player> (*mb,"rotate",&player::rotate, this);
X    rot_mode = False; step_mode = False;
}
X
void player::play() { step_mode = True; pmset(); }
void player::stop() { step_mode = False; pmset(); }
void player::rotate() { rot_mode = ! rot_mode; pmset(); }
X
void player::polling_handler() {
X  if (step_mode) step_handler(); // the virtual handler of derived classes
X  if (rot_mode) lat->rotate_alpha(0.05); // rotate the lattice for some 3 grad
}    
/************************************************************************/
// class integrator : general purpose interface to invoke any program
// that solves time step integrations
// the members init_solver, step_solver, exit_solver must be defined by app
integrator::integrator(char *name, char *video_file, int nx, int ny, int animt)
X  : video_file(video_file), animt(animt), nx(nx), ny(ny), anim(name), 
X  player(&anim, &itime) { 
X    anim.nx = nx; anim.ny = ny;
X    XStoreName(display,Win,name); // must be set again 
X    // because of initialization order : player is always first initialized !
X    header = new char[200]; header[0] = 0; 
}
X
void integrator::reinit() { 
X  init_solver(); 
X  static Bool reinit = False; // first call is init
X  if (reinit) 
X    lat->redraw_spawned(); 
X  else reinit = True;  // second call is reinit
X  anim.init_write(video_file,header,nx,ny); 
}
X
void integrator::start() {
X  reinit();
X  init_lat(); // must be done here !
X  // add buttons unique to primer window
X  new instance_button <integrator> (*mb,"reinit",this->reinit, this);
X  new instance_button <integrator> (*mb,">",&integrator::step_handler,this);
X  new instance_button <player> (*mb,">>",&player::play, this);
X  new instance_button <player> (*mb,"||",this->stop, this);
X  new instance_button <play_main> (*mb,"spawn",this->spawn,this);
X  new quit_button(*mb);
X    
X  main_loop();
X  exit_solver();
}
void integrator::step_handler() {  
X  int itold = itime;
X  step_solver();   
X  lat->redraw_spawned();
X  // save results in video file every "animt" seconds
X  if (itime / animt != itold / animt) anim.write_step(itime);
X 
}
X
void integrator::add_column(char *menu, int nitems, d2disp *items) {
X  anim.add_column(menu, nitems, items); 
}
X
/************************************************************************/
// classes to make up a synchronous driven pipe 
// the "master" creates a pipe which should be given a command with "...-pipe"
// the "slave" process then polls from stdin integer indexes for which it 
// invokes "make_step" and sends an USR1 signal upon completion to wake up 
// the master
// istep = -1 is used to terminate the slave process
X 
#ifdef SPARC
extern "C" {
X  int sigpause(int);
X  int bzero(...); // used from FD_ZERO
X  int select(...);
}
#endif
X
#include <signal.h>
#include <sys/time.h>
X
static void sig_usr1(int) {  // used to wait on signal USR1 
X  signal(SIGUSR1, sig_usr1); //  printf("child interrupt\n");
}
X
void master::start_synchron(char *command, int istep) {
X  if (spipe) return; // only one possible 
X  spipe = popen(command,"w");
X  signal(SIGPIPE,sig_pipe);  
X  signal(SIGUSR1,sig_usr1); // used for wait with sigpause
X  synchronize(istep); // startup index
}
void master::synchronize(int istep) {
X  if (spipe) { // send actual timestep through pipe to child process
X    // printf(" send step %d\n",istep);
X    fprintf(spipe,"%d \n",istep); fflush(spipe);
X    if (spipe) sigpause(0); // wait for signal from child
X  }
}
X  
void master::cleanup() {
X  if (spipe) { // for termination of spawned processes
X    fprintf(spipe," -1 "); pclose(spipe); 
X  }
}
X
FILE* master::spipe; // definition needed
X
slave::slave() {
X  signal(SIGUSR1,sig_usr1); // I may receive it myself
}
X
// read from stdin (pipe) the step index and display it
void slave::pstep() { // used as poll handler for synchronized processes
X  fd_set readfd;
X  struct timeval timeout;
X  timeout.tv_sec = 0; timeout.tv_usec = 100000; // 100 msec 
X  // in readfd sind die Bits von stdin gesetzt
X  FD_ZERO(&readfd); FD_SET(0,&readfd);  
X  // select returns either if stdin has input, or timeout happens
X
#ifdef HP
X  int sel = select(8, (int*) &readfd, NULL, NULL , &timeout);
#else
X  int sel = select(8, &readfd, NULL, NULL , &timeout);
#endif 
X  if (sel == 0) return; // timeout
X
X  int istep; 
X  scanf("%d",&istep);
X  // printf(" receive step = %i\n",istep);
X  if (istep == -1) exit(0); // termination from spawner
X  make_step(istep);
X  kill(0,SIGUSR1); // awake parent process from sigpause !
}
X
SHAR_EOF
chmod 0644 animator.c ||
echo 'restore of animator.c failed'
Wc_c="`wc -c < 'animator.c'`"
test 16979 -eq "$Wc_c" ||
	echo 'animator.c: original size 16979, current size' "$Wc_c"
fi
# ============= wave.c ==============
if test -f 'wave.c' -a X"$1" != X"-c"; then
	echo 'x - skipping wave.c (File already exists)'
else
echo 'x - extracting wave.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'wave.c' &&
// wave.c : wolf 7/95
//   demo program for three-dim.c : solution of threedim wave eq.
X
#include "three-nxnynz.h"
X
double t[NZP2][NYP2][NXP2], tp[NZP2][NYP2][NXP2], dt[NZP2][NYP2][NXP2];
X
double gamma;
double deltat = 10;
double cdx = 0.001; // paramter == c*dx
X
double sqr(double x) { return x*x; }
X
void wave_init(int *tptr) {
X  int x,y,z;
X  for (x=0; x<NXP2; x++) for (y=0; y<NYP2; y++) for (z=0; z<NZP2; z++) {
X    t[z][y][x] = 0.; 
X    tp[z][y][x] = 0.;
X  }
X  for (x=4; x<7; x++) for (y=4; y<7; y++) for (z=0; z<3; z++) 
X   t[z][y][x] = 1.0;
X  *tptr = 0;
X  gamma = sqr(cdx*deltat);
X  //  printf("init %x\n",&t);
}
X
void wave_step(int *tptr) { 
X  int x,y,z;
X  for (x=0; x<NXP2; x++) for (y=0; y<NYP2; y++) for (z=0; z<NZP2; z++) {
X
X    double tt = t[z][y][x], dt2 = 6*tt;
X    // assumes values beyond boundaries = 0
X    if (x > 0)      dt2 -= t[z][y][x-1]; 
X    if (x < NXP2-1) dt2 -= t[z][y][x+1];
X    if (y > 0)      dt2 -= t[z][y-1][x]; 
X    if (y < NYP2-1) dt2 -= t[z][y+1][x];
X    if (z > 0)      dt2 -= t[z-1][y][x]; 
X    if (z < NZP2-1) dt2 -= t[z+1][y][x];
X       
X	t[z][y][x] =  2*tt - tp[z][y][x] - gamma*dt2;
X    dt[z][y][x] = tt -  tp[z][y][x];
X    tp[z][y][x] = tt;
X  }
X  *tptr += (int) deltat;
X
}
X
void wave_exit() {
}
X
X
X 
SHAR_EOF
chmod 0644 wave.c ||
echo 'restore of wave.c failed'
Wc_c="`wc -c < 'wave.c'`"
test 1242 -eq "$Wc_c" ||
	echo 'wave.c: original size 1242, current size' "$Wc_c"
fi
# ============= three-nxnynz.h ==============
if test -f 'three-nxnynz.h' -a X"$1" != X"-c"; then
	echo 'x - skipping three-nxnynz.h (File already exists)'
else
echo 'x - extracting three-nxnynz.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'three-nxnynz.h' &&
#define NXP2 20
#define NYP2 15
#define NZP2 10
SHAR_EOF
chmod 0644 three-nxnynz.h ||
echo 'restore of three-nxnynz.h failed'
Wc_c="`wc -c < 'three-nxnynz.h'`"
test 48 -eq "$Wc_c" ||
	echo 'three-nxnynz.h: original size 48, current size' "$Wc_c"
fi
# ============= icon.h ==============
if test -f 'icon.h' -a X"$1" != X"-c"; then
	echo 'x - skipping icon.h (File already exists)'
else
echo 'x - extracting icon.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'icon.h' &&
#define icon_width 32
#define icon_height 32
static char icon_bits[] = {
X   0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
X   0x02, 0x00, 0x00, 0xe0, 0x02, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x08,
X   0x07, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01,
X   0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x80, 0x00, 0x02, 0x00, 0x40, 0x00,
X   0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x20, 0x00, 0x02, 0x40, 0x10, 0x10,
X   0xff, 0xff, 0xff, 0xff, 0x02, 0x40, 0x08, 0x10, 0x02, 0x00, 0x04, 0x00,
X   0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x02, 0x00,
X   0x22, 0x00, 0x01, 0x00, 0x42, 0x00, 0x01, 0x00, 0x82, 0x80, 0x00, 0x00,
X   0x02, 0x43, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
X   0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
X   0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
SHAR_EOF
chmod 0644 icon.h ||
echo 'restore of icon.h failed'
Wc_c="`wc -c < 'icon.h'`"
test 875 -eq "$Wc_c" ||
	echo 'icon.h: original size 875, current size' "$Wc_c"
fi
# ============= eventnames.h ==============
if test -f 'eventnames.h' -a X"$1" != X"-c"; then
	echo 'x - skipping eventnames.h (File already exists)'
else
echo 'x - extracting eventnames.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'eventnames.h' &&
static char *event_names[] = {
"",
"",
"KeyPress",
"KeyRelease",
"ButtonPress",
"ButtonRelease",
"MotionNotify",
"EnterNotify",
"LeaveNotify",
"FocusIn",
"FocusOut",
"KeymapNotify",
"Expose",
"GraphicsExpose",
"NoExpose",
"VisibilityNotify",
"CreateNotify",
"DestroyNotify",
"UnmapNotify",
"MapNotify",
"MapRequest",
"ReparentNotify",
"ConfigureNotify",
"ConfigureRequest",
"GravityNotify",
"ResizeRequest",
"CirculateNotify",
"CirculateRequest",
"PropertyNotify",
"SelectionClear",
"SelectionRequest",
"SelectionNotify",
"ColormapNotify",
"ClientMessage",
"MappingNotify" };
SHAR_EOF
chmod 0644 eventnames.h ||
echo 'restore of eventnames.h failed'
Wc_c="`wc -c < 'eventnames.h'`"
test 576 -eq "$Wc_c" ||
	echo 'eventnames.h: original size 576, current size' "$Wc_c"
fi
true || echo 'restore of README.txt failed'
echo End of part 2, continue with part 3
exit 0


