/* sounding.c */

/*ha*/
/*
 * Vis5D system for visualizing five dimensional gridded data sets.
 * Copyright (C) 1990 - 2000 Bill Hibbard, Johan Kellum, Brian Paul,
 * Dave Santek, and Andre Battaiola.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * As a special exception to the terms of the GNU General Public
 * License, you are permitted to link Vis5D with (and distribute the
 * resulting source and executables) the LUI library (copyright by
 * Stellar Computer Inc. and licensed for distribution with Vis5D),
 * the McIDAS library, and/or the NetCDF library, where those
 * libraries are governed by the terms of their own licenses.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "../config.h"


/*
 * This plots temperature and dewpoint on a skew-t or
 * plots up to three vertical plots of any variable 
 */


#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "globals.h"
#include "graphics.h"
#include "grid.h"
#include "memory.h"
#include "proj.h"
#include "gui.h"
#include "sounding.h"
#include "soundingGUI.h"

#if HAVE_OPENGL
#  include <GL/gl.h>
#elif HAVE_SGI_GL
#  include <gl/gl.h>
#endif

#include "vis5d.h"

/* MJK 12.15.98 */
#  include      "topo.h"
#  include      "v5d.h"
#  define SOUND_BARB_SIZE               48
#  define PI                            3.14159265


#define BORDER 65 

#define HEBGBS 0  

#define TICK_DASH_LENGTH 2 

#define PF_TRUECOLOR 0

#define PF_XALLOC    1

#define PF_8BIT      2





Status SND_XAllocColor( Display *dpy, Colormap cmap, int cmap_size,
                        XColor *color );

void SND_Initialize( Display_Context dtx, Display *display,
                     Visual *visual, int depth, Colormap colormap );

GC make_gc(Display_Context dtx, int foregroundR, int foregroundG, int foregroundB,
                  int backgroundR, int backgroundG, int backgroundB, int linewidth);

static void make_soundpixmap( Display_Context dtx);

static void draw_var_stuff( Display_Context dtx, int var, Context varctx);

static void draw_ticks( Display_Context dtx, int var, Context varctx);

static void draw_box ( Display_Context dtx );

static float svp( float K);

static float mixratio( float K, float pres );

static float thetaE( float pres, float temp);
  
static float get_temp_for_thte(float thte, float pres);

static void draw_wlines( Display_Context dtx);

static void draw_thtelines( Display_Context dtx );

static void draw_thtalines( Display_Context dtx );

static void cut_line_data2( Display_Context dtx, int *x1, int *y1, int *x2, int *y2);

static void precut_line_data (Display_Context dtx, int *x1, int *y1, int x2, int y2);

static void cut_line_data( Display_Context dtx, int x1, int y1, int *x2, int *y2);

static void draw_vert_stuff( Display_Context dtx );

static void draw_millibarlines ( Display_Context dtx );


/* MJK 12.15.98 */
static void draw_templines( Display_Context dtx );
static void make_a_barb( Display_Context dtx, float spd, float dir,
                         float height, int barb_size);




static void drawbarbflag( Display_Context dtx, XPoint flagpoints[], int up, float dir);

static void drawbarbline( Display_Context dtx, int x1, int y1, int x2, int y2,
                           int up, float dir);

static void convert_xy_to_barb(Display_Context dtx, int inx, int iny, float dir,
                                          int *outx, int *outy);

void vardata_to_xy(Display_Context dtx, float alt, float value, float min, float max, int *x, int *y);

void setvarsteps( Display_Context dtx);

void data_to_xy(Display_Context dtx, float alt, float temp, int *x, int *y);

void data_to_y (Display_Context dtx, float alt, int *y);

float grid_level_to_height( Display_Context dtx, float level );

static int extract_sound( Display_Context dtx, float *grid, int var,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col);

static int extract_soundPRIME( Context ctx, int var,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col);

static int extract_wind( Display_Context dtx, float *gridu, float *gridv,
                             int varu, int varv,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col);

static int extract_windPRIME( Context ctx, 
                             int varu, int varv,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col);

static float winterval[34] = { 0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.5,
                               2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 7.0, 
                               8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0,
                               20.0, 24.0, 28.0, 32.0, 36.0, 40.0, 44.0,
                               48.0, 52.0, 56.0, 60.0, 68.0, 76.0 };

static int pixelformat;

static unsigned long ctable8[5][9][5];   /* Only for PF_8BIT */

static unsigned long rtable[256], gtable[256], btable[256];  /* PF_TRUECOLOR */




    /**********************************************************************/
    /* This just resizes the window to the given width and height         */
    /**********************************************************************/
    /* Input: dtx- display context index                                  */
    /*        width- the width of the resized window                      */
    /*        height- the height of the resized window                    */
    /**********************************************************************/


void resize_snd_window(Display_Context dtx, int width, int height, int x, int y)
{
   if (!dtx->Sound.soundwin){
      return;
   }
   dtx->Sound.soundwin_width = width;
   dtx->Sound.soundwin_height = height;
   if (x==0 && y == 0 ){
      x = dtx->Sound.sndx;
      y = dtx->Sound.sndy;
   }
   else {
      dtx->Sound.sndx = x;
      dtx->Sound.sndy = y;
   }
   XMoveResizeWindow( SndDpy, dtx->Sound.soundwin, x, y, width, height);
   if (dtx->Sound.SoundCtrlWindow != 0){
      if (dtx->Sound.otherdpy){
         dtx->Sound.sndheight = height -2*BORDER;
      }
      else {
         dtx->Sound.sndheight = height -95 -2*BORDER;
      }
      dtx->Sound.sndwidth =  width - 2 * BORDER;
      do_pixmap_art ( dtx );
      draw_sounding(dtx, dtx->CurTime);
   }
   else {
      dtx->Sound.sndheight = height - 2 * BORDER;
      dtx->Sound.sndwidth =  width - 2 * BORDER;
      do_pixmap_art ( dtx );
      draw_sounding(dtx, dtx->CurTime);
   }
}   




/*
 * Given an RGB color, return the corresponding pixel value.
 * Input;  r, g, b - red, green, and blue in [0,255]
 * Return:  a pixel value
 *
 ***** This is the same code found in lui.c lines 236 - 263 ****
 */
unsigned long SND_AllocateColorInt( int r, int g, int b )
{
   XColor xcol;

   switch (pixelformat) {
      case PF_TRUECOLOR:
         return rtable[r] | gtable[g] | btable[b];
      case PF_8BIT:
         return ctable8[r/52][g/31][b/52];
      case PF_XALLOC:
         xcol.red = r << 8;
         xcol.green = g << 8;
         xcol.blue = b << 8;
         SND_XAllocColor( SndDpy, SndColormap, SndVisual->map_entries,
                          &xcol );
         return xcol.pixel;
      default:
         printf("Error in SND_AllocateColorInt %d\n", pixelformat);
         exit(0);
   }
   return 0;
}


/*
 * A replacement for XAllocColor.  This function should never fail
 * to allocate a color.  When XAllocColor fails we return the nearest
 * matching color.
 *
 ***** This is the same code found in lui.c lines 181 - 232 **** 
 */
Status SND_XAllocColor( Display *dpy, Colormap cmap, int cmap_size,
                        XColor *color )
{
   int p, bestmatch;
   double dist, mindist;  /* 3*2^16^2 exceeds long int precision */
   static XColor *allcolors = NULL;
   XColor *acptr;

#define DISTANCE(r1,g1,b1,r2,g2,b2)  ( ((r2)-(r1)) * ((r2)-(r1)) + \
    ((g2)-(g1)) * ((g2)-(g1)) + ((b2)-(b1)) * ((b2)-(b1)) )

   if (!XAllocColor(dpy, cmap, color)) {
      /* query whole colormap if not yet done */
      if (!allcolors) {
         allcolors = (XColor *) malloc( cmap_size * sizeof(XColor) );
         for (p = 0;  p < cmap_size;  p++)
           allcolors[p].pixel = p;
         XQueryColors (dpy, cmap, allcolors, cmap_size);
      }

      /* find best match */
      bestmatch = -1;
      mindist = 0.0;
      p = cmap_size;
      while (p--) {
         acptr = allcolors + p;
         dist = DISTANCE( (double)color->red, (double)color->green,
                          (double)color->blue, (double)acptr->red,
                          (double)acptr->green, (double)acptr->blue);
         if (bestmatch < 0 || dist < mindist)
           mindist = dist, bestmatch = p;
      }
      color->red   = allcolors[bestmatch].red;
      color->green = allcolors[bestmatch].green;
      color->blue  = allcolors[bestmatch].blue;
      if (!XAllocColor( dpy, cmap, color )) {
         /* this is a real hack but should be good enough */
         color->pixel = bestmatch;
      }
   }
#undef DISTANCE

   return 1;
}


/*
 * Input:  program_name - the label for all window title bars
 *         display - the X display (or NULL)
 *         visual - the X visual (or NULL)
 *         depth - the depth of the visual (or 0)
 *         colormap - the X colormap (or 0)
 */
void SND_Initialize(  Display_Context dtx, Display *display,
                     Visual *visual, int depth, Colormap colormap )
{
   static int initialized = 0;
   XVisualInfo visinfo;

   /* Only do this once */
   if (initialized)
      return;
   else
      initialized = 1;

 
   /* Open the display if one wasn't passed (already opened) */
   if (display) {
      SndDpy  = display;
   }
   else {
      SndDpy = XOpenDisplay(NULL);
      if (!SndDpy) {
         printf("Can't open sound display");
      }
   }

   /* Set defaults */
   SndRootWindow = DefaultRootWindow (SndDpy);
   SndScr        = DefaultScreen ( SndDpy );
   SndScrWidth   = DisplayWidth (SndDpy, SndScr );
   SndScrHeight  = DisplayHeight( SndDpy, SndScr );


   if (visual) {
      SndVisual = visual;
      SndDepth = depth;
      SndColormap = colormap;
   }
   else {
      if (XMatchVisualInfo( SndDpy,SndScr,24,TrueColor,&visinfo )) {
         SndVisual = visinfo.visual;
         SndDepth = 24;
         SndColormap = XCreateColormap( SndDpy, RootWindow(SndDpy, SndScr),
                                         SndVisual, AllocNone );
      }
      else {
         SndVisual = DefaultVisual( SndDpy, SndScr );
         SndDepth = DefaultDepth( SndDpy, SndScr );
         SndColormap = DefaultColormap( SndDpy, SndScr );
      }
   }

   /* Setup color allocation stuff */
   if (SndVisual->class==TrueColor || SndVisual->class==DirectColor) {
      /* Initialize rtable[], gtable[], and btable[] */
      XColor xcol;
      int i;
      xcol.green = 0;
      xcol.blue = 0;
      for (i=0;i<256;i++) {
         xcol.red = i * 0xffff / 0xff;
         XAllocColor( SndDpy, SndColormap, &xcol );
         rtable[i] = xcol.pixel;
      }
      xcol.red = 0;
      xcol.blue = 0;
      for (i=0;i<256;i++) {
         xcol.green = i * 0xffff / 0xff;
         XAllocColor( SndDpy, SndColormap, &xcol );
         gtable[i] = xcol.pixel;
      }
     xcol.red = 0;
      xcol.green = 0;
      for (i=0;i<256;i++) {
         xcol.blue = i * 0xffff / 0xff;
         XAllocColor( SndDpy, SndColormap, &xcol );
         btable[i] = xcol.pixel;
      }
      pixelformat = PF_TRUECOLOR;
   }
   else if (SndVisual->class==PseudoColor) {
      /* Note: the color allocation scheme must be the same as what's used */
      /* in Mesa to allow colormap sharing! */
      int r, g, b;
      for (r=0;r<5;r++) {
         for (g=0;g<9;g++) {
            for (b=0;b<5;b++) {
               XColor xcol;
               xcol.red   = r * 65535 / 4;
               xcol.green = g * 65535 / 8;
               xcol.blue  = b * 65535 / 4;
               SND_XAllocColor( SndDpy, SndColormap,
                                SndVisual->map_entries, &xcol );
               ctable8[r][g][b] = xcol.pixel;
            }
         }
      }
      pixelformat = PF_8BIT;
   }
   else {
      pixelformat = PF_XALLOC;
   }

#ifdef HAVE_OPENGL
	if(dtx->gfx[SOUND_FONT]==dtx->gfx[WINDOW_3D_FONT]){
	  free_Xgfx(dtx->gfx[SOUND_FONT]);
	  dtx->gfx[SOUND_FONT]=NULL;
	}
	if(dtx->gfx[SOUND_FONT]==NULL ){
	  Xgfx *new_Xgfx(Xgfx *gfx); /* api.c */
	  int set_opengl_font(char *name, Window GfxWindow, GLXContext gl_ctx, Xgfx *gfx);
	  dtx->gfx[SOUND_FONT]=new_Xgfx(NULL);
	  set_opengl_font(DEFAULT_SOUNDFONTNAME,dtx->Sound.soundwin, dtx->gl_ctx, dtx->gfx[SOUND_FONT]);
	}
#else
   /* Make sure SoundFontName is okay: */
   {
	  XFontStruct *fontinfo;
	  if (!(fontinfo = XLoadQueryFont(SndDpy, dtx->SoundFontName))) {
		 if ((fontinfo = XLoadQueryFont(SndDpy, DEFAULT_SOUNDFONTNAME))){
			strcpy(dtx->SoundFontName, DEFAULT_SOUNDFONTNAME);
		 }
		 else if ((fontinfo = XLoadQueryFont(SndDpy, "fixed"))) {
			fprintf(stderr, "SoundFontName defaulting to \"fixed\"\n");
			strcpy(dtx->SoundFontName, "fixed");
		 }
	  }
	  if (fontinfo)
		 XFreeFontInfo(0, fontinfo, 0);
	  else {
		 fprintf(stderr, "Failed opening DEFAULT_SOUNDFONTNAME (\"%s\")\n",
					DEFAULT_SOUNDFONTNAME);
	  }
   }
#endif
}




    /**********************************************************************/
    /* This makes a graphics context                                      */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        foregroundR - the red value 1..255 of the foreground        */
    /*        foregroundG - the green value 1..255 of the foreground      */
    /*        foregroundB - the blue value 1..255 of the foreground       */
    /*        backgroundR - the red value 1..255 fo the background        */
    /*        backgroundG - the green value 1..255 of the background      */
    /*        backgroundB - the blue value 1..255 of the background       */
    /*        linewidth - the line width value for the GC                 */
    /*                                                                    */
    /* Output: make_gc- the GC with the above specifications              */
    /**********************************************************************/

