/*
 *   PSFile.cc
 *   
 *   19/06/96
 *
 *   Modification le 01/03/96
 *    - fusion psfile.cc - psdict.cc
 *
 *
 *   07/08/99 : Gestion des fontes ; ajout Times/Helvetica/Symbol 
 *              
 * 
 *
 *
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

#include "psfile.h"

//++
// Class	PSFile
// Lib		PI
// include	psfile.h
//
//   	Classe encapsulant un fichier PostScript, fournissant des primitives
//	graphiques produisant du code PostScript.
//--
//++
// Links	Voir aussi
// PIGraphicPS
//--



/* En cm */
#define  MIN_SIZE_IN_PAGE  2.

/*
 *  Dictionnaire PIDict
 *
 *  Contient les fonctions suivantes : 
 *
 *
 */
#define PIDICT_PAR   \
  \
  PI_Landscape, PI_Portrait,\
  \
  PI_ColorFromMap, PI_Black, PI_White, PI_Grey, PI_Red, PI_Blue,\
  PI_Green, PI_Yellow, PI_Magenta, PI_NotDefColor,\
  PI_Cyan, PI_Turquoise, PI_NavyBlue,\
  PI_Orange, PI_SiennaRed, PI_Purple,\
  PI_LimeGreen, PI_Gold, \
  PI_Violet, PI_VioletRed, PI_BlueViolet, PI_DarkViolet, \
  PI_SkyBlue, PI_RoyalBlue, PI_ForestGreen, \
  PI_OrangeRed, PI_Brown, PI_HighlightBlue, \
  \
  PI_RomanFont, PI_BoldFont, PI_ItalicFont, PI_NotDefFontAtt,\
  PI_SmallSizeFont, PI_NormalSizeFont, PI_LargeSizeFont, PI_NotDefFontSize, \
  \
  PI_NormalLine, PI_ThinLine, PI_ThickLine, PI_NotDefLineAtt

#define PIDICT       "\
/$PIDict 50 dict def\n\
$PIDict begin $PIDict /mtrx matrix put /Landscape %d def /Portrait %d def\n\
%% Couleurs et fontes courantes\n\
/C%-2d  {ur    ug    ub    setrgbcolor} bind def %% PI_ColorFromMap\n\
/C%-2d  {0.0   0.0   0.0   setrgbcolor} bind def %% PI_Black\n\
/C%-2d  {1.000 1.000 1.000 setrgbcolor} bind def %% PI_White\n\
/C%-2d  {0.824 0.824 0.824 setrgbcolor} bind def %% PI_Grey\n\
/C%-2d  {1.000 0.0   0.0   setrgbcolor} bind def %% PI_Red\n\
/C%-2d  {0.0   0.0   1.000 setrgbcolor} bind def %% PI_Blue\n\
/C%-2d  {0.0   1.000 0.0   setrgbcolor} bind def %% PI_Green\n\
/C%-2d  {1.000 1.000 0.0   setrgbcolor} bind def %% PI_Yellow\n\
/C%-2d  {1.000 0.0   1.000 setrgbcolor} bind def %% PI_Magenta\n\
/C%-2d  {}                              bind def %% PI_NotDefColor\n\
/C%-2d  {0.0   1.000 1.000 setrgbcolor} bind def %% PI_Cyan\n\
/C%-2d  {0.250 0.875 0.813 setrgbcolor} bind def %% PI_Turquoise\n\
/C%-2d  {0.0   0.0   0.500 setrgbcolor} bind def %% PI_NavyBlue\n\
/C%-2d  {1.000 0.644 0.0   setrgbcolor} bind def %% PI_Orange\n\
/C%-2d  {0.625 0.320 0.176 setrgbcolor} bind def %% PI_SiennaRed\n\
/C%-2d  {0.625 0.125 0.937 setrgbcolor} bind def %% PI_Purple\n\
/C%-2d  {0.195 0.800 0.195 setrgbcolor} bind def %% PI_LimeGreen\n\
/C%-2d  {1.000 0.840 0.0   setrgbcolor} bind def %% PI_Gold\n\
/C%-2d  {0.933 0.510 0.933 setrgbcolor} bind def %% PI_Violet\n\
/C%-2d  {0.816 0.125 0.565 setrgbcolor} bind def %% PI_VioletRed\n\
/C%-2d  {0.541 0.167 0.886 setrgbcolor} bind def %% PI_BlueViolet\n\
/C%-2d  {0.580 0.000 0.827 setrgbcolor} bind def %% PI_DarkViolet\n\
/C%-2d  {0.530 0.805 0.920 setrgbcolor} bind def %% PI_SkyBlue\n\
/C%-2d  {0.255 0.410 0.880 setrgbcolor} bind def %% PI_RoyalBlue\n\
/C%-2d  {0.135 0.545 0.135 setrgbcolor} bind def %% PI_ForestGreen\n\
/C%-2d  {1.000 0.270 0.000 setrgbcolor} bind def %% PI_OrangeRed\n\
/C%-2d  {0.647 0.165 0.165 setrgbcolor} bind def %% PI_Brown\n\
/C%-2d  {0.600 0.750 1.000 setrgbcolor} bind def %% PI_HighlightBlue\n\
/F%-2d  {/Courier   findfont} bind def           %% PI_RomanFont\n\
/F%-2d  {/Courier-Bold    findfont} bind def     %% PI_BoldFont\n\
/F%-2d  {/Courier-Italic  findfont} bind def     %% PI_ItalicFont\n\
/F%-2d  {}\
                        bind def       %% PI_NotDefFontAtt\n\
