// Module PI : Peida Interactive     PIGraphic 
// Primitives de trace graphiques    R. Ansari  97
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

// Classe generique de trace graphique de base (Ne peut etre instancie)

#include "sopnamsp.h"
#include "pigraphgen.h"
#include <math.h>
#include <iostream>
#include "ucckprot.h"

//++
// Class	PIGraphic
// Lib		PI
// include	pigraphgen.h
//
//   	Classe de base fournissant les services de tracé graphique.
//   	La classe PIGraphicGen définit l'interface à travers des méthodes
//   	virtuelles pures. Les objets instanciés doivent être de la classe
//   	"PIGraphicWin" ou "PIGraphicUC" ou ...
//   	La classe "PIGraphicWin" a une implementation dépendante du système 
//   	utilisé (Mac, XWindow, ...). 
//   	Un type particulier *PIGrCoord* est défini pour la spécification 
//	des coordonnées graphiques. 
//--
//++
// Links	Classes derivees
// PIGraphicUC
// PIGraphic3D
// PIGraphicPS
//--
//++
// Links	Voir aussi
// PIFont
// PIColorMap
//--
//++
// Links	et
// PIGrCoord
// PILineAtt
// PIGraphicAtt
//--

//++
// Titre	Constructeurs
//--
//++
// PIGraphic()
//	Constructeur utilisé par les classes dérivées.
// PIGraphic(PIWdg* wdg)
//	Constructeur pour les *PIGraphicWin*. Objet "PIGraphic" capable 
//	de tracer dans un "PIWdg".
// PIGraphic(PIScreenBuffer* grb)
//	Constructeur pour objet "PIGraphic" capable de tracer dans un 
//	buffer graphique.
//--
//++
//--
// Titre	Méthodes
//++
// int  kind()
//	Renvoie le type de l'objet "PIGraphic" .
//	* PI_UnknownGraphics : Objet PIGraphic de type inconnue.
//	* PI_ScrBufferGraphics : Objet PIGraphic associé à un "GraphicBuffer"
//	* PI_ScrWindowGraphics : Objet PIGraphic associé à une fenêtre sur l'écran (PIWdg)
//	* PI_PSFileGraphics : Objet PIGraphic à un fichier PostScript (pour impression papier)
//	* PI_UCGraphics : Objet PIGraphic travaillant dans un système de coordonnées utilisateur.
//	* PI_3DGraphics : Objet PIGraphic fournissant des méthodes de tracé en coordonnées 3-D
// void  GetGrSpace(PIGrCoord& xmin, PIGrCoord& xmax, PIGrCoord& ymin, PIGrCoord& ymax)
//	Renvoie les limites de l'espace graphique - Coordonnées fenêtre pour un PIGraphicWin, 
//	Limites définies par l'utilisateur pour un PIGraphicUC
// void  Erase(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy) 
//	Efface le rectangle défini par le coin "x0,y0", de longeur et de largeur "dx,dy"
//	en utilisant la couleur d'arrière plan (Background)
//--


/* --Methode-- */
PIGraphicGen::PIGraphicGen()
{
myWdg = NULL;
myGrb = NULL;
myLockFCol = false;
SelArrowMarker();
}

/* --Methode-- */
PIGraphicGen::PIGraphicGen(PIWdg* wdg)
{
myWdg = wdg;
myGrb = NULL;
myLockFCol = false;
SelArrowMarker();
}

/* --Methode-- */
PIGraphicGen::PIGraphicGen(PIScreenBuffer* grb)
{
myWdg = NULL;
myGrb = grb;
myLockFCol = false;
SelArrowMarker();
}

/* --Methode-- */
PIGraphicGen::~PIGraphicGen()
{
}
/* --Methode-- */
int PIGraphicGen::kind() 
{
return PI_UnknownGraphics ;
}


/* --Methode-- */
void PIGraphicGen::GetGrSpace(PIGrCoord& xmin, PIGrCoord& xmax, PIGrCoord& ymin, PIGrCoord& ymax)
{
xmin = ymin = 0;  
xmax = ymax = 0;
if (myWdg) {
  xmax = myWdg->XSize();
  ymax = myWdg->YSize();
  }
}

