 /*
  * Khoros: $Id: axeslib.c,v 1.4 1992/03/20 22:45:56 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: axeslib.c,v 1.4 1992/03/20 22:45:56 dkhoros Exp $";
#endif

 /*
  * $Log: axeslib.c,v $
 * Revision 1.4  1992/03/20  22:45:56  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * 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.
 *----------------------------------------------------------------------
 */

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: axeslib.c                              <<<<
   >>>>                                                       <<<<
   >>>>   description:  All the routines in this file are     <<<<
   >>>>                 utilities for the axes routines       <<<<
   >>>>                                                       <<<<
   >>>>      routines: 					      <<<<
   >>>>               add_power_axis_label                    <<<<
   >>>>               set_min_max_step                        <<<<
   >>>>               ttruncate                               <<<<
   >>>>               fracround                               <<<<
   >>>>               numdecs                                 <<<<
   >>>>               step_size_linear                        <<<<
   >>>>               find_decimal_places                     <<<<
   >>>>               numdigs                                 <<<<
   >>>>               set_step                                <<<<
   >>>>               get_number_steps                        <<<<
   >>>>               find_scale_factor                       <<<<
   >>>>               label_tics                              <<<<
   >>>>               clear_label                             <<<<
   >>>>               write_label                             <<<<
   >>>>               draw_legend                             <<<<
   >>>>               set_text_params_2D                      <<<<
   >>>>               set_text_params_3D                      <<<<
   >>>>                                                       <<<<
   >>>> modifications:					      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


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


/************************************************************
*
*  MODULE NAME: label_tics
*
*      PURPOSE: generates and draw the numbers for the axes
*
*        INPUT:  Mike You Weasel You List Your Input Here!
*
*       OUTPUT: none
*
*    CALLED BY: xtics,ytics,ztics
*
*   WRITTEN BY: Mike Lang
*
*
*************************************************************/
label_tics(axes,text_coords,num,plot_type,color,width,height,depth,direction)

Coord *text_coords;
Vector direction;
caddr_t *axes;
int num, plot_type, color;
float width, height, depth;
{
	int colorindex;
	int i;

	colorindex = gwin_attr->current_colors[color];

        if (xp_device != xpX11)
            X3D_set_line_width(gwin->id, Fine);
	X3D_set_font (gwin->id, gwin_attr->font[NUMBERS]);
	for(i = 0; i < num; i++)
	{

	   if (PLOT_TYPE_2D(plot_type))
	      X2D_draw_text(gwin->id, text_coords[i], direction, width, 
			    height, axes[i], VStrlen(axes[i]),
			    &Colors[colorindex]);
	   else
	      X3D_draw_text(gwin->id, text_coords[i], direction, width, 
			    height, depth, axes[i], VStrlen(axes[i]), 
			    &Colors[colorindex]);
	}
}



/************************************************************
*
*  MODULE NAME: clear_label
*
*      PURPOSE: Clears out the plot labels using text routines.
*
*
*        INPUT: pointer to the VPGraphicsWorkspace structure
*		axis - the axis to put the label with
*		string - the string to clear
*
*       OUTPUT: Clears the plot label in the graphics workspace
*
*    CALLED BY: Draw_Axis_2D & 
*               Draw_Axis_3D &
*
*   WRITTEN BY: Danielle Argiro & Mike Lang
*
*
*
*************************************************************/
clear_label(plot_type,axis,string)

int	plot_type;
int	axis;
char 	*string;
{
	Coord text_coord;
	Vector direction;
	float  width, height, depth;
	int set_text_params_3D();
	
	X3D_set_font (gwin->id, gwin_attr->font[axis]);

	if ((axis == TITLE) || (PLOT_TYPE_2D(plot_type)))
     	{
	     set_text_params_2D(gwin_attr->disp_scale_max, 
                                gwin_attr->disp_scale_min, &direction, 
				  &text_coord, &width, &height, axis);
/*
	     if ((axis == TITLE) && (PLOT_TYPE_3D(plot_type)))
	     {
		width = (gwin_attr->disp_scale_max.x - 
                         gwin_attr->disp_scale_min.x)/20.0;
		height = (gwin_attr->disp_scale_max.z - 
                          gwin_attr->disp_scale_min.z)/20.0;
	     } 
*/

	     X2D_clear_text(gwin->id, text_coord, direction, width, 
			    height, VStrlen(string), &bg);
	}
        else
	{
            if(!(set_text_params_3D(gwin->id, gwin_attr->disp_scale_max, 
                                  gwin_attr->disp_scale_min,
				  &direction, &text_coord, &width, &height,
				  &depth, axis)))
	    {
		return;
	    }
	    else
	    {
		X3D_clear_text (gwin->id, text_coord, direction, width, 
				height, VStrlen(string), &bg);  
	    }
	}
} /* end clear_label */



