 /*
  * Khoros: $Id: gwin_util.c,v 1.3 1991/10/02 00:13:22 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: gwin_util.c,v 1.3 1991/10/02 00:13:22 khoros Exp $";
#endif

 /*
  * $Log: gwin_util.c,v $
 * Revision 1.3  1991/10/02  00:13:22  khoros
 * HellPatch2
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "xprism.h"

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: gwin_util.c
   >>>>              
   >>>>   description: Utilities to manage the gwin structure
   >>>>               
   >>>>      routines: 
   >>>>			assign_plot_to_gwin
   >>>>			create_new_gwin
   >>>>			create_window
   >>>>			find_wc_min_max
   >>>>			freegwin
   >>>>			freeplot
   >>>>			init_gwin
   >>>>			init_gwin_attributes
   >>>>			init_perspective
   >>>>			reset_world_coordinates
   >>>>			set_disp_min_max
   >>>>			set_gwin_min_max_intv_x
   >>>>			set_gwin_min_max_intv_y
   >>>>			set_gwin_min_max_intv_z
   >>>>			set_world_coordinates
   >>>>
   >>>> modifications:	
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


#define diag_id 19


/************************************************************
*
*  MODULE NAME: create_new_gwin
*
*      PURPOSE: Sets up a new graphics workspace, giving a
*               "gwin" structure (one of the elements of the
*                global "gwin" array of VPGraphicsWindow structures)
*               values for all fields. Also assigns the plot
*               structure (passed in)  to the "plist" (Plot List),
*               as the first plot to be associated with the new
*               window, and does various and sundry other bits of
*               bookkeeping.
*
*
*        INPUT: 1) plot        - pointer to plot structure
*		2) plot_type   - type of plot to display
*		3) marker_type - type of marker for plot
*		4) line_type   - type of marker for plot
*
*		NOTE: if marker_type or line_type is sent in as zero,
*			will set them to customary defaults
*
*       OUTPUT: graphics workspace displayed on screen
*
*    CALLED BY: Plotting_Routine_2D,
*               Plotting_Routine_3D,
*               Plotting_Routine_Mesh,
*               Plotting_Routine_Surface,
*
*   WRITTEN BY: Danielle Argiro 
*
*
*************************************************************/

struct VPGraphicsWindow 
*create_new_gwin(plot, plot_type, marker_type, line_type, 
                 step_size_x, begin_point_x, end_point_x, plot_color,
                 step_size_y, begin_point_y, end_point_y, legend_str, active)