//++ 
// Titre	Tracés de texte
//--
//++
// void  DrawString(PIGrCoord x, PIGrCoord y, const char* s, unsigned long pos = 0)
//	Trace la chaîne de caractères "s" à la position "x,y", 
//	en utilisant la couleur d'avant-plan (Foreground)
//	La chaine est trace avec une justification a gauche, ou droite,
//	ou centree (horzontal) - bas, haut, milieu (vertical), en fonction de
//	de la valeur du flag "pos"
//|	PI_HorizontalLeft PI_HorizontalCenter PI_HorizontalRight
//|	PI_VerticalBottom PI_VerticalCenter PI_VerticalTop
// void  DrawOpaqueString(PIGrCoord x, PIGrCoord y, const char* s, int pos = 0) 
//	Trace la chaîne de caractères "s" à la position "x,y" . La couleur d'
//	arrière-plan est utilisée pour remplir la zone rectangulaire occupée par
//	le tracé de texte.
//	La chaine est trace avec une justification a gauche, ou droite,
//	ou centree (horizontal) - bas, haut, milieu (vertical), en fonction de
//	de la valeur du flag "pos"
//|	PI_HorizontalLeft PI_HorizontalCenter PI_HorizontalRight
//|	PI_VerticalBottom PI_VerticalCenter PI_VerticalTop
// void  DrawCompString(PIGrCoord x, PIGrCoord y, const char* s, const char* s_up, \
//       const char* s_dn, PIFont const & fntss, unsigned long pos = 0)
//	Tracé d'une chaîne de caractères "s" avec une partie de texte en exposant "s_up"
//	et une partie en indice "s_dn". Une fonte différente ("fntss") peut être 
//	spécifiée pour la partie de texte en exposant et en indice. La taille 
//	de la fonte exposant-indice est calculée automatiquement en fonction de 
//	la taille de fonte courante. le positionnement s'effectue en fonction
//	du flag "pos" :
//|	PI_HorizontalLeft PI_HorizontalCenter PI_HorizontalRight
//|	PI_VerticalBottom PI_VerticalCenter PI_VerticalTop
// void  DrawCompString(PIGrCoord x, PIGrCoord y, const char* s, \
//       const char* s_up, const char* s_dn, unsigned long pos = 0)
//	Tracé d'une chaîne de caractères "s" avec une partie de texte en exposant "s_up"
//	et une partie en indice "s_dn". Fonte exposant-indice identique à la fonte
//	courante.
//--

inline void compstring_swapcoord( unsigned long txtdir, PIGrCoord& x, PIGrCoord& y)
{
  if (txtdir != PI_TextDirectionHorizontal) {
    PIGrCoord tmp = x;
    x = y; y = tmp;
  }
  return;
}

inline void compstring_chksgn_dyud( unsigned long txtdir, int & dyu, int & dyd)
{
  if (txtdir == PI_TextDirectionVerticalDown) {
    dyu = -dyu;
    dyd = -dyd;
  }
}
inline void compstring_chksgn_dx( unsigned long txtdir, int & dx)
{
  if (txtdir == PI_TextDirectionVerticalUp)  dx = -dx;
}

