
static char PanTiltGraph_id[] = "$Header: /usr/tiburon/unix/gui/tmacs/RCS/PanTiltGraph.cc,v 1.5 1997/12/12 17:55:42 oreilly Exp $";

/*
$Log: PanTiltGraph.cc,v $
Revision 1.5  1997/12/12 17:55:42  oreilly
*** empty log message ***

Revision 1.4  1997/09/10 08:52:52  oreilly
*** empty log message ***

Revision 1.3  97/04/30  19:40:44  19:40:44  oreilly (Thomas C. O'Reilly)
Check for valid numbers when setting pan and tilt

Revision 1.2  97/03/20  12:30:25  12:30:25  oreilly (Thomas C. O'Reilly)
..

Revision 1.1  96/10/28  09:12:32  09:12:32  oreilly (Thomas C. O'Reilly)
Initial revision

*/
#include <values.h>
#include "PanTiltGraph.h"
#include "malloc.h"

PanTiltGraph::PanTiltGraph(Display *display, GC axisGC, GC pointGC,
			   Radians panRange, Radians tiltRange,
			   int pointType)
{
  _label = NULL;
  
  _display = display;
  _axisGC = axisGC;
  _pointGC = pointGC;

  _pointType = pointType;
  
  setDimensions(0, 0, 1, 1);
  setPanRange(panRange);
  setTiltRange(tiltRange);

  setCenterPan(0.);
  setPan(0.);
  setTilt(0.);
  setLabel(NULL);
}


PanTiltGraph::~PanTiltGraph()
{
  if (_label) free(_label);
}


void PanTiltGraph::setPanRange(Radians panRange)
{
  _panRange = panRange;
}


void PanTiltGraph::setLabel(const char *label)
{
  if (_label) free(_label);

  if (label)
    _label = strdup(label);
  else
    _label = NULL;
}


void PanTiltGraph::setTiltRange(Radians tiltRange)
{
  _tiltRange = tiltRange;
}


void PanTiltGraph::setDimensions(int originX, int originY, 
				 int width, int height)
{
  _originX = originX;
  _originY = originY;
  _width = width;
  _height = height;
}


/* Convert x and y to physical coordinates. Origin is always at center of
graph area, and x=0, y=0 */
int PanTiltGraph::physicalCoords(Radians pan, Radians tilt,
				 int *i, int *j)
{
  double xmin = _centerPan - _panRange / 2.;
  double ymin = -_tiltRange / 2.;

  if (tilt < ymin || tilt > -ymin)
    return -1;

  if (Math::angularSeparation(xmin, pan) > _panRange)
    return -1;
  
  double value;

  value = Math::angularSeparation(_centerPan - _panRange / 2., pan) * 
    _width / _panRange;
  
  if (fabs(value) > MAXINT)
    return -1;
  
  *i = (int )(value + 0.5) + _originX;
  
  value = _height - ((tilt - ymin) * _height / _tiltRange);
  if (fabs(value) > MAXINT)
    return -1;
  
  *j = (int )(value + 0.5) + _originY;
  
  return 0;
}


void PanTiltGraph::draw(Drawable canvas)
{
  int i1, j1, i2, j2;
  
  // Draw x axis
  Radians maxVal = _centerPan + _panRange / 2.;
  Radians minVal = _centerPan - _panRange / 2.;  
  physicalCoords(minVal, 0., &i1, &j1);
  physicalCoords(maxVal, 0., &i2, &j2);
  XDrawLine(_display, canvas, _axisGC, i1, j1, i2, j2);

  // Draw tic marks
  int ticLen = _width / 20;
  Radians ticIncr = 20. * Math::RadsPerDeg;
  Radians val;
  
  for (val = 0.; val > minVal; val -= ticIncr)
  {
    physicalCoords(val, 0., &i1, &j1);
    XDrawLine(_display, canvas, _axisGC, i1, j1 - ticLen, i1, j1 + ticLen);
  }

  for (val = 0.; val < maxVal; val += ticIncr)
  {
    physicalCoords(val, 0., &i1, &j1);
    XDrawLine(_display, canvas, _axisGC, i1, j1 - ticLen, i1, j1 + ticLen);
  }
    
  // Draw y axis
  maxVal = _tiltRange / 2.;
  physicalCoords(_centerPan, -maxVal, &i1, &j1);
  physicalCoords(_centerPan, maxVal, &i2, &j2);  
  XDrawLine(_display, canvas, _axisGC, i1, j1, i2, j2);

  // Draw tic marks
  ticIncr = 10. * Math::RadsPerDeg;
  for (val = 0.; val > -maxVal; val -= ticIncr)
  {
    physicalCoords(_centerPan, val, &i1, &j1);
    XDrawLine(_display, canvas, _axisGC, i1 - ticLen, j1, i1 + ticLen, j1);
  }

  for (val = 0.; val < maxVal; val += ticIncr)
  {
    physicalCoords(_centerPan, val, &i1, &j1);
    XDrawLine(_display, canvas, _axisGC, i1 - ticLen, j1, i1 + ticLen, j1);
  }

  // Draw point
  if (physicalCoords(_pan, _tilt, &i1, &j1) == -1)
    return;

  int diameter = _width / 10;

  if (_pointType == Circle)
    XFillArc(_display, canvas, _pointGC, i1 - diameter/2, j1 - diameter/2,
	     diameter, diameter, 0, 360*64);
  else
    XFillRectangle(_display, canvas, _pointGC, 
		   i1 - diameter/2, j1 - diameter/2,
		   diameter, diameter);

  // Add label
  if (_label && strlen(_label))
  {
    Radians x = _centerPan + _panRange / 6;
    Radians y;
    if (_tilt < 0. || _pan < _centerPan)
      y = _tiltRange / 6;
    else
      y = -_tiltRange / 2 - _tiltRange / 6;

    
    physicalCoords(x, y, &i1, &j1);
    XDrawString(_display, canvas, _pointGC, i1, j1, _label, strlen(_label));
  }
}


void PanTiltGraph::setPan(Radians pan)
{
  if (isnan(pan))
    return;
  
  _pan = pan;
  Math::minusPiToPi(&_pan);

  Math::zeroToTwoPi(&pan);
}


void PanTiltGraph::setCenterPan(Radians centerPan)
{
  _centerPan = centerPan;
  Math::minusPiToPi(&_centerPan);
}


void PanTiltGraph::setTilt(Radians tilt)
{
  if (isnan(tilt))
    return;
  
  _tilt = tilt;
  Math::minusPiToPi(&_tilt);
}