XPlot *plot;
int    plot_type;
int    marker_type;
int    line_type;
int    plot_color;
int    begin_point_x, end_point_x;
int step_size_x;
int    begin_point_y, end_point_y;
int step_size_y;
int active;
char *legend_str;
{
        int         x, y;
        Window      rootwin;
        unsigned    int width, height, border_width, depth;
	char 	    tmp[50];

	/* allocate room for gwin */
	gwin = (struct VPGraphicsWindow *) 
		malloc (sizeof (struct VPGraphicsWindow));

	/* initialize structure */
	init_gwin();
	xp_device = xpX11;

        /*
         *  Create the XWindow workspace of the Graphics Window and
         *  initialize the refresh method for the plot window (Graphics
         *  Window).
         */
        create_window(&gwin->workspace, gwin->id);
        init_refresh();

        /* map the workspace window */
        XSync(display, 0);
	XFlush(display);

        /*
	 *  by convention, since this is the first plot to be displayed
         *  in this window, the window inherits the dimension characteristic
         *  (2D or 3D) from this plot
	 */
        gwin->plot_type = plot_type;

	/*
	 *  initialize the X3D (see xvgraphics) graphics structure for this 
	 *  gwin for use with calls to X3D drawing and text routines. Also
	 *  set the default viewport at this time - always will have a "buffer"
	 *  of white space around the plot, regardless of perspective or 
	 *  distance
	 */
	if (PLOT_TYPE_2D(plot_type))
	{  
	    X3D_init_graphics(gwin->id, X2D);  
	    X3D_set_font(gwin->id, DoubleRoman);  
	    X3D_set_text(gwin->id, CenterJustify, 0.4, 0.7);  
	    if (gwin_attr->draw_legend)
	       X2D_set_viewport(gwin->id, 0.2, 0.8, 0.3, 0.9);
	    else 
	       X2D_set_viewport(gwin->id, 0.1, 0.9, 0.1, 0.9);
        }
	else
	{
	     X3D_init_graphics(gwin->id, X3D);
	     X3D_set_font(gwin->id, DoubleRoman);  
	     X3D_set_text(gwin->id, CenterJustify, 0.4, 0.6);  

            if (gwin_attr->draw_legend )
               X3D_set_viewport(gwin->id, 0.2, 0.9, 0.2, 0.9, 0.2, 0.9);
	    else
	       X3D_set_viewport(gwin->id, 0.1, 0.9, 0.1, 0.9, 0.1, 0.9);

	     X3D_set_projection(gwin->id, Perspective);
	     X3D_set_view_distance(gwin->id, gwin_attr->view_dist);
	     X3D_set_viewpoint(gwin->id, gwin_attr->alpha, gwin_attr->theta,
			       gwin_attr->eye_dist);
	     init_perspective();

	     X3D_init_graphics(gwin->id, X3D);
	     X3D_set_font(gwin->id, DoubleRoman);  
	     X3D_set_text(gwin->id, CenterJustify, 0.4, 0.6);  

	     if (gwin_attr->draw_legend )
	         X3D_set_viewport(gwin->id, 0.2, 0.9, 0.2, 0.9, 0.2, 0.9);
	     else
	         X3D_set_viewport(gwin->id, 0.1, 0.9, 0.1, 0.9, 0.1, 0.9);
	     X3D_set_projection(gwin->id, Perspective);
	     X3D_set_view_distance(gwin->id, gwin_attr->view_dist);
	     X3D_set_viewpoint(gwin->id, gwin_attr->alpha, gwin_attr->theta,
			       gwin_attr->eye_dist);
	     init_perspective();
 	}


	/*
	 *  Tell the graphics routines what window and display were using
	 *  and the size and dimensions of that window.  X3D_set_X11 also
	 *  sets the graphics device to type X11.
	 */
	X3D_set_X11(gwin->id, display, NULL, gwin->xprism_widget);
        xp_device = xpX11;
	XGetGeometry(display, gwin->workspace, &rootwin, &x, &y, 
                     &width, &height,  &border_width, &depth);
	X3D_set_window (gwin->id, 0, 0, (short) width, (short) height);


        /* so far, this is the only plot to be associated with this window */
        gwin->plotnum = 1;
        gwin->disp_plotnum = 1;

        /* allocate space for the "plist", linked list of plot structures */
        gwin->plist = plot;
        
        /* set the end of the list to nil */
        gwin->plist->next = NULL;

	/* this plot starts out as active */
        gwin->plist->active = active;

	/* this plot takes on default type of plot passed in */
	gwin->plist->plot_type = plot_type;

	/* assign the data sampling to this plot */
	gwin->plist->step_size.x = (float) step_size_x;
	gwin->plist->begin_point.x =  (float) begin_point_x;
	gwin->plist->end_point.x = (float) end_point_x;
	gwin->plist->step_size.y = (float) step_size_y;
	gwin->plist->begin_point.y = (float) begin_point_y;
	gwin->plist->end_point.y = (float) end_point_y;

        /*
	 *  the first plot in a window always has an ID of 1, the
         * second has an ID of 2, and so on; the color of the first
	 * plot is derived from the id.
	 */
        gwin->plist->id = gwin->plist->colorindex   = 1;

       if (plot_color != 0)
          gwin->plist->colorindex = plot_color;
       else if (gwin->plist->id >= color_num) 
          gwin->plist->colorindex = gwin->plist->id - color_num;
       else
	  gwin->plist->colorindex = gwin->plist->id;

	gwin->plist->color = xvf_strcpy(colornames[gwin->plist->colorindex]);


        if (marker_type != 0)
	   gwin->plist->marker = marker_type;
        else if (gwin->plist->id >= NUMBER_MARKERS) 
           gwin->plist->marker = gwin->plist->id - NUMBER_MARKERS;
        else
	   gwin->plist->marker = gwin->plist->id;

	if ((line_type != 0) && 
	    (plot_type != PLOT_POLYMARKER) && 
	    (plot_type != PLOT_LINEMARKER))
	  gwin->plist->line_type = line_type;
	else gwin->plist->line_type = 1;

	gwin->plist->contour_num = 64;
	gwin->plist->contour_offset = 0.0;
        gwin->plist->levels = NULL;

        if (legend_str == NULL)
           sprintf(tmp, "Plot 1");
        else
 	   sprintf(tmp, "%s", legend_str);

        gwin->plist->legend_str = xvf_strcpy(tmp);

	/* assign the max and mins from the plot */
        find_min_max(plot, gwin->plot_type);

	gwin->WCmin = plot->WCmin;
	gwin->WCmax = plot->WCmax;

	/*  Make sure that the max and min values are not equal */
	if (plot->WCmin.x ==  plot->WCmax.x)
	{
	   gwin->WCmax.x = plot->WCmax.x + 0.5;
	   gwin->WCmin.x = plot->WCmin.x - 0.5;
	}
	if (plot->WCmin.y ==  plot->WCmax.y)
	{
	   gwin->WCmax.y = plot->WCmax.y + 0.5;
	   gwin->WCmin.y = plot->WCmin.y - 0.5;
	}
	if (PLOT_TYPE_3D(gwin->plot_type) && (plot->WCmin.z ==  plot->WCmax.z))
	{
	      gwin->WCmax.z = plot->WCmax.z + 0.5;
	      gwin->WCmin.z = plot->WCmin.z - 0.5;
	}
	
	gwin->num_tics.x = 6;
	gwin->num_tics.y = 6;
	gwin->num_tics.z = 4;
	if (PLOT_TYPE_3D(gwin->plot_type))
        {
           gwin->num_tics.y = 3;
           gwin->num_tics.x = 3;
        }


	reset_world_coordinates();

	return(gwin);
}



/************************************************************
*
*  MODULE NAME: create_window
*
*      PURPOSE: Used to create the XWindow associated with
*		the VPGraphicsWindow structure, on which all
*		drawing & text operations for that window will
*		be displayed.
*
*	 INPUT:
*
*   WRITTEN BY: Danielle Argiro, Mark Young, & Mike Lang
*
*
*************************************************************/

#define WORKSPACE_WIDTH	  512
#define WORKSPACE_HEIGHT  512

extern  char  **av;
extern  int   ac;

