pulsaranimationwidget.cpp 17.3 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;

67
	m_showOrbits = false;
Oliver Bock's avatar
Oliver Bock committed
68
	m_showRotationAxes = false;
69
	m_cameraInteraction = false;
70

71
72
	m_mouseLastX = 0;
	m_mouseLastY = 0;
Oliver Bock's avatar
Oliver Bock committed
73
	m_mouseAngleH = 90.0f;
74
	m_mouseAngleV = 30.0f;
75
	m_cameraZoom = 15.0f;
76
77
78
	m_cameraZoomLBound = 2.0f;

	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
79
80

	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
81
82
83
84
}

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

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

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

	glShadeModel(GL_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
106
107
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

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

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

126
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
127
	glEnable(GL_BLEND);
128

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

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

147
    // load textures
148
    m_pulsarTexture = bindTexture(QImage(":/textures/resources/texture_pulsar.png"), GL_TEXTURE_2D, GL_RGBA);
149
150
//    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);
151

152
    // use mipmapped textures
153
154
155
    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
156
157
158
    // 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
159
160
161
162
}

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

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

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

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

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

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

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

	// 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 };
189
	static GLfloat low_shininess[] = { 2.5 };
190
	static GLfloat translucent[] = { 1.0, 1.0, 1.0, 0.33 };
191

Oliver Bock's avatar
Oliver Bock committed
192
193
194
195
196
	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
197

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

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

		glPushMatrix();
213
214
			glRotatef(m_pulsarSpinAxisInclination, 0.0f, 0.0f, 1.0f);
			glRotatef(m_pulsarRotationAngle, 0.0f, 1.0f, 0.0f);
215

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

226
227
228
229
230
			// 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);
231
232
233

			glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
234
			gluSphere(m_quadricPulsar, 1.0f, 32, 32);
235

236
			// disable texturing
237
238
239
	        glDisable(GL_TEXTURE_GEN_S);
	        glDisable(GL_TEXTURE_GEN_T);
	        glDisable(GL_TEXTURE_2D);
240
241
		glPopMatrix();

242
243
244
245
246
247
248
		// 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);

249
		// first cone
250
		glPushMatrix();
251
252
253
254
255
			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);
256

257
			// draw magnetic axis (for both cones)
Oliver Bock's avatar
Oliver Bock committed
258
			if(m_showRotationAxes) {
259
260
261
262
263
				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();
264
265
			}

266
			glTranslatef(0.0f, 0.0f, -4.0f);
267
268
269

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

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

278
279
			glRotatef(m_pulsarRotationAngle - 90.0f, 0.0f, 0.0f, 1.0f);
			glRotatef(m_pulsarMagneticAxisInclination, 1.0f, 0.0f, 0.0f);
280

281
			glTranslatef(0.0f, 0.0f, -4.0f);
282
283
284

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

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
	// 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
309
	// draw orbital planes
310
	if(m_cameraInteraction || m_showOrbits) {
311
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
312

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
		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
335
336
		glPushMatrix();
			glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
337
			gluDisk(m_quadricPulsarOrbitPlane,
338
339
					m_pulsarSemiMajorAxis - sizeOffset,
					m_pulsarSemiMajorAxis + sizeOffset,
340
341
					64, 1);
		glPopMatrix();
342
	}
Oliver Bock's avatar
Oliver Bock committed
343
344
}

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

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

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

	updateGL();
}

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

Oliver Bock's avatar
Oliver Bock committed
375
	updateGL();
Oliver Bock's avatar
Oliver Bock committed
376
377

	emit pulsarAnimationStep(m_pulsarRotationDelta);
378
379
}

380
381
382
383
384
385
386
void PulsarAnimationWidget::showOrbits(bool enabled)
{
	m_showOrbits = enabled;

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
387
388
389
390
391
392
393
void PulsarAnimationWidget::showRotationAxes(bool enabled)
{
	m_showRotationAxes = enabled;

	updateGL();
}

394
395
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
396
397
	Q_UNUSED(event);

398
399
400
401
	m_cameraInteraction = true;
	updateGL();
}

402
403
404
405
406
407
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
408
			m_mouseAngleH = m_mouseAngleH < 360 ? m_mouseAngleH : 0;
409
410
411
412

		}
		if(m_mouseLastY != 0) {
			m_mouseAngleV -= (m_mouseLastY - event->y()) / 2;
Oliver Bock's avatar
Oliver Bock committed
413
414
			m_mouseAngleV = m_mouseAngleV < 90 ? m_mouseAngleV : 90;
			m_mouseAngleV = m_mouseAngleV > -90 ? m_mouseAngleV : -90;
415
416
417
418
419
420
421
422
		}

		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
423
			m_cameraZoom = m_cameraZoom >= m_cameraZoomLBound ? m_cameraZoom : m_cameraZoomLBound;
424
425
426
427
428
429
430
431
432
433
434
			updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
		}

		m_mouseLastY = event->y();
	}

	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}

void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event)
{
435
436
	Q_UNUSED(event);

437
438
	m_mouseLastX = 0;
	m_mouseLastY = 0;
439
440
	m_cameraInteraction = false;
	updateGL();
441
442
443
444
445
446
}

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
447
	m_cameraPosZ = cos(angleH * deg2rad) * cos(fabs(angleV * deg2rad)) * zoom;
448

449
450
	updatePulseProfile();

451
452
453
	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
454
455
456
457
458
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
	m_framesPerSecond = fps;
}

Oliver Bock's avatar
Oliver Bock committed
459
void PulsarAnimationWidget::setPulsarSemiMajorAxis(const float length)
Oliver Bock's avatar
Oliver Bock committed
460
{
Oliver Bock's avatar
Oliver Bock committed
461
462
463
	m_pulsarSemiMajorAxis = length;
	m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
	updateOrbitPeriod();
464
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
465
466

	updateGL();
Oliver Bock's avatar
Oliver Bock committed
467
}
468

Oliver Bock's avatar
Oliver Bock committed
469
void PulsarAnimationWidget::setCompanionMass(const float mass)
470
{
Oliver Bock's avatar
Oliver Bock committed
471
472
	m_companionMass = mass;
	updateOrbitRadii();
473
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
474
475

	updateGL();
476
477
}

Oliver Bock's avatar
Oliver Bock committed
478
void PulsarAnimationWidget::setPulsarMass(const float mass)
479
{
Oliver Bock's avatar
Oliver Bock committed
480
481
	m_pulsarMass = mass;
	updateOrbitRadii();
482
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
483
484
485
486
487
488
489

	updateGL();
}

void PulsarAnimationWidget::setPulsarSpinFrequency(const float frequency)
{
	m_pulsarRotationDelta = (360.0f * frequency) / m_framesPerSecond;
490
	updatePulseProfile();
491
}
492

493
494
495
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
{
	m_pulsarSpinAxisInclination = degrees;
496
	updatePulseProfile();
497
498
499
500

	updateGL();
}

501
502
503
504
505
506
void PulsarAnimationWidget::setPulsarMagneticAxisInclination(const int degrees)
{
	m_pulsarMagneticAxisInclination = degrees;

	updateGL();
}
507

Oliver Bock's avatar
Oliver Bock committed
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
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);
}

534
535
536
537
void PulsarAnimationWidget::resetParameters()
{
	m_pulsarRotationAngle = 0.0f;
	m_orbitRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
538
539

	emit pulsarAnimationReset();
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
569
570
571
572
573
574
575
576
577

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);
}