 /*
  * Khoros: $Id: PlotObj.c,v 1.3 1992/03/20 22:51:24 dkhoros Exp $
  */

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

 /*
  * $Log: PlotObj.c,v $
 * Revision 1.3  1992/03/20  22:51:24  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 *            Copyright 1990 University of New Mexico
 *  
 *  Permission to use, copy, modify, distribute, and sell this
 *  software and its documentation for any purpose is hereby
 *  granted without fee, provided that the above copyright
 *  notice appear in all copies and that both that copyright
 *  notice and this permission notice appear in supporting docu-
 *  mentation, and that the name of UNM not be used in advertis-
 *  ing or publicity pertaining to distribution of the software
 *  without specific, written prior permission.  UNM makes no
 *  representations about the suitability 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 DAMAGES WHATSOEVER
 *  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 PERFORMANCE
 *  OF THIS SOFTWARE.
 *  
 *----------------------------------------------------------------------
 */

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

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    file name: Plot.c					<<<<
   >>>>								<<<<
   >>>>   description: The object display widget used by the	<<<<
   >>>>		       objectting programs.			<<<<
   >>>>								<<<<
   >>>>      routines:						<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "PlotObjP.h"

#define XoDisplay(obj) (XtDisplay(obj->object.parent))
#define XoWindow(obj)  (XtWindow(obj->object.parent))

static void	Initialize();
static void	Redisplay();
static void	Destroy();
static void	FindMinMax();
static void	SubSample();
static void	ClassInitialize();
static void	ClassPartInitialize();

static Boolean	SetValues();


/************************************************
*
*   Full class record constant
*
************************************************/

static XtResource resources[] = { 
    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
      XtOffset(PlotObject, plot.foreground), XtRString, XtDefaultForeground},
    {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
      XtOffset(PlotObject, plot.background), XtRString, XtDefaultBackground},
    {XtNlabel,  XtCLabel, XtRString, sizeof(String),
      XtOffset(PlotObject, plot.label), XtRString, (caddr_t) NULL},
    {XtNplot,  XtCPlot, XtRInt, sizeof(int),
      XtOffset(PlotObject, plot.plot_type), XtRImmediate, (caddr_t) UNDEFINED},
    {XtNmarker,  XtCMarker, XtRInt, sizeof(int),
      XtOffset(PlotObject, plot.marker_type), XtRImmediate,(caddr_t) UNDEFINED},
    {XtNpoints, XtCPoints, XtRPointer, sizeof(Coord *),
      XtOffset(PlotObject, plot.points), XtRPointer, (caddr_t) NULL},
    {XtNplotwidth,  XtCPlotwidth, XtRInt, sizeof(int),
      XtOffset(PlotObject, plot.plot_width), XtRImmediate, (caddr_t) 0},
    {XtNplotheight,  XtCPlotheight, XtRInt, sizeof(int),
      XtOffset(PlotObject, plot.plot_height), XtRImmediate, (caddr_t) 0},
    {XtNcolors, XtCColors, XtRPointer, sizeof(XColor *),
      XtOffset(PlotObject, plot.colors), XtRPointer, (caddr_t) NULL},
    {XtNncolors,  XtCNcolors, XtRInt, sizeof(int),
      XtOffset(PlotObject, plot.ncolors), XtRImmediate, (caddr_t) 0},
    {XtNactive, XtCActive, XtRBoolean, sizeof(Boolean), 
      XtOffset(PlotObject, plot.active), XtRImmediate, (caddr_t) True},
    {XtNimage, XtCImage, XtRPointer, sizeof(struct xvimage *),
      XtOffset(PlotObject, plot.image), XtRPointer, (caddr_t) NULL},
    {XtNelevation, XtCElevation, XtRPointer, sizeof(struct xvimage *),
      XtOffset(PlotObject, plot.elevation), XtRPointer, (caddr_t) NULL},
    {XtNuse_image, XtCUse_image, XtRBoolean, sizeof(Boolean), 
      XtOffset(PlotObject, plot.use_image), XtRImmediate, (caddr_t) True},
    {XtNinterp_image, XtCInterp_image, XtRBoolean, sizeof(Boolean), 
      XtOffset(PlotObject, plot.interp_image), XtRImmediate, (caddr_t) False},
};


