diff options
Diffstat (limited to 'kscreensaver/kdesavers/rotation.cpp')
-rw-r--r-- | kscreensaver/kdesavers/rotation.cpp | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/kscreensaver/kdesavers/rotation.cpp b/kscreensaver/kdesavers/rotation.cpp new file mode 100644 index 00000000..38098cb0 --- /dev/null +++ b/kscreensaver/kdesavers/rotation.cpp @@ -0,0 +1,825 @@ +//============================================================================ +// +// KRotation screen saver for KDE +// +// The screen saver displays a physically realistic simulation of a force free +// rotating asymmetric body. The equations of motion for such a rotation, the +// Euler equations, are integrated numerically by the Runge-Kutta method. +// +// Developed by Georg Drenkhahn, georg-d@users.sourceforge.net +// +// $Id$ +// +/* + * Copyright (C) 2004 Georg Drenkhahn + * + * KRotation is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + * + * KRotation 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 02110-1301 USA + */ +//============================================================================ + +// std. C++ headers +#include <cstdlib> +// STL +#include <deque> +// Qt headers +#include <qcheckbox.h> +#include <qlineedit.h> +#include <qvalidator.h> +#include <qtooltip.h> +// KDE headers +#include <klocale.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kmessagebox.h> + +#include "sspreviewarea.h" + +// rotation.moc includes rotation.h +#include "rotation.moc" + +/** Version number of this screen saver */ +#define KROTATION_VERSION "1.1" + +// libkscreensaver interface +extern "C" +{ + /** application name for the libkscreensaver interface */ + KDE_EXPORT const char *kss_applicationName = "krotation.kss"; + /** application description for the libkscreensaver interface */ + KDE_EXPORT const char *kss_description = + I18N_NOOP("Simulation of a force free rotating asymmetric body"); + /** application version for the libkscreensaver interface */ + KDE_EXPORT const char *kss_version = KROTATION_VERSION; + + /** function to create screen saver object */ + KDE_EXPORT KScreenSaver* kss_create(WId id) + { + return new KRotationSaver(id); + } + + /** function to create setup dialog for screen saver */ + KDE_EXPORT QDialog* kss_setup() + { + return new KRotationSetup(); + } +} + +//----------------------------------------------------------------------------- +// EulerOdeSolver implementation +//----------------------------------------------------------------------------- + +EulerOdeSolver::EulerOdeSolver( + const double &t_, + const double &dt_, + const double &A_, + const double &B_, + const double &C_, + std::valarray<double> &y_, + const double &eps_) + : RkOdeSolver<double>(t_,y_,dt_,eps_), + A(A_), B(B_), C(C_) +{ +} + +std::valarray<double> EulerOdeSolver::f( + const double &x, + const std::valarray<double> &y) const +{ + // unused + (void)x; + + // vec omega in body coor. sys.: omega_body = (p, q, r) + const vec3<double> omega_body(y[std::slice(0,3,1)]); + // body unit vectors in fixed frame coordinates + const vec3<double> e1(y[std::slice(3,3,1)]); + const vec3<double> e2(y[std::slice(6,3,1)]); + const vec3<double> e3(y[std::slice(9,3,1)]); + + // don't use "const vec3<double>&" here because slice_array must be + // value-copied to vec3<double>. + + // vec omega in global fixed coor. sys. + vec3<double> omega( + omega_body[0] * e1 + + omega_body[1] * e2 + + omega_body[2] * e3); + + // return vector y' + std::valarray<double> ypr(y.size()); + + // omega_body' + ypr[0] = -(C-B)/A * omega_body[1] * omega_body[2]; // p' + ypr[1] = -(A-C)/B * omega_body[2] * omega_body[0]; // q' + ypr[2] = -(B-A)/C * omega_body[0] * omega_body[1]; // r' + + // e1', e2', e3' + ypr[std::slice(3,3,1)] = vec3<double>::crossprod(omega, e1); + ypr[std::slice(6,3,1)] = vec3<double>::crossprod(omega, e2); + ypr[std::slice(9,3,1)] = vec3<double>::crossprod(omega, e3); + + return ypr; +} +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Rotation: screen saver widget +//----------------------------------------------------------------------------- + +RotationGLWidget::RotationGLWidget( + QWidget* parent, const char* name, + const vec3<double>& _omega, + const std::deque<vec3<double> >& e1_, + const std::deque<vec3<double> >& e2_, + const std::deque<vec3<double> >& e3_, + const vec3<double>& J) + : QGLWidget(parent, name), + eyeR(25), eyeTheta(1), eyePhi(M_PI*0.25), + boxSize(1,1,1), + fixedAxses(0), + bodyAxses(0), + lightR(10), lightTheta(M_PI/4), lightPhi(0), + bodyAxsesLength(6), + fixedAxsesLength(8), + omega(_omega), + e1(e1_), + e2(e2_), + e3(e3_) +{ + // set up initial rotation matrix as unit matrix, only non-constant elements + // are set later on + for (int i=0; i<16; i++) + rotmat[i] = ((i%5)==0) ? 1:0; + + // Set the box sizes from the momenta of inertia. J is the 3 vector with + // momenta of inertia with respect to the 3 figure axes. + + // the default values must be valid so that w,h,d are real! + GLfloat + x2 = 6.0*(-J[0] + J[1] + J[2]), + y2 = 6.0*( J[0] - J[1] + J[2]), + z2 = 6.0*( J[0] + J[1] - J[2]); + + if (x2>=0 && y2>=0 && z2>=0) + { + boxSize = vec3<double>(sqrt(x2), sqrt(y2), sqrt(z2)); + } + else + { + kdDebug() << "parameter error" << endl; + boxSize = vec3<double>(1, 1, 1); + } +} + +/* --------- protected methods ----------- */ + +void RotationGLWidget::initializeGL(void) +{ + qglClearColor(QColor(black)); // set color to clear the background + + glClearDepth(1); // depth buffer setup + glEnable(GL_DEPTH_TEST); // depth testing + glDepthFunc(GL_LEQUAL); // type of depth test + + glShadeModel(GL_SMOOTH); // smooth color shading in poygons + + // nice perspective calculation + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + // set up the light + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + // set positon of light0 + GLfloat lightPos[4]= + {lightR * sin(lightTheta) * sin(lightPhi), + lightR * sin(lightTheta) * cos(lightPhi), + lightR * cos(lightTheta), 1.}; + glLightfv(GL_LIGHT0, GL_POSITION, lightPos); + + // enable setting the material colour by glColor() + glEnable(GL_COLOR_MATERIAL); + + // set up display lists + + if (fixedAxses == 0) + fixedAxses = glGenLists(1); // list to be returned + glNewList(fixedAxses, GL_COMPILE); + + // fixed coordinate system axes + + glPushMatrix(); + glLoadIdentity(); + + // z-axis, blue + qglColor(QColor(blue)); + myGlArrow(fixedAxsesLength, 0.5f, 0.03f, 0.1f); + + // x-axis, red + qglColor(QColor(red)); + glRotatef(90, 0, 1, 0); + + myGlArrow(fixedAxsesLength, 0.5f, 0.03f, 0.1f); + + // y-axis, green + qglColor(QColor(green)); + glLoadIdentity(); + glRotatef(-90, 1, 0, 0); + myGlArrow(fixedAxsesLength, 0.5f, 0.03f, 0.1f); + + glPopMatrix(); + glEndList(); + // end of axes object list + + + // box and box-axses + if (bodyAxses == 0) + bodyAxses = glGenLists(1); // list to be returned + glNewList(bodyAxses, GL_COMPILE); + + // z-axis, blue + qglColor(QColor(blue)); + myGlArrow(bodyAxsesLength, 0.5f, 0.03f, 0.1f); + + // x-axis, red + qglColor(QColor(red)); + glPushMatrix(); + glRotatef(90, 0, 1, 0); + myGlArrow(bodyAxsesLength, 0.5f, 0.03f, 0.1f); + glPopMatrix(); + + // y-axis, green + qglColor(QColor(green)); + glPushMatrix(); + glRotatef(-90, 1, 0, 0); + myGlArrow(bodyAxsesLength, 0.5f, 0.03f, 0.1f); + glPopMatrix(); + + glEndList(); +} + +void RotationGLWidget::draw_traces(void) +{ + if (e1.size()==0 && e2.size()==0 && e3.size()==0) + return; + + glPushMatrix(); + glScalef(bodyAxsesLength, bodyAxsesLength, bodyAxsesLength); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + for (int j=0; j<3; ++j) + { + const std::deque<vec3<double> >& e = + j==0 ? e1 : j==1 ? e2 : e3; + + // trace must contain at least 2 elements + if (e.size() > 1) + { + // emission colour + GLfloat em[4] = {0,0,0,1}; + em[j] = 1; // set either red, green, blue emission colour + + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, em); + glColor4fv(em); + + // set iterator of the tail part + std::deque<vec3<double> >::const_iterator eit = e.begin(); + std::deque<vec3<double> >::const_iterator tail = + e.begin() + + static_cast<std::deque<vec3<double> >::difference_type> + (0.9*e.size()); + + glBegin(GL_LINES); + for (; eit < e.end()-1; ++eit) + { + glVertex3f((*eit)[0], (*eit)[1], (*eit)[2]); + // decrease transparency for tail section + if (eit > tail) + em[3] = + static_cast<GLfloat> + (1.0 - double(eit-tail)/(0.1*e.size())); + glColor4fv(em); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, em); + glVertex3f((*(eit+1))[0], (*(eit+1))[1], (*(eit+1))[2]); + } + glEnd(); + } + } + + glDisable(GL_BLEND); + + glPopMatrix(); +} + +void RotationGLWidget::paintGL(void) +{ + // clear color and depth buffer + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); // select modelview matrix + + glLoadIdentity(); + GLfloat const em[] = {0,0,0,1}; + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, em); + + // omega vector + vec3<double> rotvec = + vec3<double>::crossprod(vec3<double>(0,0,1), omega).normalize(); + GLfloat rotdeg = + 180./M_PI * vec3<double>::angle(vec3<double>(0,0,1), omega); + glPushMatrix(); + glRotatef(rotdeg, rotvec[0], rotvec[1], rotvec[2]); + qglColor(QColor(white)); + myGlArrow(7, .5f, .1f, 0.2f); + glPopMatrix(); + + // fixed axes + glCallList(fixedAxses); + + glPushMatrix(); + + // set up variable part of rotation matrix for body + // set gl body rotation matrix from e1,e2,e3 + const vec3<double>& e1b = e1.front(); + const vec3<double>& e2b = e2.front(); + const vec3<double>& e3b = e3.front(); + + rotmat[0] = e1b[0]; + rotmat[1] = e1b[1]; + rotmat[2] = e1b[2]; + rotmat[4] = e2b[0]; + rotmat[5] = e2b[1]; + rotmat[6] = e2b[2]; + rotmat[8] = e3b[0]; + rotmat[9] = e3b[1]; + rotmat[10] = e3b[2]; + + glMultMatrixf(rotmat); + + glCallList(bodyAxses); + + glScalef(boxSize[0]/2, boxSize[1]/2, boxSize[2]/2); + + // paint box + glBegin(GL_QUADS); + // front (z) + qglColor(QColor(blue)); + glNormal3f( 0,0,1); + glVertex3f( 1, 1, 1); + glVertex3f(-1, 1, 1); + glVertex3f(-1, -1, 1); + glVertex3f( 1, -1, 1); + // back (-z) + glNormal3f( 0,0,-1); + glVertex3f( 1, 1, -1); + glVertex3f(-1, 1, -1); + glVertex3f(-1, -1, -1); + glVertex3f( 1, -1, -1); + // top (y) + qglColor(QColor(green)); + glNormal3f( 0,1,0); + glVertex3f( 1, 1, 1); + glVertex3f( 1, 1, -1); + glVertex3f(-1, 1, -1); + glVertex3f(-1, 1, 1); + // bottom (-y) + glNormal3f( 0,-1,0); + glVertex3f( 1, -1, 1); + + glVertex3f( 1, -1, -1); + glVertex3f(-1, -1, -1); + glVertex3f(-1, -1, 1); + // left (-x) + qglColor(QColor(red)); + glNormal3f( -1,0,0); + glVertex3f(-1, 1, 1); + glVertex3f(-1, 1, -1); + glVertex3f(-1, -1, -1); + glVertex3f(-1, -1, 1); + // right (x) + glNormal3f( 1,0,0); + glVertex3f( 1, 1, 1); + glVertex3f( 1, 1, -1); + glVertex3f( 1, -1, -1); + glVertex3f( 1, -1, 1); + glEnd(); + + // traces + glPopMatrix(); + draw_traces (); + + glFlush(); +} + +void RotationGLWidget::resizeGL(int w, int h) +{ + // Prevent a divide by zero + if (h == 0) h = 1; + + // set the new view port + glViewport(0, 0, (GLint)w, (GLint)h); + + // set up projection matrix + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + // Perspective view + gluPerspective(40.0f, (GLdouble)w/(GLdouble)h, 1.0, 100.0f); + + // Viewing transformation, position for better view + // Theta is polar angle 0<Theta<Pi + gluLookAt( + eyeR * sin(eyeTheta) * sin(eyePhi), + eyeR * sin(eyeTheta) * cos(eyePhi), + eyeR * cos(eyeTheta), + 0,0,0, + 0,0,1); +} + +/* --------- privat methods ----------- */ + +void RotationGLWidget::myGlArrow( + GLfloat total_length, GLfloat head_length, + GLfloat base_width, GLfloat head_width) +{ + GLUquadricObj* quadAx = gluNewQuadric(); + glPushMatrix(); + gluCylinder(quadAx, base_width, base_width, + total_length-head_length, 10, 1); + glTranslatef(0, 0, total_length-head_length); + gluCylinder(quadAx, head_width, 0, head_length, 10, 1); + glPopMatrix(); + gluDeleteQuadric(quadAx); +} + + +//----------------------------------------------------------------------------- +// KRotationSaver: screen saver class +//----------------------------------------------------------------------------- + +KRotationSaver::KRotationSaver(WId id) + : KScreenSaver(id), + J(4,2,3), // fixed box sizes! + initEulerPhi(0), + initEulerPsi(0), + solver(0), + glArea(0), + timer(0), + m_traceLengthSeconds(traceLengthSecondsDefault), + m_Lz(LzDefault), + m_initEulerTheta(initEulerThetaDefault) +{ + readSettings(); // read global settings + initData(); // init e1,e2,e3,omega,solver + + setEraseColor(black); + erase(); // erase area + glArea = new RotationGLWidget( + this, 0, omega, e1, e2, e3, J); // create gl widget + embed(glArea); // embed gl widget and resize it + glArea->show(); // show gl widget + + timer = new QTimer(this); + timer->start(deltaT, TRUE); + connect(timer, SIGNAL(timeout()), this, SLOT(doTimeStep())); +} + +KRotationSaver::~KRotationSaver() +{ + // time, rotation are automatically deleted with parent KRotationSaver + delete solver; +} + +void KRotationSaver::initData() +{ + // reset coordiante system + vec3<double> e1t(1,0,0), e2t(0,1,0), e3t(0,0,1); + // rotation by phi around z = zhat axis + e1t.rotate(initEulerPhi*e3t); + e2t.rotate(initEulerPhi*e3t); + // rotation by theta around new x axis + e2t.rotate(m_initEulerTheta*e1t); + e3t.rotate(m_initEulerTheta*e1t); + // rotation by psi around new z axis + e1t.rotate(initEulerPsi*e3t); + e2t.rotate(initEulerPsi*e3t); + // set first vector in deque + e1.clear(); e1.push_front(e1t); + e2.clear(); e2.push_front(e2t); + e3.clear(); e3.push_front(e3t); + + // calc L in body frame: 1. determine z-axis of fixed frame in body + // coordinates, undo the transformations for unit z vector of the body frame + + // calc omega_body from ... + vec3<double> e1_body(1,0,0), e3_body(0,0,1); + // rotation by -psi along z axis + e1_body.rotate(-initEulerPsi*e3_body); + // rotation by -theta along new x axis + e3_body.rotate(-m_initEulerTheta*e1_body); + // omega_body = L_body * J_body^(-1) + vec3<double> omega_body = e3_body * m_Lz; + omega_body /= J; + + // assemble initial y for solver + std::valarray<double> y(12); + y[std::slice(0,3,1)] = omega_body; + // 3 basis vectors of body system in fixed coordinates + y[std::slice(3,3,1)] = e1t; + y[std::slice(6,3,1)] = e2t; + y[std::slice(9,3,1)] = e3t; + + // initial rotation vector + omega + = omega_body[0]*e1t + + omega_body[1]*e2t + + omega_body[2]*e3t; + + if (solver!=0) delete solver; + // init solver + solver = new EulerOdeSolver( + 0.0, // t + 0.01, // first dt step size estimation + J[0], J[1], J[2], // A,B,C + y, // omega_body,e1,e2,e3 + 1e-5); // eps +} + +void KRotationSaver::readSettings() +{ + // read configuration settings from config file + KConfig *config = KGlobal::config(); + config->setGroup("Settings"); + + // internal saver parameters are set to stored values or left at their + // default values if stored values are out of range + setTraceFlag(0, config->readBoolEntry("x trace", traceFlagDefault[0])); + setTraceFlag(1, config->readBoolEntry("y trace", traceFlagDefault[1])); + setTraceFlag(2, config->readBoolEntry("z trace", traceFlagDefault[2])); + setRandomTraces(config->readBoolEntry("random traces", randomTracesDefault)); + setTraceLengthSeconds( + config->readDoubleNumEntry("length", traceLengthSecondsDefault)); + setLz( + config->readDoubleNumEntry("Lz", LzDefault)); + setInitEulerTheta( + config->readDoubleNumEntry("theta", initEulerThetaDefault)); +} + +void KRotationSaver::setTraceLengthSeconds(const double& t) +{ + if (t >= traceLengthSecondsLimitLower + && t <= traceLengthSecondsLimitUpper) + { + m_traceLengthSeconds = t; + } +} + +const double KRotationSaver::traceLengthSecondsLimitLower = 0.0; +const double KRotationSaver::traceLengthSecondsLimitUpper = 99.0; +const double KRotationSaver::traceLengthSecondsDefault = 3.0; + +const bool KRotationSaver::traceFlagDefault[3] = {false, false, true}; + +void KRotationSaver::setLz(const double& Lz) +{ + if (Lz >= LzLimitLower && Lz <= LzLimitUpper) + { + m_Lz = Lz; + } +} + +const double KRotationSaver::LzLimitLower = 0.0; +const double KRotationSaver::LzLimitUpper = 500.0; +const double KRotationSaver::LzDefault = 10.0; + +void KRotationSaver::setInitEulerTheta(const double& theta) +{ + if (theta >= initEulerThetaLimitLower + && theta <= initEulerThetaLimitUpper) + { + m_initEulerTheta = theta; + } +} + +const double KRotationSaver::initEulerThetaLimitLower = 0.0; +const double KRotationSaver::initEulerThetaLimitUpper = 180.0; +const double KRotationSaver::initEulerThetaDefault = 0.03; + +// public slots + +void KRotationSaver::doTimeStep() +{ + // integrate a step ahead + solver->integrate(0.001*deltaT); + + // read new y + std::valarray<double> y = solver->Y(); + + std::deque<vec3<double> >::size_type + max_vec_length = + static_cast<std::deque<vec3<double> >::size_type> + ( m_traceLengthSeconds/(0.001*deltaT) ); + + for (int j=0; j<3; ++j) + { + std::deque<vec3<double> >& e = + j==0 ? e1 : + j==1 ? e2 : e3; + + // read out new body coordinate system + if (m_traceFlag[j] == true + && max_vec_length > 0) + { + e.push_front(y[std::slice(3*j+3, 3, 1)]); + while (e.size() > max_vec_length) + { + e.pop_back(); + } + } + else + { + // only set the 1. element + e.front() = y[std::slice(3*j+3, 3, 1)]; + // and delete all other emements + if (e.size() > 1) + e.resize(1); + } + } + + // current rotation vector omega + omega = y[0]*e1.front() + y[1]*e2.front() + y[2]*e3.front(); + + // set new random traces every 10 seconds + if (m_randomTraces==true) + { + static unsigned int counter=0; + ++counter; + if (counter > unsigned(10.0/(0.001*deltaT))) + { + counter=0; + for (int i=0; i<3; ++i) + m_traceFlag[i] = rand()%2==1 ? true : false; + } + } + + glArea->updateGL(); + timer->start(deltaT, TRUE); // restart timer +} + +// public slot of KRotationSaver, forward resize event to public slot of glArea +// to allow the resizing of the gl area withing the setup dialog +void KRotationSaver::resizeGlArea(QResizeEvent* e) +{ + glArea->resize(e->size()); +} + +//----------------------------------------------------------------------------- +// KRotationSetup: dialog to setup screen saver parameters +//----------------------------------------------------------------------------- + +KRotationSetup::KRotationSetup(QWidget* parent, const char* name) + : KRotationSetupUi(parent, name), + // create ssaver and give it the WinID of the preview area + saver(new KRotationSaver(preview->winId())) +{ + // the dialog should block, no other control center input should be possible + // until the dialog is closed + setModal(TRUE); + + lengthEdit->setValidator( + new QDoubleValidator( + KRotationSaver::traceLengthSecondsLimitLower, + KRotationSaver::traceLengthSecondsLimitUpper, + 3, lengthEdit)); + LzEdit->setValidator( + new QDoubleValidator( + KRotationSaver::LzLimitLower, + KRotationSaver::LzLimitUpper, + 3, LzEdit)); + thetaEdit->setValidator( + new QDoubleValidator( + KRotationSaver::initEulerThetaLimitLower, + KRotationSaver::initEulerThetaLimitUpper, + 3, thetaEdit)); + + // set tool tips of editable fields + QToolTip::add( + lengthEdit, + i18n("Length of traces in seconds of visibility.\nValid values from %1 to %2.") + .arg(KRotationSaver::traceLengthSecondsLimitLower, 0, 'f', 2) + .arg(KRotationSaver::traceLengthSecondsLimitUpper, 0, 'f', 2)); + QToolTip::add( + LzEdit, + i18n("Angular momentum in z direction in arbitrary units.\nValid values from %1 to %2.") + .arg(KRotationSaver::LzLimitLower, 0, 'f', 2) + .arg(KRotationSaver::LzLimitUpper, 0, 'f', 2)); + QToolTip::add( + thetaEdit, + i18n("Gravitational constant in arbitrary units.\nValid values from %1 to %2.") + .arg(KRotationSaver::initEulerThetaLimitLower, 0, 'f', 2) + .arg(KRotationSaver::initEulerThetaLimitUpper, 0, 'f', 2)); + + // init preview area + preview->setBackgroundColor(black); + preview->show(); // otherwise saver does not get correct size + + // read settings from saver and update GUI elements with these values, saver + // has read settings in its constructor + + // set editable fields with stored values as defaults + xTrace->setChecked(saver->traceFlag(0)); + yTrace->setChecked(saver->traceFlag(1)); + zTrace->setChecked(saver->traceFlag(2)); + randTraces->setChecked(saver->randomTraces()); + QString text; + text.setNum(saver->traceLengthSeconds()); + lengthEdit->validateAndSet(text,0,0,0); + text.setNum(saver->Lz()); + LzEdit->validateAndSet(text,0,0,0); + text.setNum(saver->initEulerTheta()); + thetaEdit->validateAndSet(text,0,0,0); + + // if the preview area is resized it emmits the resized() event which is + // caught by the saver. The embedded GlArea is resized to fit into the + // preview area. + connect(preview, SIGNAL(resized(QResizeEvent*)), + saver, SLOT(resizeGlArea(QResizeEvent*))); +} + +KRotationSetup::~KRotationSetup() +{ + delete saver; +} + +// Ok pressed - save settings and exit +void KRotationSetup::okButtonClickedSlot(void) +{ + KConfig* config = KGlobal::config(); + config->setGroup("Settings"); + config->writeEntry("x trace", saver->traceFlag(0)); + config->writeEntry("y trace", saver->traceFlag(1)); + config->writeEntry("z trace", saver->traceFlag(2)); + config->writeEntry("random traces", saver->randomTraces()); + config->writeEntry("length", saver->traceLengthSeconds()); + config->writeEntry("Lz", saver->Lz()); + config->writeEntry("theta", saver->initEulerTheta()); + config->sync(); + accept(); +} + +void KRotationSetup::aboutButtonClickedSlot(void) +{ + KMessageBox::about(this, i18n("\ +<h3>KRotation Screen Saver for KDE</h3>\ +<p>Simulation of a force free rotating asymmetric body</p>\ +<p>Copyright (c) Georg Drenkhahn 2004</p>\ +<p><tt>georg-d@users.sourceforge.net</tt></p>")); +} + +void KRotationSetup::xTraceToggled(bool state) +{ + saver->setTraceFlag(0, state); +} +void KRotationSetup::yTraceToggled(bool state) +{ + saver->setTraceFlag(1, state); +} +void KRotationSetup::zTraceToggled(bool state) +{ + saver->setTraceFlag(2, state); +} +void KRotationSetup::randomTracesToggled(bool state) +{ + saver->setRandomTraces(state); + if (state==false) + { + // restore settings from gui if random traces are turned off + saver->setTraceFlag(0, xTrace->isChecked()); + saver->setTraceFlag(1, yTrace->isChecked()); + saver->setTraceFlag(2, zTrace->isChecked()); + } +} +void KRotationSetup::lengthEnteredSlot(const QString& s) +{ + saver->setTraceLengthSeconds(s.toDouble()); +} +void KRotationSetup::LzEnteredSlot(const QString& s) +{ + saver->setLz(s.toDouble()); + if (saver!=0) saver->initData(); +} +void KRotationSetup::thetaEnteredSlot(const QString& s) +{ + saver->setInitEulerTheta(s.toDouble()); + if (saver!=0) saver->initData(); +} |