create_window(workspace, gwin_id)
Window *workspace;
int	gwin_id;
{
	char	*mesg, tmp[512];
        unsigned long mask;
        XGCValues xgcvalues;
	XFontStruct *font;
	void	  check_window();

        /* Set up the graphics window attributes */
        def_scr = XDefaultScreenOfDisplay(display);
        screen  = XDefaultScreen(display);

	gwin->xprism_widget = canvas;
	*workspace = XtWindow(canvas);
        XtAddEventHandler(canvas, ExposureMask|StructureNotifyMask, FALSE,
                          check_window, NULL);

        
        /*
	 *  only if this is the 1st gwin, do we need to 
	 *  set up the global gc_draw and gc_fill 
	 *  to be used with drawing on graphics windows
	 */
  	if (gwin_id == 0)
	{
           xgcvalues.function   = GXcopy;
           mask = GCFunction;
           gc_draw = XCreateGC(display, *workspace, mask, &xgcvalues);  
           gc_fill = XCreateGC(display, *workspace, mask, &xgcvalues);  

           /* define foreground and background */
	   bg.flags = DoRed | DoGreen | DoBlue;
	   fg.flags = DoRed | DoGreen | DoBlue;
           bg.pixel = BlackPixel(display, DefaultScreen(display));
           fg.pixel = WhitePixel(display, DefaultScreen(display));

	   XQueryColor(display, XDefaultColormap(display, screen), &fg);
	   XQueryColor(display, XDefaultColormap(display, screen), &bg);

           XSetForeground(display, gc_draw, fg.pixel);
           XSetBackground(display, gc_draw, bg.pixel);
           XSetForeground(display, gc_fill, bg.pixel);

           /* font to be used with text on the workspace */
           if ((font = XLoadQueryFont(display, FONTNAME_R3)) == NULL)
           {
               if ((font = XLoadQueryFont(display, FONTNAME_R2)) == NULL)
               {
		  (void) sprintf(tmp, "Can't find small default fonts:\n%s\n%s",				 FONTNAME_R3, FONTNAME_R2);
		  mesg = xvf_strcpy(tmp);
		  xvf_error_wait(mesg, "create_window", NULL);
		  free(mesg);
                  exit(1);

               }
           }
           XSetFont(display, gc_draw, font->fid);

	   /*
	    *  Set the overlay's object list to NULL and initialize the
	    *  overlays to the xprism workspace.
	    */
	   obj_list = NULL;
	   init_overlays(gwin_id, canvas);
	}
	XSync(XtDisplay(gwin->xprism_widget), FALSE);
}


/************************************************************
*
*  MODULE NAME: assign_plot_to_gwin
*
*      PURPOSE: Assigns a plot structure to a graphics window,
*               thus associating a certain plot with that
*               window. A call to this routine implies that
*               at least one other plot structure has already
*               been associated with this graphics window.
*
*
*        INPUT: 1)  plot -- a pointer to the plot structure
*		2)  plot_type - type of plot to display
*		3)  marker_type - type of marker to display
*		4)  line_type - type of plot to display
*
*		note: if marker_type or line_type is sent in as zero,
*			will set them to customary defaults
*
*       OUTPUT:
*
*    CALLED BY: Plot
*
*   WRITTEN BY: Danielle Argiro
*
*
*************************************************************/


assign_plot_to_gwin(plot, plot_type, marker_type, line_type,
                 step_size_x, begin_point_x, end_point_x, plot_color,
                 step_size_y, begin_point_y, end_point_y, legend_str, active)

XPlot *plot;
int	plot_type;
int	marker_type;
int	line_type;
int     plot_color;
int	begin_point_x, end_point_x;
int     step_size_x;
int	begin_point_y, end_point_y;
int     step_size_y;
int     active;
char  *legend_str;

{
      int	plot_id, ok = false, done; 
      char	*mesg, tmp[50];
      XPlot	*temp;

      /*
       *  plots in the same window must be 
       *  all either 2D or 3D
       */
      if (gwin->plot_type == UNDEFINED)
      {
	 gwin->plot_type = plot_type;
      }
      else if ((PLOT_TYPE_2D(gwin->plot_type) && PLOT_TYPE_3D(plot_type)) ||
	       (PLOT_TYPE_3D(gwin->plot_type) && PLOT_TYPE_2D(plot_type)))
      {
	    mesg = xvf_strcpy("Cannot assign a 2D plot to a 3D graphics window or vice versa");
	    xvf_error_wait(mesg, "assign_plot_to_gwin", NULL);
	    free(mesg);
            FLUSH();
            return;
      }

      /*
       *  find plot id
       */
      plot_id = 1;
      while (!(ok))
      {
          temp = gwin->plist;
	  done = false;
	  while ((temp != NULL) && (!(done)))
	  {
	     if (temp->id == plot_id)
	     {
		done = true;
		ok   = false;
	     }
	     else
	     {
		ok = true;
	     }
	
	     temp = temp->next;
	 }
	 if (!(ok)) plot_id++;
      }

      /*
       *  loop to end of "plist" -- the list of plots
       *  associated with this window
       */
      temp = gwin->plist;
      while (temp->next != NULL)
	 temp = temp->next;

      temp->next = plot;
      plot->next = NULL;

      /* set the end of the list to nil, and give the plot an ID */
      plot->id		 = plot_id;
      plot->active	 = active;
      plot->plot_type	 = plot_type;
      plot->begin_point.x = (float) begin_point_x;
      plot->end_point.x	 = (float) end_point_x;
      plot->step_size.x	 = (float) step_size_x;
      plot->begin_point.y = (float) begin_point_y;
      plot->end_point.y	 = (float) end_point_y;
      plot->step_size.y	 = (float) step_size_y;

      if (legend_str == NULL)
         sprintf(tmp, "Plot %d", plot->id);
      else
 	 sprintf(tmp, "%s", legend_str);

      plot->legend_str = xvf_strcpy(tmp);

      /*
       *  determine what color this plot will be
       */
       if (plot_color != 0)
          plot->colorindex = plot_color;
       else if (plot->id >= color_num) 
          plot->colorindex = plot->id - color_num;
       else
	  plot->colorindex = plot->id;

	plot->color = xvf_strcpy(colornames[plot->colorindex]);

      /*
       *  determine what kind of marker this plot will have
       */
       if (marker_type == 0)
       {
           if (plot->id > NUMBER_MARKERS) 
              plot->marker = plot->id - NUMBER_MARKERS;
           else
	      plot->marker = plot->id;
       }
       else plot->marker = marker_type;  /* if set on cmd line */

       if ((line_type != 0) &&
	   (plot_type != PLOT_POLYMARKER) &&
	   (plot_type != PLOT_LINEMARKER))
	  plot->line_type = line_type;   /* if set on cmd line */
       else plot->line_type	 = 1;

	plot->contour_num = 64;
        plot->contour_offset = 0.0;
        plot->levels = NULL;

          /* need to fing the new min/max based on the display sampling */
	find_min_max(plot, gwin->plot_type);

      /* one more plot displayed in the window */
      gwin->plotnum++;
      gwin->disp_plotnum++;

}