GC make_gc(Display_Context dtx, int foregroundR, int foregroundG, int foregroundB,
                  int backgroundR, int backgroundG, int backgroundB, int linewidth)
{
   XGCValues vals;
   
   vals.foreground = SND_AllocateColorInt(foregroundR,
                                   foregroundG, foregroundB);
   vals.background = SND_AllocateColorInt(backgroundR,
                                   backgroundG, backgroundB);
   vals.line_width = linewidth;
   return XCreateGC ( SndDpy, dtx->Sound.soundwin, GCLineWidth |
                      GCForeground | GCBackground, &vals );
}




    /**********************************************************************/
    /* This makes the window that all of the sounding graphics is         */
    /* drawn or mapped to.  The sndheight and sndwidth are the dimentions */
    /* inside this window to which the actual data is drawn to.           */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        title - title for window if there is no parent              */
    /*        xpos, ypos - the x and y position of the window if no parent*/
    /*        width, height - of the window                               */
    /* Output: 1 if it works                                              */
    /**********************************************************************/
    
int make_soundGFX_window( Display_Context dtx, char *title, int xpos, int ypos,
                           int width, int height, Window ctrlwindow, char *wdpy_name)
{
   XSetWindowAttributes attr;
   int attr_flags;
   XWindowAttributes winatts;
   int vertical;
   float vjunk[MAXLEVELS];
   int yo;
 


   dtx->Sound.SoundCtrlWindow = ctrlwindow;
   dtx->Sound.get_vert_data = 1;
   vis5d_get_dtx_vertical(dtx->dpy_context_index, &vertical, vjunk);
   dtx->Sound.vertsys = vertical;
   if( dtx->TopBound < 1.0 && dtx->BottomBound < -1.0 ) {
      dtx->Sound.oceanonly = 1;
   }
   else {
      dtx->Sound.oceanonly = 0;
   }
   SND_Initialize( dtx, SndDpy, SndVisual, SndDepth, SndColormap);
   /* now just set some variables for the first time */
   yo = dtx->ctxarray[0];
   dtx->Sound.mainvarstep = 50;
   dtx->Sound.SndMinTemp = 228.0;
   dtx->Sound.SndMaxTemp = 323.0;
   dtx->Sound.tickstatus = 0;
   dtx->Sound.currentX = .69;
   dtx->Sound.currentY = .69;
   dtx->Sound.currentTime =1069;
   dtx->Sound.soundline = NULL;
   dtx->Sound.uwindline = NULL;
   dtx->Sound.vwindline = NULL;
   dtx->Sound.tgrid = NULL;
   dtx->Sound.dgrid = NULL;
   dtx->Sound.ugrid = NULL;
   dtx->Sound.var1grid = NULL;
   dtx->Sound.var2grid = NULL;
   dtx->Sound.var3grid = NULL;
   dtx->Sound.vertdata = NULL;

   dtx->Sound.PreviousSoundTemp = vis5d_find_var(dtx->ctxarray[0],"T");
   dtx->Sound.PreviousSoundDewpt= vis5d_find_var(dtx->ctxarray[0],"TD");
   dtx->Sound.PreviousSoundUWind= vis5d_find_var(dtx->ctxarray[0],"U");
   dtx->Sound.PreviousSoundVWind= vis5d_find_var(dtx->ctxarray[0],"V");
   dtx->Sound.PreviousSoundVar1 = -1;
   dtx->Sound.PreviousSoundVar2 = -1;
   dtx->Sound.PreviousSoundVar3 = -1;
   dtx->Sound.sndx = 15;
   dtx->Sound.sndy = 15;
   vis5d_set_sound_vars( dtx->dpy_context_index, yo, vis5d_find_var(dtx->ctxarray[0],"T"),
                                yo, vis5d_find_var(dtx->ctxarray[0],"TD"),
                                yo, vis5d_find_var(dtx->ctxarray[0],"U"),
                                yo, vis5d_find_var(dtx->ctxarray[0],"V"),
                                yo, -1, yo, -1, yo, -1 );

   attr.event_mask = ExposureMask | ButtonMotionMask | KeyReleaseMask
                           | KeyPressMask | ButtonPressMask | ButtonReleaseMask
                        | StructureNotifyMask | VisibilityChangeMask;
 
   attr.colormap = SndColormap;
   attr.background_pixel = BlackPixel( SndDpy, SndScr );
   attr.border_pixel =BlackPixel( SndDpy, SndScr ); 
   attr_flags = CWColormap | CWEventMask | CWBackPixel | CWBorderPixel;
   if (wdpy_name != NULL) {
      dtx->Sound.otherdpy = 1;
   }
   if (dtx->Sound.soundwin){
      XDestroyWindow(SndDpy, dtx->Sound.soundwin);
   }
   if ((dtx->Sound.SoundCtrlWindow != 0) && (wdpy_name == NULL)) {
      XGetWindowAttributes( SndDpy, dtx->Sound.SoundCtrlWindow, &winatts);

      dtx->Sound.soundwin = XCreateWindow(SndDpy, dtx->Sound.SoundCtrlWindow,
                       0, 95, winatts.width, winatts.height-95+HEBGBS,
                       1, SndDepth, InputOutput,
                       SndVisual, attr_flags, &attr);
      dtx->Sound.soundwin_width = winatts.width;
      dtx->Sound.soundwin_height= winatts.height-95+HEBGBS;
      dtx->Sound.sndheight = winatts.height-95-2*BORDER;
      dtx->Sound.sndwidth = winatts.width-2*BORDER;
   }
   else {
      XSizeHints sizehints;

      dtx->Sound.soundwin = XCreateWindow(SndDpy, RootWindow(SndDpy, SndScr),
                       xpos, ypos, width, height, 1, SndDepth, InputOutput,
                       SndVisual, attr_flags, &attr);
      dtx->Sound.soundwin_width = width;
      dtx->Sound.soundwin_height= height ;
      dtx->Sound.sndheight = height -2*BORDER;
      dtx->Sound.sndwidth  = width - 2*BORDER;
      sizehints.x = 20;
      sizehints.y = 40;
      sizehints.width = 200;
      sizehints.height = 200;
      sizehints.flags = PPosition | PSize; 

      XSetStandardProperties(SndDpy, dtx->Sound.soundwin,
                             "Skew-T and Vertical Plot Display",
                             "Skew-T and Vertical Plot Display",
                             None, (char**)NULL, 0, &sizehints);

   }
   /* MJK 12.15.98 */
   dtx->Sound.vert_gc  = make_gc(dtx, 255, 255, 255, 0, 0, 0, 2);
   dtx->Sound.Tempgc   = make_gc(dtx, 255, 0, 0, 0, 0, 0, 2);
   dtx->Sound.Dewptgc  = make_gc(dtx, 0, 255, 0, 0, 0, 0, 2);
   dtx->Sound.barb_gc  = make_gc(dtx, 0, 255, 255, 0, 0, 0, 2);
   dtx->Sound.barb2_gc = make_gc(dtx, 255, 255, 255, 0, 0, 0, 1);
   dtx->Sound.var1_gc  = make_gc(dtx, 255, 255, 0, 0, 0, 0, 2);
   dtx->Sound.var2_gc  = make_gc(dtx, 255, 0, 255, 0, 0, 0, 2);
   dtx->Sound.var3_gc  = make_gc(dtx, 255, 255, 255, 0, 0, 0, 2);
   dtx->Sound.rect_gc  = make_gc(dtx, 0, 0, 0, 1, 1, 1, 1);
   dtx->Sound.box_gc   = make_gc(dtx, 160, 160, 160, 0, 0, 0, 1);
   yo = height_to_pressure (dtx->BottomBound) + 0.5;
   /* if (yo % 50) yo += 50; WLH 7 June 2000 */
   if (yo < 50) yo += 50;
   dtx->Sound.BotPress = (yo / 50) * 50;
   yo = height_to_pressure (dtx->TopBound);
   if (yo < 50) yo += 50;
   dtx->Sound.TopPress = (yo / 50) * 50;
   dtx->Sound.TopHgt   = pressure_to_height ((float) dtx->Sound.TopPress);
   dtx->Sound.BotHgt   = pressure_to_height ((float) dtx->Sound.BotPress);
   dtx->Sound.DiffHgt  = dtx->Sound.TopHgt - dtx->Sound.BotHgt;
/*

   dtx->Sound.vert_gc = make_gc(dtx, 255, 255, 255, 0, 0, 0, 2);
   dtx->Sound.Tempgc = make_gc(dtx, 255, 255, 255, 0, 0, 0, 2);
   dtx->Sound.Dewptgc= make_gc(dtx, 255, 0, 255, 0, 0, 0, 2);
   dtx->Sound.barb_gc = make_gc(dtx, 0, 0, 255, 0, 0, 0, 2);
   dtx->Sound.barb2_gc= make_gc(dtx, 255,255,255, 0, 0, 0, 1);
   dtx->Sound.var1_gc = make_gc(dtx, 0, 255, 0, 0, 0, 0, 2);
   dtx->Sound.var2_gc = make_gc(dtx, 100, 255, 255, 0, 0, 0, 2);
   dtx->Sound.var3_gc = make_gc(dtx, 255, 255, 100, 0, 0, 0, 2);
   dtx->Sound.rect_gc =  make_gc(dtx, 0, 0, 0, 1, 1, 1, 1);
   dtx->Sound.box_gc =  make_gc(dtx, 169, 169, 169, 0, 0, 0, 1);
*/

   {
	  XFontStruct *fontinfo;

	  if ((fontinfo = XLoadQueryFont(SndDpy, dtx->gfx[SOUND_FONT]->FontName))){
		 XSetFont(SndDpy, dtx->Sound.var1_gc, fontinfo->fid);
		 XSetFont(SndDpy, dtx->Sound.var2_gc, fontinfo->fid);
		 XSetFont(SndDpy, dtx->Sound.var3_gc, fontinfo->fid);
		 XFreeFontInfo(NULL, fontinfo, 0);
	  }
	  else{
		 fprintf(stderr, "warning: couldn't load font \"%s\"\n",
					dtx->gfx[SOUND_FONT]->FontName);
	  }
   }
   do_pixmap_art(dtx);

   return 1;
}

    /**********************************************************************/
    /* This makes the pixmap to which all the extraneous graphics         */
    /* such as the theta lines, thtate lines, millibar lines, outside box */
    /* are drawn to.                                                      */
    /**********************************************************************/
    /* Input - context                                                    */
    /**********************************************************************/

static void make_soundpixmap( Display_Context dtx)
{
   if (dtx->Sound.soundpix){
      XFreePixmap(SndDpy, dtx->Sound.soundpix);
   } 
   if( dtx->Sound.SoundCtrlWindow ) {
      dtx->Sound.soundpix = XCreatePixmap( SndDpy, dtx->Sound.soundwin,
                                          dtx->Sound.sndwidth+2*BORDER,
                                          dtx->Sound.sndheight+95+2*BORDER,
                                          SndDepth);
      XFillRectangle(SndDpy, dtx->Sound.soundpix, dtx->Sound.rect_gc, 0, 0,
                     dtx->Sound.sndwidth+2*BORDER,
                     dtx->Sound.sndheight + 95 +2*BORDER);
   }
   else {
      dtx->Sound.soundpix = XCreatePixmap( SndDpy, dtx->Sound.soundwin,
                                          dtx->Sound.sndwidth+2*BORDER,
                                          dtx->Sound.sndheight+2*BORDER,
                                          SndDepth);
      XFillRectangle(SndDpy, dtx->Sound.soundpix, dtx->Sound.rect_gc, 0, 0,
                     dtx->Sound.sndwidth+2*BORDER,
                     dtx->Sound.sndheight+2*BORDER);
   }
}

    /**********************************************************************/
    /* This draws all the extraneous gphics to a pixmap if they are wanted*/
    /**********************************************************************/
    /* Input - context                                                    */
    /**********************************************************************/

void do_pixmap_art( Display_Context dtx )
{ 

   setvarsteps( dtx);

   make_soundpixmap( dtx);
   if ( dtx->Sound.wstatus ){
      draw_wlines(dtx);
   }
   if ( dtx->Sound.thtestatus ){
      draw_thtelines(dtx);
   }
   if ( dtx->Sound.thtastatus ){
      draw_thtalines(dtx);
   }

   /* MJK 12.15.98 */
   if ( dtx->Sound.tempstatus ){
      draw_templines(dtx);
   }


   if (dtx->Sound.SoundVar1 >= 0){
      draw_var_stuff(dtx, dtx->Sound.SoundVar1, dtx->Sound.SoundVar1Owner);
      if(dtx->Sound.tickstatus) draw_ticks(dtx, dtx->Sound.SoundVar1,
                                           dtx->Sound.SoundVar1Owner);
   }
   if (dtx->Sound.SoundVar2 >= 0){
      draw_var_stuff(dtx, dtx->Sound.SoundVar2, dtx->Sound.SoundVar2Owner);
      if(dtx->Sound.tickstatus) draw_ticks(dtx, dtx->Sound.SoundVar2,
                                           dtx->Sound.SoundVar2Owner);
   }
   if (dtx->Sound.SoundVar3 >= 0){
      draw_var_stuff(dtx, dtx->Sound.SoundVar3, dtx->Sound.SoundVar3Owner);
      if(dtx->Sound.tickstatus) draw_ticks(dtx, dtx->Sound.SoundVar3,
                                           dtx->Sound.SoundVar3Owner);
   }
   if ((dtx->Sound.vertsys != 0) && (dtx->Sound.oceanonly != 1))  draw_millibarlines(dtx);
   draw_box(dtx);
   if (!dtx->Sound.get_vert_data)  draw_vert_stuff(dtx);
}


    /**********************************************************************/
    /* This draws the numbers and unit for each variable alond the bottom */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        var - the variable whose numbers and unit should be drawn   */
    /**********************************************************************/

