114 #if !defined(ST_NO_NUMERIC_LIMITS)
116 # if !defined(ST_NO_NAMESPACES)
117 using std::numeric_limits;
122 #include "StHelix.hh"
123 #include "PhysicalConstants.h"
127 const double StHelix::NoSolution = 3.e+33;
137 StHelix::~StHelix() { };
146 mH = (h>=0) ? 1 : -1;
165 if (mSingularity && mH == -1) {
171 void StHelix::setCurvature(
double val)
181 #ifndef ST_NO_NUMERIC_LIMITS
182 if (fabs(mCurvature) <= numeric_limits<double>::epsilon())
184 if (fabs(mCurvature) <= static_cast<double>(0))
188 mSingularity =
false;
194 mCosPhase = cos(mPhase);
195 mSinPhase = sin(mPhase);
196 if (fabs(mPhase) > M_PI)
197 mPhase = atan2(mSinPhase, mCosPhase);
200 void StHelix::setDipAngle(
double val)
203 mCosDipAngle = cos(mDipAngle);
204 mSinDipAngle = sin(mDipAngle);
212 return mOrigin.x()-mCosPhase/mCurvature;
220 return mOrigin.y()-mSinPhase/mCurvature;
226 double dx = p.x()-mOrigin.x();
227 double dy = p.y()-mOrigin.y();
230 s = (dy*mCosPhase - dx*mSinPhase)/mCosDipAngle;
233 s = atan2(dy*mCosPhase - dx*mSinPhase,
234 1/mCurvature + dx*mCosPhase+dy*mSinPhase)/
235 (mH*mCurvature*mCosDipAngle);
242 return abs(this->at(
pathLength(p,scanPeriods))-p);
258 double dx = p.x()-mOrigin.x();
259 double dy = p.y()-mOrigin.y();
260 double dz = p.z()-mOrigin.z();
263 s = mCosDipAngle*(mCosPhase*dy-mSinPhase*dx) +
267 #ifndef ST_NO_NAMESPACES
269 using namespace units;
271 const double MaxPrecisionNeeded = micrometer;
272 const int MaxIterations = 100;
278 double t34 = mCurvature*mCosDipAngle*mCosDipAngle;
279 double t41 = mSinDipAngle*mSinDipAngle;
280 double t6, t7, t11, t12, t19;
292 double d, dmin = abs(at(s) - p);
293 for(j=1; j<MaxIterations; j++) {
294 if ((d = abs(at(s+j*ds) - p)) < dmin) {
301 for(j=-1; -j<MaxIterations; j--) {
302 if ((d = abs(at(s+j*ds) - p)) < dmin) {
309 if (jmin) s += jmin*ds;
318 for (
int i=0; i<MaxIterations; i++) {
319 t6 = mPhase+s*mH*mCurvature*mCosDipAngle;
321 t11 = dx-(1/mCurvature)*(t7-mCosPhase);
323 t19 = dy-(1/mCurvature)*(t12-mSinPhase);
324 s -= (t11*t12*mH*mCosDipAngle-t19*t7*mH*mCosDipAngle -
325 (dz-s*mSinDipAngle)*mSinDipAngle)/
326 (t12*t12*mCosDipAngle*mCosDipAngle+t11*t7*t34 +
327 t7*t7*mCosDipAngle*mCosDipAngle +
329 if (fabs(sOld-s) < MaxPrecisionNeeded)
break;
332 #ifndef ST_NO_NAMESPACES
342 #ifndef ST_NO_NUMERIC_LIMITS
343 return numeric_limits<double>::max();
348 return fabs(2*M_PI/(mH*mCurvature*mCosDipAngle));
353 pair<double,double> value;
354 pair<double,double> VALUE(999999999.,999999999.);
362 double t1 = mCosDipAngle*(mOrigin.x()*mSinPhase-mOrigin.y()*mCosPhase);
363 double t12 = mOrigin.y()*mOrigin.y();
364 double t13 = mCosPhase*mCosPhase;
366 double t16 = mOrigin.x()*mOrigin.x();
367 double t20 = -mCosDipAngle*mCosDipAngle*(2.0*mOrigin.x()*mSinPhase*mOrigin.y()*mCosPhase +
368 t12-t12*t13-t15+t13*t16);
369 if (t20<0.)
return VALUE;
371 value.first = (t1-t20)/(mCosDipAngle*mCosDipAngle);
372 value.second = (t1+t20)/(mCosDipAngle*mCosDipAngle);
375 double t1 = mOrigin.y()*mCurvature;
376 double t2 = mSinPhase;
377 double t3 = mCurvature*mCurvature;
378 double t4 = mOrigin.y()*t2;
379 double t5 = mCosPhase;
380 double t6 = mOrigin.x()*t5;
381 double t8 = mOrigin.x()*mOrigin.x();
382 double t11 = mOrigin.y()*mOrigin.y();
384 double t15 = t14*mCurvature;
386 double t19 = t11*t11;
389 double t32 = t14*t14;
391 double t38 = 8.0*t4*t6 - 4.0*t1*t2*t8 - 4.0*t11*mCurvature*t6 +
392 4.0*t15*t6 + t17*t3 + t19*t3 + 2.0*t21*t8 + 4.0*t8*t23 -
393 4.0*t8*mOrigin.x()*mCurvature*t5 - 4.0*t11*t23 -
394 4.0*t11*mOrigin.y()*mCurvature*t2 + 4.0*t11 - 4.0*t14 +
395 t32*t3 + 4.0*t15*t4 - 2.0*t35*t11 - 2.0*t35*t8;
396 double t40 = (-t3*t38);
397 if (t40<0.)
return VALUE;
400 double t43 = mOrigin.x()*mCurvature;
401 double t45 = 2.0*t5 - t35 + t21 + 2.0 - 2.0*t1*t2 -2.0*t43 - 2.0*t43*t5 + t8*t3;
402 double t46 = mH*mCosDipAngle*mCurvature;
404 value.first = (-mPhase + 2.0*atan((-2.0*t1 + 2.0*t2 + t40)/t45))/t46;
405 value.second = -(mPhase + 2.0*atan((2.0*t1 - 2.0*t2 + t40)/t45))/t46;
411 if (! std::isnan(value.first)) {
412 if (fabs(value.first-p) < fabs(value.first)) value.first = value.first-p;
413 else if (fabs(value.first+p) < fabs(value.first)) value.first = value.first+p;
415 if (! std::isnan(value.second)) {
416 if (fabs(value.second-p) < fabs(value.second)) value.second = value.second-p;
417 else if (fabs(value.second+p) < fabs(value.second)) value.second = value.second+p;
420 if (value.first > value.second)
421 swap(value.first,value.second);
427 double x0 = mOrigin.x();
428 double y0 = mOrigin.y();
431 pair<double, double> result = this->
pathLength(r);
451 double t = n.z()*mSinDipAngle +
452 n.y()*mCosDipAngle*mCosPhase -
453 n.x()*mCosDipAngle*mSinPhase;
457 s = ((r - mOrigin)*n)/t;
460 const double MaxPrecisionNeeded = micrometer;
461 const int MaxIterations = 20;
463 double A = mCurvature*((mOrigin - r)*n) -
466 double t = mH*mCurvature*mCosDipAngle;
467 double u = n.z()*mCurvature*mSinDipAngle;
474 const double angMax = 0.21;
475 double deltas = fabs(angMax/(mCurvature*mCosDipAngle));
480 for (i=0; i<MaxIterations; i++) {
482 double sina = sin(a);
483 double cosa = cos(a);
491 if ( fabs(fp)*deltas <= fabs(f) ) {
493 if (fp<0.) sgn = -sgn;
494 if (f <0.) sgn = -sgn;
496 if (shift<0) shift*=0.9;
502 if (fabs(sOld-s) < MaxPrecisionNeeded)
break;
505 if (i == MaxIterations)
return NoSolution;
517 if (mSingularity != h.mSingularity)
518 return pair<double, double>(NoSolution, NoSolution);
528 mCosDipAngle*mCosPhase,
531 h.mCosDipAngle*h.mCosPhase,
536 s2 = (k-ab*g)/(ab*ab-1.);
538 return pair<double, double>(s1, s2);
546 double dd = ::sqrt(dx*dx + dy*dy);
547 double r1 = 1/curvature();
548 double r2 = 1/h.curvature();
550 double cosAlpha = (r1*r1 + dd*dd - r2*r2)/(2*r1*dd);
554 if (fabs(cosAlpha) < 1) {
555 double sinAlpha = sin(acos(cosAlpha));
556 x =
xcenter() + r1*(cosAlpha*dx - sinAlpha*dy)/dd;
557 y =
ycenter() + r1*(sinAlpha*dx + cosAlpha*dy)/dd;
559 x =
xcenter() + r1*(cosAlpha*dx + sinAlpha*dy)/dd;
560 y =
ycenter() + r1*(cosAlpha*dy - sinAlpha*dx)/dd;
565 int rsign = ((r2-r1) > dd ? -1 : 1);
567 x =
xcenter() + rsign*r1*dx/dd;
568 y =
ycenter() + rsign*r1*dy/dd;
578 double range = max(2*dmin, minRange);
579 double ds = range/10;
580 double slast=-999999, ss, d;
584 while (ds > minStepSize) {
585 for (ss=s1; ss<s2+ds; ss+=ds) {
605 else if (s == slast) {
616 return pair<double, double>(s, h.
pathLength(at(s)));
627 double newPhase = atan2(newOrigin.y() -
ycenter(),
640 a.dipAngle() == b.dipAngle() &&
641 a.curvature() == b.curvature() &&
646 int operator!= (
const StHelix& a,
const StHelix& b) {
return !(a == b);}
648 ostream& operator<<(ostream& os,
const StHelix&
h)
651 <<
"curvature = " << h.curvature() <<
", "
652 <<
"dip angle = " << h.dipAngle() <<
", "
653 <<
"phase = " << h.
phase() <<
", "
654 <<
"h = " << h.
h() <<
", "
655 <<
"origin = " << h.
origin() <<
')';
void setParameters(double c, double dip, double phase, const StThreeVector< double > &o, int h)
starting point
int h() const
y-center of circle in xy-plane
pair< double, double > pathLengths(const StHelix &, double minStepSize=10 *micrometer, double minRange=10 *centimeter) const
path lengths at dca between two helices
double x(double s) const
coordinates of helix at point s
double distance(const StThreeVector< double > &p, bool scanPeriods=true) const
minimal distance between point and helix
double fudgePathLength(const StThreeVector< double > &) const
value of S where distance in x-y plane is minimal
pair< double, double > pathLength(double r) const
path length at given r (cylindrical r)
double ycenter() const
x-center of circle in xy-plane
const StThreeVector< double > & origin() const
-sign(q*B);
void setPhase(double)
performs also various checks
StHelix(double c, double dip, double phase, const StThreeVector< double > &o, int h=-1)
curvature, dip angle, phase, origin, h
virtual void moveOrigin(double s)
move the origin along the helix to s which becomes then s=0
double period() const
returns period length of helix
double xcenter() const
aziumth in xy-plane measured from ring center
double phase() const
1/R in xy-plane