/************************************************************
*
*  MODULE NAME: write_label
*
*      PURPOSE: Writes out the labels to the plot
*
*
*        INPUT: pointer to the VPGraphicsWorkspace structure
*		axis - which axis to place labels with
*		string - string to write
*
*       OUTPUT: Clears the plot label in the graphics workspace
*
*    CALLED BY: Draw_Axis_2D & 
*               Draw_Axis_3D &
*
*   WRITTEN BY: Danielle Argiro & Mike Lang
*
*
*
*************************************************************/

write_label(plot_type,axis,string, colorindex)

int     plot_type;
int     axis;
char    *string;
int	colorindex;
{
	Coord text_coord;
	Vector direction;
	float  width, height, depth;
	int set_text_params_3D();

	X3D_set_font (gwin->id, gwin_attr->font[axis]);
	if  ((axis == TITLE) || (PLOT_TYPE_2D(plot_type)))
	{
	    set_text_params_2D(gwin_attr->disp_scale_max, gwin_attr->disp_scale_min, &direction, 
				  &text_coord, &width, &height, axis);

            if (xp_device != xpX11)
                X3D_set_line_width(gwin->id, Fine);
     	    X2D_draw_text(gwin->id, text_coord, direction, width, height, 
			  string, VStrlen(string), &Colors[colorindex]);
        }
        else
	{
            if(!(set_text_params_3D(gwin->id, gwin_attr->disp_scale_max, 
                                  gwin_attr->disp_scale_min, 
				  &direction, &text_coord, &width, &height,
				  &depth, axis)))
	    {
		return;
	    }
	    else
	    {

                if (xp_device != xpX11)
                    X3D_set_line_width(gwin->id, Fine);
		X3D_draw_text(gwin->id, text_coord, direction, width, height,
			      depth, string, VStrlen(string), 
			      &Colors[colorindex]);  
	    }
        }
}  /* end write_label */



/************************************************************
*
*  MODULE NAME: draw_legend
*
*      PURPOSE: Writes out the legend on a 2D plot
*
*
*        INPUT: 
*
*       OUTPUT: the legend in the graphics workspace
*
*    CALLED BY: 
*
*   WRITTEN BY: Danielle Argiro & Mark Young
*
*************************************************************/


