 /*
  * Khoros: $Id: plot_util.c,v 1.5 1992/03/20 22:46:01 dkhoros Exp $
  */

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

 /*
  * $Log: plot_util.c,v $
 * Revision 1.5  1992/03/20  22:46:01  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.
 *----------------------------------------------------------------------
 */

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


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: plot_util.c
   >>>>               
   >>>>   description: utility routines for getting a plot ready
   >>>>			to draw.
   >>>>              
   >>>>      routines:
   >>>>			plot_routine()
   >>>>			abort_plot()
   >>>>			rotate_2D()
   >>>>			scale_2D()
   >>>>			translate_2D()
   >>>>			rotate_3D()
   >>>>			scale_3D()
   >>>>			translate_3D()
   >>>>			display_data_sampling()
   >>>>              
   >>>> modifications:
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

jmp_buf	jump_dest;



/************************************************************
*
*  MODULE NAME: plot_routine
*
*      PURPOSE: driver to call the appropriate plotting routines.
*
*       OUTPUT: plot displays
*
*    CALLED BY: xprism routines
*
*   WRITTEN BY: Danielle Argiro  & Mark Young
*
*
*************************************************************/


plot_routine()
{
	XPlot	  *plot;
	Coord	  *data_points;
	int	  size, row_size;
	int	  X3D_inquire_device();
	vsignal	  abort_plot(), (*istate)(), (*qstate)();


	/*
	 *  If no graphics workspace exists return
	 */
	if (gwin == NULL)
	   return;


	/*
	 *  Set up jump destination so that while plotting or printing
	 *  the user can abort plotting by hitting control C in the
	 *  start up window.  (at least it's something).
	 *
	 *  Set the jump

Commented out since this does not work right.  Sat Sep  1 11:35:57 MDT 1990

	if (setjmp(jump_dest) == 0)
	{
	   istate = signal(SIGINT,  abort_plot);
	   qstate = signal(SIGQUIT, abort_plot);
	}
	else
	{
	   signal(SIGINT,  istate);
	   signal(SIGQUIT, qstate);

	   XFlush(display);
	   return;
	}
	 */


	X3D_raise_window(gwin->id);
	X3D_clear_window(gwin->id);

	if (PLOT_TYPE_2D(gwin->plot_type))
           draw_axis_xp2(gwin->plot_type,TRUE);
	else
           draw_axis_xp3(gwin->plot_type,TRUE);


	plot = gwin->plist;

	/*
	 *  Draw the plot grid BEFORE the plots for THREE D
	 */
	if (gwin_attr->draw_grid && PLOT_TYPE_3D(gwin->plot_type))
	    draw_grid_3D();

	if (gwin_attr->draw_box && PLOT_TYPE_3D(gwin->plot_type))
	    draw_box_3D();

	while (plot != NULL)  /* for each plot in the workspace */
        {
	   if (plot->active == TRUE)
	   {
	      /* if line type is not solid, set to correct dash type */
	      if (plot->line_type != Solid)
		 X3D_set_line_type(gwin->id, plot->line_type);
	      else
		 X3D_set_line_type(gwin->id, Solid);

              if (xp_device != xpX11)
	          X3D_set_line_width(gwin->id, MediumFine);
	      /* check if we need to turn on clipping */
	      if(plot->WCmin.x <  gwin_attr->disp_scale_min.x || 
		 plot->WCmax.x > gwin_attr->disp_scale_max.x  || 
		 plot->WCmin.y <  gwin_attr->disp_scale_min.y || 
		 plot->WCmax.y > gwin_attr->disp_scale_max.y)
	      {
		X2D_set_clipping(gwin->id, 1);
	      }
	      else
		X2D_set_clipping(gwin->id, 0);

	      
	      display_data_sampling(plot,&data_points,&size,&row_size);

	      XFlush(display);
	      switch (plot->plot_type)
	      {
		   case PLOT_2D:         
                        X2D_draw_polyline(gwin->id, data_points, 
					  size, &Colors[plot->colorindex]);
		        break;

      		   case PLOT_DISCRETE:   
			X2D_draw_discrete(gwin->id, data_points, 
					  size, &Colors[plot->colorindex]);
		        break;

      		   case PLOT_HISTOGRAM:  
			X2D_draw_bargraph(gwin->id, data_points, 
					  size, &Colors[plot->colorindex]);
		        break;

      		   case PLOT_POLYMARKER: 
			X2D_draw_polymarker(gwin->id, data_points, size,
			    		plot->marker, &Colors[plot->colorindex]);
		        break;

      		   case PLOT_LINEMARKER: 
			X2D_draw_linemarker(gwin->id, data_points, size,
		   	    		plot->marker, &Colors[plot->colorindex]);
		        break;

	           case PLOT_3D:
			X3D_draw_lineplot(gwin->id, data_points,row_size, 
					  size, &Colors[plot->colorindex]);
		   	break;

	      	   case PLOT_MESH:
			X3D_draw_mesh(gwin->id, data_points,row_size, size,
				      &Colors[plot->colorindex], &bg);
		        break;

	      	   case PLOT_IMPULSE:
			X3D_draw_impulse(gwin->id, data_points, size,
					 &Colors[plot->colorindex]);
		        break;

	      	   case PLOT_CONTOUR_2D:
			X3D_draw_contour(gwin->id, data_points, row_size,
			                 size, plot->levels, contour_colors,
			                 plot->contour_num, TRUE);
			break;

	      	   case PLOT_CONTOUR_3D:
			X3D_draw_contour(gwin->id, data_points, row_size,
			                 size, plot->levels, contour_colors,
			                 plot->contour_num, FALSE);
		        break;  

	      	   case PLOT_SCATTER:
			X3D_draw_polymarker(gwin->id, data_points, 
					    size, plot->marker, 
					    &Colors[plot->colorindex]);
		        break;

	      	   case PLOT_HORIZON:
			X3D_draw_horizon(gwin->id, data_points, row_size,
			    		 size, &Colors[plot->colorindex], &bg, 
					 plot->WCmin, plot->WCmax);
		        break;

	      	   case PLOT_SURFACE:
			X3D_draw_surface(gwin->id, data_points, row_size,
			                 size, plot->levels, contour_colors,
			                 plot->contour_num, plot->WCmin, 
					 plot->WCmax, FALSE, TRUE);
		        break;

	      	   case PLOT_COLORMESH:
			X3D_draw_colormesh(gwin->id, data_points,
			    		   row_size, size, plot->levels,
			                   contour_colors, plot->contour_num, 
					   &bg, plot->WCmin, plot->WCmax);
		        break;
	      }
	      if(data_points != plot->points)
		free(data_points);
	   }
	   plot = plot->next;
	   X2D_set_clipping(gwin->id, 0);
	}

	X3D_set_line_type(gwin->id, Solid);
        if (xp_device != xpX11)
	    X3D_set_line_width(gwin->id, MediumFine);

	/*
	 *  Draw the unobscured part of the three dimensionals axis.
	 */
	if (PLOT_TYPE_3D(gwin->plot_type))
	   draw_axis_xp3(gwin->plot_type, FALSE);  

	/*
	 *  Draw the plot grid and axes box AFTER the plots for TWO D
	 */
	if(gwin_attr->draw_grid && PLOT_TYPE_2D(gwin->plot_type))
	   draw_grid_2D();

	if(gwin_attr->draw_box && PLOT_TYPE_2D(gwin->plot_type))
	   draw_box_2D();

	if (gwin_attr->draw_legend)
	   draw_legend(gwin->plot_type);

	if(obj_list != NULL)
	   redraw_overlays(canvas, obj_list);

	XFlush(display);
	save_window();

/*

Commented out since this does not work right.  Sat Sep  1 11:35:57 MDT 1990

	signal(SIGINT,  istate);
	signal(SIGQUIT, qstate);
 */
}



