Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-25 10:02:58

0001 // @(#)root/mathcore:$Id$
0002 // Authors: W. Brown, M. Fischler, L. Moneta    2005
0003 
0004  /**********************************************************************
0005   *                                                                    *
0006   * Copyright (c) 2005 , LCG ROOT MathLib Team and                     *
0007   *                      FNAL LCG ROOT MathLib Team                    *
0008   *                                                                    *
0009   *                                                                    *
0010   **********************************************************************/
0011 
0012 // Header source file for class DisplacementVector3D
0013 //
0014 // Created by: Lorenzo Moneta  at Mon May 30 12:21:43 2005
0015 // Major rewrite: M. Fischler  at Wed Jun  8  2005
0016 //
0017 // Last update: $Id$
0018 //
0019 
0020 #ifndef ROOT_Math_GenVector_DisplacementVector3D
0021 #define ROOT_Math_GenVector_DisplacementVector3D  1
0022 
0023 #include "Math/GenVector/Cartesian3D.h"
0024 
0025 #include "Math/GenVector/PositionVector3Dfwd.h"
0026 
0027 #include "Math/GenVector/GenVectorIO.h"
0028 
0029 #include "Math/GenVector/BitReproducible.h"
0030 
0031 #include "Math/GenVector/CoordinateSystemTags.h"
0032 
0033 #include <cassert>
0034 
0035 
0036 namespace ROOT {
0037 
0038   namespace Math {
0039 
0040 
0041 //__________________________________________________________________________________________
0042     /**
0043      Class describing a generic displacement vector in 3 dimensions.
0044      This class is templated on the type of Coordinate system.
0045      One example is the XYZVector which is a vector based on
0046      double precision x,y,z data members by using the
0047      ROOT::Math::Cartesian3D<double> Coordinate system.
0048      The class is having also an extra template parameter, the coordinate system tag,
0049      to be able to identify (tag) vector described in different reference coordinate system,
0050      like global or local coordinate systems.
0051 
0052      @ingroup GenVector
0053 
0054      @see GenVector
0055     */
0056 
0057     template <class CoordSystem, class Tag = DefaultCoordinateSystemTag >
0058     class DisplacementVector3D {
0059 
0060     public:
0061 
0062       typedef typename CoordSystem::Scalar Scalar;
0063       typedef CoordSystem CoordinateType;
0064       typedef Tag  CoordinateSystemTag;
0065 
0066       // ------ ctors ------
0067 
0068       /**
0069           Default constructor. Construct an empty object with zero values
0070       */
0071       constexpr DisplacementVector3D ( ) :   fCoordinates()  { }
0072 
0073 
0074       /**
0075          Construct from three values of type <em>Scalar</em>.
0076          In the case of a XYZVector the values are x,y,z
0077          In the case of  a polar vector they are r,theta, phi
0078       */
0079       constexpr DisplacementVector3D(Scalar a, Scalar b, Scalar c) :
0080         fCoordinates ( a , b,  c )  { }
0081 
0082      /**
0083           Construct from a displacement vector expressed in different
0084           coordinates, or using a different Scalar type, but with same coordinate system tag
0085       */
0086       template <class OtherCoords>
0087       explicit constexpr DisplacementVector3D( const DisplacementVector3D<OtherCoords, Tag> & v) :
0088         fCoordinates ( v.Coordinates() ) { }
0089 
0090 
0091       /**
0092          Construct from a position vector expressed in different coordinates
0093          but with the same coordinate system tag
0094       */
0095       template <class OtherCoords>
0096       explicit constexpr DisplacementVector3D( const PositionVector3D<OtherCoords,Tag> & p) :
0097         fCoordinates ( p.Coordinates() ) { }
0098 
0099 
0100       /**
0101           Construct from a foreign 3D vector type, for example, Hep3Vector
0102           Precondition: v must implement methods x(), y() and z()
0103       */
0104       template <class ForeignVector>
0105       explicit constexpr DisplacementVector3D( const ForeignVector & v) :
0106         fCoordinates ( Cartesian3D<Scalar>( v.x(), v.y(), v.z() ) ) { }
0107 
0108 
0109 #ifdef LATER
0110       /**
0111          construct from a generic linear algebra  vector of at least size 3
0112          implementing operator [].
0113          \par v  LAVector
0114          \par index0   index where coordinates starts (typically zero)
0115          It works for all Coordinates types,
0116          ( x= v[index0] for Cartesian and r=v[index0] for Polar )
0117       */
0118       template <class LAVector>
0119       constexpr DisplacementVector3D(const LAVector & v, size_t index0 ) {
0120         fCoordinates = CoordSystem ( v[index0], v[index0+1], v[index0+2] );
0121       }
0122 #endif
0123 
0124       // compiler-generated copy ctor and dtor are fine.
0125 
0126       // ------ assignment ------
0127 
0128       /**
0129           Assignment operator from a displacement vector of arbitrary type
0130       */
0131       template <class OtherCoords>
0132       DisplacementVector3D & operator=
0133                         ( const DisplacementVector3D<OtherCoords, Tag> & v) {
0134         fCoordinates = v.Coordinates();
0135         return *this;
0136       }
0137 
0138       /**
0139          Assignment operator from a position vector
0140          (not necessarily efficient unless one or the other is Cartesian)
0141       */
0142       template <class OtherCoords>
0143       DisplacementVector3D & operator=
0144                         ( const PositionVector3D<OtherCoords,Tag> & rhs) {
0145          SetXYZ(rhs.x(), rhs.y(), rhs.z());
0146          return *this;
0147       }
0148 
0149 
0150       /**
0151           Assignment from a foreign 3D vector type, for example, Hep3Vector
0152           Precondition: v must implement methods x(), y() and z()
0153       */
0154       template <class ForeignVector>
0155       DisplacementVector3D & operator= ( const ForeignVector & v) {
0156         SetXYZ( v.x(),  v.y(), v.z() );
0157         return *this;
0158       }
0159 
0160 
0161 #ifdef LATER
0162       /**
0163          assign from a generic linear algebra  vector of at least size 3
0164          implementing operator []. This could be also a C array
0165          \par v  LAVector
0166          \par index0   index where coordinates starts (typically zero)
0167          It works for all Coordinates types,
0168          ( x= v[index0] for Cartesian and r=v[index0] for Polar )
0169       */
0170       template <class LAVector>
0171       DisplacementVector3D & assignFrom(const LAVector & v, size_t index0 = 0) {
0172         fCoordinates = CoordSystem  ( v[index0], v[index0+1], v[index0+2] );
0173         return *this;
0174       }
0175 #endif
0176 
0177       // ------ Set, Get, and access coordinate data ------
0178 
0179       /**
0180           Retrieve a copy of the coordinates object
0181       */
0182       CoordSystem Coordinates() const {
0183         return fCoordinates;
0184       }
0185 
0186       /**
0187          Set internal data based on a C-style array of 3 Scalar numbers
0188        */
0189       DisplacementVector3D<CoordSystem, Tag>& SetCoordinates( const Scalar src[] )
0190        { fCoordinates.SetCoordinates(src); return *this; }
0191 
0192       /**
0193          Set internal data based on 3 Scalar numbers
0194        */
0195       DisplacementVector3D<CoordSystem, Tag>& SetCoordinates( Scalar a, Scalar b, Scalar c )
0196        { fCoordinates.SetCoordinates(a, b, c); return *this; }
0197 
0198       /**
0199          Set internal data based on 3 Scalars at *begin to *end
0200        */
0201       template <class IT>
0202       DisplacementVector3D<CoordSystem, Tag>& SetCoordinates( IT begin, IT end  )
0203       { IT a = begin; IT b = ++begin; IT c = ++begin;
0204         (void)end;
0205         assert (++begin==end);
0206         SetCoordinates (*a,*b,*c);
0207         return *this;
0208       }
0209 
0210       /**
0211          get internal data into 3 Scalar numbers
0212          \note Alternatively, you may use structured bindings: `auto const [a, b, c] = v`.
0213        */
0214       void GetCoordinates( Scalar& a, Scalar& b, Scalar& c ) const
0215                             { fCoordinates.GetCoordinates(a, b, c);  }
0216 
0217       /**
0218          get internal data into a C-style array of 3 Scalar numbers
0219        */
0220       void GetCoordinates( Scalar dest[] ) const
0221                             { fCoordinates.GetCoordinates(dest);  }
0222 
0223       /**
0224          get internal data into 3 Scalars at *begin to *end (3 past begin)
0225        */
0226       template <class IT>
0227       void GetCoordinates( IT begin, IT end ) const
0228       { IT a = begin; IT b = ++begin; IT c = ++begin;
0229         (void)end;
0230         assert (++begin==end);
0231         GetCoordinates (*a,*b,*c);
0232       }
0233       /**
0234          get internal data into 3 Scalars starting at *begin
0235        */
0236       template <class IT>
0237       void GetCoordinates( IT begin) const {
0238          Scalar a = Scalar(0);
0239          Scalar b = Scalar(0);
0240          Scalar c = Scalar(0);
0241          GetCoordinates(a, b, c);
0242          *begin++ = a;
0243          *begin++ = b;
0244          *begin   = c;
0245       }
0246 
0247       /**
0248          set the values of the vector from the cartesian components (x,y,z)
0249          (if the vector is held in polar or cylindrical eta coordinates,
0250          then (x, y, z) are converted to that form)
0251        */
0252       DisplacementVector3D<CoordSystem, Tag>& SetXYZ (Scalar a, Scalar b, Scalar c) {
0253          fCoordinates.SetXYZ(a, b, c);
0254          return *this;
0255       }
0256 
0257       // ------------------- Equality -----------------
0258 
0259       /**
0260         Exact equality
0261        */
0262       bool operator==(const DisplacementVector3D & rhs) const {
0263         return fCoordinates==rhs.fCoordinates;
0264       }
0265       bool operator!= (const DisplacementVector3D & rhs) const {
0266         return !(operator==(rhs));
0267       }
0268 
0269       // ------ Individual element access, in various coordinate systems ------
0270 
0271       /**
0272           Dimension
0273       */
0274       unsigned int Dimension() const
0275       {
0276          return fDimension;
0277       };
0278 
0279       /**
0280           Cartesian X, converting if necessary from internal coordinate system.
0281       */
0282       Scalar X() const { return fCoordinates.X(); }
0283 
0284       /**
0285           Cartesian Y, converting if necessary from internal coordinate system.
0286       */
0287       Scalar Y() const { return fCoordinates.Y(); }
0288 
0289       /**
0290           Cartesian Z, converting if necessary from internal coordinate system.
0291       */
0292       Scalar Z() const { return fCoordinates.Z(); }
0293 
0294       /**
0295           Polar R, converting if necessary from internal coordinate system.
0296       */
0297       Scalar R() const { return fCoordinates.R(); }
0298 
0299       /**
0300           Polar theta, converting if necessary from internal coordinate system.
0301       */
0302       Scalar Theta() const { return fCoordinates.Theta(); }
0303 
0304       /**
0305           Polar phi, converting if necessary from internal coordinate system.
0306       */
0307       Scalar Phi() const { return fCoordinates.Phi(); }
0308 
0309       /**
0310           Polar eta, converting if necessary from internal coordinate system.
0311       */
0312       Scalar Eta() const { return fCoordinates.Eta(); }
0313 
0314       /**
0315           Cylindrical transverse component rho
0316       */
0317       Scalar Rho() const { return fCoordinates.Rho(); }
0318 
0319       // ----- Other fundamental properties -----
0320 
0321       /**
0322           Magnitute squared ( r^2 in spherical coordinate)
0323       */
0324       Scalar Mag2() const { return fCoordinates.Mag2();}
0325 
0326       /**
0327          Transverse component squared (rho^2 in cylindrical coordinates.
0328       */
0329       Scalar Perp2() const { return fCoordinates.Perp2();}
0330 
0331       /**
0332          return unit vector parallel to this (scalar)
0333       */
0334       template <typename SCALAR = Scalar, typename std::enable_if<std::is_arithmetic<SCALAR>::value>::type * = nullptr>
0335       DisplacementVector3D Unit() const
0336       {
0337          const auto tot = R();
0338          return tot == 0 ? *this : DisplacementVector3D(*this) / tot;
0339       }
0340 
0341       /**
0342          return unit vector parallel to this (vector)
0343       */
0344       template <typename SCALAR = Scalar, typename std::enable_if<!std::is_arithmetic<SCALAR>::value>::type * = nullptr>
0345       DisplacementVector3D Unit() const
0346       {
0347          SCALAR tot            = R();
0348          tot(tot == SCALAR(0)) = SCALAR(1);
0349          return DisplacementVector3D(*this) / tot;
0350       }
0351 
0352       // ------ Setting of individual elements present in coordinate system ------
0353 
0354       /**
0355          Change X - Cartesian3D coordinates only
0356       */
0357        DisplacementVector3D<CoordSystem, Tag>& SetX (Scalar xx) { fCoordinates.SetX(xx); return *this;}
0358 
0359       /**
0360          Change Y - Cartesian3D coordinates only
0361       */
0362        DisplacementVector3D<CoordSystem, Tag>& SetY (Scalar yy) { fCoordinates.SetY(yy); return *this;}
0363 
0364       /**
0365          Change Z - Cartesian3D coordinates only
0366       */
0367        DisplacementVector3D<CoordSystem, Tag>& SetZ (Scalar zz) { fCoordinates.SetZ(zz); return *this;}
0368 
0369       /**
0370          Change R - Polar3D coordinates only
0371       */
0372        DisplacementVector3D<CoordSystem, Tag>& SetR (Scalar rr) { fCoordinates.SetR(rr); return *this;}
0373 
0374       /**
0375          Change Theta - Polar3D coordinates only
0376       */
0377        DisplacementVector3D<CoordSystem, Tag>& SetTheta (Scalar ang) { fCoordinates.SetTheta(ang); return *this;}
0378 
0379       /**
0380          Change Phi - Polar3D or CylindricalEta3D coordinates
0381       */
0382        DisplacementVector3D<CoordSystem, Tag>& SetPhi (Scalar ang) { fCoordinates.SetPhi(ang); return *this;}
0383 
0384       /**
0385          Change Rho - CylindricalEta3D coordinates only
0386       */
0387        DisplacementVector3D<CoordSystem, Tag>& SetRho (Scalar rr) { fCoordinates.SetRho(rr); return *this;}
0388 
0389       /**
0390          Change Eta - CylindricalEta3D coordinates only
0391       */
0392        DisplacementVector3D<CoordSystem, Tag>& SetEta (Scalar etaval) { fCoordinates.SetEta(etaval); return *this;}
0393 
0394 
0395       // ------ Operations combining two vectors ------
0396       // -- need to have the specialized version in order to avoid
0397 
0398       /**
0399        Return the scalar (dot) product of two displacement vectors.
0400        It is possible to perform the product for any type of vector coordinates,
0401        but they must have the same coordinate system tag
0402       */
0403       template< class OtherCoords >
0404       Scalar Dot( const  DisplacementVector3D<OtherCoords,Tag>  & v) const {
0405         return X()*v.X() + Y()*v.Y() + Z()*v.Z();
0406       }
0407       /**
0408           Return the scalar (dot) product of two vectors.
0409           It is possible to perform the product for any classes
0410           implementing x(), y() and z() member functions
0411       */
0412       template< class OtherVector >
0413       Scalar Dot( const  OtherVector & v) const {
0414         return X()*v.x() + Y()*v.y() + Z()*v.z();
0415       }
0416 
0417       /**
0418        Return vector (cross) product of two displacement vectors,
0419        as a vector in the coordinate system of this class.
0420        It is possible to perform the product for any type of vector coordinates,
0421        but they must have the same coordinate system tag
0422       */
0423       template <class OtherCoords>
0424       DisplacementVector3D Cross( const DisplacementVector3D<OtherCoords,Tag>  & v) const {
0425         DisplacementVector3D  result;
0426         result.SetXYZ (  Y()*v.Z() - v.Y()*Z(),
0427                          Z()*v.X() - v.Z()*X(),
0428                          X()*v.Y() - v.X()*Y() );
0429         return result;
0430       }
0431       /**
0432          Return vector (cross) product of two  vectors,
0433          as a vector in the coordinate system of this class.
0434           It is possible to perform the product for any classes
0435           implementing X(), Y() and Z() member functions
0436       */
0437       template <class OtherVector>
0438       DisplacementVector3D Cross( const OtherVector & v) const {
0439         DisplacementVector3D  result;
0440         result.SetXYZ (  Y()*v.z() - v.y()*Z(),
0441                          Z()*v.x() - v.z()*X(),
0442                          X()*v.y() - v.x()*Y() );
0443         return result;
0444       }
0445 
0446 
0447 
0448       /**
0449           Self Addition with a displacement vector.
0450       */
0451       template <class OtherCoords>
0452       DisplacementVector3D & operator+=
0453                         (const  DisplacementVector3D<OtherCoords,Tag> & v) {
0454         SetXYZ(  X() + v.X(), Y() + v.Y(), Z() + v.Z() );
0455         return *this;
0456       }
0457 
0458       /**
0459           Self Difference with a displacement vector.
0460       */
0461       template <class OtherCoords>
0462       DisplacementVector3D & operator-=
0463                         (const  DisplacementVector3D<OtherCoords,Tag> & v) {
0464         SetXYZ(  x() - v.x(), y() - v.y(), z() - v.z() );
0465         return *this;
0466       }
0467 
0468 
0469       /**
0470          multiply this vector by a scalar quantity
0471       */
0472       DisplacementVector3D & operator*= (Scalar a) {
0473         fCoordinates.Scale(a);
0474         return *this;
0475       }
0476 
0477       /**
0478          divide this vector by a scalar quantity
0479       */
0480       DisplacementVector3D & operator/= (Scalar a) {
0481         fCoordinates.Scale(1/a);
0482         return *this;
0483       }
0484 
0485       // The following methods (v*a and v/a) could instead be free functions.
0486       // They were moved into the class to solve a problem on AIX.
0487 
0488       /**
0489         Multiply a vector by a real number
0490       */
0491       DisplacementVector3D operator * ( Scalar a ) const {
0492         DisplacementVector3D tmp(*this);
0493         tmp *= a;
0494         return tmp;
0495       }
0496 
0497       /**
0498          Negative of the vector
0499        */
0500       DisplacementVector3D operator - ( ) const {
0501         return operator*( Scalar(-1) );
0502       }
0503 
0504       /**
0505          Positive of the vector, return itself
0506        */
0507       DisplacementVector3D operator + ( ) const {return *this;}
0508 
0509       /**
0510          Division of a vector with a real number
0511        */
0512       DisplacementVector3D operator/ (Scalar a) const {
0513         DisplacementVector3D tmp(*this);
0514         tmp /= a;
0515         return tmp;
0516       }
0517 
0518 
0519       // Methods providing limited backward name compatibility with CLHEP
0520 
0521       Scalar x()     const { return fCoordinates.X();     }
0522       Scalar y()     const { return fCoordinates.Y();     }
0523       Scalar z()     const { return fCoordinates.Z();     }
0524       Scalar r()     const { return fCoordinates.R();     }
0525       Scalar theta() const { return fCoordinates.Theta(); }
0526       Scalar phi()   const { return fCoordinates.Phi();   }
0527       Scalar eta()   const { return fCoordinates.Eta();   }
0528       Scalar rho()   const { return fCoordinates.Rho();   }
0529       Scalar mag2()  const { return fCoordinates.Mag2();  }
0530       Scalar perp2() const { return fCoordinates.Perp2(); }
0531       DisplacementVector3D unit() const {return Unit();}
0532 
0533 
0534     private:
0535 
0536        CoordSystem fCoordinates;  // internal coordinate system
0537        static constexpr unsigned int fDimension = CoordinateType::Dimension;
0538 
0539 #ifdef NOT_SURE_THIS_SHOULD_BE_FORBIDDEN
0540       /**
0541          Cross product involving a position vector is inappropriate
0542       */
0543       template <class T2>
0544       DisplacementVector3D Cross( const PositionVector3D<T2> & ) const;
0545 #endif
0546 
0547       // the following methods should not compile
0548 
0549       // this should not compile (if from a vector or points with different tag
0550       template <class OtherCoords, class OtherTag>
0551       explicit constexpr DisplacementVector3D( const DisplacementVector3D<OtherCoords, OtherTag> & ) {}
0552 
0553       template <class OtherCoords, class OtherTag>
0554       explicit constexpr DisplacementVector3D( const PositionVector3D<OtherCoords, OtherTag> & ) {}
0555 
0556       template <class OtherCoords, class OtherTag>
0557       DisplacementVector3D & operator=( const DisplacementVector3D<OtherCoords, OtherTag> & );
0558 
0559 
0560       template <class OtherCoords, class OtherTag>
0561       DisplacementVector3D & operator=( const PositionVector3D<OtherCoords, OtherTag> & );
0562 
0563       template <class OtherCoords, class OtherTag>
0564       DisplacementVector3D & operator+=(const  DisplacementVector3D<OtherCoords, OtherTag> & );
0565 
0566       template <class OtherCoords, class OtherTag>
0567       DisplacementVector3D & operator-=(const  DisplacementVector3D<OtherCoords, OtherTag> & );
0568 
0569       template<class OtherCoords, class OtherTag >
0570       Scalar Dot( const  DisplacementVector3D<OtherCoords, OtherTag> &  ) const;
0571 
0572       template<class OtherCoords, class OtherTag >
0573       DisplacementVector3D Cross( const  DisplacementVector3D<OtherCoords, OtherTag> &  ) const;
0574 
0575 
0576     };
0577 
0578 // ---------- DisplacementVector3D class template ends here ------------
0579 // ---------------------------------------------------------------------
0580 
0581 
0582 
0583    /**
0584         Addition of DisplacementVector3D vectors.
0585         The (coordinate system) type of the returned vector is defined to
0586         be identical to that of the first vector, which is passed by value
0587     */
0588     template <class CoordSystem1, class CoordSystem2, class U>
0589     inline
0590     DisplacementVector3D<CoordSystem1,U>
0591     operator+(       DisplacementVector3D<CoordSystem1,U> v1,
0592                const DisplacementVector3D<CoordSystem2,U>  & v2) {
0593       return v1 += v2;
0594     }
0595 
0596     /**
0597         Difference between two DisplacementVector3D vectors.
0598         The (coordinate system) type of the returned vector is defined to
0599         be identical to that of the first vector.
0600     */
0601     template <class CoordSystem1, class CoordSystem2, class U>
0602     inline
0603     DisplacementVector3D<CoordSystem1,U>
0604     operator-( DisplacementVector3D<CoordSystem1,U> v1,
0605                DisplacementVector3D<CoordSystem2,U> const & v2) {
0606       return v1 -= v2;
0607     }
0608 
0609     /**
0610        Multiplication of a displacement vector by real number  a*v
0611     */
0612     template <class CoordSystem, class U>
0613     inline
0614     DisplacementVector3D<CoordSystem,U>
0615     operator * ( typename DisplacementVector3D<CoordSystem,U>::Scalar a,
0616                  DisplacementVector3D<CoordSystem,U> v) {
0617       return v *= a;
0618       // Note - passing v by value and using operator *= may save one
0619       // copy relative to passing v by const ref and creating a temporary.
0620     }
0621 
0622 
0623     // v1*v2 notation for Cross product of two vectors is omitted,
0624     // since it is always confusing as to whether dot product is meant.
0625 
0626 
0627 
0628     // ------------- I/O to/from streams -------------
0629 
0630     template <class char_t, class traits_t, class T, class U,
0631               typename std::enable_if<std::is_arithmetic<typename DisplacementVector3D<T, U>::Scalar>::value>::type * =
0632                  nullptr>
0633     std::basic_ostream<char_t, traits_t> &operator<<(std::basic_ostream<char_t, traits_t> &os,
0634                                                      DisplacementVector3D<T, U> const &v)
0635     {
0636        if (os) {
0637 
0638           typename T::Scalar a, b, c;
0639           v.GetCoordinates(a, b, c);
0640 
0641           if (detail::get_manip(os, detail::bitforbit)) {
0642              detail::set_manip(os, detail::bitforbit, '\00');
0643              typedef GenVector_detail::BitReproducible BR;
0644              BR::Output(os, a);
0645              BR::Output(os, b);
0646              BR::Output(os, c);
0647           } else {
0648              os << detail::get_manip(os, detail::open) << a << detail::get_manip(os, detail::sep) << b
0649                 << detail::get_manip(os, detail::sep) << c << detail::get_manip(os, detail::close);
0650           }
0651       }
0652       return os;
0653     }  // op<< <>()
0654 
0655     template <class char_t, class traits_t, class T, class U,
0656               typename std::enable_if<!std::is_arithmetic<typename DisplacementVector3D<T, U>::Scalar>::value>::type * =
0657                  nullptr>
0658     std::basic_ostream<char_t, traits_t> &operator<<(std::basic_ostream<char_t, traits_t> &os,
0659                                                      DisplacementVector3D<T, U> const &v)
0660     {
0661        if (os) {
0662           os << "{ ";
0663           for (std::size_t i = 0; i < PositionVector3D<T, U>::Scalar::Size; ++i) {
0664              os << "(" << v.x()[i] << "," << v.y()[i] << "," << v.z()[i] << ") ";
0665           }
0666           os << "}";
0667        }
0668        return os;
0669     } // op<< <>()
0670 
0671     template< class char_t, class traits_t, class T, class U >
0672       inline
0673       std::basic_istream<char_t,traits_t> &
0674       operator >> ( std::basic_istream<char_t,traits_t> & is
0675                   , DisplacementVector3D<T,U> & v
0676                   )
0677     {
0678       if( !is )  return is;
0679 
0680       typename T::Scalar a, b, c;
0681 
0682       if( detail::get_manip( is, detail::bitforbit ) )  {
0683         detail::set_manip( is, detail::bitforbit, '\00' );
0684         typedef GenVector_detail::BitReproducible BR;
0685         BR::Input(is, a);
0686         BR::Input(is, b);
0687         BR::Input(is, c);
0688       }
0689       else  {
0690         detail::require_delim( is, detail::open  );  is >> a;
0691         detail::require_delim( is, detail::sep   );  is >> b;
0692         detail::require_delim( is, detail::sep   );  is >> c;
0693         detail::require_delim( is, detail::close );
0694       }
0695 
0696       if( is )
0697         v.SetCoordinates(a, b, c);
0698       return is;
0699 
0700     }  // op>> <>()
0701 
0702     // Structured bindings
0703     template <std::size_t I, class CoordSystem, class Tag>
0704     typename CoordSystem::Scalar get(DisplacementVector3D<CoordSystem, Tag> const& p)
0705     {
0706        static_assert(I < 3);
0707        if constexpr (I == 0) {
0708           return p.x();
0709        } else if constexpr (I == 1) {
0710           return p.y();
0711        } else {
0712           return p.z();
0713        }
0714     }
0715 
0716   }  // namespace Math
0717 
0718 }  // namespace ROOT
0719 
0720 // Structured bindings
0721 #include <tuple>
0722 namespace std {
0723    template <class CoordSystem, class Tag>
0724    struct tuple_size<ROOT::Math::DisplacementVector3D<CoordSystem, Tag>> : integral_constant<size_t, 3> {};
0725    template <size_t I, class CoordSystem, class Tag>
0726    struct tuple_element<I, ROOT::Math::DisplacementVector3D<CoordSystem, Tag>> {
0727       static_assert(I < 3);
0728       using type = typename CoordSystem::Scalar;
0729    };
0730 }
0731 
0732 #endif /* ROOT_Math_GenVector_DisplacementVector3D  */
0733