Logo Search packages:      
Sourcecode: kboincspy version File versions  Download package

kbslhcparticleview.cpp

/***************************************************************************
 *   Copyright (C) 2005 by Roberto Virga                                   *
 *   rvirga@users.sf.net                                                   *
 *                                                                         *
 *   This program 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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <math.h>

#include <qfontmetrics.h>
#include <qpainter.h>
#include <qpopupmenu.h>

#include <klocale.h>
#include <kstandarddirs.h>

#include <kbslhcinterpolator.h>
#include <kbslhctaskmonitor.h>

#include <lhcdata.h>

#include <kbslhctrackingdetailswindow.h>

#include "kbslhcparticleview.h"

void torus(double outer, double inner, unsigned sectors, unsigned sides)
{
  glPushMatrix();
  
  const unsigned vertices = 3 * sectors * sides;
  
  double *vertex = new double[vertices];
  double *normal = new double[vertices];
  
  const double dPhi   = 2 * M_PI / sectors;
  const double dTheta = 2 * M_PI / sides;
  
  double phi = 0.0;
  for(unsigned sector = 0; sector < sectors; ++sector)
  {
    const double sinPhi = sin(phi);
    const double cosPhi = cos(phi);
    
    double theta = 0.0;
    for(unsigned side = 0; side < sides; ++side)
    {
      const double sinTheta = sin(theta);
      const double cosTheta = cos(theta);
      
      const unsigned offset = 3 * (sector * sides + side);
      
      vertex[offset + 0] = cosPhi * (outer + cosTheta * inner);   // x coordinate
      vertex[offset + 1] = sinPhi * (outer + cosTheta * inner);   // y coordinate
      vertex[offset + 2] = sinTheta * inner;                      // z coordinate
      
      normal[offset + 0] = cosPhi * cosTheta;                     // x coordinate
      normal[offset + 1] = sinPhi * cosTheta;                     // y coordinate
      normal[offset + 2] = sinTheta;                              // z coordinate
      
      theta += dTheta;
    }
    
    phi += dPhi;
  }
  
  glBegin(GL_QUADS);
  
    for(unsigned sector = 0; sector < sectors; sector++)
      for(unsigned side = 0; side < sides; ++side)
      {
        unsigned offset = 3 * (sector * sides + side);
        
        glNormal3dv(normal + offset);
        glVertex3dv(vertex + offset);
        
        offset = (offset + 3) % vertices;
        
        glNormal3dv(normal + offset);
        glVertex3dv(vertex + offset);
        
        offset = (offset + 3 * sides) % vertices;
        
        glNormal3dv(normal + offset);
        glVertex3dv(vertex + offset);
        
        offset = (offset + vertices - 3) % vertices;
        
        glNormal3dv(normal + offset);
        glVertex3dv(vertex + offset); 
      }
    
  glEnd();
  
  delete vertex;
  delete normal;
  
  glPopMatrix();
}

void partialCylinder(double radius, double height, unsigned sectors, double start, double end)
{
  glPushMatrix();
  
  const unsigned count = 3 * (sectors + 1);
  
  double *vertex = new double[count];
  double *normal = new double[count];
  
  const double dTheta = (end - start) * (2 * M_PI) / (360 * sectors);
  
  double theta = start * (2 * M_PI) / 360;
  for(unsigned sector = 0; sector <= sectors; ++sector)
  {
    const double sinTheta = sin(theta);
    const double cosTheta = cos(theta);
    
    const unsigned offset = 3 * sector;
    
    vertex[offset + 0] = sinTheta * radius;   // x coordinate
    vertex[offset + 1] = cosTheta * radius;   // y coordinate
    
    normal[offset + 0] = sinTheta;            // x coordinate
    normal[offset + 1] = cosTheta;            // y coordinate
    normal[offset + 2] = 0.0;                 // z coordinate
    
    theta += dTheta;
  }
  
  glBegin(GL_QUADS);
  
    for(unsigned sector = 0; sector < sectors; sector++)
    {
      unsigned offset = 3 * sector;
      
      vertex[offset + 2] = 0.0;
      glNormal3dv(normal + offset);
      glVertex3dv(vertex + offset);
      
      vertex[offset + 2] = height;
      glNormal3dv(normal + offset);
      glVertex3dv(vertex + offset);
      
      offset = offset + 3;
      
      vertex[offset + 2] = height;  
      glNormal3dv(normal + offset);
      glVertex3dv(vertex + offset);
        
      vertex[offset + 2] = 0.0;
      glNormal3dv(normal + offset);
      glVertex3dv(vertex + offset);
    }
    
  glEnd();
  
  delete vertex;
  delete normal;
  
  glPopMatrix();
}

const QImage KBSLHCParticleView::s_texture[] =
{
  QGLWidget::convertToGLFormat(QImage(locate("data", "kboincspy/pics/lhc/font.png"), "PNG")),
  QGLWidget::convertToGLFormat(QImage(locate("data", "kboincspy/pics/lhc/particle.png"), "PNG"))
};

KBSLHCParticleView::KBSLHCParticleView(KBSLHCTrackingDetailsWindow *parent, const char *name)
                  : QGLWidget(parent, name),
                    m_turn(0), m_maxTurn(0), m_particles(0), m_mode(0), m_maxSets(0),
                    m_type(CrossSection), m_headerVisible(true),
                    m_texture(NULL), m_quadric(NULL), m_font(0), m_base(0)
{
  m_energy[0] = m_energy[1] = 1.0;
  
  setFocusPolicy(StrongFocus);
}

KBSLHCParticleView::~KBSLHCParticleView()
{
  makeCurrent();
  if(0 != m_font) glDeleteLists(m_font, 256);
  if(0 != m_base) glDeleteLists(m_base, Shapes);
  if(NULL != m_quadric) gluDeleteQuadric(m_quadric);
  if(NULL != m_texture) {
    glDeleteTextures(Textures, m_texture);
    delete m_texture;
  }
}

KBSLHCParticleView::Type KBSLHCParticleView::type() const
{
  return m_type;
}

void KBSLHCParticleView::setType(Type type)
{
  if(type == m_type) return;
  
  initializeGL(m_type, true);
  initializeGL(type);
  
  m_type = type;
  
  resizeGL(width(), height());
  updateGL();
}

bool KBSLHCParticleView::isHeaderVisible() const
{
  return m_headerVisible;
}

void KBSLHCParticleView::setHeaderVisible(bool visible)
{
  if(visible == m_headerVisible) return;
  
  m_headerVisible = visible;
  updateGL();
}

unsigned KBSLHCParticleView::turn() const
{
  return m_turn;
}

void KBSLHCParticleView::addTurn()
{
  if(m_turn >= m_maxTurn) return;
  
  m_turn++;
  updateGL();
}

void KBSLHCParticleView::setTurn(unsigned turn)
{
  m_turn = (turn < m_maxTurn) ? turn : m_maxTurn;
  
  updateGL();
}

unsigned KBSLHCParticleView::maxTurn() const
{
  return m_maxTurn;
}

void KBSLHCParticleView::setMaxTurn(unsigned turn)
{
  m_maxTurn = turn;
  if(m_turn > m_maxTurn) m_turn = m_maxTurn;
  
  updateGL();
}

unsigned KBSLHCParticleView::particles() const
{
  return m_particles;
}

void KBSLHCParticleView::addParticle()
{
  setParticles(m_particles + 1);
  
  updateGL();
}

void KBSLHCParticleView::removeParticle()
{
  if(0 == m_particles) return;
  setParticles(m_particles - 1);
  
  updateGL();
}

void KBSLHCParticleView::setParticles(unsigned particles)
{
  const unsigned maxParticles = this->maxParticles();
  m_particles = (particles < maxParticles) ? particles : maxParticles;
  
  KBSLHCTrackingDetailsWindow *window = static_cast<KBSLHCTrackingDetailsWindow*>(parent());
  KAction *action;
  
  action = window->action("particle_add");
  if(NULL != action) action->setEnabled(m_particles < maxParticles);
  
  action = window->action("particle_remove");
  if(NULL != action) action->setEnabled(m_particles > 0);
  
  updateGL();
}

unsigned KBSLHCParticleView::maxParticles() const
{
  return (1 == m_mode) ? m_maxSets : 2 * m_maxSets;
}

unsigned KBSLHCParticleView::trackingMode() const
{
  return m_mode;
}

unsigned KBSLHCParticleView::maxSets() const
{
  return m_maxSets;
}

void KBSLHCParticleView::setMaxSets(unsigned mode, unsigned sets)
{
  m_mode = mode;
  m_maxSets = sets;
  setParticles(maxParticles());
  
  updateGL();
}

double KBSLHCParticleView::initialEnergy(unsigned position) const
{
  return m_energy[position % 2];
}

void KBSLHCParticleView::setInitialEnergy(double energy1, double energy2)
{
  m_energy[0] = energy1;
  m_energy[1] = energy2;
  
  updateGL();
}

void KBSLHCParticleView::initializeGL()
{
  initTextures();
  initFont();
  initShapes();  
  
  initializeGL(m_type);
}

void KBSLHCParticleView::initializeGL(int type, bool reverse)
{
  switch(type) {
    default:
      if(reverse) {
        glShadeModel(GL_FLAT);
        glDisable(GL_TEXTURE_2D);
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_BLEND);
      } else {
        qglClearColor(black);
        glShadeModel(GL_SMOOTH);
        glEnable(GL_TEXTURE_2D);
        glDisable(GL_DEPTH_TEST);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
        glEnable(GL_BLEND);
      }
  }
}

void KBSLHCParticleView::resizeGL(int width, int height)
{
  switch(m_type) {
    default:
      glViewport(0, 0, GLint(width), GLint(height));
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(0, width, 0, height, -1, 1);
      glMatrixMode(GL_MODELVIEW);
      break;
  }
}

void KBSLHCParticleView::paintGL()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();
  
  if(m_headerVisible) drawHeader();
  
  if(0 == m_particles) return;
  
  KBSLHCTaskMonitor *taskMonitor =
    static_cast<KBSLHCTrackingDetailsWindow*>(parent())->taskMonitor();
  if(NULL == taskMonitor) return;
  
  const unsigned width = this->width(),
                 height = this->height();
  
  unsigned particle = 0;
  for(unsigned set = 0; set < m_maxSets && particle <= m_particles; ++set)
    for(unsigned position = 0; position < 2 && particle <= m_particles; ++position)
    {
      if(1 == m_mode && 1 == position) continue;
      
      KBSLHCInterpolator *interpolator = taskMonitor->interpolator(set, position);
      if(NULL == interpolator) continue;
      
      drawParticle2D(width / 2  + lround(width * interpolator->interpolateXCoord(m_turn) / 16),
                     height / 2 + lround(height * interpolator->interpolateYCoord(m_turn) / 16),
                     interpolator->interpolateEnergy(m_turn) / m_energy[position]);
      
      particle++;
    }
}

void KBSLHCParticleView::contextMenuEvent(QContextMenuEvent *e)
{
  KBSLHCTrackingDetailsWindow *window = static_cast<KBSLHCTrackingDetailsWindow*>(parent());
  
  QPopupMenu *context = static_cast<QPopupMenu*>(window->guiFactory()->container("context", window));
  context->popup(mapToGlobal(e->pos()));
}

void KBSLHCParticleView::drawHeader()
{
  const unsigned x = 4;
  unsigned y = height() - (12 + 4);
  
  KLocale *locale = KGlobal::locale();
  
  if(m_maxTurn > 0) {
    drawString(x, y, i18n("Turn: %1 of %2").arg(locale->formatNumber(m_turn, 0))
                                           .arg(locale->formatNumber(m_maxTurn, 0)));
    y -= (12 + 2);
  }
  
  const unsigned maxParticles = this->maxParticles();
  
  if(maxParticles > 0) {
    drawString(x, y, i18n("Particles: %1 of %2").arg(locale->formatNumber(m_particles, 0))
                                                .arg(locale->formatNumber(maxParticles, 0)));
    y -= (12 + 2);
  }
}

void KBSLHCParticleView::drawString(int x, int y, const QString &string)
{
  glBindTexture(GL_TEXTURE_2D, m_texture[FontTexture]);
  glPushMatrix();
  glLoadIdentity();
  glTranslatef(x, y, 0);
  glListBase(m_font);
  glColor4f(1.0, 1.0, 1.0, 1.0);
  glCallLists(string.length(), GL_BYTE, string.latin1());
  glPopMatrix();  
}

void KBSLHCParticleView::drawParticle2D(int x, int y, double alpha)
{
  if(alpha < 0.0) alpha = 0.0;
  else if(alpha > 1.0) alpha = 1.0;
  
  glBindTexture(GL_TEXTURE_2D, m_texture[ParticleTexture]);
  glPushMatrix();
  glLoadIdentity();
  glTranslatef(x, y, 0.0);
  glColor4f(1.0, 1.0, 1.0, alpha);
  glCallList(m_base + Particle2D);
  glPopMatrix();  
}

void KBSLHCParticleView::initTextures()
{
  m_texture = new GLuint[Textures];
  glGenTextures(Textures, m_texture);
  for(unsigned i = 0; i < Textures; ++i) {
    glBindTexture(GL_TEXTURE_2D, m_texture[i]);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, s_texture[i].width(), s_texture[i].height(), 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, s_texture[i].bits());
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  }
}

void KBSLHCParticleView::initFont()
{
  m_font = glGenLists(256);
  glBindTexture(GL_TEXTURE_2D, m_texture[FontTexture]);
  for(unsigned i = 0; i < 256; ++i)
  {
    const float size = 1 / 32.0;
    const float x = (2 * (i % 16) + 0.5) * size;
    const float y = 1.0 - (2 * (i / 16) + 0.5) * size;
    
    glNewList(m_font + i, GL_COMPILE);
      glBegin(GL_QUADS);
        glTexCoord2f(x, y - size);
        glVertex2i(0, 0);
        glTexCoord2f(x + size, y - size);
        glVertex2i(12, 0);
        glTexCoord2f(x + size, y);
        glVertex2i(12, 12);
        glTexCoord2f(x, y);
        glVertex2i(0, 12);
      glEnd();
      glTranslatef(7.5, 0, 0);
    glEndList();
  }
}
  
void KBSLHCParticleView::initShapes()
{
  m_base = glGenLists(Shapes);
  
  glNewList(m_base + Particle2D, GL_COMPILE);
    glBindTexture(GL_TEXTURE_2D, m_texture[ParticleTexture]);
    glBegin(GL_QUADS);
      glTexCoord2i(0, 0);
      glVertex2i(-64, -64);
      glTexCoord2i(1, 0);
      glVertex2i(64, -64);
      glTexCoord2i(1, 1);
      glVertex2i(64, 64);
      glTexCoord2i(0, 1);
      glVertex2i(-64, 64);
    glEnd();
  glEndList();
  
  m_quadric = gluNewQuadric();
  gluQuadricNormals(m_quadric, GLU_SMOOTH);
  
  glNewList(m_base + Ring, GL_COMPILE);
    glPushMatrix();
    glRotatef(-90, 0.0, 1.0, 0.0);
    glTranslatef(0.0, 0.0, -0.1);
    gluCylinder(m_quadric, 0.8, 0.8, 0.3, 32, 32);
    gluCylinder(m_quadric, 0.5, 0.5, 0.3, 32, 32);
    gluDisk(m_quadric, 0.5, 0.8, 32, 32);
    glTranslatef(0.0, 0.0, 0.3);
    gluDisk(m_quadric, 0.5, 0.8, 32, 32);
    glPopMatrix();
  glEndList();
  
  glNewList(m_base + Magnet, GL_COMPILE);
    glPushMatrix();
    glRotatef(-90, 0.0, 1.0, 0.0);
    glTranslatef(0.0, 0.0, -0.7);
    partialCylinder(0.9, 1.4, 16, 0, 180);
    partialCylinder(0.7, 1.4, 16, 0, 180);
    glBegin(GL_QUADS);
      glVertex3f(0.0, 0.7, 0.0);
      glVertex3f(0.0, 0.7, 1.4);
      glVertex3f(0.0, 0.9, 1.4);
      glVertex3f(0.0, 0.9, 0.0);
      glVertex3f(0.0, -0.7, 0.0);
      glVertex3f(0.0, -0.7, 1.4);
      glVertex3f(0.0, -0.9, 1.4);
      glVertex3f(0.0, -0.9, 0.0);
    glEnd();
    gluPartialDisk(m_quadric, 0.7, 0.9, 32, 32, 0, 180);
    glTranslatef(0.0, 0.0, 1.4);
    gluPartialDisk(m_quadric, 0.7, 0.9, 32, 32, 0, 180);
    glPopMatrix();
  glEndList();
  
  glNewList(m_base + Tube, GL_COMPILE);
    glPushMatrix();    
    glRotatef(90, 1.0, 0.0, 0.0);
    torus(12.0, 0.4, 2048, 32);
    glPopMatrix();
  glEndList();  
}

#include "kbslhcparticleview.moc"

Generated by  Doxygen 1.6.0   Back to index