/************************************************************
*
*  MODULE NAME: abort_plot
*
*      PURPOSE: If we get interrupted while plotting then we
*		prompt the user to see if they wish to abort
*		plotting or printing.  If they wish to abort
*		we long jump back where we will return, otherwise
*		we continue.
*
*        INPUT:  1.  sig --  the signal number
*                2.  flag -- type of trap error
*                3.  context -- a pointer to the signal context
*
*       OUTPUT:
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
***********************************************************/


vsignal  abort_plot(sig, flags, context)

int     sig, flags;
struct  sigcontext *context;
{
	int  status;
	char *label = "Xprism interrupted.  Do you wish to abort the current \
process and return to the main menu?";


	XUngrabServer(display);
	status = xvf_exit_wait(label, "Abort", NULL, NULL, NULL);
	if (status == 1)
	{
	   /*
	    *  Abort current plotting or printting
	    */
	    longjmp(jump_dest, 1);
	}
	else
	{
	   return;
	}
}




/************************************************************
*
*  MODULE NAME: rotate_2D
*
*      PURPOSE: Rotates the 2D plot(s) in the specified VPGraphicsWindow
*               structure -- prompts user for degree of rotation
*               Note: rotation is about the origin
*
*        INPUT: 
*
*       OUTPUT:
*                       with all plots in the "plist" now having their
*                       x and y arrays rotated
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young and Danielle Argiro
*
***********************************************************/


