pulsaranimationwidget.cpp 21.9 KB
Newer Older
Oliver Bock's avatar
Oliver Bock committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/******************************************************************************
 *   Copyright (C) 2008 by Oliver Bock                                        *
 *   oliver.bock[AT]aei.mpg.de                                                *
 *                                                                            *
 *   This file is part of PulsatingScience.                                   *
 *                                                                            *
 *   PulsatingScience is free software: you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published        *
 *   by the Free Software Foundation, version 3 of the License.               *
 *                                                                            *
 *   PulsatingScience is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the             *
 *   GNU General Public License for more details.                             *
 *                                                                            *
 *   You should have received a copy of the GNU General Public License        *
 *   along with PulsatingScience. If not, see <http://www.gnu.org/licenses/>. *
 *                                                                            *
 ******************************************************************************/

#include "pulsaranimationwidget.h"
22
#include "lib/antenna_lib.h"
Oliver Bock's avatar
Oliver Bock committed
23

24
25
#include <QPainter>

Oliver Bock's avatar
Oliver Bock committed
26
const double PulsarAnimationWidget::deg2rad = PI/180.0;
27

Oliver Bock's avatar
Oliver Bock committed
28
PulsarAnimationWidget::PulsarAnimationWidget(QWidget *parent) :
29
    QOpenGLWidget(parent)
Oliver Bock's avatar
Oliver Bock committed
30
{
31

Oliver Bock's avatar
Oliver Bock committed
32
    // initialize quadric pointers
Oliver Bock's avatar
Oliver Bock committed
33
34
    m_quadricVirgoh = NULL;
    m_quadricVirgov = NULL;
Oliver Bock's avatar
Oliver Bock committed
35
    m_quadricEarth = NULL;
Oliver Bock's avatar
Oliver Bock committed
36
37
    m_quadricLLOh = NULL;
    m_quadricLLOv = NULL;
Oliver Bock's avatar
Oliver Bock committed
38
39
40
    m_quadricSourcePlane = NULL;
    m_quadricSourcePlaneNormal = NULL;
    m_quadricSourcePlaneNormalCap = NULL;
41
    m_quadricSourcePlaneNormalCenter = NULL;
42
43
    m_quadricLHOv = NULL;
    m_quadricLHOh = NULL;
44
45

    // initialize texture pointers
46
    m_beamTexture = 0;
47

48
    // initial parameters (have to match GUI!)
49
50
51
    m_LHOAngle = 0;
    m_LLOAngle = 0;
    m_VirgoAngle = 0;
Oliver Bock's avatar
Oliver Bock committed
52
    m_sourceIota = 0.0;
53
    m_sourceInclination = 0;
54

Oliver Bock's avatar
Oliver Bock committed
55
    m_earthRadius = 3.0;
56

57
58
59
60
    // initial view features
    m_cameraInteraction = false;

    // initial view settings
61
62
    m_mouseAngleH = -55.0;
    m_mouseAngleV = 20.0;
63
    m_cameraZoom = 100.0;
64
65
66
67
68
69
70
    m_cameraZoomLBound = 10.0;
    m_cameraZoomUBound = 4500.0;
    m_mouseLastX = 0;
    m_mouseLastY = 0;

    // update camera based on settings above
    updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
Oliver Bock's avatar
Oliver Bock committed
71
72
73
74
}

PulsarAnimationWidget::~PulsarAnimationWidget()
{
Oliver Bock's avatar
Oliver Bock committed
75
76
    if(m_quadricVirgoh) gluDeleteQuadric(m_quadricVirgoh);
    if(m_quadricVirgov) gluDeleteQuadric(m_quadricVirgov);
Oliver Bock's avatar
Oliver Bock committed
77
    if(m_quadricEarth) gluDeleteQuadric(m_quadricEarth);
Oliver Bock's avatar
Oliver Bock committed
78
79
    if(m_quadricLLOh) gluDeleteQuadric(m_quadricLLOh);
    if(m_quadricLLOv) gluDeleteQuadric(m_quadricLLOv);
Oliver Bock's avatar
Oliver Bock committed
80
81
82
    if(m_quadricSourcePlane) gluDeleteQuadric(m_quadricSourcePlane);
    if(m_quadricSourcePlaneNormal) gluDeleteQuadric(m_quadricSourcePlaneNormal);
    if(m_quadricSourcePlaneNormalCap) gluDeleteQuadric(m_quadricSourcePlaneNormalCap);
83
    if(m_quadricSourcePlaneNormalCenter) gluDeleteQuadric(m_quadricSourcePlaneNormalCenter);
84
85
    if(m_quadricLHOv) gluDeleteQuadric(m_quadricLHOv);
    if(m_quadricLHOh) gluDeleteQuadric(m_quadricLHOh);
Oliver Bock's avatar
Oliver Bock committed
86
87
88
89
}

