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

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

 /*
  * $Log: Plot.c,v $
 * Revision 1.3  1992/03/20  22:51:17  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 plot display widget used by the	<<<<
   >>>>		       plotting programs.			<<<<
   >>>>								<<<<
   >>>>      routines:						<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

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

static void	Initialize();
static void	Realize();
static void	Redisplay();
static void	Resize();
static void	Destroy();
static void	ChangeManaged();
static void	ClassInitialize();
static void	ClassPartInitialize();


static Boolean	SetValues();
static XtGeometryResult	GeometryManager();

static void	FindMinMax();


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

static float alpha = 63.7,
	     theta = 31.8,
	     eye   = 8.0,
	     view  = 16.0,
	     hfactor = 1.0;

static XtResource resources[] = { 
    {XtNvisual, XtCVisual, XtRPointer, sizeof(Visual *),
      XtOffset(PlotWidget, plot.visual), XtRCallback, (caddr_t) NULL},
    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
      XtOffset(PlotWidget, plot.foreground), XtRString, XtDefaultForeground},
    {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
        XtOffset(PlotWidget, plot.width), XtRImmediate, (caddr_t) 512},
    {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
        XtOffset(PlotWidget, plot.height), XtRImmediate, (caddr_t) 512},
    {XtNtitle,  XtCTitle, XtRString, sizeof(String),
      XtOffset(PlotWidget, plot.title), XtRString, (caddr_t) NULL},
    {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t), 
      XtOffset(PlotWidget, plot.callbacks), XtRCallback, (caddr_t) NULL},
    {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), 
      XtOffset(PlotWidget, plot.cursor), XtRImmediate, (caddr_t) None},
    {XtNalpha, XtCAlpha, XtRFloat, sizeof(float), 
      XtOffset(PlotWidget, plot.alpha), XtRFloat, (caddr_t) &alpha},
    {XtNtheta, XtCTheta, XtRFloat, sizeof(float), 
      XtOffset(PlotWidget, plot.theta), XtRFloat, (caddr_t) &theta},
    {XtNeye, XtCEye, XtRFloat, sizeof(float), 
      XtOffset(PlotWidget, plot.eye_distance), XtRFloat, (caddr_t) &eye},
    {XtNview, XtCView, XtRFloat, sizeof(float), 
      XtOffset(PlotWidget, plot.view_distance), XtRFloat, (caddr_t) &view},
    {XtNhfactor, XtCHfactor, XtRFloat, sizeof(float), 
      XtOffset(PlotWidget, plot.hfactor), XtRFloat, (caddr_t) &hfactor},
    {XtNproportional, XtCProportional, XtRBoolean, sizeof(Boolean), 
      XtOffset(PlotWidget, plot.proportional), XtRImmediate, (caddr_t) True},
    {XtNactive, XtCActive, XtRBoolean, sizeof(Boolean), 
      XtOffset(PlotWidget, plot.active), XtRImmediate, (caddr_t) True},
};

static CompositeClassExtensionRec composite_rec = {
	/* next_extension */  NULL,
	/* record_type */     NULLQUARK,
	/* version */         XtCompositeExtensionVersion,
	/* record_size */     sizeof(CompositeClassExtensionRec),
	/* accepts_objects */ TRUE,
};

#define superclass (&compositeClassRec)

