% export2pst(EPLdata, projectname, options)
%
% This function may be used to export numeric data in a latex file for later
% use with, e.g., NumericPlots.sty.
% If the data is provided as an 1xK array, each entry of the array will be exported
% to the file <projectname>. Each entry of the array must be a structure which contains
% x, y and ident. x and y must be arrays of the same size MxN. If M>1, each column
% of the array is exported to the file and may later be used by \Data<ident><rm>, where
% <rm> is the roman representation of the column number. If M=1, the data may later
% be used with the latex command \Data<ident>
%
% EPLdata(1, i).x = x-matrix
% EPLdata(1, i).y = y-matrix
% EPLdata(1, i).ident = identifier (has to be a string without numbers ->
% latex command name)
% EPLdata(1, i).descr = description (optional)
% EPLdata(1, i).Group = GroupNr (optional) use numbers from 1 to n to define groups. For
% each group, the maximum and minimum values will be written to the output file and may be
% accessed with identifier Group<RomanNumber> where RomanNumber is the roman represenation
% of the group number. All data without group or with group number 0 is put into the group
% Dummy
% EPLdata(1, i).precision (optional) = number of decimal places to be written
% projectname = projectname (with path, without extension)
% options (optional) define which output is required
% - options.DataBoundaries [true]: if true, the min/max values of the data
% will be written to the output file.
% - options.AxisBoundaries [false]: if true, values which may be set as
% min/max values for the axis are written to the output file. These are
% the min/max values -/+ a gap.
% - options.AxisBoundariesGap [10]: defines the gap used for the axis
% min/max values in percent of the total range of the data.
% - options.SuppressWarning [false]: suppresses the warning about max/min values being to
% close together
% - options.precision [empty]: how many decimal places should be printed for x and y
% values. Will be calculated automatically if left empty.
%
% function roman.m required to convert a number to its roman representation.
%

% author: Alexander Michel
% date: 2011/08/26
% based on export2pst created by Thomas König
%
% Copyright 2010 Thomas König, Alexander Michel
%
% This file is part of NumericPlots.
%
% NumericPlots is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% any later version.
%
% NumericPlots is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with NumericPlots. If not, see <http://www.gnu.org/licenses/>.

function ret = export2pst(EPLdata, projectname, options)
workpath = cd;
Extension = 'tex';
if size(EPLdata, 1)>1
error('EPLdata must be of size [1, n]');
end

% define standard options
if ((nargin<3) || ~isfield(options, 'DataBoundaries'))
% DataBoundaries should be in the output file (xMin, xMax, yMin,
% yMax)
options.DataBoundaries = true;
end
if ~isfield(options, 'AxisBoundaries')
% axis boundaries (xMinAxis, xMaxAxis, yMinAxis, yMaxAxis)
options.AxisBoundaries = false;
end
if ~isfield(options, 'AxisBoundariesGap')
% gap for the axis boundaries in percent of full scale
options.AxisBoundariesGap = 10;
end
if ~isfield(options, 'SuppressWarning')
options.SuppressWarning = false;
end
if ~isfield(options, 'FastRead')
options.FastRead = true;
end

% create datafolder if necessary
datapath = [projectname '_data'];
if(exist(datapath,'dir'))
cd(datapath)
delete(['*.' Extension]);
cd(workpath);
else
mkdir(datapath);
end
% open file if possible
if strcmp(projectname(end-3:end), '.tex')
fname = fullfile(projectname);
else
fname = fullfile([projectname, '.tex']);
end
[fid, msg] = fopen(fname, 'wt');
if fid<0
display(msg);
error('Matlab:FileError', ['Could not open the file ', fname '.']);
end

% write file header
fprintf(fid, '%% EPLdata written by export2pst\n');
fprintf(fid, '%% date: %s\n\n', date);
fprintf(fid, '\\def\\ExpDate{%s}\n', date);
fclose(fid);

% process data
for i=1:size(EPLdata,2)
% Ident='';
My = size(EPLdata(i).y, 1);
Mx = size(EPLdata(i).x, 1);
if ( Mx>1 && Mx~=My )
error('Matlab:export2pst', 'EPLdata.x and EPLdata.y must have the same size or EPLdata.x must have one column only');
end
if ( Mx==1 )
idx_x = ones(1, My);
else
idx_x = 1:Mx;
end

% data header
if(isfield(EPLdata(1,i), 'descr'))
fid = fopen(fname, 'at');
fprintf(fid, '\\def\\Descr%s{%s}\n', EPLdata(1,i).ident, EPLdata(1,i).descr);
fclose(fid);
end
if ~isfield(EPLdata(1,i), 'group')
EPLdata(1,i).group = 0;
end
if isempty(EPLdata(1,i).group)
EPLdata(1,i).group = 0;
end