/FS {scalefont setfont} bind def\n\
%%/FS%-2d {8  scalefont setfont} bind def          %% PI_SmallSizeFont\n\
%%/FS%-2d {12 scalefont setfont} bind def          %% PI_NormalSizeFont\n\
%%/FS%-2d {16 scalefont setfont} bind def          %% PI_LargeSizeFont\n\
/FS%-2d {}                     bind def          %% PI_NotDefFontSize\n\
/L%-2d  {1    slw} bind def                      %% PI_NormalLine\n\
/L%-2d  {0.5  slw} bind def                      %% PI_ThinLine\n\
/L%-2d  {3    slw} bind def                      %% PI_ThickLine\n\
/L%-2d  {}         bind def                      %% PI_NotDefLineAtt\n\
\
%% Conversion\n\
/cm   {28.3 mul}   bind def  %% cm --> points\n\
/Ux   {$Cvrtx mul} bind def  %% Unites utilisateur /x --> points\n\
/Uy   {$Cvrty mul} bind def  %% Unites utilisateur /y --> points\n\
\
%% Pages et Blocs\n\
/newref  {%% Dx Dy Tx Ty X0 Y0 newref\n\
translate 3 -1 roll cm div 28.3 mul /$Cvrty exch def\n\
exch cm div 28.3 mul /$Cvrtx exch def} bind def\n\
/NewPage {%% Dx Dy orientation NewPage\n\
/$PageEnteredState save def 1 -1 scale Portrait eq {w cm h cm 0 h cm neg\n\
newref} { -90 rotate h cm w cm 0 0 newref} ifelse} bind def\n\
/EndPage { %% EndPage\n\
$PageEnteredState restore} bind def\n\
/NewBloc { %% Dx Dy Tx Ty X0 Y0 NewBloc\n\
/$BlocEnteredState save def newref} bind def\n\
/EndBloc { %% EndBloc\n\
$BlocEnteredState restore} bind def\n\
\
%% Trace\n\
/n  {newpath} bind def    /c  {closepath} bind def\n\
/gs {gsave}  bind def     /gr {grestore} bind def\n\
/m  {moveto} bind def     /l  {lineto} bind def\n\
/s  {stroke} bind def     /f  {fill}   bind def\n\
/sc {scale}  bind def     /S  {gs 1 -1 sc show gr} bind def \n\
/slw {setlinewidth} bind def\n\
/sljoin {setlinejoin} bind def\n\
/slcap {setlinecap} bind def\n\
/slsolid {[] 0 setdash} bind def %% Solid-Line \n\
/sldash {[6 6] 0 setdash} bind def %% Dashed-Line \n\
/sldott {[2 6] 0 setdash} bind def %% Dotted-Line \n\
/sldashdott {[2 2 4 6] 0 setdash} bind def %% Dash-Dotted-Line \n\
/ff {findfont} bind def   /sf {setfont} bind def /scf {scalefont} bind def\n\
/rl {rlineto} bind def    /tr {translate} bind def\n\
/rmv {rmoveto} bind def \n\
%% Trace de chaine avec justification diverse \n\
%% ------------------------------------------------- \n\
%% hxshstr  stack: TheString \n\
%% hx (x=r,c,l) Horizontal-X Right,Center,Left - Vertical: BaseLine \n\
%% ------------------------------------------------- \n\
/hlshstr   %% Horizontal-left Vertical-BaseLine justified \n\
{ gs 1 -1 sc show gr } bind def \n\
/hcshstr   %% Horizontal-Center Vertical-BaseLine justified \n\
{ dup stringwidth pop 2 div neg  %% get minus(string length/2)  \n\
  0 rmoveto gs 1 -1 sc show gr } bind def \n\
/hrshstr   %% Horizontal-Right Vertical-BaseLine justified \n\
{ dup stringwidth pop neg  %% get minus(string width)  \n\
  0 rmoveto gs 1 -1 sc show gr } bind def \n\
%% ------------------------------------------------- \n\
%% hxvyshstr  stack: TheString \n\
%% hx (x=r,c,l) Horizontal-X Right,Center,Left \n\
%% vy (y=t,c,b) Vertical-Y Top,Center,Bottom \n\
%% Ces procs (hxvyshstr) utilisent la variable curfntsz que l'on definit par defaut \n\
%% hxshstr  stack: TheString \n\
%% hx (x=r,c,l) Horizontal-X Right,Center,Left - Vertical: BaseLine \n\
%% ------------------------------------------------- \n\
/curfntsz 10 def \n\
/hlvbshstr   %% Horizontal-left Vertical-Bottom justified \n\
{ gs 1 -1 sc show gr } bind def \n\
/hcvbshstr   %% Horizontal-Center Vertical-Bottom justified \n\
{ dup stringwidth pop 2 div neg  %% get minus(string length/2)  \n\
  0 rmoveto gs 1 -1 sc show gr } bind def \n\
/hrvbshstr   %% Horizontal-Right Vertical-Bottom justified \n\
{ dup stringwidth pop neg  %% get minus(string width)  \n\
  0 rmoveto gs 1 -1 sc show gr } bind def \n\
/hlvcshstr   %% Horizontal-left Vertical-Center justified \n\
{ 0 curfntsz 2 div   %% get (string height)/2  \n\
  rmoveto gs 1 -1 sc show gr } bind def \n\
/hcvcshstr   %% Horizontal-Center Vertical-Center justified \n\
{ dup stringwidth pop 2 div neg curfntsz 2 div  %% s_wy/2 -s_wx/2  \n\
  rmoveto gs 1 -1 sc show gr } bind def \n\
/hrvcshstr   %% Horizontal-Right Vertical-Center justified \n\
{ dup stringwidth pop neg curfntsz  %% s_wy/2 -s_wx  \n\
  rmoveto gs 1 -1 sc show gr } bind def \n\
/hlvtshstr   %% Horizontal-left Vertical-Top justified \n\
{ 0 curfntsz   %% get s_wy  \n\
  rmoveto gs 1 -1 sc show gr } bind def \n\
/hcvtshstr   %% Horizontal-Center Vertical-Top justified \n\
{ dup stringwidth pop 2 div neg curfntsz  %% s_wy -s_wx/2  \n\
  rmoveto gs 1 -1 sc show gr } bind def \n\
/hrvtshstr   %% Horizontal-Right Vertical-Top justified \n\
{ dup stringwidth pop neg curfntsz  %% s_wy -s_wx  \n\
  rmoveto gs 1 -1 sc show gr } bind def \n\
%% Tx Ty X0 Y0 box\n\
/box {tr 0 3 1 roll neg exch 0 0 3 index neg 0 0 m rl rl rl c} bind def\n\
%% R X0 Y0 circle\n\
/circle {tr dup 0 m 0 0 3 -1 roll 0 380 arc} bind def\n\
%% DrawEllipse pompee sur transfig\n\
/ellipse {/endangle exch def /startangle exch def /yrad exch def\n\
/xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def\n\
x y tr xrad yrad sc 0 0 1 startangle endangle arc\n\
closepath savematrix setmatrix } def\n\
\
%% pipsarc Arc \n\
/pipsarc {/endangle exch def /startangle exch def /yrad exch def\n\
/xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def\n\
x y tr xrad yrad sc 0 0 1 startangle endangle arc\n\
savematrix setmatrix } def\n\
\
%% pipsfarc Arc plein \n\
/pipsfarc {/endangle exch def /startangle exch def /yrad exch def\n\
/xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def\n\
x y tr 0 0 moveto xrad yrad sc 0 0 1 startangle endangle arc 0 0  lineto\n\
closepath savematrix setmatrix } def\n\
\
%% Gestion des images\n\
%% ColorImage, pompee sur xv (qui les avait pompees sur xgrab)\n\
/colorimage where   %% do we know about 'colorimage'?\n\
  { pop }           %% yes: pop off the 'dict' returned\n\
  {                 %% no:  define one\n\
    /colortogray {  %% define an RGB->I function\n\
      /rgbdata exch store    %% call input 'rgbdata'\n\
      rgbdata length 3 idiv\n\
      /npixls exch store\n\
      /rgbindx 0 store\n\
      0 1 npixls 1 sub {\n\
        grays exch\n\
        rgbdata rgbindx       get 20 mul    %% Red\n\
        rgbdata rgbindx 1 add get 32 mul    %% Green\n\
        rgbdata rgbindx 2 add get 12 mul    %% Blue\n\
        add add 64 idiv      %% I = .5G + .31R + .18B\n\
        put\n\
        /rgbindx rgbindx 3 add store\n\
      } for\n\
      grays 0 npixls getinterval\n\
    } bind def\n\
    /mergeprocs { %% def\n\
      dup length 3 -1 roll dup length dup 5 1 roll 3 -1 roll add\n\
      array cvx dup 3 -1 roll 0 exch putinterval dup 4 2 roll\n\
      putinterval } bind def\n\
    /colorimage {\n\
      pop pop     %% remove 'false 3' operands\n\
      {colortogray} mergeprocs image} bind def\n\
  } ifelse          %% end of 'false' case\n\
\
%% GetRGB\n\
/GetRGB { %% ImageStr --> RGBStr\n\
  /ImageData exch store\n\
  %% Pour chaque element de ImageData,\n\
  %% On va chercher les valeurs RGB correspondantes\n\
  0 1 Taille 1 sub {\n\
    /i      exch store  %% On met a jour l'indice de parcours\n\
    ImageData i get     %% Recupere la Indice e val dans la chaine ImData\n\
    ColorMap exch get   %% On recupere la valeur RGB Correspondante\n\
    aload pop           %% On met tout ca dans la pile\n\
    %% Maintenant, on va mettre tout ca dans la chaine RGBStr\n\
    RGBStr i 3 mul 2 add 3 -1 roll put\n\
    RGBStr i 3 mul 1 add 3 -1 roll put\n\
    RGBStr i 3 mul       3 -1 roll put\n\
    } for\n\
  RGBStr 0 Taille 3 mul getinterval %% On renvoie la chaine RGB\n\
} bind def\n\
end\n\
"