PlotClassRec plotClassRec =
{
  {
    (WidgetClass) superclass,		/* superclass		  */	
    "Plot",				/* class_name		  */
    sizeof(PlotRec),			/* size			  */
    ClassInitialize,			/* class_initialize	  */
    ClassPartInitialize,		/* class_part_initialize  */
    FALSE,				/* class_inited		  */
    Initialize,				/* initialize		  */
    NULL,				/* initialize_hook	  */
    Realize,				/* realize		  */
    NULL,				/* actions		  */
    0,					/* num_actions		  */
    resources,				/* resources		  */
    XtNumber(resources),		/* resource_count	  */
    NULLQUARK,				/* xrm_class		  */
    TRUE,				/* compress_motion	  */
    TRUE,				/* compress_exposure	  */
    TRUE,				/* compress_enterleave    */
    FALSE,				/* visible_interest	  */
    Destroy,				/* destroy		  */
    Resize,				/* resize		  */
    Redisplay,				/* expose		  */
    SetValues,				/* set_values		  */
    NULL,				/* set_values_hook	  */
    XtInheritSetValuesAlmost,		/* set_values_almost	  */
    NULL,				/* get_values_hook	  */
    NULL,				/* accept_focus		  */
    XtVersion,				/* version		  */
    NULL,				/* callback_private	  */
    NULL,				/* tm_table		  */
    NULL,				/* query_geometry	  */
    XtInheritDisplayAccelerator,	/* display_accelerator	  */
    NULL				/* extension		  */
  },  /* CoreClass fields initialization */
  {
    GeometryManager,			/* geometry_manager	  */
    ChangeManaged,			/* change_managed	  */
    XtInheritInsertChild,		/* insert_child	  	  */
    XtInheritDeleteChild,		/* delete_child	  	  */
    NULL,				/* extension	 	  */
  },  /* CompositeClass fields initialization */
  {
    NULL,                                     /* field not used    */
  },  /* PlotClass fields initialization */
};

  /* for public consumption */
WidgetClass plotWidgetClass = (WidgetClass)&plotClassRec;


/****************************************************************
*
* Class and Class Part Initialization Routines
*
****************************************************************/

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

static void ClassPartInitialize(widget_class)

WidgetClass widget_class;
{
	PlotWidgetClass plot_class = (PlotWidgetClass) widget_class;

	composite_rec.next_extension = plot_class->composite_class.extension;
	plot_class->composite_class.extension = (caddr_t) &composite_rec;
	plot_class->composite_class.extension = (caddr_t) &composite_rec;
}



/*****************************
*
* Widget Initialization
*
******************************/

static void Initialize(request, new)

Widget request, new;
{
	PlotWidget xwid = (PlotWidget) new;


	/*
	 *  Get the xcolors for the desired foreground & background
	 */
	xwid->plot.fg.pixel = xwid->plot.foreground;
	xwid->plot.bg.pixel = xwid->core.background_pixel;

	XQueryColor(XtDisplay(new), new->core.colormap, &xwid->plot.fg);
	XQueryColor(XtDisplay(new), new->core.colormap, &xwid->plot.bg);
}

static void Realize(widget, valuemask, attributes)