draw_legend(plot_type)
int plot_type;
{
	Coord text_coord, endpts[3], begin;
        Coord legend_min, legend_max;
	Vector direction;
        Real  width, height;
	XPlot *plot;
	int   count = 0, colorindex, plotnum, num_col;
	float new_line;


	plotnum = gwin->disp_plotnum;

	legend_min.x = 0.0;  legend_max.x = 10.0;
        legend_min.y = 0.0;  legend_max.y = 2.0;
	legend_min.z = 0.0;  legend_max.z = 0.0;
	X2D_set_viewport(gwin->id, 0.0, 1.0, 0.0, 0.2);
	X2D_set_wc_min_max(gwin->id, legend_min, legend_max);
	X3D_set_text(gwin->id, LeftJustify, 0.4, 0.7);

	X3D_set_font(gwin->id, gwin_attr->font[LEGEND]);

	width = 1.0/7.0;
	height= 1.0/5.0;

	direction.x = 1.0;
        direction.y = 0.0;
        direction.z = 0.0;
	text_coord.y = 1;
	text_coord.z = 0.0;

	plot = gwin->plist;

	if (plotnum <  5)
	{
	    begin.x = 5 - plotnum - 0.75;
	    num_col = 4;
	}
	else if ( (plotnum == 6)  || (plotnum == 9) || 
		  (plotnum == 12) || (plotnum == 15) ) 
	{
	    begin.x = 1.25;
	    num_col = 3;
	}
	else 
	{
	    begin.x = 0.25;
	    num_col = 4;
	}

	if (plotnum <= 8)
	    begin.y = 1.0;
	else if (plotnum <=12)
	    begin.y = 1.3;
	else if (plotnum <=16)
	    begin.y = 1.6;
	else if (plotnum <=20)
	    begin.y = 1.9;
	
	    
	text_coord.x = begin.x;
	text_coord.y = begin.y;

	while (plot != NULL)
	{
	   if (plot->active == true)
	   {
	      count++;
	      endpts[0].x = text_coord.x;
	      endpts[0].y = text_coord.y;
	      endpts[1].x = endpts[0].x + 0.6;
	      endpts[1].y = text_coord.y;
	      if ((plot->plot_type == PLOT_POLYMARKER) || 
		  (plot->plot_type == PLOT_SCATTER))
	      {
		  endpts[2].x = text_coord.x + 0.3;  
		  endpts[2].y = endpts[0].y;
                  if (xp_device != xpX11)
                      X3D_set_line_width(gwin->id, Medium);
	          X2D_draw_polymarker (gwin->id, endpts, 3, plot->marker,
			&Colors[plot->colorindex]);
	      }
	      else if (plot->plot_type == PLOT_LINEMARKER)
	      {
		  endpts[2].x = text_coord.x + 0.3;  
		  endpts[2].y = endpts[0].y;
                  if (xp_device != xpX11)
                      X3D_set_line_width(gwin->id, Medium);
	          X2D_draw_linemarker (gwin->id, endpts, 3, plot->marker,
			&Colors[plot->colorindex]);
	      }
	      else
	      {
		  if (plot->line_type != Solid)
		  {
                     if (xp_device != xpX11)
		         X3D_set_line_type(gwin->id, plot->line_type);
		  }
                  if (xp_device != xpX11)
                      X3D_set_line_width(gwin->id, Medium);
	          X2D_draw_line(gwin->id, endpts[0], endpts[1],
			&Colors[plot->colorindex]);
		  X3D_set_line_type(gwin->id, Solid);
	      }

	      text_coord.x = endpts[1].x + 0.3;

	      colorindex = gwin_attr->current_colors[LEGEND_COLOR];

              if (xp_device != xpX11)
                  X3D_set_line_width(gwin->id, Fine);
	      X2D_draw_text(gwin->id, text_coord, direction, width, height,
                            plot->legend_str, xvf_strlen(plot->legend_str),
			    &Colors[colorindex]);

	      new_line = count % num_col;
	      if (new_line == 0)
	      {
	           text_coord.x = begin.x;
		   text_coord.y = text_coord.y - 0.3;
	      }
	      else 
	      {
		   if (num_col == 4)
		      text_coord.x = endpts[1].x + 1.85;
		   else 
		      text_coord.x = endpts[1].x + 2.0;
	      }
	   }
	   plot = plot->next;
	}


	if (PLOT_TYPE_2D(plot_type))
	{
	   X2D_set_viewport(gwin->id, 0.2, 0.8, 0.3, 0.9);
	   X2D_set_wc_min_max(gwin->id, gwin_attr->disp_scale_min, 
                              gwin_attr->disp_scale_max);
	   X3D_set_text(gwin->id, CenterJustify, 0.4, 0.7);
	}
	else
	{
	   X3D_set_viewport(gwin->id, 0.2, 0.9, 0.2, 0.9, 0.2, 0.9);
	   X3D_set_wc_min_max(gwin->id, gwin_attr->disp_scale_min, 
                                        gwin_attr->disp_scale_max);
	   X3D_set_text(gwin->id, CenterJustify, 0.4, 0.6);
	}
}



/************************************************************
*
*  MODULE NAME: set_text_params_2D
*
*      PURPOSE: Sets text parameters for 2D text to eliminate
*		repetition of code
*
*       OUTPUT: returns set text parameters
*
*    CALLED BY: Draw_Axis_2D , Draw_Axis_3D, write_label
*
*   WRITTEN BY: Danielle Argiro
*
*
*************************************************************/


set_text_params_2D(WCmax, WCmin, direction, text_coord, 
		      width, height, label_flag)
