eps.cpp
#include <math.h>
#include <time.h>
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <sstream>
#include <boost/algorithm/string/replace.hpp>

#include "eps.h" 

void Legend::AddEntry(char *acolor, char asymbol, char *ainfo){
  if (EntryNum>=MaxEntryNum){
    cerr << "legend: too many entries" << endl;
    return;
  }
  Entry[EntryNum].color=acolor;
  Entry[EntryNum].symbol=asymbol;
  Entry[EntryNum].info=ainfo;
  EntryNum++;
}

void Scale::Rescale(double aMin,double aMax,double aMinOut,double aMaxOut){
  Min=aMin;   MinOut=aMinOut;
  Max=aMax;   MaxOut=aMaxOut;
  a=(MaxOut-MinOut)/(Max-Min);
  b=MinOut-Min*a;
}

double Scale::F(double x){
  if (LogScale){
    return a*log10(x)+b;
  } else {
    if (a*x+b>MaxOut+100*(MaxOut-MinOut)) return MaxOut+100*(MaxOut-MinOut);
    if (a*x+b<MinOut-100*(MaxOut-MinOut)) return MinOut-100*(MaxOut-MinOut);
    return( a*x+b );
  }
}

void ScaleXY::Rescale(){
  if (LogXScale){
    if (MinX<=0.0 || MaxX<=0.0){
      cerr << "Out of range in log scale" << endl;
      return;
    }
    ax=(MaxXOut-MinXOut)/(log10(MaxX)-log10(MinX));
    bx=MinXOut-log10(MinX)*ax;
  } else {
    if (fabs(MaxX-MinX)<1e-100) return;
    ax=(MaxXOut-MinXOut)/(MaxX-MinX);
    bx=MinXOut-MinX*ax;
  }
  if (LogYScale){
    if (MinY<=0.0 || MaxY<=0.0){
      cerr << "Out of range in log scale" << endl;
      return;
    }
    ay=(MaxYOut-MinYOut)/(log10(MaxY)-log10(MinY));
    by=MinYOut-log10(MinY)*ay;
  } else {
    if (fabs(MaxY-MinY)<1e-100) return;
    ay=(MaxYOut-MinYOut)/(MaxY-MinY);
    by=MinYOut-MinY*ay;
  }
}

void ScaleXY::Rescale(double aMinX,double aMaxX,double aMinY,double aMaxY){
  MinX=aMinX;   MaxX=aMaxX;   
  MinY=aMinY;   MaxY=aMaxY; 
  Rescale();
}

void ScaleXY::Rescale(double aMinX,double aMaxX,double aMinY,double aMaxY,double aMinXOut,double aMaxXOut,double aMinYOut,double aMaxYOut){
  MinX=aMinX;   MaxX=aMaxX;   
  MinY=aMinY;   MaxY=aMaxY;   
  MinXOut=aMinXOut; MaxXOut=aMaxXOut;
  MinYOut=aMinYOut; MaxYOut=aMaxYOut;
  Rescale();
}

int ScaleXYZ::FZ(double z){
  int res=int(az*z+bz+0.5);
  if (res>MaxZOut) return res=int(MaxZOut);
  if (res<MinZOut) return res=int(MinZOut);
  return res;
}

void ScaleXYZ::Rescale(){
  if (fabs(MaxX-MinX)>1e-10) {
    ax=(MaxXOut-MinXOut)/(MaxX-MinX);
    bx=MinXOut-MinX*ax;
  }
  if (fabs(MaxY-MinY)>1e-10) {
    ay=(MaxYOut-MinYOut)/(MaxY-MinY);
    by=MinYOut-MinY*ay;
  }
  if (fabs(MaxZ-MinZ)>1e-10){
    az=(MaxZOut-MinZOut)/(MaxZ-MinZ);
    bz=MinZOut-MinZ*az;
  }
}

void ScaleXYZ::Rescale(double aMinX, double aMaxX, double aMinY, double aMaxY, double aMinZ, double aMaxZ){
  if (aMinX!=aMaxX){ MinX=aMinX;   MaxX=aMaxX;}
  if (aMinY!=aMaxY){ MinY=aMinY;   MaxY=aMaxY;}
  if (aMinZ!=aMaxZ){ MinZ=aMinZ;   MaxZ=aMaxZ;}
  Rescale();
}

void ScaleXYZ::Rescale(double aMinX, double aMaxX, double aMinY, double aMaxY, double aMinXOut, double aMaxXOut, double aMinYOut, double aMaxYOut, double aMinZ, double aMaxZ, double aMinZOut, double aMaxZOut){
  if (aMinX!=aMaxX){ MinX=aMinX;   MaxX=aMaxX;}
  if (aMinY!=aMaxY){ MinY=aMinY;   MaxY=aMaxY;}
  if (aMinZ!=aMaxZ){ MinZ=aMinZ;   MaxZ=aMaxZ;}
  MinXOut=aMinXOut; MaxXOut=aMaxXOut;
  MinYOut=aMinYOut; MaxYOut=aMaxYOut;
  MinZOut=aMinZOut; MaxZOut=aMaxZOut;
  Rescale();  
}