Widget		widget;
XtValueMask	*valuemask;
XSetWindowAttributes *attributes;
{
	PlotWidget xwid = (PlotWidget) widget;

	int	   mode;
	XSizeHints hints;
	Visual	   *visual;


	*valuemask |= CWColormap;
	attributes->colormap = widget->core.colormap;

	if ((attributes->cursor = xwid->plot.cursor) != None)
	   *valuemask |= CWCursor;

	if (xwid->plot.visual == NULL)
	   visual = (Visual *) CopyFromParent;
	else
	   visual = xwid->plot.visual;

	if ((mode = XDoesBackingStore(XtScreen(widget))) != NotUseful)
	{
	   *valuemask |= CWBackingStore;
	   attributes->backing_store = mode;
	} 
	XtCreateWindow(widget, InputOutput, visual, *valuemask, attributes);

	/*
	 *  Initialize the graphics library
	 */
	xwid->plot.id = (int) xwid;
	X3D_init_graphics(xwid->plot.id, X3D);
	X3D_set_font(xwid->plot.id, TimesRoman);
	X3D_set_text(xwid->plot.id, CenterJustify, 0.6, 0.9);
	X3D_set_viewport(xwid->plot.id, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
	X3D_set_projection(xwid->plot.id, Perspective);
	X3D_set_view_distance(xwid->plot.id, (Real) xwid->plot.view_distance);
	X3D_set_viewpoint(xwid->plot.id, (Real) xwid->plot.alpha,
		(Real) xwid->plot.theta, (Real) xwid->plot.eye_distance);
	X3D_set_X11(xwid->plot.id, XtDisplay(widget), NULL, widget);
	Resize(widget);
}



/*****************************
*
* Widget Management Routines
*
******************************/

static XtGeometryResult GeometryManager(widget, constraint, preferred)

Widget	widget;
XtWidgetGeometry  *constraint,		/*  unused  */
		  *preferred;
{
	PlotWidget xwid = (PlotWidget) widget;

	int	     x, y;
	Window	     root;
	unsigned     int  width, height, border_width, depth;


	preferred->request_mode = CWWidth | CWHeight;
	preferred->width  = xwid->plot.width;
	preferred->height = xwid->plot.height;
	return(XtGeometryAlmost);
}



static void ChangeManaged(widget)

Widget widget;
{
	PlotWidget xwid = (PlotWidget) widget;

	FindMinMax(xwid);
}



/***************************************************
*
*  Resize
*
***************************************************/

static void Resize(widget)

Widget  widget;
{
	PlotWidget xwid = (PlotWidget) widget;

	Window	     root;
	int	     x, y;
	unsigned     int  width, height, border_width, depth;


	if (XGetGeometry(XtDisplay(widget), XtWindow(widget), &root, &x, &y,
			 &width, &height,  &border_width, &depth))
	{
	   xwid->plot.width  = width;
	   xwid->plot.height = height;
	   X3D_set_window(xwid->plot.id, (short) 0, (short) 0, (short) width,
			  (short) height);
	}
	else
	   return;
}



/************************
*
*  Redisplay 
*
************************/

static void Redisplay(widget, event, region)

Widget	widget;
XEvent	*event;
Region  region;
{
	PlotWidget xwid = (PlotWidget) widget;

	int	    i;
	PlotObject  *plot;
	PlotObjectClass class;


	if (xwid->plot.active == False)
	   return;

	plot = (PlotObject *) xwid->composite.children;
	for (i = 0; i < xwid->composite.num_children; i++)
	{
	    class = (PlotObjectClass) (*plot)->object.widget_class;
	    if (class->plotobj_class.redisplay != NULL)
	       (class->plotobj_class.redisplay) ((Widget) *plot, NULL, NULL);

	    plot++;
	}

	if (xwid->plot.title != NULL)
	{
	   Real   width, height;
	   Coord  position;
	   Vector direction;

	   width  = (xwid->plot.wcmax.x - xwid->plot.wcmin.x)/15.0;
	   height = (xwid->plot.wcmax.y - xwid->plot.wcmin.y)/15.0;
	   position.x = (xwid->plot.wcmax.x - xwid->plot.wcmin.x)/2.0;
	   position.y = xwid->plot.wcmax.y - height;
	   direction.x = 1.0;
	   direction.y = 0.0;

	   X2D_draw_text(xwid->plot.id, position, direction, width, height,
			 xwid->plot.title, strlen(xwid->plot.title),
			 &xwid->plot.fg);
	}
}



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

static void Destroy(widget)

Widget widget;
{
}



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

static Boolean SetValues (current, request, new)

Widget current, request, new;
{
	PlotWidget cxwid = (PlotWidget) current;
	PlotWidget nxwid = (PlotWidget) new;


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

	if (cxwid->core.colormap != nxwid->core.colormap)
	{
	   XSetWindowColormap(XtDisplay(new), XtWindow(new),
			nxwid->core.colormap);
	}

	if (cxwid->plot.proportional != nxwid->plot.proportional ||
	    cxwid->plot.hfactor != nxwid->plot.hfactor)
	{
	   FindMinMax(nxwid);
	}

	if (cxwid->core.background_pixel != nxwid->core.background_pixel ||
	    cxwid->plot.foreground != nxwid->plot.foreground)
	{
	   nxwid->plot.fg.pixel = nxwid->plot.foreground;
	   nxwid->plot.bg.pixel = nxwid->core.background_pixel;

	   XQueryColor(XtDisplay(new), new->core.colormap, &nxwid->plot.fg);
	   XQueryColor(XtDisplay(new), new->core.colormap, &nxwid->plot.bg);
	}

	if (cxwid->plot.eye_distance != nxwid->plot.eye_distance ||
	    cxwid->plot.view_distance != nxwid->plot.view_distance ||
	    cxwid->plot.alpha != nxwid->plot.alpha ||
	    cxwid->plot.theta != nxwid->plot.theta)
	{
	   X3D_set_view_distance(nxwid->plot.id,
			(Real) nxwid->plot.view_distance);
	   X3D_set_viewpoint(nxwid->plot.id, (Real) nxwid->plot.alpha,
		(Real) nxwid->plot.theta, (Real) nxwid->plot.eye_distance);
	}
	return(True);
}



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

#undef  MAX
#define MAX(x,y) (((x) > (y)) ? (x) : (y))

#undef  MIN
#define MIN(x,y) (((x) < (y)) ? (x) : (y))

#undef  MIN3
#define MIN3(x0, x1, x2) ((MIN(x0,x1) < MIN(x1,x2)) \
                                          ? MIN(x0,x1) : MIN(x1,x2))