/************************************************************
*
*  MODULE NAME:  reset_world_coordinates
*
*      PURPOSE:  This routine resets the max & min values for 
*                a given graphics window.  
*
*        INPUT:
*
*       OUTPUT:  corrected values for the world coordinate
*                max and min variables of the gwin structure
*
*    CALLED BY:
*
*   WRITTEN BY:  Mark Young & Mike Lang, Tom Sauer
*
*
*************************************************************/



reset_world_coordinates()
{
        XPlot *plot;
	float num_tics;
	double min, max, major_int;

	/*  Make sure that the max and min values are not equal */

	if (gwin->WCmin.x ==  gwin->WCmax.x)
	{
	   gwin->WCmax.x = gwin->WCmax.x + 0.5;
	   gwin->WCmin.x = gwin->WCmin.x - 0.5;
	}

	if (gwin->WCmin.y ==  gwin->WCmax.y)
	{
	   gwin->WCmax.y = gwin->WCmax.y + 0.5;
	   gwin->WCmin.y = gwin->WCmin.y - 0.5;
	}

	if (PLOT_TYPE_3D(gwin->plot_type) && (gwin->WCmin.z ==  gwin->WCmax.z))
	{
	      gwin->WCmax.z = gwin->WCmax.z + 0.5;
	      gwin->WCmin.z = gwin->WCmin.z - 0.5;
	}

	num_tics = (float)gwin->num_tics.x;
	min = (double)gwin->WCmin.x;
	max = (double)gwin->WCmax.x;
	if(gwin_attr->auto_scale)
	   set_min_max_step(&major_int, &num_tics, &min, &max);
	else
	   set_step(&major_int, &num_tics, min, max);
	gwin->major_intv.x = (float)major_int; 
	gwin->num_tics.x = (int)(num_tics);
	gwin->WCmin.x = (float)min;
	gwin->WCmax.x = (float)max;

	num_tics = (float)gwin->num_tics.y;
	min = (double)gwin->WCmin.y;
	max = (double)gwin->WCmax.y;
	if(gwin_attr->auto_scale)
	   set_min_max_step(&major_int, &num_tics, &min, &max);
	else
	   set_step(&major_int, &num_tics, min, max);
	gwin->major_intv.y = (float)major_int; 
	gwin->num_tics.y = (int)(num_tics);
	gwin->WCmin.y = (float)min;
	gwin->WCmax.y = (float)max;

	if (PLOT_TYPE_3D(gwin->plot_type))
	{
	   num_tics = (float)gwin->num_tics.z;
	   min = (double)gwin->WCmin.z;
	   max = (double)gwin->WCmax.z;
	if(gwin_attr->auto_scale)
	   set_min_max_step(&major_int, &num_tics, &min, &max);
	else
	   set_step(&major_int, &num_tics, min, max);
	   gwin->major_intv.z = (float)major_int; 
	   gwin->num_tics.z = (int)(num_tics);
	   gwin->WCmin.z = (float)min;
	   gwin->WCmax.z = (float)max;
	}

	/* Reinitialize the world coordinate values.  */
	plot = gwin->plist;

        /*
	 *  loop through all the plots associated with this
         *  window structure, setting WC values to the 
         *  maximum and minimum points over all the plots
	 */
	while (plot != NULL) 
	{
	   if (plot->active == true)
	   {
	      if (plot->WCmax.x > gwin->WCmax.x) 
	         gwin->WCmax.x = plot->WCmax.x;

	      if (plot->WCmin.x < gwin->WCmin.x) 
	         gwin->WCmin.x = plot->WCmin.x;

	      if (plot->WCmax.y > gwin->WCmax.y) 
	         gwin->WCmax.y = plot->WCmax.y;

	      if (plot->WCmin.y < gwin->WCmin.y) 
	         gwin->WCmin.y = plot->WCmin.y;

	      if (PLOT_TYPE_3D(gwin->plot_type))
	      {
	         if (plot->WCmax.z > gwin->WCmax.z) 
	            gwin->WCmax.z = plot->WCmax.z;

	         if (plot->WCmin.z < gwin->WCmin.z) 
	            gwin->WCmin.z = plot->WCmin.z;
	      }
	   }
	   plot = plot->next;
	}


	num_tics = (float)gwin->num_tics.x;
	min = (double)gwin->WCmin.x;
	max = (double)gwin->WCmax.x;
	if(gwin_attr->auto_scale)
	   set_min_max_step(&major_int, &num_tics, &min, &max);
	else
	   set_step(&major_int, &num_tics, min, max);
	gwin->major_intv.x = (float)major_int; 
	gwin->num_tics.x = (int)num_tics;
	gwin->WCmin.x = (float)min;
	gwin->WCmax.x = (float)max;

	num_tics = (float)gwin->num_tics.y;
	min = (double)gwin->WCmin.y;
	max = (double)gwin->WCmax.y;
	if(gwin_attr->auto_scale)
	   set_min_max_step(&major_int, &num_tics, &min, &max);
	else
	   set_step(&major_int, &num_tics, min, max);
	gwin->major_intv.y = (float)major_int; 
	gwin->num_tics.y = (int)(num_tics);
	gwin->WCmin.y = (float)min;
	gwin->WCmax.y = (float)max;
	
	/* set wc min & max for X3D graphics routine calls */
	if (PLOT_TYPE_2D(gwin->plot_type)) 
	{
	   X2D_set_wc_min_max (gwin->id, gwin->WCmin, gwin->WCmax);
	   gwin->WCmin.z = 0.0;
	   gwin->WCmax.z = 0.0;
	}
	else 
	{
	   num_tics = (float)gwin->num_tics.z;
	   min = (double)gwin->WCmin.z;
	   max = (double)gwin->WCmax.z;
	   if(gwin_attr->auto_scale)
	      set_min_max_step(&major_int, &num_tics, &min, &max);
	   else
	      set_step(&major_int, &num_tics, min, max);
	   gwin->major_intv.z = (float)major_int; 
	   gwin->num_tics.z = (int)(num_tics);
	   gwin->WCmin.z = (float)min;
	   gwin->WCmax.z = (float)max;
	   X3D_set_wc_min_max (gwin->id, gwin->WCmin, gwin->WCmax);
	}
	set_disp_min_max_step(gwin->WCmin, gwin->WCmax, 
                              gwin->major_intv, gwin->num_tics);
              /* now that we have the gwin information 
 	       * and it is correct, we can initialize the
               * display information
               */

}