Coord  WCmax, WCmin;
Vector *direction;
Coord  *text_coord;
float  *width, *height;
int    label_flag;
{

      float text_dist;

      /* width & height of all 2D text */

      *width = (WCmax.x - WCmin.x)/30; 
      *height = (WCmax.y - WCmin.y)/30;  

      switch (label_flag)
      {

	case TITLE:

      	     text_dist = (WCmax.y - WCmin.y) /30.0;
             direction->x = WCmax.x - WCmin.x;
             direction->y = 0.0;
             direction->z = 0.0;

             text_coord->x = (WCmax.x - WCmin.x)/2.0 + WCmin.x;
             text_coord->y = WCmax.y + 2*text_dist;
             text_coord->z = 0.0;

	     break;

	case XAXIS:

 	     text_dist = (WCmax.y - WCmin.y)/30.0;
	     direction->x = WCmax.x - WCmin.x;
	     direction->y = 0.0;
	
	     text_coord->x = (WCmax.x - WCmin.x)/2.0 + WCmin.x;
	     text_coord->y = WCmin.y - 3*text_dist;

	     break;


	case YAXIS:

	     text_dist = (WCmax.x - WCmin.x)/30.0;
	     direction->x = 0.0;
	     direction->y = WCmax.y - WCmin.y;

	     text_coord->x = WCmin.x - 3*text_dist;
     	     text_coord->y = (WCmax.y - WCmin.y)/2.0 + WCmin.y;

	     break;

	}  /* end switch */

} /* end set_text_params_2D */



/************************************************************
*
*  MODULE NAME: set_text_params_3D
*
*      PURPOSE: Sets text parameters for 3D text to eliminate
*		repetition of code
*
*       OUTPUT: returns set text parameters
*
*    CALLED BY: Draw_Axis_3D , write_label
*
*   WRITTEN BY: Danielle Argiro
*
*
*************************************************************/


int set_text_params_3D(id, WCmax, WCmin, direction, text_coord, width, height,
		       depth, label_flag)
int    id;
Coord  WCmax, WCmin;
Vector *direction;
Coord  *text_coord;
float  *width, *height, *depth;
int    label_flag;
{

	Coord ndc_max, ndc_min;
        float text_distx, text_disty, text_distz;
	int X3D_convert_point_wc_to_ndc();

        *width = (WCmax.x - WCmin.x)/25; 
        *height = (WCmax.z - WCmin.z)/25;  
        *depth = (WCmax.y - WCmin.y)/25;  

  	text_distx = (WCmax.x - WCmin.x)/20.0;
  	text_disty = (WCmax.y - WCmin.y)/20.0;
        text_distz = (WCmax.z - WCmin.z)/20.0;

	if(!(X3D_convert_point_wc_to_ndc (id, WCmax, &ndc_max)))
	   return(FALSE);

	if(!(X3D_convert_point_wc_to_ndc (id, WCmin, &ndc_min)))
	   return(FALSE);

	switch (label_flag)
	{
	    case XAXIS :
	         if (ndc_max.x < ndc_min.x)
                    direction->x = WCmin.x - WCmax.x;
	         else
                    direction->x = WCmax.x - WCmin.x; 

                 direction->y = 0.0;
                 direction->z = 0.0;

                 text_coord->x = (WCmax.x - WCmin.x)/2.0 + WCmin.x;
                 text_coord->y = WCmin.y - 3*text_disty;
                 text_coord->z = WCmin.z - 2*text_distz;
		 break;

	/* Y axis title */

	    case YAXIS :
		 if (ndc_max.x < ndc_min.x)
           	    direction->y = WCmin.y - WCmax.y;
		 else
           	    direction->y = WCmax.y - WCmin.y; 

        	 direction->x = 0.0;
        	 direction->z = 0.0;

        	 text_coord->x = WCmax.x + (3.0 * text_distx);
        	 text_coord->y = (WCmax.y - WCmin.y)/2.0 + WCmin.y;
        	 text_coord->z = WCmin.z - (2.0 * text_distz);
		 break;

	    case ZAXIS :
		 if (ndc_max.x < ndc_min.x)
           	    direction->z = WCmin.z - WCmax.z;
		 else
           	    direction->z = WCmax.z - WCmin.z; 
 
         	 direction->x = 0.0;
        	 direction->y = 0.0;

        	 text_coord->x = WCmin.x - (2.5 * text_distx);
        	 text_coord->y = WCmin.y - (2.5 * text_disty);
        	 text_coord->z = (WCmax.z - WCmin.z)/2.0 + WCmin.z;
		 break;

	    }
	return(TRUE);

} /* end set_text_params_3D */


