pulsaranimationwidget.cpp 17.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"

23
24
const float PulsarAnimationWidget::deg2rad = PI/180.0f;

Oliver Bock's avatar
Oliver Bock committed
25
PulsarAnimationWidget::PulsarAnimationWidget(QWidget *parent) :
Oliver Bock's avatar
Oliver Bock committed
26
	QGLWidget(QGLFormat(QGL::AlphaChannel | QGL::SampleBuffers), parent),
27
28
	m_frameTimer(),
	m_pulseProfile(360, 0.0f)
Oliver Bock's avatar
Oliver Bock committed
29
{
Oliver Bock's avatar
Oliver Bock committed
30
31
32
33
34
35
	if(!format().directRendering()) {
		qWarning("Sorry, no direct rendering support for animation...");
	}
	if(!format().doubleBuffer()) {
		qWarning("Sorry, no double buffering support for animation...");
	}
36
	if(!format().rgba()) {
Oliver Bock's avatar
Oliver Bock committed
37
		qWarning("Sorry, no RGBA support for animation...");
38
39
	}
	if(!format().alpha()) {
Oliver Bock's avatar
Oliver Bock committed
40
		qWarning("Sorry, no alpha channel support for animation...");
41
	}
Oliver Bock's avatar
Oliver Bock committed
42
	if(!format().sampleBuffers()) {
Oliver Bock's avatar
Oliver Bock committed
43
		qWarning("Sorry, no multisampling support for animation...");
Oliver Bock's avatar
Oliver Bock committed
44
	}
45

Oliver Bock's avatar
Oliver Bock committed
46
    connect(&m_frameTimer, SIGNAL(timeout()), this, SLOT(updateFrame()));
Oliver Bock's avatar
Oliver Bock committed
47

Oliver Bock's avatar
Oliver Bock committed
48
49
    m_quadricCompanionOrbitPlane = NULL;
    m_quadricCompanion = NULL;
50
    m_quadricPulsarOrbitPlane = NULL;
Oliver Bock's avatar
Oliver Bock committed
51
    m_quadricPulsar = NULL;
52
53
	m_quadricPulsarCone1 = NULL;
	m_quadricPulsarCone2 = NULL;
54
	m_quadricPulsarSpinAxis = NULL;
55
	m_quadricPulsarMagneticAxis = NULL;
Oliver Bock's avatar
Oliver Bock committed
56

57
58
	m_pulsarTexture = 0;
	m_backgroundTexture = 0;
59

Oliver Bock's avatar
Oliver Bock committed
60
	m_framesPerSecond = 25;
61

62
	resetParameters();
63

Oliver Bock's avatar
Oliver Bock committed
64
65
66
	m_pulsarMass = 1.4f;
	m_companionMass = 1.4f;

Oliver Bock's avatar
Oliver Bock committed
67
	m_showRotationAxes = false;
68
	m_cameraInteraction = false;
69
70
	m_mouseLastX = 0;
	m_mouseLastY = 0;
Oliver Bock's avatar
Oliver Bock committed
71
	m_mouseAngleH = 90.0f;
72
	m_mouseAngleV = 30.0f;
73
	m_cameraZoom = 15.0f;
74
75
76
	m_cameraZoomLBound = 2.0f;

	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
77
78

	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
79
80
81
82
}

