pulsaranimationwidget.cpp 18.4 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 primary rendering timer to local callback
Oliver Bock's avatar
Oliver Bock committed
47
    connect(&m_frameTimer, SIGNAL(timeout()), this, SLOT(updateFrame()));
Oliver Bock's avatar
Oliver Bock committed
48

Oliver Bock's avatar
Oliver Bock committed
49
    // initialize quadric pointers
Oliver Bock's avatar
Oliver Bock committed
50
51
    m_quadricCompanionOrbitPlane = NULL;
    m_quadricCompanion = NULL;
52
    m_quadricPulsarOrbitPlane = NULL;
Oliver Bock's avatar
Oliver Bock committed
53
    m_quadricPulsar = NULL;
54
55
	m_quadricPulsarCone1 = NULL;
	m_quadricPulsarCone2 = NULL;
56
	m_quadricPulsarSpinAxis = NULL;
57
	m_quadricPulsarMagneticAxis = NULL;
Oliver Bock's avatar
Oliver Bock committed
58

Oliver Bock's avatar
Oliver Bock committed
59
	// initialize texture pointers
60
61
	m_pulsarTexture = 0;
	m_backgroundTexture = 0;
62

Oliver Bock's avatar
Oliver Bock committed
63
	// initial render timing settings
Oliver Bock's avatar
Oliver Bock committed
64
	m_framesPerSecond = 25;
Oliver Bock's avatar
Oliver Bock committed
65
66
	m_pulsarRotationDelta = 0.0f;
	m_orbitRotationDelta = 0.0f;
67
	resetParameters();
68

Oliver Bock's avatar
Oliver Bock committed
69
	// initial binary system parameters (have to match GUI!)
Oliver Bock's avatar
Oliver Bock committed
70
	m_pulsarMass = 1.4f;
Oliver Bock's avatar
Oliver Bock committed
71
	// initial companion is "Neutron Star"
Oliver Bock's avatar
Oliver Bock committed
72
	m_companionMass = 1.4f;
Oliver Bock's avatar
Oliver Bock committed
73
74
75
76
77
78
79
80
	m_pulsarSpinAxisInclination = 0.0f;
	m_pulsarMagneticAxisInclination = 45.0f;
	m_pulsarSemiMajorAxis = 5.0f;
	m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
	// initial spin frequency of 0.5 Hz
	m_pulsarRotationDelta = (360.0f * 0.5f) / m_framesPerSecond;
	// update orbital period (based on settings above)
	updateOrbitPeriod();
Oliver Bock's avatar
Oliver Bock committed
81

Oliver Bock's avatar
Oliver Bock committed
82
	// initial view features
83
	m_showOrbits = false;
Oliver Bock's avatar
Oliver Bock committed
84
	m_showRotationAxes = false;
85
	m_cameraInteraction = false;
86

Oliver Bock's avatar
Oliver Bock committed
87
	// initial view settings
Oliver Bock's avatar
Oliver Bock committed
88
	m_mouseAngleH = 90.0f;
89
	m_mouseAngleV = 30.0f;
90
	m_cameraZoom = 15.0f;
91
	m_cameraZoomLBound = 2.0f;
Oliver Bock's avatar
Oliver Bock committed
92
93
	m_mouseLastX = 0;
	m_mouseLastY = 0;
94

Oliver Bock's avatar
Oliver Bock committed
95
	// update camera based on settings above
96
	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
97

Oliver Bock's avatar
Oliver Bock committed
98
	// finally, create initial pulse profile based on settings above
99
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
100
101
102
103
}

PulsarAnimationWidget::~PulsarAnimationWidget()
{
Oliver Bock's avatar
Oliver Bock committed
104
105
	if(m_quadricCompanionOrbitPlane) gluDeleteQuadric(m_quadricCompanionOrbitPlane);
	if(m_quadricCompanion) gluDeleteQuadric(m_quadricCompanion);
106
	if(m_quadricPulsarOrbitPlane) gluDeleteQuadric(m_quadricPulsarOrbitPlane);
Oliver Bock's avatar
Oliver Bock committed
107
108
109
	if(m_quadricPulsar) gluDeleteQuadric(m_quadricPulsar);
	if(m_quadricPulsarCone1) gluDeleteQuadric(m_quadricPulsarCone1);
	if(m_quadricPulsarCone2) gluDeleteQuadric(m_quadricPulsarCone2);
110
	if(m_quadricPulsarSpinAxis) gluDeleteQuadric(m_quadricPulsarSpinAxis);
111
	if(m_quadricPulsarMagneticAxis) gluDeleteQuadric(m_quadricPulsarMagneticAxis);
112
113
114

	if(m_pulsarTexture) deleteTexture(m_pulsarTexture);
	if(m_backgroundTexture) deleteTexture(m_backgroundTexture);
Oliver Bock's avatar
Oliver Bock committed
115
116
117
118
}