/***********************************************************************
*
*  Routine Name: add_power_axis_label
*
*          Date: 06/06/90
*        
*       Purpose:  This routine will append the "power ten"
*                 number to the axis label. At this time the
*		  user can not change this label. If the 
*		  power ten is 0.0 then nothing is appended.
*
*         Input: label - char - the original label
*                power - int -  the exponential power for the axes labels
*
*        Output: a new string with 10e## appended to the axis label.
*
*    Written By: Tom Sauer 
*
* Modifications:
*
***********************************************************************/
char *add_power_axis_label(label, power)
char *label;
int power;
{
    char *new_label;
    char power_str[MaxLength];

    new_label = xvf_strcpy(label);
    if (power != 0)
    {
       sprintf(power_str, " (10e%d)", power);
       new_label = xvf_strcat(new_label, power_str);
    }
    return(new_label);

}


/***************************************************************

	Start or splot routines

	Orig.	J. Salas & M. Conely
***************************************************************/

/***********************************************************************
*
*  Routine Name: set_min_max_step
*
*          Date: May 31, 1985
*        
*       Purpose:  
*            This routine will find the step_size and number_steps
*       for the range specified by maximum and minimum.  It set-up
*       the step to be orders of magnitude of 1, 2, and 5.  This
*       may result in number_steps to have a fractional part.
*
*         Input: minimum, maximum, step_size, number_steps
*
*        Output:  number_steps, step_size, minimum, maximum
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/
set_min_max_step(step_size,number_steps,minimum,maximum) 
float *number_steps;
double *step_size,*minimum,*maximum;

{
  double temp_step_size;
  double power;
  double max_divide,min_divide;
  double ttruncate();

  if((temp_step_size = (*maximum - *minimum)/(*number_steps)) < 1)
    power = pow(10.0,ceil(log10(1.0/temp_step_size)));
  else
    power = pow(1.0/10.0,floor(log10(temp_step_size)));

  *step_size = power * temp_step_size;

  if(*step_size > 0.0 && *step_size <= 1.0)
    *step_size = 1.0;
  else if(*step_size > 1.0 && *step_size <= 2.0)
    *step_size = 2.0;
  else if(*step_size > 2.0 && *step_size <= 5.0)
    *step_size = 5.0;
  else if(*step_size > 5.0 && *step_size <= 10.0)
    *step_size = 10.0;

  *step_size *= 1.0/power;
/*
 * Calls ttruncate to establish a step size that has 2 digit accuracy,
 * so that round-off error is eleminated.
*/
  *step_size = ttruncate(*step_size,2);

  max_divide = ceil(*maximum/(*step_size));
  min_divide = floor(*minimum/(*step_size));

  *maximum = max_divide * *step_size;
  *minimum = min_divide * *step_size;
 /* plus 1 since this is the number of tics not number of steps */

  get_number_steps(*step_size, number_steps, *minimum, *maximum);
}

/***********************************************************************
*
*  Routine Name: ttruncate
*
*          Date: May 31, 1985
*        
*       Purpose:  
*              This routine rounds a number to the number of characters
*               given by char_precision and returns the result.  It does not
*               take into account the existence of a minus sign or decimal
*               point.  (E.g., if x == 345.12573 and char_precision == 6,
*               ttruncate(x) == 345.126.)
*
*         Input: x - double - number to ttruncate
*                char_precision - int - percision to ttruncate to.
*
*        Output:  ttruncated number
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/
double ttruncate(x,char_precision)
int char_precision;
double x;
{
  int numdigs();
  int numdecs();
  int k;
  int shift;

  double fracround();

  if(char_precision < 2 || char_precision > 15) return(XV_MAXFLOAT);

  shift = char_precision + numdecs(x) - 1;

  for (k = 0; k < abs(shift); k++)
  {
    if (shift > 0) x *= 10.0;
    else
      x /= 10.0;
  }

  x = fracround(x);

  for(k = 0; k < abs(shift); k++)
  {
    if(shift > 0.0) x /= 10.0;
    else
      x *= 10.0;
  }

  return(x);
}

/***********************************************************************
*
*  Routine Name: fracround
*
*          Date: May 31, 1985
*        
*       Purpose:  
*             This routine rounds the first significant digit
*             of a fractional number and returns the result.
*             If the number is greater than 1, it is rounded
*             normally.  (E.g., the number 0.002532 will be
*             rounded to 0.003.)
*
*         Input: x - double - number to be rounded
*
*        Output:  rounded number
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/
double fracround(x)
double x;
{
  int i, e;
  short negative;

  negative = FALSE;
  if (x != 0.0)
  {
    if (x < 0.0)
    /* Retain the sign.  */
    {
      negative = TRUE;
      x = -x;
    }
    e = 0;
    while (x < 1.0)
    /* Shift the first significant digit into the ones place.  */
    {
      x = x * 10.0;
      e++;
    }
    /* Round.  */
    x = floor(x +  0.5);
    if (x >= 10.0 && e > 0)
    /*
       If the rounding results in an increase in the number of
       significant digits (e.g., if 9.534 gets rounded to 10.0),
       decrease the shift amount by 1.
    */
    {
      x = 1.0;
      e--;
    }
    /* Shift back to the proper place.  */
    for (i = e; i > 0; i--) x /= 10.0;

    if (negative) x = -x; /* Restore sign if necessary. */
  }
  return(x);
}

