/**
 * Un exemple typique de  la classe 'Point2d' des points sur le plan !
 */
import java.io.*;
import static java.lang.System.*;   // cf. Java  5  pour employer 'out' directement  ...
import static java.lang.Math.*;   //  pour employer  directement 'abs', 'sqrt' etc  ...
/**
 * 'Point2d': CLASSE A EXTRAIRE POUR LA METTRE DANS
 *            LE PAQUET 'esstin.outils' sous le nom 'Point2d.java'
 * La classe 'Point2d' ne peut pas être déclarée "public" ici car la méthode
 * 'main' appartient a la classe 'tPoint2d'. La classe 'Point2d' reste
 * cependant utilisable depuis n'importe quelle classe du paquet par défaut.
 * @author  H. Nguyen-Phu
 * @version 1.3  30.09.2007 
 * @since    1.0  30.09.2004
 * @see  tpoint2d
 */
class  Point2d  {  // A RAJOUTER le mot clé 'public' (cf. Exemple 'es_.java')
/** 'jer' est  un alias de 'System.err' pour afficher des erreurs   */
       static final PrintWriter jer= new PrintWriter(System.err, true);

/** Voici le bloc des ATTRIBUTS privés (i.e. encapsulés)  */
/**    Label : nom affecte' au point courant  */
       private char Label;
/**    abs : Abscisse du point  - A distinguer avec la méthode 'abs' de la classe 'Math' ici   !! */
       private float abs;
/**    ord : Ordonnée du point  */
       private float ord;

/**  Voici le bloc des méthodes constructives ou CONSTRUCTEURS  */
/**    Constructeur sans argument : création de l'origine 'O' = (0,0)  par exemple ici ! */
       public Point2d()                    {
         Label = 'O';  // 'O' comme Origine
         abs = 0;         ord = 0;       }
/**    Constructeur à  argument unique pour clonage effectif ou constructeur de (re-)copie conforme  */
       public Point2d(Point2d unPoint)        {
         Label = unPoint.Label; 
         abs = unPoint.abs;   ord = unPoint.ord;   }	 
/**    Constructeur avec deux arguments
        * @param abs  Abscisse à modifier  (attention: C'est le même nom que l'attribut à modifier !)
        * @param ord  Ordonnée à modifier  (attention: C'est le même nom que l'attribut à modifier !)
        */  public Point2d(float abs, float ord)           {
         Label = ' ';  // ' ' <==> caractère blanc <==> pas de nom !
         this.abs = abs;       this.ord = ord;        }
/**    Constructeur avec trois arguments
        * @param c     Label à modifier
        * @param abs_  Abscisse à modifier
        * @param ord_  Ordonnée à modifier
        */    public Point2d(char c, float abs_, float ord_)  {
           Label = c;    abs = abs_;   ord = ord_;       }

/**  Voici le bloc des méthodes modificatrices ou MODIFIEURS  */
/**    Procédure modificatrice de 'Label'
        * @param  Label :  Nouveau Label (attention: C'est le même nom que l'attribut à modifier !)
        */  public void setLabel(char Label) { this.Label = Label; }
/**    Procédure modificatrice de 'abs'
        * @param  abs : Abscisse à modifier  (attention: C'est le même nom que l'attribut à modifier !)
        */  public void setAbs(float abs) {this.abs = abs; }
/**    Procédure modificatrice de 'ord'
        * @param  ord  :  Ordonnée à modifier (attention: C'est le même nom que l'attribut à modifier !)
        */  public void setOrd(float ord) {this.ord = ord; }
/**    Procédure modificatrice 'translation'
 *     @param  deltaX : variation sur l'abscisse en mode 'Donnée'
 *     @param  deltaY : variation sur l'ordonnée en mode 'Donnée'
 *     Aucun type retourné  mais le point repéré par la réf. "this" est modifié.
 */  public void translation(float deltaX, float deltaY)  {
         abs += deltaX;  ord += deltaY;                  }
/**    Procédure modificatrice 'homothetie'
 *     @param  k : facteur multiplicatif d'homothétie en mode 'Donnée'
 *     Aucun type retourné mais le point repéré par la référence "this" est modifié.
 */  public void homothetie(float k)  {  // k facteur d'homothétie
         abs *= k;  ord *= k;        }	
/**    Procédure modificatrice 'rotation'
  *     @param  angle :  angle 'theta'  en mode de  'Donnée', exprimé en radians ici !
  */ 	public void rotation(float angle)  {  // angle en radians !
    //  A COMPLETER en employant la  matrice de rotation ... -  cf.  produit de 2 nombres  complexes 




	}
/**    Procédure modificatrice 'similitude' <==>  'rotation' O 'homothetie' <==>  'homothetie'  O  'rotation'  [ O : composition de transformation géométrique ]
 *     @param  k : facteur multiplicatif en mode de 'Donnée'
  *     @param  angle :  angle 'theta'  en mode de  'Donnée', exprimé en radians ici !
  */ 	public void similitude(float k, float angle)  {  // angle en radians !
    //  A COMPLETER en employant une des deux définitions ci-dessus 

	}		 
/**    Procédure modificatrice 'copieIntegrale' <==> METHODE D'INSTANCE  pour copie INTEGRALE
 *     @param  p : un objet (ou instance)  de la classe 'Point2d' en  mode 'Donnée'
 *     Aucun type retourné  mais le point repéré par la référence "this" est modifié.
 */  private void copieIntegrale( Point2d p )  {
	  Label= p.Label; abs= p.abs; ord= p.ord;
// <==>  this.Label= p.getLabel(); this.abs= p.getAbs(); this.ord= p.getOrd();
//      'this' est la référence sur l'instance courante de la classe 'Point2d'
    }
		
/**  Voici le bloc des méthodes d'accès ou ACCESSEURS  */
/**    Fonction d'accès à 'Label'
        * @return le car. Label
        */  public char getLabel() {return Label; }
/**    Fonction d'accès à 'abs'
        * @return l'abscisse
        */  public float getAbs() {return abs; }
/**    Fonction d'accès à 'ord'
        *  @return l'ordonnée
        */  public float getOrd() {return ord; }
/**    Procédure d'affichage     */
       public void affich()  {
         out.println("Nom du point : "+ Label + " de coord. ("+abs+", "+ord+")");                    }
/**    Autre version de 'affich' en (re-)définissant  'toString' de la  super-classe 'Object' - 
        * @return une chaîne décrivant le point avec ses trois champs - VERSION CONSEILLEE en 2A !
        */  
/*		public String toString()                              {
	 	 return "Point2d := "+ Label + " ("+abs+", "+ord+")";   }
*/		 
/**    'estEgal'  Test d'égalité entre un point  du plan  avec le point coutant 'this'
        * @return  un  booléen  
        */   public boolean estEgal(Point2d unP)   { 
		return (Label == unP.Label && abs(this.abs-unP.abs) <= 2e-7 && abs(ord-unP.ord)<= 2e-7 );  }
	
/**    Test d'égalité  en  (re-)définissant  'equals' de la classe mère 'Object' - A DEBOGUER !
        * @return  un  booléen  
        */
	public boolean equals(Object objet)   { 
      if (objet == this) return true;  
      if (objet.getClass() != this.getClass()) return false;
      Point2d unP = (Point2d) objet;  // Transtypage  de 'Object'  en 'Point2d'
	  return (Label == unP.Label && abs(this.abs-unP.abs) <= 2e-7 && abs(ord-unP.ord)<= 2e-7 );  }
    //Q.:  Pourquoi  2 10^-07  ici  ?   
	// Rép. :  Pour éviter les erreurs d'arrondis et c'est  la précision relative de la norme IEEE  754 en simple précision ... 
	
/**    Calcul du code de hachage d'un point du plan  en (re-)définissant 'hashCode' de la classe  'Object' 
        * @return  un entier   -
        */  public int hashCode()  { 
		return (int) (1.1f*(new Float(abs)).hashCode()+ 0.9f*(new Float(ord)).hashCode()) + (new Character(Label)).hashCode(); }
  // Q.:   Pourqoui la pondération par  1.1  et 0.9 ici ?  :

/**    Clonage  du  point  courant 'this'   en (re-)définissant 'clone' de la classe  'Object' 
        * @return   un nouvel ojet de type  'Point2d'
        */ 
    // protected Point2d clone() { 
	protected Point2d clone()  throws CloneNotSupportedException  { 
		return  new Point2d(this);
    }

/**  Voici le bloc des "Autres Méthodes"   */	   
/**
 * METHODE DE CLASSE appartenant a` TOUS les objets appelée aussi 'méthode statique'
 * Elle doit effectuer un échange EFFECTIF entre deux objets formels 'a' et 'b'
 * @param a : premier point de la classe 'Point2d' en mode D/R (Donnée ET Résultat)
 * @param b : second  point de la classe 'Point2d' en mode D/R (Donnée ET Résultat)
 * Aucun type retourné
 */
       public static void echange(Point2d a, Point2d b) { // A DEBOGUER ...
        Point2d aux = new Point2d();

        aux = a;    // aux(ref) <-- a(ref) :  copie de surface car affectation de ref. uniquement !
	    // aux.copieIntegrale(a);   // copie complète des attributs de 'a' dans 'aux'
        jer.println("\taux : "+ aux); // impression intermédiaire pour vérification
        a = b;      // a(ref) <-- b(ref) : copie superficielle
	    // a.copieIntegrale(b);   // copie complète des attributs de 'b' dans 'a'
        jer.println("\ta   : "+ a);
        b = aux;    // b(ref) <-- aux(ref) : copie superficielle
	    // b.copieIntegrale(aux); // copie complète des attributs de 'aux' dans 'b'
        jer.println("\tb   : "+ b);
      }
}