void PulsarAnimationWidget::initializeGL()
{
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearDepth(1.0);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    glShadeModel(GL_SMOOTH);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    GLfloat LightAmbient[] = {0.3, 0.3, 0.3, 1.0};
    GLfloat LightDiffuse[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat LightSpecular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat LightPosition[] = {0.0, 0.0, 3.0, 1.0};
    GLfloat spot_direction[] = {0.0, 0.0, -1.0};

    glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpecular);
    glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 50.0);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
    glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0);

    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
    glEnable(GL_LIGHT0);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

Oliver Bock's avatar
Oliver Bock committed
118
119
    m_quadricVirgoh = gluNewQuadric();
    m_quadricVirgov = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
120
    m_quadricEarth = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
121
122
    m_quadricLLOh = gluNewQuadric();
    m_quadricLLOv = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
123
124
125
    m_quadricSourcePlane = gluNewQuadric();
    m_quadricSourcePlaneNormal = gluNewQuadric();
    m_quadricSourcePlaneNormalCap = gluNewQuadric();
126
    m_quadricSourcePlaneNormalCenter = gluNewQuadric();
127
128
    m_quadricLHOv = gluNewQuadric();
    m_quadricLHOh = gluNewQuadric();
129

Oliver Bock's avatar
Oliver Bock committed
130
131
    gluQuadricNormals(m_quadricVirgoh, GLU_SMOOTH);
    gluQuadricNormals(m_quadricVirgov, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
132
    gluQuadricNormals(m_quadricEarth, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
133
134
    gluQuadricNormals(m_quadricLLOh, GLU_SMOOTH);
    gluQuadricNormals(m_quadricLLOv, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
135
136
137
    gluQuadricNormals(m_quadricSourcePlane, GLU_SMOOTH);
    gluQuadricNormals(m_quadricSourcePlaneNormal, GLU_SMOOTH);
    gluQuadricNormals(m_quadricSourcePlaneNormalCap, GLU_SMOOTH);
138
    gluQuadricNormals(m_quadricSourcePlaneNormalCenter, GLU_SMOOTH);
139
140
    gluQuadricNormals(m_quadricLHOv, GLU_SMOOTH);
    gluQuadricNormals(m_quadricLHOh, GLU_SMOOTH);
141

Oliver Bock's avatar
Oliver Bock committed
142
143
144
145
    // query max texture size (estimate)
    GLint maxTextureSize;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);

146
    // prepare and bind beam texture
147
    QImage beamTexture(":/textures/resources/World-Map-7.jpg");
148
    m_beamTexture = new QOpenGLTexture(beamTexture.mirrored());
149

150
    // use mipmapped textures
151
152
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Oliver Bock's avatar
Oliver Bock committed
153
154
155
156
}

void PulsarAnimationWidget::resizeGL(int w, int h)
{
157
    glViewport(0, 0, w, h);
Oliver Bock's avatar
Oliver Bock committed
158

159
160
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
Oliver Bock's avatar
Oliver Bock committed
161

162
    gluPerspective(4.5, (GLfloat)w / (GLfloat)h, 0.1, 5000.0);
Oliver Bock's avatar
Oliver Bock committed
163

164
165
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
Oliver Bock's avatar
Oliver Bock committed
166
167
168
169
}

void PulsarAnimationWidget::paintGL()
{
170
171
    GLfloat x,y,angle;

172
173
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

174
175
    // TODO: should be located elsewhere
    static GLfloat no_mat[] = {0.0, 0.0, 0.0, 1.0};
176
    static GLfloat mat_diffuse[] = {0.0, 0.0, 0.5, 1.0};
177
178
179
180
181
182
183
184
185
186
    static GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
    static GLfloat low_shininess[] = {2.5};
    static GLfloat translucent[] = {1.0, 1.0, 1.0, 0.33};

    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);

187
188
189
190
191
192
193
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    gluLookAt(m_cameraPosX, m_cameraPosY, m_cameraPosZ,
              0.0, 0.0, 0.0,
              0.0, 1.0, 0.0);

194
195
196
197
198
199
200
201
202
203
204
205
    // save current state (the following is using parallel projection)
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    {
        glLoadIdentity();
        glOrtho(0, width(), 0, height(), 0.1, 501.0);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        {
            glLoadIdentity();

            // draw backdrop (independent parallel projection)
206
            glColor3f(1.0, 1.0, 1.0f);
207
208
209
210
211
212
213
214
215
216
            glTranslatef(0.0, 0.0, -501.0);

            // restore original state
            glMatrixMode(GL_PROJECTION);
        }
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
    }
    glPopMatrix();

Oliver Bock's avatar
Oliver Bock committed
217
    // draw earth
218
    glPushMatrix();
219
    {
220
        glRotatef(90, 0.0, 1.0, 0.0);
221
        glPushMatrix();
222
223
        {
            glRotatef(90, 1.0, 0.0, 0.0);
224
225
            glRotatef(180, 1.0, 1.0, 0.0);

226
227
228
229
            glDisable(GL_DEPTH_TEST);
            glEnable(GL_CULL_FACE);
            glColor4f(1.0, 1.0, 1.0f, 0.8f);

230
            // create texture coordinates and enable texturing
Oliver Bock's avatar
Oliver Bock committed
231
            gluQuadricTexture(m_quadricEarth, GL_TRUE);
232
            m_beamTexture->bind();
233
            glEnable(GL_TEXTURE_2D);
234

235
236
237
            glCullFace(GL_FRONT);
            gluSphere(m_quadricEarth, m_earthRadius, 32, 32);
            glCullFace(GL_BACK);
Oliver Bock's avatar
Oliver Bock committed
238
            gluSphere(m_quadricEarth, m_earthRadius, 32, 32);
239
240
241

            glDisable(GL_CULL_FACE);
            glEnable(GL_DEPTH_TEST);
242
243
        }
        glPopMatrix();
244
245
    }
    glPopMatrix();
246

247
248
249
250
251
    // draw LHO
    glPushMatrix();
    {
        glColor3f(1.0f, 1.0f, 1.0f);

252
253
254
        glRotatef(-48.455144, 0.0, 0.0, 1.0);
        glRotatef(-110.407656, 0.0, 1.0, 0.0);

Oliver Bock's avatar
Oliver Bock committed
255
        glTranslatef(0.0, 0.0, m_earthRadius);
256

257
        glRotatef(m_LHOAngle+180, 0.0, 0.0, 1.0);
258
259
260
        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
261
            gluCylinder(m_quadricLHOh, 0.020, 0.020, 0.40, 32, 1);
262
263
264
265
266
267
268
        }
        glPopMatrix();

        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            glRotatef(90, 1.0, 0.0, 0.0);
269
270
            glColor3f(0.0f, 0.0f, 1.0f);
            gluCylinder(m_quadricLHOv, 0.020, 0.020, 0.40, 32, 1);
271
272
273
274
275
        }
        glPopMatrix();
    }
    glPopMatrix();

