Belle II Software development
GeneralizedCircle.cc
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#include <tracking/trackingUtilities/geometry/GeneralizedCircle.h>
9
10#include <tracking/trackingUtilities/geometry/Circle2D.h>
11#include <tracking/trackingUtilities/geometry/Line2D.h>
12
13#include <tracking/trackingUtilities/numerics/EForwardBackward.h>
14#include <tracking/trackingUtilities/numerics/ERotation.h>
15
16#include <tracking/trackingUtilities/numerics/SpecialFunctions.h>
17#include <tracking/trackingUtilities/numerics/Quadratic.h>
18
19#include <ostream>
20#include <cmath>
21
22using namespace Belle2;
23using namespace TrackingUtilities;
24
26 const double n1,
27 const double n2,
28 const double n3)
29 : m_n3(n3)
30 , m_n12(n1, n2)
31 , m_n0(n0)
32{
33 normalize();
34}
35
36GeneralizedCircle::GeneralizedCircle(const double n0, const ROOT::Math::XYVector& n12, const double n3)
37 : m_n3(n3)
38 , m_n12(n12)
39 , m_n0(n0)
40{
41 normalize();
42}
43
45 : m_n3(0.0)
46 , m_n12(n012.n12())
47 , m_n0(n012.n0())
48{
49 normalize();
50}
51
53 : m_n3(1.0 / 2.0 / circle.radius())
54 , m_n12(-circle.center().x() * (m_n3 * 2.0), -circle.center().y() * (m_n3 * 2.0))
55 , m_n0((circle.center().Mag2() - circle.radiusSquared()) * m_n3)
56{
57}
58
60 const double absRadius,
61 const ERotation orientation)
62{
63 GeneralizedCircle generalizedCircle;
65 return generalizedCircle;
66}
67
69 const ROOT::Math::XYVector& tangential,
70 const double impact)
71{
72 GeneralizedCircle generalizedCircle;
74 return generalizedCircle;
75}
76
78 const double tangentialPhi,
79 const double impact)
80{
81 GeneralizedCircle generalizedCircle;
83 return generalizedCircle;
84}
85
86void GeneralizedCircle::setCenterAndRadius(const ROOT::Math::XYVector& center,
87 const double absRadius,
88 const ERotation orientation)
89{
90 double curvature = static_cast<double>(orientation) / fabs(absRadius);
91 setN0((center.Mag2() - absRadius * absRadius) * curvature / 2.0);
92 setN1(-center.x() * curvature);
93 setN2(-center.y() * curvature);
94 setN3(curvature / 2.0);
95 normalize(); // the call to normalize should be superfluous
96}
97
99 const ROOT::Math::XYVector& tangential,
100 const double impact)
101{
102 double loc_n0 = impact * (impact * curvature / 2.0 + 1.0);
103 ROOT::Math::XYVector loc_n12 = -VectorUtil::Orthogonal(tangential) * (1 + curvature * impact);
104 double loc_n3 = curvature / 2.0;
105 setN(loc_n0, loc_n12, loc_n3);
106}
107
108ROOT::Math::XYVector GeneralizedCircle::closest(const ROOT::Math::XYVector& point) const
109{
110 if (fastDistance(point) == 0) return point;
111
112 // solve the minimization | point - pointOnCirlce | ^2 subjected to the on circle constraint
113 // 1.0 * m_n0 +
114 // point.x() * m_n1 +
115 // point.y() * m_n2 +
116 // point.cylindricalRSquared() * m_n3 == 0
117 // solved with a Lagrangian multiplicator for the constraint
118
119 ROOT::Math::XYVector gradientAtPoint = gradient(point);
120 ROOT::Math::XYVector coordinateSystem = VectorUtil::unit(gradientAtPoint);
121
122 // component of closest approach orthogonal to coordinateSystem
123 double closestOrthogonal = VectorUtil::Cross(n12(), point) / gradientAtPoint.R();
124
125 // component of closest approach parallel to coordinateSystem - two solutions expected
126 double nOrthogonal = VectorUtil::unnormalizedOrthogonalComp(n12(), coordinateSystem);
127 double nParallel = VectorUtil::unnormalizedParallelComp(n12(), coordinateSystem);
128
129 double closestParallel = 0.0;
130 if (isLine()) {
131 closestParallel = -(nOrthogonal * closestOrthogonal + n0()) / nParallel;
132
133 } else {
134 const double a = n3();
135 const double b = nParallel;
136 const double c = n0() + (nOrthogonal + n3() * closestOrthogonal) * closestOrthogonal;
137
138 const std::pair<double, double> closestParallel12 = solveQuadraticABC(a, b, c);
139
140 // take the solution with smaller distance to point
141 const double pointParallel = VectorUtil::unnormalizedParallelComp(point, coordinateSystem);
142
143 const double criterion1 =
144 closestParallel12.first * (closestParallel12.first - 2 * pointParallel);
145 const double criterion2 =
146 closestParallel12.second * (closestParallel12.second - 2 * pointParallel);
147
148 closestParallel = criterion1 < criterion2 ? closestParallel12.first : closestParallel12.second;
149 }
150 return VectorUtil::compose(coordinateSystem, closestParallel, closestOrthogonal);
151}
152
153ROOT::Math::XYVector GeneralizedCircle::perigee() const
154{
155 ROOT::Math::XYVector result(n12());
156 result *= (-impact() / result.R());
157 return result;
158}
159
160ROOT::Math::XYVector GeneralizedCircle::apogee() const
161{
162 ROOT::Math::XYVector result(n12());
163 result *= ((-impact() - 2 * radius()) / result.R());
164 return result;
165}
166
167ROOT::Math::XYVector GeneralizedCircle::chooseNextForwardOf(const ROOT::Math::XYVector& start,
168 const ROOT::Math::XYVector& end1,
169 const ROOT::Math::XYVector& end2) const
170{
171 double lengthOnCurve1 = arcLengthBetween(start, end1);
172 double lengthOnCurve2 = arcLengthBetween(start, end2);
173
174 if (lengthOnCurve1 >= 0.0) {
175
176 if (lengthOnCurve2 >= 0.0) {
177 return lengthOnCurve1 < lengthOnCurve2 ? end1 : end2;
178 } else {
179 return end1;
180 }
181 } else {
182
183 if (lengthOnCurve2 >= 0.0) {
184 return end2;
185 } else {
186
187 // both lengths on curve have a negative sign
188 // the candidate with the lesser length on curve wins because of the discontinuaty
189 // unless the generalized circle is a line
190 // in this case their is no forward intersection with the same cylindrical radius
191 if (isLine()) {
192 return ROOT::Math::XYVector(NAN, NAN);
193 } else {
194 return lengthOnCurve1 < lengthOnCurve2 ? end1 : end2;
195 }
196 }
197 }
198 return ROOT::Math::XYVector(NAN, NAN); // just avoid a compiler warning
199}
200
201std::pair<ROOT::Math::XYVector, ROOT::Math::XYVector> GeneralizedCircle::atCylindricalR(const double cylindricalR) const
202{
203 // extraploted to r
204 // solve
205 // n0 + n1*x + n2*y + n3*r*r == 0
206 // and r = cylindricalR
207 // search for x and y
208
209 // solve the equation in a coordinate system parallel and orthogonal to the reduced circle center
210 const ROOT::Math::XYVector nUnit = VectorUtil::unit(n12());
211
212 // parallel component
213 const double sameCylindricalRParallel = -(n0() + n3() * square(cylindricalR)) / n12().R();
214
215 // orthogonal component
216 const double sameCylindricalROrthogonal = sqrt(square(cylindricalR) - square(sameCylindricalRParallel));
217
219 ROOT::Math::XYVector sameCylindricalR1 =
220 VectorUtil::compose(nUnit, sameCylindricalRParallel, -sameCylindricalROrthogonal);
221
222 ROOT::Math::XYVector sameCylindricalR2 =
223 VectorUtil::compose(nUnit, sameCylindricalRParallel, sameCylindricalROrthogonal);
224
225 std::pair<ROOT::Math::XYVector, ROOT::Math::XYVector> result(sameCylindricalR1, sameCylindricalR2);
226 return result;
227}
228
229ROOT::Math::XYVector GeneralizedCircle::atCylindricalRForwardOf(const ROOT::Math::XYVector& startPoint,
230 const double cylindricalR) const
231{
232 std::pair<ROOT::Math::XYVector, ROOT::Math::XYVector> candidatePoints = atCylindricalR(cylindricalR);
233 return chooseNextForwardOf(startPoint, candidatePoints.first, candidatePoints.second);
234}
235
236double GeneralizedCircle::arcLengthBetween(const ROOT::Math::XYVector& from, const ROOT::Math::XYVector& to) const
237{
238 EForwardBackward lengthSign = isForwardOrBackwardOf(from, to);
239 if (not NForwardBackward::isValid(lengthSign)) return NAN;
240
241 // Handling the rare case that from and to correspond to opposing points on the circle
242 if (lengthSign == EForwardBackward::c_Unknown) lengthSign = EForwardBackward::c_Forward;
243
244 ROOT::Math::XYVector closestAtFrom = closest(from);
245 ROOT::Math::XYVector closestAtTo = closest(to);
246 double directDistance = VectorUtil::Distance(closestAtFrom, closestAtTo);
247
248 return static_cast<double>(lengthSign) * arcLengthFactor(directDistance) * directDistance;
249}
250
251double GeneralizedCircle::arcLengthTo(const ROOT::Math::XYVector& to) const
252{
253 const ROOT::Math::XYVector from = perigee();
254
255 EForwardBackward lengthSign = isForwardOrBackwardOf(from, to);
256 if (not NForwardBackward::isValid(lengthSign)) return NAN;
257
258 // Handling the rare case that from and to correspond to opposing points on the circle
259 if (lengthSign == EForwardBackward::c_Unknown) lengthSign = EForwardBackward::c_Forward;
260
261 const ROOT::Math::XYVector& closestAtFrom = from;
262 ROOT::Math::XYVector closestAtTo = closest(to);
263 double directDistance = VectorUtil::Distance(closestAtFrom, closestAtTo);
264
265 return static_cast<double>(lengthSign) * arcLengthFactor(directDistance) * directDistance;
266}
267
268double GeneralizedCircle::arcLengthToCylindricalR(const double cylindricalR) const
269{
270 // Slight trick here
271 // Since the sought point is on the helix we treat it as the perigee
272 // and the origin as the point to extrapolate to.
273 // We know the distance of the origin to the circle, which is just d0
274 // The direct distance from the origin to the imaginary perigee is just the given cylindricalR.
275 const double dr = d0();
276 const double directDistance =
277 sqrt((cylindricalR + dr) * (cylindricalR - dr) / (1 + dr * omega()));
278 const double arcLength = arcLengthFactor(directDistance) * directDistance;
279 return arcLength;
280}
281
282double GeneralizedCircle::arcLengthFactor(const double directDistance, const double curvature)
283{
284 double x = directDistance * curvature / 2.0;
285 return asinc(x);
286}
287
288double GeneralizedCircle::distance(const ROOT::Math::XYVector& point) const
289{
290 const double fastD = fastDistance(point);
291 return distance(fastD);
292}
293
295{
296 if (fastDistance == 0.0 or isLine()) {
297 // special case for unfitted state
298 // and line
299 return fastDistance;
300 } else {
301
302 const double a = n3();
303 const double b = 1;
304 const double c = -fastDistance;
305
306 std::pair<double, double> distance12 = solveQuadraticABC(a, b, c);
307
308 // take the small solution which has always the same sign of the fastDistance
309 return distance12.second;
310 }
311}
312
313std::pair<ROOT::Math::XYVector, ROOT::Math::XYVector>
315{
316 const double m0 = generalizedCircle.n0();
317 const ROOT::Math::XYVector& m12 = generalizedCircle.n12();
318 const double m3 = generalizedCircle.n3();
319
320 const double loc_n0 = this->n0();
321 const ROOT::Math::XYVector& loc_n12 = this->n12();
322 const double loc_n3 = this->n3();
323
324 ROOT::Math::XYVector unitC = loc_n12 * m3 - m12 * loc_n3;
325 double absC = unitC.R();
326 if (absC != 0.0) {
327 unitC *= (1. / absC);
328 }
329
330 double xParallel = (m0 * loc_n3 - m3 * loc_n0) / absC;
331
332 // Use symmetric solution and use all input parameters
333 ROOT::Math::XYVector mn12 = loc_n12 + m12;
334 double mn12Parallel = VectorUtil::unnormalizedParallelComp(unitC, mn12);
335 double mn12Orthogonal = VectorUtil::unnormalizedOrthogonalComp(unitC, mn12);
336
337 double a = m3 + loc_n3;
338 double b = mn12Orthogonal;
339 double c = (a * xParallel + mn12Parallel) * xParallel + m0 + loc_n0;
340
341 std::pair<double, double> xOrthogonal = solveQuadraticABC(a, b, c);
342
343 return std::make_pair(VectorUtil::compose(unitC, xParallel, xOrthogonal.first),
344 VectorUtil::compose(unitC, xParallel, xOrthogonal.second));
345}
346
347ROOT::Math::XYVector GeneralizedCircle::atArcLength(const double arcLength) const
348{
349 double chi = arcLength * curvature();
350 double chiHalf = chi / 2.0;
351
352 double atX = arcLength * sinc(chiHalf) * sin(chiHalf) + impact();
353 double atY = -arcLength * sinc(chi);
354 return VectorUtil::compose(-VectorUtil::unit(n12()), atX, atY);
355}
356
357std::ostream& TrackingUtilities::operator<<(std::ostream& output, const GeneralizedCircle& circle)
358{
359 if (circle.isLine()) {
360 output << "Line support point = " << circle.perigee();
361 return output;
362 } else {
363 output << "CircleCenter = " << circle.center() << ", Radius = " << circle.absRadius();
364 return output;
365 }
366}
A two dimensional circle in its natural representation using center and radius as parameters.
Definition Circle2D.h:32
GeneralizedCircle()=default
Default constructor for ROOT compatibility.
ROOT::Math::XYVector tangential(const ROOT::Math::XYVector &point) const
Tangential vector to the circle near the given position.
static GeneralizedCircle fromPerigeeParameters(double curvature, const ROOT::Math::XYVector &tangential, double impact)
Constructor of a generalized circle from perigee parameters.
double m_n3
Memory for the fourth parameter.
double n1() const
Getter for the second circle parameter.
ROOT::Math::XYVector gradient(const ROOT::Math::XYVector &point) const
Gradient of the distance field Gives the gradient of the approximated distance field for the given po...
bool isLine() const
Indicates if the generalized circle is actually a line.
ROOT::Math::XYVector apogee() const
Calculates the point on the circle that is furthest away from the origin.
double fastDistance(const ROOT::Math::XYVector &point) const
Approximate distance.
void setN0(const double n0)
Setter for first circle parameter.
double arcLengthBetween(const ROOT::Math::XYVector &from, const ROOT::Math::XYVector &to) const
Calculates the arc length between two points of closest approach on the circle.
double radius() const
Gives the signed radius of the circle. If it was a line this will be infinity.
static GeneralizedCircle fromCenterAndRadius(const ROOT::Math::XYVector &center, double absRadius, ERotation orientation=ERotation::c_CounterClockwise)
Constructor from center, radius and a optional orientation.
void setCenterAndRadius(const ROOT::Math::XYVector &center, double absRadius, ERotation orientation=ERotation::c_CounterClockwise)
Setter for the circle center and radius.
const ROOT::Math::XYVector & n12() const
Getter for the second and third circle parameter which natuarally from a vector.
void setN2(const double n2)
Setter for third circle parameter.
ROOT::Math::XYVector closest(const ROOT::Math::XYVector &point) const
Closest approach on the circle to the point.
double omega() const
Gives the omega parameter as used by the framework helix.
void setN3(const double n3)
Setter for fourth circle parameter.
void setN1(const double n1)
Setter for second circle parameter.
double m_n0
Memory for the first parameter.
EForwardBackward isForwardOrBackwardOf(const ROOT::Math::XYVector &from, const ROOT::Math::XYVector &to) const
Calculates if the to vector is closer to the from vector following the along orientation of the circl...
double impact() const
Gives the signed distance of the origin to the circle.
std::pair< ROOT::Math::XYVector, ROOT::Math::XYVector > intersections(const GeneralizedCircle &generalizedCircle) const
Calculates the two points common to both circles.
double distance(const ROOT::Math::XYVector &point) const
Gives the proper distance of the point to the circle line retaining the sign of the fast distance.
double arcLengthTo(const ROOT::Math::XYVector &to) const
Calculates the arc length between the perigee and the given point.
double n3() const
Getter for the fourth circle parameter.
ROOT::Math::XYVector perigee() const
Calculates the closest approach to the two dimensional origin.
double n2() const
Getter for the third circle parameter.
ROOT::Math::XYVector chooseNextForwardOf(const ROOT::Math::XYVector &start, const ROOT::Math::XYVector &end1, const ROOT::Math::XYVector &end2) const
Returns the end point which is first reached if one follows the forward direction of the circle start...
ROOT::Math::XYVector atArcLength(double arcLength) const
Calculates the point, which lies at the give perpendicular travel distance (counted from the perigee)
double curvature() const
Gives the signed curvature of the generalized circle.
double d0() const
Getter for the absolute distance to the z axes at the support point.
double absRadius() const
Gives the signed radius of the circle. If it was a line this will be infinity.
void setPerigeeParameters(double curvature, const ROOT::Math::XYVector &tangential, double impact)
Setter for the perigee parameters.
std::pair< ROOT::Math::XYVector, ROOT::Math::XYVector > atCylindricalR(double cylindricalR) const
Calculates the two points with the given cylindrical radius on the generalised circle.
double arcLengthFactor(const double directDistance) const
Helper function the calculate the factor between the length of a secant line and the length on the ar...
ROOT::Math::XYVector atCylindricalRForwardOf(const ROOT::Math::XYVector &startPoint, double cylindricalR) const
Approach on the circle with the given cylindrical radius that lies in the forward direction of a star...
void normalize()
Normalizes the circle parameters.
double tangentialPhi() const
Gives to azimuth angle phi of the direction of flight at the perigee.
ROOT::Math::XYVector center() const
Gives the center of the circle. If it was a line both components will be infinity.
double n0() const
Getter for the first circle parameter.
void setN(const double n0, const double n1, const double n2, const double n3=0.0)
Setter for all four circle parameters.
ERotation orientation() const
Gives the orientation of the circle.
double arcLengthToCylindricalR(double cylindricalR) const
Calculates the two dimensional arc length till the cylindrical radius is reached If the radius can no...
ROOT::Math::XYVector m_n12
Memory for the second and third parameter.
A two dimensional normal line.
Definition Line2D.h:39
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
bool isValid(EForwardBackward eForwardBackward)
Check whether the given enum instance is one of the valid values.
Abstract base class for different kinds of events.