rotate_2D (rotation_degree, plot)

float	rotation_degree; 
XPlot *plot;
{
	Coord  center;

	/* 
	 * find the center of the object and prompt to see if that is
	 * the point to be rotated about 
  	 */
	center.x = ((gwin_attr->disp_scale_max.x - gwin_attr->disp_scale_min.x)/2.0 + gwin_attr->disp_scale_min.x);
	center.y = ((gwin_attr->disp_scale_max.y - gwin_attr->disp_scale_min.y)/2.0 + gwin_attr->disp_scale_min.y);

        /* 
	 *  we begin at the head of the "plist" (plot list)  
	 */
         X2D_rotate_coords (rotation_degree, center, plot->points, 
			 	      plot->size);
        find_min_max (plot, gwin->plot_type);
} /* end rotate_2D */





/************************************************************
*
*  MODULE NAME: scale_2D
*
*      PURPOSE: Scales the 2D plot(s) in the specified VPGraphicsWindow
*               structure -- prompts user for the x and y scale factors.
*
*        INPUT: gwin -- pointer to the current VPGraphicsWindow structure
*
*       OUTPUT: gwin -- pointer to the current VPGraphicsWindow structure
*                       with all plots in the "plist" now having their
*                       x and y arrays scaled
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young and Danielle Argiro
*
***********************************************************/

scale_2D (xscale, yscale, plot)

float  xscale, yscale;
XPlot *plot;
{
	X2D_scale_coords (xscale, yscale, plot->points, plot->size);
	find_min_max (plot, gwin->plot_type);

} /* end scale_2D */




/************************************************************
*
*  MODULE NAME: translate_2D
*
*      PURPOSE: Translates the 2D plot(s) in the specified VPGraphicsWindow
*               structure -- prompts user for distance of translation
*               Note: for all intensive purposes, this simply changes 
*                     the axes on x, y, and z 
*
*        INPUT:
*
*       OUTPUT:
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young and Danielle Argiro
*
***************************************************************/

translate_2D (xtrans, ytrans, plot)

float  xtrans, ytrans;
XPlot *plot;
{

      X2D_translate_coords (xtrans, ytrans, plot->points, plot->size);
      find_min_max (plot, gwin->plot_type);

}  /* end translate_2D  */



/******************************************************************
*                                                                  
*                                                                  
*     >>>>>>>> XPrism 3D
*              Rotation, Scaling, and Translation Routines <<<<<<<<
*                                                                  
*                                                                  
********************************************************************/


/************************************************************
*
*  MODULE NAME: rotate_3D
*
*      PURPOSE: Rotates the 3D plot(s) in the specified VPGraphicsWindow
*               structure -- prompts user for degree of rotation
*               and the rotation axis (which axis the plot(s) are to
*               be rotated about.
*
*        INPUT:
*
*       OUTPUT:
*
*    CALLED BY: Drv_3D,
*               Drv_Mesh, &
*               Drv_Points
*
*   WRITTEN BY: Mark Young and Danielle Argiro
*
*
*************************************************************/

rotate_3D (xrotate, yrotate, zrotate, plot)