void TodayASCII(char date_buf[20]){
  struct tm now;
  time_t dnow = time(0);
  now = *localtime(&dnow);
  sprintf(date_buf, "%.2d/%.2d/%.2d  %.2d:%.2d:%.2d",now.tm_mday,now.tm_mon,now.tm_year % 100,now.tm_hour, now.tm_min,now.tm_sec);
}

void SaveEPS::WriteHeader(const char *creator, const char *title, int abbXMin, int abbYMin, int abbXMax, int abbYMax, int LMarg, int RMarg, int TMarg, int BMarg){
  bbXMin=abbXMin;    bbXMax=abbXMax;
  bbYMin=abbYMin;    bbYMax=abbYMax;
  OutFile << "%!PS-Adobe-2.0 EPSF-1.2\n" ;
  OutFile << "%%Creator: " << creator << endl;
  OutFile << "%%Title: " << title << endl;
  char DateStr[20];
  TodayASCII(DateStr);
  OutFile << "%%CreationDate: " << DateStr << "\n" ;
  OutFile << "%%Pages: 1\n" ;
  OutFile << "%%BoundingBox:  " << bbXMin-1-LMarg << " " << bbYMin-BMarg << " " << bbXMax+RMarg << " " << bbYMax+1+TMarg << "\n" ;
  OutFile << "%%EndComments\n" ; 
}

void SaveEPS::Finish(){
  OutFile << "showpage\n";
  OutFile << "%%Trailer\n";
  OutFile << "%%EOF\n";
  OutFile.close();
}

void SaveEPS::WriteDefinitions(double Diameter, string FillColor, string DrawColor){
  OutFile << "/bd {bind def} bind def\n";
  OutFile << "/i {index} bd\n";
  OutFile << "/m {moveto} bd\n";
  OutFile << "/rm {rmoveto} bd\n";
  OutFile << "/l {lineto} bd\n";
  OutFile << "/rl {rlineto} bd\n";
  OutFile << "/n {newpath} bd\n";
  OutFile << "/c {closepath} bd\n";
  OutFile << "/s {stroke} bd\n";
  OutFile << "/f {fill} bd\n";
  OutFile << "/p {pop} bd\n";
  OutFile << "/p4 {pop pop pop pop} bd\n";
  OutFile << "/rgb {setrgbcolor} bd\n";
  OutFile << "/white {1 1 1 rgb} bd\n";
  OutFile << "/black {0 0 0 rgb} bd\n";
  OutFile << "/red {1 0 0 rgb} bd\n";
  OutFile << "/green {0 1 0 rgb} bd\n";
  OutFile << "/blue {0 0 1 rgb} bd\n";
  OutFile << "/S {n 3 i 3 i m 3 i 1 i l 1 i 1 i l 1 i 3 i l p4 c s} bd\n";
  OutFile << "/F {n 3 i 3 i m 3 i 1 i l 1 i 1 i l 1 i 3 i l p4 c f} bd\n";
  OutFile << "/C {n dxhalf 0 360 arc c f} bd\n";
  OutFile << "/R {n fillcol 3 i 3 i m 3 i 1 i l 1 i 1 i l 1 i 3 i l c f drawcol 3 i 3 i m 3 i 1 i l 1 i 1 i l 1 i 3 i l c s p4} bd\n";
  OutFile << "/P {exch dxhalf sub exch dyhalf sub 1 i dx add 1 i dy add F} bd\n";
  OutFile << "/L {n m l c s} bd\n";
  OutFile << "/sw {stringwidth} bd\n";
  OutFile << "/XH {gsave n 0 0 m (X) false charpath flattenpath pathbbox grestore 4 1 roll p p p} bd %height of 'X'\n";
  OutFile << "/XW {gsave n 0 0 m (X) false charpath flattenpath pathbbox grestore p 3 1 roll p p} bd %width of 'X'\n";
  OutFile << "/sbs {0 XH -0.4 mul rm} bd %subscript ofset\n";
  //  OutFile << "/sbs {0 XH -0.7 mul rm} bd %subscript ofset\n";
  OutFile << "/sps {0 XH 0.7 mul rm} bd %superscript ofset\n";
  OutFile << "/printobject{ dup 128 string cvs dup (--nostringval--) eq { pop type 24 string cvs }{ exch pop } ifelse} bd\n";
  OutFile << "FontDirectory printobject StandardEncoding printobject\n";

  OutFile << "/normalfontsize {24} bd\n";
  OutFile << "/normalfonttype {/Times-Roman} bd\n";
  OutFile << "/msetfont {normalfonttype findfont exch scalefont setfont} bd\n";
  OutFile << "/mshow {normalfontsize msetfont show} bd\n";
  OutFile << "/msubshow {sbs normalfontsize 0.7 mul msetfont show normalfontsize msetfont sps} bd\n";
  OutFile << "/msupshow {sps normalfontsize 0.7 mul msetfont show normalfontsize msetfont sbs} bd\n";

  OutFile << "0 setlinewidth\n";
  OutFile << "0 setgray\n"; // 100% black
  // define symbols
  OutFile << "%Symbols\n";
  // 1.273=4/pi
  OutFile << "/o {n dxhalfsq 1.273 mul 0 360 arc c s} bd\n";
  OutFile << "/O {n dxhalfsq 1.273 mul 0 360 arc c f} bd\n";
  OutFile << "/k {dxhalfsq sub exch dyhalfsq sub exch 1 i dxsq add 1 i dysq add S} bd\n";
  OutFile << "/K {dxhalfsq sub exch dyhalfsq sub exch 1 i dxsq add 1 i dysq add F} bd\n";
  OutFile << "/x {n 1 i dxhalfsq sub 1 i dyhalfsq sub m dxsq dysq rl exch dxhalfsq sub exch dyhalfsq add m dxsq dynegsq rlineto c s} bd\n";
  OutFile << "/+ {n 1 i dxhalf sub 1 i m dx 0 rl dyhalf add m 0 dyneg rl c s} bd\n";  
  OutFile << "/* {dup 2 i dup 2 i + 1 i x} bd\n";  
  OutFile << "/d {n 1 i dxhalf sub 1 i m dxhalf dyhalf rl dxhalf dyhalfneg rl dxhalfneg dyhalfneg rl c s} bd\n";
  OutFile << "/D {n 1 i dxhalf sub 1 i m dxhalf dyhalf rl dxhalf dyhalfneg rl dxhalfneg dyhalfneg rl c f} bd\n";
  // define colors (used by R)
  OutFile << "/fillcol {" << FillColor << " rgb} bd\n";
  OutFile << "/drawcol {" << DrawColor << " rgb} bd\n";
  // def sizes
  OutFile << "/dxneg {0 dx sub} bd\n";
  OutFile << "/dyneg {0 dy sub} bd\n";
  OutFile << "/dxhalf {dx 2 div} bd\n";
  OutFile << "/dyhalf {dy 2 div} bd\n";
  OutFile << "/dxhalfneg {0 dxhalf sub} bd\n";
  OutFile << "/dyhalfneg {0 dyhalf sub} bd\n";
  OutFile << "/dxhalfsq {dxhalf 1.41421 div} bd\n";
  OutFile << "/dyhalfsq {dyhalf 1.41421 div} bd\n";
  OutFile << "/dxsq {dx 1.41421 div} bd\n";
  OutFile << "/dysq {dy 1.41421 div} bd\n";
  OutFile << "/dxnegsq {dxneg 1.41421 div} bd\n";
  OutFile << "/dynegsq {dyneg 1.41421 div} bd\n";
  OutFile << "/ff {findfont} bd\n";
  OutFile << "/fs {scalefont setfont} bd\n";
  DefSizes(Diameter,Diameter);
}

