// C++ .h file for gplot, basic display classes  -*-c++-*-
// copyright Phil Andrews, Pittsburgh Supercomputing Center, 1992
// all rights reserved
#ifndef cgmdisplay_h
#define cgmdisplay_h
#include <math.h>
#include <stdio.h>
#include "cgm.h"
////
// forward declarations
////
#ifndef _XLIB_H_
class XPoint;
#endif
// handy angle class, note completely defined by sin and cos, thus no
// concept of "less than", no cuts or Riemann sheets. Inline everything.
////
class angle {
public:
  // constructor
  angle(double y, double x)
    {r = sqrt(x*x + y*y); myTan = (x) ? y/x : (y<0) ? tanMax : -tanMax;
     mySin = (r) ? y/r : 0; myCos = (r) ? x/r : 0;}

  double tan() const {return myTan;}
  double sin() const {return mySin;}
  double cos() const {return myCos;}
  ////
  // in this range ? (i.e., going from phi1 to phi2 covers *this)
  int within(angle phi1, angle phi2)
    {return (((*this - phi1).sin() >= 0) && ((phi2 - *this).sin() >= 0));}
  ////
  // now some overloaded operators
  // minus another angle
  angle operator-(angle phi) const
    {return angle(sin() * phi.cos() - cos() * phi.sin(),
		    cos() * phi.cos() + sin() * phi.sin());}
  // plus another angle
  angle operator+(angle phi) const
    {return angle(sin() * phi.cos() + cos() * phi.sin(),
	       cos() * phi.cos() - sin() * phi.sin());}
  ////
  // decrement operator
  angle operator-=(angle phi)
    {double y = sin() * phi.cos() - cos() * phi.sin();
     double x = cos() * phi.cos() + sin() * phi.sin();
     mySin = y; myCos = x; myTan = (x) ? y/x : (y<0) ? -tanMax : tanMax;
     return *this;}
  ////
  // increment operator
  angle operator+=(angle phi)
  {double y = sin() * phi.cos() + cos() * phi.sin();
   double x =  cos() * phi.cos() - sin() * phi.sin();
   mySin = y; myCos = x; myTan = (x) ? y/x : (y<0) ? -tanMax : tanMax;
   return *this;}
  ////
  double size() {return r;} // careful with this !
protected:
  double myTan, mySin, myCos, r;
  static const double tanMax;
};    
////
// base display class
////
class baseDisplay { 
public:
  baseDisplay(); // default constructor
  virtual ~baseDisplay() {if (myPxlExtent) delete myPxlExtent;}
  ////
  // delimiters
  virtual void newMF(){} // default
  void newPic(); // not virtual, must be calle
  virtual void startPic() {} // default function
  void newPicBody(float, float, float=0, float=0); // not virtual, must call
  virtual void clearScreen(const char* = NULL){} // default function
  virtual void endPic(){} // default function
  virtual void endMF(){} // default function
  ////
  // control elements, all default
  virtual void transparency(int inTrans) {myTrans = inTrans;}
  virtual void clipRect(const vdcPts *inPts) {myClipRect = inPts;}
  virtual void clip(int inClip) {myClip = inClip;}
  virtual void backColr(const genColr&) {}
  ////
  // graphical primitives, polyline required rest default
  virtual int polyline(const vdcPts*) = 0; // required in all descendants
  virtual int disPolyline(const vdcPts*); // default function
  virtual int polymarker(const vdcPts*); // default function
  virtual int text(const genText*); // default function
  virtual int polygon(const vdcPts*); // default function
  virtual int polygonSet(const vdcPts*, const int*); // default function
  virtual int cells(const cellArray*); // default function
  virtual int rectangle(const vdcPts*); // default function
  virtual int circle(const vdcPts*, const vdc*, int=0); // default function
  virtual int arc3Pt(const vdcPts*, int); // default function
  virtual int arcCtr(const vdcPts*, vdc*, int); // default function
  virtual int ellipse(const vdcPts*); // default function
  virtual int ellipArc(const vdcPts*, int); // default function
  ////
  // attributes, all default functions
  virtual void lineIndex(int inIndex) {myLineIndex = inIndex;}
  virtual void lineType(int inType) {myLineType = inType;}
  virtual void lineWidth(const vdcR *inWidth) {myLineWidth = inWidth;}
  virtual void lineColr(const genColr &inColr) {}
  virtual void markerIndex(int inIndex) {myMarkerIndex = inIndex;}
  virtual void markerType(int inType) {myMarkerType = inType;}
  virtual void markerSize(const vdcR *inSize) {myMarkerSize = inSize;}
  virtual void markerColr(const genColr &inColr) {}
  virtual void textIndex(int inIndex) {myTextIndex = inIndex;}
  virtual void fontIndex(int inIndex) {myFontIndex = inIndex;}
  virtual void textPrec(int inType) {myTextPrec = inType;}
  virtual void charSpace(float inFloat) {myCharSpace = inFloat;}
  virtual void charExpan(float inFloat) {myCharExpan = inFloat;}
  virtual void textColr(const genColr&) {}
  virtual void charHeight(const vdc *inHeight) {myCharHeight = inHeight;}
  virtual void charOri(const vdcPts *inOri) {myCharOri = inOri;}
  virtual void textPath(int inPath) {myTextPath = inPath;}
  virtual void textAlign(const alignment *inAlign) {myTextAlign = inAlign;}
  virtual void charSetIndex(int inIndex) {myCharSetIndex = inIndex;}
  virtual void altCharSetIndex(int inIndex) {myAltCharSetIndex = inIndex;}
  virtual void fillIndex(int inIndex) {myFillIndex = inIndex;}
  virtual void intStyle(int inStyle) {myIntStyle = inStyle;}
  virtual void fillColr(const genColr&){}
  virtual void hatchIndex(int inIndex) {myHatchIndex = inIndex;}
  virtual void patIndex(int inIndex) {myPatIndex = inIndex;}
  virtual void edgeIndex(int inIndex) {myEdgeIndex = inIndex;}
  virtual void edgeType(int inType) {myEdgeType = inType;}
  virtual void edgeWidth(const vdcR *inWidth) {myEdgeWidth = inWidth;}
  virtual void edgeVis(int inVis) {myEdgeVis = inVis;}
  virtual void edgeColr(const genColr &inColr) {}
  virtual void fillRefPt(const vdcPts *inPts) {myFillRefPt = inPts;}
  virtual void colrs(const colrTable*); // a colour table 
  ////
  // check on requirements of display
  virtual int invert() {return 0;} // do we need inversion of vdc pts ?
  virtual int picDefaults() {return 1;} // do we need defaults for each page
  virtual int fileDefaults() {return 0;} // do we need defaults for each file
protected:
  // utility functions
  int getSize(const vdc *inVDC) // size in x pixels
    {return (inVDC) ? (inVDC->type()) ? (int) (inVDC->f() * useScale) :
     (int) (inVDC->i() * useScale) : 0;}
  int getPts(const vdcPts*, int*&, int=0); // get right format of points
  int getPts(const vdcPts*, float*&, int=0); // get right format of points
  int getPts(const vdcPts*, short*&, int=0); // get right format of points
  int getPts(const vdcPts*, XPoint*&, int=0); // get right format of points
  vdcPts *getArc(const vdcPts*, const vdc*, const angle*, const angle*,
		 int=-1, const vdc* = NULL, const angle* = NULL); 
  float greyColr(float r, float g, float b) // grey equivalent
    {return 1.0 - (0.3 * r + 0.59 * g + 0.11 * b);}
  float greyColr(float *inF) // convenience function
    {return greyColr(inF[0], inF[1], inF[2]);}
  ////
  virtual vdcPts *pxlExtent() {return myPxlExtent;} // pixel extent
  virtual float xPxlSize() = 0; // x pixel size in mm (required)
  virtual float yPxlSize() = 0; // y pixel size in mm (required)
  // state variables
  //
  // variables for scaling
  float vdcWidth, vdcHeight, devWidth, devHeight, xScale, yScale, useScale;
  float useOff[4];
  // control elements
  int myTrans;
  const vdcPts *myClipRect;
  int myClip;
  //
  // attributes
  int myLineIndex;
  int myLineType;
  const vdcR *myLineWidth;
  int myMarkerIndex;
  int myMarkerType;
  const vdcR *myMarkerSize;
  int myTextIndex;
  int myFontIndex;
  int myTextPrec;
  float myCharExpan;
  float myCharSpace;
  const vdc *myCharHeight;
  const vdcPts *myCharOri;
  int myTextPath;
  const alignment *myTextAlign;
  int myCharSetIndex;
  int myAltCharSetIndex;
  int myFillIndex;
  int myIntStyle;
  int myHatchIndex;
  int myPatIndex;
  int myEdgeIndex;
  int myEdgeType;
  const vdcR *myEdgeWidth;
  int myEdgeVis;
  const vdcPts *myFillRefPt;
  // externally imposed values
  int myXSize, myYSize;
  vdcPts *myPxlExtent;
};
////
// class to hold a character in an Hershey font form
////
class hersheyChar {
public:
  hersheyChar(const genText*, int, int=0);
  ~hersheyChar();
  hersheyChar *next;
  int display(baseDisplay*);
  void shift(float&, float&);
  float shift1() {return myShift1;}
  float shift2() {return myShift2;}
  float shiftY1() {return myShiftY1;}
  float shiftY2() {return myShiftY2;}
  float width() {return shift1() + shift2();}
  float height() {return myHeight;}
  float depth() {return myDepth;}
  void scale(float);
protected:
  vdcPts *contents;
  static const int maxOffset;
  void addPts(vdcPts*);
  float myShift1, myShift2, myHeight, myDepth, myShiftY1, myShiftY2;
};
////
// class to hold a string in an Hershey font form
////
class hersheyString {
public:
  hersheyString(const genText*);
  ~hersheyString();
  int display(baseDisplay*);
  void right(const genText*, float&, float&);
  void left(const genText*, float&, float&);
  void up(const genText*, float&, float&);
  void down(const genText*, float&, float&);
  float width(); // the width of the string
  void scale(float); // scale the string
  float height() {return myHeight;}
  float depth() {return myDepth;}
protected:
  hersheyChar *contents;
  void addChar(hersheyChar*);
  float myHeight, myDepth;
};
#endif // cgmdisplay_h
