00001
00002
00003 #include "Iguana/Inventor/interface/IgSoIdealTrack.h"
00004 #include "Iguana/Inventor/interface/IgParticleChar.h"
00005 #include <Inventor/nodes/SoVertexProperty.h>
00006 #include <Inventor/nodes/SoPointSet.h>
00007 #include <Inventor/nodes/SoNurbsCurve.h>
00008 #include <Inventor/nodes/SoComplexity.h>
00009 #include <Inventor/nodes/SoCoordinate4.h>
00010 #include <cfloat>
00011 #include <vector>
00012 #include <cassert>
00013 #include <iostream>
00014 #include <limits>
00015
00016
00017
00018 #ifdef WIN32
00019 # define copysign _copysign
00020 #else
00021 # if (defined (__linux) && !defined (__KCC)) || (defined (MIPS) && defined (__KCC))
00022 extern "C" inline double copysign (double x, double y) throw ()
00023 {
00024 return (fabs (x) * y /fabs (y));
00025 }
00026 # endif
00027 #endif
00028
00029
00030
00031 #ifdef TGS_VERSION
00032 static const float maxNurbAngle = M_PI / 2.;
00033 #else
00034 static const float maxNurbAngle = static_cast<float>( M_PI / 6. );
00035 #endif
00036 static const float maxAngle = static_cast<float>(4 * M_PI);
00037
00038
00039
00040
00041 float IgSoIdealTrack::bfield = 4.0F;
00042 float IgSoIdealTrack::rmax = 1.4F;
00043 float IgSoIdealTrack::zmax = 3.2F;
00044
00045
00046
00047 static const int NORDER = 3;
00048 static const float SPEEDOLIGHT = 0.00299792458F;
00049
00050 SO_KIT_SOURCE (IgSoIdealTrack);
00051
00052
00053
00054
00055
00056
00057
00058 void
00059 IgSoIdealTrack::initClass (void)
00060 {
00061 SO_KIT_INIT_CLASS (IgSoIdealTrack, IgSoShapeKit, "IgSoShapeKit");
00062 IgParticleChar::initParticles ();
00063 }
00064
00065 IgSoIdealTrack::IgSoIdealTrack (void)
00066 : m_particleChar (IgParticleChar::getByName("muon")),
00067 m_ptot (1.F),
00068 m_pt (0.5F),
00069 m_charge (-1.F)
00070 {
00071 SO_KIT_CONSTRUCTOR (IgSoIdealTrack);
00072 SO_KIT_ADD_FIELD (phi, (0.0F));
00073 SO_KIT_ADD_FIELD (radius, (1.0F));
00074 SO_KIT_ADD_FIELD (zeta, (0.01F));
00075 SO_KIT_ADD_FIELD (vertex, (0.0F, 0.0F, 0.0F));
00076 SO_KIT_ADD_FIELD (t0, (0.0F));
00077 SO_KIT_ADD_FIELD (dt, (1.0F));
00078 SO_KIT_ADD_FIELD (tstart, (0.0F));
00079 SO_KIT_ADD_FIELD (tend, (500.F));
00080 SO_KIT_ADD_FIELD (particleType, ("unknown"));
00081 SO_KIT_ADD_CATALOG_ENTRY (material, SoMaterial, FALSE, separator,\x0, TRUE);
00082 SO_KIT_ADD_CATALOG_ENTRY (style, SoDrawStyle, FALSE, separator,\x0, TRUE);
00083 SO_KIT_ADD_CATALOG_ENTRY (complexity, SoComplexity, FALSE, separator,\x0, TRUE);
00084 SO_KIT_ADD_CATALOG_ENTRY (points, SoCoordinate4, FALSE, separator,\x0, TRUE);
00085 SO_KIT_ADD_CATALOG_ENTRY (curve, SoNurbsCurve, FALSE, separator,\x0, TRUE);
00086 #ifdef IG_DEBUG_PTS
00087 SO_KIT_ADD_CATALOG_ENTRY (debugStyle, SoDrawStyle, FALSE, separator,\x0, TRUE);
00088 SO_KIT_ADD_CATALOG_ENTRY (debugPoints, SoPointSet, FALSE, separator,\x0, TRUE);
00089 #endif // IG_DEBUG_PTS
00090 SO_KIT_INIT_INSTANCE ();
00091 setUpConnections (true, true);
00092 }
00093
00094 IgSoIdealTrack::~IgSoIdealTrack (void)
00095 {
00096 if (dt.isConnected ())
00097 dt.disconnect ();
00098 }
00099
00100 void
00101 IgSoIdealTrack::refresh (void)
00102 {
00103
00104 float radius = this->radius.getValue ();
00105 float zeta = this->zeta.getValue ();
00106 SbVec3f vertex = this->vertex.getValue ();
00107 float phi = this->phi.getValue ();
00108 float tstart = this->tstart.getValue ();
00109 float tend = this->tend.getValue ();
00110
00111 float t0 = this->t0.getValue ();
00112 float dt = this->dt.getValue ();
00113
00114
00115
00116 if (t0 > tend)
00117 t0 = tend;
00118
00119 float t1 = dt+t0;
00120 if (t1 > tend)
00121 t1 = tend;
00122
00123
00124
00125 if (!fabs (tend - tstart) || !fabs (t1 - t0))
00126 {
00127 setPart ("material", m_particleChar->getMaterial ());
00128 setPart ("style", m_particleChar->getStyle ());
00129 setPart ("complexity", 0);
00130 setPart ("points", 0);
00131 setPart ("curve", 0);
00132 #ifdef IG_DEBUG_PTS
00133 setPart ("debugStyle", 0);
00134 setPart ("debugPoints", 0);
00135 #endif // IG_DEBUG_PTS
00136 return;
00137 }
00138
00139 #ifdef IG_DEBUG_PTS
00140 SoDrawStyle *debugStyle = new SoDrawStyle;
00141 SoPointSet *debugPoints = new SoPointSet;
00142 SoVertexProperty *debugVtx = new SoVertexProperty;
00143 #endif // IG_DEBUG_PTS
00144
00145 SoComplexity *complexity = new SoComplexity;
00146 SoCoordinate4 *points = new SoCoordinate4;
00147 SoNurbsCurve *curve = new SoNurbsCurve;
00148 complexity->value = 0.6F;
00149 int npoints = 0;
00150 int nknots = 0;
00151 int nknot = 0;
00152 std::vector<SbVec4f> ctlPoints;
00153 std::vector<float> knots;
00154
00155 if ( bfield == 0 || m_charge == 0 )
00156 {
00157
00158 float z0, z1, x0, y0, x1, y1;
00159 z0 = timeToZ (t0);
00160 z1 = timeToZ (t1);
00161 SbVec2f xy0( timeToXY(t0) );
00162 SbVec2f xy1( timeToXY( t1 ) );
00163 xy0.getValue( x0, y0 );
00164 xy1.getValue( x1, y1 );
00165
00166
00167 npoints = 2;
00168 nknots = 4;
00169 ctlPoints.resize(static_cast<int>(npoints));
00170 knots.resize(static_cast<int>(nknots));
00171 knots[0] = 0; knots[1] = 0; knots[2] = 1; knots[3] = 1;
00172 ctlPoints[0].setValue( x0, y0, z0, 1.F );
00173 ctlPoints[1].setValue( x1, y1, z1, 1.F );
00174
00175
00176 points->point.setValues (0, npoints, &ctlPoints[0]);
00177
00178
00179 curve->numControlPoints = npoints;
00180 curve->knotVector.setValues (0, nknots, &knots[0]);
00181
00182 }
00183 else
00184 {
00185
00186 m_pt = SPEEDOLIGHT * 100.F * bfield * m_charge * radius;
00187 float pz = SPEEDOLIGHT * 100.F * bfield * m_charge * zeta;
00188 m_ptot = sqrt (m_pt * m_pt + pz * pz);
00189
00190
00191 float x0, x1, y0, y1, z0, z1;
00192 float phi0 = timeToAngle (t0);
00193 float phi1 = timeToAngle (t1);
00194 float delPhi = phi1 - phi0;
00195
00196
00197
00198 if (fabs (delPhi) > maxAngle)
00199 {
00200 delPhi = static_cast<float>(copysign (maxAngle, delPhi));
00201 phi1 = delPhi + phi0;
00202 t1 = angleToTime (phi1);
00203 }
00204
00205 if (delPhi == 0)
00206 {
00207 z0 = timeToZ (t0);
00208 z1 = timeToZ (t1);
00209 }
00210 else
00211 {
00212 z0 = vertex [2] - (phi0 - phi) * zeta;
00213 z1 = vertex [2] - (phi1 - phi) * zeta;
00214 }
00215
00216 float xc = vertex [0] + radius * sin (phi);
00217 float yc = vertex [1] - radius * cos (phi);
00218 x0 = xc - radius * sin (phi0);
00219 y0 = yc + radius * cos (phi0);
00220 x1 = xc - radius * sin (phi1);
00221 y1 = yc + radius * cos (phi1);
00222
00223
00224
00225 ctlPoints.resize (static_cast<int>(2*(maxAngle/maxNurbAngle +2)));
00226
00227 knots.resize (static_cast<int>(2*(maxAngle/maxNurbAngle +2)+NORDER));
00228
00229
00230
00231 knots [nknots++] = static_cast<float>(nknot);
00232
00233 if (fabs (delPhi) < maxNurbAngle)
00234 {
00235
00236 ctlPoints [npoints++] = SbVec4f (x0, y0, z0, 1.0);
00237
00238
00239 knots [nknots++] = static_cast<float>(nknot);
00240 knots [nknots++] = static_cast<float>(nknot++);
00241
00242 ctlPoints [npoints++] =
00243 SbVec4f (xc - sin (delPhi/2.F + phi0) * radius / fabs (cos (delPhi/2.F)),
00244 yc + cos (delPhi/2.F + phi0) * radius / fabs (cos (delPhi/2.F)),
00245 (z0 + z1) / 2.F,
00246 1.F)
00247 * fabs (cos (delPhi / 2.F));
00248 }
00249 else
00250 {
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 int nfill = 1 + (int) (fabs (delPhi) / maxNurbAngle );
00263 if (nfill == 1)
00264
00265 nfill = 2;
00266 double delAngle = delPhi / nfill;
00267 double delZ = (z1 - z0) / delPhi;
00268
00269 for (int i = 0; i < nfill; ++i)
00270 {
00271 double angle = phi0 + i * delAngle;
00272
00273 if (i == 0)
00274
00275 ctlPoints [npoints++] = SbVec4f (x0, y0, z0, 1.0F);
00276 else
00277 ctlPoints [npoints++] = SbVec4f (xc - radius * sin (angle),
00278 yc + radius * cos (angle),
00279 z0 + delZ * (angle - phi0),
00280 1.0F);
00281
00282
00283 knots [nknots++] = static_cast<float>(nknot);
00284 knots [nknots++] = static_cast<float>(nknot++);
00285
00286 ctlPoints [npoints++] =
00287 SbVec4f (xc - radius * sin (angle + delAngle/2.F) / fabs (cos (delAngle/2.F)),
00288 yc + radius * cos (angle + delAngle/2.F) / fabs (cos (delAngle/2.F)),
00289 z0 + delZ * (angle + delAngle/2.F - phi0),
00290 1.0F)
00291 * fabs (cos (delAngle/2.F));
00292 }
00293 }
00294
00295
00296 ctlPoints [npoints++] = SbVec4f (x1, y1, z1, 1.0F);
00297 knots [nknots++] = static_cast<float>(nknot);
00298 knots [nknots++] = static_cast<float>(nknot);
00299 knots [nknots++] = static_cast<float>(nknot);
00300
00301 points->point.setValues (0, npoints, &ctlPoints[0]);
00302
00303
00304 curve->numControlPoints = npoints;
00305 curve->knotVector.setValues (0, nknots, &knots[0]);
00306 }
00307 #ifdef IG_DEBUG_PTS
00308
00309 for (int i = 0; i < npoints; ++i)
00310 {
00311 SbVec3f pt;
00312 ctlPoints [i].getReal (pt);
00313 debugVtx->vertex.set1Value (i, pt);
00314 }
00315
00316 debugStyle->pointSize = 4;
00317 debugStyle->style = SoDrawStyle::LINES;
00318 debugPoints->vertexProperty = debugVtx;
00319 setPart ("debugStyle", debugStyle);
00320 setPart ("debugPoints", debugPoints);
00321 #endif // IG_DEBUG_PTS
00322
00323
00324
00325 setPart ("material", m_particleChar->getMaterial ());
00326 setPart ("style", m_particleChar->getStyle ());
00327 setPart ("complexity", complexity);
00328 setPart ("points", points);
00329 setPart ("curve", curve);
00330
00331
00332 #if 0 //DEBUG
00333 std::cout << "IgSoIdealTrack particle name: " << particleType.getValue ().getString ()
00334 << " material: " << m_particleChar->getMaterial()
00335 << std::endl;
00336 #endif //DEBUG
00337 }
00338
00339 float
00340 IgSoIdealTrack::timeToAngle (float time)
00341 {
00342 float phi = this->phi.getValue ();
00343 float radius = this->radius.getValue ();
00344 float tstart = this->tstart.getValue ();
00345 float mass = m_particleChar->getMass ();
00346 float betat = m_pt / sqrt (mass * mass + m_ptot * m_ptot);
00347 if (fabs (radius))
00348 return phi - betat * SPEEDOLIGHT * (time - tstart) / radius;
00349 else
00350 return phi;
00351 }
00352
00353 float
00354 IgSoIdealTrack::angleToTime (float angle)
00355 {
00356 float phi = this->phi.getValue ();
00357 float radius = this->radius.getValue ();
00358 float tstart = this->tstart.getValue ();
00359 float mass = m_particleChar->getMass ();
00360 float betat = m_pt / sqrt (mass * mass + m_ptot * m_ptot);
00361 return tstart - (radius * (angle - phi)) / (betat * SPEEDOLIGHT);
00362 }
00363
00364 float
00365 IgSoIdealTrack::zToTime (float z)
00366 {
00367 SbVec3f vertex = this->vertex.getValue ();
00368 float zeta = this->zeta.getValue ();
00369 float tstart = this->tstart.getValue ();
00370 float mass = m_particleChar->getMass ();
00371
00372 float betaz;
00373 if (bfield != 0 && m_charge != 0)
00374 {
00375 betaz = (zeta * SPEEDOLIGHT * 100 * bfield * m_charge)
00376 / sqrt (mass * mass + m_ptot * m_ptot);
00377 }
00378 else
00379 {
00380 betaz = zeta * m_ptot / sqrt( m_ptot*m_ptot + mass * mass );
00381 }
00382 if (fabs (betaz))
00383 return tstart + (z - vertex [2]) / (betaz * SPEEDOLIGHT);
00384 else
00385 return tstart;
00386 }
00387
00388 float
00389 IgSoIdealTrack::timeToZ (float time)
00390 {
00391 SbVec3f vertex = this->vertex.getValue ();
00392 float zeta = this->zeta.getValue ();
00393 float tstart = this->tstart.getValue ();
00394 float mass = m_particleChar->getMass ();
00395 float betaz;
00396 if ( bfield != 0 && m_charge != 0 )
00397 {
00398 betaz = (zeta * SPEEDOLIGHT * 100 * bfield * m_charge)
00399 / sqrt (mass * mass + m_ptot * m_ptot);
00400 }
00401 else
00402 {
00403 betaz = zeta * m_ptot / sqrt (mass * mass + m_ptot * m_ptot);
00404 }
00405
00406 return (time - tstart) * betaz * SPEEDOLIGHT + vertex [2];
00407 }
00408
00409 SbVec2f
00410 IgSoIdealTrack::timeToXY (float time)
00411 {
00412 if ( bfield ==0 || m_charge == 0 )
00413 {
00414 float mass = m_particleChar->getMass ();
00415 float betat = m_pt / sqrt ( mass*mass + m_ptot * m_ptot );
00416 float deltaT = time - tstart.getValue();
00417 float x = vertex.getValue() [0] + cos(phi.getValue()) * betat * deltaT * SPEEDOLIGHT;
00418 float y = vertex.getValue() [1] + sin(phi.getValue()) * betat * deltaT * SPEEDOLIGHT;
00419 return SbVec2f ( x, y );
00420 }
00421 else
00422 {
00423 float angle = timeToAngle (time);
00424 SbVec3f vertex = this->vertex.getValue ();
00425 double radius = this->radius.getValue ();
00426 double phi = this->phi.getValue ();
00427 double xc = vertex [0] + radius * sin (phi);
00428 double yc = vertex [1] - radius * cos (phi);
00429 return SbVec2f (xc - radius * sin (angle), yc + radius * cos (angle));
00430 }
00431 }
00432
00442 void
00443 IgSoIdealTrack::initialise (double *vx, double *vy, double *vz,
00444 double *px, double *py, double *pz,
00445 float *t0, IgParticleChar *pc)
00446 { initialise (*vx, *vy, *vz, *px, *py, *pz, *t0, pc); }
00447
00448 void
00449 IgSoIdealTrack::initialise (double vx, double vy, double vz,
00450 double px, double py, double pz,
00451 float t0, int pid)
00452 { initialise (vx, vy, vz, px, py, pz, t0, IgParticleChar::getByGeantID (pid)); }
00453
00454 void
00455 IgSoIdealTrack::initialise (double vx, double vy, double vz,
00456 double px, double py, double pz,
00457 float t0, IgParticleChar *pc)
00458 {
00459 m_particleChar = pc;
00460 m_charge = pc->getCharge ();
00461 particleType = pc->getName ();
00462
00463 SbVec3f vec3 = SbVec3f (px, py, pz);
00464 SbVec2f vec2 = SbVec2f (px, py);
00465 m_ptot = vec3.length ();
00466 m_pt = vec2.length ();
00467
00468 double radius, zeta;
00469
00470 double qB = SPEEDOLIGHT * 100 * bfield * m_charge;
00471 if (qB != 0)
00472 {
00473 radius = m_pt / qB;
00474 zeta = pz / qB;
00475 }
00476 else
00477 {
00478 radius = std::numeric_limits<double>::infinity();
00479 zeta = pz / m_ptot;
00480 }
00481
00482
00483 this->vertex = SbVec3f (vx, vy, vz);
00484 this->radius = static_cast<float>(radius);
00485 this->zeta = static_cast<float>(zeta);
00486 this->phi = static_cast<float>( px == 0.0 && px == 0.0 ? 0.0 : atan2(py, px) );
00487 this->t0 = t0;
00488 this->tstart = t0;
00489
00490 initEndPts ();
00491 }
00492
00493 void
00494 IgSoIdealTrack::initEndPts (void)
00495 {
00496 float radius = this->radius.getValue ();
00497 float zeta = this->zeta.getValue ();
00498 SbVec3f vertex = this->vertex.getValue ();
00499 float phi = this->phi.getValue ();
00500 double xc = vertex [0] + radius * sin (phi);
00501 double yc = vertex [1] - radius * cos (phi);
00502 double delPhi;
00503 double x1;
00504 double y1;
00505 double z1;
00506 if ( radius == std::numeric_limits<double>::infinity() )
00507 {
00508
00509 if (zeta==0)
00510 {
00511
00512 double s = -cos(phi)*vertex[0] - sin(phi)*vertex[1]+ sqrt( pow(rmax,2) - pow(vertex[0],2)
00513 - pow(vertex[1],2)+ pow( cos(phi)*vertex[0]+sin(phi)*vertex[1], 2));
00514 x1 = vertex[0] + s * cos(phi);
00515 y1 = vertex[1] + s * sin(phi);
00516 z1 = vertex[3];
00517 float mass = m_particleChar->getMass ();
00518 tend = s / ( sqrt(1.F - pow(zeta,2) ) * m_ptot / sqrt ( m_ptot*m_ptot + mass*mass) * SPEEDOLIGHT );
00519 }
00520 else if (m_pt ==0)
00521 {
00522
00523 x1 = vertex[0]; y1 = vertex[1];
00524 z1 = zeta>0 ? zmax : -zmax;
00525 tend = zToTime (z1);
00526 }
00527 else
00528 {
00529 double s = -cos(phi)*vertex[0] - sin(phi)*vertex[1] + sqrt( pow(rmax,2) - pow(vertex[0],2)
00530 - pow(vertex[1],2) + pow( cos(phi)*vertex[0]+sin(phi)*vertex[1], 2));
00531
00532 double zint = s * zeta/sqrt( 1.f - pow(zeta,2) ) + vertex[2];
00533 if ( abs(zint) > zmax )
00534 {
00535 zint = zint > 0.F ? zmax : -zmax;
00536 s = (zint - vertex[2]) * sqrt( 1 - pow(zeta,2) ) / zeta;
00537 }
00538 x1 = s * cos(phi) + vertex[0]; y1 = s * sin(phi) + vertex[1]; z1 = zint;
00539 tend = zToTime (z1);
00540 }
00541 dt = tend.getValue () - tstart.getValue ();
00542 }
00543 else
00544 {
00545
00546
00547
00548 if (xc == 0 && yc == 0)
00549 {
00550
00551 if (fabs (radius) >= rmax)
00552
00553 return;
00554
00555 x1 = vertex [0];
00556 y1 = vertex [1];
00557 delPhi = - 2. * copysign (1.0, m_charge * bfield) * M_PI * 2;
00558
00559 if (m_pt == 0.0)
00560 {
00561
00562 z1 = copysign (zmax, zeta * m_charge * bfield);
00563 delPhi = 0.0;
00564 }
00565 else
00566 {
00567 z1 = vertex [2] - delPhi * zeta;
00568 if (fabs (z1) > zmax)
00569 delPhi = -(copysign (zmax, z1) - vertex [2]) / zeta;
00570 }
00571 }
00572 else
00573 {
00574 double x2, y2, delPhi1, delPhi2;
00575 double gamma = yc ? -xc / yc : FLT_MAX;
00576 double delta = (rmax * rmax - radius * radius - xc * xc - yc * yc) / (2 * yc);
00577 double det = 4 * gamma * gamma * delta * delta
00578 - 4 * (1 + gamma * gamma) * (delta * delta - radius * radius);
00579
00580 if (det >= 0)
00581 {
00582
00583 det = sqrt (det);
00584 x1 = (-2 * gamma * delta + det) / (2 * (1 + gamma * gamma));
00585 x2 = (-2 * gamma * delta - det) / (2 * (1 + gamma * gamma));
00586 y1 = gamma * x1 + delta;
00587 y2 = gamma * x2 + delta;
00588 x1 = xc + x1;
00589 x2 = xc + x2;
00590 y1 = yc + y1;
00591 y2 = yc + y2;
00592
00593
00594 delPhi1 = atan2 (-(x1 - xc) / radius, (y1 - yc) / radius) - phi;
00595 delPhi2 = atan2 (-(x2 - xc) / radius, (y2 - yc) / radius) - phi;
00596
00597 if (m_charge * bfield < 0)
00598 {
00599
00600 if (delPhi1 < 0)
00601 delPhi1 += M_PI*2;
00602 if (delPhi2 < 0)
00603 delPhi2 += M_PI*2;
00604 }
00605 else
00606 {
00607
00608 if (delPhi1 > 0)
00609 delPhi1 -= M_PI*2;
00610 if (delPhi2 > 0)
00611 delPhi2 -= M_PI*2;
00612 }
00613
00614 if ((m_charge * bfield < 0 && delPhi1 < delPhi2)
00615 || (m_charge * bfield > 0 && delPhi1 > delPhi2))
00616 delPhi = delPhi1;
00617 else
00618 {
00619 x1 = x2;
00620 y1 = y2;
00621 delPhi = delPhi2;
00622 }
00623 }
00624 else
00625 {
00626
00627 delPhi = -2.0 * copysign (1.0, m_charge * bfield) * M_PI*2;
00628 x1 = vertex [0];
00629 y1 = vertex [1];
00630 z1 = timeToZ (angleToTime (delPhi + phi));
00631
00632 if (fabs (z1) > zmax)
00633 {
00634 z1 = copysign (zmax, z1);
00635 delPhi = timeToAngle (zToTime (z1 - vertex [2])) - phi;
00636 }
00637 }
00638 }
00639
00640 if (delPhi)
00641 tend = angleToTime (delPhi + phi);
00642 else
00643 tend = zToTime (z1);
00644
00645 dt = tend.getValue () - tstart.getValue ();
00646 }
00647 }