Oliver Bock's avatar
Oliver Bock committed
276
277
278
279
280
    // draw LLO
    glPushMatrix();
    {
        glColor3f(1.0f, 1.0f, 1.0f);

281
282
283
        glRotatef(-30.562894, 0.0, 0.0, 1.0);
        glRotatef(-90.774242, 0.0, 1.0, 0.0);

Oliver Bock's avatar
Oliver Bock committed
284
        glTranslatef(0.0, 0.0, m_earthRadius);
285

286
        glRotatef(m_LLOAngle-90, 0.0, 0.0, 1.0);
Oliver Bock's avatar
Oliver Bock committed
287
288
289
        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
290
            gluCylinder(m_quadricLLOh, 0.020, 0.020, 0.40, 32, 1);
Oliver Bock's avatar
Oliver Bock committed
291
292
293
294
295
296
297
        }
        glPopMatrix();

        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            glRotatef(90, 1.0, 0.0, 0.0);
298
299
            glColor3f(1.0f, 0.0f, 0.0f);
            gluCylinder(m_quadricLLOv, 0.020, 0.020, 0.40, 32, 1);
Oliver Bock's avatar
Oliver Bock committed
300
301
302
303
304
        }
        glPopMatrix();
    }
    glPopMatrix();

Oliver Bock's avatar
Oliver Bock committed
305
306
307
308
309
    // draw Virgo
    glPushMatrix();
    {
        glColor3f(1.0f, 1.0f, 1.0f);

310
311
312
        glRotatef(-45.6305, 1.0, 0.0, 0.0);
        glRotatef(7.5021, 0.0, 1.0, 0.0);

Oliver Bock's avatar
Oliver Bock committed
313
        glTranslatef(0.0, 0.0, m_earthRadius);
314

315
        glRotatef(m_VirgoAngle+165, 0.0, 0.0, 1.0);
Oliver Bock's avatar
Oliver Bock committed
316
317
318
        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
319
            gluCylinder(m_quadricVirgoh, 0.020, 0.020, 0.40, 32, 1);
Oliver Bock's avatar
Oliver Bock committed
320
321
322
323
324
325
326
        }
        glPopMatrix();

        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            glRotatef(90, 1.0, 0.0, 0.0);