#define superclass (&rectObjClassRec)

PlotObjClassRec plotObjClassRec =
{
  {
    (WidgetClass) superclass,		/* superclass		  */	
    "PlotObj",				/* class_name		  */
    sizeof(PlotObjRec),			/* size			  */
    ClassInitialize,			/* class_initialize	  */
    ClassPartInitialize,		/* class_part_initialize  */
    FALSE,				/* class_inited		  */
    Initialize,				/* initialize		  */
    NULL,				/* initialize_hook	  */
    NULL,				/* not used - obj	  */
    NULL,				/* not used - obj	  */
    0,					/* not used - obj	  */
    resources,				/* resources		  */
    XtNumber(resources),		/* resource_count	  */
    NULLQUARK,				/* xrm_class		  */
    FALSE,				/* not used - obj	  */
    FALSE,				/* not used - obj	  */
    FALSE,				/* not used - obj    	  */
    FALSE,				/* not used - obj	  */
    Destroy,				/* destroy		  */
    NULL,				/* not used - obj	  */
    NULL,				/* not used - obj	  */
    SetValues,				/* set_values		  */
    NULL,				/* set_values_hook	  */
    XtInheritSetValuesAlmost,		/* not used - obj	  */
    NULL,				/* get_values_hook	  */
    NULL,				/* not used - obj	  */
    XtVersion,				/* version		  */
    NULL,				/* callback_private	  */
    NULL,				/* not used - obj	  */
    NULL,				/* not used - obj	  */
    NULL,				/* not used - obj	  */
    NULL				/* extension		  */
  },  /* CoreClass fields initialization */
  {
    Redisplay,                          /* field not used    	  */
    NULL				/* extension		  */
  },  /* PlotObjClass fields initialization */
};

  /* for public consumption */
#undef superclass
WidgetClass plotObjectClass = (WidgetClass)&plotObjClassRec;



/****************************************************************
*
* Class & Class Part Initialization
*
****************************************************************/

static void ClassInitialize()
{
	XawInitializeWidgetSet();
/*
	XtAddConverter(XtRString, XtRCoord, XmuCvtStringToCoord,
			NULL, 0);
 */
}

static void ClassPartInitialize(class)

WidgetClass class;
{
	PlotObjectClass entry, super;

	entry = (PlotObjectClass) class;
	super = (PlotObjectClass) entry->rect_class.superclass;
/*
	entry->plotobj_class.redisplay = super->plotobj_class.redisplay;
 */
}

/****************************************************************
*
* Initialization & Query geometry
*
****************************************************************/


static void Initialize(request, new)

Widget request, new;
{
	PlotObject xobj = (PlotObject) new;
	Colormap colormap;


	/*
	 *  Get the xcolors for the desired foreground & background
	 */
	xobj->plot.fg.pixel = xobj->plot.foreground;
	xobj->plot.bg.pixel = xobj->plot.background;
	xobj->plot.size = xobj->plot.plot_width * xobj->plot.plot_height;

	colormap = xobj->object.parent->core.colormap;
	XQueryColor(XoDisplay(xobj), colormap, &xobj->plot.fg);
	XQueryColor(XoDisplay(xobj), colormap, &xobj->plot.bg);

	if (xobj->plot.points == NULL)
	{
	   xobj->plot.points = (Coord *) XtCalloc(1, xobj->plot.size *
			sizeof(Coord));
	}

	if (xobj->plot.image != NULL)
	   SubSample(xobj);

	/*
	 *  Find the world coordinate minimum and maximum values (some of
	 *  the 3D plotting routines need them.
	 */
	FindMinMax(xobj);
}

/************************
*
*  Redisplay (plotting)
*
************************/

static void Redisplay(widget, event, region)