/* --Methode-- */
void 
PIGraphicGen::DrawCompString(PIGrCoord x, PIGrCoord y, const char* s,
			     const char* s_up, const char* s_dn, 
			     PIFont const & fntss, unsigned long pos)
{
  if ((s_up == NULL) && (s_dn == NULL)) {
    if (s != NULL)  DrawString(x,y,s,pos);
    return;
  }

  int fh,fas,fds;
  fh = myFont.GetFontHeight(fas, fds);
  int sw_s = 0;
  if (s != NULL) sw_s = myFont.GetStringWidth(s);

  PIFont fnt_save(myFont);
  PIFont fnt_ss(fntss);
  fnt_ss.SetFontSzPt(2*myFont.GetFontSize()/3);

  int sw_sup = 0;
  if (s_up != NULL) sw_sup = fnt_ss.GetStringWidth(s_up);
  int sw_sdn = 0;
  if (s_dn != NULL) sw_sdn = fnt_ss.GetStringWidth(s_dn);

  PIGrCoord xs,ys,xss,yss; 
  int posh = pos & PI_HorizontalPosition;
  int posv = pos & PI_VerticalPosition;
  unsigned long txtdir = pos&PI_TextDirection;

  int dyu, dyd;
  dyu = -fh/2;  dyd = fh/2-fh/5; 
  if (posv == PI_VerticalBaseLine) {
    dyu = -fh/2;  dyd = fh/2-fh/5; 
    }
  else if (posv == PI_VerticalBottom) { 
    dyu = -fh/2-fds;  dyd = fh/2-fh/5-fds; 
    }
  else if (posv == PI_VerticalCenter) {
    dyu = -fds;  dyd = fh-fh/5-fds; 
  }
  else if (posv == PI_VerticalTop) {
    dyu = fh/2-fds;  dyd = 3*fh/2-fh/5-fds; 
  }

  int deltaposx = ((fh/8) > 0) ? fh/8 : 1;

  // Pour gerer les traces de texte verticaux 
  compstring_swapcoord(txtdir, x, y);
  compstring_chksgn_dyud( txtdir, dyu, dyd);
  compstring_chksgn_dx( txtdir, deltaposx); 
  compstring_chksgn_dx( txtdir, sw_s); 
  compstring_chksgn_dx( txtdir, sw_sup); 
  compstring_chksgn_dx( txtdir, sw_sdn); 

  if ((pos == 0) || ((posh == PI_HorizontalLeft) && (posv == PI_VerticalBaseLine))) {
    xs = (int)x+sw_s;
    ys = y;
    compstring_swapcoord(txtdir, xs, ys);    
    if (s != NULL)  DrawString(xs, ys, s, txtdir | PI_HorizontalRight);
    xs = (int)x+sw_s+deltaposx;
    ys = (int)y+dyu;
    SelFont(fnt_ss);
    compstring_swapcoord(txtdir, xs, ys);    
    if (s_up != NULL) DrawString(xs, ys, s_up, txtdir | PI_HorizontalLeft);
    xs = (int)x+sw_s+deltaposx;
    ys = (int)y+dyd;
    compstring_swapcoord(txtdir, xs, ys);    
    if (s_dn != NULL) DrawString(xs, ys, s_dn, txtdir | PI_HorizontalLeft);
  }
  else {
    if (posh == PI_HorizontalRight) {
      int sw_ss_max = ( sw_sup > sw_sdn ) ? sw_sup : sw_sdn;
      xss = xs = (int)x-sw_ss_max-deltaposx;
      ys = y;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s != NULL)  DrawString(xs, ys, s, txtdir | PI_HorizontalRight | posv);
      SelFont(fnt_ss);
      xs = (int)xss+deltaposx;
      ys = (int)y+dyu;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s_up != NULL) DrawString(xs, ys, s_up, txtdir | PI_HorizontalLeft);
      xs = (int)xss+deltaposx;
      ys = (int)y+dyd;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s_dn != NULL) DrawString(xs, ys, s_dn, txtdir | PI_HorizontalLeft);      
    }
    else if (posh == PI_HorizontalCenter) {
      int sw_tot = sw_sup+sw_sdn+sw_s+deltaposx;
      xss = xs = (int)x-sw_tot/2+sw_s; 
      ys = y;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s != NULL)  DrawString(xs, ys, s, txtdir | PI_HorizontalRight | posv);
      SelFont(fnt_ss);
      xs = (int)xss+deltaposx;
      ys = (int)y+dyu;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s_up != NULL) DrawString(xs, ys, s_up, txtdir | PI_HorizontalLeft);
      xs = (int)xss+deltaposx;
      ys = (int)y+dyd;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s_dn != NULL) DrawString(xs, ys, s_dn, txtdir | PI_HorizontalLeft);            
    }
    else {
      xs = (int)x+sw_s;
      ys = y;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s != NULL)  DrawString(xs, ys, s, txtdir | PI_HorizontalRight | posv);
      SelFont(fnt_ss);
      xs = (int)x+sw_s+deltaposx;
      ys = (int)y+dyu;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s_up != NULL) DrawString(xs, ys, s_up, txtdir | PI_HorizontalLeft);
      xs = (int)x+sw_s+deltaposx;
      ys = (int)y+dyd;
      compstring_swapcoord(txtdir, xs, ys);    
      if (s_dn != NULL) DrawString(xs, ys, s_dn, txtdir | PI_HorizontalLeft);
    }
  }
  SelFont(fnt_save);
  return;
}