void PulsarAnimationWidget::initializeGL()
{
Oliver Bock's avatar
Oliver Bock committed
119
120
121
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClearDepth(1.0f);
	glDepthFunc(GL_LEQUAL);
122
123
124
	glEnable(GL_DEPTH_TEST);

	glShadeModel(GL_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
125
126
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

127
	GLfloat LightAmbient[] = { 0.3f, 0.3f, 0.3f, 1.0f };
Oliver Bock's avatar
Oliver Bock committed
128
129
130
131
132
133
134
135
136
	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);
137
	glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 50.0);
Oliver Bock's avatar
Oliver Bock committed
138
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
139
	glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0);
Oliver Bock's avatar
Oliver Bock committed
140
141
142
143

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

145
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
146
	glEnable(GL_BLEND);
147

Oliver Bock's avatar
Oliver Bock committed
148
149
	m_quadricCompanionOrbitPlane = gluNewQuadric();
	m_quadricCompanion = gluNewQuadric();
150
	m_quadricPulsarOrbitPlane = gluNewQuadric();
Oliver Bock's avatar
Oliver Bock committed
151
152
153
	m_quadricPulsar = gluNewQuadric();
    m_quadricPulsarCone1 = gluNewQuadric();
    m_quadricPulsarCone2 = gluNewQuadric();
154
    m_quadricPulsarSpinAxis = gluNewQuadric();
155
    m_quadricPulsarMagneticAxis = gluNewQuadric();
156

Oliver Bock's avatar
Oliver Bock committed
157
158
    gluQuadricNormals(m_quadricCompanionOrbitPlane, GLU_SMOOTH);
    gluQuadricNormals(m_quadricCompanion, GLU_SMOOTH);
159
    gluQuadricNormals(m_quadricPulsarOrbitPlane, GLU_SMOOTH);
Oliver Bock's avatar
Oliver Bock committed
160
161
162
    gluQuadricNormals(m_quadricPulsar, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone1, GLU_SMOOTH);
    gluQuadricNormals(m_quadricPulsarCone2, GLU_SMOOTH);
163
    gluQuadricNormals(m_quadricPulsarSpinAxis, GLU_SMOOTH);
164
    gluQuadricNormals(m_quadricPulsarMagneticAxis, GLU_SMOOTH);
165

166
    // load textures
167
    m_pulsarTexture = bindTexture(QImage(":/textures/resources/texture_pulsar.png"), GL_TEXTURE_2D, GL_RGBA);
168
169
//    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);
170

171
    // use mipmapped textures
172
173
174
    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
175
176
177
    // 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
178
179
180
181
}