PulsarAnimationWidget::~PulsarAnimationWidget()
{
Oliver Bock's avatar
Oliver Bock committed
83
84
	if(m_quadricCompanionOrbitPlane) gluDeleteQuadric(m_quadricCompanionOrbitPlane);
	if(m_quadricCompanion) gluDeleteQuadric(m_quadricCompanion);
85
	if(m_quadricPulsarOrbitPlane) gluDeleteQuadric(m_quadricPulsarOrbitPlane);
Oliver Bock's avatar
Oliver Bock committed
86
87
88
	if(m_quadricPulsar) gluDeleteQuadric(m_quadricPulsar);
	if(m_quadricPulsarCone1) gluDeleteQuadric(m_quadricPulsarCone1);
	if(m_quadricPulsarCone2) gluDeleteQuadric(m_quadricPulsarCone2);
89
	if(m_quadricPulsarSpinAxis) gluDeleteQuadric(m_quadricPulsarSpinAxis);
90
	if(m_quadricPulsarMagneticAxis) gluDeleteQuadric(m_quadricPulsarMagneticAxis);
91
92
93

	if(m_pulsarTexture) deleteTexture(m_pulsarTexture);
	if(m_backgroundTexture) deleteTexture(m_backgroundTexture);
Oliver Bock's avatar
Oliver Bock committed
94
95
96
97
}

void PulsarAnimationWidget::initializeGL()
{
Oliver Bock's avatar
Oliver Bock committed
98
99
100
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClearDepth(1.0f);
	glDepthFunc(GL_LEQUAL);
101
102
103
	glEnable(GL_DEPTH_TEST);

	glShadeModel(GL_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
104
105
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

106
	GLfloat LightAmbient[] = { 0.3f, 0.3f, 0.3f, 1.0f };
Oliver Bock's avatar
Oliver Bock committed
107
108
109
110
111
112
113
114
115
	GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightPosition[] = { 0.0f, 0.0f, 3.0f, 1.0f };
	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);
116
	glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 50.0);
Oliver Bock's avatar
Oliver Bock committed
117
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
118
	glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0);
Oliver Bock's avatar
Oliver Bock committed
119
120
121
122

	glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);
Oliver Bock's avatar
Oliver Bock committed
123

124
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
125
	glEnable(GL_BLEND);
126

Oliver Bock's avatar
Oliver Bock committed
127
128
	m_quadricCompanionOrbitPlane = gluNewQuadric();
	m_quadricCompanion = gluNewQuadric();
129
	m_quadricPulsarOrbitPlane = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
130
131
132
	m_quadricPulsar = gluNewQuadric();
    m_quadricPulsarCone1 = gluNewQuadric();
    m_quadricPulsarCone2 = gluNewQuadric();
133
    m_quadricPulsarSpinAxis = gluNewQuadric();
134
    m_quadricPulsarMagneticAxis = gluNewQuadric();
135

Oliver Bock's avatar
Oliver Bock committed
136
137
    gluQuadricNormals(m_quadricCompanionOrbitPlane, GLU_SMOOTH);
    gluQuadricNormals(m_quadricCompanion, GLU_SMOOTH);
138
    gluQuadricNormals(m_quadricPulsarOrbitPlane, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
139
140
141
    gluQuadricNormals(m_quadricPulsar, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone1, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone2, GLU_SMOOTH);
142
    gluQuadricNormals(m_quadricPulsarSpinAxis, GLU_SMOOTH);
143
    gluQuadricNormals(m_quadricPulsarMagneticAxis, GLU_SMOOTH);
144

145
    // load textures
146
    m_pulsarTexture = bindTexture(QImage(":/textures/resources/texture_pulsar.png"), GL_TEXTURE_2D, GL_RGBA);
147
148
//    m_backgroundTexture = bindTexture(QImage(":/textures/resources/texture_background_simple.png"), GL_TEXTURE_2D, GL_RGBA);
    m_backgroundTexture = bindTexture(QImage(":/textures/resources/texture_background_carina.jpg"), GL_TEXTURE_2D, GL_RGB);
149

150
    // use mipmapped textures
151
152
153
    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
154
155
156
    // enable 2D mapping (s/t coordinates, sphere map won't rotate texture!)
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
Oliver Bock's avatar
Oliver Bock committed
157
158
159
160
}

