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