//++ 
// Titre	Tracés de lignes et de figures géometriques
//--
//++
// void  DrawLine(PIGrCoord x1, PIGrCoord y1, PIGrCoord x2, PIGrCoord y2)
//	Trace une ligne entre les points de coordonnées "(x1,y1)" et "(x2,y2)", 
//	en utilisant la couleur d'avant-plan (Foreground)
// void  DrawBox(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy)
//	Tracé du contour d'un rectangle défini par la position du coin "(x0,y0)"
//	et de taille "dx,dy" avec la couleur d'avant-plan.
// void  DrawFBox(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy)
//	Tracé d'un rectangle plein, défini par la position du coin "(x0,y0)"
//	et de taille "dx,dy" avec la couleur d'avant-plan.
// void  DrawCircle(PIGrCoord x0, PIGrCoord y0, PIGrCoord r)  
//	Tracé du contour d'un cercle centré en "(x0,y0)", de rayon "r"
// void  DrawFCircle(PIGrCoord x0, PIGrCoord y0, PIGrCoord r)  
//	Tracé d'un cercle plein centré en "(x0,y0)", de rayon "r"
// void  DrawOval(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy)
//	Tracé d'une ellipse centrée en "(x0,y0)" de demi-axes "dx,dy"
// void  DrawFOval(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy)
//	Tracé d'une ellipse pleine centrée en "(x0,y0)" de demi-axes "dx,dy"
// void  DrawPolygon(PIGrCoord *x, PIGrCoord *y, int n, bool cinc=true)
//	Tracé du contour d'un polygone défini par le tableau des "n" points "x,y".
//	Si "cinc==true", les coordonnées seront considérées comme relatives
//	à la position du point "(x[0], y[0])". Dans le cas contraire, chaque couple
//	"(x[i], y[i])" représentera les coordonnées absolues d'un coin du polygone.
// void  DrawFPolygon(PIGrCoord *x, PIGrCoord *y, int n, bool cinc=true)
//	Tracé d'un polygone plein de la couleur d'avant-plan.
// void  DrawArc(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy, double degdeb, double degfin)
//	Tracé d'un arc de cercle ou d'ellipse, centrée en "(x0,y0)" de demi-axes "dx,dy"
//	L'arc couvre un angle "deltadeg" en degré, et commence au point défini
//	par l'angle "degdeb". Le sens positif angulaire est celui de la rotation
//	de l'axe X vers Y. Le point (0,1) a 90 deg. (-1,0) a 180 deg.
// void  DrawFArc(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy, double degdeb, double degfin)
//	Tracé d'un arc de cercle ou d'ellipse plein, centrée en "(x0,y0)" de demi-axes "dx,dy"
//	L'arc couvre un angle "deltadeg" en degré, et commence au point défini
//	par l'angle "degdeb". Le sens positif angulaire est celui de la rotation
//	de l'axe X vers Y. Le point (0,1) a 90 deg. (-1,0) a 180 deg.
//
// Draw3PtArc(PIGrCoord x1, PIGrCoord y1, PIGrCoord x2, PIGrCoord y2, \
//            PIGrCoord x3, PIGrCoord y3)
//	Tracé d'un arc de cercle spécifié par trois points "(x1,y1)", "(x2,y2)" et "(x3,y3)"
// Draw3PtFArc(PIGrCoord x1, PIGrCoord y1, PIGrCoord x2, PIGrCoord y2, \
//             PIGrCoord x3, PIGrCoord y3)
//	Tracé d'un arc de cercle plein spécifié par trois points "(x1,y1)", "(x2,y2)" et "(x3,y3)"
//--
//++
// ComputeArcFrom3Pt(double x1, double y1, double x2, double y2, \
//                   double x3, double y3, double& x0, double& y0, 
//                   double& dx, double& dy, double& degdeb, double& deltadeg)
//	Calcul des coordonnees du centre, du rayon, ainsi que l'extension
//	angulaire d'un arc de cercle specifie par trois points. 
//	*methode statique*
//--


/* --Methode-- */
void PIGraphicGen::Draw3PtArc(PIGrCoord x1, PIGrCoord y1, PIGrCoord x2, PIGrCoord y2,
			      PIGrCoord x3, PIGrCoord y3)
  // Trace d'un arc de cercle passant par 3 points
{
  double x0, y0;
  double dx, dy;
  double degdeb, degfin;
  int rc;
  rc = ComputeArcFrom3Pt(x1, y1, x2, y2, x3, y3, x0, y0, dx, dy, degdeb, degfin);
  if (rc != 0) return;
  DrawArc(x0, y0, dx, dy, degdeb, degfin);
}

/* --Methode-- */
void PIGraphicGen::Draw3PtFArc(PIGrCoord x1, PIGrCoord y1, PIGrCoord x2, PIGrCoord y2,
			       PIGrCoord x3, PIGrCoord y3)
  // Trace d'un arc de cercle passant par 3 points
{
  double x0, y0;
  double dx, dy;
  double degdeb, degfin;
  int rc;
  rc = ComputeArcFrom3Pt(x1, y1, x2, y2, x3, y3, x0, y0, dx, dy, degdeb, degfin);
  if (rc != 0) return;
  DrawFArc(x0, y0, dx, dy, degdeb, degfin);
}

