// @(#)root/geom:$Id$
// Author: Andrei Gheata   25/10/01

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TGeoMatrix
#define ROOT_TGeoMatrix

/*************************************************************************
 * Geometrical transformations. TGeoMatrix - base class, TGeoTranslation *
 * TGeoRotation, TGeoScale, TGeoCombiTrans, TGeoGenTrans .               *
 *                                                                       *
 *************************************************************************/

#include "TNamed.h"

//--- globals
const Double_t kNullVector[3] = {0.0, 0.0, 0.0};

const Double_t kIdentityMatrix[3 * 3] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};

const Double_t kUnitScale[3] = {1.0, 1.0, 1.0};

class TGeoHMatrix;

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoMatrix - base class for geometrical transformations.               //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoMatrix : public TNamed {
public:
   enum EGeoTransfTypes {
      kGeoIdentity = 0,
      kGeoShared = BIT(14),
      kGeoTranslation = BIT(17),
      kGeoRotation = BIT(18),
      kGeoScale = BIT(19),
      kGeoReflection = BIT(20),
      kGeoRegistered = BIT(21),
      kGeoSavePrimitive = BIT(22),
      kGeoMatrixOwned = BIT(23),
      kGeoCombiTrans = kGeoTranslation | kGeoRotation,
      kGeoGenTrans = kGeoTranslation | kGeoRotation | kGeoScale,
      kGeoMatrixBits = kGeoShared | kGeoGenTrans | kGeoReflection | kGeoRegistered | kGeoSavePrimitive | kGeoMatrixOwned
   };

protected:
   TGeoMatrix(const TGeoMatrix &other);

public:
   TGeoMatrix();
   TGeoMatrix(const char *name);
   ~TGeoMatrix() override;

   Bool_t IsIdentity() const { return !TestBit(kGeoGenTrans); }
   Bool_t IsTranslation() const { return TestBit(kGeoTranslation); }
   Bool_t IsRotation() const { return TestBit(kGeoRotation); }
   Bool_t IsReflection() const { return TestBit(kGeoReflection); }
   Bool_t IsScale() const { return TestBit(kGeoScale); }
   Bool_t IsShared() const { return TestBit(kGeoShared); }
   Bool_t IsOwned() const { return TestBit(kGeoMatrixOwned); }
   Bool_t IsCombi() const { return (TestBit(kGeoTranslation) && TestBit(kGeoRotation)); }
   Bool_t IsGeneral() const { return (TestBit(kGeoTranslation) && TestBit(kGeoRotation) && TestBit(kGeoScale)); }
   Bool_t IsRegistered() const { return TestBit(kGeoRegistered); }
   Bool_t IsRotAboutZ() const;
   void GetHomogenousMatrix(Double_t *hmat) const;
   const char *GetPointerName() const;

   virtual Int_t GetByteCount() const;
   virtual const Double_t *GetTranslation() const = 0;
   virtual const Double_t *GetRotationMatrix() const = 0;
   virtual const Double_t *GetScale() const = 0;
   virtual TGeoHMatrix Inverse() const = 0;
   virtual void LocalToMaster(const Double_t *local, Double_t *master) const;
   virtual void LocalToMasterVect(const Double_t *local, Double_t *master) const;
   virtual void LocalToMasterBomb(const Double_t *local, Double_t *master) const;
   virtual TGeoMatrix *MakeClone() const = 0;
   virtual void MasterToLocal(const Double_t *master, Double_t *local) const;
   virtual void MasterToLocalVect(const Double_t *master, Double_t *local) const;
   virtual void MasterToLocalBomb(const Double_t *master, Double_t *local) const;
   static void Normalize(Double_t *vect);
   void Print(Option_t *option = "") const override; // *MENU*
   virtual void RotateX(Double_t) {}
   virtual void RotateY(Double_t) {}
   virtual void RotateZ(Double_t) {}
   virtual void ReflectX(Bool_t leftside, Bool_t rotonly = kFALSE);
   virtual void ReflectY(Bool_t leftside, Bool_t rotonly = kFALSE);
   virtual void ReflectZ(Bool_t leftside, Bool_t rotonly = kFALSE);
   virtual void RegisterYourself();
   void SetDefaultName();
   virtual void SetDx(Double_t) {}
   virtual void SetDy(Double_t) {}
   virtual void SetDz(Double_t) {}
   void SetShared(Bool_t flag = kTRUE) { SetBit(kGeoShared, flag); }

   ClassDefOverride(TGeoMatrix, 1) // base geometrical transformation class
};

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoTranslation - class describing translations. A translation is      //
//    basically an array of 3 doubles matching the positions 12, 13       //
//    and 14 in the homogenous matrix description.                        //
//                                                                        //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoTranslation : public TGeoMatrix {
protected:
   Double_t fTranslation[3]; // translation vector
