eps.h
#ifndef __eps_h

#include <fstream>
#include <iostream>
#include <string>
#include <cmath>
#include <vector>

using namespace std;

enum EPSDrawTypes {Rects,Circles,Points};
//extern char *EPSDrawTypeNames[];

struct LegendEntry{
 public:
  string color;
  char symbol;
  string info;
};

enum LegendPos {TopLeft,TopRight,BottomLeft,BottomRight};

class Legend{
 public:
  static const int MaxEntryNum=5;
  int EntryNum;
  LegendEntry Entry[MaxEntryNum];
  void AddEntry(char *acolor, char asymbol, char *ainfo);
  Legend(){EntryNum=0;}
};

struct EPSOptions {
  bool Save;
  string EPSFileName;
  string DataFileName;
  string EPSFileCreator;
  string EPSFileTitle;
  double XMin,YMin,XMax,YMax;
  bool LogXScale,LogYScale;
  int bbXMin,bbYMin,bbXMax,bbYMax;
  int LMarg,RMarg,TMarg,BMarg;
  bool Clip;
  string Title;
  bool ShowTitle;
  double TitleXPos,TitleYPos;
  double TitleFontSize;
  double XYLabelFontSize;
  bool XLabelShow,YLabelShow;
  string XLabel,YLabel;
  double XLabelXPos,XLabelYPos;
  double YLabelXPos,YLabelYPos;
  bool DrawBackground;
  string BackgroundColor,DrawColor,ExtraColor,FillColor;
  bool DrawBox;
  double BoxLineWidth;
  bool DrawTics;
  bool DrawXTics;
  bool DrawYTics;
  double ProcSmall;
  double ProcLarge;
  double XTicsSmall;
  double XTicsLarge;
  double YTicsSmall;
  double YTicsLarge;
  double XTicsLabels;
  double YTicsLabels;
  double TicsLineWidth;
  bool DrawLabels;
  bool DrawXLabels;
  bool DrawYLabels;
  double XLabelsXOfs,XLabelsYOfs;
  double YLabelsXOfs,YLabelsYOfs;
  bool TicsAutomatic;
  bool DrawGrid;
  bool DrawGridX;
  bool DrawGridY;
  double GridLineWidth;
  string GridDash;
  double LabelsFontSize;
  string LabelsFormat;
  int accuracy;
  int DrawType;
  double Diameter;  // for Circles and Points
  double DiameterSymbol;  // for symbols
  double LineWidthSymbol;  // for symbols
  double LineWidth; // for lines and rectangles
  EPSOptions(){Reset();};
  void Reset();
  void DefineMinMax(double aXMin, double aXMax, double aYMin, double aYMax){ XMin=aXMin; XMax=aXMax; YMin=aYMin; YMax=aYMax;};
};

class Scale{
public:
  double  a,b;
  double Min,Max;
  double MinOut,MaxOut;
  bool LogScale;
  void Rescale(double aMin,double aMax,double aMinOut,double aMaxOut);
  Scale(double aMin,double aMax,double aMinOut,double aMaxOut, bool aLogScale=false){LogScale=aLogScale; Rescale(aMin,aMax,aMinOut,aMaxOut);};
  Scale(){LogScale=false;};
  double F(double x);
};

inline double LinFun(double x, double a, double b, bool LogScale){return (LogScale?a*log10(x)+b:a*x+b);};

class ScaleXY{
public:
  double  ax,bx,ay,by;
  double MinX,MinY,MaxX,MaxY;
  double MinXOut,MinYOut,MaxXOut,MaxYOut;
  bool LogXScale,LogYScale;
  void Rescale();
  void Rescale(double aMinX,double aMaxX,double aMinY,double aMaxY);
  void Rescale(double aMinX,double aMaxX,double aMinY,double aMaxY,double aMinXOut,double aMaxXOut,double aMinYOut,double aMaxYOut);
  ScaleXY(double aMinX,double aMaxX,double aMinY,double aMaxY,double aMinXOut,double aMaxXOut,double aMinYOut,double aMaxYOut, bool aLogXScale=false, bool aLogYScale=false)
    {LogXScale=aLogXScale; LogYScale=aLogYScale; Rescale(aMinX, aMaxX, aMinY, aMaxY, aMinXOut, aMaxXOut, aMinYOut, aMaxYOut);};
  ScaleXY(){LogXScale=false; LogYScale=false;};
  double FunX(double x){return LinFun(x,ax,bx,LogXScale);}
  //return (LogXScale?ax*log10(x)+bx:ax*x+bx);};
  double FunY(double y){return LinFun(y,ay,by,LogYScale);}
  //{return (LogYScale?ay*log10(y)+by:ay*y+by);};
  int FX(double x){return int(FunX(x)+0.5);};
  int FY(double y){return int(FunY(y)+0.5);};
};