/* --Methode-- */
int PIGraphicGen::ComputeArcFrom3Pt(double x1, double y1, double x2, double y2,
				    double x3, double y3, double& x0, double& y0, 
				    double& dx, double& dy, double& degdeb, double& deltadeg)
{
  x0 = y0 = dx = dy = 0.;
  degdeb = deltadeg = 0.;
  double px[2], py[2];
  //  cout << "DBG - Arc3Pt" << x1 << "," << y1 << " - "
  //     << x2 << "," << y2 << " - " 
  //     << x3 << "," << y3 << endl;

  // Milieu de M1-M2
  px[0] = (x1+x2)*0.5;
  py[0] = (y1+y2)*0.5;
  // Milieu de M2-M3
  px[1] = (x2+x3)*0.5;
  py[1] = (y2+y3)*0.5;
  double delx, dely;
  double a[2], b[2];
  bool xcst[2];
  for(int i=0; i<2; i++) {
    if (i == 0) {
      delx = x2-x1;
      dely = y2-y1;
    }
    else {
      delx = x3-x2;
      dely = y3-y2;
    }
    if ((fabs(delx) > PETIT_DBLE) && (fabs(dely) > PETIT_DBLE)) {
      // Direction perpendiculaire a M1-M2 , M2-M3
      double alpha = atan2( dely, delx) + M_PI/2.;
      a[i] = tan(alpha);
      b[i] = py[i]-a[i]*px[i];
      xcst[i] = false;
    }
    else if (fabs(delx) > PETIT_DBLE) {
      a[i] = b[i] = px[i];
      xcst[i] = true;
    }
    else if (fabs(dely) > PETIT_DBLE) {
      a[i] = 0.; b[i] = py[i];
      xcst[i] = false;
    }
    else { 
      cerr << " PIGraphicGen::ComputeArcFrom3Pt()/Error - delx=" << delx 
	   << " dely=" << dely << " (=0) for i=" << i << endl;
      return(1);
    }
  }
  if (xcst[0] && xcst[1]) {
    cerr << " PIGraphicGen::ComputeArcFrom3Pt()/Error - xcst[0]&&xcst[1]" << endl; 
    return(2);
  }
  double xc,yc;
  double dela = a[1]-a[0];
  if (xcst[0] || xcst[1]) {
    if (xcst[0]) {
      xc = px[0];  yc = a[1]*xc+b[1];
    }
    else {
      xc = px[1];  yc = a[0]*xc+b[0];
    }
  }
  else {
    if (fabs(dela) < PETIT_DBLE) {
      cerr << " PIGraphicGen::ComputeArcFrom3Pt()/Error - a[1]-a[0]=" << dela << " a[0]=" << a[0] << " a[1]=" << a[1] << endl; 
      return(3);    
    }
    xc = (b[0]-b[1])/dela;  yc = a[0]*xc+b[0];
  }
  delx = x1-xc; 
  dely = y1-yc; 
  double r = sqrt(delx*delx+dely*dely);
  double ang1 = atan2(dely, delx);
  double delx2 = x3-xc; 
  double dely2 = y3-yc; 
  double ang2 = atan2(dely2, delx2);
  // angle M1-O-M3 : Produit scalaire OM1 . OM3 
  double cda = (delx*delx2+dely*dely2)/sqrt(delx*delx+dely*dely)/sqrt(delx2*delx2+dely2*dely2);
  double dang = acos(cda);
  double sda = 0.;
  double daopi = 1;
  if (fabs(dang-M_PI) < 1.e-19) {
    delx2 = x2-xc;
    dely2 = y2-yc;
  // angle M1-O-M2 : Produit vectoriel OM1 X OM2 - Signe de l'angle deltaAngle
    sda = (delx*dely2-dely*delx2);
  }
  else {
  // angle M1-O-M3 : Produit vectoriel OM1 X OM3 - Signe de l'angle deltaAngle
    sda = (delx*dely2-dely*delx2);
  // Produit scalaire (OM1 + OM3) . OM2 : deltaAngle ou 2*PI-DeltaAngle
    delx = (x1+x3)-2*xc; 
    dely = (y1+y3)-2*yc;
    daopi = (delx*delx2+dely*dely2)/sqrt(delx*delx+dely*dely)
                                   /sqrt(delx2*delx2+dely2*dely2);
  }
  if (sda >= 0.) {
    if (daopi < 0.) { 
      degdeb = ang2*180./M_PI;    
      deltadeg = (360.-dang*180./M_PI);
    }
    else {
      degdeb = ang1*180./M_PI;    
      deltadeg = dang*180./M_PI;
    }
  }
  else {
    if (daopi < 0.) { 
      degdeb = ang1*180./M_PI;    
      deltadeg = (360.-dang*180./M_PI);
    }
    else {
      degdeb = ang2*180./M_PI;    
      deltadeg = dang*180./M_PI;
    }
  }
  while (degdeb < 0.) degdeb += 360.;
  while (degdeb > 360.) degdeb -= 360.;
  x0 = xc;
  y0 = yc;
  dx = dy = r;
  //  cout << "DBG - Arc3Pt-2  " << xc << "," << yc << " R=" << r << " deg= "
  //       << degdeb << " Delta= " << deltadeg << endl;
  return(0);
}

