pulsaranimationwidget.cpp 23.6 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_quadricCompanionOrbitPlane = NULL;
    m_quadricCompanion = 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;
81
82
    m_VirgoAngle = 0;

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()
{
119
120
121
122
    if(m_quadricCompanionOrbitPlane) gluDeleteQuadric(m_quadricCompanionOrbitPlane);
    if(m_quadricCompanion) gluDeleteQuadric(m_quadricCompanion);
    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
164
165
166
167
    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);

    m_quadricCompanionOrbitPlane = gluNewQuadric();
    m_quadricCompanion = gluNewQuadric();
    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_quadricCompanionOrbitPlane, GLU_SMOOTH);
    gluQuadricNormals(m_quadricCompanion, 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();

361
    // draw source
362
    glPushMatrix();
363
    {
364
365
        glTranslatef(3.0,
                     3.0,
366
367
                     -3.0);

368
        glRotatef(-45, 0.0, 1.0, 0.0);
369
        glRotatef(90, 1.0, 0.0, 0.0);
370
371

        glPushMatrix();
372
        {
373
374
            glRotatef(m_pulsarSpinAxisInclination, 1.0, 0.0, 0.0);
            glRotatef(-45, 1.0, 0.0, 0.0);
375

Oliver Bock's avatar
Oliver Bock committed
376
377
378
379
            // draw source plane normal
            glColor3f(1.0f, 0.0f, 0.0f);
            glPushMatrix();
            {
380
381
                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
382
383
384
385
            }
            glPopMatrix();
            glPushMatrix();
            {
386
                glTranslatef(0.0, 0.0, -1.0);
Oliver Bock's avatar
Oliver Bock committed
387
388
389
390
391
                gluDisk(m_quadricPulsarSpinAxisTop1, 0, 0.020, 32, 8);
            }
            glPopMatrix();
            glPushMatrix();
            {
392
                glTranslatef(0.0, 0.0, 0.5f);
Oliver Bock's avatar
Oliver Bock committed
393
                glBegin(GL_TRIANGLE_FAN);
Oliver Bock's avatar
Oliver Bock committed
394
                {
Oliver Bock's avatar
Oliver Bock committed
395
396
                    // Pinnacle of cone is shared vertex for fan, moved up z-axis
                    // to produce a cone instead of a circle
397
                    glVertex3f(0.0f, 0.0f, 0.5f);
Oliver Bock's avatar
Oliver Bock committed
398
399
400
401

                    // 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
402
                    {
Oliver Bock's avatar
Oliver Bock committed
403
                        // Calculate x and y position of the next vertex
404
405
                        x = 0.1f * sin(angle);
                        y = 0.1f * cos(angle);
Oliver Bock's avatar
Oliver Bock committed
406
407
408

                        // Specify the next vertex for the triangle fan
                        glVertex2f(x, y);
Oliver Bock's avatar
Oliver Bock committed
409
410
                    }
                }
Oliver Bock's avatar
Oliver Bock committed
411
                glEnd();
412
            }
Oliver Bock's avatar
Oliver Bock committed
413
            glPopMatrix();
414

415
416
            // draw disc
            glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
417
418
            glEnable(GL_LIGHTING);

419
            glPushMatrix();
420
            {
421
422
                gluDisk(m_quadricPulsarOrbitPlane,
                        0,
423
                        1.0,
424
                        64, 1);
425
426
427
            }
            glPopMatrix();

428
            glDisable(GL_LIGHTING);
429
        }
430
431
        glPopMatrix();
    }
432
    glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

    // 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
452
            renderText(10, 25, -100, QString("Copyright %1 2017").arg(QChar(0x00A9)), font);
453
            renderText(10, 10, -100, tr("Max Planck Institute for Gravitational Physics"), font);
Oliver Bock's avatar
Oliver Bock committed
454
455
456
457
458
459
460
461

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

Oliver Bock's avatar
Oliver Bock committed
464
465
void PulsarAnimationWidget::runAnimation()
{
466
    m_frameTimer.start(qRound(1000.0 / m_framesPerSecond));
Oliver Bock's avatar
Oliver Bock committed
467
}
Oliver Bock's avatar
Oliver Bock committed
468

Oliver Bock's avatar
Oliver Bock committed
469
470
void PulsarAnimationWidget::pauseAnimation()
{
471
    m_frameTimer.stop();
Oliver Bock's avatar
Oliver Bock committed
472
473
474
475
}

void PulsarAnimationWidget::stopAnimation()
{
476
477
    m_frameTimer.stop();
    resetParameters();
Oliver Bock's avatar
Oliver Bock committed
478

479
    updateGL();
Oliver Bock's avatar
Oliver Bock committed
480
481
}

Oliver Bock's avatar
Oliver Bock committed
482
void PulsarAnimationWidget::updateFrame()
Oliver Bock's avatar
Oliver Bock committed
483
{
484
485
486
487
488
489
490
491
492
    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;
    }

493
494
    updatePulseProfile();

495
496
497
    updateGL();

    emit pulsarAnimationStep(m_pulsarRotationAngle);
498
499
}