static void draw_var_stuff( Display_Context dtx, int var, Context varctx)
{
   int counter= -1;
   float yo, step;
   GC var_gc;
   char num[9];
   int vary = 25;
   int stringnumber;
   int strlength = 0;

   if (var == dtx->Sound.SoundVar1 &&
       varctx == dtx->Sound.SoundVar1Owner){
      var_gc = dtx->Sound.var1_gc;
      vary += 10;
      step = dtx->Sound.var1step;
      strlength = strlen(dtx->Sound.SoundVar1Owner->Variable[var]->Units);
   }
   if (var == dtx->Sound.SoundVar2 &&
       varctx == dtx->Sound.SoundVar2Owner){
      var_gc = dtx->Sound.var2_gc;
      vary += 22;
      step = dtx->Sound.var2step;
      strlength = strlen(dtx->Sound.SoundVar2Owner->Variable[var]->Units);
   }
   if (var == dtx->Sound.SoundVar3 &&
       varctx == dtx->Sound.SoundVar3Owner){
      var_gc = dtx->Sound.var3_gc;
      vary += 34;
      step = dtx->Sound.var3step;
      strlength = strlen(dtx->Sound.SoundVar3Owner->Variable[var]->Units);
   }
   if (dtx->Sound.samestepflag){
      for ( yo = dtx->Sound.samestepmin; yo <= dtx->Sound.samestepmax; yo += step){
         counter ++;
         sprintf(num, "%.1f\n", yo );
         stringnumber = strlen(num)-1;
         if ( (dtx->Sound.mainvarstep * counter)+BORDER < dtx->Sound.sndwidth+BORDER){
            XDrawString( SndDpy, dtx->Sound.soundpix, var_gc,
                         (dtx->Sound.mainvarstep * counter+1)+BORDER-15,
                          dtx->Sound.sndheight+BORDER-HEBGBS+vary,
                          num, stringnumber);
         }
         if(stringnumber > 7){
            yo += step;
            counter ++;
         }
      }
   }
   else{
      for ( yo = varctx->Variable[var]->MinVal; yo <= varctx->Variable[var]->MaxVal; yo += step){
         counter ++;
         sprintf(num, "%.1f\n", yo );
         stringnumber = strlen(num)-1;
         if ( (dtx->Sound.mainvarstep * counter)+BORDER < dtx->Sound.sndwidth+BORDER){
            XDrawString( SndDpy, dtx->Sound.soundpix, var_gc,
                         (dtx->Sound.mainvarstep * counter+1)+BORDER-15,
                          dtx->Sound.sndheight+BORDER-HEBGBS+vary,
                          num, stringnumber);
         }
         if(stringnumber > 7){
            yo += step;
            counter ++;
         }
      }    
   }
   XDrawString( SndDpy, dtx->Sound.soundpix, var_gc,             
                BORDER - 45, dtx->Sound.sndheight + BORDER-HEBGBS+vary,
                varctx->Variable[var]->Units, strlength);
}

   /*****************************************************************/
   /* This draws the vertical ticks for the different vars          */
   /*****************************************************************/
   /* Input: dtx- context                                           */
   /*        var - the variable for which the vertical ticks should */
   /*              be drawn                                         */
   /*****************************************************************/

 
static void draw_ticks( Display_Context dtx, int var, Context varctx)
{
   float step, yo;
   int counter;
   static  char dotted[2] = {4,12};
   char *dash_list[] = {dotted};
   GC var_gc;

   XSetLineAttributes(SndDpy, dtx->Sound.var1_gc, 1, LineOnOffDash, CapButt, JoinRound);
   XSetLineAttributes(SndDpy, dtx->Sound.var2_gc, 1, LineOnOffDash, CapButt, JoinRound);
   XSetLineAttributes(SndDpy, dtx->Sound.var3_gc, 1, LineOnOffDash, CapButt, JoinRound);
   XSetDashes(SndDpy, dtx->Sound.var1_gc, 1, dash_list[0], 2);
   XSetDashes(SndDpy, dtx->Sound.var2_gc, 5, dash_list[0], 2);
   XSetDashes(SndDpy, dtx->Sound.var3_gc, 9, dash_list[0], 2);
   counter = -1;
   if (var == dtx->Sound.SoundVar1 &&
       varctx == dtx->Sound.SoundVar1Owner){
       var_gc = dtx->Sound.var1_gc;
       step = dtx->Sound.var1step;
   }
   if (var == dtx->Sound.SoundVar2 &&
       varctx == dtx->Sound.SoundVar2Owner){
      var_gc = dtx->Sound.var2_gc;
      step = dtx->Sound.var2step;
   }
   if (var == dtx->Sound.SoundVar3 &&
       varctx == dtx->Sound.SoundVar3Owner){
      var_gc = dtx->Sound.var3_gc;
      step = dtx->Sound.var3step;
   } 
   if (dtx->Sound.samestepflag){
      for ( yo = varctx->Variable[var]->MinVal; yo < varctx->Variable[var]->MaxVal; yo += step){
         counter ++;
         if ( (dtx->Sound.mainvarstep * counter)+BORDER < dtx->Sound.sndwidth+BORDER){
            XDrawLine( SndDpy, dtx->Sound.soundpix, var_gc,
                    (dtx->Sound.mainvarstep * counter)+BORDER, dtx->Sound.sndheight+BORDER-HEBGBS,
                    (dtx->Sound.mainvarstep * counter)+BORDER, BORDER-HEBGBS);
         }
      }
   }
   else {
      for ( yo = varctx->Variable[var]->MinVal; yo < varctx->Variable[var]->MaxVal; yo += step){
         counter ++;
         if ( (dtx->Sound.mainvarstep * counter)+BORDER < dtx->Sound.sndwidth+BORDER){
            XDrawLine( SndDpy, dtx->Sound.soundpix, var_gc, 
                    (dtx->Sound.mainvarstep * counter)+BORDER, dtx->Sound.sndheight+BORDER-HEBGBS,
                    (dtx->Sound.mainvarstep * counter)+BORDER, BORDER-HEBGBS);
         }
      }
   }
   XSetLineAttributes(SndDpy, dtx->Sound.var1_gc, 2, LineSolid, CapButt, JoinRound);
   XSetLineAttributes(SndDpy, dtx->Sound.var2_gc, 2, LineSolid, CapButt, JoinRound);
   XSetLineAttributes(SndDpy, dtx->Sound.var3_gc, 2, LineSolid, CapButt, JoinRound);

}   
    /**********************************************************************/
    /* This draws the main border box surrounding the sounding data       */
    /**********************************************************************/
    /* Input: dtx -context                                                */
    /**********************************************************************/

static void draw_box ( Display_Context dtx )
{ 
   XDrawLine ( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
               BORDER, BORDER-5-HEBGBS, dtx->Sound.sndwidth+BORDER, BORDER-5-HEBGBS);

   XDrawLine ( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
               dtx->Sound.sndwidth+BORDER, BORDER-5-HEBGBS, dtx->Sound.sndwidth+BORDER,
               dtx->Sound.sndheight+BORDER-HEBGBS);

   XDrawLine ( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
               BORDER, BORDER-5-HEBGBS, BORDER, dtx->Sound.sndheight+BORDER-HEBGBS);
   if((dtx->Sound.vertsys == 0) || (dtx->BottomBound < -1.0)){
      XDrawLine ( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
               BORDER, dtx->Sound.sndheight+BORDER-HEBGBS,
               dtx->Sound.sndwidth+BORDER, dtx->Sound.sndheight+BORDER-HEBGBS);
   }
}

    /**********************************************************************/
    /* This returns the saturation vapor pressure for a specified         */
    /* temperature in Kelvin                                              */
    /**********************************************************************/
    /* Input: K - temperature in Kelvin                                   */
    /* Output: svp - the saturation vapor pressure                        */
    /**********************************************************************/

static float svp( float K)
{
   float hit;

   hit = exp( (17.2693882*K - 4717.306) / (K - 35.7) );
   return  (6.1078 * hit);
}

    /**********************************************************************/
    /* This returns a mixing ration for a given temperature in Kelvin     */
    /* and a given pressure in millibars                                  */
    /**********************************************************************/
    /* Input: K - temperature in Kelvin                                   */
    /*        pres- pressure in millibars                                 */
    /* Output: mixratio - the mixing ratio                                */
    /**********************************************************************/

static float mixratio( float K, float pres )
{
   return (621.97 * svp(K) / ( pres - svp(K)));
}

    /**********************************************************************/
    /* This will give a thta-e at 1012.5 millibars for a given            */
    /* pressure in millibars and temperature in Kelvin                    */
    /**********************************************************************/
    /* Input: pres - pressure in millibars                                */
    /*        temp - temperature in Kelvin                                */
    /* Output: thetaE - theta-E in Kelvin                                 */
    /**********************************************************************/

static float thetaE( float pres, float temp)
{
   float thta, te;

   thta = temp * pow((1012.5/pres),.286);
   te = thta * exp(2.6518986* mixratio(temp, pres) / temp);
   return te;
}

    /**********************************************************************/
    /* This will approximate what the temperature(K)    for a given       */
    /* pressure (Millibars) and a given thetaE (K)                        */
    /**********************************************************************/
    /* Input: thte - Theta-E in Kelvin                                    */
    /*        pres - pressure in millibars                                */
    /* Output: get_temp_for_thte - the returned temperature in Kelving    */
    /**********************************************************************/

   
static float get_temp_for_thte(float thte, float pres)
{
   float tgnu= 293.16;
   float tgnup, tenu, tenup, cor;
   int x;

   for (x=1; x < 100; x++){
      tgnup = tgnu + 1.0;
      tenu = thetaE( pres, tgnu);
      tenup =thetaE( pres, tgnup);
      cor = (thte - tenu) / (tenup - tenu);
      tgnu = tgnu + cor;
      if (( cor < .01) && ((-1 * cor) < .01)){
         return tgnu;
      }
   }
   return 9999.9;
}




/* MJK 12.15.98 begin */
/*
 *  The sounding background grids have been changed to more closely
 *  resemble those of the sounding plots on NWS AWIPS and WFO-Advanced
 *  systems.
 *  These grids may not be desired by everyone.
 */

#define CLIP_PT1_CLIPPED        1
#define CLIP_PT2_CLIPPED        2
#define CLIP_BOTH_CLIPPED       3
#define CLIP_BOTH_OUT           -1

#define CLIP_MOVE_X(VAL,X,Y)    X = (VAL), Y = ((((VAL) * dy) + a) / dx)
#define CLIP_MOVE_Y(VAL,Y,X)    Y = (VAL), X = ((((VAL) * dx) - a) / dy)



static int clip_line_seg (Display_Context dtx,
                          int *ix1, int *iy1, int *ix2, int *iy2)
{
   int          clip_stat, ixa, iya, ixb, iyb;
   float        x1, y1, x2, y2, dx, dy, a, w, h;

   x1 = *ix1, y1 = *iy1;
   x2 = *ix2, y2 = *iy2;

   dx = x2 - x1;
   dy = y2 - y1;
   a  = (y1 * dx) - (x1 * dy);

   w  = dtx->Sound.sndwidth;
   h  = dtx->Sound.sndheight;

   /* WLH 29 August 2000 */
   if (fabs(x1) > 10000.0 || fabs(y1) > 10000.0 ||
       fabs(x2) > 10000.0 || fabs(y2) > 10000.0) {
      return CLIP_BOTH_OUT;
   }

   /* MJK 3.22.99 */
   if (x1 < 0.0 && y1 < 0.0){
      return CLIP_BOTH_OUT;
   }

   if (x1 < 0.0)
   {
      if (x2 < 0.0) return CLIP_BOTH_OUT;
      CLIP_MOVE_X(0.0, x1, y1);
   }
   else if (x1 > w)
   {
      if (x2 > w) return CLIP_BOTH_OUT;
      CLIP_MOVE_X(w, x1, y1);
   }

   if (y1 < 0.0)
   {
      if (y2 < 0.0) return CLIP_BOTH_OUT;
      CLIP_MOVE_Y(0.0, y1, x1);
   }
   else if (y1 > h)
   {
      if (y2 > h) return CLIP_BOTH_OUT;
      CLIP_MOVE_Y(h, y1, x1);
   }

   if (x2 < 0.0)
   {
      CLIP_MOVE_X(0.0, x2, y2);
   }
   else if (x2 > w)
   {
      CLIP_MOVE_X(w, x2, y2);
   }

   if (y2 < 0.0)
   {
      CLIP_MOVE_Y(0.0, y2, x2);
   }
   else if (y2 > h)
   {
      CLIP_MOVE_Y(h, y2, x2);
   }

   ixa = x1 + 0.5, iya = y1 + 0.5;
   ixb = x2 + 0.5, iyb = y2 + 0.5;

   clip_stat = 0;
   if ((ixa != *ix1) || (iya != *iy1)) clip_stat |= CLIP_PT1_CLIPPED;
   if ((ixb != *ix2) || (iyb != *iy2)) clip_stat |= CLIP_PT2_CLIPPED;
   if (clip_stat == CLIP_BOTH_CLIPPED)
   {
      if ((ixa == ixb) && (iya == iyb)) return CLIP_BOTH_OUT;
   }

   *ix1 = ixa;
   *iy1 = iya;
   *ix2 = ixb;
   *iy2 = iyb;

   return clip_stat;
}

static int draw_line_seg (Display_Context dtx, Drawable drawable, GC gc,
                          int ix1, int iy1, int ix2, int iy2)
{
   int  clip_stat, ixa, iya, ixb, iyb;


   ixa = ix1, iya = iy1;
   ixb = ix2, iyb = iy2;

   clip_stat = clip_line_seg (dtx, &ixa, &iya, &ixb, &iyb);
   if (clip_stat != CLIP_BOTH_OUT)
   {
      XDrawLine (SndDpy, drawable, gc,
                 ixa+BORDER, iya+BORDER-HEBGBS, ixb+BORDER, iyb+BORDER-HEBGBS);
   }

   return clip_stat;
}

    /**********************************************************************/
    /* This draws the contstant mixing ratio lines                        */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /**********************************************************************/