% xMax, xMin, Dx
xMax = max(max(EPLdata(1,i).x));
xMin = min(min(EPLdata(1,i).x));

% axis boundaries
xMinAxis = xMin-(xMax-xMin)*options.AxisBoundariesGap/100; % -10% axis nearly tight
xMaxAxis = xMax+(xMax-xMin)*options.AxisBoundariesGap/100; % +10% axis nearly tight

if (abs(xMax-xMin)<1e-16)
xMax = 1.0;
xMin = -1.0;
if ~options.SuppressWarning
fprintf('export2pst - Warning: |xMax-xMin|<1e-16\n');
end
end
DxV = (xMax-xMin)/5;
NrUnsigX = 0;
while (fix(DxV*10^(NrUnsigX)) == 0)
NrUnsigX = NrUnsigX+1;
end

% yMin, yMax, Dy
yMax = max(max(EPLdata(1,i).y));
yMin = min(min(EPLdata(1,i).y));

% axis boundaries
yMinAxis = yMin-(yMax-yMin)*options.AxisBoundariesGap/100; % -10% axis nearly tight
yMaxAxis = yMax+(yMax-yMin)*options.AxisBoundariesGap/100; % +10% axis nearly tight

% save min/max values for groupes
group(i) = EPLdata(1,i).group+1;
groupXmax(i) = xMax;
groupXmin(i) = xMin;
groupYmax(i) = yMax;
groupYmin(i) = yMin;

if (abs(yMax-yMin)<1e-16)
yMax = 1.0;
yMin = -1.0;
if ~options.SuppressWarning
fprintf('export2pst - Warning: |yMax-yMin|<1e-16\n');
end
end
DyV = (yMax-yMin)/5;

% check how many significant numbers DyV has. This number will be used for the precision of all Min/Max values so
% latex prints all of them with the same number of decimal places.
NrUnsigY = 0;
while (fix(DyV*10^(NrUnsigY)) == 0)
NrUnsigY = NrUnsigY+1;
end

fid = fopen(fname, 'at');
if options.DataBoundaries
fprintf(fid, ['\\def\\Data%sXmin{%1.', num2str(NrUnsigX), 'f}\n'], EPLdata(1,i).ident, floor(xMin*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sXmax{%1.', num2str(NrUnsigX), 'f}\n'], EPLdata(1,i).ident, ceil(xMax*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sYmin{%1.', num2str(NrUnsigY), 'f}\n'], EPLdata(1,i).ident, floor(yMin*10^NrUnsigY)/(10^NrUnsigY));
fprintf(fid, ['\\def\\Data%sYmax{%1.', num2str(NrUnsigY), 'f}\n'], EPLdata(1,i).ident, ceil(yMax*10^NrUnsigY)/(10^NrUnsigY));
end
fprintf(fid, ['\\def\\Data%sDxV{%1.', num2str(NrUnsigX), 'f}\n'], EPLdata(1,i).ident, DxV);
fprintf(fid, ['\\def\\Data%sDyV{%1.', num2str(NrUnsigY), 'f}\n'], EPLdata(1,i).ident, DyV);
if options.AxisBoundaries
fprintf(fid, ['\\def\\Data%sXminAxis{%1.', num2str(NrUnsigX), 'f}\n'], EPLdata(1,i).ident, floor(xMinAxis*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sXmaxAxis{%1.', num2str(NrUnsigX), 'f}\n'], EPLdata(1,i).ident, ceil(xMaxAxis*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sYminAxis{%1.', num2str(NrUnsigY), 'f}\n'], EPLdata(1,i).ident, floor(yMinAxis*10^NrUnsigY)/(10^NrUnsigY));
fprintf(fid, ['\\def\\Data%sYmaxAxis{%1.', num2str(NrUnsigY), 'f}\n'], EPLdata(1,i).ident, ceil(yMaxAxis*10^NrUnsigY)/(10^NrUnsigY));
end
fclose(fid);

cd(datapath);
% write actual data
for j=1:My
yyMax = max(EPLdata(1,i).y(idx_x(j),:));
yyMin = min(EPLdata(1,i).y(idx_x(j),:));
if (abs(yyMax-yyMin)<1e-16)
yNrPrecision = 1;
else
yNrPrecision = ceil(log10(10000/(yyMax-yyMin)));
end
xxMax = max(EPLdata(1,i).x(idx_x(j),:));
xxMin = min(EPLdata(1,i).x(idx_x(j),:));
if (abs(xxMax-xxMin)<1e-16)
xNrPrecision = 1;
else
xNrPrecision = ceil(log10(10000/(xxMax-xxMin)));
end
if isfield(EPLdata(1,i), 'precision')
NrPrecision = EPLdata(1,i).precision;
if isempty(NrPrecision)
NrPrecision = max(yNrPrecision, xNrPrecision);
end
else
NrPrecision = max(yNrPrecision, xNrPrecision);
end