/************************************************************
*
*  MODULE NAME: init_gwin
*
*      PURPOSE: Initializes the graphics window structure
*
*        INPUT: none
*
*       OUTPUT: none
*
*    CALLED BY: main
*
*   WRITTEN BY: Danielle Argiro 
*
*
*************************************************************/


init_gwin()
{
	/* identification number is the gwin's array index */
        gwin->id = 0;

	/* initially there are no plots associated with the gwin */
	gwin->plotnum = 0;
	gwin->disp_plotnum = 0;
	gwin->plist = NULL;
}




/************************************************************
*
*  MODULE NAME: init_gwin_attributes
*
*      PURPOSE: initializes the graphics window attribute structure
*
*        INPUT: none
*
*       OUTPUT: none
*
*    CALLED BY: main
*
*   WRITTEN BY: Danielle Argiro 
*
*
*************************************************************/


init_gwin_attr(gwinnum, title, xaxis, yaxis, zaxis, grid, auto_scale, axes,
	       box,  legend, scale, fonts, colors, minor_tics, numlabels, 
               rescale_relabel, machine_type, clear_labels, alpha,
	       theta, eye_dist, view_dist)
	
int    gwinnum;
char   *title, *xaxis, *yaxis, *zaxis; 
int    grid, box, auto_scale, axes, legend, numlabels;
int    machine_type, rescale_relabel, clear_labels;
Coord  scale;
int    fonts[];
int    colors[];
Coord  minor_tics;
Real alpha, theta, eye_dist, view_dist;
{
	int  i;
	char *font_type_string();


	/* default axis titles */
	if (title != NULL)
	   gwin_attr->title = xvf_strcpy(title);
	else
           gwin_attr->title = xvf_strcpy("XPRISM PLOT");

	if (xaxis != NULL)
	   gwin_attr->xaxis = xvf_strcpy(xaxis);
	else
           gwin_attr->xaxis = xvf_strcpy("X AXIS");

	if (yaxis != NULL)
	   gwin_attr->yaxis = xvf_strcpy(yaxis);
	else
           gwin_attr->yaxis = xvf_strcpy("Y AXIS");

	if (zaxis != NULL)
	   gwin_attr->zaxis = xvf_strcpy(zaxis);
	else
           gwin_attr->zaxis = xvf_strcpy("Z AXIS");

	/* set axes fields */
	gwin_attr->clear_labels = clear_labels;
	gwin_attr->draw_grid = grid;
	gwin_attr->draw_numlabels = numlabels;
	gwin_attr->draw_box = box;
	gwin_attr->auto_scale = auto_scale;
	gwin_attr->draw_axes = axes;
	gwin_attr->draw_legend = legend;
	gwin_attr->rescale_relabel = rescale_relabel;
	gwin_attr->machine_type_index = machine_type;
	gwin_attr->scale.x = LINEAR;
	gwin_attr->scale.y = LINEAR;
	gwin_attr->scale.z = LINEAR;

	/* initialize current_colors index to all white */
	for (i=0; i < MAX_COLORS; i++)
	   gwin_attr->current_colors[i] = colors[i];

	/* set fonts */
	gwin_attr->font[TITLE] = VStrcpy(font_type_string(fonts[TITLE]));
	gwin_attr->font[XAXIS] = VStrcpy(font_type_string(fonts[XAXIS]));
	gwin_attr->font[YAXIS] = VStrcpy(font_type_string(fonts[YAXIS]));
	gwin_attr->font[NUMBERS] = VStrcpy(font_type_string(fonts[NUMBERS]));
	gwin_attr->font[LEGEND] = VStrcpy(font_type_string(fonts[LEGEND]));
	gwin_attr->font[ZAXIS] = VStrcpy(font_type_string(fonts[ZAXIS]));

	/* set axes fields */
	gwin_attr->minor_tics.x = minor_tics.x;
	gwin_attr->minor_tics.y = minor_tics.y;
	gwin_attr->minor_tics.z = minor_tics.z;

	gwin_attr->power_ten.x = 0;
	gwin_attr->power_ten.y = 0;
	gwin_attr->power_ten.z = 0;

	gwin_attr->alpha = alpha;
	gwin_attr->theta = theta;
	gwin_attr->eye_dist = eye_dist;
	gwin_attr->view_dist= view_dist;
}