static void draw_wlines( Display_Context dtx)
{
#define N_MIXRAT        6

   float        mixrat[N_MIXRAT] = {0.5, 1.0, 2.0, 5.0, 10.0, 20.0};
   float        ptop = 400.0;

   int i, nchr, wow, x, y, oldx, oldy, txtw, txth, txth2, txtx, txty, xx, yy;
   float gotomintemp, p;
   char label[8];
   XFontStruct *font_info;

   x = -9999;
   y = -9999;

   if (!(font_info = XLoadQueryFont(SndDpy, dtx->gfx[SOUND_FONT]->FontName))) {
	fprintf(stderr, "failed to load font \"%s\"", dtx->gfx[SOUND_FONT]->FontName);
	return;
   }
   XSetFont(SndDpy, dtx->Sound.box_gc, font_info->fid);
   txth      = font_info->ascent;
   txth2     = txth / 2;

   XSetLineAttributes (SndDpy, dtx->Sound.box_gc, 1, LineOnOffDash,
                       CapRound, JoinRound);

   data_to_y (dtx, pressure_to_height (625.0), &txty);

   for (i = 0; i < N_MIXRAT; i++) {
      wow = 1;
      for( gotomintemp = 373.0; gotomintemp > 173.0; gotomintemp -= .1){
         p = ((621.97 * svp(gotomintemp) +
              (mixrat[i] * svp(gotomintemp)))/mixrat[i]);
         if ((p <= 1012.5) && (wow == 1)){
            wow = 0;
            data_to_xy( dtx, pressure_to_height(p), gotomintemp, &x, &y);
            oldx = x;
            oldy = y;
         }
         if ( p <= ptop) {
            data_to_xy( dtx, pressure_to_height(p), gotomintemp, &x, &y);
            gotomintemp = 100;
         }
      }
      clip_line_seg (dtx, &oldx, &oldy, &x, &y);

      yy = txty + txth;
      xx = oldx;
      if (y != oldy) xx += ((yy - oldy) * (x - oldx) / (y - oldy));
      XDrawLine( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                 oldx+BORDER, oldy+BORDER-HEBGBS, xx+BORDER, yy+BORDER-HEBGBS);
      yy = txty - txth;
      xx = oldx;
      if (y != oldy) xx += ((yy - oldy) * (x - oldx) / (y - oldy));
      XDrawLine( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                 x+BORDER, y+BORDER-HEBGBS, xx+BORDER, yy+BORDER-HEBGBS);

      if(mixrat[i] < 1.0){
         sprintf(label, "%.1f", mixrat[i]);
      }
      else {
         sprintf(label, "%.0f", mixrat[i]);
      }
      nchr = strlen (label);
      txtw = XTextWidth (font_info, label, nchr) / 2;
      txtx = oldx + ((x - oldx) * (txty - oldy) / (y - oldy));
      XDrawString( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                   txtx+BORDER-txtw, txty+BORDER-HEBGBS+txth2,
                   label, nchr);
   }

   XSetLineAttributes (SndDpy, dtx->Sound.box_gc, 1, LineSolid,
                       CapRound, JoinRound);
      
   XFreeFontInfo(NULL, font_info, 0);
#undef N_MIXRAT
}

    /**********************************************************************/
    /* This draws the moist adiabat lines                                 */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /**********************************************************************/

static void draw_thtelines( Display_Context dtx )
{
   float p, step, step2;
   float yo, gotomaxheight;
   int x, y, oldx, oldy;


   XSetLineAttributes (SndDpy, dtx->Sound.box_gc, 1, LineOnOffDash,
                       CapRound, JoinRound);

   step = .5;
   if ((dtx->Sound.sndwidth < 300) || (dtx->Sound.sndheight < 300)){
      step2= 20;
   }
   else if ((dtx->Sound.sndwidth <550) || (dtx->Sound.sndheight < 550)){
      step2= 10;
   }
   else {
      step2= 5;
   }
   for (yo = dtx->Sound.SndMaxTemp-10; yo > dtx->Sound.SndMinTemp; yo -= step2){
      data_to_xy( dtx, 0, yo, &x, &y);
      for (gotomaxheight = 0.0;
      gotomaxheight < dtx->Sound.TopHgt; gotomaxheight += step){
         p = height_to_pressure(gotomaxheight);
         oldx = x;
         oldy = y;
         data_to_xy( dtx, gotomaxheight,
                     get_temp_for_thte(thetaE(1012.5, yo), p), &x, &y);

         draw_line_seg (dtx, dtx->Sound.soundpix, dtx->Sound.box_gc,
                        oldx, oldy, x, y);
      }
   }

   XSetLineAttributes (SndDpy, dtx->Sound.box_gc, 1, LineSolid,
                       CapRound, JoinRound);
}

    /**********************************************************************/
    /* This draws the dry adiabat lines                                   */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /**********************************************************************/

static void draw_thtalines( Display_Context dtx )
{
   int yo, x, y, oldx, oldy, txtw, txth, clip_stat, drew_some;
   float mintemp = 123.0;
   float step = 10.0, step3 = 5.0;
   float p,h;
   float gotomintemp;
   char thtastring [8];
   XFontStruct *font_info;

   if (!(font_info = XLoadQueryFont(SndDpy, dtx->gfx[SOUND_FONT]->FontName))) {
	fprintf(stderr, "failed to load font \"%s\"", dtx->gfx[SOUND_FONT]->FontName);
	return;
   }
   XSetFont(SndDpy, dtx->Sound.box_gc, font_info->fid);
   txtw      = XTextWidth (font_info, "999", 3) / 2;
   txth      = font_info->ascent;
   XFreeFontInfo(NULL, font_info, 0);

   x     = dtx->Sound.sndwidth / (txtw * 8 / 3);
   y     = (470 - 290) / 5;
   step  = (x <= 0) ? 50 : (y < x) ? 5 : ((y + (x-1)) / x) * 5;

   for (yo = 470; yo >= 240; yo -= step) {
      sprintf(thtastring, "%d", yo);
      data_to_xy( dtx, 0, yo, &x, &y );

      drew_some = 0;
      for (gotomintemp = yo; gotomintemp >  mintemp; gotomintemp -= step3){
         p =  exp((1/.286)*(log((7.23674 * gotomintemp)/yo)));
         h = pressure_to_height( p );
         oldx = x;
         oldy = y;
         data_to_xy(dtx, h, gotomintemp,&x,&y);

         clip_stat = draw_line_seg (dtx, dtx->Sound.soundpix, dtx->Sound.box_gc,
                                    oldx, oldy, x, y);
         if (clip_stat == CLIP_BOTH_OUT) {
            if (drew_some) break;
         }
         else {
            if (clip_stat & CLIP_PT2_CLIPPED) break;
            drew_some = 1;
         }
      }
      x = oldx + ((0 - oldy) * (x - oldx) / (y - oldy));
      y = 0;
      if ((x > 0) && (x < dtx->Sound.sndwidth)) {
         XDrawString (SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                      x-txtw+BORDER, y-txth+BORDER-HEBGBS, thtastring, 3);
      }
   }
}

    /**********************************************************************/
    /* This draws the temperature lines                                   */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /**********************************************************************/

static void draw_templines( Display_Context dtx )
{
   int yo, yo2, x, y, oldx, oldy, txth, txth2, nchr;
   float step;
   char tempstring [8];
   XFontStruct *font_info;

   if (!(font_info = XLoadQueryFont(SndDpy, dtx->gfx[SOUND_FONT]->FontName))) {
	fprintf(stderr, "failed to load font \"%s\"", dtx->gfx[SOUND_FONT]->FontName);
	return;
   }
   XSetFont(SndDpy, dtx->Sound.box_gc, font_info->fid);
   txth      = font_info->ascent;
   txth2     = txth / 2;
   XFreeFontInfo(NULL, font_info, 0);

   if ((dtx->Sound.sndwidth < 300) || (dtx->Sound.sndheight < 300)){
      step = 20;
   }
   else if ((dtx->Sound.sndwidth <550) || (dtx->Sound.sndheight < 550)){
      step = 10;
   }
   else {
      step = 5;
   }

   for (yo = 50; yo >= -120; yo -= step) {
      yo2 = yo + 273;
      sprintf(tempstring, "%d", yo);
      nchr = strlen (tempstring);

      data_to_xy( dtx, dtx->Sound.BotHgt, yo2, &oldx, &oldy );
      data_to_xy( dtx, dtx->Sound.TopHgt, yo2, &x, &y );

      clip_line_seg (dtx, &oldx, &oldy, &x, &y);
      draw_line_seg (dtx, dtx->Sound.soundpix, dtx->Sound.box_gc,
                     oldx, oldy, x, y);
      if (y == 0) {
         y -= txth * 5 / 2;
         XDrawString( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                      x+BORDER, y+BORDER-HEBGBS,
                      tempstring, nchr);
      }
      else if (x == dtx->Sound.sndwidth) {
         XDrawString( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                      dtx->Sound.sndwidth+4+BORDER, y+txth2+BORDER-HEBGBS,
                      tempstring, nchr);
      }
   }
}

    /**********************************************************************/
    /* This just draws the millibars.                                     */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /**********************************************************************/

static void draw_millibarlines ( Display_Context dtx )
{
   float press;
   int x, y, xleft, xright, xmid, nchr, txtw, txth2, txts;
   char label[8];
   XFontStruct *font_info;

   xleft  = BORDER;
   xright = BORDER + dtx->Sound.sndwidth;
   xmid   = (xleft + xright) / 2;

   if (!(font_info = XLoadQueryFont(SndDpy, dtx->gfx[SOUND_FONT]->FontName))) {
	fprintf(stderr, "failed to load font \"%s\"", dtx->gfx[SOUND_FONT]->FontName);
	return;
   }
   XSetFont(SndDpy, dtx->Sound.box_gc, font_info->fid);
   txth2     = font_info->ascent / 2;
   txts      = XTextWidth (font_info, " ", 1);

   for (press = dtx->Sound.BotPress; press >= dtx->Sound.TopPress;
        press -= 50) {
      data_to_xy( dtx, pressure_to_height (press), 266, &x, &y);
      if ((((int) (press + 0.5)) % 100) == 0) {
         if ( y > 10 ) {
            sprintf(label,"%.0f", press );
            nchr = strlen (label);
            txtw = XTextWidth (font_info, label, nchr) / 2;
            XDrawString( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                         xmid-txtw, y+txth2+BORDER-HEBGBS, label, nchr);
            txtw += txts;
            XDrawLine ( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                        xleft, y+BORDER-HEBGBS, xmid-txtw, y+BORDER-HEBGBS);

            XDrawLine ( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                        xmid+txtw, y+BORDER-HEBGBS, xright, y+BORDER-HEBGBS);
         }
      }
      else {
         XDrawLine ( SndDpy, dtx->Sound.soundpix, dtx->Sound.box_gc,
                     xleft, y+BORDER-HEBGBS, xright, y+BORDER-HEBGBS);
      }
   }
   XFreeFontInfo(NULL, font_info, 0);
}

    /**********************************************************************/
    /* This will take two points, check if one of them is outside the data*/
    /* boundry then chop it off, if it is.  It also chops of lines at the */
    /* 200mb level. And if points x1 and y1 are not even in the data      */
    /* boundry then the line will not be drawn                            */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /*       x1, y1, x2, y2 - points making the line to be chopped        */
    /**********************************************************************/

static void cut_line_data2( Display_Context dtx, int *x1, int *y1, int *x2, int *y2)
{
   float m,b;
   float xone, yone, xtwo, ytwo;
   int p_equals_200mb;
   float bottomline;

   xone = (float) (*x1);
   yone = (float) (*y1);
   xtwo = (float) (*x2);
   ytwo = (float) (*y2);
   p_equals_200mb = *y2;

   /* get equation of line for x1, y1, x2, y2 */
   if ((xone - xtwo) == 0 ){
      m = 0.0;
      b = *y1;
   }
   else {
      m = (yone - ytwo)/(xone - xtwo);
      b = yone - (m * xone);
   }
   bottomline = ((dtx->TopBound-0.0001)*((int) (dtx->Sound.sndheight))/
                 (dtx->TopBound-dtx->BottomBound+0.0001));

   /* see where this line intersects the 1012.5 mb line */
   *x1 = (int) ((bottomline - b)/m);
   *y1 = (int) (bottomline);

   /* see where the line intersects the right line */
   *x2 = dtx->Sound.sndwidth;
   *y2 = (int) ((float) dtx->Sound.sndwidth * m + b);

   /* if it intersects the top line, the chop it off */
   if ((*y2) < p_equals_200mb){
      *x2 = (int) ((p_equals_200mb - b) / m );
      *y2 = p_equals_200mb;
   }
   if ((*y2) < 0){
      *x2 = (int) (-b / m);
      *y2 = 0;
   }
}   

    /**********************************************************************/
    /* When figureing out the starting point for the theta lines in the + */
    /* y direction on the right side of the data boundry this will chop   */
    /* off the given line so it starts at the right side given by y =     */
    /* dtx->Sound.sndwidth                                                */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /*       x1, y1, x2, y2 - points making the line to be chopped        */
    /* Output: x1, y1 - these may be altered in order to start at boudry  */
    /**********************************************************************/
 
static void precut_line_data (Display_Context dtx, int *x1, int *y1, int x2, int y2)
{
   float m,b;
   float line_intercept;
   float  xone, yone, xtwo, ytwo;

   /* get equation of line for x1, y1, x2, y2 */
   xone = (float) *x1;
   yone = (float) *y1;
   xtwo = (float) (x2);
   ytwo = (float) (y2);
   if ((xone - xtwo) == 0 ){
      m = 0.0;
      b = yone;
   }
   else {
      m = (yone - ytwo)/(xone - xtwo);
      b = yone - (m * xone);
   }
   
   /* see where on the line x= sndwidth it intersecpts */
   line_intercept = m * dtx->Sound.sndwidth + b;

   *x1 = dtx->Sound.sndwidth;
   *y1 = (int) (line_intercept); 
}



    /**********************************************************************/
    /* This cuts the given line so that it's end point will be on the     */
    /* left or top side of the data boundry.  It is used in drawing the   */
    /* theta lines.                                                       */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /*       x1, y1, x2, y2 - points making the line to be chopped        */
    /* Output x2, y2 - these points may be altered to end at data boudry  */
    /**********************************************************************/

        
static void cut_line_data( Display_Context dtx, int x1, int y1, int *x2, int *y2)
{
   float m,b;
   float x_intercept, y_intercept;
   float  xone, yone, xtwo, ytwo;
 
   /* get equation of line for x1, y1, x2, y2 */
   xone = (float) x1;
   yone = (float) y1;
   xtwo = (float) (*x2);
   ytwo = (float) (*y2);
   if ((x1 - xtwo) == 0 ){
      m = 0.0;
      b = yone;
   }
   else { 
      m = (yone - ytwo)/(xone - xtwo);
      b = yone - (m * xone);
   }

   /* see where this line intersects the axies */
   y_intercept = b;
   x_intercept = (-1.0 * b)/m;

   if (y_intercept == 0 ){
      *x2 = 0;
      *y2 = 0;
   }
   else if ( y_intercept < 0 ){
      *x2 = (int) (x_intercept);
      *y2 = 0;
   }
   else if ( x_intercept < 0){
      *x2 = 0;
      *y2 = (int) (y_intercept);
   }
}

    /**********************************************************************/
    /* This draws the numbers and ticks up the vertical                   */
    /**********************************************************************/
    /* Input dtx - context                                                */
    /**********************************************************************/

