ATLAS Offline Software
BoundaryCheck.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 namespace Trk {
6 // should have maximum (average) error of 0.0015 (0.00089) radians or 0.0859
7 // (0.0509) degrees, fine for us and much faster (>4 times)
8 inline double
9 BoundaryCheck::FastArcTan(double x) const
10 {
11  double y;
12  bool complement = false; // true if arg was >1
13  bool sign = false; // true if arg was < 0
14  if (x < 0.) {
15  x = -x;
16  sign = true; // arctan(-x)=-arctan(x)
17  }
18  if (x > 1.) {
19  x = 1. / x; // keep arg between 0 and 1
20  complement = true;
21  }
22  y = M_PI_4 * x - x * (fabs(x) - 1) * (0.2447 + 0.0663 * fabs(x));
23  if (complement)
24  y = M_PI_2 - y; // correct for 1/x if we did that
25  if (sign)
26  y = -y; // correct for negative arg
27  return y;
28 }
29 
30 // should have maximum (average) error of 0.001 (0.0005) radians or 0.0573
31 // (0.029) degrees, fine for us and much faster
32 // (>8 times)
33 inline sincosCache
34 BoundaryCheck::FastSinCos(double x) const
35 {
36  sincosCache tmp;
37  // always wrap input angle to -PI..PI
38  if (x < -M_PI)
39  x += 2. * M_PI;
40  else if (x > M_PI)
41  x -= 2. * M_PI;
42 
43  // compute sine
44  if (x < 0.) {
45  tmp.sinC = 1.27323954 * x + .405284735 * x * x;
46 
47  if (tmp.sinC < 0.)
48  tmp.sinC = .225 * (tmp.sinC * -tmp.sinC - tmp.sinC) + tmp.sinC;
49  else
50  tmp.sinC = .225 * (tmp.sinC * tmp.sinC - tmp.sinC) + tmp.sinC;
51  } else {
52  tmp.sinC = 1.27323954 * x - 0.405284735 * x * x;
53 
54  if (tmp.sinC < 0.)
55  tmp.sinC = .225 * (tmp.sinC * -tmp.sinC - tmp.sinC) + tmp.sinC;
56  else
57  tmp.sinC = .225 * (tmp.sinC * tmp.sinC - tmp.sinC) + tmp.sinC;
58  }
59 
60  // compute cosine: sin(x + PI/2) = cos(x)
61  x += M_PI_2;
62  if (x > M_PI)
63  x -= 2. * M_PI;
64 
65  if (x < 0.) {
66  tmp.cosC = 1.27323954 * x + 0.405284735 * x * x;
67 
68  if (tmp.cosC < 0.)
69  tmp.cosC = .225 * (tmp.cosC * -tmp.cosC - tmp.cosC) + tmp.cosC;
70  else
71  tmp.cosC = .225 * (tmp.cosC * tmp.cosC - tmp.cosC) + tmp.cosC;
72  } else {
73  tmp.cosC = 1.27323954 * x - 0.405284735 * x * x;
74 
75  if (tmp.cosC < 0.)
76  tmp.cosC = .225 * (tmp.cosC * -tmp.cosC - tmp.cosC) + tmp.cosC;
77  else
78  tmp.cosC = .225 * (tmp.cosC * tmp.cosC - tmp.cosC) + tmp.cosC;
79  }
80  return tmp;
81 }
82 
83 // does the conversion of an ellipse of height h and width w to an polygon with
84 // 4 + 4*resolution points
85 inline std::vector<Amg::Vector2D>
86 BoundaryCheck::EllipseToPoly(int resolution) const
87 {
88  const double h = nSigmas * sqrt(lCovariance(1, 1));
89  const double w = nSigmas * sqrt(lCovariance(0, 0));
90 
91  // first add the four vertices
92  std::vector<Amg::Vector2D> v((1 + resolution) * 4);
93  v[0] = Amg::Vector2D ( w, 0.);
94  v[1] = Amg::Vector2D (-w, 0.);
95  v[2] = Amg::Vector2D ( 0., h);
96  v[3] = Amg::Vector2D ( 0., -h);
97 
98  // now add a number, equal to the resolution, of equidistant points in each
99  // quadrant resolution == 3 seems to be a solid working point, but possibility
100  // open to change to any number in the future
101  AmgSymMatrix(2) t1;
102  // cppcheck-suppress constStatement
103  t1 << 1, 0, 0, -1;
104  AmgSymMatrix(2) t2;
105  // cppcheck-suppress constStatement
106  t2 << -1, 0, 0, -1;
107  AmgSymMatrix(2) t3;
108  // cppcheck-suppress constStatement
109  t3 << -1, 0, 0, 1;
110  if (resolution != 3) {
111  sincosCache scResult;
112  for (int i = 1; i <= resolution; i++) {
113  scResult = FastSinCos(M_PI_2 * i / (resolution + 1));
114  Amg::Vector2D t (w * scResult.sinC, h * scResult.cosC);
115  v[i * 4 + 0] = t;
116  v[i * 4 + 1] = t1 * t;
117  v[i * 4 + 2] = t2 * t;
118  v[i * 4 + 3] = t3 * t;
119  }
120  } else {
121  Amg::Vector2D t (w * s_cos22, h * s_cos67);
122  v[4] = t;
123  v[5] = t1 * t;
124  v[6] = t2 * t;
125  v[7] = t3 * t;
126  t = Amg::Vector2D (w * s_cos45, h * s_cos45);
127  v[8] = t;
128  v[9] = t1 * t;
129  v[10] = t2 * t;
130  v[11] = t3 * t;
131  t = Amg::Vector2D (w * s_cos67, h * s_cos22);
132  v[12] = t;
133  v[13] = t1 * t;
134  v[14] = t2 * t;
135  v[15] = t3 * t;
136  }
137  return v;
138 }
139 
140 // calculates KDOP object from given polygon and set of axes
141 inline void
142 BoundaryCheck::ComputeKDOP(const std::vector<Amg::Vector2D>& v,
143  const std::vector<Amg::Vector2D>& KDOPAxes,
144  std::vector<KDOP>& kdop) const
145 {
146  // initialize KDOP to first point
147  unsigned int k = KDOPAxes.size();
148  for (unsigned int i = 0; i < k; i++) {
149  kdop[i].max =
150  KDOPAxes[i](0, 0) * v[0](0, 0) + KDOPAxes[i](1, 0) * v[0](1, 0);
151  kdop[i].min =
152  KDOPAxes[i](0, 0) * v[0](0, 0) + KDOPAxes[i](1, 0) * v[0](1, 0);
153  }
154  // now for each additional point, update KDOP bounds if necessary
155  float value;
156  for (unsigned int i = 1; i < v.size(); i++) {
157  for (unsigned int j = 0; j < k; j++) {
158  value = KDOPAxes[j](0, 0) * v[i](0, 0) + KDOPAxes[j](1, 0) * v[i](1, 0);
159  if (value < kdop[j].min)
160  kdop[j].min = value;
161  else if (value > kdop[j].max)
162  kdop[j].max = value;
163  }
164  }
165 }
166 
167 // this is the method to actually check if two KDOPs overlap
168 inline bool
169 BoundaryCheck::TestKDOPKDOP(const std::vector<KDOP>& a,
170  const std::vector<KDOP>& b) const
171 {
172  int k = a.size();
173  // check if any intervals are non-overlapping, return if so
174  for (int i = 0; i < k; i++)
175  if (a[i].min > b[i].max || a[i].max < b[i].min)
176  return false;
177  // all intervals are overlapping, so KDOPs must intersect
178  return true;
179 }
180 
181 }
182