//++ 
// Titre	Tracés de signes et de flèches
//--
//++
// void  DrawMarker(PIGrCoord x0, PIGrCoord y0)  
//	Tracé d'un signe au point "(x0,y0)". Le choix du signe tracé s'effectue
//	à travers la méthode "SelMarker()"
// void  DrawMarkers(PIGrCoord *x, PIGrCoord *y, int n)
//	Tracé de "n" signes aux points "(x[i],y[i])"
// void DrawArrowMarker(PIGrCoord x1, PIGrCoord y1, PIGrCoord x2, PIGrCoord y2, \
//      bool fgline=true)
//	Tracé d'un signe de type flèche orienté selon la droite "x1,y1" -> "x2,y2".
//	Si "fgline==true", la ligne "(x1,y1) (x2,y2)" est aussi tracée.
//--

/* --Methode-- */
void 
PIGraphicGen::DrawArrowMarker(PIGrCoord x1, PIGrCoord y1, PIGrCoord x2, PIGrCoord y2, bool fgline)
{
  double dx = (double)x2-(double)x1;
  double dy = (double)y2-(double)y1;
  double theta = atan2(dy, dx);

  PIGrCoord x[5], y[5];
  PIGrCoord x2l, y2l;
  bool fgfill = false;
  int npt = 3;
  double t0,tp,tm,asz;

  switch (myArrowMrk) {

  case PI_BasicArrowMarker :
    t0 = M_PI/4.;
    asz = (double)myArrowMrkSz/cos(t0)*0.75;
    tp = theta+0.75*M_PI;
    tm = theta-0.75*M_PI;
    x[0] = (double)x2 + cos(tp)*asz;
    y[0] = (double)y2 + sin(tp)*asz;
    x[1] = x2;
    y[1] = y2;
    x[2] = (double)x2 + cos(tm)*asz;
    y[2] = (double)y2 + sin(tm)*asz;
    x2l = x2;  y2l =y2;
    fgfill = false;
    npt = 3;
    break;

  case PI_TriangleArrowMarker :
  case PI_FTriangleArrowMarker :
    t0 = M_PI/6.;
    asz = (double)myArrowMrkSz/cos(t0);
    tp = theta+5.*M_PI/6.;
    tm = theta-5.*M_PI/6.;
    x[0] = (double)x2 + cos(tp)*asz;
    y[0] = (double)y2 + sin(tp)*asz;
    x[1] = x2;
    y[1] = y2;
    x[2] = (double)x2 + cos(tm)*asz;
    y[2] = (double)y2 + sin(tm)*asz;
    x[3] = x[0];
    y[3] = y[0];
    x2l = (double)x2 - cos(theta)*myArrowMrkSz;
    y2l = (double)y2 - sin(theta)*myArrowMrkSz;
    npt = 4;
    if (myArrowMrk == PI_FTriangleArrowMarker)  fgfill = true;
    else  fgfill = false;
    break;

  case PI_ArrowShapedArrowMarker :
  case PI_FArrowShapedArrowMarker :
    t0 = M_PI/8.;
    asz = 2.*(double)myArrowMrkSz*cos(t0);
    tp = theta+7.*M_PI/8.;
    tm = theta-7.*M_PI/8.;
    x2l = (double)x2 - cos(theta)*myArrowMrkSz;
    y2l = (double)y2 - sin(theta)*myArrowMrkSz;
    x[0] = x2;  
    y[0] = y2;
    x[1] = (double)x2 + cos(tp)*asz;
    y[1] = (double)y2 + sin(tp)*asz;
    x[2] = x2l;
    y[2] = y2l;
    x[3] = (double)x2 + cos(tm)*asz;
    y[3] = (double)y2 + sin(tm)*asz;
    x[4] = x[0];
    y[4] = y[0];
    npt = 5;
    if (myArrowMrk == PI_FArrowShapedArrowMarker)  fgfill = true;
    else  fgfill = false;
    break;
    
  default:
    t0 = M_PI/4.;
    asz = (double)myArrowMrkSz/cos(t0)*0.75;
    tp = theta+5.*M_PI/4.;
    tm = theta-5.*M_PI/4.;

    x[0] = (double)x2 + cos(tp)*asz;
    y[0] = (double)y2 + sin(tp)*asz;
    x[1] = x2;
    y[1] = y2;
    x[2] = (double)x2 + cos(tm)*asz;
    y[2] = (double)y2 + sin(tm)*asz;
    x[3] = x[0];
    y[3] = y[0];
    x2l = x2;  y2l =y2;
    fgfill = false;
    npt = 3;
    break;
  }

  if (fgline)  DrawLine(x1, y1, x2l, y2l);

  if (fgfill)  DrawFPolygon(x, y, npt, false);
  else  DrawPolygon(x, y, npt, false);
}