void PulsarAnimationWidget::resizeGL(int w, int h)
{
Oliver Bock's avatar
Oliver Bock committed
161
162
163
164
165
	glViewport(0, 0, w, h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

Oliver Bock's avatar
Oliver Bock committed
166
	gluPerspective(45.0f, (GLfloat)w / (GLfloat)h, 0.1f, 500.0f);
Oliver Bock's avatar
Oliver Bock committed
167
168
169
170
171
172
173
174
175
176
177
178

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void PulsarAnimationWidget::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

179
180
	gluLookAt(m_cameraPosX, m_cameraPosY, m_cameraPosZ,
			  0.0, 0.0, 0.0,
181
			  0.0, 1.0, 0.0);
Oliver Bock's avatar
Oliver Bock committed
182
183
184
185
186

	// TODO: should be located elsewhere
	static GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
	static GLfloat mat_diffuse[] = { 0.5, 0.5, 0.5, 1.0 };
	static GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
187
	static GLfloat low_shininess[] = { 2.5 };
188
	static GLfloat translucent[] = { 1.0, 1.0, 1.0, 0.33 };
189

Oliver Bock's avatar
Oliver Bock committed
190
191
192
193
194
	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);
Oliver Bock's avatar
Oliver Bock committed
195

196
	// draw companion
Oliver Bock's avatar
Oliver Bock committed
197
	glPushMatrix();
Oliver Bock's avatar
Oliver Bock committed
198
		glTranslatef(sin((m_orbitRotationAngle + 180) * deg2rad) * m_companionSemiMajorAxis,
199
					 0.0f,
Oliver Bock's avatar
Oliver Bock committed
200
201
					 cos((m_orbitRotationAngle + 180) * deg2rad) * m_companionSemiMajorAxis);
		gluSphere(m_quadricCompanion, 1.0f, 32, 32);
Oliver Bock's avatar
Oliver Bock committed
202
203
	glPopMatrix();

204
	// draw pulsar
Oliver Bock's avatar
Oliver Bock committed
205
	glPushMatrix();
Oliver Bock's avatar
Oliver Bock committed
206
		glTranslatef(sin(m_orbitRotationAngle * deg2rad) * m_pulsarSemiMajorAxis,
207
					 0.0f,
Oliver Bock's avatar
Oliver Bock committed
208
					 cos(m_orbitRotationAngle * deg2rad) * m_pulsarSemiMajorAxis);
209
210

		glPushMatrix();
211
212
			glRotatef(m_pulsarSpinAxisInclination, 0.0f, 0.0f, 1.0f);
			glRotatef(m_pulsarRotationAngle, 0.0f, 1.0f, 0.0f);
213

214
			// draw spin axis
Oliver Bock's avatar
Oliver Bock committed
215
			if(m_showRotationAxes) {
216
217
				glPushMatrix();
					glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
218
					glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
219
220
221
222
223
					glTranslatef(0.0f, 0.0f, -5.0f);
					gluCylinder(m_quadricPulsarSpinAxis, 0.05f, 0.05f, 10.0f, 32, 1);
				glPopMatrix();
			}

224
225
226
227
228
			// create texture coordinates and enable texturing
	        glEnable(GL_TEXTURE_GEN_S);
	        glEnable(GL_TEXTURE_GEN_T);
	        glBindTexture(GL_TEXTURE_2D, m_pulsarTexture);
	        glEnable(GL_TEXTURE_2D);
229
230
231

			glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
232
			gluSphere(m_quadricPulsar, 1.0f, 32, 32);
233

234
			// disable texturing
235
236
237
	        glDisable(GL_TEXTURE_GEN_S);
	        glDisable(GL_TEXTURE_GEN_T);
	        glDisable(GL_TEXTURE_2D);
238
239
		glPopMatrix();

240
241
242
243
244
245
246
		// TODO: should be located elsewhere
		static GLfloat coneAmbient[] = { 1.0, 1.0, 0.0, 1.0 };
		static GLfloat coneDiffuse[] = { 1.0, 1.0, 0.0, 1.0 };
		static GLfloat coneSpecular[] = { 1.0, 1.0, 0.5, 1.0 };

		glMaterialfv(GL_FRONT, GL_SPECULAR, coneSpecular);

247
		// first cone
248
		glPushMatrix();
249
250
251
252
253
			glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
			glRotatef(m_pulsarSpinAxisInclination, 0.0f, 1.0f, 0.0f);

			glRotatef(-m_pulsarRotationAngle - 90.0f, 0.0f, 0.0f, 1.0f);
			glRotatef(-m_pulsarMagneticAxisInclination, 1.0f, 0.0f, 0.0f);
254

255
			// draw magnetic axis (for both cones)
Oliver Bock's avatar
Oliver Bock committed
256
			if(m_showRotationAxes) {
257
258
259
260
261
				glPushMatrix();
					glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
					glTranslatef(0.0f, 0.0f, -5.0f);
					gluCylinder(m_quadricPulsarMagneticAxis, 0.05f, 0.05f, 10.0f, 32, 1);
				glPopMatrix();
262
263
			}

264
			glTranslatef(0.0f, 0.0f, -4.0f);
265
266
267

			glMaterialfv(GL_FRONT, GL_AMBIENT, coneAmbient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, coneDiffuse);
268
			gluCylinder(m_quadricPulsarCone1, 0.475f, 0.0f, 3.0f, 32, 32);
269
270
		glPopMatrix();

271
		// second cone
272
		glPushMatrix();
273
274
			glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
			glRotatef(-m_pulsarSpinAxisInclination, 0.0f, 1.0f, 0.0f);
275

276
277
			glRotatef(m_pulsarRotationAngle - 90.0f, 0.0f, 0.0f, 1.0f);
			glRotatef(m_pulsarMagneticAxisInclination, 1.0f, 0.0f, 0.0f);
278

279
			glTranslatef(0.0f, 0.0f, -4.0f);
280
281
282

			glMaterialfv(GL_FRONT, GL_AMBIENT, coneAmbient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, coneDiffuse);
283
			gluCylinder(m_quadricPulsarCone2, 0.475f, 0.0f, 3.0f, 32, 32);
284
		glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
285
	glPopMatrix();
286

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
	// save current state
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(0, width(), 0, height(), 0.1f, 501.0f);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	// draw backdrop (independent parallel projection)
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_specular);
	glTranslatef(0.0f, 0.0f, -501.0f);
	drawTexture(QPointF(0.0f, 0.0f), m_backgroundTexture);

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