Widget	widget;
XEvent	*event;
Region  region;
{
	PlotObject xobj = (PlotObject) widget;

	XColor   *fg, *bg;
	register Coord *points;
	register int id, width, size;


	/*
	 *  Check to see if this plot is active or not
	 */
	if (xobj->plot.active == False)
	   return;

	id	 = XPlotID(xobj->object.parent);
	size     = xobj->plot.size;
	width    = xobj->plot.plot_width;
	points   = xobj->plot.points;
	fg	 = &xobj->plot.fg;
	bg	 = &xobj->plot.bg;

	switch (xobj->plot.plot_type)
	{
	   case PLOT_2D:         
		X2D_draw_polyline(id, points, size, fg);
		break;

	   case PLOT_DISCRETE:   
		X2D_draw_discrete(id, points, size, fg);
		break;

	   case PLOT_HISTOGRAM:  
		X2D_draw_bargraph(id, points, size, fg);
		break;

	   case PLOT_POLYMARKER: 
		X2D_draw_polymarker(id, points, size, xobj->plot.marker_type,
			fg);
		break;

	   case PLOT_LINEMARKER: 
		X2D_draw_linemarker(id, points, size, xobj->plot.marker_type,
			fg);
		break;

	   case PLOT_3D:
		X3D_draw_lineplot(id, points, width, size, fg);
		break;

	   case PLOT_MESH:
		X3D_draw_mesh(id, points, width, size, fg, bg);
		break;

	   case PLOT_IMPULSE:
		X3D_draw_impulse(id, points, size, fg);
		break;

	   case PLOT_CONTOUR_2D:
		X3D_draw_contour(id, points, width, size, NULL,
			xobj->plot.colors, xobj->plot.ncolors, TRUE);
		break;

	   case PLOT_CONTOUR_3D:
		X3D_draw_contour(id, points, width, size, NULL,
			xobj->plot.colors, xobj->plot.ncolors, FALSE);
		break;  

	   case PLOT_SCATTER:
		X3D_draw_polymarker(id, points, size, xobj->plot.marker_type,
			fg);
		break;

	   case PLOT_HORIZON:
		X3D_draw_horizon(id, points, width, size, fg, bg,
			xobj->plot.wcmin, xobj->plot.wcmax);
		break;

	   case PLOT_SURFACE:
		X3D_draw_surface(id, points, width, size, NULL,
			xobj->plot.colors, xobj->plot.ncolors,
			xobj->plot.wcmin, xobj->plot.wcmax,
			xobj->plot.use_image, xobj->plot.interp_image);
		break;

	   case PLOT_COLORMESH:
		X3D_draw_colormesh(id, points, width, size, NULL,
			xobj->plot.colors, xobj->plot.ncolors, bg,
			xobj->plot.wcmin, xobj->plot.wcmax);
		break;

	   case PLOT_WIREFRAME:
		X3D_draw_wireframe(id, points, width, size, fg);
		break;
	}
}


/***************************************************
*
*  Destroy
*
***************************************************/

static void Destroy(widget)

Widget widget;
{
	PlotObject xobj = (PlotObject) widget;
}


/***************************************************
*
*  SetValues
*
***************************************************/

static Boolean SetValues (current, request, new)

Widget current, request, new;
{
	PlotObject cobj = (PlotObject) current;
	PlotObject nobj = (PlotObject) new;


	if (!XtIsRealized(new))
	   return(FALSE);

	/*
	 *  Check to see if the plot width or plot height have changed.
	 *  If so then we need to free the old array and re-subsample
	 *  the image data.
	 */
	if (cobj->plot.plot_width != nobj->plot.plot_width ||
	    cobj->plot.plot_height != nobj->plot.plot_height)
	{
	   nobj->plot.size = nobj->plot.plot_width * nobj->plot.plot_height;
	   if (nobj->plot.image != NULL)
	   {
	      if (nobj->plot.points != NULL)
		 free(nobj->plot.points);

	      nobj->plot.points = (Coord *) XtCalloc(1, nobj->plot.size *
			sizeof(Coord));
	      SubSample(nobj);
	      FindMinMax(nobj);
	   }
	}
	else if (cobj->plot.image != nobj->plot.image || 
	    cobj->plot.elevation != nobj->plot.elevation)
	{
	   SubSample(nobj);
	   FindMinMax(nobj);
	}
	return(True);
}

