Files
geant4/source/externals/clhep/src/SpaceVector.cc
T
2016-06-09 17:01:34 +02:00

304 lines
8.4 KiB
C++

// -*- C++ -*-
// ---------------------------------------------------------------------------
//
// This file is a part of the CLHEP - a Class Library for High Energy Physics.
//
// SpaceVector
//
// This is the implementation of those methods of the Hep3Vector class which
// originated from the ZOOM SpaceVector class. Several groups of these methods
// have been separated off into the following code units:
//
// SpaceVectorR.cc All methods involving rotation
// SpaceVectorD.cc All methods involving angle decomposition
// SpaceVectorP.cc Intrinsic properties and methods involving second vector
//
#ifdef GNUPRAGMA
#pragma implementation
#endif
#include "CLHEP/Vector/ThreeVector.h"
#include "CLHEP/Units/PhysicalConstants.h"
#include <cmath>
namespace CLHEP {
//-*****************************
// - 1 -
// set (multiple components)
// in various coordinate systems
//
//-*****************************
void Hep3Vector::setSpherical (
double r1,
double theta1,
double phi1) {
// if ( r1 < 0 ) {
// std::cerr << "Hep3Vector::setSpherical() - "
// << "Spherical coordinates set with negative R" << std::endl;
// // No special return needed if warning is ignored.
// }
// if ( (theta1 < 0) || (theta1 > CLHEP::pi) ) {
// std::cerr << "Hep3Vector::setSpherical() - "
// << "Spherical coordinates set with theta not in [0, PI]" << std::endl;
// // No special return needed if warning is ignored.
// }
dz = r1 * std::cos(theta1);
double rho1 ( r1*std::sin(theta1));
dy = rho1 * std::sin (phi1);
dx = rho1 * std::cos (phi1);
return;
} /* setSpherical (r, theta1, phi1) */
void Hep3Vector::setCylindrical (
double rho1,
double phi1,
double z1) {
// if ( rho1 < 0 ) {
// std::cerr << "Hep3Vector::setCylindrical() - "
// << "Cylindrical coordinates supplied with negative Rho" << std::endl;
// // No special return needed if warning is ignored.
// }
dz = z1;
dy = rho1 * std::sin (phi1);
dx = rho1 * std::cos (phi1);
return;
} /* setCylindrical (r, phi, z) */
void Hep3Vector::setRhoPhiTheta (
double rho1,
double phi1,
double theta1) {
if (rho1 == 0) {
std::cerr << "Hep3Vector::setRhoPhiTheta() - "
<< "Attempt set vector components rho, phi, theta with zero rho -- "
<< "zero vector is returned, ignoring theta and phi" << std::endl;
dx = 0; dy = 0; dz = 0;
return;
}
// if ( (theta1 == 0) || (theta1 == CLHEP::pi) ) {
// std::cerr << "Hep3Vector::setRhoPhiTheta() - "
// << "Attempt set cylindrical vector vector with finite rho and "
// << "theta along the Z axis: infinite Z would be computed" << std::endl;
// }
// if ( (theta1 < 0) || (theta1 > CLHEP::pi) ) {
// std::cerr << "Hep3Vector::setRhoPhiTheta() - "
// << "Rho, phi, theta set with theta not in [0, PI]" << std::endl;
// // No special return needed if warning is ignored.
// }
dz = rho1 / std::tan (theta1);
dy = rho1 * std::sin (phi1);
dx = rho1 * std::cos (phi1);
return;
} /* setCyl (rho, phi, theta) */
void Hep3Vector::setRhoPhiEta (
double rho1,
double phi1,
double eta1 ) {
if (rho1 == 0) {
std::cerr << "Hep3Vector::setRhoPhiEta() - "
<< "Attempt set vector components rho, phi, eta with zero rho -- "
<< "zero vector is returned, ignoring eta and phi" << std::endl;
dx = 0; dy = 0; dz = 0;
return;
}
double theta1 (2 * std::atan ( std::exp (-eta1) ));
dz = rho1 / std::tan (theta1);
dy = rho1 * std::sin (phi1);
dx = rho1 * std::cos (phi1);
return;
} /* setCyl (rho, phi, eta) */
//************
// - 3 -
// Comparisons
//
//************
int Hep3Vector::compare (const Hep3Vector & v) const {
if ( dz > v.dz ) {
return 1;
} else if ( dz < v.dz ) {
return -1;
} else if ( dy > v.dy ) {
return 1;
} else if ( dy < v.dy ) {
return -1;
} else if ( dx > v.dx ) {
return 1;
} else if ( dx < v.dx ) {
return -1;
} else {
return 0;
}
} /* Compare */
bool Hep3Vector::operator > (const Hep3Vector & v) const {
return (compare(v) > 0);
}
bool Hep3Vector::operator < (const Hep3Vector & v) const {
return (compare(v) < 0);
}
bool Hep3Vector::operator>= (const Hep3Vector & v) const {
return (compare(v) >= 0);
}
bool Hep3Vector::operator<= (const Hep3Vector & v) const {
return (compare(v) <= 0);
}
//-********
// Nearness
//-********
// These methods all assume you can safely take mag2() of each vector.
// Absolutely safe but slower and much uglier alternatives were
// provided as build-time options in ZOOM SpaceVectors.
// Also, much smaller codes were provided tht assume you can square
// mag2() of each vector; but those return bad answers without warning
// when components exceed 10**90.
//
// IsNear, HowNear, and DeltaR are found in ThreeVector.cc
double Hep3Vector::howParallel (const Hep3Vector & v) const {
// | V1 x V2 | / | V1 dot V2 |
double v1v2 = std::fabs(dot(v));
if ( v1v2 == 0 ) {
// Zero is parallel to no other vector except for zero.
return ( (mag2() == 0) && (v.mag2() == 0) ) ? 0 : 1;
}
Hep3Vector v1Xv2 ( cross(v) );
double abscross = v1Xv2.mag();
if ( abscross >= v1v2 ) {
return 1;
} else {
return abscross/v1v2;
}
} /* howParallel() */
bool Hep3Vector::isParallel (const Hep3Vector & v,
double epsilon) const {
// | V1 x V2 | **2 <= epsilon **2 | V1 dot V2 | **2
// V1 is *this, V2 is v
static const double TOOBIG = std::pow(2.0,507);
static const double SCALE = std::pow(2.0,-507);
double v1v2 = std::fabs(dot(v));
if ( v1v2 == 0 ) {
return ( (mag2() == 0) && (v.mag2() == 0) );
}
if ( v1v2 >= TOOBIG ) {
Hep3Vector sv1 ( *this * SCALE );
Hep3Vector sv2 ( v * SCALE );
Hep3Vector sv1Xsv2 = sv1.cross(sv2);
double x2 = sv1Xsv2.mag2();
double limit = v1v2*SCALE*SCALE;
limit = epsilon*epsilon*limit*limit;
return ( x2 <= limit );
}
// At this point we know v1v2 can be squared.
Hep3Vector v1Xv2 ( cross(v) );
if ( (std::fabs (v1Xv2.dx) > TOOBIG) ||
(std::fabs (v1Xv2.dy) > TOOBIG) ||
(std::fabs (v1Xv2.dz) > TOOBIG) ) {
return false;
}
return ( (v1Xv2.mag2()) <= ((epsilon * v1v2) * (epsilon * v1v2)) );
} /* isParallel() */
double Hep3Vector::howOrthogonal (const Hep3Vector & v) const {
// | V1 dot V2 | / | V1 x V2 |
double v1v2 = std::fabs(dot(v));
//-| Safe because both v1 and v2 can be squared
if ( v1v2 == 0 ) {
return 0; // Even if one or both are 0, they are considered orthogonal
}
Hep3Vector v1Xv2 ( cross(v) );
double abscross = v1Xv2.mag();
if ( v1v2 >= abscross ) {
return 1;
} else {
return v1v2/abscross;
}
} /* howOrthogonal() */
bool Hep3Vector::isOrthogonal (const Hep3Vector & v,
double epsilon) const {
// | V1 x V2 | **2 <= epsilon **2 | V1 dot V2 | **2
// V1 is *this, V2 is v
static const double TOOBIG = std::pow(2.0,507);
static const double SCALE = std::pow(2.0,-507);
double v1v2 = std::fabs(dot(v));
//-| Safe because both v1 and v2 can be squared
if ( v1v2 >= TOOBIG ) {
Hep3Vector sv1 ( *this * SCALE );
Hep3Vector sv2 ( v * SCALE );
Hep3Vector sv1Xsv2 = sv1.cross(sv2);
double x2 = sv1Xsv2.mag2();
double limit = epsilon*epsilon*x2;
double y2 = v1v2*SCALE*SCALE;
return ( y2*y2 <= limit );
}
// At this point we know v1v2 can be squared.
Hep3Vector eps_v1Xv2 ( cross(epsilon*v) );
if ( (std::fabs (eps_v1Xv2.dx) > TOOBIG) ||
(std::fabs (eps_v1Xv2.dy) > TOOBIG) ||
(std::fabs (eps_v1Xv2.dz) > TOOBIG) ) {
return true;
}
// At this point we know all the math we need can be done.
return ( v1v2*v1v2 <= eps_v1Xv2.mag2() );
} /* isOrthogonal() */
double Hep3Vector::setTolerance (double tol) {
// Set the tolerance for Hep3Vectors to be considered near one another
double oldTolerance (tolerance);
tolerance = tol;
return oldTolerance;
}
//-***********************
// Helper Methods:
// negativeInfinity()
//-***********************
double Hep3Vector::negativeInfinity() const {
// A byte-order-independent way to return -Infinity
struct Dib {
union {
double d;
unsigned char i[8];
} u;
};
Dib negOne;
Dib posTwo;
negOne.u.d = -1.0;
posTwo.u.d = 2.0;
Dib value;
int k;
for (k=0; k<8; k++) {
value.u.i[k] = negOne.u.i[k] | posTwo.u.i[k];
}
return value.u.d;
}
} // namespace CLHEP