#undef  MAX3
#define MAX3(x0, x1, x2) ((MAX(x0,x1) > MAX(x1,x2)) \
                                          ? MAX(x0,x1) : MAX(x1,x2))


static void FindMinMax(xwid)

PlotWidget xwid;
{
	int	    i;
	Real	    diff, ndiff;
	PlotObject  *pobj;
	Coord        wcmin, wcmax;

	pobj = (PlotObject *) xwid->composite.children;

	wcmin = (*pobj)->plot.wcmin;
	wcmax = (*pobj)->plot.wcmax;
	pobj++;

	for (i = 1; i < xwid->composite.num_children; i++)
	{
	    if ((*pobj)->plot.wcmin.x < wcmin.x)
	       wcmin.x = (*pobj)->plot.wcmin.x;
	    else if ((*pobj)->plot.wcmax.x > wcmax.x)
	       wcmax.x = (*pobj)->plot.wcmax.x;

	    if ((*pobj)->plot.wcmin.y < wcmin.y)
	       wcmin.y = (*pobj)->plot.wcmin.y;
	    else if ((*pobj)->plot.wcmax.y > wcmax.y)
	       wcmax.y = (*pobj)->plot.wcmax.y;

	    if ((*pobj)->plot.wcmin.z < wcmin.z)
	       wcmin.z = (*pobj)->plot.wcmin.z;
	    else if ((*pobj)->plot.wcmax.z > wcmax.z)
	       wcmax.z = (*pobj)->plot.wcmax.z;

	    if ((*pobj)->plot.wcmin.d < wcmin.d)
	       wcmin.d = (*pobj)->plot.wcmin.d;
	    else if ((*pobj)->plot.wcmax.d > wcmax.d)
	       wcmax.d = (*pobj)->plot.wcmax.d;

	    pobj++;
	}

	if (xwid->plot.proportional)
	{

	   diff = MAX3(wcmax.x - wcmin.x, wcmax.y - wcmin.x, wcmax.z - wcmin.z);

	   wcmin.x -= (diff - (wcmax.x - wcmin.x))/2;
	   wcmax.x += (diff - (wcmax.x - wcmin.x))/2;

	   wcmin.y -= (diff - (wcmax.y - wcmin.y))/2;
	   wcmax.y += (diff - (wcmax.y - wcmin.y))/2;

	   wcmin.z -= (diff - (wcmax.z - wcmin.z))/2;
	   wcmax.z += (diff - (wcmax.z - wcmin.z))/2;
	}

	if (xwid->plot.hfactor != 1.0 && xwid->plot.hfactor > 0.0)
	{

	   if (xwid->plot.hfactor < 1.0)
	   {
	      diff = wcmax.z - wcmin.z;
	      ndiff = diff/xwid->plot.hfactor;
	      wcmax.z = (diff/2 + wcmin.z) + ndiff/2;
	      wcmin.z = (diff/2 + wcmin.z) - ndiff/2;
	   }
	   else
	   {
	      diff = wcmax.z - wcmin.z;
	      ndiff = diff/xwid->plot.hfactor;
	      wcmax.z = (diff/2 + wcmin.z) + ndiff/2;
	      wcmin.z = (diff/2 + wcmin.z) - ndiff/2;
	   }
	}
	xwid->plot.wcmin = wcmin;
	xwid->plot.wcmax = wcmax;
	X3D_set_wc_min_max(xwid->plot.id, wcmin, wcmax);
}



/************************
*
*  Public Routines 
*
************************/

int XPlotID(widget)

Widget widget;
{
	PlotWidget xwid = (PlotWidget) widget;

	if (!XtIsRealized(widget))
	   return(-1);
	else
	   return(xwid->plot.id);
}
