/************************************************************************************* * Copyright (C) 2007 by Aleix Pol * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "graph3d.h" #if defined(Q_WS_MAC) #include #else #include #endif #include #include #include #include #include #include #include "analitza.h" #include "value.h" using std::fabs; using std::log10; using Analitza::Cn; using Analitza::Expression; enum ActionsEnum { KEYRIGHT=1<<0, KEYLEFT=1<<1, KEYUP=1<<2, KEYDOWN=1<<3, KEYAVPAG=1<<4, KEYREPAG=1<<5, KEYS=1<<6, KEYW=1<<7, KEYQ=1<<8, KEYE=1<<9, LCLICK=1<<10, RCLICK=1<<11, MCLICK=1<<12 }; Graph3D::Graph3D(QWidget *parent) : QGLWidget(parent), default_step(0.15f), default_size(8.0f), zoom(1.0f), points(0), alpha(60.), method(Solid), trans(false), keyspressed(0), m_n(4) { this->setFocusPolicy(Qt::ClickFocus); rotation[0] = 90.0; rotation[1] = 0.0; rotation[2] = 0.0; } Graph3D::~Graph3D() { if(points) { const int j= 2*static_cast(default_size/default_step); for(int i=0; ibutton() == Qt::LeftButton) { press = e->pos(); keyspressed |= LCLICK; } } void Graph3D::mouseReleaseEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton) keyspressed &= ~LCLICK; } void Graph3D::mouseMoveEvent(QMouseEvent *e) { if(keyspressed & LCLICK){ QPoint rel = e->pos() - press; rotation[0] += rel.y(); rotation[2] -= rel.x(); press = e->pos(); this->repaint(); } } void Graph3D::drawAxes() { glColor3f(0.8, 0.8, 0.4); this->renderText(11.0, 0.0, 0.0, "X"); this->renderText(0.0, 11.0, 0.0, "Y"); this->renderText(0.0, 0.0,-11.0, "Z"); glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-10.0f, 0.0f, 0.0f); glVertex3f( 10.0f, 0.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f( 0.0f, 10.0f, 0.0f); glVertex3f( 0.0f,-10.0f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f( 0.0f, 0.0f, 10.0f); glVertex3f( 0.0f, 0.0f,-10.0f); glEnd(); } void Graph3D::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if(keyspressed & KEYDOWN) rotation[0]+=3.f; if(keyspressed & KEYUP) rotation[0]-=3.f; if(keyspressed & KEYAVPAG) rotation[1]+=3.f; if(keyspressed & KEYREPAG) rotation[1]-=3.f; if(keyspressed & KEYLEFT) rotation[2]+=3.f; if(keyspressed & KEYRIGHT) rotation[2]-=3.f; if(keyspressed & KEYW) alpha/=2.f; if(keyspressed & KEYS && alpha<=90.f) alpha*=2.f; if(keyspressed & KEYQ) { zoom/=2.0f; create(); } if(keyspressed & KEYE) { zoom*=2.0f; create(); } if(rotation[0]>=360.f) rotation[0]-=360.f; if(rotation[1]>=360.f) rotation[1]-=360.f; if(rotation[2]>=360.f) rotation[2]-=360.f; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(alpha,(GLfloat)width()/(GLfloat)height(),0.1f,100.0f); float z=25.f; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0,0,-z); glRotatef(rotation[0], 1.0, 0.0, 0.0); glRotatef(rotation[1], 0.0, 1.0, 0.0); glRotatef(rotation[2], 0.0, 0.0, 1.0); const double mida=default_size*zoom, step=default_step*zoom; uint bound=(2*mida/step)-1; drawAxes(); if(!points || !func3d.isCorrect()) return; if(method==Dots) { glBegin(GL_POINTS); for(uint i=0; i(mida/step)*2; int part = k/m_n; QList threads; Analitza::Analitza a; a.setExpression(func3d); QTime t; t.restart(); for(int i=0; isetTo(2*static_cast(default_size/default_step)); threads << r; r->start(); } bool ret=true; QList::iterator it = threads.begin(); for(; it!=threads.end(); ++it) { if(!(*it)->wait(1000)) { ret=false; (*it)->terminate(); } } // qDebug() << "Elapsed time" << t.elapsed(); qDeleteAll(threads); return ret; } void Calculate3D::run() { if(!a.isCorrect()) return; Q_ASSERT(points); const int k= static_cast(size/step)*2; Cn *x=a.insertValueVariable("x", 0.); Cn *y=a.insertValueVariable("y", 0.); for(int i=from; isetValue(i*step-size); for(int j=0; jsetValue(j*step-size); points[i][j] = -a.calculate().toReal().value(); } } } void Graph3D::wheelEvent(QWheelEvent * e) { if(e->delta()>0) alpha/=2.f; else if(alpha<=90.f) alpha*=2.f; repaint(); } void Graph3D::keyPressEvent( QKeyEvent *e ) { switch(e->key()) { case Qt::Key_Up: keyspressed |= KEYUP; break; case Qt::Key_Down: keyspressed |= KEYDOWN; break; case Qt::Key_Left: keyspressed |= KEYLEFT; break; case Qt::Key_Right: keyspressed |= KEYRIGHT; break; case Qt::Key_PageUp: keyspressed |= KEYREPAG; break; case Qt::Key_PageDown: keyspressed |= KEYAVPAG; break; case Qt::Key_W: keyspressed |= KEYW; break; case Qt::Key_S: keyspressed |= KEYS; break; case Qt::Key_Q: //Be careful keyspressed |= KEYQ; break; case Qt::Key_E: //Be careful keyspressed |= KEYE; break; } // sendStatus(QString("-%1-").arg(keyspressed, 16)); this->repaint(); } void Graph3D::keyReleaseEvent( QKeyEvent *e ) { switch(e->key()) { case Qt::Key_Up: keyspressed &= ~KEYUP; break; case Qt::Key_Down: keyspressed &= ~KEYDOWN; break; case Qt::Key_Left: keyspressed &= ~KEYLEFT; break; case Qt::Key_Right: keyspressed &= ~KEYRIGHT; break; case Qt::Key_PageUp: keyspressed &= ~KEYREPAG; break; case Qt::Key_PageDown: keyspressed &= ~KEYAVPAG; break; case Qt::Key_W: keyspressed &= ~KEYW; break; case Qt::Key_S: keyspressed &= ~KEYS; break; case Qt::Key_Q: //Be careful keyspressed &= ~KEYQ; break; case Qt::Key_E: //Be careful keyspressed &= ~KEYE; break; } // sendStatus(QString(".%1.").arg(keyspressed, 16)); this->repaint(); } void Graph3D::timeOut() { rotation[0] += 20.0; rotation[1] += 20.0; rotation[2] += 20.0; this->repaint(); } void Graph3D::setFunc(const Expression& exp) { if(exp.isCorrect()) { func3d = exp; load(); } else sendStatus(i18n("Error: %1", exp.error().join(", "))); } int Graph3D::load() { Analitza::Analitza f3d; f3d.setExpression(func3d); f3d.insertValueVariable("x", 0.); f3d.insertValueVariable("y", 0.); Expression e=f3d.calculate(); if(f3d.isCorrect() && e.isReal()) { QTime t; t.restart(); sendStatus(i18n("Generating... Please wait")); mem(); create(); // xgettext: no-c-format sendStatus(i18nc("3D graph done in x miliseconds", "Done: %1ms", t.elapsed())); this->repaint(); return 0; } else { if(f3d.isCorrect()) sendStatus(i18n("Error: We need values to draw a graph")); else sendStatus(i18n("Error: %1", f3d.errors().join(", "))); this->repaint(); return -1; } } void Graph3D::mem() { const int j= 2*static_cast(default_size/default_step); if(points!=0){ for(int i=0; irepaint(); } void Graph3D::setStep(double newRes) { default_step = newRes; this->repaint(); } void Graph3D::setZoom(float a) { alpha = a; this->repaint(); } void Graph3D::setMethod(enum Type m) { method = m; this->repaint(); } QPixmap Graph3D::toPixmap() { return this->renderPixmap(); } void Graph3D::resetView() { default_step=0.15f; default_size=8.0f; if(zoom!=1.0f) { zoom=1.0f; create(); } alpha=60.; rotation[0] = 90.0; rotation[1] = 0.0; rotation[2] = 0.0; updateGL(); } #include "graph3d.moc"