Belle II Software development
VectorUtil.h
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#pragma once
10
11#include <framework/geometry/VectorUtil.h>
12
13#include <tracking/trackingUtilities/numerics/EForwardBackward.h>
14#include <tracking/trackingUtilities/numerics/ERightLeft.h>
15#include <tracking/trackingUtilities/numerics/ERotation.h>
16#include <tracking/trackingUtilities/numerics/ESign.h>
17
18/* ROOT headers. */
19#include <Math/Vector3D.h>
20#include <Math/Vector2D.h>
21#include <Math/VectorUtil.h>
22
23namespace Belle2 {
28
29 namespace VectorUtil {
30
31 inline bool hasNAN(const ROOT::Math::XYVector& a)
32 {
33 return std::isnan(a.X()) or std::isnan(a.Y());
34 }
35
36 inline bool hasNAN(const ROOT::Math::XYZVector& a)
37 {
38 return std::isnan(a.X()) or std::isnan(a.Y()) or std::isnan(a.Z());
39 }
40
41 inline bool isNull(const ROOT::Math::XYVector& a)
42 {
43 return a.X() == 0.0 and a.Y() == 0.0;
44 }
45
46 inline bool isNull(const ROOT::Math::XYZVector& a)
47 {
48 return a.X() == 0.0 and a.Y() == 0.0 and a.Z() == 0.0;
49 }
50
52
56 inline ROOT::Math::XYVector average(const ROOT::Math::XYVector& a, const ROOT::Math::XYVector& b)
57 {
58 if (hasNAN(a)) {
59 return b;
60 } else if (hasNAN(b)) {
61 return a;
62 } else {
63 return ROOT::Math::XYVector((a.X() + b.X()) / 2.0, (a.Y() + b.Y()) / 2.0);
64 }
65 }
66
68
72 inline ROOT::Math::XYVector average(const ROOT::Math::XYVector& a, const ROOT::Math::XYVector& b, const ROOT::Math::XYVector& c)
73 {
74 if (hasNAN(a)) {
75 return average(b, c);
76 } else if (hasNAN(b)) {
77 return average(a, c);
78 } else if (hasNAN(c)) {
79 return average(a, b);
80 } else {
81 return ROOT::Math::XYVector((a.X() + b.X() + c.X()) / 3.0,
82 (a.Y() + b.Y() + c.Y()) / 3.0);
83 }
84 }
85
87
91 inline ROOT::Math::XYZVector average(const ROOT::Math::XYZVector& a, const ROOT::Math::XYZVector& b)
92 {
93 if (hasNAN(a)) {
94 return b;
95 } else if (hasNAN(b)) {
96 return a;
97 } else {
98 return ROOT::Math::XYZVector((a.x() + b.x()) / 2.0,
99 (a.y() + b.y()) / 2.0,
100 (a.z() + b.z()) / 2.0);
101 }
102 }
103
106
110 inline ROOT::Math::XYVector compose(const ROOT::Math::XYVector& coordinateVec, const double parallelCoor, const double orthoCoor)
111 {
112 return ROOT::Math::XYVector(coordinateVec.x() * parallelCoor - coordinateVec.y() * orthoCoor,
113 coordinateVec.y() * parallelCoor + coordinateVec.x() * orthoCoor);
114 }
115
117 template<class Vector>
118 inline Vector unit(const Vector& a)
119 {
120 if (isNull(a)) {
121 return Vector();
122 }
123 Vector tmp(a);
124 // Somehow, the Cartesion2D vector knows Scale, but DisplacementVector2D does not, and as DisplacementVector2D<Cartesion2D.....
125 // So can't use Scale, and perform plain math operations instead... ¯\_(ツ)_/¯
126 // return tmp.Scale(1. / tmp.R());
127 return tmp / tmp.R();
128 }
129
131 inline ROOT::Math::XYVector Phi(const double phi)
132 {
133 return std::isnan(phi) ? ROOT::Math::XYVector(0.0, 0.0) : ROOT::Math::XYVector(std::cos(phi), std::sin(phi));
134 }
135
137 inline ROOT::Math::XYVector Orthogonal(const ROOT::Math::XYVector& a, const TrackingUtilities::ERotation ccwInfo)
138 {
139 return isValid(ccwInfo) ? ROOT::Math::XYVector(-static_cast<double>(ccwInfo) * a.Y(),
140 static_cast<double>(ccwInfo) * a.X()) : ROOT::Math::XYVector();
141 }
142
144 inline double Distance(const ROOT::Math::XYVector& from, const ROOT::Math::XYVector& to = ROOT::Math::XYVector(0.0, 0.0))
145 {
146 return (from - to).R();
147 }
148
150 inline double Distance(const ROOT::Math::XYZVector& from, const ROOT::Math::XYZVector& to = ROOT::Math::XYZVector(0.0, 0.0, 0.0))
151 {
152 return (from - to).R();
153 }
154
161 template<class Vector>
162 inline double unnormalizedParallelComp(const Vector& v1, const Vector& relativTo)
163 {
164 return relativTo.Dot(v1);
165 }
166
168
173 template<class Vector>
174 inline double orthogonalComp(const Vector& v1, const Vector& relativTo)
175 {
176 return Cross(relativTo, v1) / relativTo.R();
177 }
178
180
186 inline double unnormalizedOrthogonalComp(const ROOT::Math::XYVector& v1, const ROOT::Math::XYVector& relativTo)
187 {
188 return Cross(relativTo, v1);
189 }
190
195 inline ROOT::Math::XYVector passiveRotatedBy(const ROOT::Math::XYVector& v1, const ROOT::Math::XYVector& phiVec)
196 {
197 return ROOT::Math::XYVector(unnormalizedParallelComp(v1, phiVec), unnormalizedOrthogonalComp(v1, phiVec));
198 }
199
202 inline TrackingUtilities::ERightLeft isRightOrLeftOf(const ROOT::Math::XYVector& toCheck, const ROOT::Math::XYVector& rhs)
203 {
204 return static_cast<TrackingUtilities::ERightLeft>(-TrackingUtilities::sign(unnormalizedOrthogonalComp(toCheck, rhs)));
205 }
206
208 inline bool isLeftOf(const ROOT::Math::XYVector& toCheck, const ROOT::Math::XYVector& rhs)
209 {
210 return isRightOrLeftOf(toCheck, rhs) == TrackingUtilities::ERightLeft::c_Left;
211 }
212
214 inline bool isRightOf(const ROOT::Math::XYVector& toCheck, const ROOT::Math::XYVector& rhs)
215 {
216 return isRightOrLeftOf(toCheck, rhs) == TrackingUtilities::ERightLeft::c_Right;
217 }
218
220 inline bool sameSign(float n1, float n2, float n3)
221 {
222 return ((n1 > 0 and n2 > 0 and n3 > 0) or (n1 < 0 and n2 < 0 and n3 < 0));
223 }
224
230 inline bool isBetween(const ROOT::Math::XYVector& toCheck, const ROOT::Math::XYVector& lower, const ROOT::Math::XYVector& upper)
231 {
232 // Set up a linear (nonorthogonal) transformation that maps
233 // lower -> (1, 0)
234 // upper -> (0, 1)
235 // Check whether this transformation is orientation conserving
236 // If yes this vector must lie in the first quadrant to be between lower and upper
237 // If no it must lie in some other quadrant.
238 const double det = Cross(lower, upper);
239 if (det == 0) {
240 // lower and upper are coaligned
241 return isRightOf(toCheck, lower) and isLeftOf(toCheck, upper);
242 } else {
243 const bool flipsOrientation = det < 0;
244 const double transformedX = Cross(toCheck, upper);
245 const double transformedY = -Cross(toCheck, lower);
246 bool inFirstQuadrant = sameSign(det, transformedX, transformedY);
247 if (flipsOrientation) {
248 inFirstQuadrant = not inFirstQuadrant;
249 }
250 return inFirstQuadrant;
251 }
252 }
253
256 inline TrackingUtilities::EForwardBackward isForwardOrBackwardOf(const ROOT::Math::XYVector& toCheck,
257 const ROOT::Math::XYVector& rhs)
258 {
259 return static_cast<TrackingUtilities::EForwardBackward>(TrackingUtilities::sign(unnormalizedParallelComp(toCheck, rhs)));
260 }
261
263
269 inline bool smaller(const ROOT::Math::XYVector& lhs, const ROOT::Math::XYVector& rhs)
270 {
271 return lhs.Mag2() < rhs.Mag2() or
272 (lhs.Mag2() == rhs.Mag2() and (lhs.Phi() < rhs.Phi()));
273 }
274
277
283 inline bool smaller(const ROOT::Math::XYZVector& lhs, const ROOT::Math::XYZVector& rhs)
284 {
285 return lhs.R() < rhs.R() or (lhs.R() == rhs.R() and
286 (lhs.z() < rhs.z() or (lhs.z() == rhs.z() and (lhs.Phi() < rhs.Phi()))));
287 }
288
290 inline ROOT::Math::XYVector getXYVector(const ROOT::Math::XYZVector& a)
291 {
292 return ROOT::Math::XYVector(a.X(), a.Y());
293 }
294
295 } // namespace VectorUtil
296
298} // namespace Belle2
bool isValid(EForwardBackward eForwardBackward)
Check whether the given enum instance is one of the valid values.
Abstract base class for different kinds of events.