static void draw_vert_stuff( Display_Context dtx )
{
   int yo, y;
   int maxlev;
   static  char dotted[2] = {4, 12};
   char *dash_list[] = {dotted};
   char num[10];
   int stringnumber;
   double average;
   XFontStruct *font_info;
   font_info = XLoadQueryFont(SndDpy, dtx->gfx[SOUND_FONT]->FontName);

   if (!dtx->Sound.vert_gc){
      dtx->Sound.vert_gc = make_gc(dtx, 255, 255, 255, 0, 0, 0, 2);
   }
   maxlev = (int) (dtx->Sound.vertdata[0]);
   {
      double total=0.0;;
      for (yo=1; yo < maxlev + 1; yo++){
         total += dtx->Sound.vertdata[yo];
      }
      average = total / (double)(maxlev);
   }    
      
   for ( yo=1; yo < maxlev + 1; yo++){
      dtx->Sound.vert_gc = make_gc(dtx, 100, 100, 100, 0, 0, 0, 1);
      XSetLineAttributes(SndDpy, dtx->Sound.vert_gc, 0, LineOnOffDash, CapButt, JoinRound);
      XSetDashes(SndDpy, dtx->Sound.vert_gc, 1, dash_list[0], 2);
      data_to_y( dtx, dtx->Sound.vertdata[yo], &y);
      if(dtx->Sound.tickstatus){ 
         XDrawLine( SndDpy, dtx->Sound.soundpix, dtx->Sound.vert_gc, BORDER, y + BORDER - HEBGBS,
                    dtx->Sound.sndwidth+BORDER, y + BORDER - HEBGBS);
      }
      if (average < .1){
         float numb;
         numb = dtx->Sound.vertdata[yo] * 1000.0;
         sprintf(num, "%.2f\n", numb);
      }
      else{
         sprintf(num, "%.1f\n", dtx->Sound.vertdata[yo]);
      }
      stringnumber = strlen(num)-1;
      dtx->Sound.vert_gc = make_gc(dtx, 255, 255, 255, 0, 0, 0, 1);
      if (font_info)
	   XSetFont(SndDpy, dtx->Sound.vert_gc, font_info->fid);
      XDrawString( SndDpy, dtx->Sound.soundpix, dtx->Sound.vert_gc,
                   dtx->Sound.sndwidth + BORDER + 25, y + BORDER - HEBGBS + 4,
                   num, stringnumber);
   }
   if (average < .1){
      sprintf(num, "m");
   }
   else{
      sprintf(num, "Km");
   }
   if( dtx->Sound.vertsys != 0 )
      XDrawString( SndDpy, dtx->Sound.soundpix, dtx->Sound.vert_gc,
                 dtx->Sound.sndwidth + BORDER + 25+5,  BORDER - HEBGBS -8,
                 num, 2);

   if (font_info)
	XFreeFontInfo(NULL, font_info, 0);   
}     

    /**********************************************************************/
    /* This will draw a barb onto the soundwin                            */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        spd - this is the given speed in meters/second              */
    /*        dir - this is the direction in radians                      */
    /*        height - this is the height at which the barb info is given */
    /**********************************************************************/
 
/* MJK 12.15.98 begin */
static void make_a_barb( Display_Context dtx, float spd, float dir,
                         float height, int barb_size)
{
   int location;
   int mainstemlength = barb_size;
   int fiftycount = 0;
   int tencount = 0;
   int fivecount = 0;
   int calmcount = 0;
   int speed;
   int yo;
   int space = mainstemlength / 8;
   int bigx  = space * 2;
   int x,y;
   XPoint  flagpoints[3];
/* MJK 12.15.98 end */

   data_to_xy( dtx, height, 273, &x, &y);
   /* get the count of how many and what kind of flags */
   spd = spd / .51282;
   speed = (int) spd;
   fiftycount = speed / 50;
   speed -= fiftycount * 50;
   tencount   = speed / 10;
   speed -= tencount * 10;
   fivecount  = speed / 5;
   if ( fiftycount == 0 && tencount == 0 && fivecount == 0 ){
      calmcount = 1;
   }

   /* now contruct a barb giving the x and y and draw that line */
   location = mainstemlength;

   /*draw main stem line */
   if (!calmcount) drawbarbline(dtx, 0, 0, 0, location, y, dir);

   /*draw any 50's if there is any*/
   for (yo = 0; yo < fiftycount; yo++){
      drawbarbline(dtx, 0, location, bigx, location, y, dir);
      location -= space;
      drawbarbline(dtx, 0, location, bigx, location + space, y, dir);
      flagpoints[0].x = 0;
      flagpoints[0].y = location + space;
      flagpoints[1].x = bigx;
      flagpoints[1].y = location + space;
      flagpoints[2].x = 0;
      flagpoints[2].y = location;
      drawbarbflag( dtx, flagpoints, y, dir);
}

   /*draw any 10's if there are any*/
   for (yo = 0; yo < tencount; yo ++){
      if ( yo != 0 ) location -= space;
      drawbarbline(dtx, 0, location, bigx, location+space, y, dir);
   }

   /*draw any 5's if there are any */
   for (yo = 0; yo < fivecount; yo++){
      location -= space;
      drawbarbline(dtx, 0, location, bigx/2, location + space/2, y, dir);
   }

   /*draw the calm little x if it is calm out*/
   if (calmcount == 1){
      drawbarbline(dtx,-4, 0, 4, 0, y, 0);
      drawbarbline(dtx, 0, -4, 0, 4,y, 0);
   }
}

    /**********************************************************************/
    /* This will draw and color in any barb flags                         */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        flagpoints - the three points making up the barb flag       */
    /*        up - the lenght from the center of barb to flag             */
    /*        dir - the number or radians from 0 degrees to turn and draw */
    /*              the barb flag                                         */
    /**********************************************************************/

static void drawbarbflag( Display_Context dtx, XPoint flagpoints[], int up, float dir)
{
   int x, y, x1, x2, x3, y1, y2, y3, xx1, yy1, xx2, xx3, yy2, yy3;;

   x = 0;
   y = up;
   x1 = flagpoints[0].x;
   y1 = flagpoints[0].y;
   x2 = flagpoints[1].x;
   y2 = flagpoints[1].y;
   x3 = flagpoints[2].x;
   y3 = flagpoints[2].y;

   convert_xy_to_barb( dtx, x1, y1, dir, &xx1, &yy1);
   convert_xy_to_barb( dtx, x2, y2, dir, &xx2, &yy2);
   convert_xy_to_barb( dtx, x3, y3, dir, &xx3, &yy3);
   flagpoints[0].x = xx1 + x + BORDER;
   flagpoints[0].y = yy1 + y + BORDER-HEBGBS;
   flagpoints[1].x = xx2 + x + BORDER;
   flagpoints[1].y = yy2 + y + BORDER-HEBGBS;
   flagpoints[2].x = xx3 + x + BORDER;
   flagpoints[2].y = yy3 + y + BORDER-HEBGBS;

   XFillPolygon( SndDpy, dtx->Sound.soundwin, dtx->Sound.barb2_gc,
                 flagpoints, 3, Nonconvex, CoordModeOrigin);
}

    /**********************************************************************/
    /* This will take two points,the radius, and direction and draw a line*/
    /**********************************************************************/
    /* Input dtx - context                                                */
    /*       x1, y1, x2, y2 - points for the line to be drawn             */
    /*       up - radius                                                  */
    /*       dir - degrees from 0 degree to turn                          */
    /**********************************************************************/


static void drawbarbline( Display_Context dtx, int x1, int y1, int x2, int y2,
                           int up, float dir)
{
   int x, y, xx1, yy1, xx2, yy2;

   x = 0;
   y = up;
   convert_xy_to_barb( dtx, x1, y1, dir, &xx1, &yy1);
   convert_xy_to_barb( dtx, x2, y2, dir, &xx2, &yy2);
   XDrawLine( SndDpy, dtx->Sound.soundwin, dtx->Sound.barb_gc, xx1 + x + BORDER,
              yy1 + y + BORDER-HEBGBS, xx2 + x + BORDER,
              yy2 + y + BORDER-HEBGBS);
}

    /**********************************************************************/
    /* This will take a point, convert it to polar coordinates, turn it   */
    /* the given direction, then convert it back to catesian coordinates  */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        inx, iny - the x and y fot the point to be transformed      */
    /*        dir - the number of radians to turn the point to the right  */
    /*        outx, outy - the x and y after transformation               */
    /**********************************************************************/


static void convert_xy_to_barb(Display_Context dtx, int inx, int iny, float dir,
                                          int *outx, int *outy)
{
   float x, y, r, angle;

   x = (float) inx;
   y = (float) iny;

   /* first convert to polar coordinates */
   r = sqrt((x * x) + (y * y));
   if ( x > 0 && y < 0 )
      angle = PI + atan(x / y);
   else if ( x < 0 && y < 0)
      angle = PI + atan(x / y);
   else if (y == 0){
      if ( x < 0 )
         angle = 3 * PI / 2;
      else
         angle = PI / 2;
   }
   else if (x == 0){
      if ( y < 0 )
         angle = PI;
      else
         angle = 0;
   }
   else
      angle = atan(x / y);

   /* now just add on the angle */
   angle +=  (float) dir;

   /* now convert back to x and y */
   *outx = (int) (cos(angle) * r);
   *outy = (int) (sin(angle) * r);
}    

    /**********************************************************************/
    /* This reload the grids for the sounding variables in case the       */
    /* variables change or the time changes this can be used to change them*/
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /**********************************************************************/


int reload_sounding_data( Display_Context dtx )
{
   if ( dtx->Sound.SoundTemp >= 0 ) {
      if (dtx->Sound.tgrid == NULL ) {
         dtx->Sound.tgrid = get_grid( dtx->Sound.SoundTempOwner,
                                      dtx->Sound.SoundTempOwner->CurTime, dtx->Sound.SoundTemp);
      }
      else {
         release_grid( dtx->Sound.SoundTempOwner, dtx->Sound.SoundTempOwner->CurTime,
                       dtx->Sound.SoundTemp, dtx->Sound.tgrid );
         dtx->Sound.tgrid = get_grid( dtx->Sound.SoundTempOwner, dtx->Sound.SoundTempOwner->CurTime,
                                      dtx->Sound.SoundTemp);
      }
   }

   if ( dtx->Sound.SoundDewpt >= 0){
      if (dtx->Sound.dgrid == NULL ) {
         dtx->Sound.dgrid = get_grid( dtx->Sound.SoundDewptOwner, dtx->Sound.SoundDewptOwner->CurTime,
                                      dtx->Sound.SoundDewpt);
      }
      else {
         release_grid( dtx->Sound.SoundDewptOwner, dtx->Sound.SoundDewptOwner->CurTime,
                       dtx->Sound.SoundDewpt, dtx->Sound.dgrid );
         dtx->Sound.dgrid = get_grid( dtx->Sound.SoundDewptOwner, dtx->Sound.SoundDewptOwner->CurTime,
                                      dtx->Sound.SoundDewpt);
      }
   }


   if ( dtx->Sound.SoundUWind >= 0 && dtx->Sound.SoundVWind >=0 ){
      if (dtx->Sound.ugrid == NULL ) {
         dtx->Sound.ugrid = get_grid( dtx->Sound.SoundUWindOwner, dtx->Sound.SoundUWindOwner->CurTime,
                                      dtx->Sound.SoundUWind);
      }
      else {
         release_grid( dtx->Sound.SoundUWindOwner, dtx->Sound.SoundUWindOwner->CurTime,
                       dtx->Sound.SoundUWind, dtx->Sound.ugrid );
         dtx->Sound.ugrid = get_grid( dtx->Sound.SoundUWindOwner, dtx->Sound.SoundUWindOwner->CurTime,
                                      dtx->Sound.SoundUWind);
      }
      if (dtx->Sound.vgrid == NULL ) {
         dtx->Sound.vgrid = get_grid( dtx->Sound.SoundVWindOwner, dtx->Sound.SoundVWindOwner->CurTime,
                                      dtx->Sound.SoundVWind);
      }
      else {
         release_grid( dtx->Sound.SoundVWindOwner, dtx->Sound.SoundVWindOwner->CurTime,
                       dtx->Sound.SoundVWind, dtx->Sound.vgrid );
         dtx->Sound.vgrid = get_grid( dtx->Sound.SoundVWindOwner, dtx->Sound.SoundVWindOwner->CurTime,
                                      dtx->Sound.SoundVWind);
      }
   }


   if ( dtx->Sound.SoundVar1 >= 0){
      if (dtx->Sound.var1grid == NULL ) {
         dtx->Sound.var1grid = get_grid( dtx->Sound.SoundVar1Owner, dtx->Sound.SoundVar1Owner->CurTime,
                                         dtx->Sound.SoundVar1);
      }
      else {
         release_grid( dtx->Sound.SoundVar1Owner, dtx->Sound.SoundVar1Owner->CurTime,
                       dtx->Sound.SoundVar1, dtx->Sound.var1grid );
         dtx->Sound.var1grid = get_grid( dtx->Sound.SoundVar1Owner, dtx->Sound.SoundVar1Owner->CurTime,
                                         dtx->Sound.SoundVar1);
      }
   }


   if ( dtx->Sound.SoundVar2 >= 0){
      if (dtx->Sound.var2grid == NULL ) {
         dtx->Sound.var2grid = get_grid( dtx->Sound.SoundVar2Owner, dtx->Sound.SoundVar2Owner->CurTime,
                                         dtx->Sound.SoundVar2);
      }
      else {
         release_grid( dtx->Sound.SoundVar2Owner, dtx->Sound.SoundVar2Owner->CurTime,
                       dtx->Sound.SoundVar2, dtx->Sound.var2grid );
         dtx->Sound.var2grid = get_grid( dtx->Sound.SoundVar2Owner, dtx->Sound.SoundVar2Owner->CurTime,
                                         dtx->Sound.SoundVar2);
      }
   }


   if ( dtx->Sound.SoundVar3 >= 0){
      if (dtx->Sound.var3grid == NULL ) {
         dtx->Sound.var3grid = get_grid( dtx->Sound.SoundVar3Owner, dtx->Sound.SoundVar3Owner->CurTime,
                                         dtx->Sound.SoundVar3);
      }
      else {
         release_grid( dtx->Sound.SoundVar3Owner, dtx->Sound.SoundVar3Owner->CurTime,
                       dtx->Sound.SoundVar3, dtx->Sound.var3grid );
         dtx->Sound.var3grid = get_grid( dtx->Sound.SoundVar3Owner, dtx->Sound.SoundVar3Owner->CurTime,
                                         dtx->Sound.SoundVar3);
      }
   }
   return 1;
}   