public:
   TGeoTranslation();
   TGeoTranslation(const TGeoTranslation &other);
   TGeoTranslation(const TGeoMatrix &other);
   TGeoTranslation(Double_t dx, Double_t dy, Double_t dz);
   TGeoTranslation(const char *name, Double_t dx, Double_t dy, Double_t dz);
   ~TGeoTranslation() override {}

   TGeoTranslation &operator=(const TGeoTranslation &other) { return TGeoTranslation::operator=((TGeoMatrix &)other); }
   TGeoTranslation &operator=(const TGeoMatrix &matrix);
   TGeoTranslation &operator*=(const TGeoTranslation &other);
   TGeoTranslation operator*(const TGeoTranslation &right) const;
   TGeoHMatrix operator*(const TGeoMatrix &right) const;
   Bool_t operator==(const TGeoTranslation &other) const;

   void Add(const TGeoTranslation *other);
   TGeoHMatrix Inverse() const override;
   void LocalToMaster(const Double_t *local, Double_t *master) const override;
   void LocalToMasterVect(const Double_t *local, Double_t *master) const override;
   void LocalToMasterBomb(const Double_t *local, Double_t *master) const override;
   TGeoMatrix *MakeClone() const override;
   void MasterToLocal(const Double_t *master, Double_t *local) const override;
   void MasterToLocalVect(const Double_t *master, Double_t *local) const override;
   void MasterToLocalBomb(const Double_t *master, Double_t *local) const override;
   void RotateX(Double_t angle) override;
   void RotateY(Double_t angle) override;
   void RotateZ(Double_t angle) override;
   void SavePrimitive(std::ostream &out, Option_t *option = "") override;
   void Subtract(const TGeoTranslation *other);
   void SetTranslation(Double_t dx, Double_t dy, Double_t dz);
   void SetTranslation(const TGeoMatrix &other);
   void SetDx(Double_t dx) override { SetTranslation(dx, fTranslation[1], fTranslation[2]); }
   void SetDy(Double_t dy) override { SetTranslation(fTranslation[0], dy, fTranslation[2]); }
   void SetDz(Double_t dz) override { SetTranslation(fTranslation[0], fTranslation[1], dz); }

   const Double_t *GetTranslation() const override { return &fTranslation[0]; }
   const Double_t *GetRotationMatrix() const override { return &kIdentityMatrix[0]; }
   const Double_t *GetScale() const override { return &kUnitScale[0]; }

   ClassDefOverride(TGeoTranslation, 1) // translation class
};

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoRotation - class describing rotations. A rotation is a 3*3 array   //
//    Column vectors has to be orthogonal unit vectors.                   //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoRotation : public TGeoMatrix {
protected:
   Double_t fRotationMatrix[3 * 3]; // rotation matrix

   void CheckMatrix();