float  xrotate, yrotate, zrotate;
XPlot *plot;
{
	double atof();
	Coord  center;
        char   *prompt[MaxPrompt], *answers[MaxPrompt];
	int    i;

        /* init prompt & answers arrays of strings */
        for (i = 0; i < MaxPrompt; i++)
        {
            prompt[i] = NULL;
            answers[i] = NULL;
        }

        /* malloc and init answers array for prompt form */
        for (i = 0; i < 3; i++)
        {
            answers[i] = (char *) malloc (MaxRespLength* sizeof(char));
            bzero(answers[i], MaxRespLength);
            prompt[i]  = (char *) malloc (MaxPromptLength* sizeof(char));
            bzero(prompt[i], MaxPromptLength);
        }


	/* 
	 *  find the center of the object and prompt to see if that is
	 *  the point to be rotated about 
  	 */
	center.x = ((gwin_attr->disp_scale_max.x - 
		     gwin_attr->disp_scale_min.x)/2.0 + 
		     gwin_attr->disp_scale_min.x);
	center.y = ((gwin_attr->disp_scale_max.y - 
		     gwin_attr->disp_scale_min.y)/2.0 + 
		     gwin_attr->disp_scale_min.y);
	center.z = ((gwin_attr->disp_scale_max.z - 
		     gwin_attr->disp_scale_min.z)/2.0 + 
		     gwin_attr->disp_scale_min.z);

       
   
        /* the prompt to be used on prompt form */
        prompt[0] = xvf_strcpy("Rotate about the center of the object (y/n)?");

        /* call up prompt form to ask if they want to rotate about center */
	sprintf(answers[0],"n");
        xvf_query_wait(NULL, prompt, "Ok", answers, 1, MaxRespLength);

	/*
	 *  if they don't want to rotate about the center, prompt for the
	 *  point of rotation
	 */
        if ((*answers[0] == 'n') || (*answers[0] == 'N'))
	{
	   /* tell them what the center of the object is */
	   bzero(answers[0], MaxRespLength);
	   bzero(answers[1], MaxRespLength);
	   bzero(answers[2], MaxRespLength);
	   sprintf(answers[0],"0.0");
	   sprintf(answers[1],"0.0");
	   sprintf(answers[2],"0.0");
	   prompt[0] = xvf_strcpy("Enter the x coordinate of rotation point: ");
	   prompt[1] = xvf_strcpy("Enter the y coordinate of rotation point: ");
	   prompt[2] = xvf_strcpy("Enter the z coordinate of rotation point: ");

           /* call the prompt form to get the rotation point */
           xvf_query_wait(NULL, prompt, "Enter", answers, 
				 3, MaxRespLength);

           /* set the rotation point according to answers string array 
	      returned by the prompt form */ 
	   center.x = atof(answers[0]);
	   center.y = atof(answers[1]);
	   center.z = atof(answers[2]);
	}

        X3D_rotate_coords (xrotate, yrotate, zrotate, center, plot->points, 
			          plot->size);
       find_min_max (plot, gwin->plot_type);

} /* end rotate_3D */





/************************************************************
*
*  MODULE NAME: scale_3D
*
*      PURPOSE: Scales the 3D plot(s) in the specified VPGraphicsWindow
*               structure -- prompts user for x, y, and z scale factors.
*
*        INPUT:
*
*       OUTPUT: the gwin structure, with all plots in the "plist", 
*		now having their x, y and z arrays scaled
*
*    CALLED BY: Drv_3D,
*               Drv_Mesh,
*               Drv_Points
*
*   WRITTEN BY: Mark Young and Danielle Argiro
*
*
*************************************************************/

scale_3D (xscale, yscale, zscale, plot)

float  xscale, yscale, zscale; 
XPlot *plot;
{

      X3D_scale_coords (xscale, yscale, zscale, plot->points, plot->size);
      find_min_max (plot, gwin->plot_type);

} /* end scale_3D */





/************************************************************
*
*  MODULE NAME: translate_3D
*
*      PURPOSE: Translates the 3D plot(s) in the specified VPGraphicsWindow
*               structure -- prompts user for distance of translation
*               Note: for all intensive purposes, this simply changes 
*                     the plot axes
*
*        INPUT:
*
*       OUTPUT: gwin -- pointer to gwin, with all plots in the "plist" 
*			now having their x and y arrays translated
*
*    CALLED BY: Drv_3D,
*               Drv_Mesh,
*               Drv_Points
*
*   WRITTEN BY: Mark Young and Danielle Argiro
*
**************************************************************/

translate_3D (xtrans, ytrans, ztrans, plot)

float  xtrans, ytrans, ztrans; 
XPlot *plot;
{

       X3D_translate_coords (xtrans, ytrans, ztrans, plot->points, 
				     plot->size);
       find_min_max (plot, gwin->plot_type);

} /* end translate_3D  */