/* MJK 12.15.98 begin */
#define RESET_ELEV              -99999.0

static int draw_sounding_line (Display_Context dtx, GC gc, int x, int y,
                               float alt, float elev)
{

   static int           oldx = -1;
   static int           oldy = -1;
   static float         olda = RESET_ELEV;


   if (alt == RESET_ELEV) {
      oldx = oldy = -1;
      olda = RESET_ELEV;

      return 0;
   }

   if (alt >= elev) {

      if ((alt >= elev) && (olda < elev)) {
         float  frac;

         frac  = ((float) (elev - olda)) / ((float) (alt - olda));
         oldx += (x - oldx) * frac;
         oldy += (y - oldy) * frac;
      }

      draw_line_seg (dtx, dtx->Sound.soundwin, gc, oldx, oldy, x, y);
   }

   oldx = x;
   oldy = y;
   olda = alt;


   return 1;
}


    /**********************************************************************/
    /* This function puts everything together and draws the soundings and */
    /* vertical plot lines for a given time, and cursor location which    */
    /* is found in the context                                            */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        time - time step for whcih the sounding line is drawn       */
    /* Output: returns 1 is all goes well                                 */
    /**********************************************************************/



int draw_sounding( Display_Context dtx, int time )
{
   float windspeed, winddir;
   float row, col, lev;
   float alt, value;
   float frow, fcol;
   int x, y;
   int yo, yo2;
   int icol, irow;

   float        elev, lat, lon, hgt, *temp_save = NULL;
   int          barb_size;
   unsigned int line_width;
   Context      varownerctx, prvownerctx, var2ownerctx, prv2ownerctx;

   XFontStruct *font_info;
   font_info = XLoadQueryFont(SndDpy, dtx->gfx[SOUND_FONT]->FontName);

   /* this will get the heights for the levels*/
   /* and put them in dtx->Sound.vertdata, and the first number in this array */
   /* tells how many levels there are */

   if (dtx->Sound.get_vert_data){
      dtx->Sound.get_vert_data = 0;
      dtx->Sound.vertdata = (float *) malloc(dtx->MaxNl * sizeof(float) + 1);
      if (!dtx->Sound.vertdata) {
         return 0;
      }
      dtx->Sound.vertdata[0] = (float) (dtx->MaxNl);
      for ( yo = 1; yo < dtx->MaxNl + 1; yo++){
         dtx->Sound.vertdata[yo] = grid_level_to_height( dtx, yo-1);
      }
   }
   XSync( SndDpy, 0);

   XCopyArea(SndDpy, dtx->Sound.soundpix, dtx->Sound.soundwin,
             dtx->Sound.box_gc,
             0, 0, dtx->Sound.sndwidth+2*BORDER,
             dtx->Sound.sndheight+95+2*BORDER+(BORDER/2), 0, 0);


   /*                               */
   /* draw the data into the window */
   /*                               */
   xyzPRIME_to_gridPRIME( dtx, dtx->CurTime, 1,
                dtx->CursorX, dtx->CursorY, dtx->CursorZ, &row, &col, &lev );
   irow = (int)(row + 0.5);
   icol = (int)(col + 0.5);
   frow = row - (float)irow;
   fcol = col - (float)icol;

   if ( fabs(frow) < 0.001){
      row = (float)(irow);
   }
   if ( fabs(fcol) < 0.001){
      col = (float)(icol);
   }

   elev = RESET_ELEV;
   if (dtx->topo->TopoData) {
      xyzPRIME_to_geo (dtx, -1, -1, dtx->CursorX, dtx->CursorY, 0.0,
                       &lat, &lon, &hgt);
      elev = elevation (dtx, dtx->topo, lat, lon, NULL) / 1000.0;
   }

/* 13May98  Phil McDonald */
   if ((dtx->Sound.PreviousSoundTemp < 0) && (dtx->Sound.SoundTemp >= 0) &&
       (dtx->Sound.tgrid != NULL))
       dtx->Sound.PreviousSoundTemp = dtx->Sound.SoundTemp;
   if ((dtx->Sound.PreviousSoundDewpt < 0) && (dtx->Sound.SoundDewpt >= 0) &&
       (dtx->Sound.dgrid != NULL))
       dtx->Sound.PreviousSoundDewpt = dtx->Sound.SoundDewpt;
   if ((dtx->Sound.PreviousSoundUWind < 0) && (dtx->Sound.SoundUWind >= 0) &&
       (dtx->Sound.ugrid != NULL))
       dtx->Sound.PreviousSoundUWind = dtx->Sound.SoundUWind;
   if ((dtx->Sound.PreviousSoundVWind < 0) && (dtx->Sound.SoundVWind >= 0) &&
       (dtx->Sound.vgrid != NULL))
       dtx->Sound.PreviousSoundVWind = dtx->Sound.SoundVWind;
   if ((dtx->Sound.PreviousSoundVar1 < 0) && (dtx->Sound.SoundVar1 >= 0) &&
       (dtx->Sound.var1grid != NULL))
       dtx->Sound.PreviousSoundVar1 = dtx->Sound.SoundVar1;
   if ((dtx->Sound.PreviousSoundVar2 < 0) && (dtx->Sound.SoundVar2 >= 0) &&
       (dtx->Sound.var2grid != NULL))
       dtx->Sound.PreviousSoundVar2 = dtx->Sound.SoundVar2;
   if ((dtx->Sound.PreviousSoundVar3 < 0) && (dtx->Sound.SoundVar3 >= 0) &&
       (dtx->Sound.var3grid != NULL))
       dtx->Sound.PreviousSoundVar3 = dtx->Sound.SoundVar3;



   /* draw the temperature first if it is given*/

   if (dtx->Sound.SoundTemp >= 0){
      varownerctx = dtx->Sound.SoundTempOwner;
      prvownerctx = dtx->Sound.PreviousSoundTempOwner;

      if ( (dtx->Sound.SoundTemp != dtx->Sound.PreviousSoundTemp) &&
           (varownerctx != prvownerctx) && (dtx->Sound.tgrid != NULL) ){
         release_grid( prvownerctx, time,
                       dtx->Sound.PreviousSoundTemp, dtx->Sound.tgrid );
         dtx->Sound.tgrid = NULL;
      }
      dtx->Sound.PreviousSoundTemp      = dtx->Sound.SoundTemp;
      dtx->Sound.PreviousSoundTempOwner = varownerctx;

      if (dtx->Sound.tgrid == NULL ) {
         dtx->Sound.tgrid = get_grid( varownerctx, time, dtx->Sound.SoundTemp);
         if (dtx->Sound.tgrid == NULL) return 0;
      }

      if (varownerctx->GridSameAsGridPRIME){
         yo =  extract_sound( dtx, dtx->Sound.tgrid, dtx->Sound.SoundTemp,
                              varownerctx->Nr, varownerctx->Nc,
                              varownerctx->Nl[dtx->Sound.SoundTemp],
                              varownerctx->Variable[dtx->Sound.SoundTemp]->LowLev,
                              row, col );
      }
      else{
         yo = extract_soundPRIME( varownerctx, dtx->Sound.SoundTemp,
                                  varownerctx->Nr, varownerctx->Nc,
                                  varownerctx->Nl[dtx->Sound.SoundTemp],
                                  varownerctx->Variable[dtx->Sound.SoundTemp]->LowLev,
                                  row, col );
      }

      draw_sounding_line (dtx, dtx->Sound.Tempgc, -1, -1, RESET_ELEV, elev);

      for (yo=0; yo < varownerctx->Nl[dtx->Sound.SoundTemp]; yo++){
         alt   = gridlevel_to_height( varownerctx, yo);
         value = dtx->Sound.soundline[yo];
         data_to_xy(dtx, alt, value, &x, &y);

         draw_sounding_line (dtx, dtx->Sound.Tempgc, x, y, alt, elev);
      }

/* 13Oct97  Phil McDonald       save temp to compare with dewpt */
      temp_save            = dtx->Sound.soundline;
      dtx->Sound.soundline = NULL;

   }
   else {
      if (dtx->Sound.tgrid != NULL ){
         release_grid( dtx->Sound.PreviousSoundTempOwner, time,
                       dtx->Sound.PreviousSoundTemp, dtx->Sound.tgrid );
         dtx->Sound.tgrid = NULL;
      }
   }



   /* now draw the dewpoint line if its there */

   if (dtx->Sound.SoundDewpt >= 0){
      varownerctx = dtx->Sound.SoundDewptOwner;
      prvownerctx = dtx->Sound.PreviousSoundDewptOwner;

      if ( (dtx->Sound.SoundDewpt != dtx->Sound.PreviousSoundDewpt) &&
           (varownerctx != prvownerctx) && (dtx->Sound.dgrid != NULL) ){
         release_grid( prvownerctx, time,
                       dtx->Sound.PreviousSoundDewpt, dtx->Sound.dgrid );
         dtx->Sound.dgrid = NULL;
      }
      dtx->Sound.PreviousSoundDewpt      = dtx->Sound.SoundDewpt;
      dtx->Sound.PreviousSoundDewptOwner = varownerctx;

      if (dtx->Sound.dgrid == NULL ) {
         dtx->Sound.dgrid = get_grid( varownerctx, time, dtx->Sound.SoundDewpt);
         if (dtx->Sound.dgrid == NULL) return 0;
      }

      if (varownerctx->GridSameAsGridPRIME){
         yo =  extract_sound( dtx, dtx->Sound.dgrid, dtx->Sound.SoundDewpt,
                              varownerctx->Nr, varownerctx->Nc,
                              varownerctx->Nl[dtx->Sound.SoundDewpt],
                              varownerctx->Variable[dtx->Sound.SoundDewpt]->LowLev,
                              row, col );
      }
      else{
         yo = extract_soundPRIME( varownerctx,  dtx->Sound.SoundDewpt,
                                  varownerctx->Nr, varownerctx->Nc,
                                  varownerctx->Nl[dtx->Sound.SoundDewpt],
                                  varownerctx->Variable[dtx->Sound.SoundDewpt]->LowLev,
                                  row, col );
      }

      draw_sounding_line (dtx, dtx->Sound.Dewptgc, -1, -1, RESET_ELEV, elev);

      for (yo=0; yo < varownerctx->Nl[dtx->Sound.SoundDewpt]; yo++){
         alt   = gridlevel_to_height(varownerctx, yo);
         value = dtx->Sound.soundline[yo];

/* 13Oct97  Phil McDonald       ensure that dewpt doesn't exceed temp */
         if (temp_save != NULL)
         {
            if ((!IS_MISSING(temp_save[yo])) && (!IS_MISSING(value)))
            {
               if (value > temp_save[yo]) value = temp_save[yo];
            }
         }

         data_to_xy(dtx, alt, value, &x, &y);

         draw_sounding_line (dtx, dtx->Sound.Dewptgc, x, y, alt, elev);
      }

   }
   else {
      if (dtx->Sound.dgrid != NULL ){
         release_grid( dtx->Sound.PreviousSoundDewptOwner, time,
                       dtx->Sound.PreviousSoundDewpt, dtx->Sound.dgrid );
         dtx->Sound.dgrid = NULL;
      }
   }

/* 13Oct97  Phil McDonald */
   if (temp_save != NULL) free (temp_save), temp_save = NULL;



   /* now draw all the wind barb stuff */

   if ((dtx->Sound.SoundUWind >= 0) && (dtx->Sound.SoundVWind >= 0 )){
      varownerctx  = dtx->Sound.SoundUWindOwner;
      prvownerctx  = dtx->Sound.PreviousSoundUWindOwner;
      var2ownerctx = dtx->Sound.SoundVWindOwner;
      prv2ownerctx = dtx->Sound.PreviousSoundVWindOwner;

      if ( (dtx->Sound.SoundUWind != dtx->Sound.PreviousSoundUWind) &&
           (varownerctx != prvownerctx) && (dtx->Sound.ugrid != NULL) ){
         release_grid( prvownerctx, time,
                       dtx->Sound.PreviousSoundUWind, dtx->Sound.ugrid );
         dtx->Sound.ugrid = NULL;
      }
      dtx->Sound.PreviousSoundUWind      = dtx->Sound.SoundUWind;
      dtx->Sound.PreviousSoundUWindOwner = varownerctx;

      if ( (dtx->Sound.SoundVWind != dtx->Sound.PreviousSoundVWind) &&
           (var2ownerctx != prv2ownerctx) && (dtx->Sound.vgrid != NULL) ){
         release_grid( prv2ownerctx, time,
                       dtx->Sound.PreviousSoundVWind, dtx->Sound.vgrid );
         dtx->Sound.vgrid = NULL;
      }
      dtx->Sound.PreviousSoundVWind      = dtx->Sound.SoundVWind;
      dtx->Sound.PreviousSoundVWindOwner = var2ownerctx;

      if( dtx->Sound.ugrid == NULL ) {
         dtx->Sound.ugrid = get_grid( varownerctx, time,
                                      dtx->Sound.SoundUWind);
         if (dtx->Sound.ugrid == NULL) return 0;
      }
      if( dtx->Sound.vgrid == NULL ) {
         dtx->Sound.vgrid = get_grid( var2ownerctx, time,
                                      dtx->Sound.SoundVWind);
         if (dtx->Sound.vgrid == NULL) {
            release_grid( varownerctx, time,
                          dtx->Sound.SoundUWind, dtx->Sound.ugrid );
            return 0;
         }
      }

      if (varownerctx->GridSameAsGridPRIME){
         yo = extract_wind( dtx, dtx->Sound.ugrid, dtx->Sound.vgrid,
                            dtx->Sound.SoundUWind, dtx->Sound.SoundVWind,
                            dtx->Nr, dtx->Nc, dtx->Nl,
                            dtx->LowLev, row, col );
      }
      else{
         yo = extract_windPRIME( varownerctx,
                                 dtx->Sound.SoundUWind, dtx->Sound.SoundVWind,
                                 varownerctx->Nr, varownerctx->Nr,
                                 varownerctx->Nl[dtx->Sound.SoundUWind],
                                 varownerctx->Variable[dtx->Sound.SoundUWind]->LowLev,
                                 row, col);
      }

/* 20Oct97  Phil McDonald       calc a suitable barb size and line width */
      barb_size = 0;
      alt = grid_level_to_height( dtx, 0);
      data_to_xy( dtx, alt, 273, &x, &yo2);
      for (yo=1; yo < varownerctx->Nl[dtx->Sound.SoundUWind]; yo++){
         alt = grid_level_to_height( dtx, yo);
         data_to_xy( dtx, alt, 273, &x, &y);
         barb_size += (yo2 - y);
         yo2 = y;
      }
      barb_size = (barb_size * 5) /
                  ((varownerctx->Nl[dtx->Sound.SoundUWind] - 1) * 3);
      if (barb_size > SOUND_BARB_SIZE) barb_size = SOUND_BARB_SIZE;
      line_width = (barb_size < 40) ? 1 : 2;
      XSetLineAttributes (SndDpy, dtx->Sound.barb_gc, line_width,
                                  LineSolid, CapButt, JoinRound);

      for (yo=0; yo < varownerctx->Nl[dtx->Sound.SoundUWind]; yo++){
         alt = gridlevel_to_height(varownerctx, yo);

         if (alt >= elev) {
            float u, v;

            u = dtx->Sound.uwindline[yo];
            v = dtx->Sound.vwindline[yo];

            windspeed = sqrt((u * u) + (v * v));

            if (windspeed < 300.0) {
               winddir = (PI / 2.0) - atan2 (v, u);
               if (winddir < 0.0) winddir += PI * 2.0;

               make_a_barb (dtx, windspeed, winddir+PI/2, alt, barb_size);
            }
         }
      }
   }
   else {
      if (dtx->Sound.ugrid != NULL ) {
         release_grid( dtx->Sound.PreviousSoundUWindOwner,
                       time, dtx->Sound.PreviousSoundUWind, dtx->Sound.ugrid);
         dtx->Sound.ugrid = NULL;
      }
      if (dtx->Sound.vgrid != NULL ) {
         release_grid( dtx->Sound.PreviousSoundVWindOwner,
                       time, dtx->Sound.PreviousSoundVWind, dtx->Sound.vgrid);
         dtx->Sound.vgrid = NULL;
      }
   }



   /* now draw the different vertical variables */

   if( dtx->Sound.SoundVar1 >= 0){
      varownerctx  = dtx->Sound.SoundVar1Owner;
      prvownerctx  = dtx->Sound.PreviousSoundVar1Owner;

      if ( (dtx->Sound.SoundVar1 != dtx->Sound.PreviousSoundVar1) &&
           (varownerctx != prvownerctx) && (dtx->Sound.var1grid != NULL) ){
         release_grid( prvownerctx, time,
                       dtx->Sound.PreviousSoundVar1, dtx->Sound.var1grid );
         dtx->Sound.var1grid = NULL;
      }
      dtx->Sound.PreviousSoundVar1      = dtx->Sound.SoundVar1;
      dtx->Sound.PreviousSoundVar1Owner = varownerctx;

      if (dtx->Sound.var1grid == NULL ){
         dtx->Sound.var1grid = get_grid( varownerctx, time,
                                         dtx->Sound.SoundVar1);
         if (dtx->Sound.var1grid == NULL) return 0;
      }

      if (varownerctx->GridSameAsGridPRIME){
         yo= extract_sound( dtx, dtx->Sound.var1grid, dtx->Sound.SoundVar1,
                            dtx->Nr, dtx->Nc, dtx->Nl,
                            dtx->LowLev, row, col );
      }
      else{
         yo= extract_soundPRIME(varownerctx, dtx->Sound.SoundVar1,
                                varownerctx->Nr, varownerctx->Nc,
                                varownerctx->Nl[dtx->Sound.SoundVar1],
                                varownerctx->Variable[dtx->Sound.SoundVar1]->LowLev,
                                row, col );
      }

      if (font_info)
	   XSetFont(SndDpy, dtx->Sound.var1_gc, font_info->fid);
      draw_sounding_line (dtx, dtx->Sound.var1_gc, -1, -1, RESET_ELEV, elev);

      for (yo=0; yo < varownerctx->Nl[dtx->Sound.SoundVar1]; yo++){
         alt   = gridlevel_to_height(varownerctx, yo);
         value = dtx->Sound.soundline[yo];
         vardata_to_xy(dtx, alt, value,
                       varownerctx->Variable[dtx->Sound.SoundVar1]->MinVal,
                       varownerctx->Variable[dtx->Sound.SoundVar1]->MaxVal, &x, &y);

         draw_sounding_line (dtx, dtx->Sound.var1_gc, x, y, alt, elev);
      }

   }
   else {
      if (dtx->Sound.var1grid != NULL ){
         release_grid(dtx->Sound.PreviousSoundVar1Owner, time,
                      dtx->Sound.PreviousSoundVar1, dtx->Sound.var1grid);
         dtx->Sound.var1grid = NULL;
      }
   }



   if( dtx->Sound.SoundVar2 >= 0){
      varownerctx  = dtx->Sound.SoundVar2Owner;
      prvownerctx  = dtx->Sound.PreviousSoundVar2Owner;

      if ( (dtx->Sound.SoundVar2 != dtx->Sound.PreviousSoundVar2) &&
           (varownerctx != prvownerctx) && (dtx->Sound.var2grid != NULL) ){
         release_grid( prvownerctx, time,
                       dtx->Sound.PreviousSoundVar2, dtx->Sound.var2grid );
         dtx->Sound.var2grid = NULL;
      }
      dtx->Sound.PreviousSoundVar2      = dtx->Sound.SoundVar2;
      dtx->Sound.PreviousSoundVar2Owner = varownerctx;

      if (dtx->Sound.var2grid == NULL ){
         dtx->Sound.var2grid = get_grid( varownerctx, time,
                                         dtx->Sound.SoundVar2);
         if (dtx->Sound.var2grid == NULL) return 0;
      }

      if (varownerctx->GridSameAsGridPRIME){
         yo= extract_sound( dtx, dtx->Sound.var2grid, dtx->Sound.SoundVar2,
                            dtx->Nr, dtx->Nc, dtx->Nl,
                            dtx->LowLev, row, col );
      }
      else{
         yo= extract_soundPRIME(varownerctx, dtx->Sound.SoundVar2,
                                varownerctx->Nr, varownerctx->Nc,
                                varownerctx->Nl[dtx->Sound.SoundVar2],
                                varownerctx->Variable[dtx->Sound.SoundVar2]->LowLev,
                                row, col );
      }
      
      if (font_info)
	   XSetFont(SndDpy, dtx->Sound.var2_gc, font_info->fid);
      draw_sounding_line (dtx, dtx->Sound.var2_gc, -1, -1, RESET_ELEV, elev);

      for (yo=0; yo < varownerctx->Nl[dtx->Sound.SoundVar2]; yo++){
         alt   = gridlevel_to_height(varownerctx, yo);
         value = dtx->Sound.soundline[yo];
         vardata_to_xy(dtx, alt, value,
                       varownerctx->Variable[dtx->Sound.SoundVar2]->MinVal,
                       varownerctx->Variable[dtx->Sound.SoundVar2]->MaxVal, &x, &y);

         draw_sounding_line (dtx, dtx->Sound.var2_gc, x, y, alt, elev);
      }

   }
   else {
      if (dtx->Sound.var2grid != NULL ){
         release_grid(dtx->Sound.PreviousSoundVar2Owner, time,
                      dtx->Sound.PreviousSoundVar2, dtx->Sound.var2grid);
         dtx->Sound.var2grid = NULL;
      }
   }



   if( dtx->Sound.SoundVar3 >= 0){
      varownerctx  = dtx->Sound.SoundVar3Owner;
      prvownerctx  = dtx->Sound.PreviousSoundVar3Owner;

      if ( (dtx->Sound.SoundVar3 != dtx->Sound.PreviousSoundVar3) &&
           (varownerctx != prvownerctx) && (dtx->Sound.var3grid != NULL) ){
         release_grid( prvownerctx, time,
                       dtx->Sound.PreviousSoundVar3, dtx->Sound.var3grid );
         dtx->Sound.var3grid = NULL;
      }
      dtx->Sound.PreviousSoundVar3      = dtx->Sound.SoundVar3;
      dtx->Sound.PreviousSoundVar3Owner = varownerctx;

      if (dtx->Sound.var3grid == NULL ){
         dtx->Sound.var3grid = get_grid( varownerctx, time,
                                         dtx->Sound.SoundVar3);
         if (dtx->Sound.var3grid == NULL) return 0;
      }

      if (varownerctx->GridSameAsGridPRIME){
         yo= extract_sound( dtx, dtx->Sound.var3grid, dtx->Sound.SoundVar3,
                            dtx->Nr, dtx->Nc, dtx->Nl,
                            dtx->LowLev, row, col );
      }
      else{
         yo= extract_soundPRIME(varownerctx, dtx->Sound.SoundVar3,
                                varownerctx->Nr, varownerctx->Nc,
                                varownerctx->Nl[dtx->Sound.SoundVar3],
                                varownerctx->Variable[dtx->Sound.SoundVar3]->LowLev,
                                row, col );
      }

      if (font_info)
	   XSetFont(SndDpy, dtx->Sound.var3_gc, font_info->fid);
      draw_sounding_line (dtx, dtx->Sound.var3_gc, -1, -1, RESET_ELEV, elev);

      for (yo=0; yo < varownerctx->Nl[dtx->Sound.SoundVar3]; yo++){
         alt   = gridlevel_to_height(varownerctx, yo);
         value = dtx->Sound.soundline[yo];
         vardata_to_xy(dtx, alt, value,
                       varownerctx->Variable[dtx->Sound.SoundVar3]->MinVal,
                       varownerctx->Variable[dtx->Sound.SoundVar3]->MaxVal, &x, &y);

         draw_sounding_line (dtx, dtx->Sound.var3_gc, x, y, alt, elev);
      }

   }
   else {
      if (dtx->Sound.var3grid != NULL ){
         release_grid(dtx->Sound.PreviousSoundVar3Owner, time,
                      dtx->Sound.PreviousSoundVar3, dtx->Sound.var3grid);
         dtx->Sound.var3grid = NULL;
      }
   }

   if (font_info)
	XFreeFontInfo(NULL, font_info, 0);

   return 1;
}