void SaveEPS::Init(const EPSOptions & EPSOpt){
  WriteHeader(EPSOpt.EPSFileCreator.c_str(),EPSOpt.EPSFileTitle.c_str(),EPSOpt.bbXMin,EPSOpt.bbYMin,EPSOpt.bbXMax,EPSOpt.bbYMax,EPSOpt.LMarg,EPSOpt.RMarg,EPSOpt.TMarg,EPSOpt.BMarg);

  WriteDefinitions(EPSOpt.Diameter,EPSOpt.FillColor,EPSOpt.DrawColor);

  if (EPSOpt.DrawBackground){
    OutFile << EPSOpt.BackgroundColor << " rgb\n";
    FillRect(EPSOpt.bbXMin-1-EPSOpt.LMarg,EPSOpt.bbYMin-EPSOpt.BMarg,EPSOpt.bbXMax+EPSOpt.RMarg,EPSOpt.bbYMax+1+EPSOpt.TMarg);
    //    FillBackground(EPSOpt.BackgroundColor);
  }

  OutFile << "gsave\n";

  RescaleToBoundingBox(0,1,0,1);
  OutFile.precision(5);

  SetColor("0 0 0");
  if (EPSOpt.ShowTitle) DrawStringLatexR(EPSOpt.Title,EPSOpt.TitleFontSize,EPSOpt.TitleXPos,EPSOpt.TitleYPos);
  if (EPSOpt.XLabelShow) DrawStringLatexR(EPSOpt.XLabel,EPSOpt.XYLabelFontSize,EPSOpt.XLabelXPos,EPSOpt.XLabelYPos);
  if (EPSOpt.YLabelShow) DrawStringLatexR(EPSOpt.YLabel,EPSOpt.XYLabelFontSize,EPSOpt.YLabelXPos,EPSOpt.YLabelYPos);

  OutFile << "grestore\n";

  LogXScale=EPSOpt.LogXScale;
  LogYScale=EPSOpt.LogYScale;

  OutFile << "gsave\n";

  RescaleToBoundingBox(EPSOpt.XMin,EPSOpt.XMax,EPSOpt.YMin,EPSOpt.YMax);
  OutFile << "0 0 0 rgb" << endl;
  
  if (EPSOpt.DrawGrid){
    double XTics=EPSOpt.XTicsLarge;
    double YTics=EPSOpt.YTicsLarge;
    if (EPSOpt.TicsAutomatic) GetXYTicsAutomatic(XTics,YTics);
    DrawXYGrid(XTics,YTics,EPSOpt.GridLineWidth,EPSOpt.GridDash.c_str(),EPSOpt.DrawGridX,EPSOpt.DrawGridY);
  }

  OutFile << "%DrawBox" << endl;
  if (EPSOpt.DrawBox) DrawBox(EPSOpt.BoxLineWidth);
  if (EPSOpt.DrawTics) {
    //    SetLineWidth(EPSOpt.TicsLineWidth);
    double XTics=EPSOpt.XTicsLarge;
    double YTics=EPSOpt.YTicsLarge;
    if (EPSOpt.TicsAutomatic) GetXYTicsAutomatic(XTics,YTics);
    if (EPSOpt.DrawXTics){
      DrawXTicsOnly(0.2*XTics,EPSOpt.ProcSmall,EPSOpt.TicsLineWidth);
      DrawXTicsOnly(XTics,EPSOpt.ProcLarge,EPSOpt.TicsLineWidth);
    }
    if (EPSOpt.DrawYTics){
      DrawYTicsOnly(0.2*YTics,EPSOpt.ProcSmall,EPSOpt.TicsLineWidth);
      DrawYTicsOnly(YTics,EPSOpt.ProcLarge,EPSOpt.TicsLineWidth);
    }
  }

  if (EPSOpt.DrawLabels){
    double XTics=EPSOpt.XTicsLabels;
    double YTics=EPSOpt.YTicsLabels;
    if (EPSOpt.TicsAutomatic) GetXYTicsAutomatic(XTics,YTics);
    if (EPSOpt.DrawXLabels) DrawXLabels(XTics,EPSOpt.LabelsFontSize,EPSOpt.LabelsFormat,EPSOpt.XLabelsXOfs,EPSOpt.XLabelsYOfs);
    if (EPSOpt.DrawYLabels) DrawYLabels(YTics,EPSOpt.LabelsFontSize,EPSOpt.LabelsFormat,EPSOpt.YLabelsXOfs,EPSOpt.YLabelsYOfs);
  }

  if (EPSOpt.Clip) SetClip(EPSOpt.bbXMin,EPSOpt.bbXMax,EPSOpt.bbYMin,EPSOpt.bbYMax); 
  SetColor(EPSOpt.DrawColor.c_str());
  SetLineWidth(EPSOpt.LineWidth);
}