/**
 * Classe 'tpoint2d' pour tester 'Point2d'
 * Elle contient la méthode principale 'main' et doit être publique ici.
 * @see  Point2d
 */
public class tpoint2d {
/** 'jo' est  un alias de 'System.out' pour soulager la frappe ... */
        static final PrintWriter jo = new PrintWriter(System.out, true);
	/*** Méthode principale publique 'main(...)'.
		*   @param args Tableau de chaînes pour ligne de commande éventuelle
	*/ public static void main(String args[]) throws CloneNotSupportedException  {
		Point2d  o, m, n;
        jo.println("tpoint2d: Vérif. de schéma mémoire & test d'encapsulation d'attributs privés");
        jo.println("--------  + Test d'affectations de références d'objets dr type 'Point2d'\n");
        jo.println("A ANALYSER & DEBOGUER & COMPLETER ... (c)~/2A env. - 10h50 2007.09.30\n");

        o= new Point2d();  // test du constructeur sans arguments !
		jo.println("L'objet 'o' de type " + o ); 
		o.affich(); //  'print( ... + o)' fait appel à  la méthode 'toString'  surchargée  ci-dessus
        m= new Point2d('M', 1, 1); // test du constructeur à 3 arguments !
		jo.println("L'objet 'm' de type " + m); m.affich();
        jo.println("o == m est '"+ (o == m) + "'! C'est correct.");    	                               // "=="  fait appel à 'equals' ici !
   		n= m.clone(); // test du constructeur de  clonage via la méthode  (re-)définie 'clone'
		jo.println("\nPar clonage, l'instance 'n' de type " + n); n.affich(); 
		jo.println("n.estEgal(m) est "+ (n.estEgal(m) ? " VRAI !" : "FAUX !") );
		// jo.println("n == m  est '"+ (n == m) + "'!  Pourquoi ?");
		
        n.setLabel('N'); 
		jo.println("\nAprès 'setLabel' par N, 'n' de type " + n); n.affich(); 
        jo.println("n == m  est '"+ (n == m) + "'! C'est correct.");
		
        m.translation(1, 2);
		jo.println("\nApres translation par vecteur(1,2), 'm' de type " + m); m.affich();
        n=m; jo.println("Après l'affectation 'n=m;', les réf. 'n' et 'm' sont identiques !");
		jo.println("Donc  n == m  est '"+ (n == m) + "' car c'est une  égalité  SUPERFICIELLE !!");
        jo.println("En effet, 'n' désigne le même objet que 'm' de type "+ n); n.affich();
		
		n.setLabel('N');  // Donc,  le point M aura comme label 'N' !
        jo.println("\nAprès  'setLabel'  par N, la réf.  'n'  pointe sur "+n); n.affich();
		jo.println("Et la réf. 'm' pointe toujours sur le même objet "+m); m.affich();  
		/* Attention: c'est le nom 'N' qui est affiché  à ce niveau !   */
		
        m.translation(-1f, -2f); 
		jo.println("\nAprès translation(-1, -2),  'm' désigne maintenant " + m); m.affich();
		// pour revenir sur le point 'M' initial mais avec le label 'N'
        float gain = 3f;
        m.homothetie(gain);
        Point2d l = new Point2d(m); l.setLabel('L');
        jo.println("L'homoth\u00e9tie de M via le gain "+gain+" donne un nouveau "+ l); l.affich();
		
		m= new Point2d('M', 1, 1); // pour ré-initialiser  l'objet référencé par  'm' de départ
        jo.println("\nAVANT \u00e9change des points l ('L') et m ('M') :");
        jo.print("l: "+ l); jo.println("  m: "+ m + "\n");

        Point2d.echange(l, m); //  appel de la méthode de classe en préfixant par le nom de la classe même
        l.setLabel('L');  m.setLabel('M');   /*     MAJ des bons labels !!  */

        jo.println("\nAPRES \u00e9change des points l ('L') et m ('M') :");
        jo.print("l: "+ l); jo.println("  m: "+ m + "\n\nPROBLEME: Aucun échange effectué ici ! Comment y remédier ?");


// Pour stabiliser l'écran avant de quitter, choisir entre:
        es.attente();  // 'es'  est dans le paquet par défaut avec 'tpoint2d'
//	es_.attente(); // 'es_' sera rangé dans le paquet  "esstin.outils"
//      es__.attente();// 'es__' sera rangé dans le paquet "esstin.test"

  }
}