#undef RESET_ELEV


    /**********************************************************************/
    /* This converts vertical plot data to x and y's matching the soundwin*/
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        alt - altitude of data point in                             */
    /*        value - value of the data point, to be plotted on the y axis*/
    /*        min - minimum value for the data point                      */
    /*        max - maximum value for the data point                      */
    /* Output: x, y - the coordinates to be plotted on soundwin           */
    /**********************************************************************/



void vardata_to_xy(Display_Context dtx, float alt, float value,
                   float min, float max, int *x, int *y)
{

   if (dtx->Sound.samestepflag){
      min = dtx->Sound.samestepmin;
      max = dtx->Sound.samestepmax;
   }

   *x = dtx->Sound.sndwidth * (value - min) / (max - min);

   data_to_y (dtx, alt, y);
}

    /**********************************************************************/
    /* This will figure out what the interval for the value of the        */
    /* variable is compared to dtx->mainvarstep                           */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /**********************************************************************/

void setvarsteps( Display_Context dtx)
{

   if (dtx->Sound.samestepflag){
      int min, max;
  
      if (dtx->Sound.SoundVar1 >= 0){
         min = dtx->Sound.SoundVar1Owner->Variable[dtx->Sound.SoundVar1]->MinVal;
         max = dtx->Sound.SoundVar1Owner->Variable[dtx->Sound.SoundVar1]->MaxVal;
      }
      if (dtx->Sound.SoundVar2 >= 0){
         if (dtx->Sound.SoundVar2Owner->Variable[dtx->Sound.SoundVar2]->MinVal < min){
            min = dtx->Sound.SoundVar2Owner->Variable[dtx->Sound.SoundVar2]->MinVal;
         }
         if (dtx->Sound.SoundVar2Owner->Variable[dtx->Sound.SoundVar2]->MaxVal > max){
            max = dtx->Sound.SoundVar2Owner->Variable[dtx->Sound.SoundVar2]->MaxVal;
         }
      }
      if (dtx->Sound.SoundVar3 >= 0){
         if (dtx->Sound.SoundVar3Owner->Variable[dtx->Sound.SoundVar3]->MinVal < min) {
            min = dtx->Sound.SoundVar3Owner->Variable[dtx->Sound.SoundVar3]->MinVal;
         }
         if (dtx->Sound.SoundVar3Owner->Variable[dtx->Sound.SoundVar3]->MaxVal > max) {
            max = dtx->Sound.SoundVar3Owner->Variable[dtx->Sound.SoundVar3]->MaxVal;
         }
      }
      if (dtx->Sound.SoundVar1 >= 0){
         dtx->Sound.var1step =(( ((float)(dtx->Sound.mainvarstep)) * (max -
                        min ))/ ((float)(dtx->Sound.sndwidth))) ;
      }
      if (dtx->Sound.SoundVar2 >= 0){
         dtx->Sound.var2step =(( ((float)(dtx->Sound.mainvarstep)) * (max -
                        min))/ ((float)(dtx->Sound.sndwidth))) ;
      }
      if (dtx->Sound.SoundVar3 >= 0){
         dtx->Sound.var3step =(( ((float)(dtx->Sound.mainvarstep)) * (max -
                        min))/ ((float)(dtx->Sound.sndwidth))) ;
      }
      dtx->Sound.samestepmax = max;
      dtx->Sound.samestepmin = min;
   }
   else {
      if (dtx->Sound.SoundVar1 >= 0){
         dtx->Sound.var1step =(( ((float)(dtx->Sound.mainvarstep)) *
                              (dtx->Sound.SoundVar1Owner->Variable[dtx->Sound.SoundVar1]->MaxVal -
                        dtx->Sound.SoundVar1Owner->Variable[dtx->Sound.SoundVar1]->MinVal))/
                       ((float)(dtx->Sound.sndwidth))) ;
      }
      if (dtx->Sound.SoundVar2 >= 0){
         dtx->Sound.var2step =(( ((float)(dtx->Sound.mainvarstep)) *
                              (dtx->Sound.SoundVar2Owner->Variable[dtx->Sound.SoundVar2]->MaxVal -
                        dtx->Sound.SoundVar2Owner->Variable[dtx->Sound.SoundVar2]->MinVal))/
                       ((float)(dtx->Sound.sndwidth))) ;
      }
      if (dtx->Sound.SoundVar3 >= 0){
         dtx->Sound.var3step =(( ((float)(dtx->Sound.mainvarstep)) *
                              (dtx->Sound.SoundVar3Owner->Variable[dtx->Sound.SoundVar3]->MaxVal -
                        dtx->Sound.SoundVar3Owner->Variable[dtx->Sound.SoundVar3]->MinVal))/
                       ((float)(dtx->Sound.sndwidth))) ;
      }
   }
}