void SaveEPS::SetColorRRGGBB(const char *Color){
  int digitnum=6;
  if (int(strlen(Color))!=digitnum){
    cerr << "Wrong color" << endl;
    return;
  }
  int d[digitnum];
  for (int i=0;i<digitnum;i++){
    d[i]=0;
    if (Color[i]>='0' && Color[i]<='9') d[i]=int(Color[i]-'0');
    if (Color[i]>='A' && Color[i]<='F') d[i]=int(10+Color[i]-'A');
    if (Color[i]>='a' && Color[i]<='f') d[i]=int(10+Color[i]-'a');
  }
  for (int i=0;i<3;i++){
    double c=(16*d[2*i]+d[2*i+1])/255.0;
    OutFile << setprecision(3) << c << ' ';
  }
  OutFile << "rgb\n";
}

void SaveEPS::OutXTics(double X1, double DX, double X2, double Y1, double Y2){
  OutFile << "n\n";
  OutFile << X1 << ' ' << DX << ' ' << X2 << "{\n";
  OutFile << "  dup " << Y1 << " m "<<  Y2 << " l\n";
  OutFile << "} for\n";
  OutFile << "c s\n";
}

void SaveEPS::OutYTics(double X1, double DX, double X2, double Y1, double Y2){
  OutFile << "n\n";
  OutFile << X1 << ' ' << DX << ' ' << X2 << "{\n";
  OutFile << "  dup " << Y1 << " exch m " << Y2 << " exch l\n";
  OutFile << "} for\n";
  OutFile << "c s\n";
}

void SaveEPS::DrawXYTics(double XTics, double YTics, double Size, double linewidth){
  if (linewidth>=0) OutFile << linewidth << " setlinewidth\n";
  OutXTics(FunX(ceil(MinX/XTics)*XTics),ax*XTics,FunX(MaxX),FunY(MinY),FunY(MinY) + Size);
  OutXTics(FunX(ceil(MinX/XTics)*XTics),ax*XTics,FunX(MaxX),FunY(MaxY),FunY(MaxY) - Size);
  OutYTics(FunY(ceil(MinY/YTics)*YTics),ay*YTics,FunY(MaxY),FunX(MinX),FunX(MinX) + Size);
  OutYTics(FunY(ceil(MinY/YTics)*YTics),ay*YTics,FunY(MaxY),FunX(MaxX),FunX(MaxX) - Size);
}

void SaveEPS::DrawXTicsOnly(double XTics, double Size, double linewidth){
  if (linewidth>=0) OutFile << linewidth << " setlinewidth\n";
  OutXTics(FunX(ceil(MinX/XTics)*XTics),ax*XTics,FunX(MaxX),FunY(MinY),FunY(MinY) + Size);
  OutXTics(FunX(ceil(MinX/XTics)*XTics),ax*XTics,FunX(MaxX),FunY(MaxY),FunY(MaxY) - Size);
}