class ScaleXYZ : public ScaleXY {
public:
  double az,bz;
  double MinZ,MaxZ;
  double MinZOut,MaxZOut;
  void Rescale();
  void Rescale(double aMinX, double aMaxX, double aMinY, double aMaxY, double aMinZ=0, double aMaxZ=0);
  void Rescale(double aMinX, double aMaxX, double aMinY, double aMaxY, double aMinXOut, double aMaxXOut, double aMinYOut, double aMaxYOut, double aMinZ=0, double aMaxZ=0, double aMinZOut=0, double aMaxZOut=0);
  ScaleXYZ(double aMinX, double aMaxX, double aMinY, double aMaxY, double aMinXOut, double aMaxXOut, double aMinYOut, double aMaxYOut, double aMinZ=0, double aMaxZ=1, double aMinZOut=0, double aMaxZOut=1)
    {Rescale(aMinX, aMaxX, aMinY, aMaxY, aMinXOut, aMaxXOut, aMinYOut, aMaxYOut, aMinZ, aMaxZ, aMinZOut, aMaxZOut);};
  ScaleXYZ(){};
  double FunZ(double z){return( az*z+bz );};
  int FZ(double z);
};

double GetTicsAutomatic(double MinVal, double MaxVal, bool LogScale);

class SaveEPS : public ScaleXY {
public:
  enum {AlignRight,AlignCenter,AlignLeft,AlignTop,AlignBottom};
  ofstream OutFile;
  int bbXMin,bbXMax,bbYMin,bbYMax;
  SaveEPS(){};
  SaveEPS(char *FileName){OutFile.open(FileName);};
  SaveEPS(string FileName){OutFile.open(FileName.c_str());};
  void open(string FileName){OutFile.open(FileName.c_str());};
  void WriteHeader(const char *creator, const char *title, int abbXMin, int abbYMin, int abbXMax, int abbYMax, int LMarg=0, int RMarg=0, int TMarg=0, int BMarg=0);
  void Finish();
  void WriteDefinitions(double Diameter, string FillColor, string DrawColor);
  void Init(const EPSOptions & EPSOpt);
  void RescaleToBoundingBox(double X1, double X2, double Y1, double Y2);
  // after applying above function you can use S to rescale from X1,X2,Y1,Y2 to bounding box and also use Draw????R with parameters from range X1,X2,Y1,Y2
  void RescaleToBoundingBox(double X1, double X2, double Y1, double Y2, bool aLogXScale, bool aLogYScale);
  void ChangeCoordinates(double MinXOut, double MaxXOut, double MinYOut, double MaxYOut);
  // after applying above function values will be scaled from MinXOut, MaxXOut, MinYOut, MaxYOut to bounding box automatically by eps, !!! does not change behavior of S or Draw????R !!!
  void SetClip(double aMinXOut, double aMaxXOut, double aMinYOut, double aMaxYOut);
  void RescaleToNDigits(double X1, double X2, double Y1, double Y2, int accuracy);
  void OutXTics(double X1, double DX, double X2, double Y1, double Y2);
  void OutYTics(double X1, double DX, double X2, double Y1, double Y2);
  void GetXYTicsAutomatic(double & XTics, double & YTics);
  void DrawXYTics(double XTics,double YTics,double Size, double linewidth=-1);
  void DrawXTicsOnly(double XTics,double Size, double linewidth=-1);
  void DrawYTicsOnly(double YTics,double Size, double linewidth=-1);
  void DrawXYGrid(double XTics,double YTics, double linewidth=-1, const char *dash=0,bool DrawGridX=true, bool DrawGridY=true);
  void DrawStringLatex(string label, double FontSize, double XPos, double YPos);
  void DrawStringLatexR(string label, double FontSize, double XPos, double YPos){DrawStringLatex(label,FontSize,FunX(XPos),FunY(YPos));};
  void DrawXLabels(double XTics,double LabelsFontSize, string LabelsFormat, double XOfs, double YOfs);
  void DrawYLabels(double YTics,double LabelsFontSize, string LabelsFormat, double XOfs, double YOfs);
  void SetColor(const char *Color){ OutFile << Color << " rgb\n"; };
  void SetColorRRGGBB(const char *Color);
  void SetColor(const string & Color){ SetColor(Color.c_str()); };
  void DrawLine(double X1, double Y1, double X2, double Y2){ OutFile << X1 << " " << Y1 << " " << X2 << " " << Y2 << " L\n";};
  void DrawLineR(double X1, double Y1, double X2, double Y2){ DrawLine(FunX(X1),FunY(Y1),FunX(X2),FunY(Y2));};
  void DrawRect(double X1, double Y1, double X2, double Y2){ OutFile << X1 << " " << Y1 << " " << X2 << " " << Y2 << " S\n";};
  void DrawRectR(double X1, double Y1, double X2, double Y2){ DrawRect(FunX(X1),FunY(Y1),FunX(X2),FunY(Y2));};
  void FillRect(double X1, double Y1, double X2, double Y2){ OutFile << X1 << " " << Y1 << " " << X2 << " " << Y2 << " F\n";};
  void FillRectR(double X1, double Y1, double X2, double Y2){ FillRect(FunX(X1),FunY(Y1),FunX(X2),FunY(Y2));};
  void DrawFillRect(double X1, double Y1, double X2, double Y2){ OutFile << X1 << " " << Y1 << " " << X2 << " " << Y2 << " R\n";};
  void DrawFillRectR(double X1, double Y1, double X2, double Y2){ DrawFillRect(FunX(X1),FunY(Y1),FunX(X2),FunY(Y2));};
  void DrawCircle(double X1, double Y1){ OutFile << X1 << " " << Y1 << " C\n"; };
  void DrawCircle(double XPos, double YPos, double Size){ OutFile << "n " << XPos << " " << YPos << " " << Size << " 0 360 arc c s\n";};
  void DrawPoint(double X1, double Y1){ OutFile << X1 << " " << Y1 << " P\n"; };
  void DrawCircleR(double X1, double Y1){ DrawCircle(FunX(X1),FunY(Y1)); };
  void DrawPointR(double X1, double Y1){ DrawPoint(FunX(X1),FunY(Y1)); };
  void DrawBox(double linewidth=-1);
  void FillBackground(string BackgroundColor);
  void SetFont(double FontSize, const char *FontName){ OutFile << "/" << FontName << " ff " << FontSize << " fs\n";};
  void DrawString(double XPos, double YPos, const char *WS, int XAlign=AlignLeft, int YAlign=AlignBottom);
  void DrawStringCenter(double XPos, double YPos, const char *WS){DrawString(XPos,YPos,WS,AlignCenter);};
  void DrawStringRight(double XPos, double YPos, const char *WS){DrawString(XPos,YPos,WS,AlignRight);};
  void DrawStringR(double XPos, double YPos, const char *WS, int XAlign=AlignLeft, int YAlign=AlignBottom){ DrawString(FunX(XPos),FunY(YPos),WS,XAlign,YAlign);};
  void DefSizes(double SizeX, double SizeY);
  void DefSizesAutomatic(double Size){DefSizes(Size*(MaxX-MinX),Size*(MaxY-MinY));}
  void DefSizesAutomaticOut(double Size){DefSizes(Size*(MaxXOut-MinXOut),Size*(MaxYOut-MinYOut));}
  void DefSizesAutomaticOutEqual(double Size){DefSizes(Size*(MaxXOut-MinXOut),Size*(MaxXOut-MinXOut));}
  void DefLineWidth(double Size){ OutFile << Size << " setlinewidth\n";}
  void SetLineWidth(double Size){ OutFile << Size << " setlinewidth\n";}
  void SetDash(const char *dash){ OutFile << dash << " setdash\n";}
  void SetDash(const string & dash){ SetDash(dash.c_str());}
  void DefLineWidthAutomatic(double Size){DefLineWidth(Size*(MaxX-MinX));};
  void DefLineWidthAutomaticOut(double Size){DefLineWidth(Size*(MaxXOut-MinXOut));};
  void DrawSymbol(char c, double XPos, double YPos, double Size=1){ OutFile << XPos << " " << YPos << " " << c << endl;}
  void DrawSymbolR(char c, double XPos, double YPos, double Size=1){ DrawSymbol(c,FunX(XPos),FunY(YPos),Size);}
  void DrawCircleR(double XPos, double YPos, double Size){DrawCircle(FunX(XPos),FunY(YPos),ax*Size);};
  void ShowInfo(double XPos, double YPos, double Length, const char *color, double LineWidth, char symbol, double SymbolLineWidth, const char *info, double InfoOfset); 
  void ShowData(vector <double> &x, vector <double> &y, char *color, double LineWidth, char symbol, double SymbolLineWidth);
  void ShowLegend(Legend &legend, LegendPos Pos=TopRight, double XPos=10, double YPos=10, double FontSize=18, double VertOffsetBottom=10, double EntryHeight=15, double VertOffsetTop=-5, double HorOffset=5, double LineLength=30, double InfoLength=50, double LineWidth=0.5, double SymbolLineWidth=2.0);
};

#define __eps_h __eps_h

#endif