//++
// Titre	Tracé d'images (pixmap)
//--
//++
// void  DrawPixmap(PIGrCoord x, PIGrCoord y, unsigned char *pix, int sx, int sy, PIColorMap* cmap)
//	Tracé d'un pixmap dans un rectangle positionné en "(x,y)". Le tableau des pixels
//	"pix", de taille "sx,sy" représente les index dans la table de couleur "cmap".
//--

//++
// Titre	Modifications des attributs graphiques	
//--
//++
// void  SelForeground(PIColors col=PI_Black)
//	Choix de la couleur de tracé d'avant-plan
//|	PI_Black , PI_White,  PI_Grey , PI_Red , PI_Blue , PI_Green ,  
//|	PI_Yellow , PI_Magenta , PI_Cyan , PI_Turquoise , PI_NavyBlue , 
//|	PI_Orange , PI_SiennaRed , PI_Purple , PI_LimeGreen , PI_Gold ,
//|	PI_ColorAllBits0 , PI_ColorAllBits1
// void  SelBackground(PIColors col=PI_White)
//	Choix de la couleur d'arrière-plan
// void  SelForeground(PIColorMap& cmap, int cid) 
//	Choix de la couleur de tracé d'avant-plan: Couleur numéro "cid" de la table de couleur "cmap"
// void  SelBackground(PIColorMap& cmap, int cid)
//	Choix de la couleur d'arrière-plan: Couleur numéro "cid" de la table de couleur "cmap"
// void  SelGOMode(PIGOMode mod=PI_GOCopy) 
//	Choix du mode de tracé graphique: "PI_GOCopy" ou "PI_GOXOR" ou 	"PI_GOInvert"
// void  SelLine(PILineAtt att=PI_NormalLine)
//	Choix du type de ligne pour le tracé des lignes et contours
//|	PI_NormalLine, PI_ThinLine , PI_ThickLine
//|	PI_DashedLine, PI_ThinDashedLine, PI_ThickDashedLine
//|	PI_DottedLine, PI_ThinDottedLine, PI_ThickDottedLine
// void  SelMarker(int msz=3, PIMarker mrk=PI_DotMarker) 
//	Choix de la taille et du type de signe pour "DrawMarker() / DrawMarkers()"
//|	PI_DotMarker , PI_PlusMarker , PI_CrossMarker
//|	PI_CircleMarker , PI_FCircleMarker
//|	PI_BoxMarker , PI_FBoxMarker
//|	PI_TriangleMarker , PI_FTriangleMarker
//|	PI_StarMarker , PI_FStarMarker
// void  SelArrowMarker(int arrsz=5, PIArrowMarker arrmrk=PI_BasicArrowMarker)
//	Choix de la taille et du type de flèches.
//|	PI_NotDefArrowMarker , PI_BasicArrowMarker
//|	PI_TriangleArrowMarker , PI_FTriangleArrowMarker
//|	PI_ArrowShapedArrowMarker , PI_FArrowShapedArrowMarker
//--

//++
// Titre	Changement de fontes
//--
//++
// void  SelFont(PIFont & fnt)
//	Choix de fonte courant.
// void  SelFont(PIFontSize sz=PI_NormalSizeFont, PIFontAtt att=PI_RomanFont)
//	Changement de taille et attribut de fonte
//|	PI_TinySizeFont, PI_SmallSizeFont , PI_NormalSizeFont 
//|	PI_BigSizeFont, PI_VeryLargeSizeFont , PI_HugeSizeFont
//|	PI_RomanFont , PI_BoldFont 
//|	PI_ItalicFont , PI_BoldItalicFont
// void  SelFontSzPt(int npt=12, PIFontAtt att=PI_RomanFont)
//	Choix de taille de fonte avec spécification de taille en points 
//	(pixels sur l'écran)
// 
//--

void
PIGraphicGen::SelArrowMarker(int arrsz, PIArrowMarker arrmrk)
{
  if (arrsz > 0) myArrowMrkSz = arrsz;
  myArrowMrk = arrmrk;
}

//++
// Titre	Sélection de la zone de tracé (clip)	
//--
//++
// void  SetClipRectangle(PIGrCoord x0, PIGrCoord y0, PIGrCoord dx, PIGrCoord dy)
//	Limite la zone de tracé permise au rectangle "(x0,y0)", "dx,dy"
// void  ClearClipRectangle() 
//	Supprime si nécéssaire la limitation de la zone de tracé.	
//--

