Select Git revision
pulsaranimationwidget.cpp
pulsaranimationwidget.cpp 25.34 KiB
/******************************************************************************
* 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"
// workaround for lack of C99 support in C++
#define isnan(x) ((x) != (x))
const double PulsarAnimationWidget::deg2rad = PI/180.0;
PulsarAnimationWidget::PulsarAnimationWidget(QWidget *parent) :
QGLWidget(QGLFormat(QGL::AlphaChannel | QGL::SampleBuffers), parent),
m_frameTimer(),
m_pulseProfile(360, 0.0)
{
QString msgThis = tr("3D animation");
if(!format().directRendering()) {
QString msg = tr("Sorry, no direct rendering support for %1...");
qWarning() << msg.arg(msgThis);
}
if(!format().doubleBuffer()) {
QString msg = tr("Sorry, no double buffering support for %1...");
qWarning() << msg.arg(msgThis);
}
if(!format().rgba()) {
QString msg = tr("Sorry, no RGBA support for %1...");
qWarning() << msg.arg(msgThis);
}
if(!format().alpha()) {
QString msg = tr("Sorry, no alpha channel support for %1...");
qWarning() << msg.arg(msgThis);
}
if(!format().sampleBuffers()) {
QString msg = tr("Sorry, no multisampling support for %1...");
qWarning() << msg.arg(msgThis);
}
// connect primary rendering timer to local callback
connect(&m_frameTimer, SIGNAL(timeout()), this, SLOT(updateFrame()));
// initialize quadric pointers
m_quadricPulsar = NULL;
m_quadricPulsarSpinAxis = NULL;
m_quadricPulsarSpinAxisTop1 = NULL;
m_quadricPulsarSpinAxisTop2 = NULL;
m_quadricPulsarMagneticAxis = NULL;
m_quadricPulsarConeRim1 = NULL;
m_quadricPulsarConeRim2 = NULL;
m_quadricLineOfSight = NULL;
m_quadricLineOfSightTop = NULL;
m_quadricLineOfSightCone = NULL;
m_quadricLineOfSightConeBase = NULL;
// initialize texture pointers
m_backgroundTexture = 0;
m_beamTexture = 0;
// initial render timing settings
m_framesPerSecond = 25;
m_pulsarRotationDelta = 0.0;
m_pulsarRotationAngle = 0.0;
m_pulsarRadius = 0.5;
m_pulsarBeamLength = 3.0f;
setPulsarSpinAxisInclination(30);
setPulsarMagneticAxisInclination(20);
setPulsarBeamAngle(74);
// initial spin frequency of 0.5 Hz
m_pulsarRotationDelta = (360.0 * 0.5) / m_framesPerSecond;
// initial view features
m_showRotationAxes = false;
m_cameraInteraction = false;
// initial view settings
m_mouseAngleH = 0.0;
m_mouseAngleV = 0.0;
m_cameraZoom = 80.0;
m_cameraZoomLBound = 10.0;
m_cameraZoomUBound = 4500.0;
m_mouseLastX = 0;
m_mouseLastY = 0;
// update camera based on settings above
updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}
PulsarAnimationWidget::~PulsarAnimationWidget()
{
if(m_quadricPulsar) gluDeleteQuadric(m_quadricPulsar);
if(m_quadricPulsarConeRim1) gluDeleteQuadric(m_quadricPulsarConeRim1);
if(m_quadricPulsarConeRim2) gluDeleteQuadric(m_quadricPulsarConeRim2);
if(m_quadricPulsarSpinAxis) gluDeleteQuadric(m_quadricPulsarSpinAxis);
if(m_quadricPulsarSpinAxisTop1) gluDeleteQuadric(m_quadricPulsarSpinAxisTop1);
if(m_quadricPulsarSpinAxisTop2) gluDeleteQuadric(m_quadricPulsarSpinAxisTop2);
if(m_quadricPulsarMagneticAxis) gluDeleteQuadric(m_quadricPulsarMagneticAxis);
if(m_quadricLineOfSight) gluDeleteQuadric(m_quadricLineOfSight);
if(m_quadricLineOfSightTop) gluDeleteQuadric(m_quadricLineOfSightTop);
if(m_quadricLineOfSightCone) gluDeleteQuadric(m_quadricLineOfSightCone);
if(m_quadricLineOfSightConeBase) gluDeleteQuadric(m_quadricLineOfSightConeBase);
if(m_backgroundTexture) deleteTexture(m_backgroundTexture);
if(m_beamTexture) deleteTexture(m_beamTexture);
}
void PulsarAnimationWidget::initializeGL()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
GLfloat LightAmbient[] = {0.3, 0.3, 0.3, 1.0};
GLfloat LightDiffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat LightSpecular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat LightPosition[] = {0.0, 0.0, 0.0, 1.0};
GLfloat spot_direction[] = {0.0, 0.0, 0.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);
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 50.0);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glEnable(GL_LIGHT0);
// glEnable(GL_LIGHTING);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
m_quadricPulsar = gluNewQuadric();
m_quadricPulsarConeRim1 = gluNewQuadric();
m_quadricPulsarConeRim2 = gluNewQuadric();
m_quadricPulsarSpinAxis = gluNewQuadric();
m_quadricPulsarSpinAxisTop1 = gluNewQuadric();
m_quadricPulsarSpinAxisTop2 = gluNewQuadric();
m_quadricPulsarMagneticAxis = gluNewQuadric();
m_quadricLineOfSight = gluNewQuadric();
m_quadricLineOfSightTop = gluNewQuadric();
m_quadricLineOfSightCone = gluNewQuadric();
m_quadricLineOfSightConeBase = gluNewQuadric();
gluQuadricNormals(m_quadricPulsar, GLU_SMOOTH);
gluQuadricNormals(m_quadricPulsarConeRim1, GLU_SMOOTH);
gluQuadricNormals(m_quadricPulsarConeRim2, GLU_SMOOTH);
gluQuadricNormals(m_quadricPulsarSpinAxis, GLU_SMOOTH);
gluQuadricNormals(m_quadricPulsarSpinAxisTop1, GLU_SMOOTH);
gluQuadricNormals(m_quadricPulsarSpinAxisTop2, GLU_SMOOTH);
gluQuadricNormals(m_quadricPulsarMagneticAxis, GLU_SMOOTH);
gluQuadricNormals(m_quadricLineOfSight, GLU_SMOOTH);
gluQuadricNormals(m_quadricLineOfSightTop, GLU_SMOOTH);
gluQuadricNormals(m_quadricLineOfSightCone, GLU_SMOOTH);
gluQuadricNormals(m_quadricLineOfSightConeBase, GLU_SMOOTH);
// query max texture size (estimate)
GLint maxTextureSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
// prepare local messages
QString msgShape = tr("%1 texture shape not quadratic!");
QString msgPower = tr("%1 texture dimensions not a power of 2!");
QString msgSize = tr("Maximum texture size exceeded! Scaling down %1 texture to %2x%3...");
// prepare and check background texture
QImage backgroundTexture(":/textures/resources/texture_background_carina.png");
if(backgroundTexture.width() != backgroundTexture.height()) {
qWarning() << msgShape.arg(tr("Background"));
}
else {
double integer = 0.0;
double fraction = 0.0;
fraction = modf(log(backgroundTexture.width()) / log(2.0), &integer);
if(fraction > 0.0) {
qWarning() << msgPower.arg(tr("Background"));
}
}
if(backgroundTexture.width() > maxTextureSize) {
qWarning() << msgSize.arg(tr("background").arg(maxTextureSize).arg(maxTextureSize));
backgroundTexture = backgroundTexture.scaled(maxTextureSize, maxTextureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
// prepare and check beam texture
QImage beamTexture(":/textures/resources/texture_beam.png");
if(beamTexture.width() != beamTexture.height()) {
qWarning() << msgShape.arg(tr("Beam"));
}
else {
double integer = 0.0;
double fraction = 0.0;
fraction = modf(log(beamTexture.width()) / log(2.0), &integer);
if(fraction > 0.0) {
qWarning() << msgPower.arg(tr("Beam"));
}
}
if(beamTexture.width() > maxTextureSize) {
qWarning() << msgSize.arg(tr("beam").arg(maxTextureSize).arg(maxTextureSize));
beamTexture = beamTexture.scaled(maxTextureSize, maxTextureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
// bind textures
m_backgroundTexture = bindTexture(backgroundTexture, GL_TEXTURE_2D, GL_RGBA);
m_beamTexture = bindTexture(beamTexture, GL_TEXTURE_2D, GL_RGBA);
// use mipmapped textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
}
void PulsarAnimationWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(4.5, (GLfloat)w / (GLfloat)h, 0.1, 5000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void PulsarAnimationWidget::paintGL()
{
GLfloat x,y,angle;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// initial perspective/camera setup
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(m_cameraPosX, m_cameraPosY, m_cameraPosZ,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
// save current state (the following is using parallel projection)
glMatrixMode(GL_PROJECTION);
glPushMatrix();
{
glLoadIdentity();
glOrtho(0, width(), 0, height(), 0.1, 501.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glLoadIdentity();
// draw backdrop first so that foreground alpha blending works correctly
glColor3f(1.0f, 1.0f, 1.0f);
glTranslatef(0.0, 0.0, -501.0);
drawTexture(QPointF(0.0, 0.0), m_backgroundTexture);
// restore original state
glMatrixMode(GL_PROJECTION);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
glPopMatrix();
// define materials
// 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};
static GLfloat low_shininess[] = {2.5};
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);
// let's draw everything as wireframe model
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
// draw scence
glPushMatrix();
{
//draw line of sight (observer)
if(m_showRotationAxes) {
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glColor3f(0.33f, 0.33f, 1.0f);
glPushMatrix();
{
glTranslatef(0.0, 0.0, m_pulsarRadius);
gluCylinder(m_quadricLineOfSightCone, 0, 0.1, 0.5, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, m_pulsarRadius + 0.5);
gluDisk(m_quadricLineOfSightConeBase, 0, 0.1, 32, 8);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, m_pulsarRadius + 0.5);
gluCylinder(m_quadricLineOfSight, 0.025, 0.025, 3.01, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, m_pulsarRadius + 3.51);
gluDisk(m_quadricLineOfSightTop, 0, 0.025, 32, 8);
}
glPopMatrix();
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
// draw pulsar
glPushMatrix();
{
glRotatef(-m_pulsarSpinAxisInclination, 1.0, 0.0, 0.0);
glRotatef(m_pulsarRotationAngle, 0.0, 0.0, 1.0);
// draw spin axis
if(m_showRotationAxes) {
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glColor3f(1.0f, 1.0f, 1.0f);
glPushMatrix();
{
glTranslatef(0.0, 0.0, -4.0);
gluCylinder(m_quadricPulsarSpinAxis, 0.020, 0.020, 8.0, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, -4.0);
gluDisk(m_quadricPulsarSpinAxisTop1, 0, 0.020, 32, 8);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, 4.0);
gluDisk(m_quadricPulsarSpinAxisTop2, 0, 0.020, 32, 8);
}
glPopMatrix();
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
// gives pulsar spherical appearance
glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
gluSphere(m_quadricPulsar, m_pulsarRadius, 32, 32);
glDisable(GL_LIGHTING);
}
glPopMatrix();
// first cone (pointing away from camera)
glPushMatrix();
{
glRotatef(-m_pulsarSpinAxisInclination, 1.0, 0.0, 0.0);
glRotatef(m_pulsarRotationAngle - 90.0, 0.0, 0.0, 1.0);
glRotatef(m_pulsarMagneticAxisInclination, 0.0, 1.0, 0.0);
// draw magnetic axis (for both cones)
if(m_showRotationAxes) {
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glColor3f(1.0f, 1.0f, 0.0f);
glPushMatrix();
{
glTranslatef(0.0, 0.0, -4.0);
gluCylinder(m_quadricPulsarMagneticAxis, 0.020, 0.020, 8.0, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, -4.0);
gluDisk(m_quadricPulsarSpinAxisTop1, 0, 0.020, 32, 8);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, 4.0);
gluDisk(m_quadricPulsarSpinAxisTop2, 0, 0.020, 32, 8);
}
glPopMatrix();
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
glTranslatef(0.0, 0.0, -m_pulsarBeamLength);
// draw first cone's outer layer
glBegin(GL_TRIANGLE_FAN);
{
// Pinnacle of cone is shared vertex for fan, moved up z-axis
// to produce a cone instead of a circle
glColor4f(1.0f, 1.0f, 0.0f, 0.33f);
glVertex3f(0.0f, 0.0f, m_pulsarBeamLength);
// Loop around in a circle and specify even points along the circle
// as the vertices of the triangle fan (32 sections)
for(angle = 0.0f; angle < (2.0f*PI); angle += (PI/32.0f))
{
// Calculate x and y position of the next vertex
x = m_pulsarBeamOuterRadius * sin(angle);
y = m_pulsarBeamOuterRadius * cos(angle);
// Specify the next vertex for the triangle fan
glVertex2f(x, y);
}
}
glEnd();
// draw first cone's "base" (textured bottom to visualize beam intensity)
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// create texture coordinates and enable texturing
gluQuadricTexture(m_quadricPulsarConeRim1, GL_TRUE);
glBindTexture(GL_TEXTURE_2D, m_beamTexture);
glEnable(GL_TEXTURE_2D);
gluDisk(m_quadricPulsarConeRim1, 0, m_pulsarBeamOuterRadius, 32, 1);
// disable texturing
glDisable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
glPopMatrix();
// second cone (pointing towards from camera)
glPushMatrix();
{
glRotatef(180.0, 1.0, 0.0, 0.0);
glRotatef(-m_pulsarSpinAxisInclination, 1.0, 0.0, 0.0);
glRotatef(-m_pulsarRotationAngle - 90.0, 0.0, 0.0, 1.0);
glRotatef(m_pulsarMagneticAxisInclination, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, -m_pulsarBeamLength);
// draw second cone's outer layer
glBegin(GL_TRIANGLE_FAN);
{
// Pinnacle of cone is shared vertex for fan, moved up z-axis
// to produce a cone instead of a circle
glColor4f(1.0f, 1.0f, 0.0f, 0.33f);
glVertex3f(0.0f, 0.0f, m_pulsarBeamLength);
// Loop around in a circle and specify even points along the circle
// as the vertices of the triangle fan (32 sections)
for(angle = 0.0f; angle < (2.0f*PI); angle += (PI/32.0f))
{
// Calculate x and y position of the next vertex
x = m_pulsarBeamOuterRadius * sin(angle);
y = m_pulsarBeamOuterRadius * cos(angle);
// Specify the next vertex for the triangle fan
glVertex2f(x, y);
}
}
glEnd();
// draw second cone's "base" (textured bottom to visualize beam intensity)
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// create texture coordinates and enable texturing
gluQuadricTexture(m_quadricPulsarConeRim2, GL_TRUE);
glBindTexture(GL_TEXTURE_2D, m_beamTexture);
glEnable(GL_TEXTURE_2D);
gluDisk(m_quadricPulsarConeRim2, 0, m_pulsarBeamOuterRadius, 32, 1);
// disable texturing
glDisable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
glPopMatrix();
}
glPopMatrix();
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
// save current state (the following is using parallel projection)
glMatrixMode(GL_PROJECTION);
glPushMatrix();
{
glLoadIdentity();
glOrtho(0, width(), 0, height(), 0.1, 501.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glLoadIdentity();
// draw copyright info last (appears in front of everything)
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
QFont font;
font.setPointSize(11);
font.setBold(true);
font.setFamily("Arial");
font.setStyleStrategy((QFont::StyleStrategy) (QFont::OpenGLCompatible | QFont::PreferQuality));
renderText(10, 25, -100, QString::fromLocal8Bit("Copyright © 2009-2010"), font);
renderText(10, 10, -100, QString::fromLocal8Bit("Max-Planck-Insitut für Gravitationsphysik"), font);
// restore original state
glMatrixMode(GL_PROJECTION);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
glPopMatrix();
}
void PulsarAnimationWidget::runAnimation()
{
m_frameTimer.start(qRound(1000.0 / m_framesPerSecond));
}
void PulsarAnimationWidget::pauseAnimation()
{
m_frameTimer.stop();
}
void PulsarAnimationWidget::stopAnimation()
{
m_frameTimer.stop();
resetParameters();
updateGL();
}
void PulsarAnimationWidget::resetViewpoint()
{
m_mouseAngleH = 0.0;
m_mouseAngleV = 0.0;
m_cameraZoom = 80.0;
updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}
void PulsarAnimationWidget::updateFrame()
{
m_pulsarRotationAngle += m_pulsarRotationDelta;
if(m_pulsarRotationAngle > 360.0) {
m_pulsarRotationAngle -= 360.0;
updatePulseProfile();
}
updateGL();
emit pulsarAnimationStep(m_pulsarRotationAngle);
}
void PulsarAnimationWidget::showRotationAxes(bool enabled)
{
m_showRotationAxes = enabled;
updateGL();
}
void PulsarAnimationWidget::mousePressEvent(QMouseEvent *event)
{
Q_UNUSED(event);
m_cameraInteraction = true;
updateGL();
}
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());
m_mouseAngleH = m_mouseAngleH < 360 ? m_mouseAngleH : 0;
m_mouseAngleH = m_mouseAngleH >= 0 ? m_mouseAngleH : 359;
}
if(m_mouseLastY != 0) {
m_mouseAngleV -= (m_mouseLastY - event->y());
m_mouseAngleV = m_mouseAngleV < 90 ? m_mouseAngleV : 90;
m_mouseAngleV = m_mouseAngleV > -90 ? m_mouseAngleV : -90;
}
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());
m_cameraZoom = m_cameraZoom >= m_cameraZoomLBound ? m_cameraZoom : m_cameraZoomLBound;
m_cameraZoom = m_cameraZoom >= m_cameraZoomUBound ? m_cameraZoomUBound : m_cameraZoom;
}
m_mouseLastY = event->y();
}
updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}
void PulsarAnimationWidget::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);
m_mouseLastX = 0;
m_mouseLastY = 0;
m_cameraInteraction = false;
updateGL();
}
void PulsarAnimationWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event);
// update and propagate pulse profile
updatePulseProfile();
}
void PulsarAnimationWidget::updateCameraPosition(const double angleH, const double angleV, const double zoom)
{
m_cameraPosX = sin(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
m_cameraPosY = sin(angleV * deg2rad) * zoom;
m_cameraPosZ = cos(angleH * deg2rad) * cos(angleV * deg2rad) * zoom;
updateGL();
qDebug("Camera (x,y,z,+,h,v): %f, %f, %f, %f, %f, %f", m_cameraPosX, m_cameraPosY, m_cameraPosZ, zoom, angleH, angleV);
}
void PulsarAnimationWidget::setFramePerSecond(const unsigned int fps)
{
m_framesPerSecond = fps;
}
void PulsarAnimationWidget::setPulsarSpinFrequency(const double frequency)
{
m_pulsarRotationDelta = (360.0 * frequency) / m_framesPerSecond;
updatePulseProfile();
}
void PulsarAnimationWidget::setPulsarSpinAxisInclination(const int degrees)
{
m_pulsarSpinAxisInclination = degrees;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::setPulsarMagneticAxisInclination(const int degrees)
{
m_pulsarMagneticAxisInclination = degrees;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::setPulsarBeamAngle(const int degrees)
{
double beamTexturePeakCorrectionFactor = 0.83;
double correctedOuterRadius;
// compute visual radius
m_pulsarBeamOuterRadius = tan(deg2rad * degrees * 0.5f) * m_pulsarBeamLength;
// compute corrected angle for pulse profile
correctedOuterRadius = m_pulsarBeamOuterRadius * beamTexturePeakCorrectionFactor;
m_pulsarBeamAngle = 2 * atan(correctedOuterRadius / m_pulsarBeamLength) * 180.0/PI;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::resetParameters()
{
m_pulsarRotationAngle = 0.0;
updatePulseProfile();
emit pulsarAnimationStep(m_pulsarRotationAngle);
}
void PulsarAnimationWidget::updatePulseProfile()
{
// prepare parameters (e.g. convert to radians where necessary)
const double deltaPhiRot = deg2rad * 1.0;
const double gamma = deg2rad * m_pulsarSpinAxisInclination;
const double alpha = deg2rad * m_pulsarMagneticAxisInclination;
const double beta = -alpha + gamma;
const double rho = deg2rad * m_pulsarBeamAngle * 0.5;
const double gaussProfile = 0.04;
const double t1 = pow(sin(rho*0.5), 2) - pow(sin(beta*0.5), 2);
const double t2 = sin(alpha) * sin(beta+alpha);
const double W = 2 * asin(sqrt( t1 / t2 ));
qDebug("alpha: %f, beta: %f, rho: %f, t1: %f, t2: %f, W: %f", alpha*180/PI, beta*180/PI, rho*180/PI, t1*180/PI, t2*180/PI, W*180/PI);
for(int x = 0; x < 360; ++x) {
// update pulsar rotation angle
const double phiRot = x * deltaPhiRot;
// determine and store pulse amplitude
if(!isnan(W)){
m_pulseProfile[x] = exp(-2.0 * pow(phiRot - W, 2) / gaussProfile) + exp(-2.0 * pow(phiRot + W - 2.0 * PI, 2) / gaussProfile);
}
else {
m_pulseProfile[x] = 0.0;
}
}
// propagate new profile
emit pulseProfileUpdated(m_pulseProfile);
}