Oliver Bock's avatar
Oliver Bock committed
307
	// draw orbital planes
308
	if(m_cameraInteraction) {
309
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
310

311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
		static float sizeOffset = 0.25f;

		// companion's plane (only if not identical with pulsar's)
		if(m_companionSemiMajorAxis != m_pulsarSemiMajorAxis) {
			glPushMatrix();
				glRotatef(90.0f, 1.0f, 0.0f, 0.0f);

				// separate them slightly in case of overlap
				// based on ugly mass diff check (no collision detection)
				// single known problematic pair: (m_c=1.4, m_p=1.5)
				if((int)(10*(m_pulsarMass-m_companionMass)+0.5f) == 1){
					glTranslatef(0.0f, 0.0f, 0.01f);
				}

				gluDisk(m_quadricCompanionOrbitPlane,
						m_companionSemiMajorAxis - sizeOffset,
						m_companionSemiMajorAxis + sizeOffset,
						64, 1);
			glPopMatrix();
		}

		// pulsar's plane
Oliver Bock's avatar
Oliver Bock committed
333
334
		glPushMatrix();
			glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
335
			gluDisk(m_quadricPulsarOrbitPlane,
336
337
					m_pulsarSemiMajorAxis - sizeOffset,
					m_pulsarSemiMajorAxis + sizeOffset,
338
339
					64, 1);
		glPopMatrix();
340
	}
Oliver Bock's avatar
Oliver Bock committed
341
342
}