/* 
 *  Les PIMarkers sont definis et geres commes des fontes
 *
 *
 */
#define PIMARKERS_PAR  PI_DotMarker, PI_PlusMarker, PI_CrossMarker,\
  PI_CircleMarker, PI_FCircleMarker, PI_BoxMarker, PI_FBoxMarker,\
  PI_TriangleMarker, PI_FTriangleMarker, PI_StarMarker, PI_FStarMarker

#define PIMARKERS  "\
%% Definition de la fonte $PIMarkers\n\
/$PIMarkers 26 dict def\n\
$PIMarkers begin\n\
/FontType 3 def\n\
/FontMatrix [0.001 0 0 0.001 -0.375 -0.375] def\n\
/FontBBox   [0 0 1000 1000] def\n\
/Encoding 256 array def\n\
0 1 255 {Encoding exch /.notdef put} for\n\
Encoding  %d /PIDot       put %% PI_DotMarker\n\
Encoding  %d /PIPlus      put %% PI_PlusMarker\n\
Encoding  %d /PICross     put %% PI_CrossMarker\n\
Encoding  %d /PICircle    put %% PI_CircleMarker\n\
Encoding  %d /PIFCircle   put %% PI_FCircleMarker\n\
Encoding  %d /PIBox       put %% PI_BoxMarker\n\
Encoding  %d /PIFBox      put %% PI_FBoxMarker\n\
Encoding  %d /PITriangle  put %% PI_TriangleMarker\n\
Encoding  %d /PIFTriangle put %% PI_FTriangleMarker\n\
Encoding  %d /PIStar      put %% PI_StarMarker\n\
Encoding  %d /PIFStar     put %% PI_FStarMarker\n\
/CharProcs 26 dict def\n\
$PIDict begin\n\
CharProcs begin\n\
/.notdef     {} def\n\
/PIDot       {100 375 375 circle f} bind def\n\
/PIPlus      {0 375 m 750 375 l 375 0 m 375 750 l s} bind def\n\
/PICross     {0 0 m 750 750 l 750 0 m 0 750 l s} bind def\n\
/PICircle    {375 375 375 circle s} bind def\n\
/PIFCircle   {375 375 375 circle f} bind def\n\
/PIBox       {0 0 m 750 0 l 750 750 l 0 750 l c s} bind def\n\
/PIFBox      {0 0 m 750 0 l 750 750 l 0 750 l c f} bind def\n\
/PITriangle  {0 750 m 375 0 l 750 750 l c s} bind def\n\
/PIFTriangle {0 750 m 375 0 l 750 750 l c f} bind def\n\
/PIStar      {731 260 m 459 260 l 375 0 l 291 260 l 19 260 l \
239 419 l 155 678 l 375 518 l 595 678 l 511 419 l c s} def\n\
/PIFStar     {731 260 m 459 260 l 375 0 l 291 260 l 19 260 l \
239 419 l 155 678 l 375 518 l 595 678 l 511 419 l c f} def\n\
end %%$PIDict\n\
end %%$CharProcs\n\
/BuildChar {\n\
1000 0      %% Largeur \n\
0 0 750 750 %% Bounding Box\n\
setcachedevice \n\
exch begin\n\
Encoding exch get\n\
CharProcs exch get\n\
end 75 slw exec} def\n\
end\n\
/PIMarkers $PIMarkers definefont pop\n\
save\n\
"

/* Dimensions des divers formats */
  struct PaperSize {
      double width ;
      double height ;
  };
struct PaperSize PaperSizeTable[] = {
    { 0.0,  0.0},    /* PI_NotDefFormat */
    {21.0, 29.7},    /* PI_A4 */
    {29.7, 42.0},    /* PI_A3 */
    {14.8, 21.0}     /* PI_A5 ? */
} ;


double cm2pt(double x);


/* Fonction WriteHeader */
#define END_PROLOG_PAR  PAGE_WIDTH, PAGE_HEIGHT
#define END_PROLOG  "/NewFile { %%%% w h NewFile (--> h et w en cm <--)\n\
$PIDict begin /PIMarkers ff 14 scf sf /h exch def /w exch def \n\
/$PIEnteredState save def} bind def\n\
/EndFile {$PIEnteredState restore end} bind def\n\
%%%%EndProlog\n\n\
"

#define HEADER     "\
%%%%Title: %s\n\
%%%%Creator: PI-PSFile (N.R. 07/08/99)\n\
%%%%CreationDate: %s\
%%%%Pages: (atend)\n\
%%%%EndComments\n\n\
"

//++
// Titre	Constructeurs
//--
//++
// PSFile (const char * FileName, double sc = 1.0)
//	Créateur pour fichier Encapsulated Postscript
// PSFile (const char * FileName, PIOrientation orientation, -
//         PIPaperSize paperSize= PI_A4, -
//         double marginX = 5.0, double marginY = 5.0 )
//	Créateur pour fichier Postscript
//--

/* 
   Utilisation de la resolution coordonnees utilisateur (resolution ecran)
   pour definir correctement la taille des fontes 
                                      R. Ansari - Juillet 2001
*/
/* Definition de la resolution coordonnees user par defaut (point/cm ou pixels/cm) */ 

float PSFile::postscript_resolution = 28.;  /* environ 72 points / pouce  */
float PSFile::def_user_resol_X = 30.;      /* environ 75 points / pouce  */
float PSFile::def_user_resol_Y = 30.;
float PSFile::def_user_resolution = 30.;

void PSFile::SetUserCoordResolution(float resx, float resy)
{
  if ((resx < 1.) || (resy < 1.)) return;
  def_user_resol_X = resx;
  def_user_resol_Y = resy;
  def_user_resolution = 0.5*(resx+resy);
}
float PSFile::GetUserCoordResolution(float& resx, float& resy)
{
  resx = def_user_resol_X;
  resy = def_user_resol_Y;
  return (def_user_resolution);
}
float PSFile::PSCoordResolution()
{
  return (postscript_resolution);
}

/* 
 *   PostScript encapsule...
 * 
 *   Attention la bounding Box ne sera specifiee 
 *     qu'au premier NewPage() --> definie dans 
 *     le champ "Trailer" 
 *
 */
