Select Git revision
pulsaranimationwidget.cpp
-
Bruce Allen authored
Add some frequency and amplitude modulation to the plot
Bruce Allen authoredAdd some frequency and amplitude modulation to the plot
pulsaranimationwidget.cpp 19.11 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"
#include "lib/antenna_lib.h"
const double PulsarAnimationWidget::deg2rad = PI/180.0;
PulsarAnimationWidget::PulsarAnimationWidget(QWidget *parent) :
QGLWidget(QGLFormat(QGL::AlphaChannel | QGL::SampleBuffers), parent)
{
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);
}
// initialize quadric pointers
m_quadricVirgoh = NULL;
m_quadricVirgov = NULL;
m_quadricEarth = NULL;
m_quadricLLOh = NULL;
m_quadricLLOv = NULL;
m_quadricSourcePlane = NULL;
m_quadricSourcePlaneNormal = NULL;
m_quadricSourcePlaneNormalCap = NULL;
m_quadricSourcePlaneNormalCenter = NULL;
m_quadricLHOv = NULL;
m_quadricLHOh = NULL;
// initialize texture pointers
m_beamTexture = 0;
// initial parameters (have to match GUI!)
m_LHOAngle = 0;
m_LLOAngle = 0;
m_VirgoAngle = 0;
m_sourceIota = 0.0;
m_sourceInclination = 0;
m_earthRadius = 3.0;
// initial view features
m_cameraInteraction = false;
// initial view settings
m_mouseAngleH = -55.0;
m_mouseAngleV = 20.0;
m_cameraZoom = 100.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_quadricVirgoh) gluDeleteQuadric(m_quadricVirgoh);
if(m_quadricVirgov) gluDeleteQuadric(m_quadricVirgov);
if(m_quadricEarth) gluDeleteQuadric(m_quadricEarth);
if(m_quadricLLOh) gluDeleteQuadric(m_quadricLLOh);
if(m_quadricLLOv) gluDeleteQuadric(m_quadricLLOv);
if(m_quadricSourcePlane) gluDeleteQuadric(m_quadricSourcePlane);
if(m_quadricSourcePlaneNormal) gluDeleteQuadric(m_quadricSourcePlaneNormal);
if(m_quadricSourcePlaneNormalCap) gluDeleteQuadric(m_quadricSourcePlaneNormalCap);
if(m_quadricSourcePlaneNormalCenter) gluDeleteQuadric(m_quadricSourcePlaneNormalCenter);
if(m_quadricLHOv) gluDeleteQuadric(m_quadricLHOv);
if(m_quadricLHOh) gluDeleteQuadric(m_quadricLHOh);
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, 3.0, 1.0};
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);
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);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
m_quadricVirgoh = gluNewQuadric();
m_quadricVirgov = gluNewQuadric();
m_quadricEarth = gluNewQuadric();
m_quadricLLOh = gluNewQuadric();
m_quadricLLOv = gluNewQuadric();
m_quadricSourcePlane = gluNewQuadric();
m_quadricSourcePlaneNormal = gluNewQuadric();
m_quadricSourcePlaneNormalCap = gluNewQuadric();
m_quadricSourcePlaneNormalCenter = gluNewQuadric();
m_quadricLHOv = gluNewQuadric();
m_quadricLHOh = gluNewQuadric();
gluQuadricNormals(m_quadricVirgoh, GLU_SMOOTH);
gluQuadricNormals(m_quadricVirgov, GLU_SMOOTH);
gluQuadricNormals(m_quadricEarth, GLU_SMOOTH);
gluQuadricNormals(m_quadricLLOh, GLU_SMOOTH);
gluQuadricNormals(m_quadricLLOv, GLU_SMOOTH);
gluQuadricNormals(m_quadricSourcePlane, GLU_SMOOTH);
gluQuadricNormals(m_quadricSourcePlaneNormal, GLU_SMOOTH);
gluQuadricNormals(m_quadricSourcePlaneNormalCap, GLU_SMOOTH);
gluQuadricNormals(m_quadricSourcePlaneNormalCenter, GLU_SMOOTH);
gluQuadricNormals(m_quadricLHOv, GLU_SMOOTH);
gluQuadricNormals(m_quadricLHOh, GLU_SMOOTH);
// query max texture size (estimate)
GLint maxTextureSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
// prepare and check beam texture
QImage beamTexture(":/textures/resources/World-Map-7.jpg");
// bind textures
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);
// TODO: should be located elsewhere
static GLfloat no_mat[] = {0.0, 0.0, 0.0, 1.0};
static GLfloat mat_diffuse[] = {0.0, 0.0, 0.5, 1.0};
static GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
static GLfloat low_shininess[] = {2.5};
static GLfloat translucent[] = {1.0, 1.0, 1.0, 0.33};
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);
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 (independent parallel projection)
glColor3f(1.0, 1.0, 1.0f);
glTranslatef(0.0, 0.0, -501.0);
// restore original state
glMatrixMode(GL_PROJECTION);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
glPopMatrix();
// draw earth
glPushMatrix();
{
glRotatef(90, 0.0, 1.0, 0.0);
glPushMatrix();
{
glRotatef(90, 1.0, 0.0, 0.0);
glRotatef(180, 1.0, 1.0, 0.0);
// create texture coordinates and enable texturing
gluQuadricTexture(m_quadricEarth, GL_TRUE);
glBindTexture(GL_TEXTURE_2D, m_beamTexture);
glEnable(GL_TEXTURE_2D);
gluSphere(m_quadricEarth, m_earthRadius, 32, 32);
}
glPopMatrix();
}
glPopMatrix();
// draw LHO
glPushMatrix();
{
glColor3f(1.0f, 1.0f, 1.0f);
glRotatef(-48.455144, 0.0, 0.0, 1.0);
glRotatef(-110.407656, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, m_earthRadius);
glRotatef(m_LHOAngle+180, 0.0, 0.0, 1.0);
glPushMatrix();
{
glRotatef(90, 0.0, 1.0, 0.0);
gluCylinder(m_quadricLHOh, 0.020, 0.020, 0.40, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glRotatef(90, 0.0, 1.0, 0.0);
glRotatef(90, 1.0, 0.0, 0.0);
glColor3f(0.0f, 0.0f, 1.0f);
gluCylinder(m_quadricLHOv, 0.020, 0.020, 0.40, 32, 1);
}
glPopMatrix();
}
glPopMatrix();
// draw LLO
glPushMatrix();
{
glColor3f(1.0f, 1.0f, 1.0f);
glRotatef(-30.562894, 0.0, 0.0, 1.0);
glRotatef(-90.774242, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, m_earthRadius);
glRotatef(m_LLOAngle-90, 0.0, 0.0, 1.0);
glPushMatrix();
{
glRotatef(90, 0.0, 1.0, 0.0);
gluCylinder(m_quadricLLOh, 0.020, 0.020, 0.40, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glRotatef(90, 0.0, 1.0, 0.0);
glRotatef(90, 1.0, 0.0, 0.0);
glColor3f(1.0f, 0.0f, 0.0f);
gluCylinder(m_quadricLLOv, 0.020, 0.020, 0.40, 32, 1);
}
glPopMatrix();
}
glPopMatrix();
// draw Virgo
glPushMatrix();
{
glColor3f(1.0f, 1.0f, 1.0f);
glRotatef(-45.6305, 1.0, 0.0, 0.0);
glRotatef(7.5021, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, m_earthRadius);
glRotatef(m_VirgoAngle+165, 0.0, 0.0, 1.0);
glPushMatrix();
{
glRotatef(90, 0.0, 1.0, 0.0);
gluCylinder(m_quadricVirgoh, 0.020, 0.020, 0.40, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glRotatef(90, 0.0, 1.0, 0.0);
glRotatef(90, 1.0, 0.0, 0.0);
glColor3f(0.0f, 1.0f, 0.0f);
gluCylinder(m_quadricVirgov, 0.020, 0.020, 0.40, 32, 1);
}
glPopMatrix();
}
glPopMatrix();
// draw source
glPushMatrix();
{
glRotatef(-31.384, 0.0, 0.0, 1.0);
glRotatef(45.093, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, m_earthRadius + 2.0);
glRotatef(m_sourceInclination, 0.0, 1.0, 0.0);
glRotatef(180, 0.0, 1.0, 0.0);
glPushMatrix();
{
glRotatef(m_sourceIota, 1.0, 0.0, 0.0);
// draw source plane normal
glColor3f(1.0f, 0.0f, 0.0f);
glPushMatrix();
{
glTranslatef(0.0, 0.0, -1.0);
gluCylinder(m_quadricSourcePlaneNormal, 0.020, 0.020, 1.5, 32, 1);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, -1.0);
gluDisk(m_quadricSourcePlaneNormalCap, 0, 0.020, 32, 8);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, 0.0, 0.5f);
glBegin(GL_TRIANGLE_FAN);
{
// Pinnacle of cone is shared vertex for fan, moved up z-axis
// to produce a cone instead of a circle
glVertex3f(0.0f, 0.0f, 0.5f);
// 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 = 0.1f * sin(angle);
y = 0.1f * cos(angle);
// Specify the next vertex for the triangle fan
glVertex2f(x, y);
}
}
glEnd();
}
glPopMatrix();
glColor3f(1.0f, 1.0f, 1.0f);
glPushMatrix();
{
gluSphere(m_quadricSourcePlaneNormalCenter, 0.040, 32, 32);
}
glPopMatrix();
// draw disc
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, translucent);
glEnable(GL_LIGHTING);
glPushMatrix();
{
gluDisk(m_quadricSourcePlane,
0,
1.0,
64, 1);
}
glPopMatrix();
glDisable(GL_LIGHTING);
}
glPopMatrix();
}
glPopMatrix();
// 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("Copyright %1 2017").arg(QChar(0x00A9)), font);
renderText(10, 10, -100, tr("Max Planck Institute for Gravitational Physics"), font);
// restore original state
glMatrixMode(GL_PROJECTION);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
glPopMatrix();
}
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();
}
void PulsarAnimationWidget::setSourceInclination(const double degrees)
{
m_sourceInclination = degrees;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::setLHOAngle(const double degrees)
{
m_LHOAngle = degrees;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::setLLOAngle(const double degrees)
{
m_LLOAngle = degrees;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::setVirgoAngle(const int degrees)
{
m_VirgoAngle = degrees;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::setSourceIota(const int degrees)
{
m_sourceIota = degrees;
updatePulseProfile();
updateGL();
}
void PulsarAnimationWidget::getCameraPosition(double& cameraAngleH, double& cameraAngleV, double& cameraZoom)
{
cameraAngleH = m_mouseAngleH;
cameraAngleV = m_mouseAngleV;
cameraZoom = m_cameraZoom;
}
void PulsarAnimationWidget::resetCameraPosition(const double angleH, const double angleV, const double zoom)
{
m_mouseAngleH = angleH;
m_mouseAngleV = angleV;
m_cameraZoom = zoom;
updateCameraPosition(m_mouseAngleH, m_mouseAngleV, m_cameraZoom);
}
void PulsarAnimationWidget::updatePulseProfile()
{
struct InputStruct in;
struct OutputStruct out;
in.iota = m_sourceIota;
in.psi = m_sourceInclination;
in.orientation[0] = m_LLOAngle;
in.orientation[1] = m_LHOAngle;
in.orientation[2] = m_VirgoAngle;
// get actual detector data
get_antenna(&out, &in);
// populate plot data object
for(int x = 0; x < 360*PERIODS; ++x) {
double t=x/(PERIODS*360.0);
double freq = 1.0/pow(1.1-t,0.375);
m_plotData.m_dataLLO[x] = out.amp[0] * freq * freq * sin(freq*x* deg2rad);// + out.dt[0];
m_plotData.m_dataLHO[x] = out.amp[1] * freq * freq * sin((freq*x+out.phase[1]-out.phase[0]) * deg2rad);// + out.dt[1];
m_plotData.m_dataVirgo[x] = out.amp[2] * freq * freq * sin((freq*x+out.phase[2]-out.phase[0]) * deg2rad);// + out.dt[2];
}
m_plotData.m_ampLLO = out.amp[0];
m_plotData.m_ampLHO = out.amp[1];
m_plotData.m_ampVirgo = out.amp[2];
m_plotData.m_phiLLO = out.phase[0];
m_plotData.m_phiLHO = out.phase[1];
m_plotData.m_phiVirgo = out.phase[2];
m_plotData.m_dtLLO = out.dt[0];
m_plotData.m_dtLHO = out.dt[1];
m_plotData.m_dtVirgo = out.dt[2];
// propagate new plot data
emit pulseProfileUpdated(m_plotData);
}