Oliver Bock's avatar
Oliver Bock committed
343
344
void PulsarAnimationWidget::runAnimation()
{
Oliver Bock's avatar
Oliver Bock committed
345
	m_frameTimer.start(1000.0f / m_framesPerSecond);
Oliver Bock's avatar
Oliver Bock committed
346
}
Oliver Bock's avatar
Oliver Bock committed
347

Oliver Bock's avatar
Oliver Bock committed
348
349
350
351
352
353
354
355
void PulsarAnimationWidget::pauseAnimation()
{
	m_frameTimer.stop();
}

void PulsarAnimationWidget::stopAnimation()
{
	m_frameTimer.stop();
356
	resetParameters();
Oliver Bock's avatar
Oliver Bock committed
357
358
359
360

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
361
void PulsarAnimationWidget::updateFrame()
Oliver Bock's avatar
Oliver Bock committed
362
{
Oliver Bock's avatar
Oliver Bock committed
363
364
365
	m_pulsarRotationAngle += m_pulsarRotationDelta;
	if(m_pulsarRotationAngle > 360) {
		m_pulsarRotationAngle = 0.0f;
366
		updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
367
	}
Oliver Bock's avatar
Oliver Bock committed
368
369
370
	m_orbitRotationAngle += m_orbitRotationDelta;
	if(m_orbitRotationAngle > 360) {
		m_orbitRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
371
372
	}

Oliver Bock's avatar
Oliver Bock committed
373
	updateGL();
Oliver Bock's avatar
Oliver Bock committed
374
375

	emit pulsarAnimationStep(m_pulsarRotationDelta);
376
377
}

Oliver Bock's avatar
Oliver Bock committed
378
379
380
381
382
383
384
void PulsarAnimationWidget::showRotationAxes(bool enabled)
{
	m_showRotationAxes = enabled;

	updateGL();
}

385
386
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
387
388
	Q_UNUSED(event);

389
390
391
392
	m_cameraInteraction = true;
	updateGL();
}

393
394
395
396
397
398
void PulsarAnimationWidget::mouseMoveEvent(QMouseEvent *event)
{
	Qt::MouseButtons buttons = event->buttons();
	if((buttons & Qt::LeftButton) == Qt::LeftButton) {
		if(m_mouseLastX != 0) {
			m_mouseAngleH -= (m_mouseLastX - event->x()) / 2;
Oliver Bock's avatar
Oliver Bock committed
399
			m_mouseAngleH = m_mouseAngleH < 360 ? m_mouseAngleH : 0;
400
401
402
403

		}
		if(m_mouseLastY != 0) {
			m_mouseAngleV -= (m_mouseLastY - event->y()) / 2;
Oliver Bock's avatar
Oliver Bock committed
404
405
			m_mouseAngleV = m_mouseAngleV < 90 ? m_mouseAngleV : 90;
			m_mouseAngleV = m_mouseAngleV > -90 ? m_mouseAngleV : -90;
406
407
408
409
410
411
412
413
		}

		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()) / 2;
Oliver Bock's avatar
Oliver Bock committed
414
			m_cameraZoom = m_cameraZoom >= m_cameraZoomLBound ? m_cameraZoom : m_cameraZoomLBound;
415
416
417
418
419
420
421
422
423
424
425
			updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
		}

		m_mouseLastY = event->y();
	}

	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}

void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event)
{
426
427
	Q_UNUSED(event);

428
429
	m_mouseLastX = 0;
	m_mouseLastY = 0;
430
431
	m_cameraInteraction = false;
	updateGL();
432
433
434
435
436
437
}

void PulsarAnimationWidget::updateCameraPosition(const int angleH, const int angleV, const float zoom)
{
	m_cameraPosX = sin(angleH * deg2rad) * zoom;
	m_cameraPosY = sin(angleV * deg2rad) * zoom;
Oliver Bock's avatar
Oliver Bock committed
438
	m_cameraPosZ = cos(angleH * deg2rad) * cos(fabs(angleV * deg2rad)) * zoom;
439

440
441
	updatePulseProfile();

442
443
444
	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
445
446
447
448
449
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
	m_framesPerSecond = fps;
}