PSFile::PSFile(const char * FileName, double sc) 
    : mPSFileName(FileName==NULL? "unnamed.eps" : const_cast<char *>(FileName)),
      Tw (-1.), Th(-1.),         /* Non specifies pour du eps  */
      WMargin (-1), HMargin(-1), /* Non specifiees en eps  */ 
      isEPS(1),
      scale(sc),                 /* Defaut : 1. */
      mPaperSize(PI_NotDefPaperSize), /* Non specifiee en eps */
      PageCounter(0),            /* Fichier vide */
      FileEmpty(1),              /* Fichier vide */
      currentPage(NULL),
      currentBloc(NULL),
      mDrawColor(PI_Black),
      mFillColor(PI_Black),
      mFontAtt(PI_RomanFont),
      mFontSize(0),
      mFontName(PI_DefaultFont), 
      mLineAtt(PI_NormalLine),
      mMarker(PI_DotMarker),
      setFontDone(true)
{
    char*  date = new (char[64] ) ; 
    time_t timer ; 

    /* Ouverture du fichier en mode w+ */
    if ( (mPSFile = fopen(FileName, "w+")) == NULL){
	  perror (FileName);
	  return;
    }

    /* Ecriture du Header  */
    fprintf(mPSFile, "%%!PS-Adobe-2.0 EPSF-2.0\n");
    fprintf(mPSFile, "%%%%BoundingBox: ");
    /* 
     * Les dimensions de la BB seront notees ici lors du 
     * premier appel a NewPage
     *
     * C'est laid... si qqn a une meilleure idee...
     */
    boundingBox = ftell(mPSFile) ; 
    fprintf(mPSFile, "                       \n");

    time(&timer) ; 
    date = ctime(&timer) ; 
    fprintf(mPSFile, HEADER, mPSFileName, date) ; /* titre, date etc... */
    fprintf(mPSFile, PIDICT, PIDICT_PAR) ;        /* Dictionnaire */
    fprintf(mPSFile, PIMARKERS, PIMARKERS_PAR) ;  /* Fonte "PIMARKERS" */
    //    fprintf(mPSFile, END_PROLOG) ;
    /* Aucun format n'est specifie ici ... */
    fprintf(mPSFile, "$PIDict begin /PIMarkers ff 14 scf sf\n") ;
    fprintf(mPSFile, "/FState save def\n%%%%EndProlog\n\n") ;
}



/*
 *  PostScript simple...
 *
 *
 */
PSFile::PSFile(const char *FileName,
	       PIOrientation orientation,
	       PIPaperSize   paperSize,
	       double marginX, double marginY)
 :  mPSFileName (FileName == NULL ? "unnamed.ps" : const_cast<char *>(FileName)),
    Tw(PaperSizeTable[paperSize].width),  /* Format papier utilise */
    Th(PaperSizeTable[paperSize].height), /*                       */
    WMargin(marginX),
    HMargin(marginY),
    isEPS(0),
    scale(0.),
    PageCounter(0),  /* Fichier vide */
    FileEmpty(1),    /*              */
    currentPage(NULL),
    currentBloc(NULL),
    mDrawColor(PI_Black),
    mFillColor(PI_Black),
    mFontAtt(PI_RomanFont),
    mFontSize(0),
    mFontName(PI_DefaultFont),
    mLineAtt(PI_NormalLine),
    mMarker(PI_DotMarker), 
    setFontDone(true)
{
    char * date = new(char[64]) ; 
    time_t timer ; 

    /* Ouverture du fichier, en mode w+ (tout est ecrase) */
    if ( (mPSFile = fopen(FileName, "w+")) == NULL){
	  perror (FileName);
	  return;
    }

    /* Format et orientation */

    /* Ecriture du Header  */
    fprintf(mPSFile, "%%!PS-Adobe-2.0\n") ;
    time(&timer) ; 
    date = ctime(&timer) ; 
    fprintf(mPSFile, HEADER, mPSFileName, date) ; /* titre, date etc... */
    fprintf(mPSFile, PIDICT, PIDICT_PAR) ;        /* Dictionnaire */
    fprintf(mPSFile, PIMARKERS, PIMARKERS_PAR) ;  /* Fonte "PIMARKERS" */
    fprintf(mPSFile, "$PIDict begin /PIMarkers ff 14 scf sf\n") ;
    fprintf(mPSFile, "/FState save def\n%%%%EndProlog\n\n") ;
}


/* 
 * Destructeur
 *
 */
PSFile::~PSFile () {

    /* On ferme tout ce qui ne l'est pas */
    if (currentBloc) PSFile::EndBloc();
    if (currentPage) PSFile::EndPage();

    /* Si le fichier est vide, on le detruit */
    if (FileEmpty) remove(mPSFileName);

    /* On ecrit le "Trailer" et on ferme */
    else {
	/* On restore l'etat initial */
	fprintf(mPSFile,"FState restore\n") ;
	fprintf(mPSFile, "%%%%Trailer\n%%%%Pages: %d\n%%%%EOF\n", 
		PageCounter) ;
	fclose (mPSFile);
    }
}


int   PSFile::IsEPS(){

    return(isEPS);
}


const char* PSFile::GetFileName() {

    return(mPSFileName);
}

PIColors PSFile::GetDrawColor() {

    return(mDrawColor);
}

PIColors PSFile::GetFillColor() {

    return(mFillColor);
}

PIFontAtt PSFile::GetFontAtt() {

    return(mFontAtt);
}

// N.R. 07/08/99 return val PIFontSize --> int 
int PSFile::GetFontSize() {

    return(mFontSize);
}

PILineAtt PSFile::GetLineAtt() {

    return(mLineAtt);
}

PIMarker PSFile::GetMarker() {

    return(mMarker);
}

//++
// NewPage(double Dx, double Dy, PIOrientation orientation) 
//	Debut de nouvelle page, (Dx,Dy) indique l'extension
//	(taille) du systeme de coordonnees utilisees pour la page
// EndPage()
//	Fin de page
//--

