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