void SaveEPS::DrawYTicsOnly(double YTics, double Size, double linewidth){
  if (linewidth>=0) OutFile << linewidth << " setlinewidth\n";
  OutYTics(FunY(ceil(MinY/YTics)*YTics),ay*YTics,FunY(MaxY),FunX(MinX),FunX(MinX) + Size);
  OutYTics(FunY(ceil(MinY/YTics)*YTics),ay*YTics,FunY(MaxY),FunX(MaxX),FunX(MaxX) - Size);
}

void SaveEPS::DrawXYGrid(double XTics,double YTics, double linewidth, const char *dash, bool DrawGridX, bool DrawGridY){
  if (DrawGridX){
    if (linewidth>=0) SetLineWidth(linewidth);
    if (dash) SetDash(dash);
    if (LogXScale){
      int pot=int(ceil(log10(1.00001*MinX)/log10(XTics)));
      double X=1.0;
      for (int i=0;i<abs(pot);i++) X*=XTics;
      if (pot<0) X=1.0/X;
      double Y1=FunY(MinY);
      double Y2=FunY(MaxY);
      while (true){
	OutFile << FunX(X) << " " << Y1 << " " << FunX(X) << " " << Y2 << " L\n";
	X*=XTics;
	if (X>MaxX) break;
      }
    } else {
      double X1,X2,Y1,Y2,DX;
      X1=FunX((ceil(MinX/XTics))*XTics);
      DX=ax*XTics;
      X2=FunX(MaxX)+0.001*DX;
      Y1=FunY(MinY);
      Y2=FunY(MaxY);
      OutFile << "n\n";
      OutFile << X1 << ' ' << DX << ' ' << X2 << "{\n";
      OutFile << "  dup " << Y1 << " m "<<  Y2 << " l\n";
      OutFile << "} for\n";
      OutFile << "s\n";
    }
  }

  if (DrawGridY){     
    if (LogYScale){
      int pot=int(ceil(log10(1.00001*MinY)/log10(YTics)));
      double Y=1.0;
      for (int i=0;i<abs(pot);i++) Y*=YTics;
      if (pot<0) Y=1.0/Y;
      double X1=FunX(MinX);
      double X2=FunX(MaxX);
      while (true){
	OutFile << X1 << " " << FunY(Y) << " " << X2 << " " << FunY(Y) << " L\n";
	Y*=YTics;
	if (Y>MaxY) break;
      }
    } else {
      double X1,X2,Y1,Y2,DX;
      X1=FunY((ceil(MinY/YTics))*YTics);
      DX=ay*YTics;
      X2=FunY(MaxY)+0.001*DX;
      Y1=FunX(MinX);
      Y2=FunX(MaxX);
      OutFile << "n\n";
      OutFile << X1 << ' ' << DX << ' ' << X2 << "{\n";
      OutFile << "  dup " << Y1 << " exch m " << Y2 << " exch l\n";
      OutFile << "} for\n";
      OutFile << "s\n";
    }
  }
  if (dash) SetDash("[] 0");
}

double GetTicsAutomatic(double MinVal, double MaxVal, bool LogScale){
  double Tics=1.0;
  if (LogScale){
    Tics=10.0;
    int nummax=8;
    while (true){
      double range=log10(MaxVal/MinVal);
      int num=int(range/log10(Tics));
      if (num<=nummax) break;
      Tics*=10;
    }
  } else {
    Tics=1.0;
    int nummax=10;
    int nummin=4;
    int iter=0;
    while (true){
      //      double X1=LinFun((ceil(MinVal/Tics))*Tics,a,b,LogScale);
      //      double D=a*Tics;
      //      double X2=LinFun(MaxVal,a,b,LogScale)+0.00001*D;
      double X1=(ceil(MinVal/Tics))*Tics;
      double D=Tics;
      double X2=MaxVal+0.00001*D;
      //      double Y2=FunY(MaxVal);
      int num=int(ceil((X2-X1)/D));
      if (num>=nummin && num<=nummax) break;
      if (num<nummin) Tics/=(iter%2==0?2.0:5.0);
      if (num>nummax) Tics*=(iter%2==0?2.0:5.0);
      iter++;
    }
  }
  return Tics;
}

void SaveEPS::GetXYTicsAutomatic(double & XTics, double & YTics){
  XTics=GetTicsAutomatic(MinX,MaxX,LogXScale);
  YTics=GetTicsAutomatic(MinY,MaxY,LogYScale);
  //  cout << XTics << " " << YTics << endl;
}

string Double2String(double x){
  ostringstream oss;
  oss << x;
  string s=oss.str();
  boost::replace_all(s, "e-0", "e-");
  return s;
}

string Double2String(double x, int precision){
  ostringstream oss;
  oss.precision(precision);
  oss << x;
  return oss.str();
}