327
328
            glColor3f(0.0f, 1.0f, 0.0f);
            gluCylinder(m_quadricVirgov, 0.020, 0.020, 0.40, 32, 1);
Oliver Bock's avatar
Oliver Bock committed
329
330
331
332
333
        }
        glPopMatrix();
    }
    glPopMatrix();

334
    // draw source
335
    glPushMatrix();
336
    {
337
338
339
340
        // The second rotation isn't right:
        // -> should be around x-axis (not z) and not mess up source iota from below!
        // -> does the x-axis not rotate with its object (around the first y-rotation)?
        // -> putting them in their own matrix doesn't help either
341
342
        glRotatef(-31.384, 0.0, 0.0, 1.0);
        glRotatef(45.093, 0.0, 1.0, 0.0);
343

Oliver Bock's avatar
Oliver Bock committed
344
        glTranslatef(0.0, 0.0, m_earthRadius + 2.0);
345

346
        glPushMatrix();
347
        {
348
            glRotatef(-m_sourceInclination+23.5, 0.0, 0.0, 1.0);
349
            glRotatef(180, 0.0, 1.0, 0.0);
Oliver Bock's avatar
Oliver Bock committed
350
            glRotatef(m_sourceIota, 0.0, 1.0, 0.0);
351

Oliver Bock's avatar
Oliver Bock committed
352
353
354
355
            // draw source plane normal
            glColor3f(1.0f, 0.0f, 0.0f);
            glPushMatrix();
            {
356
                glTranslatef(0.0, 0.0, -1.0);
Oliver Bock's avatar
Oliver Bock committed
357
                gluCylinder(m_quadricSourcePlaneNormal, 0.020, 0.020, 1.5, 32, 1);
Oliver Bock's avatar
Oliver Bock committed
358
359
360
361
            }
            glPopMatrix();
            glPushMatrix();
            {
362
                glTranslatef(0.0, 0.0, -1.0);
Oliver Bock's avatar
Oliver Bock committed
363
                gluDisk(m_quadricSourcePlaneNormalCap, 0, 0.020, 32, 8);
Oliver Bock's avatar
Oliver Bock committed
364
365
366
367
            }
            glPopMatrix();
            glPushMatrix();
            {
368
                glTranslatef(0.0, 0.0, 0.5f);
Oliver Bock's avatar
Oliver Bock committed
369
                glBegin(GL_TRIANGLE_FAN);
Oliver Bock's avatar
Oliver Bock committed
370
                {
Oliver Bock's avatar
Oliver Bock committed
371
372
                    // Pinnacle of cone is shared vertex for fan, moved up z-axis
                    // to produce a cone instead of a circle
373
                    glVertex3f(0.0f, 0.0f, 0.5f);
Oliver Bock's avatar
Oliver Bock committed
374
375
376
377

                    // Loop around in a circle and specify even points along the circle
                    // as the vertices of the triangle fan (32 sections)
                    for(angle = 0.0f; angle < (2.0f*PI); angle += (PI/32.0f))
Oliver Bock's avatar
Oliver Bock committed
378
                    {
Oliver Bock's avatar
Oliver Bock committed
379
                        // Calculate x and y position of the next vertex
380
381
                        x = 0.1f * sin(angle);
                        y = 0.1f * cos(angle);
Oliver Bock's avatar
Oliver Bock committed
382
383
384

                        // Specify the next vertex for the triangle fan
                        glVertex2f(x, y);
Oliver Bock's avatar
Oliver Bock committed
385
386
                    }
                }
Oliver Bock's avatar
Oliver Bock committed
387
                glEnd();
388
            }
Oliver Bock's avatar
Oliver Bock committed
389
            glPopMatrix();
390
391
392
393
394
395
            glColor3f(1.0f, 1.0f, 1.0f);
            glPushMatrix();
            {
                gluSphere(m_quadricSourcePlaneNormalCenter, 0.040, 32, 32);
            }
            glPopMatrix();
396

397
398
            // draw disc
            glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
399
400
            glEnable(GL_LIGHTING);

401
            glPushMatrix();
402
            {
Oliver Bock's avatar
Oliver Bock committed
403
                gluDisk(m_quadricSourcePlane,
404
                        0,
405
                        1.0,
406
                        64, 1);
407
408
409
            }
            glPopMatrix();

410
            glDisable(GL_LIGHTING);
411
        }
412
413
        glPopMatrix();
    }
