pulsaranimationwidget.cpp 24.2 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
22
/******************************************************************************
 *   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"

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

Oliver Bock's avatar
Oliver Bock committed
25
PulsarAnimationWidget::PulsarAnimationWidget(QWidget *parent) :
26
27
28
    QGLWidget(QGLFormat(QGL::AlphaChannel | QGL::SampleBuffers), parent),
    m_frameTimer(),
    m_pulseProfile(360, 0.0)
Oliver Bock's avatar
Oliver Bock committed
29
{
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    QString msgThis = tr("3D animation");
    if(!format().directRendering()) {
        QString msg = tr("Sorry, no direct rendering support for %1...");
        qWarning() << msg.arg(msgThis);
    }
    if(!format().doubleBuffer()) {
        QString msg = tr("Sorry, no double buffering support for %1...");
        qWarning() << msg.arg(msgThis);
    }
    if(!format().rgba()) {
        QString msg = tr("Sorry, no RGBA support for %1...");
        qWarning() << msg.arg(msgThis);
    }
    if(!format().alpha()) {
        QString msg = tr("Sorry, no alpha channel support for %1...");
        qWarning() << msg.arg(msgThis);
    }
    if(!format().sampleBuffers()) {
        QString msg = tr("Sorry, no multisampling support for %1...");
        qWarning() << msg.arg(msgThis);
    }

    // connect primary rendering timer to local callback
Oliver Bock's avatar
Oliver Bock committed
53
    connect(&m_frameTimer, SIGNAL(timeout()), this, SLOT(updateFrame()));
Oliver Bock's avatar
Oliver Bock committed
54

Oliver Bock's avatar
Oliver Bock committed
55
    // initialize quadric pointers
Oliver Bock's avatar
Oliver Bock committed
56
57
    m_quadricVirgoh = NULL;
    m_quadricVirgov = NULL;
58
    m_quadricPulsarOrbitPlane = NULL;
Oliver Bock's avatar
Oliver Bock committed
59
    m_quadricPulsar = NULL;
Oliver Bock's avatar
Oliver Bock committed
60
61
    m_quadricLLOh = NULL;
    m_quadricLLOv = NULL;
62
    m_quadricPulsarSpinAxis = NULL;
63
    m_quadricPulsarSpinAxisTop1 = NULL;
64
65
    m_quadricLHOv = NULL;
    m_quadricLHOh = NULL;
66
67
68

    // initialize texture pointers
    m_backgroundTexture = 0;
69
    m_beamTexture = 0;
70
71
72
73
74
75
76
77

    // initial render timing settings
    m_framesPerSecond = 25;
    m_pulsarRotationDelta = 0.0;
    m_orbitRotationDelta = 0.0;
    m_pulsarRotationAngle = 0.0;
    m_orbitRotationAngle = 0.0;

78
79
    // initial parameters (have to match GUI!)
    m_LHOAngle = 180;
Oliver Bock's avatar
Oliver Bock committed
80
    m_LLOAngle = -100;
Oliver Bock's avatar
Oliver Bock committed
81
    m_VirgoAngle = 165;
82

83
    m_pulsarRadius = 3.0;
84
    m_pulsarSpinAxisInclination = 0.0;
85

86
87
    // initial spin frequency of 0.5 Hz
    m_pulsarRotationDelta = (360.0 * 0.5) / m_framesPerSecond;
88
89
90
    // beam properties (keep this order!)
    m_pulsarBeamLength = 3.0f;
    setPulsarBeamAngle(30);
Oliver Bock's avatar
Oliver Bock committed
91
92
93
    // initial companion is "Neutron Star"
    m_companionMass = 1.4;
    m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
94

95
96
97
98
99
100
    // update orbital period (based on settings above)
    updateOrbitPeriod();

    // initial view features
    m_showOrbits = false;
    m_showRotationAxes = false;
101
    m_showPulseFlashes = true;
102
103
104
    m_cameraInteraction = false;

    // initial view settings
105
106
    m_mouseAngleH = 0.0;
    m_mouseAngleV = 0.0;
107
    m_cameraZoom = 100.0;
108
109
110
111
112
113
114
    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
115
116
117
118
}

PulsarAnimationWidget::~PulsarAnimationWidget()
{
Oliver Bock's avatar
Oliver Bock committed
119
120
    if(m_quadricVirgoh) gluDeleteQuadric(m_quadricVirgoh);
    if(m_quadricVirgov) gluDeleteQuadric(m_quadricVirgov);
121
122
    if(m_quadricPulsarOrbitPlane) gluDeleteQuadric(m_quadricPulsarOrbitPlane);
    if(m_quadricPulsar) gluDeleteQuadric(m_quadricPulsar);
Oliver Bock's avatar
Oliver Bock committed
123
124
    if(m_quadricLLOh) gluDeleteQuadric(m_quadricLLOh);
    if(m_quadricLLOv) gluDeleteQuadric(m_quadricLLOv);
125
    if(m_quadricPulsarSpinAxis) gluDeleteQuadric(m_quadricPulsarSpinAxis);
126
    if(m_quadricPulsarSpinAxisTop1) gluDeleteQuadric(m_quadricPulsarSpinAxisTop1);
127
128
    if(m_quadricLHOv) gluDeleteQuadric(m_quadricLHOv);
    if(m_quadricLHOh) gluDeleteQuadric(m_quadricLHOh);
129
130

    if(m_backgroundTexture) deleteTexture(m_backgroundTexture);
131
    if(m_beamTexture) deleteTexture(m_beamTexture);
Oliver Bock's avatar
Oliver Bock committed
132
133
134
135
}

void PulsarAnimationWidget::initializeGL()
{
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    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
164
165
    m_quadricVirgoh = gluNewQuadric();
    m_quadricVirgov = gluNewQuadric();
166
167
    m_quadricPulsarOrbitPlane = gluNewQuadric();
    m_quadricPulsar = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
168
169
    m_quadricLLOh = gluNewQuadric();
    m_quadricLLOv = gluNewQuadric();
170
    m_quadricPulsarSpinAxis = gluNewQuadric();
171
    m_quadricPulsarSpinAxisTop1 = gluNewQuadric();
172
173
    m_quadricLHOv = gluNewQuadric();
    m_quadricLHOh = gluNewQuadric();
174

Oliver Bock's avatar
Oliver Bock committed
175
176
    gluQuadricNormals(m_quadricVirgoh, GLU_SMOOTH);
    gluQuadricNormals(m_quadricVirgov, GLU_SMOOTH);
177
    gluQuadricNormals(m_quadricPulsarOrbitPlane, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
178
    gluQuadricNormals(m_quadricPulsar, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
179
180
    gluQuadricNormals(m_quadricLLOh, GLU_SMOOTH);
    gluQuadricNormals(m_quadricLLOv, GLU_SMOOTH);
181
    gluQuadricNormals(m_quadricPulsarSpinAxis, GLU_SMOOTH);
182
    gluQuadricNormals(m_quadricPulsarSpinAxisTop1, GLU_SMOOTH);
183
184
    gluQuadricNormals(m_quadricLHOv, GLU_SMOOTH);
    gluQuadricNormals(m_quadricLHOh, GLU_SMOOTH);
185

Oliver Bock's avatar
Oliver Bock committed
186
187
188
189
    // query max texture size (estimate)
    GLint maxTextureSize;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);

Oliver Bock's avatar
Oliver Bock committed
190
191
192
193
194
    // prepare local messages
    QString msgShape = tr("%1 texture shape not quadratic!");
    QString msgPower = tr("%1 texture dimensions not a power of 2!");
    QString msgSize = tr("Maximum texture size exceeded! Scaling down %1 texture to %2x%3...");

Oliver Bock's avatar
Oliver Bock committed
195
    // prepare and check background texture
Oliver Bock's avatar
Oliver Bock committed
196
    QImage backgroundTexture(":/textures/resources/texture_background_carina.png");
Oliver Bock's avatar
Oliver Bock committed
197
    if(backgroundTexture.width() != backgroundTexture.height()) {
198
        qWarning() << msgShape.arg(tr("Background"));
Oliver Bock's avatar
Oliver Bock committed
199
200
    }
    else {
201
202
203
204
205
206
        double integer = 0.0;
        double fraction = 0.0;
        fraction = modf(log(backgroundTexture.width()) / log(2.0), &integer);
        if(fraction > 0.0) {
            qWarning() << msgPower.arg(tr("Background"));
        }
Oliver Bock's avatar
Oliver Bock committed
207
208
    }
    if(backgroundTexture.width() > maxTextureSize) {
209
210
        qWarning() << msgSize.arg(tr("background").arg(maxTextureSize).arg(maxTextureSize));
        backgroundTexture = backgroundTexture.scaled(maxTextureSize, maxTextureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
Oliver Bock's avatar
Oliver Bock committed
211
212
    }

213
    // prepare and check beam texture
214
    QImage beamTexture(":/textures/resources/World-Map-7.jpg");
215

Oliver Bock's avatar
Oliver Bock committed
216
    // bind textures
Oliver Bock's avatar
Oliver Bock committed
217
    m_backgroundTexture = bindTexture(backgroundTexture, GL_TEXTURE_2D, GL_RGBA);
218
    m_beamTexture = bindTexture(beamTexture, GL_TEXTURE_2D, GL_RGBA);
219

220
    // use mipmapped textures
221
222
    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
223
224
225
226
}

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

229
230
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
Oliver Bock's avatar
Oliver Bock committed
231

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

234
235
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
Oliver Bock's avatar
Oliver Bock committed
236
237
238
239
}

void PulsarAnimationWidget::paintGL()
{
240
241
    GLfloat x,y,angle;

242
243
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

244
245
    // TODO: should be located elsewhere
    static GLfloat no_mat[] = {0.0, 0.0, 0.0, 1.0};
246
    static GLfloat mat_diffuse[] = {0.0, 0.0, 0.5, 1.0};
247
248
249
250
251
252
253
254
255
256
    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);

257
258
259
260
261
262
263
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

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

264
265
266
267
268
269
270
271
272
273
274
275
    // 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)
276
            glColor3f(1.0, 1.0, 1.0f);
277
278
279
280
281
282
283
284
285
286
            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
287
    // draw earth
288
    glPushMatrix();
289
290
291
    {
        glRotatef(130, 0.0, 1.0, 0.0);
        glPushMatrix();
292
293
        {
            glRotatef(90, 1.0, 0.0, 0.0);
294
295
296
297
298
299
            glRotatef(180, 1.0, 1.0, 0.0);

            // create texture coordinates and enable texturing
            gluQuadricTexture(m_quadricPulsar, GL_TRUE);
            glBindTexture(GL_TEXTURE_2D, m_beamTexture);
            glEnable(GL_TEXTURE_2D);
300

301
302
303
            gluSphere(m_quadricPulsar, m_pulsarRadius, 32, 32);
        }
        glPopMatrix();
304
305
    }
    glPopMatrix();
306

307
308
309
310
311
312
313
    // draw LHO
    glPushMatrix();
    {
        glColor3f(1.0f, 1.0f, 1.0f);

        glRotatef(-81, 1.0, 1.0, 0.0);
        glTranslatef(0.0, 0.0, m_pulsarRadius);
314
        glRotatef(m_LHOAngle, 0.0, 0.0, 1.0);
315
316
317
318
319
320
321
322
323
324
325
        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            gluCylinder(m_quadricLHOh, 0.010, 0.010, 0.20, 32, 1);
        }
        glPopMatrix();

        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            glRotatef(90, 1.0, 0.0, 0.0);
326
            glColor3f(0.5f, 0.5f, 1.0f);
327
328
329
330
331
332
            gluCylinder(m_quadricLHOv, 0.010, 0.010, 0.20, 32, 1);
        }
        glPopMatrix();
    }
    glPopMatrix();

Oliver Bock's avatar
Oliver Bock committed
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
    // draw LLO
    glPushMatrix();
    {
        glColor3f(1.0f, 1.0f, 1.0f);

        glRotatef(-2, 0.0, 1.0, 0.0);
        glRotatef(5, 1.0, 0.0, 0.0);
        glRotatef(-60, 1.0, 1.0, 0.0);
        glTranslatef(0.0, 0.0, m_pulsarRadius);
        glRotatef(m_LLOAngle, 0.0, 0.0, 1.0);
        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            gluCylinder(m_quadricLLOh, 0.010, 0.010, 0.20, 32, 1);
        }
        glPopMatrix();

        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            glRotatef(90, 1.0, 0.0, 0.0);
            glColor3f(1.0f, 0.5f, 0.5f);
            gluCylinder(m_quadricLLOv, 0.010, 0.010, 0.20, 32, 1);
        }
        glPopMatrix();
    }
    glPopMatrix();

Oliver Bock's avatar
Oliver Bock committed
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    // draw Virgo
    glPushMatrix();
    {
        glColor3f(1.0f, 1.0f, 1.0f);

        glRotatef(50, 0.0, 1.0, 0.0);
        glRotatef(-43, 1.0, 0.0, 0.0);
        glTranslatef(0.0, 0.0, m_pulsarRadius);
        glRotatef(m_VirgoAngle, 0.0, 0.0, 1.0);
        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            gluCylinder(m_quadricVirgoh, 0.010, 0.010, 0.20, 32, 1);
        }
        glPopMatrix();

        glPushMatrix();
        {
            glRotatef(90, 0.0, 1.0, 0.0);
            glRotatef(90, 1.0, 0.0, 0.0);
            glColor3f(0.5f, 1.0f, 0.5f);
            gluCylinder(m_quadricVirgov, 0.010, 0.010, 0.20, 32, 1);
        }
        glPopMatrix();
    }
    glPopMatrix();

388
    // draw source
389
    glPushMatrix();
390
    {
391
392
        glTranslatef(3.0,
                     3.0,
393
394
                     -3.0);

395
        glRotatef(-45, 0.0, 1.0, 0.0);
396
        glRotatef(90, 1.0, 0.0, 0.0);
397
398

        glPushMatrix();
399
        {
400
401
            glRotatef(m_pulsarSpinAxisInclination, 1.0, 0.0, 0.0);
            glRotatef(-45, 1.0, 0.0, 0.0);
402

Oliver Bock's avatar
Oliver Bock committed
403
404
405
406
            // draw source plane normal
            glColor3f(1.0f, 0.0f, 0.0f);
            glPushMatrix();
            {
407
408
                glTranslatef(0.0, 0.0, -1.0);
                gluCylinder(m_quadricPulsarSpinAxis, 0.020, 0.020, 1.5, 32, 1);
Oliver Bock's avatar
Oliver Bock committed
409
410
411
412
            }
            glPopMatrix();
            glPushMatrix();
            {
413
                glTranslatef(0.0, 0.0, -1.0);
Oliver Bock's avatar
Oliver Bock committed
414
415
416
417
418
                gluDisk(m_quadricPulsarSpinAxisTop1, 0, 0.020, 32, 8);
            }
            glPopMatrix();
            glPushMatrix();
            {
419
                glTranslatef(0.0, 0.0, 0.5f);
Oliver Bock's avatar
Oliver Bock committed
420
                glBegin(GL_TRIANGLE_FAN);
Oliver Bock's avatar
Oliver Bock committed
421
                {
Oliver Bock's avatar
Oliver Bock committed
422
423
                    // Pinnacle of cone is shared vertex for fan, moved up z-axis
                    // to produce a cone instead of a circle
424
                    glVertex3f(0.0f, 0.0f, 0.5f);
Oliver Bock's avatar
Oliver Bock committed
425
426
427
428

                    // 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
429
                    {
Oliver Bock's avatar
Oliver Bock committed
430
                        // Calculate x and y position of the next vertex
431
432
                        x = 0.1f * sin(angle);
                        y = 0.1f * cos(angle);
Oliver Bock's avatar
Oliver Bock committed
433
434
435

                        // Specify the next vertex for the triangle fan
                        glVertex2f(x, y);
Oliver Bock's avatar
Oliver Bock committed
436
437
                    }
                }
Oliver Bock's avatar
Oliver Bock committed
438
                glEnd();
439
            }
Oliver Bock's avatar
Oliver Bock committed
440
            glPopMatrix();
441

442
443
            // draw disc
            glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
444
445
            glEnable(GL_LIGHTING);

446
            glPushMatrix();
447
            {
448
449
                gluDisk(m_quadricPulsarOrbitPlane,
                        0,
450
                        1.0,
451
                        64, 1);
452
453
454
            }
            glPopMatrix();

455
            glDisable(GL_LIGHTING);
456
        }
457
458
        glPopMatrix();
    }
459
    glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

    // 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;
            font.setPointSize(11);
            font.setBold(true);
            font.setFamily("Arial");
            font.setStyleStrategy((QFont::StyleStrategy) (QFont::OpenGLCompatible | QFont::PreferQuality));
Oliver Bock's avatar
Oliver Bock committed
479
            renderText(10, 25, -100, QString("Copyright %1 2017").arg(QChar(0x00A9)), font);
480
            renderText(10, 10, -100, tr("Max Planck Institute for Gravitational Physics"), font);
Oliver Bock's avatar
Oliver Bock committed
481
482
483
484
485
486
487
488

            // restore original state
            glMatrixMode(GL_PROJECTION);
        }
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
    }
    glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
489
490
}

Oliver Bock's avatar
Oliver Bock committed
491
492
void PulsarAnimationWidget::runAnimation()
{
493
    m_frameTimer.start(qRound(1000.0 / m_framesPerSecond));
Oliver Bock's avatar
Oliver Bock committed
494
}
Oliver Bock's avatar
Oliver Bock committed
495

Oliver Bock's avatar
Oliver Bock committed
496
497
void PulsarAnimationWidget::pauseAnimation()
{
498
    m_frameTimer.stop();
Oliver Bock's avatar
Oliver Bock committed
499
500
501
502
}

void PulsarAnimationWidget::stopAnimation()
{
503
504
    m_frameTimer.stop();
    resetParameters();
Oliver Bock's avatar
Oliver Bock committed
505

506
    updateGL();
Oliver Bock's avatar
Oliver Bock committed
507
508
}

Oliver Bock's avatar
Oliver Bock committed
509
void PulsarAnimationWidget::updateFrame()
Oliver Bock's avatar
Oliver Bock committed
510
{
511
512
513
514
515
516
517
518
519
    m_pulsarRotationAngle += m_pulsarRotationDelta;
    if(m_pulsarRotationAngle >   360.0) {
        m_pulsarRotationAngle -= 360.0;
    }
    m_orbitRotationAngle += m_orbitRotationDelta;
    if(m_orbitRotationAngle >   360.0) {
        m_orbitRotationAngle -= 360.0;
    }

520
521
    updatePulseProfile();

522
523
524
    updateGL();

    emit pulsarAnimationStep(m_pulsarRotationAngle);
525
526
}

527
528
void PulsarAnimationWidget::showOrbits(bool enabled)
{
529
    m_showOrbits = enabled;
530

531
    updateGL();
532
533
}

Oliver Bock's avatar
Oliver Bock committed
534
535
void PulsarAnimationWidget::showRotationAxes(bool enabled)
{
536
    m_showRotationAxes = enabled;
Oliver Bock's avatar
Oliver Bock committed
537

538
    updateGL();
Oliver Bock's avatar
Oliver Bock committed
539
540
}

541
542
543
544
545
546
547
void PulsarAnimationWidget::showPulseFlashes(bool enabled)
{
    m_showPulseFlashes = enabled;

    updateGL();
}

548
549
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
550
    Q_UNUSED(event);
551

552
553
    m_cameraInteraction = true;
    updateGL();
554
555
}

556
557
void PulsarAnimationWidget::mouseMoveEvent(QMouseEvent *event)
{
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
    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);
585
586
587
588
}

void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event)
{
589
    Q_UNUSED(event);
590

591
592
593
    m_mouseLastX = 0;
    m_mouseLastY = 0;
    m_cameraInteraction = false;
594

595
    updateGL();
596
597
}

Oliver Bock's avatar
Oliver Bock committed
598
599
void PulsarAnimationWidget::showEvent(QShowEvent *event)
{
600
    Q_UNUSED(event);
Oliver Bock's avatar
Oliver Bock committed
601

602
603
    // update and propagate pulse profile
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
604
605
}

Oliver Bock's avatar
Oliver Bock committed
606
void PulsarAnimationWidget::updateCameraPosition(const double angleH, const double angleV, const double zoom)
607
{
608
609
610
    m_cameraPosX = sin(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
    m_cameraPosY = sin(angleV * deg2rad) * zoom;
    m_cameraPosZ = cos(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
611

612
    updatePulseProfile();
613

614
    updateGL();
615
616
}

Oliver Bock's avatar
Oliver Bock committed
617
618
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
619
    m_framesPerSecond = fps;
Oliver Bock's avatar
Oliver Bock committed
620
621
}

Oliver Bock's avatar
Oliver Bock committed
622
void PulsarAnimationWidget::setPulsarSemiMajorAxis(const double length)
Oliver Bock's avatar
Oliver Bock committed
623
{
624
625
626
627
    m_pulsarSemiMajorAxis = length;
    m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
    updateOrbitPeriod();
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
628

629
    updateGL();
Oliver Bock's avatar
Oliver Bock committed
630
}
631

Oliver Bock's avatar
Oliver Bock committed
632
void PulsarAnimationWidget::setLHOAngle(const double degrees)
633
{
634
    m_LHOAngle = degrees + 180;
635
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
636

637
    updateGL();
638
639
}

640
void PulsarAnimationWidget::setLLOAngle(const double degrees)
641
{
Oliver Bock's avatar
Oliver Bock committed
642
    m_LLOAngle = degrees - 100;
643
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
644
645

    updateGL();
Oliver Bock's avatar
Oliver Bock committed
646
647
}

648
void PulsarAnimationWidget::setVirgoAngle(const int degrees)
Oliver Bock's avatar
Oliver Bock committed
649
{
Oliver Bock's avatar
Oliver Bock committed
650
    m_VirgoAngle = degrees + 165;
651
    updatePulseProfile();
652

653
    updateGL();
654
655
}

656
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
657
{
658
    m_pulsarSpinAxisInclination = degrees;
659
    updatePulseProfile();
660

661
    updateGL();
662
}
663

664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
void PulsarAnimationWidget::setPulsarBeamAngle(const int degrees)
{
    double beamTexturePeakCorrectionFactor = 0.83;
    double correctedOuterRadius;

    // compute visual radius
    m_pulsarBeamOuterRadius = tan(deg2rad * degrees * 0.5f) * m_pulsarBeamLength;

    // compute corrected angle for pulse profile
    correctedOuterRadius = m_pulsarBeamOuterRadius * beamTexturePeakCorrectionFactor;
    m_pulsarBeamAngle = 2 * atan(correctedOuterRadius / m_pulsarBeamLength) * 180.0/PI;

    updatePulseProfile();

    updateGL();
}

681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
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);
}

Oliver Bock's avatar
Oliver Bock committed
697
698
void PulsarAnimationWidget::updateOrbitPeriod()
{
699
700
701
    m_orbitalPeriod = 3.1553e7 * sqrt(
                                    (pow(m_pulsarSemiMajorAxis, 3.0) * pow(m_pulsarMass+m_companionMass, 2.0)) / pow(m_companionMass, 3.0)
                                 );
Oliver Bock's avatar
Oliver Bock committed
702

703
704
    // visual correction factor (increase orbital momentum)
    double visualCorrection = 1e-8;
Oliver Bock's avatar
Oliver Bock committed
705

706
    m_orbitRotationDelta  = (360.0 / (m_orbitalPeriod*visualCorrection)) / m_framesPerSecond;
Oliver Bock's avatar
Oliver Bock committed
707
708
709
710
}

void PulsarAnimationWidget::updateOrbitRadii()
{
711
712
713
714
    m_pulsarSemiMajorAxis = 1.0015e-5 * pow(
                                            (pow(m_orbitalPeriod, 2.0) * pow(m_companionMass, 3.0)) / pow(m_pulsarMass+m_companionMass, 2.0),
                                            1.0/3.0
                                        );
Oliver Bock's avatar
Oliver Bock committed
715

716
    m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
Oliver Bock's avatar
Oliver Bock committed
717

718
    emit pulsarSemiMajorAxisUpdated(m_pulsarSemiMajorAxis);
Oliver Bock's avatar
Oliver Bock committed
719
720
}

721
722
void PulsarAnimationWidget::resetParameters()
{
723
724
725
    m_pulsarRotationAngle = 0.0;
    m_orbitRotationAngle = 0.0;
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
726

727
    emit pulsarAnimationStep(m_pulsarRotationAngle);
728
}
729
730
731

void PulsarAnimationWidget::updatePulseProfile()
{
732
733
734
    // avoid division by zero (keep profile visible if pulsar doesn't spin)
    double pulsarRotationDelta = m_pulsarRotationDelta == 0.0 ? 0.01 : m_pulsarRotationDelta;

735
736
737
738
739
    // prepare parameters (e.g. convert to radians where necessary)
    const double    i               = deg2rad * m_pulsarSpinAxisInclination;
    const double    y               = deg2rad * m_pulsarMagneticAxisInclination;
    double          phiOrb          = deg2rad * (m_orbitRotationAngle + 90.0);
    const double    deltaPhiRot     = deg2rad * 1.0;
740
    const double    deltaPhiOrb     = deg2rad * deltaPhiRot * m_orbitRotationDelta / pulsarRotationDelta;
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
    const double    rp              = m_pulsarSemiMajorAxis;
    const double    xk              = -m_cameraPosZ;
    const double    yk              = -m_cameraPosX;
    const double    zk              = m_cameraPosY;
    const double    cam             = pow(xk, 2.0) + pow(yk, 2.0) + pow(zk, 2.0);
    const double    alpha           = deg2rad * (90.0 - m_mouseAngleH);
    const double    delta           = deg2rad * m_mouseAngleV;
    const double    gaussProfile    = 0.012337;

    for(int x = 0; x < 360; ++x) {
        // determine angle between pulsar's magnetic axis and line of sight
        phiOrb += deltaPhiOrb;
        const double phiRot = x * deltaPhiRot;

        double a = -sin(y) * sin(phiRot) * (xk + rp * cos(phiOrb)) \
                   + (cos(i) * sin(y) * cos(phiRot) + sin(i) * cos(y)) * (yk + rp * sin(phiOrb)) \
                   - (sin(i) * sin(y) * cos(phiRot) - cos(i) * cos(y)) * zk;

        double b = sqrt(pow(rp,2.0) + cam - (2.0 * sqrt(cam) * rp * cos(delta) * sin(alpha + phiOrb)));

        // determine and store pulse amplitude
        m_pulseProfile[x] = exp(-2.0 * (1.0 - fabs(a/b)) / gaussProfile);
    }

    // propagate new profile
    emit pulseProfileUpdated(m_pulseProfile);
767
}