void  PSFile::NewPage(double Dx, double Dy, PIOrientation orientation) {

double  tw, th; /* largeur & hauteur corrigees des marges */

    /* On ferme ce qui doit l'etre ... */
    if (currentPage) PSFile::EndPage();

    currentPage = new (Page) ; 

    /* Initialisations */
    currentPage->num = ++PageCounter;
    currentPage->BlocCounter = 0;
    currentPage->Dx = Dx;
    currentPage->Dy = Dy;
    currentPage->orientation = orientation ;

    /* Position du debut AVANT D'ECRIRE! */
    currentPage->begin  = ftell(mPSFile);

    /* On ecrit dans le fichier */
    fprintf(mPSFile, "%%%%Page: %d %d\n", PageCounter, PageCounter) ;
    fprintf(mPSFile, "/PState save def 1 -1 scale\n");

    /* 
     *  Si eps : Portrait || Auto == on laisse tel que
     *           Landscape == on tourne de -90 degres
     */
    if(isEPS) {
	if( (orientation == PI_Portrait) || (orientation == PI_Auto) )
	    fprintf(mPSFile,
		    "%.2f %.2f %.2f %.2f %.2f %.2f newref\n",
		    Dx, Dy, Dx*scale, Dy*scale, 0., -Dy*scale);
	else
	    if(orientation==PI_Landscape)
		fprintf(mPSFile, 
			"-90 rotate %.2f %.2f %.2f %.2f %.2f %.2f newref\n",
			Dx, Dy, Dx*scale, Dy*scale, 0., 0.);
	    else
		fprintf(stderr, "Orientation Error ; Page : %d\n",
			currentPage->num) ; 
    /* 
     * On specifie la bb 
     * (Si non encore fait par un appel precedent a NewPage() ) 
     */
	if(boundingBox) {
	    currentPage->tmp = ftell(mPSFile) ;
	    fseek(mPSFile,boundingBox,SEEK_SET) ;
	    if( (orientation == PI_Portrait) || (orientation == PI_Auto) )
		fprintf(mPSFile, "%d %d %d %d", 0, 0, 
			(int)(Dx*scale), (int)(Dy*scale) ) ; 
	    else
		fprintf(mPSFile, "%d %d %d %d", 0, 0, 
			(int)(Dy*scale), (int)(Dx*scale) ) ;
	    fseek(mPSFile,currentPage->tmp,SEEK_SET) ;
	    boundingBox = 0 ; 
	} /* BB */
	/* facteur d'echelle pour les fontes*/
	currentPage->FontScaleFactor = scale; 
	//	  postscript_resolution/def_user_resolution*scale;
	/*
	cout << " EPS_DBG_FontScaleFactor = " << currentPage->FontScaleFactor
	     << " scale= " << scale << " postscript_resolution= " 
	     << postscript_resolution << " def_user_resolution= " 
	     << def_user_resolution << endl;
	*/
    } /* EPS */
    /*
     * Si ps : 
     *   - soustraction marges --> rectangle utile.
     *   - Si PI_Auto : On fait au mieux pour minimiser le 
     *      redimensionnement...
     *   - Si PI_Portrait, on ne fait rien, sauf 
     *      peut-etre un redimensionnement pour rentrer dans les marges
     *   - Si PI_Landscape, on tourne de -90 degres.
     */
    else {
        // Si marges <= 0 on les met a 2cm
        if(WMargin<=0) WMargin = 2. ; 
        if(HMargin<=0) HMargin = 2. ; 
	/* Eviter image reduite a un point...ou moins... */
	if((tw = Tw - 2*WMargin) < (Tw/10)) {
	    WMargin = (0.45)*Tw ;
	    tw = Tw/10;
	}
	if((th = Th - 2*HMargin)< (Th/10)) {
	    HMargin = (0.45)*Th ;
	    th = Th/10;
	}
	/* Portrait ou Landscape ? */
	if(orientation == PI_Auto) 
	    if( ((tw < th) && (Dx < 1.2*Dy)) ||
		((tw > th) && (Dx > Dy) )) 
		currentPage->orientation = PI_Portrait ;
	    else 
		currentPage->orientation = PI_Landscape ;

	if(currentPage->orientation == PI_Portrait) {
	  //	    if( (tw/Dx) < (th/Dy) ) 
	  //		scale = tw/Dx ;
	  //                scale = tw/Tw ; 
	  //	    else 
	  //		scale = th/Dy;
	  //                scale = th/Th;
	  //	    fprintf(mPSFile, 
	  //		    "%.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
	  //		    Dx, Dy, 
	  //		    Dx*scale, Dy*scale, 
	  //		    Tw*scale, Th*scale, 
	  //		    0.5*(Tw-tw), -0.5*(Th+th)) ;
            scale = (tw/Dx)<(th/Dy) ? tw/Dx : th/Dy ; 
            tw = scale*Dx ; th = scale*Dy ; 
	    fprintf(mPSFile, 
		    "%.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
		    Dx, Dy, 
		    tw, th, 
		    0.5*(Tw-tw), -0.5*(Th+th)) ;
	}  /* End if .Portrait  */
	if(currentPage->orientation == PI_Landscape) {
	    /* Idem avec X<->Y */
//	    if( (th/Dx) < (th/Dy) ) 
//		scale = th/Dx;
//                scale = th/Tw;
//	    else
//		scale = tw/Dy ;
//                scale = tw/Th;
//	    fprintf(mPSFile,
//	       "-90 rotate %.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
//	       Dx, Dy,
//	       Dx*scale, Dy*scale, 
//	       Th*scale, Tw*scale, 
//	       0.5*(Th-th), 0.5*(Tw-tw));

            scale = (th/Dx)<(tw/Dy) ? th/Dx : tw/Dy ; 
            th = scale*Dx ; tw = scale*Dy ; 
	    fprintf(mPSFile,
	       "-90 rotate %.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
	       Dx, Dy,
	       th, tw,
	       0.5*(Th-th), 0.5*(Tw-tw));
	} /* End if .Landscape */
	/* facteur d'echelle pour les fontes*/
	currentPage->FontScaleFactor = scale*postscript_resolution;
	/*
	cout << " PS_DBG_FontScaleFactor = " << currentPage->FontScaleFactor
	     << " scale= " << scale << " postscript_resolution= " 
	     << postscript_resolution << " def_user_resolution= " 
	     << def_user_resolution << endl;
	*/
    } /* End if .ps */
// On redefint la fonte par defaut - $CHECK$ Reza 11/12/99
mFontAtt = PI_RomanFont;
mFontSize = 10;
mFontName = PI_DefaultFont;
double scaledFontSize = (double)mFontSize*currentPage->FontScaleFactor;
fprintf(mPSFile, "/Courier ff %g FS /curfntsz %g def \n", scaledFontSize, scaledFontSize) ; 
setFontDone = true;
currentPage->tmp = ftell(mPSFile);
}



void  PSFile::EndPage() {

    /* Si rien a fermer, on s'en va */
    if ( ! currentPage ) return;

    /* Si un bloc non ferme, on appelle EndBloc */
    if ( currentBloc ) PSFile::EndBloc();
    
    /* Si la page est vide, on la detruit */
    if (currentPage->tmp == ftell(mPSFile)) {
	fseek(mPSFile, currentPage->begin, SEEK_SET);
	delete(currentPage) ;
	PageCounter--;
    }
    /* Sinon, fin page + empilage */
    else {
	//	it = mPageList.end(); it--;
	fprintf(mPSFile,"PState restore  showpage\n");
	fprintf(mPSFile,"%%>EndPage %d\n\n\n", currentPage->num);
	currentPage->end = ftell(mPSFile);
	mPageList.push_back(*currentPage); /* Pourquoi PageList ? */
	FileEmpty = 0;
    }
    currentPage = NULL;
}


//++
// NewBloc(double x0, double y0, double Tx, double Ty, double Dx, double Dy)
//	Debut de bloc.
//|	x0,y0 : position du bloc ds la page
//|	Tx,Ty : Taille du bloc dans la page
//|	Dx,Dy : Extension (taille) du systeme de coordonnees utilisateur
//|	dans le bloc
//
// EndBloc()
//	Fin de bloc
//--