public:
   TGeoRotation();
   TGeoRotation(const TGeoRotation &other);
   TGeoRotation(const TGeoMatrix &other);
   TGeoRotation(const char *name);
   //   TGeoRotation(const char *name, Double_t *matrix) ;
   TGeoRotation(const char *name, Double_t phi, Double_t theta, Double_t psi);
   TGeoRotation(const char *name, Double_t theta1, Double_t phi1, Double_t theta2, Double_t phi2, Double_t theta3,
                Double_t phi3);
   ~TGeoRotation() override {}

   TGeoRotation &operator=(const TGeoRotation &other) { return TGeoRotation::operator=((TGeoMatrix &)other); }
   TGeoRotation &operator=(const TGeoMatrix &other);
   TGeoRotation &operator*=(const TGeoRotation &other);
   TGeoRotation operator*(const TGeoRotation &other) const;
   TGeoHMatrix operator*(const TGeoMatrix &right) const;
   Bool_t operator==(const TGeoRotation &other) const;

   Bool_t IsValid() const;
   TGeoHMatrix Inverse() const override;
   void Clear(Option_t *option = "") override;
   Double_t Determinant() const;
   void FastRotZ(const Double_t *sincos);
   void GetAngles(Double_t &theta1, Double_t &phi1, Double_t &theta2, Double_t &phi2, Double_t &theta3,
                  Double_t &phi3) const;
   void GetAngles(Double_t &phi, Double_t &theta, Double_t &psi) const;
   Double_t GetPhiRotation(Bool_t fixX = kFALSE) const;
   void LocalToMaster(const Double_t *local, Double_t *master) const override;
   void LocalToMasterVect(const Double_t *local, Double_t *master) const override
   {
      TGeoRotation::LocalToMaster(local, master);
   }
   void LocalToMasterBomb(const Double_t *local, Double_t *master) const override
   {
      TGeoRotation::LocalToMaster(local, master);
   }
   TGeoMatrix *MakeClone() const override;
   void MasterToLocal(const Double_t *master, Double_t *local) const override;
   void MasterToLocalVect(const Double_t *master, Double_t *local) const override
   {
      TGeoRotation::MasterToLocal(master, local);
   }
   void MasterToLocalBomb(const Double_t *master, Double_t *local) const override
   {
      TGeoRotation::MasterToLocal(master, local);
   }
   void MultiplyBy(const TGeoRotation *rot, Bool_t after = kTRUE);
   void RotateX(Double_t angle) override;
   void RotateY(Double_t angle) override;
   void RotateZ(Double_t angle) override;
   void SavePrimitive(std::ostream &out, Option_t *option = "") override;
   void ReflectX(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void ReflectY(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void ReflectZ(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void SetAngles(Double_t phi, Double_t theta, Double_t psi);
   void SetAngles(Double_t theta1, Double_t phi1, Double_t theta2, Double_t phi2, Double_t theta3, Double_t phi3);
   void SetMatrix(const Double_t *rot)
   {
      memcpy(&fRotationMatrix[0], rot, 9 * sizeof(Double_t));
      CheckMatrix();
   }
   void SetRotation(const TGeoMatrix &other);
   void GetInverse(Double_t *invmat) const;

   const Double_t *GetTranslation() const override { return &kNullVector[0]; }
   const Double_t *GetRotationMatrix() const override { return &fRotationMatrix[0]; }
   const Double_t *GetScale() const override { return &kUnitScale[0]; }

   ClassDefOverride(TGeoRotation, 1) // rotation class
};

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoScale - class describing scale transformations. A scale is an      //
//    array of 3 doubles (sx, sy, sz) multiplying elements 0, 5 and 10    //
//    of the homogenous matrix. A scale is normalized : sx*sy*sz = 1      //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoScale : public TGeoMatrix {
protected:
   Double_t fScale[3]; // scale (x, y, z)
public:
   TGeoScale();
   TGeoScale(const TGeoScale &other);
   TGeoScale(const TGeoMatrix &other);
   TGeoScale(Double_t sx, Double_t sy, Double_t sz);
   TGeoScale(const char *name, Double_t sx, Double_t sy, Double_t sz);
   ~TGeoScale() override;

   TGeoScale &operator=(const TGeoScale &other) { return TGeoScale::operator=((TGeoMatrix &)other); }
   TGeoScale &operator=(const TGeoMatrix &other);
   TGeoScale &operator*=(const TGeoScale &other);
   TGeoScale operator*(const TGeoScale &other) const;
   TGeoHMatrix operator*(const TGeoMatrix &right) const;
   Bool_t operator==(const TGeoScale &other) const;

   TGeoHMatrix Inverse() const override;
   void SetScale(Double_t sx, Double_t sy, Double_t sz);
   void SetScale(const TGeoMatrix &other);
   void LocalToMaster(const Double_t *local, Double_t *master) const override;
   Double_t LocalToMaster(Double_t dist, const Double_t *dir = nullptr) const;
   void LocalToMasterVect(const Double_t *local, Double_t *master) const override
   {
      TGeoScale::LocalToMaster(local, master);
   }
   TGeoMatrix *MakeClone() const override;
   void MasterToLocal(const Double_t *master, Double_t *local) const override;
   Double_t MasterToLocal(Double_t dist, const Double_t *dir = nullptr) const;
   void MasterToLocalVect(const Double_t *master, Double_t *local) const override
   {
      TGeoScale::MasterToLocal(master, local);
   }
   void ReflectX(Bool_t, Bool_t) override
   {
      fScale[0] = -fScale[0];
      SetBit(kGeoReflection, !IsReflection());
   }
   void ReflectY(Bool_t, Bool_t) override
   {
      fScale[1] = -fScale[1];
      SetBit(kGeoReflection, !IsReflection());
   }
   void ReflectZ(Bool_t, Bool_t) override
   {
      fScale[2] = -fScale[2];
      SetBit(kGeoReflection, !IsReflection());
   }

   const Double_t *GetTranslation() const override { return &kNullVector[0]; }
   const Double_t *GetRotationMatrix() const override { return &kIdentityMatrix[0]; }
   const Double_t *GetScale() const override { return &fScale[0]; }

   ClassDefOverride(TGeoScale, 1) // scaling class
};

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoCombiTrans - class describing rotation + translation. Most         //
//    frequently used in the description of TGeoNode 's                   //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoCombiTrans : public TGeoMatrix {
protected:
   Double_t fTranslation[3]; // translation vector
   TGeoRotation *fRotation;  // rotation matrix
public:
   TGeoCombiTrans();
   TGeoCombiTrans(const TGeoCombiTrans &other) : TGeoCombiTrans((TGeoMatrix &)other) {}
   TGeoCombiTrans(const TGeoMatrix &other);
   TGeoCombiTrans(const TGeoTranslation &tr, const TGeoRotation &rot);
   TGeoCombiTrans(const char *name);
   TGeoCombiTrans(Double_t dx, Double_t dy, Double_t dz, TGeoRotation *rot);
   TGeoCombiTrans(const char *name, Double_t dx, Double_t dy, Double_t dz, TGeoRotation *rot);

   TGeoCombiTrans &operator=(const TGeoCombiTrans &other) { return TGeoCombiTrans::operator=((TGeoMatrix &)other); }
   TGeoCombiTrans &operator=(const TGeoMatrix &matrix);
   TGeoCombiTrans &operator*=(const TGeoMatrix &other);
   TGeoCombiTrans operator*(const TGeoMatrix &other) const;
   Bool_t operator==(const TGeoMatrix &other) const;

   ~TGeoCombiTrans() override;

   void Clear(Option_t *option = "") override;
   TGeoHMatrix Inverse() const override;
   TGeoMatrix *MakeClone() const override;
   void Multiply(const TGeoMatrix *right);
   void RegisterYourself() override;
   void RotateX(Double_t angle) override;
   void RotateY(Double_t angle) override;
   void RotateZ(Double_t angle) override;
   void ReflectX(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void ReflectY(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void ReflectZ(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void SavePrimitive(std::ostream &out, Option_t *option = "") override;
   void SetDx(Double_t dx) override { SetTranslation(dx, fTranslation[1], fTranslation[2]); }
   void SetDy(Double_t dy) override { SetTranslation(fTranslation[0], dy, fTranslation[2]); }
   void SetDz(Double_t dz) override { SetTranslation(fTranslation[0], fTranslation[1], dz); }
   void SetTranslation(const TGeoTranslation &tr);
   void SetTranslation(Double_t dx, Double_t dy, Double_t dz);
   void SetTranslation(Double_t *vect);
   void SetRotation(const TGeoRotation &other);
   void SetRotation(const TGeoRotation *rot);

   TGeoRotation *GetRotation() const { return fRotation; }

   const Double_t *GetTranslation() const override { return &fTranslation[0]; }
   const Double_t *GetRotationMatrix() const override;
   const Double_t *GetScale() const override { return &kUnitScale[0]; }

   ClassDefOverride(TGeoCombiTrans, 1) // rotation + translation
};

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoGenTrans - most general transformation, holding a translation,     //
//    a rotation and a scale                                              //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoGenTrans : public TGeoCombiTrans {
protected:
   Double_t fScale[3]; // scale (x, y, z)
public:
   TGeoGenTrans();
   TGeoGenTrans(const char *name);
   TGeoGenTrans(Double_t dx, Double_t dy, Double_t dz, Double_t sx, Double_t sy, Double_t sz, TGeoRotation *rot);
   TGeoGenTrans(const char *name, Double_t dx, Double_t dy, Double_t dz, Double_t sx, Double_t sy, Double_t sz,
                TGeoRotation *rot);
   ~TGeoGenTrans() override;

   void Clear(Option_t *option = "") override;
   TGeoHMatrix Inverse() const override;
   void SetScale(Double_t sx, Double_t sy, Double_t sz);
   void SetScale(Double_t *scale) { memcpy(&fScale[0], scale, 3 * sizeof(Double_t)); }
   TGeoMatrix *MakeClone() const override { return nullptr; }
   Bool_t Normalize();

   const Double_t *GetScale() const override { return &fScale[0]; }

   ClassDefOverride(TGeoGenTrans, 1) // rotation + translation + scale
};

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoIdentity - an identity transformation. It holds no data member     //
//    and returns pointers to static null translation and identity        //
//    transformations for rotation and scale                              //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoIdentity : public TGeoMatrix {
private:
   // no data members
public:
   TGeoIdentity();
   TGeoIdentity(const char *name);
   ~TGeoIdentity() override {}

   TGeoHMatrix Inverse() const override;
   void LocalToMaster(const Double_t *local, Double_t *master) const override
   {
      memcpy(master, local, 3 * sizeof(Double_t));
   }
   void LocalToMasterVect(const Double_t *local, Double_t *master) const override
   {
      memcpy(master, local, 3 * sizeof(Double_t));
   }
   void LocalToMasterBomb(const Double_t *local, Double_t *master) const override
   {
      TGeoIdentity::LocalToMaster(local, master);
   }
   TGeoMatrix *MakeClone() const override { return nullptr; }
   void MasterToLocal(const Double_t *master, Double_t *local) const override
   {
      memcpy(local, master, 3 * sizeof(Double_t));
   }
   void MasterToLocalVect(const Double_t *master, Double_t *local) const override
   {
      memcpy(local, master, 3 * sizeof(Double_t));
   }
   void MasterToLocalBomb(const Double_t *master, Double_t *local) const override
   {
      TGeoIdentity::MasterToLocal(master, local);
   }

   const Double_t *GetTranslation() const override { return &kNullVector[0]; }
   const Double_t *GetRotationMatrix() const override { return &kIdentityMatrix[0]; }
   const Double_t *GetScale() const override { return &kUnitScale[0]; }
   void SavePrimitive(std::ostream &, Option_t * = "") override {}

   ClassDefOverride(TGeoIdentity, 1) // identity transformation class
};

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TGeoHMatrix - Matrix class used for computing global transformations   //
//     Should NOT be used for node definition. An instance of this class  //
//     is generally used to pile-up local transformations starting from   //
//     the top level physical node, down to the current node.             //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

class TGeoHMatrix : public TGeoMatrix {
private:
   Double_t fTranslation[3];    // translation component
   Double_t fRotationMatrix[9]; // rotation matrix
   Double_t fScale[3];          // scale component

public:
   TGeoHMatrix();
   TGeoHMatrix(const TGeoHMatrix &other) : TGeoHMatrix((TGeoMatrix &)other) {}
   TGeoHMatrix(const TGeoMatrix &matrix);
   TGeoHMatrix(const char *name);
   ~TGeoHMatrix() override;

   TGeoHMatrix &operator=(const TGeoHMatrix &other) { return TGeoHMatrix::operator=((TGeoMatrix &)other); }
   TGeoHMatrix &operator=(const TGeoMatrix *other);
   TGeoHMatrix &operator=(const TGeoMatrix &other);
   TGeoHMatrix &operator*=(const TGeoMatrix &other);
   TGeoHMatrix operator*(const TGeoMatrix &other) const;
   Bool_t operator==(const TGeoMatrix &other) const;

   void Clear(Option_t *option = "") override;
   void CopyFrom(const TGeoMatrix *other);
   Double_t Determinant() const;
   void FastRotZ(const Double_t *sincos);
   TGeoHMatrix Inverse() const override;
   TGeoMatrix *MakeClone() const override;
   void Multiply(const TGeoMatrix *right);
   void Multiply(const TGeoMatrix &right) { Multiply(&right); }
   void MultiplyLeft(const TGeoMatrix *left);
   void MultiplyLeft(const TGeoMatrix &left) { MultiplyLeft(&left); }

   void RotateX(Double_t angle) override;
   void RotateY(Double_t angle) override;
   void RotateZ(Double_t angle) override;
   void ReflectX(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void ReflectY(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void ReflectZ(Bool_t leftside, Bool_t rotonly = kFALSE) override;
   void SavePrimitive(std::ostream &out, Option_t *option = "") override;
   void SetDx(Double_t dx) override
   {
      fTranslation[0] = dx;
      SetBit(kGeoTranslation);
   }
   void SetDy(Double_t dy) override
   {
      fTranslation[1] = dy;
      SetBit(kGeoTranslation);
   }
   void SetDz(Double_t dz) override
   {
      fTranslation[2] = dz;
      SetBit(kGeoTranslation);
   }
   void SetTranslation(const Double_t *vect)
   {
      SetBit(kGeoTranslation);
      memcpy(&fTranslation[0], vect, 3 * sizeof(Double_t));
   }
   void SetRotation(const Double_t *matrix)
   {
      SetBit(kGeoRotation);
      memcpy(&fRotationMatrix[0], matrix, 9 * sizeof(Double_t));
   }
   void SetScale(const Double_t *scale)
   {
      SetBit(kGeoScale);
      memcpy(&fScale[0], scale, 3 * sizeof(Double_t));
   }

   const Double_t *GetTranslation() const override { return &fTranslation[0]; }
   const Double_t *GetRotationMatrix() const override { return &fRotationMatrix[0]; }
   const Double_t *GetScale() const override { return &fScale[0]; }

   virtual Double_t *GetTranslation() { return &fTranslation[0]; }
   virtual Double_t *GetRotationMatrix() { return &fRotationMatrix[0]; }
   virtual Double_t *GetScale() { return &fScale[0]; }
   ClassDefOverride(TGeoHMatrix, 1) // global matrix class
};

R__EXTERN TGeoIdentity *gGeoIdentity;

#endif