/* MJK 12.15.98 begin */

    /**********************************************************************/
    /* This converts skew-t values to the x and y to be plotted           */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        alt - altitude of data point in kilometers                  */
    /*        temp - temperature in Kelvin of data point to be plotter    */
    /* Output: x, y - the coordinates to be plotted on soundwin           */
    /**********************************************************************/

void data_to_xy(Display_Context dtx, float alt, float temp, int *x, int *y)
{
   temp += ((alt + 0.00000069) * 4.638);
   *x = dtx->Sound.sndwidth * (temp - dtx->Sound.SndMinTemp) /
        (dtx->Sound.SndMaxTemp - dtx->Sound.SndMinTemp);
   data_to_y (dtx, alt, y);
}

    /**********************************************************************/
    /* This just converts vertical values into a y coordinate             */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        alt - altitude of the value                                 */
    /* Output: y - the y coordinate to be plotted in soundwin             */
    /**********************************************************************/


void data_to_y (Display_Context dtx, float alt, int *y)
{
   alt += .00000069;
   *y = dtx->Sound.sndheight * (dtx->Sound.TopHgt - alt) / dtx->Sound.DiffHgt;
}

/* MJK 12.15.98 end */

    /**********************************************************************/
    /* This converts a grid level to a height                             */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        level - grid level                                          */
    /* Output: height                                                     */
    /*************************** NOTE!! ***********************************/
    /*******  This same code is used in proj.c lines 614 - 649  ***********/
    /**********************************************************************/


float grid_level_to_height( Display_Context dtx, float level )
{
   int ilevel;
   float rlevel;

   if (level<=0) {
      return dtx->BottomBound;
   }
   else if (level>=dtx->MaxNl-1 || dtx->MaxNl == 1) {
      return dtx->TopBound;
   }
   else {
      switch (dtx->VerticalSystem) {
         case VERT_GENERIC:
         case VERT_EQUAL_KM:
            return dtx->BottomBound + level * dtx->LevInc;
         case VERT_NONEQUAL_MB:
         case VERT_NONEQUAL_KM:
            ilevel = (int) level;
            rlevel = level - ilevel;
            return dtx->Height[ilevel] * (1.0-rlevel) + dtx->Height[ilevel+1] * rlevel;
         default:
            printf("Error in gridlevel_to_height\n");
      }
   }
   return 0.0;
}

    /**********************************************************************/
    /* This interpolates values in between grid points                    */
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        grid - grid array                                           */
    /*        var - variable to extract form grid                         */
    /*        nr, nc, nl - number or rows, columns, and levels for varible*/
    /*        lowlev - the lowest level for the variable                  */
    /*        row, col - row and column where cursor is                   */
    /* Output: return 1 if all goes well                                  */
    /**********************************************************************/

static int extract_sound( Display_Context dtx, float *grid, int var,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col)
{
   float a, b, c, d;
   float I, J, K, L, E, F, Z;
   int  level, lowrow, highrow, leftcol, rightcol;


   /* allocate buffer to put soundline data into */
   if (dtx->Sound.soundline != NULL){
      free(dtx->Sound.soundline);
   }
   dtx->Sound.soundline = (float *) malloc(nl * sizeof(float) );
   if (!dtx->Sound.soundline) {
     return 0;
   }

   /*
    *  The best way to see the interpolation here is to draw a box
    *  each of the four coners represents a discrete grid point with a certain
    *  given value and the cursor lies someplace in side this box or on the BORDER
    *  of it.  The box has sides: TOP, BOTTOM, LEFT, and RIGHT.   Rows increase
    *  going down, and Cols increase going right.  So
    *  the upper left  corner is (leftcol, lowrow)  with a data value I
    *  the upper right corner is (rightcol,lowrow)  with a data value J
    *  the lower left  corner is (leftcol, highrow) with a data value K
    *  the lower right corner is (rightcol,highrow) with a data value L
    *  q is the point where the cursor col intersects the BOTTOM line
    *  r is the point where the cursor col intersects the TOP line
    *  s is the point on the line between q and r where the cursor lies
    *  E is the interpolated value for the point q
    *  F is the interpolated value for the point r
    *  Then one simply interpolates for what the value of the point s is
    *
    */

   level = lowlev;
   lowrow = (int) row;
   leftcol = (int) col;
   highrow = lowrow + 1;
   rightcol = leftcol + 1;

   if (highrow > nr-1)
      highrow = nr-1;
   if (rightcol > nc-1)
      rightcol = nc-1;

   a = col - leftcol;
   b = 1 - a;
   c = row - lowrow;
   d = 1 - c;

   if ( (row == ((float)lowrow)) && (col == ((float)leftcol)) ){
      for (level = lowlev; level < nl; level++){
         Z = grid[ lowrow + nr * (leftcol + nc * level)];
         if (IS_MISSING(Z)){
            dtx->Sound.soundline[level] = MISSING;
         }
         else{
            dtx->Sound.soundline[level] = Z;
         }
      }
   }
   else {
      for (level = lowlev; level < nl; level++){
         /* get values for the four coners of the (col, row) box */
         I = grid[ lowrow + nr * (leftcol + nc * level)];
         J = grid[ lowrow + nr * (rightcol+ nc * level)];
         K = grid[ highrow+ nr * (leftcol + nc * level)];
         L = grid[ highrow+ nr * (rightcol+ nc * level)];
         if (IS_MISSING(I) || IS_MISSING(J) || IS_MISSING(K) || IS_MISSING(L)) {
            dtx->Sound.soundline[level] = MISSING;
         }
         else {
            E = a * L +  b * K ;
            F = a * J +  b * I ;
            dtx->Sound.soundline[level] = c * E + d * F;
         }
      }
   }
   return 1;
}

static int extract_soundPRIME( Context ctx, int var,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col)
{
   int  level;
   float ROW, COL, LEV, Row, Col, Lev;

   /* allocate buffer to put soundline data into */
   if (ctx->dpy_ctx->Sound.soundline != NULL){
      free(ctx->dpy_ctx->Sound.soundline);
   }
   ctx->dpy_ctx->Sound.soundline = (float *) malloc(nl * sizeof(float) );
   if (!ctx->dpy_ctx->Sound.soundline) {
     return 0;
   }


   ROW = (float)(row);
   COL = (float)(col);
   LEV = gridlevel_to_gridlevelPRIME( ctx, lowlev);
   for (level = lowlev; level < nl; level++){
      gridPRIME_to_grid(ctx, 0, var, 1, &ROW, &COL, &LEV, &Row, &Col, &Lev);  
      ctx->dpy_ctx->Sound.soundline[level]=interpolate_grid_value( ctx,
                                           0, var, Row, Col, level);
   }
   return 1;
}






    /**********************************************************************/
    /* This interpolates values in between grid points, for wind variables*/
    /**********************************************************************/
    /* Input: dtx - context                                               */
    /*        ugrid, vgrid  - grid arrays                                 */
    /*        varu, varv - variable to extract form grid                  */
    /*        nr, nc, nl - number or rows, columns, and levels for varible*/
    /*        lowlev - the lowest level for the variables                 */
    /*        row, col - row and column where cursor is                   */
    /* Output: return 1 if all goes well                                  */
    /**********************************************************************/

static int extract_wind( Display_Context dtx, float *gridu, float *gridv,
                             int varu, int varv,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col)
{
   float a, b, c, d;
   float I, J, K, L, E, F, Z;
   int  level, lowrow, highrow, leftcol, rightcol;


   /* allocate buffer to put windline data into */


   if (dtx->Sound.uwindline != NULL) free(dtx->Sound.uwindline);
   if (dtx->Sound.vwindline != NULL) free(dtx->Sound.vwindline);

   dtx->Sound.uwindline = (float *) malloc( nl * sizeof(float) );
   dtx->Sound.vwindline = (float *) malloc( nl * sizeof(float) );
   if ((!dtx->Sound.uwindline) || (!dtx->Sound.vwindline)) {

      /* MJK 12.15.98 */
      if (dtx->Sound.uwindline != NULL)
      {
         free (dtx->Sound.uwindline);
         dtx->Sound.uwindline = NULL;
      }
      if (dtx->Sound.vwindline != NULL)
      {
         free (dtx->Sound.vwindline);
         dtx->Sound.vwindline = NULL;
      }


      return 0;
   }

   level = lowlev;
   lowrow = (int) row;
   leftcol = (int) col;
   highrow = lowrow + 1;
   rightcol = leftcol + 1;

   if (highrow > nr-1)
      highrow = nr-1;
   if (rightcol > nc-1)
      rightcol = nc-1;

   a = col - leftcol;
   b = 1 - a;
   c = row - lowrow;
   d = 1 - c;

   if ( (row == ((float)lowrow)) && (col == ((float)leftcol)) ){
      for (level = lowlev; level < nl; level++){
         Z = gridu[ lowrow + nr * (leftcol + nc * level)];
         if (IS_MISSING(Z)){
            dtx->Sound.uwindline[level] = MISSING;
         }
         else{
            dtx->Sound.uwindline[level] = Z;
         }
      }
      for (level = lowlev; level < nl; level++){
         Z = gridv[ lowrow + nr * (leftcol + nc * level)];
         if (IS_MISSING(Z)){
            dtx->Sound.vwindline[level] = MISSING;
         }
         else{
            dtx->Sound.vwindline[level] = Z;
         }
      }
   return 1;
   }
   else {
      for (level = lowlev; level < nl; level++){
         /* get values for the four coners of the (col, row) box */
         I = gridu[ lowrow + nr * (leftcol + nc * level)];
         J = gridu[ lowrow + nr * (rightcol+ nc * level)];
         K = gridu[ highrow+ nr * (leftcol + nc * level)];
         L = gridu[ highrow+ nr * (rightcol+ nc * level)];
         if (IS_MISSING(I) || IS_MISSING(J) || IS_MISSING(K) || IS_MISSING(L)) {
            dtx->Sound.uwindline[level] = MISSING;
         }
         else {
            E = a * L +  b * K ;
            F = a * J +  b * I ;
            dtx->Sound.uwindline[level] = c * E + d * F;
         }
      }

      for (level = lowlev; level < nl; level++){
         /* get values for the four coners of the (col, row) box */
         I = gridv[ lowrow + nr * (leftcol + nc * level)];
         J = gridv[ lowrow + nr * (rightcol+ nc * level)];
         K = gridv[ highrow+ nr * (leftcol + nc * level)];
         L = gridv[ highrow+ nr * (rightcol+ nc * level)];
         if (IS_MISSING(I) || IS_MISSING(J) || IS_MISSING(K) || IS_MISSING(L)) {
            dtx->Sound.vwindline[level] = MISSING;
         }
         else {
            E = a * L +  b * K ;
            F = a * J +  b * I ;
            dtx->Sound.vwindline[level] = c * E + d * F;
         }
      }
      return 1;
   }
}

static int extract_windPRIME( Context ctx, 
                             int varu, int varv,
                             int nr, int nc, int nl, int lowlev,
                             float row, float col)
{
   int  level;
   float ROW, COL, LEV, Row, Col, Lev;


   /* allocate buffer to put windline data into */


   if (ctx->dpy_ctx->Sound.uwindline != NULL) free(ctx->dpy_ctx->Sound.uwindline);
   if (ctx->dpy_ctx->Sound.vwindline != NULL) free(ctx->dpy_ctx->Sound.vwindline);

   ctx->dpy_ctx->Sound.uwindline = (float *) malloc( nl * sizeof(float) );
   ctx->dpy_ctx->Sound.vwindline = (float *) malloc( nl * sizeof(float) );
   if ((!ctx->dpy_ctx->Sound.uwindline) || (!ctx->dpy_ctx->Sound.vwindline)) {


      /* MJK 12.15.98 */
      if (ctx->dpy_ctx->Sound.uwindline != NULL)
      {
         free (ctx->dpy_ctx->Sound.uwindline);
         ctx->dpy_ctx->Sound.uwindline = NULL;
      }
      if (ctx->dpy_ctx->Sound.vwindline != NULL)
      {
         free (ctx->dpy_ctx->Sound.vwindline);
         ctx->dpy_ctx->Sound.vwindline = NULL;
      }


      return 0;
   }

   ROW = (float)(row);
   COL = (float)(col);
   LEV = gridlevel_to_gridlevelPRIME( ctx, lowlev);
   for (level = lowlev; level < nl; level++){
      gridPRIME_to_grid(ctx, 0, varu, 1, &ROW, &COL, &LEV, &Row, &Col, &Lev);
      ctx->dpy_ctx->Sound.uwindline[level]=interpolate_grid_value( ctx,
                                           0, varu, Row, Col, level);
   }
   ROW = (float)(row);
   COL = (float)(col);
   LEV = gridlevel_to_gridlevelPRIME( ctx, lowlev);
   for (level = lowlev; level < nl; level++){
      gridPRIME_to_grid(ctx, 0, varv, 1, &ROW, &COL, &LEV, &Row, &Col, &Lev);
      ctx->dpy_ctx->Sound.vwindline[level]=interpolate_grid_value( ctx,
                                           0, varv, Row, Col, level);
   }
   return 1;
}


syntax highlighted by Code2HTML, v. 0.9.1