// -*- C++ -*-
// ---------------------------------------------------------------------------
//
// This file is a part of the CLHEP - a Class Library for High Energy Physics.
// 
// This is the definitions of the inline member functions of the
// HepLorentzVector class.
//

#include <cmath>

namespace CLHEP {

inline double HepLorentzVector::x() const { return pp.x(); }
inline double HepLorentzVector::y() const { return pp.y(); }
inline double HepLorentzVector::z() const { return pp.z(); }
inline double HepLorentzVector::t() const { return ee; }

inline HepLorentzVector::
HepLorentzVector(double x1, double y1, double z1, double t1)
  : pp(x1, y1, z1), ee(t1) {}

inline HepLorentzVector:: HepLorentzVector(double x1, double y1, double z1)
  : pp(x1, y1, z1), ee(0) {}

inline HepLorentzVector:: HepLorentzVector(double t1)
  : pp(0, 0, 0), ee(t1) {}

inline HepLorentzVector:: HepLorentzVector()
  : pp(0, 0, 0), ee(0) {}

inline HepLorentzVector::HepLorentzVector(const Hep3Vector & p, double e1)
  : pp(p), ee(e1) {}

inline HepLorentzVector::HepLorentzVector(double e1, const Hep3Vector & p)
  : pp(p), ee(e1) {}

inline HepLorentzVector::HepLorentzVector(const HepLorentzVector & p)
  : pp(p.x(), p.y(), p.z()), ee(p.t()) {}

inline HepLorentzVector::~HepLorentzVector() {}

inline HepLorentzVector::operator const Hep3Vector & () const {return pp;}
inline HepLorentzVector::operator Hep3Vector & () { return pp; }

inline void HepLorentzVector::setX(double a) { pp.setX(a); } 
inline void HepLorentzVector::setY(double a) { pp.setY(a); }
inline void HepLorentzVector::setZ(double a) { pp.setZ(a); }
inline void HepLorentzVector::setT(double a) { ee = a;}

inline double HepLorentzVector::px() const { return pp.x(); }
inline double HepLorentzVector::py() const { return pp.y(); }
inline double HepLorentzVector::pz() const { return pp.z(); }
inline double HepLorentzVector::e()  const { return ee; }

inline void HepLorentzVector::setPx(double a) { pp.setX(a); } 
inline void HepLorentzVector::setPy(double a) { pp.setY(a); }
inline void HepLorentzVector::setPz(double a) { pp.setZ(a); }
inline void HepLorentzVector::setE(double a)  { ee = a;}

inline Hep3Vector HepLorentzVector::vect() const { return pp; } 
inline void HepLorentzVector::setVect(const Hep3Vector &p) { pp = p; } 

inline double HepLorentzVector::theta() const { return pp.theta(); }
inline double HepLorentzVector::cosTheta() const { return pp.cosTheta(); }
inline double HepLorentzVector::phi() const { return pp.phi(); }
inline double HepLorentzVector::rho() const { return pp.mag(); }

inline void HepLorentzVector::setTheta(double a) { pp.setTheta(a); }
inline void HepLorentzVector::setPhi(double a) { pp.setPhi(a); }
inline void HepLorentzVector::setRho(double a) { pp.setMag(a); }

double & HepLorentzVector::operator [] (int i)       { return (*this)(i); }
double   HepLorentzVector::operator [] (int i) const { return (*this)(i); }

inline HepLorentzVector &
HepLorentzVector::operator = (const HepLorentzVector & q) {
  pp = q.vect();
  ee = q.t();
  return *this;
}

inline HepLorentzVector
HepLorentzVector::operator + (const HepLorentzVector & q) const {
  return HepLorentzVector(x()+q.x(), y()+q.y(), z()+q.z(), t()+q.t());
}

inline HepLorentzVector &
HepLorentzVector::operator += (const HepLorentzVector & q) {
  pp += q.vect();
  ee += q.t();
  return *this;
}

inline HepLorentzVector
HepLorentzVector::operator - (const HepLorentzVector & q) const {
  return HepLorentzVector(x()-q.x(), y()-q.y(), z()-q.z(), t()-q.t());
}

inline HepLorentzVector &
HepLorentzVector::operator -= (const HepLorentzVector & q) {
  pp -= q.vect();
  ee -= q.t();
  return *this;
}

inline HepLorentzVector HepLorentzVector::operator - () const {
  return HepLorentzVector(-x(), -y(), -z(), -t());
}

inline HepLorentzVector& HepLorentzVector::operator *= (double a) {
  pp *= a;
  ee *= a;
  return *this;
}

inline bool
HepLorentzVector::operator == (const HepLorentzVector & q) const {
  return (vect()==q.vect() && t()==q.t());
}

inline bool
HepLorentzVector::operator != (const HepLorentzVector & q) const {
  return (vect()!=q.vect() || t()!=q.t());
}

inline double HepLorentzVector::perp2() const   { return pp.perp2(); }
inline double HepLorentzVector::perp()  const   { return pp.perp(); }
inline void HepLorentzVector::setPerp(double a) { pp.setPerp(a); }

inline double HepLorentzVector::perp2(const Hep3Vector &v1) const {
  return pp.perp2(v1);
}

inline double HepLorentzVector::perp(const Hep3Vector &v1) const {
  return pp.perp(v1);
}

inline double HepLorentzVector::angle(const Hep3Vector &v1) const {
  return pp.angle(v1);
}

inline double HepLorentzVector::mag2() const {
  return metric*(t()*t() - pp.mag2());
}

inline double HepLorentzVector::mag() const {
  double mmm = m2();
  return mmm < 0.0 ? -std::sqrt(-mmm) : std::sqrt(mmm);
}

inline double HepLorentzVector::m2() const { 
  return t()*t() - pp.mag2();
}

inline double HepLorentzVector::m() const { return mag(); }

inline double HepLorentzVector::mt2() const {
  return e()*e() - pz()*pz();
}

inline double HepLorentzVector::mt() const {
  double mmm = mt2();
  return mmm < 0.0 ? -std::sqrt(-mmm) : std::sqrt(mmm);
}

inline double HepLorentzVector::et2() const {
  double pt2 = pp.perp2();
  return pt2 == 0 ? 0 : e()*e() * pt2/(pt2+z()*z());
}

inline double HepLorentzVector::et() const {
  double etet = et2();
  return e() < 0.0 ? -std::sqrt(etet) : std::sqrt(etet);
}

inline double HepLorentzVector::et2(const Hep3Vector & v1) const {
  double pt2 = pp.perp2(v1);
  double pv = pp.dot(v1.unit());
  return pt2 == 0 ? 0 : e()*e() * pt2/(pt2+pv*pv);
}

inline double HepLorentzVector::et(const Hep3Vector & v1) const {
  double etet = et2(v1);
  return e() < 0.0 ? -std::sqrt(etet) : std::sqrt(etet);
}

inline void 
HepLorentzVector::setVectMag(const Hep3Vector & spatial, double magnitude) {
  setVect(spatial);
  setT(std::sqrt(magnitude * magnitude + spatial * spatial));
}

inline void 
HepLorentzVector::setVectM(const Hep3Vector & spatial, double mass) {
  setVectMag(spatial, mass);
}

inline double HepLorentzVector::dot(const HepLorentzVector & q) const {
  return metric*(t()*q.t() - z()*q.z() - y()*q.y() - x()*q.x());
}

inline double
HepLorentzVector::operator * (const HepLorentzVector & q) const {
  return dot(q);
}

inline double HepLorentzVector::plus() const {
  return t() + z();
}

inline double HepLorentzVector::minus() const {
  return t() - z();
}

inline HepLorentzVector & HepLorentzVector::boost(const Hep3Vector & b) {
  return boost(b.x(), b.y(), b.z());
}

inline double HepLorentzVector::pseudoRapidity() const {
  return pp.pseudoRapidity();
}

inline double HepLorentzVector::eta() const {
  return pp.pseudoRapidity();
}

inline double HepLorentzVector::eta( const Hep3Vector & ref ) const {
  return pp.eta( ref );
}

inline HepLorentzVector &
HepLorentzVector::operator *= (const HepRotation & m1) {
  pp.transform(m1);
  return *this;
}

inline HepLorentzVector &
HepLorentzVector::transform(const HepRotation & m1) {
  pp.transform(m1);
  return *this;
}

inline HepLorentzVector operator * (const HepLorentzVector & p, double a) {
  return HepLorentzVector(a*p.x(), a*p.y(), a*p.z(), a*p.t());
}

inline HepLorentzVector operator * (double a, const HepLorentzVector & p) {
  return HepLorentzVector(a*p.x(), a*p.y(), a*p.z(), a*p.t());
}

// The following were added when ZOOM PhysicsVectors was merged in:

inline HepLorentzVector::HepLorentzVector( 
	double x1, double y1, double z1, Tcomponent t1 ) :
	pp(x1, y1, z1), ee(t1) {}

inline void HepLorentzVector::set(
	double x1, double y1, double z1, Tcomponent t1 ) {
  pp.set(x1,y1,z1);
  ee = t1;
}

inline void HepLorentzVector::set(
        double x1, double y1, double z1, double t1 ) {
  set (x1,y1,z1,Tcomponent(t1));
}

inline HepLorentzVector::HepLorentzVector( 
	Tcomponent t1, double x1, double y1, double z1 ) :
        pp(x1, y1, z1), ee(t1) {}   

inline void HepLorentzVector::set(
	Tcomponent t1, double x1, double y1, double z1 ) {
  pp.set(x1,y1,z1);
  ee = t1;
}

inline void HepLorentzVector::set( Tcomponent t1 ) {
  pp.set(0, 0, 0);
  ee = t1;
}

inline void HepLorentzVector::set( double t1 ) {
  pp.set(0, 0, 0);
  ee = t1;
}

inline HepLorentzVector::HepLorentzVector( Tcomponent t1 ) : 
	pp(0, 0, 0), ee(t1) {}

inline void HepLorentzVector::set( const Hep3Vector & v1 ) {
  pp = v1;
  ee = 0;
}

inline HepLorentzVector::HepLorentzVector( const Hep3Vector & v1 ) : 
	pp(v1), ee(0) {}

inline void HepLorentzVector::setV(const Hep3Vector & v1) {
  pp = v1;
}

inline HepLorentzVector & HepLorentzVector::operator=(const Hep3Vector & v1) {
  pp = v1;
  ee = 0;
  return *this;
}

inline double HepLorentzVector::getX() const { return pp.x(); }
inline double HepLorentzVector::getY() const { return pp.y(); }
inline double HepLorentzVector::getZ() const { return pp.z(); }
inline double HepLorentzVector::getT() const { return ee; }

inline Hep3Vector HepLorentzVector::getV() const { return pp; } 
inline Hep3Vector HepLorentzVector::v() const { return pp; } 

inline void HepLorentzVector::set(double t1, const Hep3Vector & v1) {
  pp = v1;
  ee = t1;
}

inline void HepLorentzVector::set(const Hep3Vector & v1, double t1) {
  pp = v1;
  ee = t1;
}

inline void HepLorentzVector::setV( double x1,
             double y1,
             double z1 ) { pp.set(x1, y1, z1); }

inline void HepLorentzVector::setRThetaPhi 
		( double r, double ttheta, double phi1 ) 
                         { pp.setRThetaPhi( r, ttheta, phi1 ); }

inline void HepLorentzVector::setREtaPhi 
		( double r, double eta1, double phi1 ) 
                         { pp.setREtaPhi( r, eta1, phi1 ); }

inline void HepLorentzVector::setRhoPhiZ
		( double rho1, double phi1, double z1 )
                         { pp.setRhoPhiZ ( rho1, phi1, z1 ); }

inline bool HepLorentzVector::isTimelike() const {
  return restMass2() > 0;
}  

inline bool  HepLorentzVector::isSpacelike() const {
  return restMass2() < 0;
}

inline bool  HepLorentzVector::isLightlike(double epsilon) const {
  return std::fabs(restMass2()) < 2.0 * epsilon * ee * ee;
}

inline double HepLorentzVector::diff2( const HepLorentzVector & w ) const {
    return metric*( (ee-w.ee)*(ee-w.ee) - (pp-w.pp).mag2() );
}

inline double HepLorentzVector::delta2Euclidean 
					( const HepLorentzVector & w ) const {
    return (ee-w.ee)*(ee-w.ee) + (pp-w.pp).mag2();
}

inline double HepLorentzVector::euclideanNorm2()  const {
  return ee*ee + pp.mag2();
}

inline double HepLorentzVector::euclideanNorm()  const {
  return std::sqrt(euclideanNorm2());
}

inline double HepLorentzVector::restMass2()      const { return m2(); }
inline double HepLorentzVector::invariantMass2() const { return m2(); }

inline double HepLorentzVector::restMass() const {
//    if( t() < 0.0 )
//      std::cerr << "HepLorentzVector::restMass() - "
//                << "E^2-p^2 < 0 for this particle. Magnitude returned."
//                << std::endl;
    return t() < 0.0 ? -m() : m();
}

inline double HepLorentzVector::invariantMass() const {
//    if( t() < 0.0 )
//      std::cerr << "HepLorentzVector::invariantMass() - "
//                << "E^2-p^2 < 0 for this particle. Magnitude returned."
//                << std::endl;
    return t() < 0.0 ? -m() : m();
}

inline double HepLorentzVector::invariantMass2
					(const HepLorentzVector & w) const {
  return (*this + w).m2();
} /* invariantMass2 */

//-*********
// boostOf()
//-*********

// Each of these is a shell over a boost method.

inline HepLorentzVector boostXOf
	(const HepLorentzVector & vec, double bbeta) {
  HepLorentzVector vv (vec);
  return vv.boostX (bbeta);
}

inline HepLorentzVector boostYOf
	(const HepLorentzVector & vec, double bbeta) {
  HepLorentzVector vv (vec);
  return vv.boostY (bbeta);
}

inline HepLorentzVector boostZOf
	(const HepLorentzVector & vec, double bbeta) {
  HepLorentzVector vv (vec);
  return vv.boostZ (bbeta);
}

inline HepLorentzVector boostOf
	(const HepLorentzVector & vec, const Hep3Vector & betaVector ) {
  HepLorentzVector vv (vec);
  return vv.boost (betaVector);
}

inline HepLorentzVector boostOf
    (const HepLorentzVector & vec, const Hep3Vector & aaxis,  double bbeta) {
  HepLorentzVector vv (vec);
  return vv.boost (aaxis, bbeta);
}

}  // namespace CLHEP