void SaveEPS::DrawXLabels(double XTics,double LabelsFontSize, string LabelsFormat, double XOfs, double YOfs){
  SetFont(LabelsFontSize,"Times-Roman");
  if (LogXScale){
    int pot=int(ceil(log10(0.99999*MinX)/log10(XTics)));
    int incr=int(floor(log10(1.0001*XTics)));
    pot*=incr;
    double X=1.0;
    for (int i=0;i<abs(pot);i++) X*=10.0;
    if (pot<0) X=1.0/X;
    OutFile << "/normalfontsize {" << LabelsFontSize << "} bd\n";
    OutFile << "/normalfonttype {/Times-Roman} bd\n";
    while (true){
      char WS[50]="10";
      //      DrawString(FunX(X)+XOfs,FunY(MinY)+YOfs,WS,AlignCenter,AlignBottom);
      sprintf(WS,"%d",pot);
      // set display position (move to FunX(X)+XOfs and move back by half of width of "10"
      OutFile << "n " << FunX(X)+XOfs << " " << FunY(MinY)+YOfs << " m\n";
      OutFile << "(10) sw pop -0.5 mul " // XOffset
	      << " XH -0.3 mul rm\n"; // YOffset
      OutFile << "(10) show\n";
      OutFile << "(" << WS << ") msupshow\n";
      pot+=incr;
      X*=XTics;
      if (X>MaxX) break;
    }
  } else {
    for (double XPos=ceil(MinX/XTics)*XTics;XPos<=MaxX;XPos+=XTics){
      if (fabs(XPos)<1e-10) XPos=0;
      /*      char WS[50];
      sprintf(WS,LabelsFormat.c_str(),XPos);
      for (unsigned int i=0;i<strlen(WS);i++) if (WS[i]==',') WS[i]='.';
      char *dotpos=index(WS,'.');
      if (dotpos!=NULL){
	while (strlen(WS)>0 && WS[strlen(WS)-1]=='0') WS[strlen(WS)-1]='\0';
      }
      if (WS[strlen(WS)-1]=='.') WS[strlen(WS)-1]='\0';
      DrawString(FunX(XPos)+XOfs,FunY(MinY)+YOfs,WS,AlignCenter,AlignBottom);
      */
      string s=Double2String(XPos,10);
      DrawString(FunX(XPos)+XOfs,FunY(MinY)+YOfs,s.c_str(),AlignCenter,AlignBottom);
    }
  }
}

void SaveEPS::DrawYLabels(double YTics,double LabelsFontSize, string LabelsFormat, double XOfs, double YOfs){
  SetFont(LabelsFontSize,"Times-Roman");
  if (LogYScale){
    int pot=int(ceil(log10(0.99999*MinY)/log10(YTics)));
    int incr=int(floor(log10(1.0001*YTics)));
    pot*=incr;
    double Y=1.0;
    for (int i=0;i<abs(pot);i++) Y*=10;
    if (pot<0) Y=1.0/Y;
    OutFile << "/normalfontsize {" << LabelsFontSize << "} bd\n";
    OutFile << "/normalfonttype {/Times-Roman} bd\n";
    while (true){
      char WS[50]="10";
      //      DrawString(FunX(MinX)+XOfs,FunY(YPos)+YOfs,WS,AlignRight,AlignCenter);
      sprintf(WS,"%d",pot);
      // set display position (move to FunX(X)+XOfs and move back by the width of "10"
      OutFile << "n " << FunX(MinX)+XOfs << " " << FunY(Y)+YOfs << " m\n";
      OutFile << " (10) sw pop -1.0 mul " << "(" << WS << ") sw pop -0.7 mul add " // Xoffset
      	      << " XW -0.5 mul rm\n"; // Yoffset
      OutFile << "(10) show\n";
      OutFile << "(" << WS << ") msupshow\n";
      pot+=incr;
      Y*=YTics;
      if (Y>MaxY) break;
    }
  } else {
    for (double YPos=ceil(MinY/YTics)*YTics;YPos<=MaxY;YPos+=YTics){
      //      char WS[20];
      if (fabs(YPos)<1e-10) YPos=0;
      /*
      sprintf(WS,LabelsFormat.c_str(),YPos);
      for (unsigned int i=0;i<strlen(WS);i++) if (WS[i]==',') WS[i]='.';
      char *dotpos=index(WS,'.');
      if (dotpos!=NULL){
	while (strlen(WS)>0 && WS[strlen(WS)-1]=='0') WS[strlen(WS)-1]='\0';
      }
      if (WS[strlen(WS)-1]=='.') WS[strlen(WS)-1]='\0';
      DrawString(FunX(MinX)+XOfs,FunY(YPos)+YOfs,WS,AlignRight,AlignCenter);*/
      string s=Double2String(YPos);
      DrawString(FunX(MinX)+XOfs,FunY(YPos)+YOfs,s.c_str(),AlignRight,AlignCenter);
    }
  }
}

void SaveEPS::DrawBox(double linewidth){
  OutFile << "0 setgray\n";
  if (linewidth>=0) SetLineWidth(linewidth);
  DrawRectR(MinX,MinY,MaxX,MaxY);
}

void SaveEPS::FillBackground(string BackgroundColor){
  OutFile << BackgroundColor << " rgb\n";
  FillRectR(MinX,MinY,MaxX,MaxY);
}

void SaveEPS::ChangeCoordinates(double aMinXOut, double aMaxXOut, double aMinYOut, double aMaxYOut){
  OutFile << 1.0*(bbXMax-bbXMin)/(aMaxXOut-aMinXOut) << " " << 1.0*(bbYMax-bbYMin)/(aMaxYOut-aMinYOut) << " scale\n";
  OutFile << -aMinXOut << " " << -aMinYOut << " translate\n";
}