void  PSFile::NewBloc(double x0, double y0, double Tx, double Ty,
			      double Dx, double Dy){

    /* Si pas de page, on s'en va */
    if ( ! currentPage ) return;

    /* On ferme le bloc precedent (Pas de Bloc-gigognes ! ) */
    if (currentBloc) PSFile::EndBloc();

    currentBloc = new (Bloc) ; 
    /* On remplit currentBloc */
    currentBloc->num = ++(currentPage->BlocCounter);
    currentBloc->X0 = x0;
    currentBloc->Y0 = y0;
    currentBloc->Tx = Tx;
    currentBloc->Ty = Ty;
    currentBloc->Dx = Dx;
    currentBloc->Dy = Dy;
    currentBloc->begin = ftell(mPSFile);

    /* On met a jour le fichier */
    fprintf(mPSFile, "%%>BeginBloc %d\n", currentBloc->num);
    fprintf(mPSFile, "%.2f %.2f %.2f Ux %.2f Uy %.2f Ux %.2f Uy NewBloc\n",
	    currentBloc->Dx, currentBloc->Dy,
	    currentBloc->Tx, currentBloc->Ty,
	    currentBloc->X0, currentBloc->Y0);
    // On redefinit la zone de clip
    fprintf(mPSFile, "%% Define clip region to the entire bloc area \n");
    fprintf(mPSFile, "initclip newpath 0 0 m %.2f Ux 0 rl 0 %.2f Uy rl %2f Ux 0 rl closepath clip \n",
	    currentBloc->Dx, currentBloc->Dy, -currentBloc->Dx); 
    // On redefint la fonte par defaut - $CHECK$ Reza 11/12/99
    mFontAtt = PI_RomanFont;
    mFontSize = 10;
    mFontName = PI_DefaultFont;
    double scaledFontSize = (double)mFontSize*currentPage->FontScaleFactor;
    fprintf(mPSFile, "/Courier ff %g FS /curfntsz %g def \n", 
	    scaledFontSize, scaledFontSize) ;
    mLineAtt = PI_NotDefLineAtt;
    SelectLine(PILineAtt(PI_NormalLine));
    setFontDone = true;
    currentBloc->tmp = ftell(mPSFile) ;
}


void  PSFile::EndBloc() {

    /* On verifie qu'un bloc ouvert existe bien */
    if ( ! currentBloc ) return;

    /* Si le bloc est vide, on le detruit */
    if (currentBloc->tmp == ftell(mPSFile)) {
	fseek(mPSFile, currentBloc->begin, SEEK_SET) ; 
	currentPage->BlocCounter-- ; 
    }
    /* Sinon, Ok met a jour le fichier */
    else { 
	fprintf(mPSFile, "EndBloc\n"); 
	fprintf(mPSFile, "%%>EndBloc %d\n", currentBloc->num); 
	currentBloc->end = ftell(mPSFile) ; 
	currentPage->mBlocList.push_back(*currentBloc) ; 
	//	PageEmpty = 0; 
    } 
    /* Flags */
    currentBloc = NULL ; 
}


void PSFile::SetClipRectangle(double x0, double y0, double dx, double dy)
{
  // On redefinit la zone de clip
  fprintf(mPSFile, "%% SetClipRectangle: Define clip region \n ");
  fprintf(mPSFile, "newpath %.2f Ux %.2f Uy m %.2f Ux 0 rl 0 %.2f Uy rl %.2f Ux 0 rl closepath clip \n",
	  x0, y0, dx, dy, -dx); 
}

void PSFile::ClearClipRectangle()
{
  // On redefinit la zone de clip a l'ensemble du bloc
  fprintf(mPSFile, "%% Define clip region to the entire bloc area \n");
  fprintf(mPSFile, "initclip newpath 0 0 m %.2f Ux 0 rl 0 %.2f Uy rl %2f Ux 0 rl closepath clip \n",
	  currentBloc->Dx, currentBloc->Dy, -currentBloc->Dx); 
}

void PSFile::SelForeground(PIColorMap& cmap, int cid)
{
  mDrawColor = PI_ColorFromMap ; 
  PIColor tmp = cmap.GetColor(cid) ; 
  fprintf(mPSFile, "/ur %.3f def /ug %.3f def /ub %.3f def \n", 
          (double)(tmp.red)/65535., 
          (double)(tmp.green)/65535., 
          (double)(tmp.blue)/65535.) ; 
}


void PSFile::SelBackground(PIColorMap& cmap, int cid)
{
  mDrawColor = PI_ColorFromMap ; 
}


/* fonction pour rajouter \ devant ( ) et \ pour string postscript */
static char * EscapePSString(const char *s)
{
  int nce = 0;
  int ls = strlen(s);
  int i,j,k;
  for(int k=0; k<ls; k++) 
    if ( (s[k] == '(') || (s[k] == ')') || (s[k] == '\\') ) nce++;
  if (nce == 0) return NULL;
  char * es = new char[ls+nce+1];
  j = 0;
  for(int k=0; k<ls; k++) {
    if ( (s[k] == '(') || (s[k] == ')') || (s[k] == '\\') ) {
      es[j] = '\\';  j++; 
    }
    es[j] = s[k];  j++;
  }
  es[j] = '\0';
  return es;
}