/************************************************************
*
*  MODULE NAME: display_data_sampling
*
*      PURPOSE: To sample display data
*
*        INPUT: plot--  Pointer to current plot
*
*       OUTPUT: NONE
*
*    CALLED BY: plot_routine
*
*   WRITTEN BY: mike&mohead
*
**************************************************************/
display_data_sampling(plot,new_coords,size,row_size)
XPlot	*plot;
Coord	**new_coords;
int	*size, *row_size;

{
	Coord	*tmp_coords;
	int	j,i, k, m, nc, nr;
	int   end, begin;
	int   end_x, begin_x, end_y, begin_y;
	double	tmp_row_size;

	if(PLOT_TYPE_2D(gwin->plot_type))
	{

	   if(plot->begin_point.x == 0.0 && plot->step_size.x == 1.0)
	   {
		*new_coords=plot->points;	
		*size=plot->size;	
		*row_size=plot->row_size;	
		return;
	   }
	   else
	   {
		begin = plot->begin_point.x;
                if (plot->begin_point.x == 0.0) 
		{
		   begin = 1;
		   end = plot->size;
		}
		else
		{
		   if(plot->end_point.x == 0.0 ) 
		      end = plot->size;
		   else
		      end = (int)plot->end_point.x;
	        }

		*size = (end - begin)/ ((int) plot->step_size.x) + 1;

		if((tmp_coords =(Coord *)malloc(sizeof(Coord)*(*size))) == NULL)
		{
		   xvf_error_wait(
		   "Out of Memory, Displaying all data points with a step size of 1",
		    "display_data_sampling", NULL);
		   *new_coords=plot->points;	
		   *size=plot->size;	
		   *row_size=plot->row_size;	
		   return;
		}
			
		j = 0;
		for (i = (begin - 1); i < end; i += (int)plot->step_size.x)
		{
			tmp_coords[j].x = plot->points[i].x;
			tmp_coords[j++].y = plot->points[i].y;
		}
		*new_coords = tmp_coords;
		*row_size=plot->row_size; /* don't care for 2D */
	   }
	}
	else if(PLOT_TYPE_3D(gwin->plot_type))
	{
	   if(plot->begin_point.x == 0.0 && plot->step_size.x == 1.0 &&
	      plot->begin_point.y == 0.0 && plot->step_size.y == 1.0)
	   {
		*new_coords=plot->points;	
		*size=plot->size;	
		*row_size=plot->row_size;	
		return;
	   }
	   else
	   {
	        nc = plot->row_size;
        	nr = plot->size/plot->row_size;
		
		begin_x = (int) plot->begin_point.x;
		begin_y = (int) plot->begin_point.y;

		if(plot->begin_point.x == 0.0)
		{
		    begin_x = 1;
		    end_x = nc;
	        }
		else
		{
		    if(plot->end_point.x == 0.0) 
		       end_x = nc;
		    else
		       end_x = (int) plot->end_point.x;
		}

                if (plot->begin_point.y == 0.0) 
		{
		   begin_y = 1;
		   end_y = nr;
		}
		else
		{
		   if(plot->end_point.y == 0.0) 
		      end_y = nr;
		   else
		      end_y = (int) plot->end_point.y;
		}

		*size = (((end_x-(begin_x))/((int) plot->step_size.x)+1) *
		         ((end_y - (begin_y))/((int) plot->step_size.y)+1));

		if((tmp_coords =(Coord *)malloc(sizeof(Coord)*(*size))) == NULL)
		{
		   xvf_error_wait(
		   "Out of Memory, Displaying all data points with a step size of 1",
		    "display_data_sampling", NULL);
		   *new_coords=plot->points;	
		   *size=plot->size;	
		   *row_size=plot->row_size;	
		   return;
		}
			

		k = 0;
		for (i = (begin_y - 1); i < end_y; i += (int)plot->step_size.y)
	        {
		   for(j = (begin_x - 1); j < end_x;j += (int)plot->step_size.x)
		   {
		        m = i * nc + j;
			tmp_coords[k].x = plot->points[m].x;
			tmp_coords[k].y = plot->points[m].y;
			tmp_coords[k++].z = plot->points[m].z;
		   }
	        }
		*new_coords = tmp_coords;
		tmp_row_size = (double) nc / (double) plot->step_size.x;
		*row_size= (int) (ceil(tmp_row_size));
	   }
	}
}
