#ifndef _det_MPositionable_h #define _det_MPositionable_h #include #include #include #include #include #include #include namespace det { /** * \class MPositionable MPositionable "mdet/MPositionable.h" * \brief Mixin class to be inherited from objects that have a position. * * The class provides the basic methods for one of those objects: * - GetPosition * - GetLocalCoordinateSystem * * Delegates to deriving classes the definition of the coordinate system * to which the position is referred (GetReferenceCoordinateSystem). * The actual values are retrieved from the configuration imposed by the * objects of the template argument. * The position is specified by components and angles, the components can * be on any of the defined types of coordinates. * * The translational part is configured by three components, and the rotation * by the so-called "Euler angles". The convention for Euler angles is taken * from: * Goldstein, Herbert et al; "Classical Mechanics", 3rd edition, Addison-Wesley. * See 4.4-The Euler angles / pp 150-154. * For quick reference the convention is given here: * - Given an initial system of axes \f$xyz\f$. * - They are rotated by \f$\phi\f$ counterclockwise about * the \f$z\f$ axis. * - The resulting axes are labeled as \f$\xi\eta\zeta\f$. * - They are rotated by \f$\theta\f$ counterclockwise about * the \f$\xi\f$ axis (the new \f$x\f$ axis). * - The resulting axes are labeled as \f$\xi^\prime\eta^\prime\zeta^\prime\f$. * - They are rotated by \f$\psi\f$ counterclockwise about the * \f$\zeta^\prime\f$ axis (the new \f$z\f$ axis). * \image html det_MPositionable_EulerAngles.png * * These conventions for Euler angles are also the ones used in ROOT's TGeoRotation. * * The template argument \p Config is expected to be able to resolve a member * call with the following signatures: * * -double& GetData(utl::ShadowPtr&, const std::string&) const; * -CoordinateType& GetData(utl::ShadowPtr&, const std::string&) const; * * with the semantics that that call will initialize the pointer or retrieve its * current value (whatever is correct) for the given property (see constants with * the tag names). * * \todo All the non template-dependant code may be put in a superclass and * the template dependant code be kept here. Then the template MPositionable would * derive from the former. In this way some bloat (of the generated object files) * may be avoided. See next todo about Boost's shared_ptr. See Scott Meyers' * "Effective C++", item 44 "Factor parameter-independent code out of templates". * * \todo Note that the template argument is used as the callback mechanism to resolve * particular datum. This class could be made non-template in two ways. The first is * obviously to have, in Java parlance, an interface defined with the callback method, and so * accept objects deriving from it. Another posibility is to borrow the idea of Boost's * shared pointers; that is to define that interface privately, have a private implementation * of it and then wrap with the second the objects received by a templated constructor. See * "My Most Important C++ Aha! Moments...Ever" by Scott Meyers * http://www.artima.com/cppsource/top_cpp_aha_moments.html * "External Polymorphism" by Chris Cleeland et al. * http://www.cs.wustl.edu/~schmidt/PDF/External-Polymorphism.pdf * "The shared_ptr Class" by Danny Kalev * http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=239 * and of course Boost's docs & srcs. * * \todo This class could be split into two clases: * - A pure abstract interface with the required methods that * make a "positionable" (GetPosition, GetLocalCoordinateSystem). In relation to this * note that users of this class won't be likely to be treated polymorphically, so this * interface may not be needed. * - A base implementation of the former. * Given this, the clients could choose between mixing-in the functionality * via (posibly multiple) inheritance (the choice favored by the current * single class implementation) or composition plus method-call delegation (in an * idiom more typical of Java). What would be also necesary in this second approach * is to change the stategy for GetReferenceCoordinateSystem, what should be done * is something like giving directly a reference to that system via the * nested-object's constructor (in addition to the current reference to this, * used to resolve GetData). Another possibility (instead of a 2nd argument in * constructor) would be to split even more the classes, and put * GetReferenceCoordinateSystem in less specific interface, that would be extended * by the original interface, implemented by the delegatee class and required by * the delegate (in it's constructor). Of course, given the use of templates * (for GetData resolution) that interface with GetReferenceCoordinateSystem * may be implicitly required on the type, that is, C++ parlance, a concept. * * \todo In the light of the first usage (within a hierarchy of det::DetectorComponent) * another last posibility would be to define a type to mix "positionable" with * "component", let's say something like PositionableDetectorComponent: in this way * multiple inheritance would be avoided. * * \todo This class doesn't handle UTM points. For that case, in addition to the 3 * components band & zone are required (and there's no coordinate type). Up to now * the neccesity was only to work with derived coordinate systems (which is materialized * by the presence of the GetReferenceCoordinateSystem method). * * As reference see item 40 "Use multiple inheritance judiciouly" in "Effective C++" by * Scott Meyers. * * \author Rodolfo Federico Gamarra * \date 09 Jan 2009 * \ingroup det_interface */ template class MPositionable { public: /** * \brief Construct a MPositionable with the config provider. * * A reference to \p c is kept const within this class, and to it * the resolution of values (components, angles and type) are forwarded * when appropiate. More preciselly the */ MPositionable(const Config& cp) : fConfig(cp) {}; /** * \brief Destructor. */ virtual ~MPositionable() {}; /** * \brief Local system based on position and configured rotations. */ utl::CoordinateSystemPtr GetLocalCoordinateSystem() const; /** * \brief This object position, based the configured components and the reference coordinate system. * * The return type is by-copy as of the general recommendation due to Bugzilla's report #307. Also * this topic was referred by in 'Point copy vs reference, GetPosition and report #307.', see * auger-offline-devel archives for January 2009. */ utl::Point GetPosition() const; protected: /** * \brief Tag for coordinate type selection. * * This tag defines the meaning of the three components. * \sa utl::BasicVector::CoordinateType */ static const std::string kCoordinateTypeTag; /// Tag for first vector component in config. static const std::string kComponent1Tag; /// Tag for second vector component in config. static const std::string kComponent2Tag; /// Tag for third vector component in config. static const std::string kComponent3Tag; /// Tag for first rotation's Euler angle in config. static const std::string kEulerPhiTag; /// Tag for second rotation's Euler angle in config. static const std::string kEulerThetaTag; /// Tag for third rotation's Euler angle in config. static const std::string kEulerPsiTag; /** * \brief Simple internal typedef to emulate the actual enumeration * via a type handled in the configuration mechanism. */ typedef std::string CoordinateType; /* * Discarded by now: CoordinateSystem is also prepared for this. * Seems clearer the use of a string tag instead of an integral value. * * typedef int CoordinateType; */ /* * In the following there are several virtual methods that are thought to * allow deriving classes to fill some holes (ie in a Template pattern fashion) * regarding the coordinates of this object coordinate system. * * One of them is even a pure virtual method without an implementation provided * here, the others have an implementation by this class. * * Currently most of them are protected methods, tough it may be enough to have them * just private (ie the deriving classes just need to overrided / define any of * these methods, but no do an actual call to one of them). Making these methods * privated would follow the guideline given by Herb Sutter in * * "Virtuality" * C/C++ Users Journal, 19(9), September 2001. * (http://www.gotw.ca/publications/mill18.htm) where it's said: * Guideline #2: Prefer to make virtual functions private. * Guideline #3: Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected. * * On the other hand, all these functions are getters that doesn't perform any operation but to retrieve a value (maybe accesing configuration), * so there's no workflow to be ensured by this class (ie there's on risk to call them in some not foreseen situation): so at last * it seems reasonable to leave them protected so as to allow deriving classes a (probably necessary) call to one of them. * * But, at last, for the pure virtual function case there's no point to have it protected: it has to be defined by deriving classes, and so when * defined "down the hierarchy" the accesss control modifier here specified is overrided; conversely, if not defined, it couldn't be called: it has * no definition provided (remember that a __pure__ virtual function may have, anyway, a definition provided: the, say, "purity" just enforces * deriving classes to provide an implementation by themselves)! */ /** * \name Specific datum accesor components. * * In the most commeon situation deriving clases won't override * these methods (and so the actual retrieval will be forwarded to * the expected method in the Config template argument. Nevertheless * they are made virtual in order to allow posible customization * by subclasses. This customization could be done in principle * in the Get method, basing the decision on the tag, but * that would be pretty ugly. */ //@{ /** * \brief First component of the position vector. * * It could be x or r, according to the type determined * by GetCoordinateType. * * \sa utl::Vector */ virtual double GetComponent1() const; /** * \brief Second component of the position vector. * * \sa GetComponent1 */ virtual double GetComponent2() const; /** * \brief Third component of the position vector. * * \sa GetComponent1 */ virtual double GetComponent3() const; /** * \brief First Euler angle for rotation over (original) z. */ virtual double GetEulerPhi() const; /** * \brief Second Euler angle for rotation over (intermediate) * x. */ virtual double GetEulerTheta() const; /** * \brief Third Euler angle for rotation over (intermediate) * z. */ virtual double GetEulerPsi() const; /** * \brief Coordinate type. * * \sa utl::Vector::CoordinateType */ virtual CoordinateType GetCoordinateType() const; //@} private: /** * \brief Coordinate system of reference wrt which the components are expressed. * * This pure virtual method acts as a hook by which deriving classes determine a reference * coordinate system from which refer the coordinates. */ virtual utl::CoordinateSystemPtr GetReferenceCoordinateSystem() const = 0; /** * \brief Cached data. * * Hold pointer to the data resolved by the respective * calls to GetData. Note the usage of mutable, that goes * along the caching meaning. * Note that for the coordinate-system was is actually * stored is computed from the calls to the here-defined * GetXXX functions. */ //@{ mutable utl::ShadowPtr fComponent1; mutable utl::ShadowPtr fComponent2; mutable utl::ShadowPtr fComponent3; mutable utl::ShadowPtr fEulerPhi; mutable utl::ShadowPtr fEulerTheta; mutable utl::ShadowPtr fEulerPsi; mutable utl::ShadowPtr fCoordinateType; mutable utl::CoordinateSystemPtr fLocalCoordinateSystem; //@} /// Hold a reference to the configuration proxy. const Config& fConfig; }; template const std::string MPositionable::kComponent1Tag("positionComponent1"); template const std::string MPositionable::kComponent2Tag("positionComponent2");; template const std::string MPositionable::kComponent3Tag("positionComponent3");; template const std::string MPositionable::kEulerPhiTag("eulerPhi"); template const std::string MPositionable::kEulerThetaTag("eulerTheta"); template const std::string MPositionable::kEulerPsiTag("eulerPsi"); template const std::string MPositionable::kCoordinateTypeTag("coordinateType"); template double MPositionable::GetComponent1() const { /* Hack to fix compilation using g++ 4.1.2 on SL 5.5 (present in most GRID nodes) RFG 2013 See: http://www.gotw.ca/publications/mill17.htm */ return fConfig.template GetData(fComponent1, kComponent1Tag); } template double MPositionable::GetComponent2() const { return fConfig.template GetData(fComponent2, kComponent2Tag); } template double MPositionable::GetComponent3() const { return fConfig.template GetData(fComponent3, kComponent3Tag); } template double MPositionable::GetEulerPhi() const { return fConfig.template GetData(fEulerPhi, kEulerPhiTag); } template double MPositionable::GetEulerTheta() const { return fConfig.template GetData(fEulerTheta, kEulerThetaTag); } template double MPositionable::GetEulerPsi() const { return fConfig.template GetData(fEulerPsi, kEulerPsiTag); } template typename MPositionable::CoordinateType MPositionable::GetCoordinateType() const { return fConfig.template GetData(fCoordinateType, kCoordinateTypeTag); } template utl::Point MPositionable::GetPosition() const { // Can't be simpler! return utl::Point(0, 0, 0, GetLocalCoordinateSystem()); } template utl::CoordinateSystemPtr MPositionable::GetLocalCoordinateSystem() const { if (!fLocalCoordinateSystem) { // Alias for convenience. typedef utl::Vector::CoordinateType Type; // Retrieve the reference one and the apply the pertaining transformations. utl::CoordinateSystemPtr cs = GetReferenceCoordinateSystem(); // Displacement components. const double c1 = GetComponent1(); const double c2 = GetComponent2(); const double c3 = GetComponent3(); // Now the rotation part. const double phi = GetEulerPhi(); const double theta = GetEulerTheta(); const double psi = GetEulerPsi(); // Check if there's something to be done (if not cs stays the same)... if (c1 || c2 || c3 || phi || theta || psi) { // Create the given coordinate type (the innermost creation may throw). const Type& ct = Type::Create(Type::KindCreator::Create(GetCoordinateType())); // Construct the displacement vector. const utl::Vector trans(c1, c2, c3, cs, ct); // Move the system. cs = utl::CoordinateSystem::Translation(trans, cs); /* * Apply the rotations in the established conventional order and * to the correspoding axes (some of them being the result of * previously applied rotations). See this class' main comment. * * The rotations are finally forwarded to CLHEP rotation classes, * which state that they are counterclockwise (see Transform3D.h * in there). */ if (phi) cs = utl::CoordinateSystem::RotationZ(phi, cs); if (theta) cs = utl::CoordinateSystem::RotationX(theta, cs); if (psi) cs = utl::CoordinateSystem::RotationZ(psi, cs); } fLocalCoordinateSystem = cs; } return fLocalCoordinateSystem; } } #endif // _det_Positionable_h