/***********************************************************************
*
*  Routine Name: numdecs
*
*          Date: May 31, 1985
*        
*       Purpose:  
*               This routine returns the number of decimals in
*               a fractional number.  If the number is greater than
*               or equal to 1, it returns 0.  If x == 0, the answer
*               is defined to be 1.  (E.g., if x == 0.00341,
*               numdecs(x) == 3.  If x == 3.221, numdecs(x) == 0.)
*
*         Input: x - double - input number
*
*        Output: number of decimal places 
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/
int numdecs(x)
double x;
{
  int e;

  if(x == 0) return(1);
  x = fabs(x);
  e = 0;
  while (x < 1)
  {
    x *= 10.0;
    e++;
  }
  return(e);
}

/***********************************************************************
*
*  Routine Name: step_size_linear
*
*          Date: May 31, 1985
*        
*       Purpose:  
*          This routine will calculate the maximum, minimum, and
*          number_steps for a specified step_size for the range passed
*          in maximum and minimum.  The new maximum and minimum are
*          set such that when divided by the step_size the result will
*          be an integer value.
*          NOTE: Some range must be specified by maximum and minimum.
*
*
*         Input: minimum, maximum
*
*        Output:  number_steps, step_size
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/
step_size_linear(step_size,number_steps,minimum,maximum)

float *number_steps;
double step_size,*minimum,*maximum;

{
  double divisible;
  double ceil();
  double floor();

  /* kludge kludge */
  if(step_size <= 0.0) step_size = 1.0;

  divisible = floor(*minimum/step_size);
  *minimum = step_size * divisible;

  divisible = ceil(*maximum/step_size);
  *maximum = step_size * divisible;

  get_number_steps(step_size, number_steps, *minimum, *maximum);
}

/***********************************************************************
*
*  Routine Name: find_decimal_places
*
*          Date: May 31, 1985
*        
*       Purpose:  
*              This routine finds the largest number of decimal places
*       which fit in the range determined from characters_displayed.
*       The value is found for the three variables maximum, minimum,
*       and step.
*
*
*         Input: minimum, maximum, characters_displayed, step
*
*        Output:  decimal_places
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/

find_decimal_places(characters_displayed,maximum,minimum,step,decimal_places)
int characters_displayed,*decimal_places;
double maximum,minimum,step;
{
  int j;
  int integer_places;
  int temp_integer_places;

  double abs_temp_min,abs_temp_max,abs_temp_step;
  double temp_value_int;
  double power;
  double remainder_min,remainder_max,remainder_step;
  double temp_value;
/*
   The following calculates the integer part of the numbers to
   be displayed.  If the integer part is zero it must be ignored,
   therefore it is set to 1.
*/
  if(fabs(maximum) > 1.0)
    integer_places = (int) floor(fabs(log10(fabs(maximum)))) + 1;
  else
    integer_places = 1;

  if(fabs(minimum) > 1.0)
    temp_integer_places = (int) floor(fabs(log10(fabs(minimum)))) + 1;
  else
    temp_integer_places = 1;

  if(integer_places < temp_integer_places)
    integer_places = temp_integer_places;

  power = characters_displayed - integer_places;

  abs_temp_min = (double) floor(fabs(minimum) + pow(1.0/10.0,power));
  abs_temp_max = (double) floor(fabs(maximum) + pow(1.0/10.0,power));
  abs_temp_step = (double) floor(fabs(step) + pow(1.0/10.0,power));

  remainder_min = fabs(fabs(minimum) - abs_temp_min);
  if(remainder_min < pow(1.0/10.0,power)) remainder_min = 1.0;

  remainder_max = fabs(fabs(maximum) - abs_temp_max);
  if(remainder_max < pow(1.0/10.0,power)) remainder_max = 1.0;

  remainder_step = fabs(fabs(step) - abs_temp_step);
  if(remainder_step < pow(1.0/10.0,power)) remainder_step = 1.0;