void PulsarAnimationWidget::resizeGL(int w, int h)
{
Oliver Bock's avatar
Oliver Bock committed
182
183
184
185
186
	glViewport(0, 0, w, h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

Oliver Bock's avatar
Oliver Bock committed
187
	gluPerspective(45.0f, (GLfloat)w / (GLfloat)h, 0.1f, 500.0f);
Oliver Bock's avatar
Oliver Bock committed
188
189
190
191
192
193
194
195
196
197
198
199

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

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

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

200
201
	gluLookAt(m_cameraPosX, m_cameraPosY, m_cameraPosZ,
			  0.0, 0.0, 0.0,
202
			  0.0, 1.0, 0.0);
Oliver Bock's avatar
Oliver Bock committed
203
204
205
206
207

	// 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 };
208
	static GLfloat low_shininess[] = { 2.5 };
209
	static GLfloat translucent[] = { 1.0, 1.0, 1.0, 0.33 };
210

Oliver Bock's avatar
Oliver Bock committed
211
212
213
214
215
	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
216

217
	// draw companion
Oliver Bock's avatar
Oliver Bock committed
218
	glPushMatrix();
Oliver Bock's avatar
Oliver Bock committed
219
		glTranslatef(sin((m_orbitRotationAngle + 180.0f) * deg2rad) * m_companionSemiMajorAxis,
220
					 0.0f,
Oliver Bock's avatar
Oliver Bock committed
221
					 cos((m_orbitRotationAngle + 180.0f) * deg2rad) * m_companionSemiMajorAxis);
Oliver Bock's avatar
Oliver Bock committed
222
		gluSphere(m_quadricCompanion, 1.0f, 32, 32);
Oliver Bock's avatar
Oliver Bock committed
223
224
	glPopMatrix();

225
	// draw pulsar
Oliver Bock's avatar
Oliver Bock committed
226
	glPushMatrix();
Oliver Bock's avatar
Oliver Bock committed
227
		glTranslatef(sin(m_orbitRotationAngle * deg2rad) * m_pulsarSemiMajorAxis,
228
					 0.0f,
Oliver Bock's avatar
Oliver Bock committed
229
					 cos(m_orbitRotationAngle * deg2rad) * m_pulsarSemiMajorAxis);
230
231

		glPushMatrix();
232
233
			glRotatef(m_pulsarSpinAxisInclination, 0.0f, 0.0f, 1.0f);
			glRotatef(m_pulsarRotationAngle, 0.0f, 1.0f, 0.0f);
234

235
			// draw spin axis
Oliver Bock's avatar
Oliver Bock committed
236
			if(m_showRotationAxes) {
237
238
				glPushMatrix();
					glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
239
					glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
240
241
242
243
244
					glTranslatef(0.0f, 0.0f, -5.0f);
					gluCylinder(m_quadricPulsarSpinAxis, 0.05f, 0.05f, 10.0f, 32, 1);
				glPopMatrix();
			}

245
246
247
248
249
			// 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);
250
251
252

			glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
253
			gluSphere(m_quadricPulsar, 1.0f, 32, 32);
254

255
			// disable texturing
256
257
258
	        glDisable(GL_TEXTURE_GEN_S);
	        glDisable(GL_TEXTURE_GEN_T);
	        glDisable(GL_TEXTURE_2D);
259
260
		glPopMatrix();

261
262
263
264
265
266
267
		// 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);

268
		// first cone
269
		glPushMatrix();
270
271
272
273
274
			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);
275

276
			// draw magnetic axis (for both cones)
Oliver Bock's avatar
Oliver Bock committed
277
			if(m_showRotationAxes) {
278
279
280
281
282
				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();
283
284
			}

285
			glTranslatef(0.0f, 0.0f, -4.0f);
286
287
288

			glMaterialfv(GL_FRONT, GL_AMBIENT, coneAmbient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, coneDiffuse);
289
			gluCylinder(m_quadricPulsarCone1, 0.475f, 0.0f, 3.0f, 32, 32);
290
291
		glPopMatrix();

292
		// second cone
293
		glPushMatrix();
294
295
			glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
			glRotatef(-m_pulsarSpinAxisInclination, 0.0f, 1.0f, 0.0f);
296

297
298
			glRotatef(m_pulsarRotationAngle - 90.0f, 0.0f, 0.0f, 1.0f);
			glRotatef(m_pulsarMagneticAxisInclination, 1.0f, 0.0f, 0.0f);
299

300
			glTranslatef(0.0f, 0.0f, -4.0f);
301
302
303

			glMaterialfv(GL_FRONT, GL_AMBIENT, coneAmbient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, coneDiffuse);
304
			gluCylinder(m_quadricPulsarCone2, 0.475f, 0.0f, 3.0f, 32, 32);
305
		glPopMatrix();
Oliver Bock's avatar
Oliver Bock committed
306
	glPopMatrix();
307

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
	// 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
328
	// draw orbital planes
329
	if(m_cameraInteraction || m_showOrbits) {
330
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
		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
354
355
		glPushMatrix();
			glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
356
			gluDisk(m_quadricPulsarOrbitPlane,
357
358
					m_pulsarSemiMajorAxis - sizeOffset,
					m_pulsarSemiMajorAxis + sizeOffset,
359
360
					64, 1);
		glPopMatrix();
361
	}
Oliver Bock's avatar
Oliver Bock committed
362
363
}

Oliver Bock's avatar
Oliver Bock committed
364
365
void PulsarAnimationWidget::runAnimation()
{
Oliver Bock's avatar
Oliver Bock committed
366
	m_frameTimer.start(1000.0f / m_framesPerSecond);
Oliver Bock's avatar
Oliver Bock committed
367
}
Oliver Bock's avatar
Oliver Bock committed
368