Oliver Bock's avatar
Oliver Bock committed
450
void PulsarAnimationWidget::setPulsarSemiMajorAxis(const float length)
Oliver Bock's avatar
Oliver Bock committed
451
{
Oliver Bock's avatar
Oliver Bock committed
452
453
454
	m_pulsarSemiMajorAxis = length;
	m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
	updateOrbitPeriod();
455
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
456
457

	updateGL();
Oliver Bock's avatar
Oliver Bock committed
458
}
459

Oliver Bock's avatar
Oliver Bock committed
460
void PulsarAnimationWidget::setCompanionMass(const float mass)
461
{
Oliver Bock's avatar
Oliver Bock committed
462
463
	m_companionMass = mass;
	updateOrbitRadii();
464
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
465
466

	updateGL();
467
468
}

Oliver Bock's avatar
Oliver Bock committed
469
void PulsarAnimationWidget::setPulsarMass(const float mass)
470
{
Oliver Bock's avatar
Oliver Bock committed
471
472
	m_pulsarMass = mass;
	updateOrbitRadii();
473
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
474
475
476
477
478
479
480

	updateGL();
}

void PulsarAnimationWidget::setPulsarSpinFrequency(const float frequency)
{
	m_pulsarRotationDelta = (360.0f * frequency) / m_framesPerSecond;
481
	updatePulseProfile();
482
}
483

484
485
486
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
{
	m_pulsarSpinAxisInclination = degrees;
487
	updatePulseProfile();
488
489
490
491

	updateGL();
}

492
493
494
495
496
497
void PulsarAnimationWidget::setPulsarMagneticAxisInclination(const int degrees)
{
	m_pulsarMagneticAxisInclination = degrees;

	updateGL();
}
498

Oliver Bock's avatar
Oliver Bock committed
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
void PulsarAnimationWidget::updateOrbitPeriod()
{
	m_orbitalPeriod = 3.1553e7 * sqrt(
						(pow(m_pulsarSemiMajorAxis,3) * pow(m_pulsarMass+m_companionMass,2)) /
						 pow(m_companionMass,3)
					  );

	// visual correction factor (increase orbital momentum)
	double visualCorrection = 1e-8;

	m_orbitRotationDelta  = (360.0 / (m_orbitalPeriod*visualCorrection)) / m_framesPerSecond;
}

void PulsarAnimationWidget::updateOrbitRadii()
{
	m_pulsarSemiMajorAxis = 1.0015e-5 * pow(
								(pow(m_orbitalPeriod,2) * pow(m_companionMass,3)) /
								 pow(m_pulsarMass+m_companionMass,2),
								 1.0/3.0
							);

	m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;

	emit pulsarSemiMajorAxisUpdated(m_pulsarSemiMajorAxis);
}

525
526
527
528
void PulsarAnimationWidget::resetParameters()
{
	m_pulsarRotationAngle = 0.0f;
	m_orbitRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
529
530

	emit pulsarAnimationReset();
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
558
559
560
561
562
563
564
565
566
567
568

void PulsarAnimationWidget::updatePulseProfile()
{
	const double i = m_pulsarSpinAxisInclination;
	const double y = m_pulsarMagneticAxisInclination;
	const double deltaPhiOrb = m_orbitRotationDelta;
	const double deltaPhiRot = m_pulsarRotationDelta;
	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) + pow(yk,2) + pow(zk,2);
	const double alpha = -m_mouseAngleH;
	const double delta = 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
		const double phiOrb = x * 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) + cam - 2 * sqrt(cam) * rp * cos(delta) * sin(alpha + phiOrb));

		// determine pulse amplitude
		double amp = exp(-2 * (1 - fabs(a/b)) / gaussProfile);

		// store amplitude
		m_pulseProfile[x] = (float) amp;
	}

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