1 package org.lcsim.util.swim;
2
3 import static java.lang.Math.abs;
4 import static java.lang.Math.asin;
5 import static java.lang.Math.atan2;
6 import static java.lang.Math.cos;
7 import static java.lang.Math.signum;
8 import static java.lang.Math.sin;
9 import static java.lang.Math.sqrt;
10 import hep.physics.vec.BasicHep3Vector;
11 import hep.physics.vec.Hep3Vector;
12 import hep.physics.vec.VecOp;
13
14 import org.lcsim.spacegeom.CartesianPoint;
15 import org.lcsim.spacegeom.CartesianVector;
16 import org.lcsim.spacegeom.SpacePoint;
17 import org.lcsim.spacegeom.SpaceVector;
18
19
20
21
22
23
24
25
26
27
28
29
30 public class Helix implements Trajectory {
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public Helix(Hep3Vector org, double r, double p, double lambda) {
50
51
52
53 origin = org;
54 radius = r;
55 phi = p;
56
57
58 cosPhi = cos(phi);
59 sinPhi = sin(phi);
60 cosLambda = cos(lambda);
61 sinLambda = sin(lambda);
62 xCenter = origin.x() + radius * sinPhi;
63 yCenter = origin.y() - radius * cosPhi;
64 setSpatialParameters();
65 }
66
67
68
69
70
71
72 public SpacePoint getPointAtDistance(double alpha) {
73 double darg = alpha * cosLambda / radius - phi;
74 double x = xCenter + radius * sin(darg);
75 double y = yCenter + radius * cos(darg);
76 double z = origin.z() + alpha * sinLambda;
77 return new CartesianPoint(x, y, z);
78 }
79
80 public double getRadius() {
81 return radius;
82 }
83
84 public Hep3Vector getCenterXY() {
85 return new BasicHep3Vector(xCenter, yCenter, 0);
86 }
87
88 public double getDistanceToZPlane(double z) {
89 return (z - origin.z()) / sinLambda;
90 }
91
92
93
94
95
96
97
98
99
100
101 public double getDistanceToInfiniteCylinder(double r) {
102 double phiToCenter = atan2(yCenter, xCenter);
103 double radiusOfCenter = sqrt(xCenter * xCenter + yCenter * yCenter);
104
105 if (r < 0)
106 throw new IllegalArgumentException("radius " + r + "<0");
107 double darg = r * r / (2. * radius * radiusOfCenter) - radiusOfCenter
108 / (2. * radius) - radius / (2. * radiusOfCenter);
109 double deltaphi = phi - phiToCenter;
110 if (deltaphi < -Math.PI)
111 deltaphi += 2. * Math.PI;
112 if (deltaphi > Math.PI)
113 deltaphi -= 2. * Math.PI;
114 double diff = asin(darg) + deltaphi;
115 double result = (radius / cosLambda) * diff;
116 while (result < 0)
117 result += Math.abs(radius / cosLambda) * 2 * Math.PI;
118 return result;
119 }
120 public double getDistanceToPolyhedra(double r, int nsides)
121 {
122 double mins = 9999999.;
123 double period = Math.abs(2.*Math.PI*radius/cosLambda);
124 for(int i=0;i<nsides;i++)
125 {
126 double dphi = i*2.*Math.PI/nsides;
127 double beta = (r - Math.cos(dphi)*xCenter - Math.sin(dphi)*yCenter)/radius;
128 if(Math.abs(beta) <= 1.)
129 {
130 double s1 = radius/cosLambda*(Math.asin(beta) - dphi + phi);
131 double s2 = radius/cosLambda*(Math.PI - Math.asin(beta) - dphi + phi);
132 while(s1 < 0.){s1 += period;}
133 while(s2 < 0.){s2 += period;}
134 s1 = s1%period;
135 s2 = s2%period;
136 double s = Math.min(s1,s2);
137 if(s1 < mins)mins = s1;
138 }
139 }
140 if(mins == 9999999.)return Double.NaN;
141 return mins;
142 }
143
144 public double getDistanceToPoint(Hep3Vector point) {
145
146
147 Hep3Vector pos = new BasicHep3Vector(origin.v());
148 Hep3Vector u = VecOp.unit(new BasicHep3Vector(px, py, pz));
149 Hep3Vector zhat = new BasicHep3Vector(0., 0., 1.);
150
151
152 double s = 0.;
153 if(Math.abs(sinLambda) > .00001)s = getDistanceToZPlane(point.z());
154 double stot = s;
155
156
157 Hep3Vector unew = propagateDirection(u, s);
158 Hep3Vector posnew = propagatePosition(pos, u, s);
159 u = unew;
160 pos = posnew;
161
162
163 Hep3Vector delta = VecOp.sub(pos, point);
164
165 int count = 0;
166 int maxcount = 20;
167
168 while (delta.magnitude() > eps) {
169 count++;
170
171 double c = VecOp.dot(u, delta);
172 double b = 1. - rho * VecOp.dot(VecOp.cross(u, zhat), delta);
173 double a = -0.5 * rho*rho * (c - delta.z()*u.z());
174
175
176 double arg = b*b - 4 * a * c;
177 double s1 = (-b + Math.sqrt(arg)) / (2. * a);
178 double s2 = (-b - Math.sqrt(arg)) / (2. * a);
179
180
181 Hep3Vector pos1 = propagatePosition(pos, u, s1);
182 double d1 = VecOp.sub(pos1, point).magnitude();
183 Hep3Vector pos2 = propagatePosition(pos, u, s2);
184 double d2 = VecOp.sub(pos2, point).magnitude();
185
186
187
188 if (d1 < d2) {
189 unew = propagateDirection(u, s1);
190 u = unew;
191 pos = pos1;
192 stot += s1;
193 if (Math.abs(s1) < eps) return stot;
194 } else {
195 unew = propagateDirection(u, s2);
196 u = unew;
197 pos = pos2;
198 stot += s2;
199 if (Math.abs(s2) < eps) return stot;
200 }
201
202 if(count > maxcount)return stot;
203
204 delta = VecOp.sub(pos, point);
205 }
206
207
208 return stot;
209 }
210
211
212
213
214
215
216
217
218
219
220 public double getDistanceToXYPosition(Hep3Vector point) {
221 double tanLambda = sinLambda / cosLambda;
222 double pMag = sqrt(px * px + py * py + pz * pz);
223 Hep3Vector p0 = new BasicHep3Vector(px, py, pz);
224 Hep3Vector pCrossB = new BasicHep3Vector(py, -px, 0);
225
226
227 Hep3Vector xDiff = VecOp.sub(origin, point);
228 int addedQuarterPeriods = 0;
229 if (abs(tanLambda) > 1e-10) {
230 double zPos = xDiff.z();
231 while (abs(zPos) > abs(radius * tanLambda * Math.PI)) {
232 zPos -= signum(zPos) * abs(radius * tanLambda * Math.PI);
233 ++addedQuarterPeriods;
234 }
235
236 if (zPos > 0 && addedQuarterPeriods > 0)
237 addedQuarterPeriods *= -1;
238 if (addedQuarterPeriods % 2 != 0)
239 addedQuarterPeriods += signum(addedQuarterPeriods);
240 xDiff = new BasicHep3Vector(xDiff.x(), xDiff.y(), zPos);
241 }
242 double factorA1 = pMag - pz * pz / pMag - (VecOp.dot(xDiff, pCrossB))
243 * rho;
244 double factorA2 = (VecOp.dot(xDiff, p0) - xDiff.z() * pz) * rho;
245
246
247
248
249 return addedQuarterPeriods * abs(radius / cosLambda * Math.PI)
250 - Math.atan2(factorA2, factorA1) / rho;
251 }
252
253
254
255
256
257
258
259
260
261
262 public double getSignedClosestDifferenceToPoint(Hep3Vector point) {
263 double tanLambda = sinLambda / cosLambda;
264 Hep3Vector pCrossB = new BasicHep3Vector(py, -px, 0);
265 Hep3Vector xDiff = VecOp.sub(origin, point);
266 double pMag = sqrt(px * px + py * py + pz * pz);
267
268
269
270 double zPos = xDiff.z();
271 zPos = Math.IEEEremainder(zPos, abs(radius * tanLambda * Math.PI / 4));
272 if (zPos < 0) zPos += abs(radius * tanLambda * Math.PI / 4);
273
274 if (zPos/abs(radius * tanLambda * Math.PI / 4) < 0 || zPos/abs(radius * tanLambda * Math.PI / 4) > 1)
275 {
276 System.out.println("Valid range of zPos/abs(radius*tanLambda*Math.PI/4) [0 and 1], value is: "+zPos/abs(radius * tanLambda * Math.PI / 4));
277 }
278
279 xDiff = new BasicHep3Vector(xDiff.x(), xDiff.y(), zPos);
280
281 double numerator = (-2 * VecOp.dot(xDiff, pCrossB) + pMag * rho
282 * (xDiff.magnitudeSquared() - xDiff.z() * xDiff.z()))
283 / radius;
284 double denominator = 1 + sqrt(1 - 2 * rho * pMag
285 * VecOp.dot(xDiff, pCrossB) / radius / radius + pMag * pMag
286 * rho * rho
287 * (xDiff.magnitudeSquared() - xDiff.z() * xDiff.z()) / radius
288 / radius);
289 return numerator / denominator;
290 }
291
292
293
294
295 public Hep3Vector getTangentAtDistance(double alpha) {
296 double p0x = px * cos(rho * alpha) - py * sin(rho * alpha);
297 double p0y = py * cos(rho * alpha) + px * sin(rho * alpha);
298 double p0z = pz;
299 return new BasicHep3Vector(p0x, p0y, p0z);
300 }
301
302
303 public double getSecondDistanceToInfiniteCylinder(double r) {
304 double result = getDistanceToInfiniteCylinder(r);
305 SpacePoint first = getPointAtDistance(result);
306 double angto0 = Math.atan2(-yCenter, -xCenter);
307 double angtofirst = Math
308 .atan2(first.y() - yCenter, first.x() - xCenter);
309 double dang = angtofirst - angto0;
310 if (dang < -Math.PI)
311 dang += 2. * Math.PI;
312 if (dang > Math.PI)
313 dang -= 2. * Math.PI;
314 double angofarc = 2. * (Math.PI - Math.abs(dang));
315 double arc = Math.abs(radius) * angofarc / cosLambda;
316 return result + arc;
317 }
318
319 public double getZPeriod() {
320 return Math.PI * radius * 2. * sinLambda / cosLambda;
321 }
322
323
324
325
326
327 private void setSpatialParameters() {
328 abs_r = abs(radius);
329 px = abs_r * cosPhi;
330 py = abs_r * sinPhi;
331 pz = abs_r * sinLambda / cosLambda;
332 rho = -cosLambda / radius;
333 }
334
335
336
337
338
339
340
341
342 private Hep3Vector propagateDirection(Hep3Vector u, double s) {
343 double ux = u.x();
344 double uy = u.y();
345 double uz = u.z();
346 double carg = Math.cos(rho * s);
347 double sarg = Math.sin(rho * s);
348 double uxnew = ux * carg -uy * sarg;
349 double uynew = uy * carg + ux * sarg;
350 double uznew = uz;
351 return new BasicHep3Vector (uxnew, uynew, uznew);
352 }
353
354
355
356
357
358
359
360
361
362 private Hep3Vector propagatePosition(Hep3Vector pos, Hep3Vector u, double s) {
363 double x = pos.x();
364 double y = pos.y();
365 double z = pos.z();
366 double ux = u.x();
367 double uy = u.y();
368 double uz = u.z();
369 double carg = Math.cos(rho * s);
370 double sarg = Math.sin(rho * s);
371 double xnew = x + ux * sarg / rho - uy * (1 - carg) / rho;
372 double ynew = y + uy * sarg / rho + ux * (1 - carg) / rho;
373 double znew = z + uz * s;
374 return new BasicHep3Vector(xnew, ynew, znew);
375 }
376
377
378
379
380
381
382 public SpaceVector getUnitTangentAtLength(double alpha) {
383 double angle = phi + alpha * rho;
384 return new CartesianVector(cos(angle), sin(angle), sinLambda
385 / cosLambda);
386 }
387
388 Hep3Vector origin;
389 double xCenter;
390 double yCenter;
391 protected double radius;
392 protected double sinLambda;
393 protected double cosLambda;
394 protected double sinPhi;
395 protected double cosPhi;
396 protected double phi;
397
398
399
400
401
402
403 private double px;
404 private double py;
405 private double pz;
406 private double abs_r;
407 private double rho;
408
409
410 private double eps = 1.e-6;
411 public void setExtrapToPointPrecision(double prec){eps = prec;}
412 }