414
    glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

    // save current state (the following is using parallel projection)
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    {
        glLoadIdentity();
        glOrtho(0, width(), 0, height(), 0.1, 501.0);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        {
            glLoadIdentity();

            // draw copyright info last (appears in front of everything)
            glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
            QFont font;
430
            font.setPointSize(14);
Oliver Bock's avatar
Oliver Bock committed
431
432
433
            font.setBold(true);
            font.setFamily("Arial");
            font.setStyleStrategy((QFont::StyleStrategy) (QFont::OpenGLCompatible | QFont::PreferQuality));
434
435
436
437
            renderText(0, 0, -100, tr("B. Allen and O. Bock"), font);
//            renderText(10, 25, -100, tr("MPI for Gravitational Physics"));
//            renderText(10, 10, -100, QString("Copyright %1 2017").arg(QChar(0x00A9)));

Oliver Bock's avatar
Oliver Bock committed
438
439
440
441
442
443
444
            // restore original state
            glMatrixMode(GL_PROJECTION);
        }
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
    }
    glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
445
446
}

447
448
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
449
    Q_UNUSED(event);
450

451
    m_cameraInteraction = true;
452
    update();
453
454
}

455
456
void PulsarAnimationWidget::mouseMoveEvent(QMouseEvent *event)
{
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
    Qt::MouseButtons buttons = event->buttons();
    if((buttons & Qt::LeftButton) == Qt::LeftButton) {
        if(m_mouseLastX != 0) {
            m_mouseAngleH += (m_mouseLastX - event->x());
            m_mouseAngleH = m_mouseAngleH < 360 ? m_mouseAngleH : 0;
            m_mouseAngleH = m_mouseAngleH >=  0 ? m_mouseAngleH : 359;
        }
        if(m_mouseLastY != 0) {
            m_mouseAngleV -= (m_mouseLastY - event->y());
            m_mouseAngleV = m_mouseAngleV <  90 ? m_mouseAngleV : 90;
            m_mouseAngleV = m_mouseAngleV > -90 ? m_mouseAngleV : -90;
        }

        m_mouseLastX = event->x();
        m_mouseLastY = event->y();
    }
    else if((buttons & Qt::RightButton) == Qt::RightButton) {
        if(m_mouseLastY != 0) {
            m_cameraZoom -= (m_mouseLastY - event->y());
            m_cameraZoom = m_cameraZoom >= m_cameraZoomLBound ? m_cameraZoom : m_cameraZoomLBound;
            m_cameraZoom = m_cameraZoom >= m_cameraZoomUBound ? m_cameraZoomUBound : m_cameraZoom;
        }

        m_mouseLastY = event->y();
    }

    updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
484
485
486
487
}

void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event)
{
488
    Q_UNUSED(event);
489

490
491
492
    m_mouseLastX = 0;
    m_mouseLastY = 0;
    m_cameraInteraction = false;
493

494
    update();
495
496
}

