Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TEveTrackPropagator.cxx
Go to the documentation of this file.
1 // @(#)root/eve:$Id$
2 // Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 
13 #include "TEveTrackPropagator.h"
14 #include "TEveTrack.h"
15 #include "TEveTrans.h"
16 
17 #include "TMath.h"
18 
19 #include <cassert>
20 
21 /** \class TEveMagField
22 \ingroup TEve
23 Abstract base-class for interfacing to magnetic field needed by the
24 TEveTrackPropagator.
25 See sub-classes for two simple implementations.
26 
27 NOTE: Magnetic field direction convention is inverted.
28 */
29 
30 ClassImp(TEveMagField);
31 
32 /** \class TEveMagFieldConst
33 \ingroup TEve
34 Implements constant magnetic field, given by a vector fB.
35 
36 NOTE: Magnetic field direction convention is inverted.
37 */
38 
39 ClassImp(TEveMagFieldConst);
40 
41 /** \class TEveMagFieldDuo
42 \ingroup TEve
43 Implements constant magnetic filed that switches on given axial radius fR2
44 from vector fBIn to fBOut.
45 
46 NOTE: Magnetic field direction convention is inverted.
47 */
48 
49 ClassImp(TEveMagFieldDuo);
50 
51 namespace
52 {
53  //const Double_t kBMin = 1e-6;
54  const Double_t kPtMinSqr = 1e-20;
55  const Double_t kAMin = 1e-10;
56  const Double_t kStepEps = 1e-3;
57 }
58 
59 ////////////////////////////////////////////////////////////////////////////////
60 /// Default constructor.
61 
62 TEveTrackPropagator::Helix_t::Helix_t() :
63  fCharge(0),
64  fMaxAng(45), fMaxStep(20.f), fDelta(0.1),
65  fPhi(0), fValid(kFALSE),
66  fLam(-1), fR(-1), fPhiStep(-1), fSin(-1), fCos(-1),
67  fRKStep(20.0),
68  fPtMag(-1), fPlMag(-1), fLStep(-1)
69 {
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 /// Common update code for helix and RK propagation.
74 
75 void TEveTrackPropagator::Helix_t::UpdateCommon(const TEveVectorD& p, const TEveVectorD& b)
76 {
77  fB = b;
78 
79  // base vectors
80  fE1 = b;
81  fE1.Normalize();
82  fPlMag = p.Dot(fE1);
83  fPl = fE1*fPlMag;
84 
85  fPt = p - fPl;
86  fPtMag = fPt.Mag();
87  fE2 = fPt;
88  fE2.Normalize();
89 }
90 
91 ////////////////////////////////////////////////////////////////////////////////
92 /// Update helix parameters.
93 
94 void TEveTrackPropagator::Helix_t::UpdateHelix(const TEveVectorD& p, const TEveVectorD& b,
95  Bool_t full_update, Bool_t enforce_max_step)
96 {
97  UpdateCommon(p, b);
98 
99  // helix parameters
100  TMath::Cross(fE1.Arr(), fE2.Arr(), fE3.Arr());
101  if (fCharge < 0) fE3.NegateXYZ();
102 
103  if (full_update)
104  {
105  using namespace TMath;
106  Double_t a = fgkB2C * b.Mag() * Abs(fCharge);
107  if (a > kAMin && fPtMag*fPtMag > kPtMinSqr)
108  {
109  fValid = kTRUE;
110 
111  fR = Abs(fPtMag / a);
112  fLam = fPlMag / fPtMag;
113 
114  // get phi step, compare fMaxAng with fDelta
115  fPhiStep = fMaxAng * DegToRad();
116  if (fR > fDelta)
117  {
118  Double_t ang = 2.0 * ACos(1.0f - fDelta/fR);
119  if (ang < fPhiStep)
120  fPhiStep = ang;
121  }
122 
123  // check max step size
124  Double_t curr_step = fR * fPhiStep * Sqrt(1.0f + fLam*fLam);
125  if (curr_step > fMaxStep || enforce_max_step)
126  fPhiStep *= fMaxStep / curr_step;
127 
128  fLStep = fR * fPhiStep * fLam;
129  fSin = Sin(fPhiStep);
130  fCos = Cos(fPhiStep);
131  }
132  else
133  {
134  fValid = kFALSE;
135  }
136  }
137 }
138 
139 ////////////////////////////////////////////////////////////////////////////////
140 /// Update helix for stepper RungeKutta.
141 
142 void TEveTrackPropagator::Helix_t::UpdateRK(const TEveVectorD& p, const TEveVectorD& b)
143 {
144  UpdateCommon(p, b);
145 
146  if (fCharge)
147  {
148  fValid = kTRUE;
149 
150  // cached values for propagator
151  fB = b;
152  fPlMag = p.Dot(fB);
153  }
154  else
155  {
156  fValid = kFALSE;
157  }
158 }
159 
160 ////////////////////////////////////////////////////////////////////////////////
161 /// Step helix for given momentum p from vertex v.
162 
163 void TEveTrackPropagator::Helix_t::Step(const TEveVector4D& v, const TEveVectorD& p,
164  TEveVector4D& vOut, TEveVectorD& pOut)
165 {
166  vOut = v;
167 
168  if (fValid)
169  {
170  TEveVectorD d = fE2*(fR*fSin) + fE3*(fR*(1-fCos)) + fE1*fLStep;
171  vOut += d;
172  vOut.fT += TMath::Abs(fLStep);
173 
174  pOut = fPl + fE2*(fPtMag*fCos) + fE3*(fPtMag*fSin);
175 
176  fPhi += fPhiStep;
177  }
178  else
179  {
180  // case: pT < kPtMinSqr or B < kBMin
181  // might happen if field directon changes pT ~ 0 or B becomes zero
182  vOut += p * (fMaxStep / p.Mag());
183  vOut.fT += fMaxStep;
184  pOut = p;
185  }
186 }
187 
188 /** \class TEveTrackPropagator
189 \ingroup TEve
190 Holding structure for a number of track rendering parameters.
191 Calculates path taking into account the parameters.
192 
193 NOTE: Magnetic field direction convention is inverted.
194 
195 This is decoupled from TEveTrack/TEveTrackList to allow sharing of the
196 Propagator among several instances. Back references are kept so the tracks
197 can be recreated when the parameters change.
198 
199 TEveTrackList has Get/Set methods for RnrStlye. TEveTrackEditor and
200 TEveTrackListEditor provide editor access.
201 
202 Enum EProjTrackBreaking_e and member fProjTrackBreaking specify whether 2D
203 projected tracks get broken into several segments when the projected space
204 consists of separate domains (like Rho-Z). The track-breaking is enabled by
205 default.
206 */
207 
208 ClassImp(TEveTrackPropagator);
209 
210 Double_t TEveTrackPropagator::fgDefMagField = 0.5;
211 const Double_t TEveTrackPropagator::fgkB2C = 0.299792458e-2;
212 TEveTrackPropagator TEveTrackPropagator::fgDefault;
213 
214 Double_t TEveTrackPropagator::fgEditorMaxR = 2000;
215 Double_t TEveTrackPropagator::fgEditorMaxZ = 4000;
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 /// Default constructor.
219 
220 TEveTrackPropagator::TEveTrackPropagator(const char* n, const char* t,
221  TEveMagField *field, Bool_t own_field) :
222  TEveElementList(n, t),
223  TEveRefBackPtr(),
224 
225  fStepper(kHelix),
226  fMagFieldObj(field),
227  fOwnMagFiledObj(own_field),
228 
229  fMaxR (350), fMaxZ (450),
230  fNMax (4096), fMaxOrbs (0.5),
231 
232  fEditPathMarks (kTRUE),
233  fFitDaughters (kTRUE), fFitReferences (kTRUE),
234  fFitDecay (kTRUE),
235  fFitCluster2Ds (kTRUE), fFitLineSegments (kTRUE),
236  fRnrDaughters (kFALSE), fRnrReferences (kFALSE),
237  fRnrDecay (kFALSE), fRnrCluster2Ds (kFALSE),
238  fRnrFV (kFALSE),
239  fPMAtt(), fFVAtt(),
240 
241  fProjTrackBreaking(kPTB_Break), fRnrPTBMarkers(kFALSE), fPTBAtt(),
242 
243  fV()
244 {
245  fPMAtt.SetMarkerColor(kYellow);
246  fPMAtt.SetMarkerStyle(2);
247  fPMAtt.SetMarkerSize(2);
248 
249  fFVAtt.SetMarkerColor(kRed);
250  fFVAtt.SetMarkerStyle(4);
251  fFVAtt.SetMarkerSize(1.5);
252 
253  fPTBAtt.SetMarkerColor(kBlue);
254  fPTBAtt.SetMarkerStyle(4);
255  fPTBAtt.SetMarkerSize(0.8);
256 
257  if (fMagFieldObj == 0) {
258  fMagFieldObj = new TEveMagFieldConst(0., 0., fgDefMagField);
259  fOwnMagFiledObj = kTRUE;
260  }
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Destructor.
265 
266 TEveTrackPropagator::~TEveTrackPropagator()
267 {
268  if (fOwnMagFiledObj)
269  {
270  delete fMagFieldObj;
271  }
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Virtual from TEveRefBackPtr - track reference count has reached zero.
276 
277 void TEveTrackPropagator::OnZeroRefCount()
278 {
279  CheckReferenceCount("TEveTrackPropagator::OnZeroRefCount ");
280 }
281 
282 ////////////////////////////////////////////////////////////////////////////////
283 /// Check reference count - virtual from TEveElement.
284 /// Must also take into account references from TEveRefBackPtr.
285 
286 void TEveTrackPropagator::CheckReferenceCount(const TEveException& eh)
287 {
288  if (fRefCount <= 0)
289  {
290  TEveElementList::CheckReferenceCount(eh);
291  }
292 }
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Element-change notification.
296 /// Stamp all tracks as requiring display-list regeneration.
297 /// Virtual from TEveElement.
298 
299 void TEveTrackPropagator::ElementChanged(Bool_t update_scenes, Bool_t redraw)
300 {
301  TEveTrack* track;
302  RefMap_i i = fBackRefs.begin();
303  while (i != fBackRefs.end())
304  {
305  track = dynamic_cast<TEveTrack*>(i->first);
306  track->StampObjProps();
307  ++i;
308  }
309  TEveElementList::ElementChanged(update_scenes, redraw);
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////
313 /// Initialize internal data-members for given particle parameters.
314 
315 void TEveTrackPropagator::InitTrack(const TEveVectorD &v, Int_t charge)
316 {
317  fV = v;
318  fPoints.push_back(fV);
319 
320  // init helix
321  fH.fPhi = 0;
322  fH.fCharge = charge;
323 }
324 
325 ////////////////////////////////////////////////////////////////////////////////
326 /// TEveVectorF wrapper.
327 
328 void TEveTrackPropagator::InitTrack(const TEveVectorF& v, Int_t charge)
329 {
330  TEveVectorD vd(v);
331  InitTrack(vd, charge);
332 }
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Reset cache holding particle trajectory.
336 
337 void TEveTrackPropagator::ResetTrack()
338 {
339  fLastPoints.clear();
340  fPoints.swap(fLastPoints);
341 
342  // reset helix
343  fH.fPhi = 0;
344 }
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// Get index of current point on track.
348 
349 Int_t TEveTrackPropagator::GetCurrentPoint() const
350 {
351  return fPoints.size() - 1;
352 }
353 
354 ////////////////////////////////////////////////////////////////////////////////
355 /// Calculate track length from start_point to end_point.
356 /// If end_point is less than 0, distance to the end is returned.
357 
358 Double_t TEveTrackPropagator::GetTrackLength(Int_t start_point, Int_t end_point) const
359 {
360  if (end_point < 0) end_point = fPoints.size() - 1;
361 
362  Double_t sum = 0;
363  for (Int_t i = start_point; i < end_point; ++i)
364  {
365  sum += (fPoints[i+1] - fPoints[i]).Mag();
366  }
367  return sum;
368 }
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// Propagate particle with momentum p to vertex v.
372 
373 Bool_t TEveTrackPropagator::GoToVertex(TEveVectorD& v, TEveVectorD& p)
374 {
375  Update(fV, p, kTRUE);
376 
377  if ((v-fV).Mag() < kStepEps)
378  {
379  fPoints.push_back(v);
380  return kTRUE;
381  }
382 
383  return fH.fValid ? LoopToVertex(v, p) : LineToVertex(v);
384 }
385 
386 ////////////////////////////////////////////////////////////////////////////////
387 /// Propagate particle with momentum p to line with start point s and vector r
388 /// to the second point.
389 
390 Bool_t TEveTrackPropagator::GoToLineSegment(const TEveVectorD& s, const TEveVectorD& r, TEveVectorD& p)
391 {
392  Update(fV, p, kTRUE);
393 
394  if (!fH.fValid)
395  {
396  TEveVectorD v;
397  ClosestPointBetweenLines(s, r, fV, p, v);
398  LineToVertex(v);
399  return kTRUE;
400  }
401  else
402  {
403  return LoopToLineSegment(s, r, p);
404  }
405 }
406 
407 ////////////////////////////////////////////////////////////////////////////////
408 /// TEveVectorF wrapper.
409 
410 Bool_t TEveTrackPropagator::GoToVertex(TEveVectorF& v, TEveVectorF& p)
411 {
412  TEveVectorD vd(v), pd(p);
413  Bool_t result = GoToVertex(vd, pd);
414  v = vd; p = pd;
415  return result;
416 }
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 /// TEveVectorF wrapper.
420 
421 Bool_t TEveTrackPropagator::GoToLineSegment(const TEveVectorF& s, const TEveVectorF& r, TEveVectorF& p)
422 {
423  TEveVectorD sd(s), rd(r), pd(p);
424  Bool_t result = GoToLineSegment(sd, rd, pd);
425  p = pd;
426  return result;
427 }
428 
429 ////////////////////////////////////////////////////////////////////////////////
430 /// Propagate particle to bounds.
431 /// Return TRUE if hit bounds.
432 
433 void TEveTrackPropagator::GoToBounds(TEveVectorD& p)
434 {
435  Update(fV, p, kTRUE);
436 
437  fH.fValid ? LoopToBounds(p): LineToBounds(p);
438 }
439 
440 ////////////////////////////////////////////////////////////////////////////////
441 /// TEveVectorF wrapper.
442 
443 void TEveTrackPropagator::GoToBounds(TEveVectorF& p)
444 {
445  TEveVectorD pd(p);
446  GoToBounds(pd);
447  p = pd;
448 }
449 
450 ////////////////////////////////////////////////////////////////////////////////
451 /// Update helix / B-field projection state.
452 
453 void TEveTrackPropagator::Update(const TEveVector4D& v, const TEveVectorD& p,
454  Bool_t full_update, Bool_t enforce_max_step)
455 {
456  if (fStepper == kHelix)
457  {
458  fH.UpdateHelix(p, fMagFieldObj->GetFieldD(v), !fMagFieldObj->IsConst() || full_update, enforce_max_step);
459  }
460  else
461  {
462  fH.UpdateRK(p, fMagFieldObj->GetFieldD(v));
463 
464  if (full_update)
465  {
466  using namespace TMath;
467 
468  Float_t a = fgkB2C * fMagFieldObj->GetMaxFieldMagD() * Abs(fH.fCharge);
469  if (a > kAMin)
470  {
471  fH.fR = p.Mag() / a;
472 
473  // get phi step, compare fDelta with MaxAng
474  fH.fPhiStep = fH.fMaxAng * DegToRad();
475  if (fH.fR > fH.fDelta )
476  {
477  Double_t ang = 2.0 * ACos(1.0f - fH.fDelta/fH.fR);
478  if (ang < fH.fPhiStep)
479  fH.fPhiStep = ang;
480  }
481 
482  // check against maximum step-size
483  fH.fRKStep = fH.fR * fH.fPhiStep * Sqrt(1 + fH.fLam*fH.fLam);
484  if (fH.fRKStep > fH.fMaxStep || enforce_max_step)
485  {
486  fH.fPhiStep *= fH.fMaxStep / fH.fRKStep;
487  fH.fRKStep = fH.fMaxStep;
488  }
489  }
490  else
491  {
492  fH.fRKStep = fH.fMaxStep;
493  }
494  }
495  }
496 }
497 
498 ////////////////////////////////////////////////////////////////////////////////
499 /// Wrapper to step helix.
500 
501 void TEveTrackPropagator::Step(const TEveVector4D &v, const TEveVectorD &p, TEveVector4D &vOut, TEveVectorD &pOut)
502 {
503  if (fStepper == kHelix)
504  {
505  fH.Step(v, p, vOut, pOut);
506  }
507  else
508  {
509  Double_t vecRKIn[7];
510  vecRKIn[0] = v.fX;
511  vecRKIn[1] = v.fY;
512  vecRKIn[2] = v.fZ;
513  Double_t pm = p.Mag();
514  Double_t nm = 1.0 / pm;
515  vecRKIn[3] = p.fX*nm;
516  vecRKIn[4] = p.fY*nm;
517  vecRKIn[5] = p.fZ*nm;
518  vecRKIn[6] = p.Mag();
519 
520  Double_t vecRKOut[7];
521  StepRungeKutta(fH.fRKStep, vecRKIn, vecRKOut);
522 
523  vOut.fX = vecRKOut[0];
524  vOut.fY = vecRKOut[1];
525  vOut.fZ = vecRKOut[2];
526  vOut.fT = v.fT + fH.fRKStep;
527  pm = vecRKOut[6];
528  pOut.fX = vecRKOut[3]*pm;
529  pOut.fY = vecRKOut[4]*pm;
530  pOut.fZ = vecRKOut[5]*pm;
531  }
532 }
533 
534 ////////////////////////////////////////////////////////////////////////////////
535 /// Propagate charged particle with momentum p to bounds.
536 /// It is expected that Update() with full-update was called before.
537 
538 void TEveTrackPropagator::LoopToBounds(TEveVectorD& p)
539 {
540  const Double_t maxRsq = fMaxR*fMaxR;
541 
542  TEveVector4D currV(fV);
543  TEveVector4D forwV(fV);
544  TEveVectorD forwP (p);
545 
546  Int_t np = fPoints.size();
547  Double_t maxPhi = fMaxOrbs*TMath::TwoPi();
548 
549  while (fH.fPhi < maxPhi && np<fNMax)
550  {
551  Step(currV, p, forwV, forwP);
552 
553  // cross R
554  if (forwV.Perp2() > maxRsq)
555  {
556  Float_t t = (fMaxR - currV.R()) / (forwV.R() - currV.R());
557  if (t < 0 || t > 1)
558  {
559  Warning("HelixToBounds", "In MaxR crossing expected t>=0 && t<=1: t=%f, r1=%f, r2=%f, MaxR=%f.",
560  t, currV.R(), forwV.R(), fMaxR);
561  return;
562  }
563  TEveVectorD d(forwV);
564  d -= currV;
565  d *= t;
566  d += currV;
567  fPoints.push_back(d);
568  return;
569  }
570 
571  // cross Z
572  else if (TMath::Abs(forwV.fZ) > fMaxZ)
573  {
574  Double_t t = (fMaxZ - TMath::Abs(currV.fZ)) / TMath::Abs((forwV.fZ - currV.fZ));
575  if (t < 0 || t > 1)
576  {
577  Warning("HelixToBounds", "In MaxZ crossing expected t>=0 && t<=1: t=%f, z1=%f, z2=%f, MaxZ=%f.",
578  t, currV.fZ, forwV.fZ, fMaxZ);
579  return;
580  }
581  TEveVectorD d(forwV -currV);
582  d *= t;
583  d += currV;
584  fPoints.push_back(d);
585  return;
586  }
587 
588  currV = forwV;
589  p = forwP;
590  Update(currV, p);
591 
592  fPoints.push_back(currV);
593  ++np;
594  }
595 }
596 
597 ////////////////////////////////////////////////////////////////////////////////
598 /// Propagate charged particle with momentum p to vertex v.
599 /// It is expected that Update() with full-update was called before.
600 
601 Bool_t TEveTrackPropagator::LoopToVertex(TEveVectorD& v, TEveVectorD& p)
602 {
603  const Double_t maxRsq = fMaxR * fMaxR;
604 
605  TEveVector4D currV(fV);
606  TEveVector4D forwV(fV);
607  TEveVectorD forwP(p);
608 
609  Int_t first_point = fPoints.size();
610  Int_t np = first_point;
611 
612  Double_t prod0=0, prod1;
613 
614  do
615  {
616  Step(currV, p, forwV, forwP);
617  Update(forwV, forwP);
618 
619  if (PointOverVertex(v, forwV, &prod1))
620  {
621  break;
622  }
623 
624  if (IsOutsideBounds(forwV, maxRsq, fMaxZ))
625  {
626  fV = currV;
627  return kFALSE;
628  }
629 
630  fPoints.push_back(forwV);
631  currV = forwV;
632  p = forwP;
633  prod0 = prod1;
634  ++np;
635  } while (np < fNMax);
636 
637  // make the remaining fractional step
638  if (np > first_point)
639  {
640  if ((v - currV).Mag() > kStepEps)
641  {
642  Double_t step_frac = prod0 / (prod0 - prod1);
643  if (step_frac > 0)
644  {
645  // Step for fraction of previous step size.
646  // We pass 'enforce_max_step' flag to Update().
647  Float_t orig_max_step = fH.fMaxStep;
648  fH.fMaxStep = step_frac * (forwV - currV).Mag();
649  Update(currV, p, kTRUE, kTRUE);
650  Step(currV, p, forwV, forwP);
651  p = forwP;
652  currV = forwV;
653  fPoints.push_back(currV);
654  ++np;
655  fH.fMaxStep = orig_max_step;
656  }
657 
658  // Distribute offset to desired crossing point over all segment.
659 
660  TEveVectorD off(v - currV);
661  off *= 1.0f / currV.fT;
662  DistributeOffset(off, first_point, np, p);
663  fV = v;
664  return kTRUE;
665  }
666  }
667 
668  fPoints.push_back(v);
669  fV = v;
670  return kTRUE;
671 }
672 
673 ////////////////////////////////////////////////////////////////////////////////
674 /// Propagate charged particle with momentum p to line segment with point s and
675 /// vector r to the second point. It is expected that Update() with full-update
676 /// was called before. Returns kFALSE if hits bounds.
677 
678 Bool_t TEveTrackPropagator::LoopToLineSegment(const TEveVectorD& s, const TEveVectorD& r, TEveVectorD& p)
679 {
680  const Double_t maxRsq = fMaxR * fMaxR;
681  const Double_t rMagInv = 1./r.Mag();
682 
683  TEveVector4D currV(fV);
684  TEveVector4D forwV(fV);
685  TEveVectorD forwP(p);
686 
687  Int_t first_point = fPoints.size();
688  Int_t np = first_point;
689 
690  TEveVectorD forwC;
691  TEveVectorD currC;
692  do
693  {
694  Step(currV, p, forwV, forwP);
695  Update(forwV, forwP);
696 
697  ClosestPointFromVertexToLineSegment(forwV, s, r, rMagInv, forwC);
698 
699  // check forwV is over segment with orthogonal component of
700  // momentum to vector r
701  TEveVectorD b = r; b.Normalize();
702  Double_t x = forwP.Dot(b);
703  TEveVectorD pTPM = forwP - x*b;
704  if (pTPM.Dot(forwC - forwV) < 0)
705  {
706  break;
707  }
708 
709  if (IsOutsideBounds(forwV, maxRsq, fMaxZ))
710  {
711  fV = currV;
712  return kFALSE;
713  }
714 
715  fPoints.push_back(forwV);
716  currV = forwV;
717  p = forwP;
718  currC = forwC;
719  ++np;
720  } while (np < fNMax);
721 
722  // Get closest point on segment relative to line with forw and currV points.
723  TEveVectorD v;
724  ClosestPointBetweenLines(s, r, currV, forwV - currV, v);
725 
726  // make the remaining fractional step
727  if (np > first_point)
728  {
729  if ((v - currV).Mag() > kStepEps)
730  {
731  TEveVector last_step = forwV - currV;
732  TEveVector delta = v - currV;
733  Double_t step_frac = last_step.Dot(delta) / last_step.Mag2();
734  if (step_frac > 0)
735  {
736  // Step for fraction of previous step size.
737  // We pass 'enforce_max_step' flag to Update().
738  Float_t orig_max_step = fH.fMaxStep;
739  fH.fMaxStep = step_frac * (forwV - currV).Mag();
740  Update(currV, p, kTRUE, kTRUE);
741  Step(currV, p, forwV, forwP);
742  p = forwP;
743  currV = forwV;
744  fPoints.push_back(currV);
745  ++np;
746  fH.fMaxStep = orig_max_step;
747  }
748 
749  // Distribute offset to desired crossing point over all segment.
750 
751  TEveVectorD off(v - currV);
752  off *= 1.0f / currV.fT;
753  DistributeOffset(off, first_point, np, p);
754  fV = v;
755  return kTRUE;
756  }
757  }
758 
759  fPoints.push_back(v);
760  fV = v;
761  return kTRUE;
762 }
763 
764 ////////////////////////////////////////////////////////////////////////////////
765 /// Distribute offset between first and last point index and rotate
766 /// momentum.
767 
768 void TEveTrackPropagator::DistributeOffset(const TEveVectorD& off, Int_t first_point, Int_t np, TEveVectorD& p)
769 {
770  // Calculate the required momentum rotation.
771  // lpd - last-points-delta
772  TEveVectorD lpd0(fPoints[np-1]);
773  lpd0 -= fPoints[np-2];
774  lpd0.Normalize();
775 
776  for (Int_t i = first_point; i < np; ++i)
777  {
778  fPoints[i] += off * fPoints[i].fT;
779  }
780 
781  TEveVectorD lpd1(fPoints[np-1]);
782  lpd1 -= fPoints[np-2];
783  lpd1.Normalize();
784 
785  TEveTrans tt;
786  tt.SetupFromToVec(lpd0, lpd1);
787 
788  // TEveVectorD pb4(p);
789  // printf("Rotating momentum: p0 = "); p.Dump();
790  tt.RotateIP(p);
791  // printf(" p1 = "); p.Dump();
792  // printf(" n1=%f, n2=%f, dp = %f deg\n", pb4.Mag(), p.Mag(),
793  // TMath::RadToDeg()*TMath::ACos(p.Dot(pb4)/(pb4.Mag()*p.Mag())));
794 }
795 
796 ////////////////////////////////////////////////////////////////////////////////
797 /// Propagate neutral particle to vertex v.
798 
799 Bool_t TEveTrackPropagator::LineToVertex(TEveVectorD& v)
800 {
801  TEveVector4D currV = v;
802 
803  currV.fX = v.fX;
804  currV.fY = v.fY;
805  currV.fZ = v.fZ;
806  fPoints.push_back(currV);
807 
808  fV = v;
809  return kTRUE;
810 }
811 
812 ////////////////////////////////////////////////////////////////////////////////
813 /// Propagate neutral particle with momentum p to bounds.
814 
815 void TEveTrackPropagator::LineToBounds(TEveVectorD& p)
816 {
817  Double_t tZ = 0, tR = 0, tB = 0;
818 
819  // time where particle intersect +/- fMaxZ
820  if (p.fZ > 0)
821  tZ = (fMaxZ - fV.fZ) / p.fZ;
822  else if (p.fZ < 0)
823  tZ = - (fMaxZ + fV.fZ) / p.fZ;
824  else
825  tZ = 1e99;
826 
827  // time where particle intersects cylinder
828  Double_t a = p.fX*p.fX + p.fY*p.fY;
829  Double_t b = 2.0 * (fV.fX*p.fX + fV.fY*p.fY);
830  Double_t c = fV.fX*fV.fX + fV.fY*fV.fY - fMaxR*fMaxR;
831  Double_t d = b*b - 4.0*a*c;
832  if (d >= 0) {
833  Double_t sqrtD = TMath::Sqrt(d);
834  tR = (-b - sqrtD) / (2.0 * a);
835  if (tR < 0) {
836  tR = (-b + sqrtD) / (2.0 * a);
837  }
838  tB = tR < tZ ? tR : tZ; // compare the two times
839  } else {
840  tB = tZ;
841  }
842  TEveVectorD nv(fV.fX + p.fX*tB, fV.fY + p.fY*tB, fV.fZ + p.fZ*tB);
843  LineToVertex(nv);
844 }
845 
846 ////////////////////////////////////////////////////////////////////////////////
847 /// Intersect helix with a plane. Current position and argument p define
848 /// the helix.
849 
850 Bool_t TEveTrackPropagator::HelixIntersectPlane(const TEveVectorD& p,
851  const TEveVectorD& point,
852  const TEveVectorD& normal,
853  TEveVectorD& itsect)
854 {
855  TEveVectorD pos(fV);
856  TEveVectorD mom(p);
857  if (fMagFieldObj->IsConst())
858  fH.UpdateHelix(mom, fMagFieldObj->GetFieldD(pos), kFALSE, kFALSE);
859 
860  TEveVectorD n(normal);
861  TEveVectorD delta = pos - point;
862  Double_t d = delta.Dot(n);
863  if (d > 0) {
864  n.NegateXYZ(); // Turn normal around so that we approach from negative side of the plane
865  d = -d;
866  }
867 
868  TEveVector4D forwV;
869  TEveVectorD forwP;
870  TEveVector4D pos4(pos);
871  while (kTRUE)
872  {
873  Update(pos4, mom);
874  Step(pos4, mom, forwV , forwP);
875  Double_t new_d = (forwV - point).Dot(n);
876  if (new_d < d)
877  {
878  // We are going further away ... fail intersect.
879  Warning("HelixIntersectPlane", "going away from the plane.");
880  return kFALSE;
881  }
882  if (new_d > 0)
883  {
884  delta = forwV - pos;
885  itsect = pos + delta * (d / (d - new_d));
886  return kTRUE;
887  }
888  pos4 = forwV;
889  mom = forwP;
890  }
891 }
892 
893 ////////////////////////////////////////////////////////////////////////////////
894 /// Intersect line with a plane. Current position and argument p define
895 /// the line.
896 
897 Bool_t TEveTrackPropagator::LineIntersectPlane(const TEveVectorD& p,
898  const TEveVectorD& point,
899  const TEveVectorD& normal,
900  TEveVectorD& itsect)
901 {
902  TEveVectorD pos(fV.fX, fV.fY, fV.fZ);
903  TEveVectorD delta = point - pos;
904 
905  Double_t pn = p.Dot(normal);
906  if (pn == 0)
907  {
908  return kFALSE;
909  }
910  Double_t t = delta.Dot(normal) / pn;
911  if (t < 0) {
912  return kFALSE;
913  } else {
914  itsect = pos + p*t;
915  return kTRUE;
916  }
917 }
918 
919 ////////////////////////////////////////////////////////////////////////////////
920 /// Find intersection of currently propagated track with a plane.
921 /// Current track position is used as starting point.
922 ///
923 /// Args:
924 /// - p - track momentum to use for extrapolation
925 /// - point - a point on a plane
926 /// - normal - normal of the plane
927 /// - itsect - output, point of intersection
928 /// Returns:
929 /// - kFALSE if intersection can not be found, kTRUE otherwise.
930 
931 Bool_t TEveTrackPropagator::IntersectPlane(const TEveVectorD& p,
932  const TEveVectorD& point,
933  const TEveVectorD& normal,
934  TEveVectorD& itsect)
935 {
936  if (fH.fCharge && fMagFieldObj && p.Perp2() > kPtMinSqr)
937  return HelixIntersectPlane(p, point, normal, itsect);
938  else
939  return LineIntersectPlane(p, point, normal, itsect);
940 }
941 
942 ////////////////////////////////////////////////////////////////////////////////
943 /// Get closest point from given vertex v to line segment defined with s and r.
944 /// Argument rMagInv is cached. rMagInv= 1./rMag()
945 
946 void TEveTrackPropagator::ClosestPointFromVertexToLineSegment(const TEveVectorD& v,
947  const TEveVectorD& s,
948  const TEveVectorD& r,
949  Double_t rMagInv,
950  TEveVectorD& c)
951 {
952  TEveVectorD dir = v - s;
953  TEveVectorD b1 = r * rMagInv;
954 
955  // parallel distance
956  Double_t dot = dir.Dot(b1);
957  TEveVectorD dirI = dot * b1;
958 
959  Double_t facX = dot * rMagInv;
960 
961  if (facX <= 0)
962  c = s;
963  else if (facX >= 1)
964  c = s + r;
965  else
966  c = s + dirI;
967 }
968 
969 ////////////////////////////////////////////////////////////////////////////////
970 /// Get closest point on line defined with vector p0 and u.
971 /// Return false if the point is forced on the line segment.
972 
973 Bool_t TEveTrackPropagator::ClosestPointBetweenLines(const TEveVectorD& p0,
974  const TEveVectorD& u,
975  const TEveVectorD& q0,
976  const TEveVectorD& v,
977  TEveVectorD& out)
978 {
979  TEveVectorD w0 = p0 -q0;
980  Double_t a = u.Mag2();
981  Double_t b = u.Dot(v);
982  Double_t c = v.Mag2();
983  Double_t d = u.Dot(w0);
984  Double_t e = v.Dot(w0);
985 
986  Double_t x = (b*e - c*d)/(a*c -b*b);
987  Bool_t force = (x < 0 || x > 1);
988  out = p0 + TMath::Range(0., 1., x) * u;
989  return force;
990 }
991 
992 ////////////////////////////////////////////////////////////////////////////////
993 /// Reset ps and populate it with points in propagation cache.
994 
995 void TEveTrackPropagator::FillPointSet(TEvePointSet* ps) const
996 {
997  Int_t size = TMath::Min(fNMax, (Int_t)fPoints.size());
998  ps->Reset(size);
999  for (Int_t i = 0; i < size; ++i)
1000  {
1001  const TEveVector4D& v = fPoints[i];
1002  ps->SetNextPoint(v.fX, v.fY, v.fZ);
1003  }
1004 }
1005 
1006 ////////////////////////////////////////////////////////////////////////////////
1007 /// Rebuild all tracks using this render-style.
1008 
1009 void TEveTrackPropagator::RebuildTracks()
1010 {
1011  TEveTrack* track;
1012  RefMap_i i = fBackRefs.begin();
1013  while (i != fBackRefs.end())
1014  {
1015  track = dynamic_cast<TEveTrack*>(i->first);
1016  track->MakeTrack();
1017  track->StampObjProps();
1018  ++i;
1019  }
1020 }
1021 
1022 ////////////////////////////////////////////////////////////////////////////////
1023 /// Set constant magnetic field and rebuild tracks.
1024 
1025 void TEveTrackPropagator::SetMagField(Double_t bX, Double_t bY, Double_t bZ)
1026 {
1027  SetMagFieldObj(new TEveMagFieldConst(bX, bY, bZ));
1028 }
1029 
1030 ////////////////////////////////////////////////////////////////////////////////
1031 /// Set constant magnetic field and rebuild tracks.
1032 
1033 void TEveTrackPropagator::SetMagFieldObj(TEveMagField* field, Bool_t own_field)
1034 {
1035  if (fMagFieldObj && fOwnMagFiledObj) delete fMagFieldObj;
1036 
1037  fMagFieldObj = field;
1038  fOwnMagFiledObj = own_field;
1039 
1040  RebuildTracks();
1041 }
1042 
1043 ////////////////////////////////////////////////////////////////////////////////
1044 
1045 void TEveTrackPropagator::PrintMagField(Double_t x, Double_t y, Double_t z) const
1046 {
1047  if (fMagFieldObj) fMagFieldObj->PrintField(x, y, z);
1048 }
1049 
1050 ////////////////////////////////////////////////////////////////////////////////
1051 /// Set maximum radius and rebuild tracks.
1052 
1053 void TEveTrackPropagator::SetMaxR(Double_t x)
1054 {
1055  fMaxR = x;
1056  RebuildTracks();
1057 }
1058 
1059 ////////////////////////////////////////////////////////////////////////////////
1060 /// Set maximum z and rebuild tracks.
1061 
1062 void TEveTrackPropagator::SetMaxZ(Double_t x)
1063 {
1064  fMaxZ = x;
1065  RebuildTracks();
1066 }
1067 
1068 ////////////////////////////////////////////////////////////////////////////////
1069 /// Set maximum number of orbits and rebuild tracks.
1070 
1071 void TEveTrackPropagator::SetMaxOrbs(Double_t x)
1072 {
1073  fMaxOrbs = x;
1074  RebuildTracks();
1075 }
1076 
1077 ////////////////////////////////////////////////////////////////////////////////
1078 /// Set maximum step angle and rebuild tracks.
1079 /// WARNING -- this method / variable was mis-named.
1080 
1081 void TEveTrackPropagator::SetMinAng(Double_t x)
1082 {
1083  Warning("SetMinAng", "This method was mis-named, use SetMaxAng() instead!");
1084  SetMaxAng(x);
1085 }
1086 ////////////////////////////////////////////////////////////////////////////////
1087 /// Get maximum step angle.
1088 /// WARNING -- this method / variable was mis-named.
1089 
1090 Double_t TEveTrackPropagator::GetMinAng() const
1091 {
1092  Warning("GetMinAng", "This method was mis-named, use GetMaxAng() instead!");
1093  return GetMaxAng();
1094 }
1095 
1096 ////////////////////////////////////////////////////////////////////////////////
1097 /// Set maximum step angle and rebuild tracks.
1098 
1099 void TEveTrackPropagator::SetMaxAng(Double_t x)
1100 {
1101  fH.fMaxAng = x;
1102  RebuildTracks();
1103 }
1104 
1105 ////////////////////////////////////////////////////////////////////////////////
1106 /// Set maximum step-size and rebuild tracks.
1107 
1108 void TEveTrackPropagator::SetMaxStep(Double_t x)
1109 {
1110  fH.fMaxStep = x;
1111  RebuildTracks();
1112 }
1113 
1114 ////////////////////////////////////////////////////////////////////////////////
1115 /// Set maximum error and rebuild tracks.
1116 
1117 void TEveTrackPropagator::SetDelta(Double_t x)
1118 {
1119  fH.fDelta = x;
1120  RebuildTracks();
1121 }
1122 
1123 ////////////////////////////////////////////////////////////////////////////////
1124 /// Set daughter creation point fitting and rebuild tracks.
1125 
1126 void TEveTrackPropagator::SetFitDaughters(Bool_t x)
1127 {
1128  fFitDaughters = x;
1129  RebuildTracks();
1130 }
1131 
1132 ////////////////////////////////////////////////////////////////////////////////
1133 /// Set track-reference fitting and rebuild tracks.
1134 
1135 void TEveTrackPropagator::SetFitReferences(Bool_t x)
1136 {
1137  fFitReferences = x;
1138  RebuildTracks();
1139 }
1140 
1141 ////////////////////////////////////////////////////////////////////////////////
1142 /// Set decay fitting and rebuild tracks.
1143 
1144 void TEveTrackPropagator::SetFitDecay(Bool_t x)
1145 {
1146  fFitDecay = x;
1147  RebuildTracks();
1148 }
1149 
1150 ////////////////////////////////////////////////////////////////////////////////
1151 /// Set line segment fitting and rebuild tracks.
1152 
1153 void TEveTrackPropagator::SetFitLineSegments(Bool_t x)
1154 {
1155  fFitLineSegments = x;
1156  RebuildTracks();
1157 }
1158 
1159 ////////////////////////////////////////////////////////////////////////////////
1160 /// Set 2D-cluster fitting and rebuild tracks.
1161 
1162 void TEveTrackPropagator::SetFitCluster2Ds(Bool_t x)
1163 {
1164  fFitCluster2Ds = x;
1165  RebuildTracks();
1166 }
1167 
1168 ////////////////////////////////////////////////////////////////////////////////
1169 /// Set decay rendering and rebuild tracks.
1170 
1171 void TEveTrackPropagator::SetRnrDecay(Bool_t rnr)
1172 {
1173  fRnrDecay = rnr;
1174  RebuildTracks();
1175 }
1176 
1177 ////////////////////////////////////////////////////////////////////////////////
1178 /// Set rendering of 2D-clusters and rebuild tracks.
1179 
1180 void TEveTrackPropagator::SetRnrCluster2Ds(Bool_t rnr)
1181 {
1182  fRnrCluster2Ds = rnr;
1183  RebuildTracks();
1184 }
1185 
1186 ////////////////////////////////////////////////////////////////////////////////
1187 /// Set daughter rendering and rebuild tracks.
1188 
1189 void TEveTrackPropagator::SetRnrDaughters(Bool_t rnr)
1190 {
1191  fRnrDaughters = rnr;
1192  RebuildTracks();
1193 }
1194 
1195 ////////////////////////////////////////////////////////////////////////////////
1196 /// Set track-reference rendering and rebuild tracks.
1197 
1198 void TEveTrackPropagator::SetRnrReferences(Bool_t rnr)
1199 {
1200  fRnrReferences = rnr;
1201  RebuildTracks();
1202 }
1203 
1204 ////////////////////////////////////////////////////////////////////////////////
1205 /// Set first-vertex rendering and rebuild tracks.
1206 
1207 void TEveTrackPropagator::SetRnrFV(Bool_t x)
1208 {
1209  fRnrFV = x;
1210  RebuildTracks();
1211 }
1212 
1213 ////////////////////////////////////////////////////////////////////////////////
1214 /// Set projection break-point mode and rebuild tracks.
1215 
1216 void TEveTrackPropagator::SetProjTrackBreaking(UChar_t x)
1217 {
1218  fProjTrackBreaking = x;
1219  RebuildTracks();
1220 }
1221 
1222 ////////////////////////////////////////////////////////////////////////////////
1223 /// Set projection break-point rendering and rebuild tracks.
1224 
1225 void TEveTrackPropagator::SetRnrPTBMarkers(Bool_t x)
1226 {
1227  fRnrPTBMarkers = x;
1228  RebuildTracks();
1229 }
1230 
1231 ////////////////////////////////////////////////////////////////////////////////
1232 /// Wrapper to step with method RungeKutta.
1233 
1234 void TEveTrackPropagator::StepRungeKutta(Double_t step,
1235  Double_t* vect, Double_t* vout)
1236 {
1237  /// ******************************************************************
1238  /// * *
1239  /// * Runge-Kutta method for tracking a particle through a magnetic *
1240  /// * field. Uses Nystroem algorithm (See Handbook Nat. Bur. of *
1241  /// * Standards, procedure 25.5.20) *
1242  /// * *
1243  /// * Input parameters *
1244  /// * CHARGE Particle charge *
1245  /// * STEP Step size *
1246  /// * VECT Initial co-ords,direction cosines,momentum *
1247  /// * Output parameters *
1248  /// * VOUT Output co-ords,direction cosines,momentum *
1249  /// * User routine called *
1250  /// * CALL GUFLD(X,F) *
1251  /// * *
1252  /// * ==>Called by : <USER>, GUSWIM *
1253  /// * Authors R.Brun, M.Hansroul ********* *
1254  /// * V.Perevoztchikov (CUT STEP implementation) *
1255  /// * *
1256  /// * *
1257  /// ******************************************************************
1258 
1259  Double_t h2, h4, f[4];
1260  Double_t /* xyzt[3], */ a, b, c, ph,ph2;
1261  Double_t secxs[4],secys[4],seczs[4],hxp[3];
1262  Double_t g1, g2, g3, g4, g5, g6, ang2, dxt, dyt, dzt;
1263  Double_t est, at, bt, ct, cba;
1264  Double_t f1, f2, f3, f4, rho, tet, hnorm, hp, rho1, sint, cost;
1265 
1266  Double_t x;
1267  Double_t y;
1268  Double_t z;
1269 
1270  Double_t xt;
1271  Double_t yt;
1272  Double_t zt;
1273 
1274  // const Int_t maxit = 1992;
1275  const Int_t maxit = 500;
1276  const Int_t maxcut = 11;
1277 
1278  const Double_t hmin = 1e-4; // !!! MT ADD, should be member
1279  const Double_t kdlt = 1e-3; // !!! MT CHANGE from 1e-4, should be member
1280  const Double_t kdlt32 = kdlt/32.;
1281  const Double_t kthird = 1./3.;
1282  const Double_t khalf = 0.5;
1283  const Double_t kec = 2.9979251e-3;
1284 
1285  const Double_t kpisqua = 9.86960440109;
1286  const Int_t kix = 0;
1287  const Int_t kiy = 1;
1288  const Int_t kiz = 2;
1289  const Int_t kipx = 3;
1290  const Int_t kipy = 4;
1291  const Int_t kipz = 5;
1292 
1293  // *.
1294  // *. ------------------------------------------------------------------
1295  // *.
1296  // * this constant is for units cm,gev/c and kgauss
1297  // *
1298  Int_t iter = 0;
1299  Int_t ncut = 0;
1300  for(Int_t j = 0; j < 7; j++)
1301  vout[j] = vect[j];
1302 
1303  Double_t pinv = kec * fH.fCharge / vect[6];
1304  Double_t tl = 0.;
1305  Double_t h = step;
1306  Double_t rest;
1307 
1308  do {
1309  rest = step - tl;
1310  if (TMath::Abs(h) > TMath::Abs(rest))
1311  h = rest;
1312 
1313  f[0] = -fH.fB.fX;
1314  f[1] = -fH.fB.fY;
1315  f[2] = -fH.fB.fZ;
1316 
1317  // * start of integration
1318  x = vout[0];
1319  y = vout[1];
1320  z = vout[2];
1321  a = vout[3];
1322  b = vout[4];
1323  c = vout[5];
1324 
1325  h2 = khalf * h;
1326  h4 = khalf * h2;
1327  ph = pinv * h;
1328  ph2 = khalf * ph;
1329  secxs[0] = (b * f[2] - c * f[1]) * ph2;
1330  secys[0] = (c * f[0] - a * f[2]) * ph2;
1331  seczs[0] = (a * f[1] - b * f[0]) * ph2;
1332  ang2 = (secxs[0]*secxs[0] + secys[0]*secys[0] + seczs[0]*seczs[0]);
1333  if (ang2 > kpisqua) break;
1334 
1335  dxt = h2 * a + h4 * secxs[0];
1336  dyt = h2 * b + h4 * secys[0];
1337  dzt = h2 * c + h4 * seczs[0];
1338  xt = x + dxt;
1339  yt = y + dyt;
1340  zt = z + dzt;
1341 
1342  // * second intermediate point
1343  est = TMath::Abs(dxt) + TMath::Abs(dyt) + TMath::Abs(dzt);
1344  if (est > h) {
1345  if (ncut++ > maxcut) break;
1346  h *= khalf;
1347  continue;
1348  }
1349 
1350  // xyzt[0] = xt;
1351  // xyzt[1] = yt;
1352  // xyzt[2] = zt;
1353 
1354  fH.fB = fMagFieldObj->GetFieldD(xt, yt, zt);
1355  f[0] = -fH.fB.fX;
1356  f[1] = -fH.fB.fY;
1357  f[2] = -fH.fB.fZ;
1358 
1359  at = a + secxs[0];
1360  bt = b + secys[0];
1361  ct = c + seczs[0];
1362 
1363  secxs[1] = (bt * f[2] - ct * f[1]) * ph2;
1364  secys[1] = (ct * f[0] - at * f[2]) * ph2;
1365  seczs[1] = (at * f[1] - bt * f[0]) * ph2;
1366  at = a + secxs[1];
1367  bt = b + secys[1];
1368  ct = c + seczs[1];
1369  secxs[2] = (bt * f[2] - ct * f[1]) * ph2;
1370  secys[2] = (ct * f[0] - at * f[2]) * ph2;
1371  seczs[2] = (at * f[1] - bt * f[0]) * ph2;
1372  dxt = h * (a + secxs[2]);
1373  dyt = h * (b + secys[2]);
1374  dzt = h * (c + seczs[2]);
1375  xt = x + dxt;
1376  yt = y + dyt;
1377  zt = z + dzt;
1378  at = a + 2.*secxs[2];
1379  bt = b + 2.*secys[2];
1380  ct = c + 2.*seczs[2];
1381 
1382  est = TMath::Abs(dxt)+TMath::Abs(dyt)+TMath::Abs(dzt);
1383  if (est > 2.*TMath::Abs(h)) {
1384  if (ncut++ > maxcut) break;
1385  h *= khalf;
1386  continue;
1387  }
1388 
1389  // xyzt[0] = xt;
1390  // xyzt[1] = yt;
1391  // xyzt[2] = zt;
1392 
1393  fH.fB = fMagFieldObj->GetFieldD(xt, yt, zt);
1394  f[0] = -fH.fB.fX;
1395  f[1] = -fH.fB.fY;
1396  f[2] = -fH.fB.fZ;
1397 
1398  z = z + (c + (seczs[0] + seczs[1] + seczs[2]) * kthird) * h;
1399  y = y + (b + (secys[0] + secys[1] + secys[2]) * kthird) * h;
1400  x = x + (a + (secxs[0] + secxs[1] + secxs[2]) * kthird) * h;
1401 
1402  secxs[3] = (bt*f[2] - ct*f[1])* ph2;
1403  secys[3] = (ct*f[0] - at*f[2])* ph2;
1404  seczs[3] = (at*f[1] - bt*f[0])* ph2;
1405  a = a+(secxs[0]+secxs[3]+2. * (secxs[1]+secxs[2])) * kthird;
1406  b = b+(secys[0]+secys[3]+2. * (secys[1]+secys[2])) * kthird;
1407  c = c+(seczs[0]+seczs[3]+2. * (seczs[1]+seczs[2])) * kthird;
1408 
1409  est = TMath::Abs(secxs[0]+secxs[3] - (secxs[1]+secxs[2]))
1410  + TMath::Abs(secys[0]+secys[3] - (secys[1]+secys[2]))
1411  + TMath::Abs(seczs[0]+seczs[3] - (seczs[1]+seczs[2]));
1412 
1413  if (est > kdlt && TMath::Abs(h) > hmin) {
1414  if (ncut++ > maxcut) break;
1415  h *= khalf;
1416  continue;
1417  }
1418 
1419  ncut = 0;
1420  // * if too many iterations, go to helix
1421  if (iter++ > maxit) break;
1422 
1423  tl += h;
1424  if (est < kdlt32)
1425  h *= 2.;
1426  cba = 1./ TMath::Sqrt(a*a + b*b + c*c);
1427  vout[0] = x;
1428  vout[1] = y;
1429  vout[2] = z;
1430  vout[3] = cba*a;
1431  vout[4] = cba*b;
1432  vout[5] = cba*c;
1433  rest = step - tl;
1434  if (step < 0.) rest = -rest;
1435  if (rest < 1.e-5*TMath::Abs(step))
1436  {
1437  Float_t dot = (vout[3]*vect[3] + vout[4]*vect[4] + vout[5]*vect[5]);
1438  fH.fPhi += TMath::ACos(dot);
1439  return;
1440  }
1441 
1442  } while(1);
1443 
1444  // angle too big, use helix
1445 
1446  f1 = f[0];
1447  f2 = f[1];
1448  f3 = f[2];
1449  f4 = TMath::Sqrt(f1*f1+f2*f2+f3*f3);
1450  rho = -f4*pinv;
1451  tet = rho * step;
1452 
1453  hnorm = 1./f4;
1454  f1 = f1*hnorm;
1455  f2 = f2*hnorm;
1456  f3 = f3*hnorm;
1457 
1458  hxp[0] = f2*vect[kipz] - f3*vect[kipy];
1459  hxp[1] = f3*vect[kipx] - f1*vect[kipz];
1460  hxp[2] = f1*vect[kipy] - f2*vect[kipx];
1461 
1462  hp = f1*vect[kipx] + f2*vect[kipy] + f3*vect[kipz];
1463 
1464  rho1 = 1./rho;
1465  sint = TMath::Sin(tet);
1466  cost = 2.*TMath::Sin(khalf*tet)*TMath::Sin(khalf*tet);
1467 
1468  g1 = sint*rho1;
1469  g2 = cost*rho1;
1470  g3 = (tet-sint) * hp*rho1;
1471  g4 = -cost;
1472  g5 = sint;
1473  g6 = cost * hp;
1474 
1475  vout[kix] = vect[kix] + g1*vect[kipx] + g2*hxp[0] + g3*f1;
1476  vout[kiy] = vect[kiy] + g1*vect[kipy] + g2*hxp[1] + g3*f2;
1477  vout[kiz] = vect[kiz] + g1*vect[kipz] + g2*hxp[2] + g3*f3;
1478 
1479  vout[kipx] = vect[kipx] + g4*vect[kipx] + g5*hxp[0] + g6*f1;
1480  vout[kipy] = vect[kipy] + g4*vect[kipy] + g5*hxp[1] + g6*f2;
1481  vout[kipz] = vect[kipz] + g4*vect[kipz] + g5*hxp[2] + g6*f3;
1482 
1483  fH.fPhi += tet;
1484 }