package hep.graphics.j3d;
// Java
import java.util.ArrayList;
import java.util.Iterator;
// Java3D
import javax.media.j3d.Appearance;
import javax.media.j3d.Shape3D;
import javax.media.j3d.LineStripArray;
import javax.media.j3d.GeometryArray;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
/** Helix segment in solenoidal magnetic field along z-axis.
* Parameters are defined in "vertex representation".
* <img src="doc-files/Helix.gif">
* @version 3.0.0
* @author <a href="mailto:Julius.Hrivnac@cern.ch">J.Hrivnac</a> */
// TBD: provide perigee parametrisation
// TBD: use PolyLine
public class Helix extends Shape3D {
/** Create helix.
* @param charge particles' charge
* @param eta track' polar angle [deg]
* @param phi track' azimutal angle [deg]
* @param pt track' pt [GeV]
* @param v_phi vertex' polar angle [deg]
* @param v_rho vertex' radial coordinate
* @param v_z vertex' z coordinate
* @param mField magnetic field [T]
* @param granularity number of segments of curves approximations
* @param appearance object' Appearance
* @preconditions charge >= -1 && charge <= 1
* @preconditions phi > 0 && phi < 360
* @preconditions pt > 0
* @preconditions v_phi > 0 && v_phi < 360
* @preconditions mField > 0
* @preconditions granularity > 1 */
public Helix(int charge,
double eta,
double phi,
double pt,
double v_phi,
double v_rho,
double v_z,
double mField,
int granularity,
Appearance appearance) {
if (charge == 0) {
constructNeutral(eta,
pt,
v_phi,
v_rho,
v_z,
appearance);
}
else {
constructCharged(charge,
eta,
phi,
pt,
v_phi,
v_rho,
v_z,
mField,
granularity,
appearance);
}
}
private void constructNeutral(double eta,
double phi,
double v_phi,
double v_rho,
double v_z,
Appearance appearance) {
Point3d start = new Point3d(v_rho * Math.cos(v_phi),
v_rho * Math.sin(v_phi),
v_z);
Point3d end0 = new Point3d(start.x,
start.y,
start.z);
final double tant = 2 / (Math.exp(eta) - Math.exp(-eta));
if (tant > _length / _radius) {
end0.add(new Point3d(_radius * Math.cos(phi),
_radius * Math.sin(phi),
_radius * tant));
}
else {
end0.add(new Point3d(_length * Math.cos(phi) / tant,
_length * Math.sin(phi) / tant,
_length));
}
int[] counts = new int[1];
counts[0] = 2;
LineStripArray lineArray = new LineStripArray(2,
GeometryArray.COORDINATES|
GeometryArray.NORMALS,
counts);
float[] normal = {0, 0, 0};
lineArray.setCoordinate(0, start);
lineArray.setCoordinate(1, end0);
lineArray.setNormal(0, normal);
setGeometry(lineArray);
_end = new Vector3d(end0);
setAppearance(appearance);
}
private void constructCharged(int charge,
double eta,
double phi,
double pt,
double v_phi,
double v_rho,
double v_z,
double mField,
int granularity,
Appearance appearance) {
final double rx = v_rho * Math.cos(v_phi);
final double ry = v_rho * Math.sin(v_phi);
final double rz = v_z;
final double px = pt * Math.cos(phi);
final double py = pt * Math.sin(phi);
final double pz = pt / 2 * (Math.exp(eta) - Math.exp(-eta));
final double sigma = pt / mField / 0.3;
final double alpha = sigma * pz / pt;
final double sx = rx - py * sigma * charge;
final double sy = ry + px * sigma * charge;
final double st = Math.sqrt(sx * sx + sy *sy);
final double dx = (1 - sigma * pt / st) * sx;
final double dy = (1 - sigma * pt / st) * sy;
final double sin_dphi_2 = Math.sqrt((rx - dx) * (rx - dx) + (ry - dy) * (ry - dy)) / 2 / sigma;
final double cos_dphi_2 = Math.sqrt(1 - sin_dphi_2 * sin_dphi_2);
double dphi = 2 * Math.atan2(sin_dphi_2, cos_dphi_2);
if ((rx - dx) * px + (ry - dy) * py > 0) {
dphi = - dphi;
}
final double phi0 = Math.atan2(ry - sy, rx - sx);
final double delta = 2 * Math.PI / granularity / pt; // TBD: do it better
double x = 0;
double y = 0;
double z = 0;
int i = 0;
double w = 0;
ArrayList points = new ArrayList();
if (Math.sqrt(rx*rx + ry*ry) < _radius &&
Math.abs(rz) < _length / 2f) {
do {
x = rx + sigma * (Math.cos(phi0) - Math.cos(- charge * delta * w + phi0));
y = ry + sigma * (Math.sin(phi0) - Math.sin(- charge * delta * w + phi0));
z = rz + alpha * delta * w;
points.add(new Point3d(x, y, z));
i += 1;
w += 1;
} while (Math.sqrt(x*x + y*y) < _radius &&
Math.abs(z) < _length / 2f &&
i < granularity);
}
if (i > 0) {
int[] counts = new int[1];
counts[0] = points.size();
LineStripArray lineArray = new LineStripArray(points.size(),
GeometryArray.COORDINATES|
GeometryArray.NORMALS,
counts);
float[] normal = {0, 0, 0};
int j = 0;
Iterator it = points.iterator();
while (it.hasNext()) {
lineArray.setCoordinate(j++, (Point3d)(it.next()));
}
lineArray.setNormal(0, normal);
setGeometry(lineArray);
_end = new Vector3d(x, y, z);
}
setAppearance(appearance);
}
/** End point of the helix. */
public Vector3d end() {
return _end;
}
private Vector3d _end;
/** Set maximal end point of the helix.
* The default is 30,12. */
public static void cutAt(double length, double radius) {
_length = length;
_radius = radius;
}
private static double _length = 30; // half-length
private static double _radius = 12;
}