Oliver Bock's avatar
Oliver Bock committed
369
370
371
372
373
374
375
376
void PulsarAnimationWidget::pauseAnimation()
{
	m_frameTimer.stop();
}

void PulsarAnimationWidget::stopAnimation()
{
	m_frameTimer.stop();
377
	resetParameters();
Oliver Bock's avatar
Oliver Bock committed
378
379
380
381

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
382
void PulsarAnimationWidget::updateFrame()
Oliver Bock's avatar
Oliver Bock committed
383
{
Oliver Bock's avatar
Oliver Bock committed
384
385
386
	m_pulsarRotationAngle += m_pulsarRotationDelta;
	if(m_pulsarRotationAngle > 360) {
		m_pulsarRotationAngle = 0.0f;
387
		updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
388
	}
Oliver Bock's avatar
Oliver Bock committed
389
390
391
	m_orbitRotationAngle += m_orbitRotationDelta;
	if(m_orbitRotationAngle > 360) {
		m_orbitRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
392
393
	}

Oliver Bock's avatar
Oliver Bock committed
394
	updateGL();
Oliver Bock's avatar
Oliver Bock committed
395
396

	emit pulsarAnimationStep(m_pulsarRotationDelta);
397
398
}

399
400
401
402
403
404
405
void PulsarAnimationWidget::showOrbits(bool enabled)
{
	m_showOrbits = enabled;

	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
406
407
408
409
410
411
412
void PulsarAnimationWidget::showRotationAxes(bool enabled)
{
	m_showRotationAxes = enabled;

	updateGL();
}

413
414
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
415
416
	Q_UNUSED(event);

417
418
419
420
	m_cameraInteraction = true;
	updateGL();
}

421
422
423
424
425
void PulsarAnimationWidget::mouseMoveEvent(QMouseEvent *event)
{
	Qt::MouseButtons buttons = event->buttons();
	if((buttons & Qt::LeftButton) == Qt::LeftButton) {
		if(m_mouseLastX != 0) {
Oliver Bock's avatar
Oliver Bock committed
426
			m_mouseAngleH -= (m_mouseLastX - event->x()) * 0.5f ;
Oliver Bock's avatar
Oliver Bock committed
427
			m_mouseAngleH = m_mouseAngleH < 360 ? m_mouseAngleH : 0;
428
429
430

		}
		if(m_mouseLastY != 0) {
Oliver Bock's avatar
Oliver Bock committed
431
			m_mouseAngleV -= (m_mouseLastY - event->y()) * 0.5f;
Oliver Bock's avatar
Oliver Bock committed
432
433
			m_mouseAngleV = m_mouseAngleV < 90 ? m_mouseAngleV : 90;
			m_mouseAngleV = m_mouseAngleV > -90 ? m_mouseAngleV : -90;
434
435
436
437
438
439
440
		}

		m_mouseLastX = event->x();
		m_mouseLastY = event->y();
	}
	else if((buttons & Qt::RightButton) == Qt::RightButton) {
		if(m_mouseLastY != 0) {
Oliver Bock's avatar
Oliver Bock committed
441
			m_cameraZoom -= (m_mouseLastY - event->y()) * 0.5f;
Oliver Bock's avatar
Oliver Bock committed
442
			m_cameraZoom = m_cameraZoom >= m_cameraZoomLBound ? m_cameraZoom : m_cameraZoomLBound;
443
444
445
446
447
448
449
450
451
452
453
			updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
		}

		m_mouseLastY = event->y();
	}

	updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}

void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event)
{
454
455
	Q_UNUSED(event);

456
457
	m_mouseLastX = 0;
	m_mouseLastY = 0;
458
459
	m_cameraInteraction = false;
	updateGL();
460
461
462
463
464
465
}

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
466
	m_cameraPosZ = cos(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
467

468
469
	updatePulseProfile();

470
471
472
	updateGL();
}

Oliver Bock's avatar
Oliver Bock committed
473
474
475
476
477
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
	m_framesPerSecond = fps;
}

Oliver Bock's avatar
Oliver Bock committed
478
void PulsarAnimationWidget::setPulsarSemiMajorAxis(const float length)
Oliver Bock's avatar
Oliver Bock committed
479
{
Oliver Bock's avatar
Oliver Bock committed
480
481
482
	m_pulsarSemiMajorAxis = length;
	m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;
	updateOrbitPeriod();
483
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
484
485

	updateGL();
Oliver Bock's avatar
Oliver Bock committed
486
}
487