//++
// Titre	Accès aux attributs graphiques
//--
//++
// PIColors  GetForeground()
//	Renvoie la couleur de tracé d'avant-plan courante. 
//	("PI_ColorFromMap" si défini à partir d'une table de couleur
// PIColors  GetBackground()
//	Renvoie la couleur d'arrière-plan courante.
// PIGOMode  GetGOMode()
//	Renvoie le mode de tracé graphique courante.
// PIFontAtt GetFontAtt()
//	Renvoie les attributs de la fonte courante.
// int GetFontSize() 
//	Renvoie la taille de la fonte courante.
// PILineAtt GetLineAtt() 
//	Renvoie le type de ligne courant
// PIMarker  GetMarker() 
//	Renvoie le type de signe (Marker) courant
// int GetMarkerSize()
//	Renvoie la taille des signes (Marker) pour le marker courant
// PIFont  GetFont()
//	Retourne une copie de l'objet "PIFont" courant.
// PIGrCoord  GetFontHeight(PIGrCoord& asc, PIGrCoord& desc);
//	Renvoie la hauteur des caractères, ainsi que la taille au dessus
//	et en-dessous de la ligne de base ("asc , desc") pour la fonte courante
//	dans le système de coordonnées courant (Fenêtre ou UC).
// PIGrCoord CalcStringWidth(char const* s)
//	Renvoie la largeur occupé par un texte s'il était affiché dans le 
//	système de coordonnées courant (Fenêtre ou UC).
// bool  CalcStringPositionShift(char const* s, unsigned long pos, \
//       int& dx, int& dy)
//	Renvoie le shift de position compte tenu du flag de positionnement "pos"
//--

/* --Methode-- */
PIArrowMarker PIGraphicGen::GetArrowMarker()
{
  return(myArrowMrk);
}

/* --Methode-- */
int PIGraphicGen::GetArrowMarkerSize()
{
  return(myArrowMrkSz);
}

/* --Methode-- */
PIGrCoord PIGraphicGen::GetFontHeight(PIGrCoord& asc, PIGrCoord& desc)
{
int t,a,d;
t = myFont.GetFontHeight(a, d);
asc = a;   desc = d;
return(t);
}

/* --Methode-- */
PIGrCoord PIGraphicGen::CalcStringWidth(char const* s)
{
return (myFont.GetStringWidth(s));
}

/* --Methode-- */
bool PIGraphicGen::CalcStringPositionShift(char const* s, unsigned long pos, 
					   int& dx, int& dy)
{
  dx = 0;
  dy = 0;
  if (pos == 0) return(false);
  else {
    int posh = pos & PI_HorizontalPosition;
    int posv = pos & PI_VerticalPosition;
    if ( ((posh == 0) &&  (posv == PI_VerticalBaseLine)) || 
	 ((posh == PI_HorizontalLeft) && (posv == 0)) ||
	 ((posh == PI_HorizontalLeft) && (posv == PI_VerticalBaseLine)) )
      return(false);
    if (posh != PI_HorizontalLeft) {
      int wx = myFont.GetStringWidth(s);
      if (posh == PI_HorizontalCenter)  dx = wx/2;
      else if (posh == PI_HorizontalRight)  dx = wx;
      else wx = 0;
    }
    if (posv != PI_VerticalBaseLine) {
      int asc,desc;
      int wy = myFont.GetFontHeight(asc, desc);
      if (posv == PI_VerticalBottom) dy = desc;
      else if (posv == PI_VerticalCenter)  dy = -wy/2+desc;
      else if (posv == PI_VerticalTop)  dy = -wy+desc;
      else dy = 0;
    }
    return(true);
  }
}


//++
// Titre	Sauvegarde et rappel des attributs graphiques
//--
//++
// void  SaveGraphicAtt()
//	Sauvegarde des attributs graphiques courants
// void  RestoreGraphicAtt()
//	Utilisation de l'ensemble des attributs graphiques sauvegardés par un appel
//	à "SaveGraphicAtt()"
//--


/* --Methode-- */
void PIGraphicGen::SaveGraphicAtt()
{
  // Doit-on sauver et utiliser l'etat de lock ? Reza - Mai 2003
  sFCol = GetForeground();
  sBCol = GetBackground();
  sGOm = GetGOMode();
  sFont = GetFont();   
  sLAtt = GetLineAtt();
  sMrk = GetMarker();   
  sMrkSz = GetMarkerSize();
  sArrowMrk = GetArrowMarker();
  sArrowMrkSz = GetArrowMarkerSize();
  return;
}

/* --Methode-- */
void PIGraphicGen::RestoreGraphicAtt()
{
  UnLockForegroundColor(); // Doit-on sauver et utiliser l'etat de lock ?
  SelForeground(sFCol);
  SelBackground(sBCol);
  SelGOMode(sGOm);
  SelFont(sFont);
  SelLine(sLAtt);
  SelMarker(sMrkSz, sMrk);
  SelArrowMarker(sArrowMrkSz, sArrowMrk);
  return;
}