void SaveEPS::SetClip(double aMinXOut, double aMaxXOut, double aMinYOut, double aMaxYOut){
  OutFile << "n " << aMinXOut << " " << aMinYOut << " m " 
                  << aMaxXOut << " " << aMinYOut << " l " 
                  << aMaxXOut << " " << aMaxYOut << " l " 
                  << aMinXOut << " " << aMaxYOut << " l c clip\n";
}

void SaveEPS::RescaleToBoundingBox(double X1, double X2, double Y1, double Y2){
  Rescale(X1,X2,Y1,Y2,bbXMin,bbXMax,bbYMin,bbYMax);
  OutFile << "/FX {" << ax << " mul " << bx << " add " << "} bd" << endl;
  OutFile << "/FY {" << ay << " mul " << by << " add " << "} bd" << endl;
  OutFile << "/FXY {exch FX exch FY} bd" << endl;
  // it is possible to use current values and add FX, FY or FXY to convert to Bounding Box
}

void SaveEPS::RescaleToBoundingBox(double X1, double X2, double Y1, double Y2, bool aLogXScale, bool aLogYScale){
  LogXScale=aLogXScale;
  LogYScale=aLogYScale;
  Rescale(X1,X2,Y1,Y2,bbXMin,bbXMax,bbYMin,bbYMax);
  OutFile << "/FX {" << ax << " mul " << bx << " add " << "} bd" << endl;
  OutFile << "/FY {" << ay << " mul " << by << " add " << "} bd" << endl;
  OutFile << "/FXY {exch FX exch FY} bd" << endl;
  // it is possible to use current values and add FX, FY or FXY to convert to Bounding Box
}

void SaveEPS::RescaleToNDigits(double X1, double X2, double Y1, double Y2, int accuracy){
  int Acc=accuracy;
  int AccMax=1;
  for (int i=1;i<=Acc;i++) AccMax*=10;
  int XR=bbXMax-bbXMin;
  int YR=bbYMax-bbYMin;
  int xmin=AccMax/10;
  int xmax=AccMax-1;
  int ymin=AccMax/10;
  int ymax=AccMax-1;
  if (XR<YR){
    xmax=xmin+(AccMax-1-AccMax/10)*XR/YR;
  }
  if (YR<XR){
    ymax=ymin+(AccMax-1-AccMax/10)*YR/XR;
  }
  ChangeCoordinates(xmin,xmax,ymin,ymax);
  Rescale(X1,X2,Y1,Y2,xmin,xmax,ymin,ymax);
  OutFile.precision(Acc);
  SetClip(xmin,xmax,ymin,ymax);
}

void SaveEPS::DrawString(double XPos, double YPos, const char *WS, int XAlign, int YAlign){
  OutFile << "n " << XPos << " "<< YPos << " m\n";
  OutFile << "(" << WS << ") ";
  switch (XAlign){
    case AlignRight: OutFile << "dup sw p -1 mul "; break;
    case AlignCenter: OutFile << "dup sw p 2 div -1 mul "; break;
    case AlignLeft: OutFile << "0 "; break;
  }
  switch (YAlign){
    case AlignBottom: OutFile << "0 "; break;
    case AlignCenter: OutFile << "XW -0.5 mul "; break;
    case AlignTop:    OutFile << "XW -1 mul "; break;
  }
  OutFile << "rm show\n";
}

void SaveEPS::DrawStringLatex(string label, double FontSize, double XPos, double YPos){
  OutFile << "n " << XPos << " "<< YPos << " m\n";
  OutFile << "/normalfontsize {" << FontSize << "} bd\n";
  OutFile << "/normalfonttype {/" << "Times-Italic" << "} bd\n";
  bool NextDn=false;
  bool NextUp=false;
  for (unsigned int i=0;i<label.size();i++){
    switch(label.c_str()[i]){
      case '_': NextDn=true; NextUp=false; break;
      case '^': NextUp=true; NextDn=false; break;
      case '\n': NextUp=false; NextDn=false; break;
      case '\\': {
        i++;
        bool ControlChar=true;
        if (i<label.size()){
          switch (label.c_str()[i]){ 
          case 's': OutFile << "/normalfonttype {/" << "Symbol" << "} bd\n"; break;
          case 'r': OutFile << "/normalfonttype {/" << "Times-Roman" << "} bd\n"; break;
          case 'i': OutFile << "/normalfonttype {/" << "Times-Italic" << "} bd\n"; break;
          default: ControlChar=false;
          }
        }
        if (ControlChar) break;
      } 
      default:
        if (label.c_str()[i]=='(' || label.c_str()[i]==')') OutFile << "(\\" << label.c_str()[i] << ")";
        else OutFile << "(" << label.c_str()[i] << ")";
        if (NextDn) OutFile << "msubshow\n";
        if (NextUp) OutFile << "msupshow\n";
        if (!NextUp && !NextDn) OutFile << "mshow\n";
	//        NextDn=false;
	//        NextUp=false;
        break;
    }
  }
}

void SaveEPS::DefSizes(double SizeX, double SizeY){
  OutFile << "/dx {" << SizeX << "} bd\n";
  OutFile << "/dy {" << SizeY << "} bd\n";
}

