1
/*******************************************************************************
3
* drawEvent.c -- Map the event - ie., the list of four-momentum vectors to an *
4
* array of points or segments for displaying on the spin widget *
6
* Copyright (c) 1991 Universities Research Association, Inc. *
7
* All rights reserved. *
9
* This material resulted from work developed under a Government Contract and *
10
* is subject to the following license: The Government retains a paid-up, *
11
* nonexclusive, irrevocable worldwide license to reproduce, prepare derivative *
12
* works, perform publicly and display publicly by or for the Government, *
13
* including the right to distribute to other Government contractors. Neither *
14
* the United States nor the United States Department of Energy, nor any of *
15
* their employees, makes any warrenty, express or implied, or assumes any *
16
* legal liability or responsibility for the accuracy, completeness, or *
17
* usefulness of any information, apparatus, product, or process disclosed, or *
18
* represents that its use would not infringe privately owned rights. *
20
* Fermilab Nirvana GUI Library *
21
* June 17, 1991, August 22, 1991 *
23
* Written by Paul Lebrun & Mark Edel *
25
*******************************************************************************/
26
static char SCCSID[] = "@(#)drawEvent.c 1.1 4/6/92";
33
#include "spin/Spin.h"
34
#include "util/stringUtils.h"
38
#include "drawEvent.h"
40
#define MAXPARTCOLOR 30 /* Size of particle color table */
41
#define EPSILON 0.1e-10
43
#define FULL_ON 0xffff
44
#define HALF_ON (0xffff/2)
49
#define MAXCHAR_HEPNAM 30 /* for use with hepnam_ */
51
extern float stdchg_(long *id);
53
static Pixel allocRGB(Screen *screen,
54
unsigned short red, unsigned short green, unsigned short blue);
55
static Pixel particlePixel(int particleID);
56
static void detectorToSegment(SpaceWindow *window, SpinSegment *segdt,
62
** Generate the HEP color convention : This routines fills the
63
** Global array ParticleColors, which is simply an list of color indices generated
64
** by calls to XAllocColor.
66
** This convention is the following :
68
** The photon is always black. If a color can not be allocated, Black
71
** For GrayScale Display, the charged leptons are white, the other
72
** neutrinos are black and the quarks and hadrons are gray.
74
** For Color display, the charged leptons have the three fundamental
75
** RGB colors: electron is blue, muon is green and tau is red.
76
** The neutrinos are gray. The quarks are characterised a mixture
77
** where one componenet of RGB is set to 0, the other two are
78
** half of the full intensity. For instance, the up quark has
79
** no blue compoenet, and is half green, half red.
80
** The Weak bosons and the gluons are made of a disgusting
81
** mixture of all RGB colors ( pink for the W andZ bosons,
82
** brown for the gluons).
83
** The color of a hadron is set the by color of the heaviest quark
86
void AllocateColors(Screen *screen)
88
Display *display = DisplayOfScreen(screen);
89
Pixel black = BlackPixelOfScreen(screen);
90
Pixel white = WhitePixelOfScreen(screen);
95
/* As a fallback, initialize all particle colors to black */
96
for (i=0; i<MAXPARTCOLOR; i++)
97
ParticleColors[i]=black;
99
/* Assign colors based on type of screen available */
100
if (XMatchVisualInfo(display, XScreenNumberOfScreen(screen),
101
DefaultDepthOfScreen(screen), PseudoColor, &info)) {
103
** Screen can handle PseudoColor (color lookup table)
106
ParticleColors[1] = allocRGB(screen, FULL_ON, FULL_ON, OFF);
109
ParticleColors[2] = allocRGB(screen, FULL_ON, HALF_ON, OFF);
111
/* The Strange quark */
112
ParticleColors[3] = allocRGB(screen, OFF, FULL_ON, FULL_ON);
114
/* The Charm quark */
115
ParticleColors[4] = allocRGB(screen, OFF, FULL_ON, HALF_ON);
118
ParticleColors[5] = allocRGB(screen, FULL_ON, OFF, FULL_ON);
121
ParticleColors[6] = allocRGB(screen, HALF_ON, OFF, FULL_ON);
124
ParticleColors[11] = allocRGB(screen, OFF, OFF, FULL_ON);
127
ParticleColors[13] = allocRGB(screen, OFF, FULL_ON, OFF);
130
ParticleColors[15] = allocRGB(screen, FULL_ON, OFF, OFF);
133
color = allocRGB(screen, FULL_ON/3, FULL_ON/3, FULL_ON/3);
134
ParticleColors[16] = ParticleColors[14] = ParticleColors[12] = color;
136
/* The photon quark */
137
ParticleColors[22] = black;
140
ParticleColors[24] = allocRGB(screen, FULL_ON, HALF_ON, HALF_ON);
143
ParticleColors[23] = allocRGB(screen, FULL_ON, FULL_ON, HALF_ON);
146
color = allocRGB(screen, FULL_ON, HALF_ON, 2*FULL_ON/3);
147
ParticleColors[21] = ParticleColors[9] = color;
149
} else if (XMatchVisualInfo(display, XScreenNumberOfScreen(screen),
150
DefaultDepthOfScreen(screen), GrayScale, &info)) {
152
** Screen can't handle color but can handle GrayScale
155
color = allocRGB(screen, OFF, FULL_ON, FULL_ON);
157
ParticleColors[i] = color;
158
ParticleColors[9] = color;
159
ParticleColors[21]= color;
162
ParticleColors[11] = white;
163
ParticleColors[13] = white;
164
ParticleColors[15] = white;
168
** Produce a bunch of Radial coordinates to build a small icon describing the
174
double pi, dphi, dteta, phi, teta;
177
dphi = 2.0 * pi / NUMPINSPHI; dteta = pi / NUMPINSTETA;
178
for (i=0, phi = 0. ; i < NUMPINSTETA; i++, phi += dphi) {
179
for (j=0, teta = 0. ; j < NUMPINSPHI; j++, teta += dteta) {
180
XPinVertexPoints[j][i] = sin(teta) * cos(phi);
181
YPinVertexPoints[j][i] = sin(teta) * sin(phi);
182
ZPinVertexPoints[j][i] = cos(teta);
190
** Map an event to 3D segments for the spin widget. From a 4-momentum vector,
191
** (i.e., the 3-momentum vector and the unique identifier from which a physical
192
** mass can be obtained), An array of 3-dimensional vector and track type is
193
** deduced). The structure PhaseEvent is described in phase.h. The setting
194
** of the displayMode toggle on the event display panel determines how the
195
** event is mapped onto the screen:
197
** BY_MOMENTUM: The length is proportional the |P|, the norm of the 3-d
198
** momentum vector. This is the simplest and default option.
200
** BY_PT: The length of the vector is proportional to Pt, the
201
** transverse momentum. This trick greatly enhances
202
** the "high Pt" Physics in the event.
204
** BY_RAPIDITY: The length of the vector is propotional to the rapidity
205
** of the particle, as defined in the PDG bible.
207
** BY_PSEUDORAPIDITY: The length of the vector is proportional to the pseudo
208
** rapidity, i.e., the mass of the particle is
211
** BY_USER_ROUTINE : The user function specified in the DisplayEvent call
212
** is called to determine what the new vector ought to be...
214
void DrawEvent(StdHepWindow *window, int setScale)
216
int i, maxIndex, nSegments, nns, npvis;
218
double scale, innerScale, length, maxLength, outVec[3];
219
SpinSegment *segment, *segments, *segdt, temp;
220
SpinPoint *point, *points;
221
PhaseParticle *p, *particles = window->event.particles;
222
int nStable = 0, nParticles = window->event.nParticles;
223
SpaceVertex *pinv, *v;
224
char nameText[MAXCHAR_HEPNAM], statText[255];
226
/* There is a very wierd Ultrix compiler problem concerning this statement:*/
227
/* PhaseEvent *event; */
228
static char *unitText[6] = {"p", "Pt", "Eta", "Eta", "value", "Eta-Pt"};
234
/* If a Space window, find out the number of vertices in this event,
235
so we can allocate more space to draw short segments to represent
238
if (window->type == STDHEP_SPACE) {
239
wins = (SpaceWindow *) window;
240
/* allocate space for the maximum possible number of segments or points */
241
nns = NUMPINSTETA * NUMPINSPHI * wins->numRealVertices + nParticles;
242
nns += wins->nDetectorSegments;
243
segments = (SpinSegment *)XtMalloc(sizeof(SpinSegment) * nns);
245
} else if (window->type == STDHEP_PARA) {
246
winpa = (ParaWindow *) window;
247
segments = (SpinSegment *)XtMalloc(sizeof(SpinSegment) * nParticles);
250
winp =(PhaseWindow *) window;
251
doPoints = (winp->vectorLength == 0.);
253
points = (SpinPoint *)XtMalloc(sizeof(SpinPoint) * nParticles);
255
segments = (SpinSegment *)XtMalloc(sizeof(SpinSegment) * nParticles);
258
/* Loop over all of the particles, translating them into 3-D line segments
259
or points for the Spin widget. Also find the particle of maximum value
260
(for setting the scale and printing statistics), and the number of stable
261
particles (for printing statistics later) */
267
for (i=0, p=particles; i<nParticles; i++, p++) {
270
if (ParticleToSegment(winp, p, &temp, &length)) {
274
point->pixel = temp.pixel;
278
if (length > maxLength) {
284
/* Display the points */
285
SpinSetPoints(window->spin, points, nSegments);
286
XtFree((char *) points);
288
if (window->type == STDHEP_PHASE) {
290
for (i=0, p=particles; i<nParticles; i++, p++) {
293
if (ParticleToSegment(winp, p, segment, &length)) {
297
if (length > maxLength) {
303
} else if (window->type == STDHEP_PARA) {
305
for (i=0, p=particles; i<nParticles; i++, p++) {
308
if (ParticleToParaSegment(winpa, p, segment, &length)) {
312
if (length > maxLength) {
321
for (i=0, p=particles, v=wins->vertices;
322
i<nParticles; i++, p++, v++) {
325
if (TrackToSegment(wins, p, v, segment, &length)) {
329
if (length > maxLength) {
335
if (wins->nDetectorSegments > 0) {
336
for (i=0, segdt = wins->detectorSegments;
337
i < wins->nDetectorSegments;
338
i++, segdt++, segment++, nSegments++)
339
detectorToSegment(wins, segdt, segment);
341
if (wins->showVertices) {
342
for (i=0, pinv=wins->realVertices;
343
i < wins->numRealVertices; i++, pinv++){
344
if (fabs((double) pinv->z) < wins->currentScale) {
345
VertexToSegment(wins, pinv, &segment);
346
nSegments += NUMPINSPHI *NUMPINSTETA;
352
/* Display the line segments with the spin widget */
353
SpinSetSegments(window->spin, segments, nSegments);
354
XtFree((char *) segments);
356
* Currently, the spin widget Perspective resource is buggy,
359
SET_ONE_RSRC(window->spin, XmNperspectiveOn, FALSE);
361
/* If requested, set the scale to show the data most effectively */
363
SpinSetScale(window->spin, (maxLength > 0.) ? 1./maxLength : 1.);
367
/* Fill in the statistics window */
369
sprintf(statText, "%d tracks, %d are stable.\nNo Tracks are visible",
370
nParticles, nStable);
372
if ((window->type == STDHEP_PHASE) || (window->type == STDHEP_PARA)) {
373
GET_ONE_RSRC(window->statsLabel, XmNfontList, &fontList);
374
if (CharsetAvailable("greek", fontList)) {
375
hepnmg_(&particles[maxIndex].id, nameText);
377
hepnam_(&particles[maxIndex].id, nameText, MAXCHAR_HEPNAM);
378
*strchr(nameText, ' ') = '\0';
380
if (window->type == STDHEP_PHASE) {
382
"%d tracks, %d are stable,\n%d are now displayed\nTrack of max. %s is a(n) %s",
383
nParticles, nStable, nSegments,
384
unitText[winp->displayMode], nameText);
387
"%d tracks, %d are stable,\n%d are now displayed\nTrack of max. %s is a(n) %s",
388
nParticles, nStable, nSegments,
389
unitText[5], nameText);
392
if (wins->showVertices)
394
- (NUMPINSPHI * NUMPINSTETA * wins->numRealVertices);
395
else nns = nSegments;
397
"%d tracks, %d are stable,\n%d are now displayed\n %d distinct vertices found",
398
nParticles, nStable, nns, wins->numRealVertices);
401
cStatText = MultiFontString(statText);
402
SET_ONE_RSRC(window->statsLabel, XmNlabelString, cStatText);
403
XmStringFree(cStatText);
406
int ParticleToSegment(PhaseWindow *window, PhaseParticle *p,
407
SpinSegment *seg, double *length)
410
double scale, innerScale, outVec[3];
412
if (!ParticleVisible((StdHepWindow *) window, p->id, p->stable))
415
switch (window->displayMode) {
417
*length = ParticleMomentum(p->px, p->py, p->pz);
420
*length = ParticlePT(p->px, p->py);
423
*length = ParticleRapidity(p->px, p->py, p->pz, p->mass);
425
case BY_PSEUDORAPIDITY:
426
*length = ParticlePseudorapidity(p->px, p->py, p->pz);
428
/* case BY_USER_ROUTINE:
429
(*window->userMapProc)(window->event, outVec, &outColor);
430
*length = sqrt(pow(outVec[0],2) + pow(outVec[1],2) + pow(outVec[2],2));
433
if (window->displayMode == BY_USER_ROUTINE) {
437
seg->x2 = outVec[0] * (1. - window->vectorLength);
438
seg->y2 = outVec[0] * (1. - window->vectorLength);
439
seg->z2 = outVec[0] * (1. - window->vectorLength);
440
seg->pixel = ParticleColors[outColor];
442
scale = *length / ParticleMomentum(p->px, p->py, p->pz);
443
innerScale = scale * (1. - window->vectorLength);
444
seg->x1 = p->px * scale;
445
seg->y1 = p->py * scale;
446
seg->z1 = p->pz * scale;
447
seg->x2 = p->px * innerScale;
448
seg->y2 = p->py * innerScale;
449
seg->z2 = p->pz * innerScale;
450
seg->pixel = particlePixel(p->id);
455
int ParticleToParaSegment(ParaWindow *window, PhaseParticle *p,
456
SpinSegment *seg, double *length)
458
if (!ParticleVisible((StdHepWindow *) window, p->id, p->stable))
466
seg->z1 = window->currentTranslz -
467
( ParticleRapidity(p->px, p->py, p->pz, p->mass) *
468
window->currentRapToPt);
470
seg->z1 = window->currentTranslz +
471
( ParticleRapidity(p->px, p->py, p->pz, p->mass) *
472
window->currentRapToPt);
474
seg->pixel = particlePixel(p->id);
475
*length = ParticlePT(p->px, p->py);
479
int TrackToSegment(SpaceWindow *window, PhaseParticle *p, SpaceVertex *v,
480
SpinSegment *seg, double *length)
482
double scaleZ, scaleT;
484
if (!ParticleVisible((StdHepWindow *)window, p->id, p->stable))
487
scaleZ = window->currentMomToSpace;
488
scaleT = window->currentMomToSpace * window->currentLongToTr;
489
seg->x1 = window->currentLongToTr * v->x;
490
seg->y1 = window->currentLongToTr * v->y;
493
** Check now that we are in the visible range
496
if (fabs(seg->z1) > window->currentScale) return False;
500
seg->x1 = seg->x1 + window->currentLongToTr * window->currentTransl[0];
501
seg->y1 = seg->y1 + window->currentLongToTr * window->currentTransl[1];
502
seg->z1 = seg->z1 + window->currentTransl[2];
504
** The end of the tracks is set by the momentum
506
seg->x2 = seg->x1 + scaleT * p->px;
507
seg->y2 = seg->y1 + scaleT * p->py;
508
seg->z2 = seg->z1 + scaleZ * p->pz;
509
*length = sqrt ((seg->x2 * seg->x2) + (seg->y2 * seg->y2) +
510
(seg->z2 * seg->z2));
511
seg->pixel = particlePixel(p->id);
515
void VertexToSegment(SpaceWindow *window, SpaceVertex *v,
518
double scaleZ, scaleT;
524
screen = XtScreen(window->shell);
525
black = BlackPixelOfScreen(screen);
526
scaleZ = PINSIZE * window->maxTransl[2];
527
/* scaleT = PINSIZE * window->maxTransl[0]; */
529
for (i=0; i < NUMPINSTETA; i++) {
530
for (j=0; j < NUMPINSPHI; j++) {
531
segt->x1 = window->currentLongToTr * v->x;
532
segt->y1 = window->currentLongToTr * v->y;
537
segt->x1 = segt->x1 +
538
window->currentLongToTr * window->currentTransl[0];
539
segt->y1 = segt->y1 +
540
window->currentLongToTr * window->currentTransl[1];
541
segt->z1 = segt->z1 +
542
window->currentTransl[2];
544
** The end of the pins..
546
segt->x2 = segt->x1 + scaleZ * XPinVertexPoints[j][i];
547
segt->y2 = segt->y1 + scaleZ * YPinVertexPoints[j][i];
548
segt->z2 = segt->z1 + scaleZ * ZPinVertexPoints[j][i];
556
static void detectorToSegment(SpaceWindow *window, SpinSegment *segdt,
563
screen = XtScreen(window->shell);
564
black = BlackPixelOfScreen(screen);
566
seg->x1 = window->currentLongToTr * segdt->x1;
567
seg->y1 = window->currentLongToTr * segdt->y1;
569
seg->x2 = window->currentLongToTr * segdt->x2;
570
seg->y2 = window->currentLongToTr * segdt->y2;
576
window->currentLongToTr * window->currentTransl[0];
578
window->currentLongToTr * window->currentTransl[1];
580
window->currentTransl[2];
582
window->currentLongToTr * window->currentTransl[0];
584
window->currentLongToTr * window->currentTransl[1];
586
window->currentTransl[2];
592
void SetDisplayMode(PhaseWindow *window, int newMode)
594
int changeScale, oldMode = window->displayMode;
596
changeScale = (((newMode == BY_MOMENTUM || newMode == BY_PT) &&
597
(oldMode != BY_MOMENTUM && oldMode != BY_PT) ) ||
598
((newMode == BY_RAPIDITY || newMode == BY_PSEUDORAPIDITY) &&
599
(oldMode != BY_RAPIDITY && oldMode != BY_PSEUDORAPIDITY) ) ||
600
(newMode == BY_USER_ROUTINE && oldMode != BY_USER_ROUTINE));
601
window->displayMode = newMode;
602
DrawEvent((StdHepWindow *) window, changeScale);
605
void DrawScale(StdHepWindow *window)
607
Widget scaleWidget = window->scaleArea;
608
Window scaleWindow = XtWindow(scaleWidget);
609
Display *display = XtDisplay(scaleWidget);
610
double scale, scaleAreaWidth, scaleBarLength = 1., barMultiplier = 2.;
612
short widgetWidth, spinWidth, widgetHeight;
613
int leftX, rightX, topY, midY, bottomY;
614
GC gc = window->scaleGC;
622
/* Get the scale factor for translating spin coordinates to pixels */
623
GET_ONE_RSRC(window->spin, XmNwidth, &spinWidth);
624
scale = (1./(SpinGetScale(window->spin)/2.)) / (double)spinWidth;
626
/* Calculate the width of the scale draw area in spin coordinates */
627
GET_ONE_RSRC(scaleWidget, XmNwidth, &widgetWidth);
628
scaleAreaWidth = widgetWidth * scale;
630
/* choose a sensible length for the scale bar, such as 1, 5, 10, 50 etc. */
631
if (scaleAreaWidth < 1.) {
632
while (scaleBarLength > scaleAreaWidth) {
633
scaleBarLength /= barMultiplier;
634
barMultiplier = (barMultiplier == 2.) ? 5. : 2.;
637
while (scaleBarLength < scaleAreaWidth) {
638
barMultiplier = (barMultiplier == 2.) ? 5. : 2.;
639
scaleBarLength *= barMultiplier;
641
scaleBarLength /= barMultiplier;
644
/* draw the scale bar in the middle of the scale area widget */
645
GET_ONE_RSRC(scaleWidget, XmNheight, &widgetHeight);
646
leftX = ((scaleAreaWidth - scaleBarLength) / 2.) / scale;
647
rightX = leftX + scaleBarLength / scale;
648
topY = widgetHeight/4;
649
midY = widgetHeight/2;
650
bottomY = midY + widgetHeight/4;
651
XClearWindow(display, scaleWindow);
652
XDrawLine(display, scaleWindow, gc, leftX, topY, leftX, bottomY);
653
XDrawLine(display, scaleWindow, gc, rightX, topY, rightX, bottomY);
654
XDrawLine(display, scaleWindow, gc, leftX, midY, rightX, midY);
656
/* put in the text to label the scale */
657
if (window->type == STDHEP_PHASE) {
658
winp = (PhaseWindow *) window;
659
if (winp->displayMode == BY_MOMENTUM || winp->displayMode == BY_PT)
660
sprintf(scaleText, "%G Gev/c", scaleBarLength);
662
sprintf(scaleText, "%G Unit Eta", scaleBarLength);
663
} else if (window->type == STDHEP_PARA) {
664
winpa = (ParaWindow *) window;
665
scaleVertex = scaleBarLength / winpa->currentRapToPt;
666
sprintf (scaleText, "%G eta = %G Gev/c",scaleBarLength, scaleVertex);
669
wins = (SpaceWindow *) window;
670
tempMom = wins->currentMomToSpace;
671
if( tempMom == 0.0) tempMom = EPSILON;
672
scaleVertex = scaleBarLength / tempMom;
673
sprintf (scaleText, "%G cm = %G Gev/c",scaleBarLength, scaleVertex);
675
cScaleText = MKSTRING(scaleText);
676
SET_ONE_RSRC(window->scaleLabel, XmNlabelString, cScaleText);
677
XmStringFree(cScaleText);
681
static Pixel allocRGB(Screen *screen,
682
unsigned short red, unsigned short green, unsigned short blue)
684
Display *display = DisplayOfScreen(screen);
690
if (XAllocColor(display, DefaultColormapOfScreen(screen), &color))
693
return BlackPixelOfScreen(screen);
696
int ParticleVisible(StdHepWindow *window, long id, int stable)
698
long absID = abs(id);
699
float charge = stdchg_(&id);
701
if (stable && !window->stable)
703
if (!stable && !window->unstable)
706
if ((fabs(charge) < 0.1) && !window->neutral)
708
if ((fabs(charge) > 0.1) && !window->charged)
711
if (absID == 11 && !window->electrons)
713
if (absID == 13 && !window->muons)
715
if ((absID == 12 || absID == 14 || absID == 16) && !window->neutrinos)
717
if ((absID <= 6 || absID == 9 || absID == 21) && !window->quarks)
719
if ((absID == 23 || absID == 24) && !window->wz)
721
if (absID == 22 && !window->gammas)
723
if (absID >= 100 && !window->hadrons)
728
static Pixel particlePixel(int particleID)
730
return ParticleColors[ParticleColorIndex(particleID)];
733
int ParticleColorIndex(int particleID)
735
long absID = abs(particleID);
736
long i, aid, kq[3], kqj;
737
double akqx, akq3, akq2, akq1, akqj;
740
** For non hadrons, return the particle id as the color
743
if (absID > (MAXPARTCOLOR - 1))
744
return MAXPARTCOLOR - 1;
749
** For hadrons, return the largest digit? (ask paul...)
751
akqj = ((double)absID)/10.;
755
kq[0] = aid - ((long)akq1) * 10;
759
kq[1] = aid - ((long)akq2) * 10;
763
kq[2] = aid - ((long)akq3) * 10;
767
if (kq[i] > kqj) kqj = kq[i];
769
if (kqj > (MAXPARTCOLOR-1))
770
return MAXPARTCOLOR-1;
775
double ParticleMomentum(double px, double py, double pz)
777
double pTmp = sqrt(SQR(px) + SQR(py) + SQR(pz));
778
if (pTmp == 0.0) return EPSILON;
782
double ParticlePT(double px, double py)
784
return sqrt(SQR(px) + SQR(py));
787
double ParticleRapidity(double px, double py, double pz, double mass)
791
p = ParticleMomentum(px, py, pz);
792
e = sqrt(p*p + mass*mass);
793
return fabs(0.5*log(fabs((e+pz+0.0001)/(e-pz+0.0000001))));
796
double ParticlePseudorapidity(double px, double py, double pz)
800
p = ParticleMomentum(px, py, pz);
801
pt = ParticlePT(px,py);
802
teta = acos(pz/(p+ 0.00001));
803
return fabs(log(fabs(tan(0.5*teta))));