/*
   The loops uses the remainder values from above to find the decimalplaces
   to which the number is displayed.
*/
  *decimal_places = 0;

  for(j = 0;j <= (characters_displayed - integer_places);j++)
  {
    temp_value = pow(10.0,(double)j) * remainder_min;
    temp_value_int = (double) floor(temp_value + pow(1.0/10.0,power));
    power = characters_displayed - integer_places - j;
    if(fabs(temp_value - temp_value_int) >= 1.0) break;
    if(fabs(temp_value - temp_value_int) < pow(1.0/10.0,power)) break;
  }

  if(*decimal_places < j) *decimal_places = j;

  for(j = 0;j <= (characters_displayed - integer_places);j++)
  {
    temp_value = pow(10.0,(double)j) * remainder_max;
    temp_value_int = (double) floor(temp_value + pow(1.0/10.0,power));
    power = characters_displayed - integer_places - j;
    if(fabs(temp_value - temp_value_int) >= 1.0) break;
    if(fabs(temp_value - temp_value_int) < pow(1.0/10.0,power)) break;
  }

  if(*decimal_places < j) *decimal_places = j;

  for(j = 0;j <= (characters_displayed - integer_places);j++)
  {
    temp_value = pow(10.0,(double)j) * remainder_step;
    temp_value_int = (double) floor(temp_value + pow(1.0/10.0,power));
    power = characters_displayed - integer_places - j;
    if(fabs(temp_value - temp_value_int) >= 1.0) break;
    if(fabs(temp_value - temp_value_int) < pow(1.0/10.0,power)) break;
  }

  if(*decimal_places < j) *decimal_places = j;
}


/***********************************************************************
*
*  Routine Name: numdigs
*
*          Date: August 8, 1985
*        
*       Purpose:  
*           This routine computes and returns the number of decimals in a
*           fractional number or the number of integer digits in a number 
*           greater than or equal to 1.  The value for 0 is defined to be
*           1.  (E.g., if x == 0.0032232, numdigs(x) == 7.  If x == 323.23023, 
*           numdigs(x) == 3.)  if numdigs(x) > 100 return 100
*
*         Input: x
*
*        Output: as explained above 
*
*    Written By:  Mike Conley
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/
int numdigs(x)
double x;
{
  int e;

  if(x == 0.0) return(1);
  x = fabs(x);
  e = 0;
  if (x < 1)
  {
    while (x < 1.0 && x != 0.0 && e<100)
    {
      x *= 10.0;
      x = x - (int)x;	/* subtract off int portion and keep shifting */
      e++;
    }
  }
  else
  {
    while (x >= 1.0 && e<100)
    {
      x /= 10.0;
      e++;
    }
  }
  return(e);
}



/***********************************************************************
*
*  Routine Name: set_step
*
*          Date: May 31, 1985
*        
*       Purpose:  
*            This routine will find the step_size and number_steps
*       for the range specified by maximum and minimum.  It set-up
*       the step to be orders of magnitude of 1, 2, and 5.  This
*       may result in number_steps to have a fractional part.
*
*
*         Input: minimum, maximum
*
*        Output:  number_steps, step_size
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/

set_step(step_size,number_steps,minimum,maximum)
float *number_steps;
double *step_size,minimum,maximum;

{
  double temp_step_size;
  double ttruncate();
  double power;


  if((temp_step_size = (maximum - minimum)/(*number_steps)) < 1)
  {
    power = pow(10.0,ceil(log10(1.0/(temp_step_size))));
  }
  else
  {
    power = pow(1.0/10.0,floor(log10(temp_step_size)));
  }

  *step_size = power * (maximum - minimum)/(*number_steps);

  if(*step_size > 0.0 && *step_size <= 1.0)
  {
    *step_size = 1.0;
  }
  else if(*step_size > 1.0 && *step_size <= 2.0)
  {
    *step_size = 2.0;
  }
  else if(*step_size > 2.0 && *step_size <= 5.0)
  {
    *step_size = 5.0;
  }
  else if(*step_size > 5.0 && *step_size <= 10.0)
  {
    *step_size = 10.0;
  }

  *step_size *= 1.0/power;
/*
 * Calls ttruncate to establish a step size that has 2 digit accuracy,
 * so that round-off error is eleminated.
*/
  *step_size = ttruncate(*step_size,2);
  get_number_steps(*step_size, number_steps, minimum, maximum);

}