/************************************************************
*
*  MODULE NAME: freegwin
*
*      PURPOSE: "Frees" a gwin structure, one of the elements
*               of the global "gwin" array of VPGraphicsWindow
*               structures, by re-initializing key fields and
*               freeing the "plist" list of plot structures 
*               associated with this graphics window.
*
*        INPUT:
*
*       OUTPUT: none 
*
*    CALLED BY: Plot, under case delete
*                        when deleting a graphics window
*
*   WRITTEN BY: Danielle Argiro
*
*
*************************************************************/

freegwin()
{
        XPlot *plot, *tempptr;


	if (obj_list != NULL)
	{
	   destroy_overlays(canvas, obj_list);
	   obj_list = NULL;
	}

	XClearWindow(XtDisplay(gwin->xprism_widget), gwin->workspace);
	XFlush(XtDisplay(gwin->xprism_widget));

        /*
	 *  go through the "plist" linked list of plot structures,
         *  freeing memory as we go.  Start at the head of the list.
	 */
        plot = gwin->plist;
        while (plot != NULL)
        {
           tempptr = plot->next;
           freeplot(plot);
	   plot = tempptr;
        }
	free(gwin);
	gwin = NULL;
}



/************************************************************
*
*  MODULE NAME: freeplot
*
*      PURPOSE: This routine frees an XPlot structure.
*
*        INPUT: plot --  a pointer to an XPlot structure that 
*			 contains the plot structure to be freed.
*
*       OUTPUT: (none)  since all we are doing is freeing as much of
*		a plot structure as we can.
*
*    CALLED BY: any routine that wishes to free an XPlot structure
*
*   WRITTEN BY: Mark Young and Mike Lang
*
*
*************************************************************/

freeplot(plot)

XPlot *plot;
{
	/*
	 *  Free as much of the plot structure as we can.  But first check to
	 *  make sure the plot not NULL.
	 */
	if (plot != NULL)
	{
	   /* free Coord data array */
	   if (plot->points != NULL && plot->size > 0)
	      free ((char *) plot->points);

	   /*
	    *  Get rid of the plot structure itself.  We know it is not
	    *  NULL, since we checked it above.
	    */
	   free((char *) plot);
	}
}


/************************************************************
*
*  MODULE NAME: init_perspective
*
*      PURPOSE: Allows the user to change the viewing system
*               interactively using a selection bar and the
*               mouse; allows the user to experiment with
*              the eye distance, view distance, alpha, and theta.
*
*        INPUT: id - the identification # of the gwin involved
*
*       OUTPUT: new values for the gwin's eye distance, view
*               distance, alpha, and thetat (indirectly, as
*               the approprate X3D routines are called to do this)
*               * returns TRUE if the user hit "Use" to use the
*                 new viewing &perspective values
*               * returns FALSE if the user did not hit "Use" to use the
*                 new viewing &perspective values
*
*    CALLED BY: Plot_Options
*
*   WRITTEN BY: Danielle Argiro
*
*
*************************************************************/

init_perspective()