if(My > 1)
Ident = roman(num2str(j));
else
Ident='';
end;
datafilename = [EPLdata(1,i).ident Ident '.' Extension];
fid = fopen(datafilename, 'w+');
fclose(fid);
if(options.FastRead)
fid = fopen(datafilename, 'w+');
fprintf(fid, '%% EPLdata written by export2pst\n');
fprintf(fid, '%% date: %s\n\n', date);
fprintf(fid,'\\def\\FigureToPlot{');
%fprintf(fid,'[');
fclose(fid);
dlmwrite(datafilename, [EPLdata(1,i).x(idx_x(j),:); EPLdata(1,i).y(j,:)]','-append', 'delimiter', ' ', 'precision', ['%.', num2str(NrPrecision), 'f']);
fid = fopen(datafilename, 'a');
fprintf(fid,'}');
%fprintf(fid,']');
fclose(fid);
else
fid = fopen(datafilename, 'w+');
fprintf(fid, '%% EPLdata written by export2pst\n');
fprintf(fid, '%% date: %s\n\n', date);
fclose(fid);
dlmwrite(datafilename, [EPLdata(1,i).x(idx_x(j),:); EPLdata(1,i).y(j,:)]','-append', 'delimiter', ' ', 'precision', ['%.', num2str(NrPrecision), 'f']);
end
end
cd(workpath)
end

% write group values
for i = 1:max(group)
xMax = max(groupXmax(group==i));
xMin = min(groupXmin(group==i));
yMax = max(groupYmax(group==i));
yMin = min(groupYmin(group==i));
if (abs(yMax-yMin)<1e-16)
yMax = 1.0;
yMin = -1.0;
end
if (abs(xMax-xMin)<1e-16)
xMax = 1.0;
xMin = -1.0;
end

% axis boundaries
xMinAxis = xMin-(xMax-xMin)*options.AxisBoundariesGap/100;
xMaxAxis = xMax+(xMax-xMin)*options.AxisBoundariesGap/100;
yMinAxis = yMin-(yMax-yMin)*options.AxisBoundariesGap/100;
yMaxAxis = yMax+(yMax-yMin)*options.AxisBoundariesGap/100;

DxV = (xMax-xMin)/5;
DyV = (yMax-yMin)/5;

% check how many significant numbers DyV has. This number will be used for the precision of all Min/Max values so
% latex prints all of them with the same number of decimal places.
NrUnsigY = 0;
while (fix(DyV*10^(NrUnsigY)) == 0)
NrUnsigY = NrUnsigY+1;
end
NrUnsigX = 0;
while (fix(DxV*10^(NrUnsigX)) == 0)
NrUnsigX = NrUnsigX+1;
end

if i>1.5
ident = strcat('Group', roman(num2str(i-1)));
else
ident = 'GroupDummy';
end

fid = fopen(fname, 'at');
if options.DataBoundaries
fprintf(fid, ['\\def\\Data%sXmin{%1.', num2str(NrUnsigX), 'f}\n'], ident, floor(xMin*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sXmax{%1.', num2str(NrUnsigX), 'f}\n'], ident, ceil(xMax*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sYmin{%1.', num2str(NrUnsigY), 'f}\n'], ident, floor(yMin*10^NrUnsigY)/(10^NrUnsigY));
fprintf(fid, ['\\def\\Data%sYmax{%1.', num2str(NrUnsigY), 'f}\n'], ident, ceil(yMax*10^NrUnsigY)/(10^NrUnsigY));
end
fprintf(fid, ['\\def\\Data%sDxV{%1.', num2str(NrUnsigX), 'f}\n'], ident, DxV);
fprintf(fid, ['\\def\\Data%sDyV{%1.', num2str(NrUnsigY), 'f}\n'], ident, DyV);
if options.AxisBoundaries
fprintf(fid, ['\\def\\Data%sXminAxis{%1.', num2str(NrUnsigX), 'f}\n'], ident, floor(xMinAxis*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sXmaxAxis{%1.', num2str(NrUnsigX), 'f}\n'], ident, ceil(xMaxAxis*10^NrUnsigX)/(10^NrUnsigX));
fprintf(fid, ['\\def\\Data%sYminAxis{%1.', num2str(NrUnsigY), 'f}\n'], ident, floor(yMinAxis*10^NrUnsigY)/(10^NrUnsigY));
fprintf(fid, ['\\def\\Data%sYmaxAxis{%1.', num2str(NrUnsigY), 'f}\n'], ident, ceil(yMaxAxis*10^NrUnsigY)/(10^NrUnsigY));
end

fclose(fid);
ret = 1;
end