void  PSFile::DrawString  (double x,  double y, const char *s, 
			   PIColors DrawColor, 
			   PIFontName FontName, 
			   PIFontAtt FontAtt, 
			   int FontSize, 
			   unsigned long pos) {
    bool change = false;

    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) && (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }
    /* Choix des fontes */
    if ( (FontAtt != PI_NotDefFontAtt) && (FontAtt != mFontAtt) ) {
//DBG      printf("PSFile::DrawString(%s) : FontAtt a change : %d %d \n", s, mFontAtt, FontAtt) ; 
      mFontAtt = FontAtt;
      change = true;
    }
    if ( (FontSize != PI_NotDefFontSize) && (FontSize != mFontSize) ) {
//DBG      printf("PSFile::DrawString(%s) : FontSize a change : %d %d \n", s, mFontSize, FontSize) ; 
      mFontSize = FontSize;  
      change = true;
    }
    if( (FontName != mFontName) ) {
//DBG      printf("PSFile::DrawString(%s) : FontName a change : %d %d \n", s, mFontName, FontName) ; 
      mFontName = (PIFontName) FontName ; 
      change = true ; 
    }

    if (change || !setFontDone) { // $CHECK$ setFontDone Reza 11/12/99 
      string fname ; 
      switch(mFontName) {
      case PI_DefaultFont:
      case PI_CourierFont:
	fprintf(mPSFile, "/Courier") ; 
	break ; 
      case PI_HelveticaFont:
	fprintf(mPSFile, "/Helvetica") ; 
	break ; 
      case PI_TimesFont:
	fprintf(mPSFile, "/Times") ; 
	break ; 
      case PI_SymbolFont:
	fprintf(mPSFile, "/Symbol ") ; 
	break ; 
      } // endsw 
      
      switch(mFontAtt) {
      case PI_NotDefFontAtt:
      case PI_RomanFont:
	fprintf(mPSFile, " ") ; 
	break ; 
      case PI_BoldFont:
	if(mFontName != PI_SymbolFont) fprintf(mPSFile, "-Bold ") ; 
	break ; 
      case PI_ItalicFont:
	if ((mFontName == PI_DefaultFont) || (mFontName == PI_CourierFont) ||
	    (mFontName == PI_HelveticaFont) ) fprintf(mPSFile, "-Oblique ") ;
	else if (mFontName == PI_TimesFont) fprintf(mPSFile, "-Italic ") ; 
	break ; 
      case PI_BoldItalicFont:
	if ((mFontName == PI_DefaultFont) || (mFontName == PI_CourierFont) ||
	    (mFontName == PI_HelveticaFont) ) fprintf(mPSFile, "-BoldOblique ") ;
	else if (mFontName == PI_TimesFont) fprintf(mPSFile, "-BoldItalic ") ; 
	break ; 	
      } // endsw 
      double scaledFontSize = (double)FontSize*currentPage->FontScaleFactor;
      fprintf(mPSFile, " ff %g FS /curfntsz %g def \n", scaledFontSize, scaledFontSize);
      setFontDone = true ;   // $CHECK$ - doit etre fait uniquement a ce moment
    }
    /* Les () et \ doivent avoir le caractere escape \ dans les chaines postscript */
    char * es = EscapePSString(s);
    const char * epss = s;
    if (es != NULL) epss = es;
    if (pos == 0) 
      fprintf(mPSFile, "gs %.2f Ux %.2f Uy m (%s) S gr\n", x, y, epss) ; 
    else {
      unsigned long txtdir = pos & PI_TextDirection;
      int posh = pos & PI_HorizontalPosition;
      int posv = pos & PI_VerticalPosition;
      int angle = 0;
      if (txtdir == PI_TextDirectionVerticalUp) angle = -90;
      else if (txtdir == PI_TextDirectionVerticalDown) angle = 90;

      if ((posh == PI_HorizontalLeft)  && 
	  ((posv == PI_VerticalBaseLine) || (posv == 0)) ) {
	if (angle == 0) 
	  fprintf(mPSFile, "gs %.2f Ux %.2f Uy m (%s) hlshstr gr\n", 
		  x, y, epss) ;
	else 
	  fprintf(mPSFile, "gs %.2f Ux %.2f Uy m %d rotate (%s) hlshstr gr\n", 
		  x, y, angle, epss) ;
      }
      else {
	char ssvp = 'b';
	char sshp = 'l';
	if (posh != PI_HorizontalLeft) {
	  if (posh == PI_HorizontalCenter)  sshp = 'c';
	  else if (posh == PI_HorizontalRight)  sshp = 'r';
	  else sshp = 'l';
	}
	if (posv == 0) {
	  if (angle == 0) 
	    fprintf(mPSFile, "gs %.2f Ux %.2f Uy m (%s) h%cshstr gr\n", 
		    x, y, epss, sshp) ;
	  else fprintf(mPSFile, "gs %.2f Ux %.2f Uy m %d rotate (%s) h%cshstr gr\n", 
		       x, y, angle, epss, sshp) ;
	}
	else {
	  if (posv == PI_VerticalCenter)  ssvp = 'c';
	  else if (posv == PI_VerticalTop)  ssvp = 't';
	  else ssvp = 'b';
	}
	if (angle == 0) 
	  fprintf(mPSFile, "gs %.2f Ux %.2f Uy m (%s) h%cv%cshstr gr\n", 
		  x, y, epss, sshp, ssvp) ; 
	else 
	  fprintf(mPSFile, "gs %.2f Ux %.2f Uy m %d rotate (%s) h%cv%cshstr gr\n", 
		  x, y, angle, epss, sshp, ssvp) ; 
      }
    }

    if (es) delete[] es;  /* chaine modifiee avec des \( \) ou \\ */    
    return;
}


void  PSFile::DrawLine    (double x1, double y1, double x2, double y2, 
			   PIColors DrawColor,
			   PILineAtt LineAtt) {


    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor);
    }

    /* Dessin */
    fprintf(mPSFile, "n %.2f Ux %.2f Uy m %.2f Ux %.2f Uy l s\n",
	    x1, y1, x2, y2) ;
}



void  PSFile::DrawBox(double x0, double y0, double Tx, double Ty, 
		      PIColors  DrawColor,
		      PILineAtt LineAtt) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    /* Changement couleurs ? */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }


    /* On dessine */
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy box s gr\n",
	    Tx, Ty, x0, y0) ; 
}


void  PSFile::DrawFBox(double x0, double y0, double Tx, double Ty, 
		   PIColors DrawColor,
		   PIColors FillColor, 
		   PILineAtt LineAtt) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    /* Dessin du fond */
    if ( (FillColor != PI_NotDefColor) || (FillColor != mDrawColor) ) {
      mDrawColor = FillColor;
      fprintf(mPSFile, "C%d ", mDrawColor) ;
    } 
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy box f gr\n",
	    Tx, Ty, x0, y0) ; 

    /* Dessin du contour (s'il y a lieu) */
    if ( (DrawColor != PI_NotDefColor) && (FillColor != DrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
	fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy box s gr\n",
		Tx, Ty, x0, y0) ;
    }
}


void  PSFile::DrawCircle  (double x0, double y0, double r, 
			   PIColors DrawColor,
			   PILineAtt LineAtt) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor); 
    }


    /* Dessin */
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy 0 360 ellipse s gr\n",
	    x0, y0, r, r) ;
}


void  PSFile::DrawFCircle (double x0, double y0, double r,
		   PIColors DrawColor,
		   PIColors FillColor, 
		   PILineAtt LineAtt) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    /* Dessin du fond */
    if ( (FillColor != PI_NotDefColor) || (FillColor != mDrawColor) ){
	mDrawColor = FillColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ;
    }
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy \
                      0 360 ellipse f gr\n",
	    x0, y0, r, r);

    /* Dessin du contour (s'il y a lieu) */
    if ( (DrawColor != PI_NotDefColor) && (FillColor != DrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor); 
	fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy 0 360 ellipse s gr\n",
		x0, y0, r, r) ;
    }
}

void  PSFile::DrawArc (double x0, double y0, double dx, double dy,
		       double degdeb, double deltadeg,
		       PIColors DrawColor,
		       PILineAtt LineAtt) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor); 
    }
    
    double degfin = degdeb+deltadeg;
    while (degfin > 360.) degfin -= 360.;
    while (degfin < 0.)   degfin += 360.;
    /* Dessin */
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy %.2f %.2f pipsarc s gr\n",
	    x0, y0, dx, dy, degdeb, degfin) ;
}


void  PSFile::DrawFArc (double x0, double y0, double dx, double dy,
			double degdeb, double deltadeg,
			PIColors DrawColor,
			PIColors FillColor, 
			PILineAtt LineAtt) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    double degfin = degdeb+deltadeg;
    while (degfin > 360.) degfin -= 360.;
    while (degfin < 0.)   degfin += 360.;
    /* Dessin du fond */
    if ( (FillColor != PI_NotDefColor) || (FillColor != mDrawColor) ){
	mDrawColor = FillColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ;
    }
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy %.2f %.2f pipsfarc f gr\n",
	    x0, y0, dx, dy, degdeb, degfin);

    /* Dessin du contour (s'il y a lieu) */
    if ( (DrawColor != PI_NotDefColor) && (FillColor != DrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor); 
	fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy %.2f %.2f pipsfarc s gr\n",
		x0, y0, dx, dy, degdeb, degfin) ;
    }
}


// Les coordonnees sont supposees etre en mode incremental .
void  PSFile::DrawPolygon (double *x, double *y, int n,
		   PIColors DrawColor, 
		   PILineAtt LineAtt, bool cinc) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    /* Couleur */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ;
    }
    
    /* On dessine ; ici*/
    fprintf(mPSFile, "%.2f Ux %.2f Uy m\n", x[0], y[0]);

    const char* cmd ; 
    if(cinc == true) cmd = "%.2f Ux %.2f Uy rl\n" ; 
    else             cmd = "%.2f Ux %.2f Uy l\n" ; 

    for(int i = 1; i<n; i++) 
      fprintf(mPSFile, cmd, x[i], y[i]);
    fprintf(mPSFile, " s\n");   // On ne ferme pas le path - Reza 02/2002 - fprintf(mPSFile, "c s\n");
}