500
501
void PulsarAnimationWidget::showOrbits(bool enabled)
{
502
    m_showOrbits = enabled;
503

504
    updateGL();
505
506
}

Oliver Bock's avatar
Oliver Bock committed
507
508
void PulsarAnimationWidget::showRotationAxes(bool enabled)
{
509
    m_showRotationAxes = enabled;
Oliver Bock's avatar
Oliver Bock committed
510

511
    updateGL();
Oliver Bock's avatar
Oliver Bock committed
512
513
}

514
515
516
517
518
519
520
void PulsarAnimationWidget::showPulseFlashes(bool enabled)
{
    m_showPulseFlashes = enabled;

    updateGL();
}

521
522
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
523
    Q_UNUSED(event);
524

525
526
    m_cameraInteraction = true;
    updateGL();
527
528
}

529
530
void PulsarAnimationWidget::mouseMoveEvent(QMouseEvent *event)
{
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
    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);
558
559
560
561
}

void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event)
{
562
    Q_UNUSED(event);
563

564
565
566
    m_mouseLastX = 0;
    m_mouseLastY = 0;
    m_cameraInteraction = false;
567

568
    updateGL();
569
570
}

Oliver Bock's avatar
Oliver Bock committed
571
572
void PulsarAnimationWidget::showEvent(QShowEvent *event)
{
573
    Q_UNUSED(event);
Oliver Bock's avatar
Oliver Bock committed
574

575
576
    // update and propagate pulse profile
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
577
578
}

Oliver Bock's avatar
Oliver Bock committed
579
void PulsarAnimationWidget::updateCameraPosition(const double angleH, const double angleV, const double zoom)
580
{
581
582
583
    m_cameraPosX = sin(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
    m_cameraPosY = sin(angleV * deg2rad) * zoom;
    m_cameraPosZ = cos(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
584

585
    updatePulseProfile();
586

587
    updateGL();
588
589
}

Oliver Bock's avatar
Oliver Bock committed
590
591
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
592
    m_framesPerSecond = fps;
Oliver Bock's avatar
Oliver Bock committed
593
594
}

Oliver Bock's avatar
Oliver Bock committed
595
void PulsarAnimationWidget::setPulsarSemiMajorAxis(const double length)
Oliver Bock's avatar
Oliver Bock committed
596
{
597
598
599
600
    m_pulsarSemiMajorAxis = length;
    m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
    updateOrbitPeriod();
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
601

602
    updateGL();
Oliver Bock's avatar
Oliver Bock committed
603
}
604

Oliver Bock's avatar
Oliver Bock committed
605
void PulsarAnimationWidget::setLHOAngle(const double degrees)
606
{
607
    m_LHOAngle = degrees + 180;
608
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
609

610
    updateGL();
611
612
}

613
void PulsarAnimationWidget::setLLOAngle(const double degrees)
614
{
Oliver Bock's avatar
Oliver Bock committed
615
    m_LLOAngle = degrees - 100;
616
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
617
618

    updateGL();
Oliver Bock's avatar
Oliver Bock committed
619
620
}

621
void PulsarAnimationWidget::setVirgoAngle(const int degrees)
Oliver Bock's avatar
Oliver Bock committed
622
{
623
    m_VirgoAngle = degrees;
624
    updatePulseProfile();
625

626
    updateGL();
627
628
}

629
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
630
{
631
    m_pulsarSpinAxisInclination = degrees;
632
    updatePulseProfile();
633

634
    updateGL();
635
}
636

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
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();
}

654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
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
670
671
void PulsarAnimationWidget::updateOrbitPeriod()
{
672
673
674
    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
675

676
677
    // visual correction factor (increase orbital momentum)
    double visualCorrection = 1e-8;
Oliver Bock's avatar
Oliver Bock committed
678

679
    m_orbitRotationDelta  = (360.0 / (m_orbitalPeriod*visualCorrection)) / m_framesPerSecond;
Oliver Bock's avatar
Oliver Bock committed
680
681
682
683
}

void PulsarAnimationWidget::updateOrbitRadii()
{
684
685
686
687
    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
688

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

691
    emit pulsarSemiMajorAxisUpdated(m_pulsarSemiMajorAxis);
Oliver Bock's avatar
Oliver Bock committed
692
693
}

694
695
void PulsarAnimationWidget::resetParameters()
{
696
697
698
    m_pulsarRotationAngle = 0.0;
    m_orbitRotationAngle = 0.0;
    updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
699

700
    emit pulsarAnimationStep(m_pulsarRotationAngle);
701
}
702
703
704

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

708
709
710
711
712
    // 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;
713
    const double    deltaPhiOrb     = deg2rad * deltaPhiRot * m_orbitRotationDelta / pulsarRotationDelta;
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
    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);
740
}