Oliver Bock's avatar
Oliver Bock committed
488
void PulsarAnimationWidget::setCompanionMass(const float mass)
489
{
Oliver Bock's avatar
Oliver Bock committed
490
491
	m_companionMass = mass;
	updateOrbitRadii();
492
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
493
494

	updateGL();
495
496
}

Oliver Bock's avatar
Oliver Bock committed
497
void PulsarAnimationWidget::setPulsarMass(const float mass)
498
{
Oliver Bock's avatar
Oliver Bock committed
499
500
	m_pulsarMass = mass;
	updateOrbitRadii();
501
	updatePulseProfile();
Oliver Bock's avatar
Oliver Bock committed
502
503
504
505
506
507
508

	updateGL();
}

void PulsarAnimationWidget::setPulsarSpinFrequency(const float frequency)
{
	m_pulsarRotationDelta = (360.0f * frequency) / m_framesPerSecond;
509
	updatePulseProfile();
510
}
511

512
513
514
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
{
	m_pulsarSpinAxisInclination = degrees;
515
	updatePulseProfile();
516
517
518
519

	updateGL();
}

520
521
522
void PulsarAnimationWidget::setPulsarMagneticAxisInclination(const int degrees)
{
	m_pulsarMagneticAxisInclination = degrees;
Oliver Bock's avatar
Oliver Bock committed
523
	updatePulseProfile();
524
525
526

	updateGL();
}
527

Oliver Bock's avatar
Oliver Bock committed
528
529
530
void PulsarAnimationWidget::updateOrbitPeriod()
{
	m_orbitalPeriod = 3.1553e7 * sqrt(
Oliver Bock's avatar
Oliver Bock committed
531
532
						(pow(m_pulsarSemiMajorAxis, 3.0f) * pow(m_pulsarMass+m_companionMass, 2.0f)) /
						 pow(m_companionMass, 3.0f)
Oliver Bock's avatar
Oliver Bock committed
533
534
535
536
537
538
539
540
541
542
543
					  );

	// 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(
Oliver Bock's avatar
Oliver Bock committed
544
545
546
								(pow(m_orbitalPeriod, 2.0f) * pow(m_companionMass, 3.0f)) /
								 pow(m_pulsarMass+m_companionMass, 2.0f),
								 1.0f/3.0f
Oliver Bock's avatar
Oliver Bock committed
547
548
549
550
551
552
553
							);

	m_companionSemiMajorAxis = (m_pulsarMass/m_companionMass) * m_pulsarSemiMajorAxis;

	emit pulsarSemiMajorAxisUpdated(m_pulsarSemiMajorAxis);
}

554
555
556
557
void PulsarAnimationWidget::resetParameters()
{
	m_pulsarRotationAngle = 0.0f;
	m_orbitRotationAngle = 0.0f;
Oliver Bock's avatar
Oliver Bock committed
558
559

	emit pulsarAnimationReset();
560
}
561
562
563

void PulsarAnimationWidget::updatePulseProfile()
{
Oliver Bock's avatar
Oliver Bock committed
564
565
566
567
568
569
570
571
572
573
574
575
576
577
	// 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;
	const double	deltaPhiRot		= deg2rad * 1.0;
	const double	deltaPhiOrb		= deg2rad * deltaPhiRot * m_orbitRotationDelta / 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.0f) + pow(yk, 2.0f) + pow(zk, 2.0f);
	const double	alpha			= deg2rad * (90.0f - m_mouseAngleH);
	const double	delta			= deg2rad * m_mouseAngleV;
	const double	gaussProfile	= 0.012337;
578
579
580

	for(int x = 0; x < 360; ++x) {
		// determine angle between pulsar's magnetic axis and line of sight
Oliver Bock's avatar
Oliver Bock committed
581
		phiOrb += deltaPhiOrb;
582
583
584
585
586
587
		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;

Oliver Bock's avatar
Oliver Bock committed
588
		double b = sqrt(pow(rp,2.0) + cam - (2.0 * sqrt(cam) * rp * cos(delta) * sin(alpha + phiOrb)));
589
590

		// determine pulse amplitude
Oliver Bock's avatar
Oliver Bock committed
591
		double amp = exp(-2.0 * (1.0 - fabs(a/b)) / gaussProfile);
592
593
594
595
596
597
598
599

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

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