void  PSFile::DrawFPolygon(double *x, double *y, int n,
		   PIColors DrawColor,
		   PIColors FillColor,
		   PILineAtt LineAtt, bool cinc) {

    /* Line Att */  
    if ( (LineAtt != PI_NotDefLineAtt) && (LineAtt != mLineAtt) ) 
      SelectLine(LineAtt);

    const char* cmd ; 
    if(cinc == true) cmd = "%.2f Ux %.2f Uy rl\n" ; 
    else             cmd = "%.2f Ux %.2f Uy l\n" ; 

    /* Dessin du fond... */
    if ( (FillColor != PI_NotDefColor) || (FillColor != mDrawColor) ) {
	mDrawColor = FillColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ;
    }
    fprintf(mPSFile, "%.2f Ux %.2f Uy m\n", x[0], y[0]);
    int i;
    for(i = 1; i<n; i++) 
	fprintf(mPSFile, cmd, x[i], y[i]);
    fprintf(mPSFile, "c f\n");

    /* ...puis du contour (s'il y a lieu) */
    if ( (DrawColor != PI_NotDefColor) && (DrawColor != FillColor) ) {
      mDrawColor = DrawColor;
      fprintf(mPSFile, "C%d ", mDrawColor) ;
      fprintf(mPSFile, "%.2f Ux %.2f Uy m\n", x[0], y[0]);
      for(i = 1; i<n; i++) 
	fprintf(mPSFile, cmd, x[i], y[i]);
      fprintf(mPSFile, "c s\n");
    }
}



void  PSFile::DrawMarker  (double x0, double y0,
			   PIMarker MrkType,   
			   PIColors DrawColor,
			   int MarkerSize) {
    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }

    /* Marker */
    if (MrkType != PI_NotDefMarker)
	mMarker = MrkType;
    if ((MrkType == PI_DotMarker) && (MarkerSize<3)) MarkerSize=3;
    if(MarkerSize != mMarkerSize || setFontDone) {
	mMarkerSize = MarkerSize ;
	fprintf(mPSFile, "/PIMarkers ff %d scf sf\n", 
		(int)(mMarkerSize*currentPage->FontScaleFactor)) ; 
        setFontDone = false ; 
    }
    /* Dessin */
    fprintf(mPSFile, "%.2f Ux %.2f Uy m (\\%#o) show\n", x0, y0, mMarker) ;
}

/*
 * Pas d'options pour specifier la taille des Markers ?
 *
 */
void  PSFile::DrawMarkers (double *x0, double *y0, int n,
			   PIMarker MrkType,
			   PIColors DrawColor,
			   int MarkerSize) {
    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }    

    /* Marker */
    if (MrkType != PI_NotDefMarker)
	mMarker = MrkType;

    if(MarkerSize != mMarkerSize || setFontDone) {
	mMarkerSize = MarkerSize ;
	fprintf(mPSFile, "/PIMarkers ff %d scf sf\n",  
		(int)(mMarkerSize*currentPage->FontScaleFactor)) ; 
        setFontDone = false ; 
    }
    /* Dessin */
    for(int i = 0; i<n; i++)
	fprintf(mPSFile, "%.2f Ux %.2f Uy m (\\%#o) show\n", x0[i], y0[i], mMarker) ; 
}

void PSFile::Image(double x0, double y0, double Tx, double Ty,
		   int Nx, int Ny,
		   unsigned char *Pict, 
		   PIColorMap *mMap) {

    int i, j;

    /* Buffers PostScript */
    fprintf(mPSFile, "/Taille %d def\n", Nx);
    fprintf(mPSFile, "/ImStr Taille string def\n");
    fprintf(mPSFile, "/RGBStr Taille 3  mul string def\n");

    /* Ecriture ColorMap */
    fprintf(mPSFile, "/ColorMap %02d array def\n", mMap->NCol() );
    for(i = 0; i < mMap->NCol(); i++) {
	fprintf(mPSFile, "ColorMap %d [16#%02X 16#%02X 16#%02X] put\n",
		i,
		(int)(mMap->GetColor(i).red/256),
		(int)(mMap->GetColor(i).green/256),
		(int)(mMap->GetColor(i).blue/256));
    }
    /* Emplacement de l'image */
    fprintf(mPSFile, "gs %.2f Ux %.2f Uy tr %.2f Ux %.2f Uy sc\n", x0, y0, Tx, Ty);
    /* Nbr pix-X, Nbr pix-Y bits/pixels */
    fprintf(mPSFile, "%d %d 8\n", Nx, Ny);
    /* Matrice de passage */
    fprintf(mPSFile, "[%d 0 0 %d 0 0]", Nx, Ny);
    /* Fonction colorimage */
    fprintf(mPSFile, "{currentfile ImStr readhexstring pop GetRGB}\
false 3 colorimage\n\n");
    /* Data */
    for(i = 0; i < Ny; i++) {
	for(j = 0; j<Nx-1; j++ )
	    fprintf(mPSFile, "%02X", Pict[i*Nx+j]);
    fprintf(mPSFile, "%02X\n", Pict[i*Nx+j]);
    }
    /* Un petit grestore ...*/
    fprintf(mPSFile, "gr\n");
}


void  PSFile::SelectLine(PILineAtt att)
{
    
  //  if (att.GetLineWidth() != mLineAtt.GetLineWidth()) {
  double scaledLineWidth = att.GetLineWidthD()*currentPage->FontScaleFactor;
  fprintf(mPSFile, "%g slw ", scaledLineWidth) ;
  if (att.GetLineDash() != mLineAtt.GetLineDash()) {
      switch (att.GetLineDash()) {
        case PI_LineSolid :
	  fprintf(mPSFile, "slsolid ");
	  break;
        case PI_LineDashed :
	  fprintf(mPSFile, "sldash ");
	  break;
        case PI_LineDotted :
	  fprintf(mPSFile, "sldott ");
	  break;
        case PI_LineDashDotted :
	  fprintf(mPSFile, "sldashdott ");
	  break;
        default :
	  fprintf(mPSFile, "slsolid ");
	  break;
      }
  }
  if (att.GetLineJoin() != mLineAtt.GetLineJoin()) {
      switch (att.GetLineJoin()) {
        case PI_JoinMiter :
	  fprintf(mPSFile, "0 sljoin ");
	  break;
        case PI_JoinRound :
	  fprintf(mPSFile, "1 sljoin ");
	  break;
        case PI_JoinBevel :
	  fprintf(mPSFile, "2 sljoin ");
	  break;
        default :
	  fprintf(mPSFile, "0 sljoin ");
	  break;
      }
  }
  if (att.GetLineCap() != mLineAtt.GetLineCap()) {
      switch (att.GetLineCap()) {
        case PI_CapButt :
	  fprintf(mPSFile, "0 slcap \n");
	  break;
        case PI_CapRound :
	  fprintf(mPSFile, "1 slcap \n");
	  break;
        case PI_CapProjecting :
	  fprintf(mPSFile, "2 slcap \n");
	  break;
        default :
	  fprintf(mPSFile, "0 slcap \n");	  
	  break;
      }
  }
      mLineAtt = att;
}

/* 
 *  Conversion
 *
 */

double cm2pt(double x) {
    return (x*28.35);
}

