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;
}