{
        int         x, y;
        Window      rootwin;
        Coord       diagmin, diagmax;
        unsigned    int width, height, border_width, depth;

        static int  initialized = FALSE;


        /*
        *  initialize the Coord arrays that will describe the
        *  axes diagram that represents the current viewpoint
        */
        init_axes_diag(arrow_x, arrow_y, arrow_z);

        /*
        *  set the viewing parameters for the axes diagram:
        *  according to values of actual plot, but modified
        *  slightly in accordance with the diagram itself,
        *  which is bounded by the unit cube
        */
        diagmin.x = -0.1; diagmin.y = -0.1; diagmin.z = -0.1;
        diagmax.x = 1.1; diagmax.y = 1.1; diagmax.z = 1.1;

        if (initialized == FALSE)
        {
           X3D_init_graphics(diag_id, X3D);
           initialized = TRUE;
        }
        X3D_set_X11(diag_id, display, NULL, gwin->xprism_widget);
        XGetGeometry(display, gwin->workspace, &rootwin, &x, &y,
                     &width, &height,  &border_width, &depth);
 	X3D_set_window (diag_id, 0, 0, (short) width, (short) height);
        X3D_set_viewport(diag_id, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
        X3D_set_projection(diag_id, Perspective);
        X3D_set_view_distance(diag_id, gwin_attr->view_dist);
        X3D_set_viewpoint(diag_id, gwin_attr->alpha, gwin_attr->theta, 
			  gwin_attr->eye_dist);
        X3D_set_wc_min_max(diag_id,diagmin,diagmax );
}

/************************************************************
*
*  MODULE NAME: set_disp_min_max
*
*      PURPOSE: This routine will set the display min, max and
*		major interval.
*
*        INPUT: 
*
*       OUTPUT: 
*
*    CALLED BY: any routine that wishes to reset the display 
*		min, max, interval.
*
*   WRITTEN BY: Tom Sauer
*
*
*************************************************************/

set_disp_min_max_step(min, max, intv, step)

Coord min, max, intv, step;
{

           gwin_attr->disp_label_min.x = min.x;
           gwin_attr->disp_label_min.y = min.y;
           gwin_attr->disp_label_min.z = min.z;

           gwin_attr->disp_label_max.x = max.x;
           gwin_attr->disp_label_max.y = max.y;
           gwin_attr->disp_label_max.z = max.z;

           gwin_attr->disp_label_num_tics.x = step.x;
           gwin_attr->disp_label_num_tics.y = step.y;
           gwin_attr->disp_label_num_tics.z = step.z;

           gwin_attr->disp_label_major_intv.x = intv.x;
           gwin_attr->disp_label_major_intv.y = intv.y;
           gwin_attr->disp_label_major_intv.z = intv.z;

           gwin_attr->disp_scale_min.x = min.x;
           gwin_attr->disp_scale_min.y = min.y;
           gwin_attr->disp_scale_min.z = min.z;

           gwin_attr->disp_scale_max.x = max.x;
           gwin_attr->disp_scale_max.y = max.y;
           gwin_attr->disp_scale_max.z = max.z;

           gwin_attr->disp_scale_num_tics.x = step.x;
           gwin_attr->disp_scale_num_tics.y = step.y;
           gwin_attr->disp_scale_num_tics.z = step.z;

           gwin_attr->disp_scale_major_intv.x = intv.x;
           gwin_attr->disp_scale_major_intv.y = intv.y;
           gwin_attr->disp_scale_major_intv.z = intv.z;

}

/************************************************************
*
*  MODULE NAME: set_gwin_min_max_intv_x
*
*      PURPOSE: This will set up the GC min, max and intv
*		specified for the gwin
*
*	 INPUT: x  min, max and interval.
*
*   WRITTEN BY: Tom Sauer
*
*
*************************************************************/
set_gwin_min_max_intv_x(rescale_relabel, xmin, xmax, xintv)
float xmin, xmax, xintv;
int rescale_relabel;

{
	float num_tics;

	    if ((xintv > 0) && (xintv < xmax - xmin))
	    {
	       if (gwin_attr->auto_scale)
	       {
	             get_number_steps(xintv, &num_tics,xmin,xmax);
                     set_min_max_step(&xintv, &num_tics, &xmin, &xmax);
	       }
	       else
	       {
	              get_number_steps(xintv, &num_tics,xmin,xmax);
	       }
	       gwin_attr->disp_label_max.x = (float) xmax;
	       gwin_attr->disp_label_min.x = (float) xmin;
	       gwin_attr->disp_label_num_tics.x = (int) num_tics;
	       gwin_attr->disp_label_major_intv.x = xintv;
	    }
	    else
		return(0);

            if (rescale_relabel == RESCALE)
            {
                set_disp_min_max_step(gwin_attr->disp_label_min, 
                                 gwin_attr->disp_label_max, 
                                 gwin_attr->disp_label_major_intv,
                                 gwin_attr->disp_label_num_tics);
	        X3D_set_wc_min_max (gwin->id, gwin_attr->disp_scale_min, 
                                              gwin_attr->disp_scale_max);
            }

	return(1);
}

/************************************************************
*
*  MODULE NAME: set_gwin_min_max_intv_y
*
*      PURPOSE: This will set up the GC min, max and intv
*		specified for the gwin
*
*	 INPUT: x, y and z min, max and interval.
*
*   WRITTEN BY: Tom Sauer
*
*
*************************************************************/
set_gwin_min_max_intv_y(rescale_relabel, ymin, ymax, yintv)
float ymin, ymax, yintv;
int rescale_relabel;

{
	float num_tics;

	    if ((yintv > 0) && (yintv < ymax - ymin))
	    {
	       if (gwin_attr->auto_scale)
	       {
	             get_number_steps(yintv,&num_tics,ymin,ymax);
                     set_min_max_step(&yintv, &num_tics, &ymin, &ymax);
	       }
	       else
	       {
	              get_number_steps(yintv,&num_tics,ymin,ymax);
	       }
	       gwin_attr->disp_label_max.y = (float) ymax;
	       gwin_attr->disp_label_min.y = (float) ymin;
	       gwin_attr->disp_label_num_tics.y = (int)num_tics;
	       gwin_attr->disp_label_major_intv.y = yintv;
	    }
	    else
		return(0);

            if (rescale_relabel == RESCALE)
            {
                set_disp_min_max_step(gwin_attr->disp_label_min, 
                                 gwin_attr->disp_label_max, 
                                 gwin_attr->disp_label_major_intv,
                                 gwin_attr->disp_label_num_tics);
	        X3D_set_wc_min_max (gwin->id, gwin_attr->disp_scale_min, 
                                              gwin_attr->disp_scale_max);
            }

	return(1);
}
/************************************************************
*
*  MODULE NAME: set_gwin_min_max_intv_z
*
*      PURPOSE: This will set up the GC min, max and intv
*		specified for the gwin
*
*	 INPUT: z min, max and interval.
*
*   WRITTEN BY: Tom Sauer
*
*
*************************************************************/
set_gwin_min_max_intv_z(rescale_relabel, zmin, zmax, zintv)
float zmin, zmax, zintv;
int rescale_relabel;

{
	float num_tics;

	       if ((zintv > 0) && (zintv < zmax - zmin))
	       {
	          if (gwin_attr->auto_scale)
	    	  {
	                get_number_steps(zintv,&num_tics,zmin,zmax);
                        set_min_max_step(&zintv, &num_tics, &zmin, &zmax);
	          }
	          else
	    	  {
	                 get_number_steps(zintv,&num_tics,zmin,zmax);
	          }
	          gwin_attr->disp_label_max.z = (float) zmax;
	          gwin_attr->disp_label_min.z = (float) zmin;
	          gwin_attr->disp_label_num_tics.z = (int)num_tics;
	          gwin_attr->disp_label_major_intv.z = zintv;
	       }
	       else
		   return(0);

            if (rescale_relabel == RESCALE)
            {
                set_disp_min_max_step(gwin_attr->disp_label_min, 
                                 gwin_attr->disp_label_max, 
                                 gwin_attr->disp_label_major_intv,
                                 gwin_attr->disp_label_num_tics);
	        X3D_set_wc_min_max (gwin->id, gwin_attr->disp_scale_min, 
                                              gwin_attr->disp_scale_max);
            }

	return(1);
}
/************************************************************
*
*  MODULE NAME:  find_wc_min_max
*
*      PURPOSE:  This routine will find the wc min and max of
*		 all plots associated with 
*                a given graphics window.  
*
*        INPUT:
*
*       OUTPUT: Coord - min - returns the min value  
*		Coord - max - return the max value
*
*    CALLED BY:
*
*   WRITTEN BY:  Tom Sauer
*
*
*************************************************************/

find_wc_min_max()
{
        XPlot *plot;
	int done = FALSE;
	Coord min, max;


	/* this is in case there are no active plots */
   
	min.x = gwin->WCmin.x;
	min.y = gwin->WCmin.y;
	min.z = gwin->WCmin.z;

	max.x = gwin->WCmax.x;
	max.y = gwin->WCmax.y;
	max.z = gwin->WCmax.z;

	plot = gwin->plist;
	while (plot != NULL && ! done) 
	{
	   if (plot->active == true)
	   {
		min.x = plot->WCmin.x;
		max.x = plot->WCmax.x;
		min.y = plot->WCmin.y;
		max.y = plot->WCmax.y;
	        if (PLOT_TYPE_3D(gwin->plot_type))
	        {
                   min.z = plot->WCmin.z;
                   max.z = plot->WCmax.z;
		}
		done = TRUE;
	   }
	   plot = plot->next;
	}

        /*
	 *  loop through all the plots associated with this
         *  window structure, setting WC values to the 
         *  maximum and minimum points over all the plots
	 */
	while (plot != NULL) 
	{
	   if (plot->active == true)
	   {
	      if (plot->WCmax.x > max.x) 
	         max.x = plot->WCmax.x;

	      if (plot->WCmin.x < min.x) 
	         min.x = plot->WCmin.x;

	      if (plot->WCmax.y > max.y) 
	         max.y = plot->WCmax.y;

	      if (plot->WCmin.y < min.y) 
	         min.y = plot->WCmin.y;

	      if (PLOT_TYPE_3D(gwin->plot_type))
	      {
	         if (plot->WCmax.z > max.z) 
	            max.z = plot->WCmax.z;

	         if (plot->WCmin.z < min.z) 
	            min.z = plot->WCmin.z;
	      }
	   }
	   plot = plot->next;
	}

          /* resetting the gwin values */
	gwin->WCmin.x =  min.x;
	gwin->WCmin.y =  min.y;
	gwin->WCmin.z =  min.z;
	gwin->WCmax.x =  max.x;
	gwin->WCmax.y =  max.y;
	gwin->WCmax.z =  max.z;
        gwin->num_tics.x = 6;
        gwin->num_tics.y = 6;
        if (PLOT_TYPE_3D(gwin->plot_type))
        {
           gwin->num_tics.y = 3;
           gwin->num_tics.x = 3;
           gwin->num_tics.z = 4;
        }
}

/************************************************************
*
*  MODULE NAME:  set_world_coordinates
*
*      PURPOSE:  This routine is to set the world coordiates given 
*		 the min, max, and num_steps.
*
*       INPUT: Coord - min - min value  
*		Coord - max - max value
*		Coord - num_steps - the number of steps
*
*    CALLED BY:
*
*   WRITTEN BY:  Tom Sauer
*
*
*************************************************************/

set_world_coordinates(min, max, num_steps)
Coord min,max, num_steps;
{
	Coord intv;

	intv.x = (max.x - min.x)/num_steps.x;
	set_gwin_min_max_intv_x(RESCALE, min.x, max.x, intv.x);
	intv.y = (max.y - min.y)/num_steps.y;
	set_gwin_min_max_intv_y(RESCALE, min.y, max.y, intv.y);
	if (PLOT_TYPE_3D(gwin->plot_type))
	{
	    intv.z = (max.z - min.z)/num_steps.z;
	    set_gwin_min_max_intv_z(RESCALE, min.z, max.z, intv.z);
        }
}