/***********************************************************************
*
*  Routine Name: get_number_steps
*
*          Date: 4/90
*        
*       Purpose: determines the number of major intervals given
*                the min, max and interval size. 
*
*         Input: minimum - plot minimum
*		 maximum - plot maximum
*		 step_size - the interval size
*
*        Output: number_steps - number of major intervals
*
*    Written By: Tom Sauer & Mike Lang 
*
* Modifications: 05/29/90 - added 0.5 to round up.
*
***********************************************************************/

get_number_steps(step_size,number_steps,minimum,maximum)
double step_size, maximum, minimum;
float *number_steps;
{
        float num_steps = 0.0;

	while ( (step_size * (num_steps + 1.0)) + minimum < maximum)
            num_steps++;
        *number_steps = num_steps + 1; /* the +1 is for the minimum */
/*
	*number_steps = (maximum -minimum)/step_size;
*/

}



/***********************************************************************
*
*  Routine Name: find_scale_factor
*
*          Date: May 31, 1985
*        
*       Purpose:  
*            This routine will set a scale factor if needed and 
*            call parse_scale_factor() to attach it to the end of the
*            appropriate axis label.  If will also find the number of
*            significant decimal places for the numerical labels.
*
*         Input: minimum, maximum, characters_displayed, step_size
*
*        Output:  multiplier, power_ten, decimal_places
*
*    Written By:  John M. Salas
*
* Modifications: original code from splot written by John M. Salas
*
***********************************************************************/
find_scale_factor(characters_displayed, maximum,minimum,step_size,
                   decimal_places, multiplier,power_ten)

int characters_displayed,*decimal_places,*power_ten;
double maximum,minimum,step_size,*multiplier;

{

  double power_fraction,power_integer;
  double lower_limit;
  double upper_limit;

    *power_ten = 0;

    if (fabs(minimum) == 0.0)
       lower_limit = 1.0;
    else
       lower_limit = minimum;

    if (fabs(maximum) == 0.0)
       upper_limit = 1.0;
    else
       upper_limit = maximum;

    if((power_fraction = characters_displayed - 2) > 6.0)
      power_fraction = 6.0;

    power_integer = characters_displayed - 2;

    if((fabs(upper_limit) < pow(10.0,power_integer) &&
       fabs(upper_limit) > pow(0.1,power_fraction)) &&
       (fabs(lower_limit) < pow(10.0,power_integer) &&
       fabs(lower_limit) > pow(0.1,power_fraction)))
    {
      *multiplier = 1.0;
    }
    else
    {
      if(fabs(maximum) < pow(0.1,power_fraction) ||
	 fabs(minimum) < pow(0.1,power_fraction))
      {
	if(maximum == 0.0)
	{
	  *power_ten = (int) floor(log10(1.0/fabs(minimum)));
	}
	else
	{
	  *power_ten = (int) floor(log10(1.0/fabs(maximum)));
	}
	*multiplier = pow(10.0,(double) (*power_ten));
	*power_ten = -*power_ten;
      }
      else
      {
	*power_ten = (int) floor(log10(fabs(maximum)));
	if(*power_ten < ((int) floor(log10(fabs(minimum)))))
	*power_ten = (int) floor(log10(fabs(minimum)));
	*multiplier = pow(0.1,(double) (*power_ten));
      }
    }
/*
   Finds out the decimal places in the label.
*/
  maximum = *multiplier * maximum;
  minimum = *multiplier * minimum;
  step_size = *multiplier * step_size;
  find_decimal_places(characters_displayed,maximum,minimum,step_size,
		      decimal_places);
}
/***************************************************************
	End of splot routines
****************************************************************/