void SaveEPS::ShowInfo(double XPos, double YPos, double Length, const char *color, double LineWidth, char symbol, double SymbolLineWidth, const char *info, double InfoOfset){
  SetColor(color);
  SetLineWidth(LineWidth);
  DrawLine(XPos,YPos,XPos+Length,YPos);
  SetLineWidth(SymbolLineWidth);
  DrawSymbol(symbol,XPos+0.5*Length,YPos);
  SetColor("0 0 0");
  DrawString(XPos+Length+InfoOfset,YPos,info,SaveEPS::AlignLeft,SaveEPS::AlignCenter);
}

void SaveEPS::ShowData(vector <double> &x, vector <double> &y, char *color, double LineWidth, char symbol, double SymbolLineWidth){
  SetColor(color);
  SetLineWidth(SymbolLineWidth);
  for (unsigned int i=0;i<x.size();i++) DrawSymbolR(symbol,x[i],y[i]);
  SetLineWidth(LineWidth);
  for (unsigned int i=1;i<x.size();i++) DrawLineR(x[i-1],y[i-1],x[i],y[i]);
}

void SaveEPS::ShowLegend(Legend &legend, LegendPos Pos, double XDist, double YDist, double FontSize, double VertOffsetBottom, double EntryHeight, double VertOffsetTop, double HorOffset, double LineLength, double InfoLength, double LineWidth, double SymbolLineWidth){
  int num=legend.EntryNum;
  double Height=VertOffsetBottom+num*EntryHeight+VertOffsetTop;
  double Length=HorOffset+LineLength+HorOffset+InfoLength+HorOffset;
  double XPos=0.0;
  double YPos=0.0;
  if (Pos==TopRight){
    XPos=bbXMax-Length-XDist;
    YPos=bbYMax-Height-YDist;
  }
  if (Pos==BottomRight){
    XPos=bbXMax-Length-XDist;
    YPos=YDist;
  }
  if (Pos==BottomLeft){
    XPos=XDist;
    YPos=YDist;
  }
  if (Pos==TopLeft){
    XPos=XDist;
    YPos=bbYMax-Height-YDist;
  }

  OutFile << "gsave\n";
  RescaleToBoundingBox(bbXMin,bbXMax,bbYMin,bbYMax,false,false);

  SetColor("white");
  FillRectR(XPos,YPos,XPos+Length,YPos+Height);
  SetColor("black");
  SetLineWidth(0.2);
  DrawRectR(XPos,YPos,XPos+Length,YPos+Height);

  OutFile << "/normalfontsize {" << FontSize << "} bd\n";
  OutFile << "/normalfonttype {/Times-Roman} bd\n";
  for (int i=0;i<num;i++){
    ShowInfo(XPos+HorOffset,YPos+VertOffsetBottom+EntryHeight*(num-1-i),LineLength,legend.Entry[i].color.c_str(),LineWidth,legend.Entry[i].symbol,SymbolLineWidth,legend.Entry[i].info.c_str(),HorOffset);
  }
  OutFile << "grestore\n";

}

//char *EPSDrawTypeNames[]={ "Rects","Circles","Points",NULL };

void EPSOptions::Reset(){
  Save = true;
  EPSFileName="";
  DataFileName="";
  EPSFileCreator="";
  EPSFileTitle="";
  LogXScale=false;
  LogYScale=false;
  bbXMin=0;
  bbYMin=0;
  bbXMax=300;
  bbYMax=200;
  LMarg=35;
  RMarg=20;
  TMarg=20;
  BMarg=20;
  ShowTitle=!true;
  Title="";
  Clip=true;
  TitleXPos=0.75;
  TitleYPos=0.85;
  TitleFontSize=20;
  XYLabelFontSize=14;
  XLabelShow=!true;
  XLabelXPos=1.02;
  XLabelYPos=0.0;
  YLabelShow=!true;
  YLabelXPos=0.0;
  YLabelYPos=1.03;
  DrawBackground=false;
  BackgroundColor="0.7 0.7 1";
  DrawColor="0 0 1";
  FillColor="0 0 0";
  DrawBox=true;
  BoxLineWidth=0.5;
  DrawTics=true;
  DrawXTics=true;
  DrawYTics=true;
  ProcSmall=2;
  ProcLarge=5;
  XTicsSmall=1;
  XTicsLarge=3;
  YTicsSmall=1;
  YTicsLarge=3;
  XTicsLabels=1;
  YTicsLabels=0.5;
  TicsLineWidth=0.5;
  DrawLabels=true;
  DrawXLabels=true;
  DrawYLabels=true;
  XLabelsXOfs=0;
  XLabelsYOfs=-12;
  YLabelsXOfs=-3;
  YLabelsYOfs=0;
  DrawGrid=true;
  DrawGridX=true;
  DrawGridY=true;
  TicsAutomatic=true;
  GridLineWidth=0.5;
  GridDash="[3 7] 0";
  LabelsFontSize=12;
  LabelsFormat="%3.1f";
  DrawType=Points;
  Diameter=10;
  DiameterSymbol=3;
  LineWidthSymbol=2;
  LineWidth=2;
  accuracy=4;
}