/***************************************************
*
*  Local Routines
*
***************************************************/

static void FindMinMax(xobj)

PlotObject xobj;
{
	register int i;
	Coord wcmin, wcmax; 
	register Coord *points;

	points = xobj->plot.points;
	wcmin.x = wcmax.x = points[0].x;
	wcmin.y = wcmax.y = points[0].y;
	wcmin.z = wcmax.z = points[0].z;
	wcmin.d = wcmax.d = points[0].d;

	for (i = xobj->plot.size -1; i >= 0; i--)
	{
	   if (points[i].x > wcmax.x) wcmax.x = points[i].x;
	   else if (points[i].x < wcmin.x) wcmin.x = points[i].x;

	   if (points[i].y > wcmax.y) wcmax.y = points[i].y;
	   else if (points[i].y < wcmin.y) wcmin.y = points[i].y;

	   if (points[i].z > wcmax.z) wcmax.z = points[i].z;
	   else if (points[i].z < wcmin.z) wcmin.z = points[i].z;

	   if (points[i].d > wcmax.d) wcmax.d = points[i].d;
	   else if (points[i].d < wcmin.d) wcmin.d = points[i].d;
	}
	xobj->plot.wcmin = wcmin;
	xobj->plot.wcmax = wcmax;
}

static void SubSample(xobj)

PlotObject xobj;
{
	register Coord *points;
	register Real  xincr, yincr;
	register int   i, k, m, l, base, width, height, elvation_type;

	XColor   *colors;
	struct xvimage *image, *elevation;
	unsigned char  *imagedata;

	short	 *sptr;
	int	 *iptr;
	float	 *fptr;
	double	 *dptr;
	unsigned char *bptr;


	if (xobj->plot.image == NULL)
	   return;

	points  = xobj->plot.points;
	image   = xobj->plot.image;
	if (xobj->plot.elevation == NULL)
	   elevation = xobj->plot.image;
	else
	   elevation = xobj->plot.elevation;

	width  = elevation->row_size;
	height = elevation->col_size;
	xincr  = ((Real) width)/xobj->plot.plot_width;
	yincr  = ((Real) height)/xobj->plot.plot_height;

	elvation_type = elevation->data_storage_type;
	sptr = (short *) 	 elevation->imagedata;
	iptr = (int *)		 elevation->imagedata;
	fptr = (float *)	 elevation->imagedata;
	dptr = (double *)	 elevation->imagedata;
	bptr = (unsigned char *) elevation->imagedata;
	imagedata = (unsigned char *) image->imagedata;

	for (m = k = 0; k < xobj->plot.plot_height; k++)
	{
	   base = ((int) (height - k*yincr -1)) * width;
	   for (i = 0; i < xobj->plot.plot_width; i++, m++)
	   {
	      l = base + i*xincr;
	      if (elevation->location_type == VFF_LOC_IMPLICIT ||
		  elevation->location_dim != 2)
	      {
		 points[m].x = i * xincr;
		 points[m].y = k * yincr;
	      }
	      else
	      {
		 points[m].x = elevation->location[l];
		 points[m].y = elevation->location[l+width*height];
	      }
	      switch(elvation_type)
	      {
		 case VFF_TYP_1_BYTE:
		      points[m].z = (Real) bptr[l];
		      break;

		 case VFF_TYP_2_BYTE:
		      points[m].z = (Real) sptr[l];
		      break;

		 case VFF_TYP_4_BYTE:
		      points[m].z = (Real) iptr[l];
		      break;

		 case VFF_TYP_FLOAT:
		      points[m].z = (Real) fptr[l];
		      break;

		 case VFF_TYP_DOUBLE:
		      points[m].z = (Real) dptr[l];
		      break;
	      }
	      points[m].d = imagedata[l];
	   }
	}
}