Oliver Bock's avatar
Oliver Bock committed
497
498
void PulsarAnimationWidget::showEvent(QShowEvent *event)
{
499
    Q_UNUSED(event);
Oliver Bock's avatar
Oliver Bock committed
500

501
502
    // update and propagate pulse profile
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
503
504
}

Oliver Bock's avatar
Oliver Bock committed
505
void PulsarAnimationWidget::updateCameraPosition(const double angleH, const double angleV, const double zoom)
506
{
507
508
509
    m_cameraPosX = sin(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
    m_cameraPosY = sin(angleV * deg2rad) * zoom;
    m_cameraPosZ = cos(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
510

511
    update();
512
513
}

514
void PulsarAnimationWidget::setSourceInclination(const double degrees)
Oliver Bock's avatar
Oliver Bock committed
515
{
516
517
518
519
520
521
522
523

   // This sign convention differs from my notes.  In my notes,
   // increasing psi means that the orbital ellipse rotates CCW when
   // viewed from above.  But the convention in LAL is that increasing
   // psi rotates the ellipse CCW when viewed from Earth, and CW when
   // viewed from above.  So I have adjusted this code to be
   // consistent with LAL, and inserted a factor of -1 in my code.
   // Bruce
524
    m_sourceInclination = degrees;
525
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
526

527
    update();
Oliver Bock's avatar
Oliver Bock committed
528
}
529

Oliver Bock's avatar
Oliver Bock committed
530
void PulsarAnimationWidget::setLHOAngle(const double degrees)
531
{
532
    m_LHOAngle = degrees;
533
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
534

535
    update();
536
537
}

538
void PulsarAnimationWidget::setLLOAngle(const double degrees)
539
{
540
    m_LLOAngle = degrees;
541
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
542

543
    update();
Oliver Bock's avatar
Oliver Bock committed
544
545
}

546
void PulsarAnimationWidget::setVirgoAngle(const int degrees)
Oliver Bock's avatar
Oliver Bock committed
547
{
548
    m_VirgoAngle = degrees;
549
    updatePulseProfile();
550

551
    update();
552
553
}

Oliver Bock's avatar
Oliver Bock committed
554
void PulsarAnimationWidget::setSourceIota(const int degrees)
555
{
Oliver Bock's avatar
Oliver Bock committed
556
    m_sourceIota = degrees;
557
    updatePulseProfile();
558

559
    update();
560
}
561

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
void PulsarAnimationWidget::getCameraPosition(double& cameraAngleH, double& cameraAngleV, double& cameraZoom)
{
    cameraAngleH = m_mouseAngleH;
    cameraAngleV = m_mouseAngleV;
    cameraZoom = m_cameraZoom;
}

void PulsarAnimationWidget::resetCameraPosition(const double angleH, const double angleV, const double zoom)
{
    m_mouseAngleH = angleH;
    m_mouseAngleV = angleV;
    m_cameraZoom = zoom;

    updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}

578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
void PulsarAnimationWidget::renderText(double x, double y, double z, const QString &text, const QFont & font) {
    // Identify x and y locations to render text within widget
    int height = this->height();
    GLdouble textPosX = 0, textPosY = 0, textPosZ = 0;
//    project(x, y, 0f, &textPosX, &textPosY, &textPosZ);
    textPosY = height - textPosY; // y is inverted

    // Retrieve last OpenGL color to use as a font color
    GLdouble glColor[4];
    glGetDoublev(GL_CURRENT_COLOR, glColor);
    QColor fontColor = QColor(glColor[0], glColor[1], glColor[2], glColor[3]);

    // save OpenGL state
    glPushAttrib(GL_ACCUM_BUFFER_BIT);
    glPushAttrib(GL_COLOR_BUFFER_BIT);
    glPushAttrib(GL_CURRENT_BIT);
    glPushAttrib(GL_DEPTH_BUFFER_BIT);
    glPushAttrib(GL_ENABLE_BIT);
    glPushAttrib(GL_EVAL_BIT);
    glPushAttrib(GL_FOG_BIT);
    glPushAttrib(GL_HINT_BIT);
    glPushAttrib(GL_FOG_BIT);
    glPushAttrib(GL_LIGHTING_BIT);
    glPushAttrib(GL_LINE_BIT);
    glPushAttrib(GL_LIST_BIT);
    glPushAttrib(GL_MULTISAMPLE_BIT);
    glPushAttrib(GL_PIXEL_MODE_BIT);
    glPushAttrib(GL_POINT_BIT);
    glPushAttrib(GL_POLYGON_BIT);
    glPushAttrib(GL_POLYGON_STIPPLE_BIT);
    glPushAttrib(GL_SCISSOR_BIT);
    glPushAttrib(GL_STENCIL_BUFFER_BIT);
    glPushAttrib(GL_TEXTURE_BIT);
    glPushAttrib(GL_TRANSFORM_BIT);
    glPushAttrib(GL_VIEWPORT_BIT);
    glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);

    // Render text
    QPainter painter(this);
    painter.setPen(fontColor);
    painter.setFont(font);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    painter.drawText(textPosX, textPosY, text);
    painter.end();

    // save OpenGL state
    glPopAttrib();
    glPopClientAttrib();
}

628
629
void PulsarAnimationWidget::updatePulseProfile()
{
630
631
632
633
    struct InputStruct in;
    struct OutputStruct out;

    in.iota = m_sourceIota;
634
635
636
637
638
639
640
641

    // This sign convention for in.psi differs from my notes.  In my
    // notes, increasing psi means that the orbital ellipse rotates
    // CCW when viewed from above.  But the convention in LAL is that
    // increasing psi rotates the ellipse CCW when viewed from Earth,
    // and CW when viewed from above.  So I have adjusted this code to
    // be consistent with LAL, and inserted a factor of -1 in my code.
    // Bruce
642
643
644
645
646
    in.psi = m_sourceInclination;
    in.orientation[0] = m_LLOAngle;
    in.orientation[1] = m_LHOAngle;
    in.orientation[2] = m_VirgoAngle;

Oliver Bock's avatar
Oliver Bock committed
647
    // get actual detector data
648
649
    get_antenna(&out, &in);

Oliver Bock's avatar
Oliver Bock committed
650
    // populate plot data object
651
652
653
654
655
656
657
658
659
660
    
    // suppose that the initial frequency is 30 Hz and dx is the
    // amount of x range in one cycle.  That means that dx freq0= 360
    // => dx = 360/freq0 = 30ms.  Hence freq0 = 360/30ms.  The phase
    // delay in degrees caused by the offset in arrival time will then
    // be phase_delay_degrees = freq0 * out.dt = 360*out.dt/30ms.  The
    // x delay is then freq0*dx=360*out.dt/30ms => dx =
    // 360*out.dt/(freq0*30ms).

    double freq0 = 1.0/pow(1.1,0.375);
661
662
    double dx[3];
    
Bruce Allen's avatar
Bruce Allen committed
663
    for (int i=0; i<3; i++) dx[i]=360*out.dt[i]/(30.0*freq0);
664
    
665
    for(int x = 0; x < 360*PERIODS; ++x) {
666
667
       double t=x/(PERIODS*360.0);
       double freq = 1.0/pow(1.1-t,0.375);
Bruce Allen's avatar
Bruce Allen committed
668
669
670
       m_plotData.m_dataLLO[x]   = 0.8 * out.amp[0] * freq * freq * sin((freq*(x + dx[0]) + out.phase[0]) * deg2rad);
       m_plotData.m_dataLHO[x]   = 0.8 * out.amp[1] * freq * freq * sin((freq*(x + dx[1]) + out.phase[1]) * deg2rad);
       m_plotData.m_dataVirgo[x] = 0.8 * out.amp[2] * freq * freq * sin((freq*(x + dx[2]) + out.phase[2]) * deg2rad);
671
672
    }

Oliver Bock's avatar
Oliver Bock committed
673
674
675
676
677
678
679
680
681
682
683
684
685
    m_plotData.m_ampLLO   = out.amp[0];
    m_plotData.m_ampLHO   = out.amp[1];
    m_plotData.m_ampVirgo = out.amp[2];

    m_plotData.m_phiLLO   = out.phase[0];
    m_plotData.m_phiLHO   = out.phase[1];
    m_plotData.m_phiVirgo = out.phase[2];

    m_plotData.m_dtLLO   = out.dt[0];
    m_plotData.m_dtLHO   = out.dt[1];
    m_plotData.m_dtVirgo = out.dt[2];

    // propagate new plot data
686
    emit pulseProfileUpdated(m_plotData);
687
}