1
2
3
4
5
6
7
8 package org.lcsim.fit.helicaltrack;
9
10 import hep.physics.matrix.BasicMatrix;
11 import hep.physics.matrix.Matrix;
12 import hep.physics.matrix.SymmetricMatrix;
13 import hep.physics.vec.BasicHep3Vector;
14 import hep.physics.vec.Hep3Vector;
15 import java.util.ArrayList;
16 import java.util.List;
17 import org.lcsim.fit.circle.CircleFit;
18
19
20
21
22
23
24
25
26
27
28
29
30
31 public class HelixUtils {
32 private static double _minslope = 1.e-6;
33 private static double _maxpath = 2400;
34 private static double _epsilon = 0.01;
35 private static double _tol = 1.e-4;
36
37
38
39
40 public HelixUtils() {
41 }
42
43
44
45
46
47
48
49
50 public static double PathLength(CircleFit cfit, HelicalTrackHit hit1, HelicalTrackHit hit2) {
51
52 Hep3Vector pos1 = getPositionOnCircle(cfit, hit1);
53 Hep3Vector pos2 = getPositionOnCircle(cfit, hit2);
54
55 return PathCalc(xc(cfit), yc(cfit), RC(cfit), pos1.x(), pos1.y(), pos2.x(), pos2.y());
56 }
57
58
59
60
61
62
63
64 public static double PathLength(CircleFit cfit, HelicalTrackHit hit) {
65
66 Hep3Vector pos = getPositionOnCircle(cfit, hit);
67
68 return PathCalc(xc(cfit), yc(cfit), RC(cfit), x0(cfit), y0(cfit), pos.x(), pos.y());
69 }
70
71
72
73
74
75
76
77 public static double PathLength(HelicalTrackFit helix, HelicalTrackHit hit) {
78
79
80 double path0 = PathCalc(helix.xc(), helix.yc(), helix.R(), helix.x0(), helix.y0(), hit.x(), hit.y());
81 if (hit instanceof HelicalTrack2DHit) return path0;
82
83
84 HelicalTrackHit close = null;
85 double zhit = hit.z();
86 for (HelicalTrackHit fithit : helix.PathMap().keySet()) {
87 if (!(fithit instanceof HelicalTrack2DHit)) {
88
89 if (close == null) {
90
91 close = fithit;
92 } else {
93
94 if (Math.abs(zhit - fithit.z()) < Math.abs(zhit - close.z())) close = fithit;
95 }
96 }
97 }
98
99
100 if (close == null) return path0;
101
102
103 double path = helix.PathMap().get(close) +
104 PathCalc(helix.xc(), helix.yc(), helix.R(), close.x(), close.y(), hit.x(), hit.y());
105 return path;
106 }
107
108
109
110
111
112
113
114 public static double PathToZPlane(HelicalTrackFit helix, double z) {
115
116 double zdist = z - helix.z0();
117 double safeslope = helix.slope();
118 if (Math.abs(safeslope) < _minslope) safeslope = _minslope * Math.signum(safeslope);
119 return zdist / safeslope;
120 }
121
122
123
124
125
126
127
128 public static List<Double> PathToXPlane(HelicalTrackFit helix, double x,double smax, int mxint) {
129
130 List<Double> pathlist = new ArrayList<Double>();
131
132 double x0 = helix.x0();
133 double y0 = helix.y0();
134
135 double xc=helix.xc();
136 double yc=helix.yc();
137 double RC = helix.R();
138 double y=yc+Math.signum(RC)*Math.sqrt(RC*RC-Math.pow(x-xc,2));
139
140 double s=PathCalc(xc,yc,RC,x0,y0,x,y);
141
142
143
144
145
146
147
148
149
150
151
152
153
154 pathlist.add(s);
155
156 return pathlist;
157 }
158
159
160
161
162
163
164
165
166
167
168 public static List<Double> PathToCylinder(HelicalTrackFit helix, double r, double smax, int mxint) {
169
170 List<Double> pathlist = new ArrayList<Double>();
171
172 double dca = helix.dca();
173 double RC = helix.R();
174
175 double cdphi = 1 - (r * r - dca * dca) / (2. * RC * (RC - dca));
176
177 if (Math.abs(cdphi) < 1.) {
178
179 double dphi = Math.acos(cdphi);
180 Double s = dphi * Math.abs(RC);
181
182 while (s < smax && pathlist.size() < mxint) {
183
184 pathlist.add(s);
185
186 s += 2. * (Math.PI - dphi) * Math.abs(RC);
187
188 if (s < smax && pathlist.size() < mxint) pathlist.add(s);
189
190 s += 2. * dphi * Math.abs(RC);
191 }
192 }
193 return pathlist;
194 }
195
196
197
198
199
200
201
202
203 public static Hep3Vector Direction(HelicalTrackFit helix, double s) {
204
205 double phi = helix.phi0() - s / helix.R();
206 double sth = helix.sth();
207
208 double ux = Math.cos(phi) * helix.sth();
209 double uy = Math.sin(phi) * helix.sth();
210 double uz = helix.cth();
211
212 return new BasicHep3Vector(ux, uy, uz);
213 }
214
215
216
217
218
219
220
221
222
223
224 public static TrackDirection CalculateTrackDirection(HelicalTrackFit helix, double s) {
225 Hep3Vector dir = Direction(helix, s);
226 Matrix deriv = DirectionDerivates(helix, dir, s);
227 return new TrackDirection(dir, deriv);
228 }
229
230
231
232
233
234
235
236 public static Hep3Vector PointOnHelix(HelicalTrackFit helix, double s) {
237
238 double RC = helix.R();
239 double phi = helix.phi0() - s / RC;
240
241 double x = helix.xc() - RC * Math.sin(phi);
242 double y = helix.yc() + RC * Math.cos(phi);
243 double z = helix.z0() + s * helix.slope();
244
245 return new BasicHep3Vector(x, y, z);
246 }
247
248 private static Hep3Vector getPositionOnCircle(CircleFit cfit, HelicalTrackHit hit) {
249
250
251 Hep3Vector pos = hit.getCorrectedPosition();
252 SymmetricMatrix cov = hit.getCorrectedCovMatrix();
253 double dxdx = cov.diagonal(0);
254 double dydy = cov.diagonal(1);
255 if ((dxdx < _tol * dydy) && (dydy < _tol * dxdx)) return pos;
256
257
258 double x0 = xc(cfit);
259 double y0 = yc(cfit);
260 double R = Math.abs(RC(cfit));
261
262
263 double x = pos.x();
264 double y = pos.y();
265
266
267 if (_tol * dxdx > dydy && Math.abs(y-y0) < R) {
268 double xnew1 = Math.sqrt(R*R - (y-y0)*(y-y0)) + x0;
269 double xnew2 = -xnew1 + 2. * x0;
270 if (Math.abs(xnew1 - x) < Math.abs(xnew2 - x)) {
271 x = xnew1;
272 } else {
273 x = xnew2;
274 }
275 }
276 if (_tol * dydy > dxdx && Math.abs(x-x0) < R) {
277 double ynew1 = Math.sqrt(R*R - (x-x0)*(x-x0)) + y0;
278 double ynew2 = -ynew1 + 2. * y0;
279 if (Math.abs(ynew1 - y) < Math.abs(ynew2 - y)) {
280 y = ynew1;
281 } else {
282 y = ynew2;
283 }
284 }
285
286 return new BasicHep3Vector(x, y, pos.z());
287 }
288
289 private static double PathCalc(double xc, double yc, double RC, double x1, double y1, double x2, double y2) {
290
291 double phi1 = Math.atan2(y1 - yc, x1 - xc);
292 double phi2 = Math.atan2(y2 - yc, x2 - xc);
293 double dphi = phi2 - phi1;
294
295 if (dphi > Math.PI) dphi -= 2. * Math.PI;
296 if (dphi < -Math.PI) dphi += 2. * Math.PI;
297
298 return -RC * dphi;
299 }
300
301
302
303
304
305
306
307
308
309
310 private static Matrix DirectionDerivates(HelicalTrackFit helix, Hep3Vector u, double s) {
311
312 BasicMatrix deriv = new BasicMatrix(3,5);
313
314 double cphi0 = Math.cos(helix.phi0());
315 double sphi0 = Math.sin(helix.phi0());
316 double sth = helix.sth();
317 double cth = helix.cth();
318 double dca = helix.dca();
319 double omega = helix.curvature();
320
321 deriv.setElement(0, HelicalTrackFit.curvatureIndex, (u.x() - cphi0 * sth) / omega);
322 deriv.setElement(1, HelicalTrackFit.curvatureIndex, (u.y() - sphi0 * sth) / omega);
323 deriv.setElement(0, HelicalTrackFit.dcaIndex, -omega * cphi0 * sth);
324 deriv.setElement(1, HelicalTrackFit.dcaIndex, -omega * sphi0 * sth);
325 deriv.setElement(0, HelicalTrackFit.phi0Index, -(1 - dca * omega) * sphi0 * sth);
326 deriv.setElement(1, HelicalTrackFit.phi0Index, (1 - dca * omega) * cphi0 * sth);
327 deriv.setElement(0, HelicalTrackFit.slopeIndex, -u.x() * sth * cth);
328 deriv.setElement(1, HelicalTrackFit.slopeIndex, -u.y() * sth * cth);
329 deriv.setElement(2, HelicalTrackFit.slopeIndex, sth*sth*sth);
330
331 return deriv;
332 }
333
334
335
336
337
338
339
340
341
342
343
344 public static boolean isInterceptingBoundedCylinder(HelicalTrackFit helix,double r,double zmin,double zmax){
345 double minpath = PathToZPlane(helix, zmin);
346 double maxpath = PathToZPlane(helix, zmax);
347 double path = Math.max(minpath, maxpath);
348 List<Double> pathlist = PathToCylinder(helix,r,path,10);
349 for(double s:pathlist){
350 double z = PointOnHelix(helix,s).z();
351 if(z<zmax && z> zmin)
352 return true;
353 }
354 return false;
355 }
356
357
358
359
360
361
362
363
364 public static boolean isInterceptingZDisk(HelicalTrackFit helix,double rmin,double rmax, double z ){
365 double s = PathToZPlane(helix,z);
366 Hep3Vector point = PointOnHelix(helix,s);
367 double x = point.x();
368 double y = point.y();
369 double r = Math.sqrt(x*x+y*y);
370 if(r < rmax && r > rmin ){return true;}
371 return false;
372 }
373
374
375
376
377
378
379
380
381
382
383
384
385 public static boolean isInterceptingZpolygon(HelicalTrackFit helix,double z,List<Hep3Vector> vertices){
386
387 double epsilon = Math.PI/360.;
388 double s = PathToZPlane(helix,z);
389 if(s<0){return false;}
390 if(s>_maxpath){return false;}
391 Hep3Vector point = PointOnHelix(helix,s);
392 double angle = insidePolygon(point,vertices);
393 if(Math.abs(angle-2*Math.PI)<epsilon)
394 return true;
395 return false;
396 }
397
398
399
400
401
402
403
404
405
406
407
408
409 public static boolean isInterceptingXYPlane(HelicalTrackFit helix, Hep3Vector normal,Hep3Vector orig){
410 if(normal.z()>_epsilon)
411 throw new UnsupportedOperationException("Not a XY plan !"+normal);
412 double x = -helix.x0()+orig.x();
413 double y = -helix.y0()+orig.y();
414 double z = -helix.z0()+orig.z();
415 double xn= normal.x();
416 double yn= normal.y();
417 double zn= normal.z();
418 double Phip = Math.atan2(yn, xn);
419 double dist = (xn*x+yn*y+zn*z);
420 double verif = Math.sin(Phip-helix.phi0())+helix.curvature()*dist;
421 if(normal.magnitude() < 0.99)
422 throw new UnsupportedOperationException("normal vector not unitary :"+normal.magnitude());
423 if(Math.abs(verif)>1)
424 return false;
425 else
426 return true ;
427 }
428
429
430
431
432
433
434
435
436
437 public static boolean isInterceptingBoundedXYPlane(HelicalTrackFit helix,Hep3Vector normal,List<Hep3Vector> nodes){
438 Hep3Vector orig = nodes.get(0);
439 if(!isInterceptingXYPlane(helix,normal,orig)){return false;}
440 double s = PathToXYPlan(helix, normal, orig);
441 if(s<0) {return false;}
442 if(s>_maxpath){return false;}
443 Hep3Vector point = PointOnHelix(helix, s);
444 if(Math.abs(insidePolygon(point, nodes)-2*Math.PI)<_epsilon)
445 return true;
446 return false;
447 }
448
449
450
451
452
453
454
455
456
457
458
459 public static double PathToXYPlan(HelicalTrackFit helix,Hep3Vector normal,Hep3Vector origin){
460 if(normal.z()>_epsilon)
461 throw new UnsupportedOperationException("Not a XY plan ! normal vector is "+normal);
462 double x = -helix.x0()+origin.x();
463 double y = -helix.y0()+origin.y();
464 double z = -helix.z0()+origin.z();
465 double xn= normal.x();
466 double yn= normal.y();
467 double zn= normal.z();
468 double phip = Math.atan2(yn, xn);
469 double dist = (xn*x+yn*y+zn*z);
470 double sinPlan = Math.sin(phip-helix.phi0())+helix.curvature()*dist;
471 double Cs = (Math.asin(sinPlan)-phip+helix.phi0());
472 double s=dist/(Math.sqrt(xn*xn+yn*yn)*(2./Cs)*Math.sin(Cs/2.)*Math.cos(Cs/2+phip-helix.phi0())+zn*helix.slope());
473 return s;
474 }
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494 private static double insidePolygon(Hep3Vector q,List<Hep3Vector> p)
495 {
496 int i;
497 double epsilon = _epsilon;
498 double m1,m2;
499 double anglesum=0,costheta;
500 double x1,x2,y1,y2,z1,z2,m1m2;
501
502 Hep3Vector p1;
503 Hep3Vector p2;
504 int n = p.size();
505 for (i=0;i<n;i++) {
506 p1 = p.get(i);
507 p2 = p.get((i+1)%n);
508 x1 = (p1.x()-q.x());
509 y1 = (p1.y()-q.y());
510 z1 = (p1.z()-q.z());
511 x2 = (p2.x()-q.x());
512 y2 = (p2.y()-q.y());
513 z2 = (p2.z()-q.z());
514 m1m2 = Math.sqrt(x1*x1+y1*y1+z1*z1)*Math.sqrt(x2*x2+y2*y2+z2*z2);
515
516
517 if (m1m2 <= epsilon){
518 return 2*Math.PI;
519 }
520 else{
521 costheta = (x1*x2 + y1*y2 + z1*z2)/(m1m2);
522 anglesum += Math.acos(costheta);
523 }
524 }
525 return anglesum;
526 }
527
528
529 private static double RC(CircleFit cfit) {
530 return 1.0 / cfit.curvature();
531 }
532
533 private static double xc(CircleFit cfit) {
534
535 return cfit.xref() + (RC(cfit) - (-1*cfit.dca())) * Math.sin(cfit.phi());
536
537 }
538
539 private static double yc(CircleFit cfit) {
540
541 return cfit.yref() - (RC(cfit) - (-1*cfit.dca())) * Math.cos(cfit.phi());
542
543 }
544
545 private static double x0(CircleFit cfit) {
546
547 return cfit.xref() - (-1*cfit.dca()) * Math.sin(cfit.phi());
548 }
549
550 private static double y0(CircleFit cfit) {
551
552 return cfit.yref() + (-1*cfit.dca()) * Math.cos(cfit.phi());
553 }
554
555 }