Deprecated--
[kdeartwork.git] / kscreensaver / kdesavers / rotation.cpp
blobf8e4366ba3158cfbc02f20ec56befe0688247dd0
1 //============================================================================
2 //
3 // KRotation screen saver for KDE
4 //
5 // The screen saver displays a physically realistic simulation of a force free
6 // rotating asymmetric body. The equations of motion for such a rotation, the
7 // Euler equations, are integrated numerically by the Runge-Kutta method.
8 //
9 // Developed by Georg Drenkhahn, georg-d@users.sourceforge.net
11 // $Id$
14 * Copyright (C) 2004 Georg Drenkhahn
16 * KRotation is free software; you can redistribute it and/or modify it under
17 * the terms of the GNU General Public License version 2 as published by the
18 * Free Software Foundation.
20 * KRotation is distributed in the hope that it will be useful, but WITHOUT ANY
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
22 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License along with
25 * this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 //============================================================================
30 #define QT_NO_COMPAT
32 // std. C++ headers
33 #include <cstdlib>
34 // STL
35 #include <deque>
36 // Qt headers
37 #include <qcheckbox.h>
38 #include <qlineedit.h>
39 #include <qvalidator.h>
40 #include <qtooltip.h>
41 //Added by qt3to4:
42 #include <QResizeEvent>
43 // KDE headers
44 #include <klocale.h>
45 #include <kconfig.h>
46 #include <kdebug.h>
47 #include <kmessagebox.h>
49 #include "sspreviewarea.h"
51 // rotation.moc includes rotation.h
52 #include "rotation.moc"
54 /** Version number of this screen saver */
55 #define KROTATION_VERSION "1.1"
57 // libkscreensaver interface
58 class KRotationSaverInterface : public KScreenSaverInterface
60 public:
61 virtual KAboutData* aboutData() {
62 return new KAboutData( "krotation.kss", I18N_NOOP("Simulation of a force free rotating asymmetric body"), KROTATION_VERSION, I18N_NOOP("Simulation of a force free rotating asymmetric body") );
65 /** function to create screen saver object */
66 virtual KScreenSaver* create(WId id)
68 return new KRotationSaver(id);
71 /** function to create setup dialog for screen saver */
72 virtual QDialog* setup()
74 return new KRotationSetup();
78 int main( int argc, char *argv[] )
80 KRotationSaverInterface kss;
81 return kScreenSaverMain( argc, argv, kss );
84 //-----------------------------------------------------------------------------
85 // EulerOdeSolver implementation
86 //-----------------------------------------------------------------------------
88 EulerOdeSolver::EulerOdeSolver(
89 const double &t_,
90 const double &dt_,
91 const double &A_,
92 const double &B_,
93 const double &C_,
94 std::valarray<double> &y_,
95 const double &eps_)
96 : RkOdeSolver<double>(t_,y_,dt_,eps_),
97 A(A_), B(B_), C(C_)
101 std::valarray<double> EulerOdeSolver::f(
102 const double &x,
103 const std::valarray<double> &y) const
105 // unused
106 (void)x;
108 // vec omega in body coor. sys.: omega_body = (p, q, r)
109 const vec3<double> omega_body(y[std::slice(0,3,1)]);
110 // body unit vectors in fixed frame coordinates
111 const vec3<double> e1(y[std::slice(3,3,1)]);
112 const vec3<double> e2(y[std::slice(6,3,1)]);
113 const vec3<double> e3(y[std::slice(9,3,1)]);
115 // don't use "const vec3<double>&" here because slice_array must be
116 // value-copied to vec3<double>.
118 // vec omega in global fixed coor. sys.
119 vec3<double> omega(
120 omega_body[0] * e1
121 + omega_body[1] * e2
122 + omega_body[2] * e3);
124 // return vector y'
125 std::valarray<double> ypr(y.size());
127 // omega_body'
128 ypr[0] = -(C-B)/A * omega_body[1] * omega_body[2]; // p'
129 ypr[1] = -(A-C)/B * omega_body[2] * omega_body[0]; // q'
130 ypr[2] = -(B-A)/C * omega_body[0] * omega_body[1]; // r'
132 // e1', e2', e3'
133 ypr[std::slice(3,3,1)] = vec3<double>::crossprod(omega, e1);
134 ypr[std::slice(6,3,1)] = vec3<double>::crossprod(omega, e2);
135 ypr[std::slice(9,3,1)] = vec3<double>::crossprod(omega, e3);
137 return ypr;
139 //-----------------------------------------------------------------------------
142 //-----------------------------------------------------------------------------
143 // Rotation: screen saver widget
144 //-----------------------------------------------------------------------------
146 RotationGLWidget::RotationGLWidget(
147 QWidget* parent, const char* name,
148 const vec3<double>& _omega,
149 const std::deque<vec3<double> >& e1_,
150 const std::deque<vec3<double> >& e2_,
151 const std::deque<vec3<double> >& e3_,
152 const vec3<double>& J)
153 : QGLWidget(parent, name),
154 eyeR(25), eyeTheta(1), eyePhi(M_PI*0.25),
155 boxSize(1,1,1),
156 fixedAxses(0),
157 bodyAxses(0),
158 lightR(10), lightTheta(M_PI/4), lightPhi(0),
159 bodyAxsesLength(6),
160 fixedAxsesLength(8),
161 omega(_omega),
162 e1(e1_),
163 e2(e2_),
164 e3(e3_)
166 // set up initial rotation matrix as unit matrix, only non-constant elements
167 // are set later on
168 for (int i=0; i<16; i++)
169 rotmat[i] = ((i%5)==0) ? 1:0;
171 // Set the box sizes from the momenta of inertia. J is the 3 vector with
172 // momenta of inertia with respect to the 3 figure axes.
174 // the default values must be valid so that w,h,d are real!
175 GLfloat
176 x2 = 6.0*(-J[0] + J[1] + J[2]),
177 y2 = 6.0*( J[0] - J[1] + J[2]),
178 z2 = 6.0*( J[0] + J[1] - J[2]);
180 if (x2>=0 && y2>=0 && z2>=0)
182 boxSize = vec3<double>(sqrt(x2), sqrt(y2), sqrt(z2));
184 else
186 kDebug() << "parameter error" << endl;
187 boxSize = vec3<double>(1, 1, 1);
191 /* --------- protected methods ----------- */
193 void RotationGLWidget::initializeGL(void)
195 qglClearColor(QColor(Qt::black)); // set color to clear the background
197 glClearDepth(1); // depth buffer setup
198 glEnable(GL_DEPTH_TEST); // depth testing
199 glDepthFunc(GL_LEQUAL); // type of depth test
201 glShadeModel(GL_SMOOTH); // smooth color shading in poygons
203 // nice perspective calculation
204 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
206 // set up the light
207 glEnable(GL_LIGHTING);
208 glEnable(GL_LIGHT0);
209 // set positon of light0
210 GLfloat lightPos[4]=
211 {lightR * sin(lightTheta) * sin(lightPhi),
212 lightR * sin(lightTheta) * cos(lightPhi),
213 lightR * cos(lightTheta), 1.};
214 glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
216 // enable setting the material colour by glColor()
217 glEnable(GL_COLOR_MATERIAL);
219 // set up display lists
221 if (fixedAxses == 0)
222 fixedAxses = glGenLists(1); // list to be returned
223 glNewList(fixedAxses, GL_COMPILE);
225 // fixed coordinate system axes
227 glPushMatrix();
228 glLoadIdentity();
230 // z-axis, blue
231 qglColor(QColor(Qt::blue));
232 myGlArrow(fixedAxsesLength, 0.5f, 0.03f, 0.1f);
234 // x-axis, red
235 qglColor(QColor(Qt::red));
236 glRotatef(90, 0, 1, 0);
238 myGlArrow(fixedAxsesLength, 0.5f, 0.03f, 0.1f);
240 // y-axis, green
241 qglColor(QColor(Qt::green));
242 glLoadIdentity();
243 glRotatef(-90, 1, 0, 0);
244 myGlArrow(fixedAxsesLength, 0.5f, 0.03f, 0.1f);
246 glPopMatrix();
247 glEndList();
248 // end of axes object list
251 // box and box-axses
252 if (bodyAxses == 0)
253 bodyAxses = glGenLists(1); // list to be returned
254 glNewList(bodyAxses, GL_COMPILE);
256 // z-axis, blue
257 qglColor(QColor(Qt::blue));
258 myGlArrow(bodyAxsesLength, 0.5f, 0.03f, 0.1f);
260 // x-axis, red
261 qglColor(QColor(Qt::red));
262 glPushMatrix();
263 glRotatef(90, 0, 1, 0);
264 myGlArrow(bodyAxsesLength, 0.5f, 0.03f, 0.1f);
265 glPopMatrix();
267 // y-axis, green
268 qglColor(QColor(Qt::green));
269 glPushMatrix();
270 glRotatef(-90, 1, 0, 0);
271 myGlArrow(bodyAxsesLength, 0.5f, 0.03f, 0.1f);
272 glPopMatrix();
274 glEndList();
277 void RotationGLWidget::draw_traces(void)
279 if (e1.size()==0 && e2.size()==0 && e3.size()==0)
280 return;
282 glPushMatrix();
283 glScalef(bodyAxsesLength, bodyAxsesLength, bodyAxsesLength);
285 glEnable(GL_BLEND);
286 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
288 for (int j=0; j<3; ++j)
290 const std::deque<vec3<double> >& e =
291 j==0 ? e1 : j==1 ? e2 : e3;
293 // trace must contain at least 2 elements
294 if (e.size() > 1)
296 // emission colour
297 GLfloat em[4] = {0,0,0,1};
298 em[j] = 1; // set either red, green, blue emission colour
300 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, em);
301 glColor4fv(em);
303 // set iterator of the tail part
304 std::deque<vec3<double> >::const_iterator eit = e.begin();
305 std::deque<vec3<double> >::const_iterator tail =
306 e.begin() +
307 static_cast<std::deque<vec3<double> >::difference_type>
308 (0.9*e.size());
310 glBegin(GL_LINES);
311 for (; eit < e.end()-1; ++eit)
313 glVertex3f((*eit)[0], (*eit)[1], (*eit)[2]);
314 // decrease transparency for tail section
315 if (eit > tail)
316 em[3] =
317 static_cast<GLfloat>
318 (1.0 - double(eit-tail)/(0.1*e.size()));
319 glColor4fv(em);
320 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, em);
321 glVertex3f((*(eit+1))[0], (*(eit+1))[1], (*(eit+1))[2]);
323 glEnd();
327 glDisable(GL_BLEND);
329 glPopMatrix();
332 void RotationGLWidget::paintGL(void)
334 // clear color and depth buffer
335 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
337 glMatrixMode(GL_MODELVIEW); // select modelview matrix
339 glLoadIdentity();
340 GLfloat const em[] = {0,0,0,1};
341 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, em);
343 // omega vector
344 vec3<double> rotvec =
345 vec3<double>::crossprod(vec3<double>(0,0,1), omega).normalize();
346 GLfloat rotdeg =
347 180./M_PI * vec3<double>::angle(vec3<double>(0,0,1), omega);
348 glPushMatrix();
349 glRotatef(rotdeg, rotvec[0], rotvec[1], rotvec[2]);
350 qglColor(QColor(Qt::white));
351 myGlArrow(7, .5f, .1f, 0.2f);
352 glPopMatrix();
354 // fixed axes
355 glCallList(fixedAxses);
357 glPushMatrix();
359 // set up variable part of rotation matrix for body
360 // set gl body rotation matrix from e1,e2,e3
361 const vec3<double>& e1b = e1.front();
362 const vec3<double>& e2b = e2.front();
363 const vec3<double>& e3b = e3.front();
365 rotmat[0] = e1b[0];
366 rotmat[1] = e1b[1];
367 rotmat[2] = e1b[2];
368 rotmat[4] = e2b[0];
369 rotmat[5] = e2b[1];
370 rotmat[6] = e2b[2];
371 rotmat[8] = e3b[0];
372 rotmat[9] = e3b[1];
373 rotmat[10] = e3b[2];
375 glMultMatrixf(rotmat);
377 glCallList(bodyAxses);
379 glScalef(boxSize[0]/2, boxSize[1]/2, boxSize[2]/2);
381 // paint box
382 glBegin(GL_QUADS);
383 // front (z)
384 qglColor(QColor(Qt::blue));
385 glNormal3f( 0,0,1);
386 glVertex3f( 1, 1, 1);
387 glVertex3f(-1, 1, 1);
388 glVertex3f(-1, -1, 1);
389 glVertex3f( 1, -1, 1);
390 // back (-z)
391 glNormal3f( 0,0,-1);
392 glVertex3f( 1, 1, -1);
393 glVertex3f(-1, 1, -1);
394 glVertex3f(-1, -1, -1);
395 glVertex3f( 1, -1, -1);
396 // top (y)
397 qglColor(QColor(Qt::green));
398 glNormal3f( 0,1,0);
399 glVertex3f( 1, 1, 1);
400 glVertex3f( 1, 1, -1);
401 glVertex3f(-1, 1, -1);
402 glVertex3f(-1, 1, 1);
403 // bottom (-y)
404 glNormal3f( 0,-1,0);
405 glVertex3f( 1, -1, 1);
407 glVertex3f( 1, -1, -1);
408 glVertex3f(-1, -1, -1);
409 glVertex3f(-1, -1, 1);
410 // left (-x)
411 qglColor(QColor(Qt::red));
412 glNormal3f( -1,0,0);
413 glVertex3f(-1, 1, 1);
414 glVertex3f(-1, 1, -1);
415 glVertex3f(-1, -1, -1);
416 glVertex3f(-1, -1, 1);
417 // right (x)
418 glNormal3f( 1,0,0);
419 glVertex3f( 1, 1, 1);
420 glVertex3f( 1, 1, -1);
421 glVertex3f( 1, -1, -1);
422 glVertex3f( 1, -1, 1);
423 glEnd();
425 // traces
426 glPopMatrix();
427 draw_traces ();
429 glFlush();
432 void RotationGLWidget::resizeGL(int w, int h)
434 // Prevent a divide by zero
435 if (h == 0) h = 1;
437 // set the new view port
438 glViewport(0, 0, (GLint)w, (GLint)h);
440 // set up projection matrix
441 glMatrixMode(GL_PROJECTION);
442 glLoadIdentity();
443 // Perspective view
444 gluPerspective(40.0f, (GLdouble)w/(GLdouble)h, 1.0, 100.0f);
446 // Viewing transformation, position for better view
447 // Theta is polar angle 0<Theta<Pi
448 gluLookAt(
449 eyeR * sin(eyeTheta) * sin(eyePhi),
450 eyeR * sin(eyeTheta) * cos(eyePhi),
451 eyeR * cos(eyeTheta),
452 0,0,0,
453 0,0,1);
456 /* --------- privat methods ----------- */
458 void RotationGLWidget::myGlArrow(
459 GLfloat total_length, GLfloat head_length,
460 GLfloat base_width, GLfloat head_width)
462 GLUquadricObj* quadAx = gluNewQuadric();
463 glPushMatrix();
464 gluCylinder(quadAx, base_width, base_width,
465 total_length-head_length, 10, 1);
466 glTranslatef(0, 0, total_length-head_length);
467 gluCylinder(quadAx, head_width, 0, head_length, 10, 1);
468 glPopMatrix();
469 gluDeleteQuadric(quadAx);
473 //-----------------------------------------------------------------------------
474 // KRotationSaver: screen saver class
475 //-----------------------------------------------------------------------------
477 KRotationSaver::KRotationSaver(WId id)
478 : KScreenSaver(id),
479 J(4,2,3), // fixed box sizes!
480 initEulerPhi(0),
481 initEulerPsi(0),
482 solver(0),
483 glArea(0),
484 timer(0),
485 m_traceLengthSeconds(traceLengthSecondsDefault),
486 m_Lz(LzDefault),
487 m_initEulerTheta(initEulerThetaDefault)
489 readSettings(); // read global settings
490 initData(); // init e1,e2,e3,omega,solver
492 setEraseColor(Qt::black);
493 erase(); // erase area
494 glArea = new RotationGLWidget(
495 this, 0, omega, e1, e2, e3, J); // create gl widget
496 embed(glArea); // embed gl widget and resize it
497 glArea->show(); // show gl widget
499 timer = new QTimer(this);
500 timer->start(deltaT, TRUE);
501 connect(timer, SIGNAL(timeout()), this, SLOT(doTimeStep()));
504 KRotationSaver::~KRotationSaver()
506 // time, rotation are automatically deleted with parent KRotationSaver
507 delete solver;
510 void KRotationSaver::initData()
512 // reset coordiante system
513 vec3<double> e1t(1,0,0), e2t(0,1,0), e3t(0,0,1);
514 // rotation by phi around z = zhat axis
515 e1t.rotate(initEulerPhi*e3t);
516 e2t.rotate(initEulerPhi*e3t);
517 // rotation by theta around new x axis
518 e2t.rotate(m_initEulerTheta*e1t);
519 e3t.rotate(m_initEulerTheta*e1t);
520 // rotation by psi around new z axis
521 e1t.rotate(initEulerPsi*e3t);
522 e2t.rotate(initEulerPsi*e3t);
523 // set first vector in deque
524 e1.clear(); e1.push_front(e1t);
525 e2.clear(); e2.push_front(e2t);
526 e3.clear(); e3.push_front(e3t);
528 // calc L in body frame: 1. determine z-axis of fixed frame in body
529 // coordinates, undo the transformations for unit z vector of the body frame
531 // calc omega_body from ...
532 vec3<double> e1_body(1,0,0), e3_body(0,0,1);
533 // rotation by -psi along z axis
534 e1_body.rotate(-initEulerPsi*e3_body);
535 // rotation by -theta along new x axis
536 e3_body.rotate(-m_initEulerTheta*e1_body);
537 // omega_body = L_body * J_body^(-1)
538 vec3<double> omega_body = e3_body * m_Lz;
539 omega_body /= J;
541 // assemble initial y for solver
542 std::valarray<double> y(12);
543 y[std::slice(0,3,1)] = omega_body;
544 // 3 basis vectors of body system in fixed coordinates
545 y[std::slice(3,3,1)] = e1t;
546 y[std::slice(6,3,1)] = e2t;
547 y[std::slice(9,3,1)] = e3t;
549 // initial rotation vector
550 omega
551 = omega_body[0]*e1t
552 + omega_body[1]*e2t
553 + omega_body[2]*e3t;
555 if (solver!=0) delete solver;
556 // init solver
557 solver = new EulerOdeSolver(
558 0.0, // t
559 0.01, // first dt step size estimation
560 J[0], J[1], J[2], // A,B,C
561 y, // omega_body,e1,e2,e3
562 1e-5); // eps
565 void KRotationSaver::readSettings()
567 // read configuration settings from config file
568 KConfig *config = KGlobal::config();
569 config->setGroup("Settings");
571 // internal saver parameters are set to stored values or left at their
572 // default values if stored values are out of range
573 setTraceFlag(0, config->readEntry("x trace", traceFlagDefault[0]));
574 setTraceFlag(1, config->readEntry("y trace", traceFlagDefault[1]));
575 setTraceFlag(2, config->readEntry("z trace", traceFlagDefault[2]));
576 setRandomTraces(config->readEntry("random traces", randomTracesDefault));
577 setTraceLengthSeconds(
578 config->readDoubleNumEntry("length", traceLengthSecondsDefault));
579 setLz(
580 config->readDoubleNumEntry("Lz", LzDefault));
581 setInitEulerTheta(
582 config->readDoubleNumEntry("theta", initEulerThetaDefault));
585 void KRotationSaver::setTraceLengthSeconds(const double& t)
587 if (t >= traceLengthSecondsLimitLower
588 && t <= traceLengthSecondsLimitUpper)
590 m_traceLengthSeconds = t;
594 const double KRotationSaver::traceLengthSecondsLimitLower = 0.0;
595 const double KRotationSaver::traceLengthSecondsLimitUpper = 99.0;
596 const double KRotationSaver::traceLengthSecondsDefault = 3.0;
598 const bool KRotationSaver::traceFlagDefault[3] = {false, false, true};
600 void KRotationSaver::setLz(const double& Lz)
602 if (Lz >= LzLimitLower && Lz <= LzLimitUpper)
604 m_Lz = Lz;
608 const double KRotationSaver::LzLimitLower = 0.0;
609 const double KRotationSaver::LzLimitUpper = 500.0;
610 const double KRotationSaver::LzDefault = 10.0;
612 void KRotationSaver::setInitEulerTheta(const double& theta)
614 if (theta >= initEulerThetaLimitLower
615 && theta <= initEulerThetaLimitUpper)
617 m_initEulerTheta = theta;
621 const double KRotationSaver::initEulerThetaLimitLower = 0.0;
622 const double KRotationSaver::initEulerThetaLimitUpper = 180.0;
623 const double KRotationSaver::initEulerThetaDefault = 0.03;
625 // public slots
627 void KRotationSaver::doTimeStep()
629 // integrate a step ahead
630 solver->integrate(0.001*deltaT);
632 // read new y
633 std::valarray<double> y = solver->Y();
635 std::deque<vec3<double> >::size_type
636 max_vec_length =
637 static_cast<std::deque<vec3<double> >::size_type>
638 ( m_traceLengthSeconds/(0.001*deltaT) );
640 for (int j=0; j<3; ++j)
642 std::deque<vec3<double> >& e =
643 j==0 ? e1 :
644 j==1 ? e2 : e3;
646 // read out new body coordinate system
647 if (m_traceFlag[j] == true
648 && max_vec_length > 0)
650 e.push_front(y[std::slice(3*j+3, 3, 1)]);
651 while (e.size() > max_vec_length)
653 e.pop_back();
656 else
658 // only set the 1. element
659 e.front() = y[std::slice(3*j+3, 3, 1)];
660 // and delete all other emements
661 if (e.size() > 1)
662 e.resize(1);
666 // current rotation vector omega
667 omega = y[0]*e1.front() + y[1]*e2.front() + y[2]*e3.front();
669 // set new random traces every 10 seconds
670 if (m_randomTraces==true)
672 static unsigned int counter=0;
673 ++counter;
674 if (counter > unsigned(10.0/(0.001*deltaT)))
676 counter=0;
677 for (int i=0; i<3; ++i)
678 m_traceFlag[i] = rand()%2==1 ? true : false;
682 glArea->updateGL();
683 timer->start(deltaT, TRUE); // restart timer
686 // public slot of KRotationSaver, forward resize event to public slot of glArea
687 // to allow the resizing of the gl area withing the setup dialog
688 void KRotationSaver::resizeGlArea(QResizeEvent* e)
690 glArea->resize(e->size());
693 //-----------------------------------------------------------------------------
694 // KRotationSetup: dialog to setup screen saver parameters
695 //-----------------------------------------------------------------------------
697 KRotationSetup::KRotationSetup(QWidget* parent, const char* name)
698 : KRotationSetupUi(parent, name),
699 // create ssaver and give it the WinID of the preview area
700 saver(new KRotationSaver(preview->winId()))
702 // the dialog should block, no other control center input should be possible
703 // until the dialog is closed
704 setModal(TRUE);
706 lengthEdit->setValidator(
707 new QDoubleValidator(
708 KRotationSaver::traceLengthSecondsLimitLower,
709 KRotationSaver::traceLengthSecondsLimitUpper,
710 3, lengthEdit));
711 LzEdit->setValidator(
712 new QDoubleValidator(
713 KRotationSaver::LzLimitLower,
714 KRotationSaver::LzLimitUpper,
715 3, LzEdit));
716 thetaEdit->setValidator(
717 new QDoubleValidator(
718 KRotationSaver::initEulerThetaLimitLower,
719 KRotationSaver::initEulerThetaLimitUpper,
720 3, thetaEdit));
722 // set tool tips of editable fields
723 QToolTip::add(
724 lengthEdit,
725 ki18n("Length of traces in seconds of visibility.\nValid values from %1 to %2.")
726 .subs(KRotationSaver::traceLengthSecondsLimitLower, 0, 'f', 2)
727 .subs(KRotationSaver::traceLengthSecondsLimitUpper, 0, 'f', 2)
728 .toString());
729 QToolTip::add(
730 LzEdit,
731 ki18n("Angular momentum in z direction in arbitrary units.\nValid values from %1 to %2.")
732 .subs(KRotationSaver::LzLimitLower, 0, 'f', 2)
733 .subs(KRotationSaver::LzLimitUpper, 0, 'f', 2)
734 .toString());
735 QToolTip::add(
736 thetaEdit,
737 ki18n("Gravitational constant in arbitrary units.\nValid values from %1 to %2.")
738 .subs(KRotationSaver::initEulerThetaLimitLower, 0, 'f', 2)
739 .subs(KRotationSaver::initEulerThetaLimitUpper, 0, 'f', 2)
740 .toString());
742 // init preview area
743 preview->setBackgroundColor(Qt::black);
744 preview->show(); // otherwise saver does not get correct size
746 // read settings from saver and update GUI elements with these values, saver
747 // has read settings in its constructor
749 // set editable fields with stored values as defaults
750 xTrace->setChecked(saver->traceFlag(0));
751 yTrace->setChecked(saver->traceFlag(1));
752 zTrace->setChecked(saver->traceFlag(2));
753 randTraces->setChecked(saver->randomTraces());
754 QString text;
755 text.setNum(saver->traceLengthSeconds());
756 lengthEdit->validateAndSet(text,0,0,0);
757 text.setNum(saver->Lz());
758 LzEdit->validateAndSet(text,0,0,0);
759 text.setNum(saver->initEulerTheta());
760 thetaEdit->validateAndSet(text,0,0,0);
762 // if the preview area is resized it emmits the resized() event which is
763 // caught by the saver. The embedded GlArea is resized to fit into the
764 // preview area.
765 connect(preview, SIGNAL(resized(QResizeEvent*)),
766 saver, SLOT(resizeGlArea(QResizeEvent*)));
769 KRotationSetup::~KRotationSetup()
771 delete saver;
774 // Ok pressed - save settings and exit
775 void KRotationSetup::okButtonClickedSlot(void)
777 KConfig* config = KGlobal::config();
778 config->setGroup("Settings");
779 config->writeEntry("x trace", saver->traceFlag(0));
780 config->writeEntry("y trace", saver->traceFlag(1));
781 config->writeEntry("z trace", saver->traceFlag(2));
782 config->writeEntry("random traces", saver->randomTraces());
783 config->writeEntry("length", saver->traceLengthSeconds());
784 config->writeEntry("Lz", saver->Lz());
785 config->writeEntry("theta", saver->initEulerTheta());
786 config->sync();
787 accept();
790 void KRotationSetup::aboutButtonClickedSlot(void)
792 KMessageBox::about(this, i18n("\
793 <h3>KRotation Screen Saver for KDE</h3>\
794 <p>Simulation of a force free rotating asymmetric body</p>\
795 <p>Copyright (c) Georg&nbsp;Drenkhahn 2004</p>\
796 <p><tt>georg-d@users.sourceforge.net</tt></p>"));
799 void KRotationSetup::xTraceToggled(bool state)
801 saver->setTraceFlag(0, state);
803 void KRotationSetup::yTraceToggled(bool state)
805 saver->setTraceFlag(1, state);
807 void KRotationSetup::zTraceToggled(bool state)
809 saver->setTraceFlag(2, state);
811 void KRotationSetup::randomTracesToggled(bool state)
813 saver->setRandomTraces(state);
814 if (state==false)
816 // restore settings from gui if random traces are turned off
817 saver->setTraceFlag(0, xTrace->isChecked());
818 saver->setTraceFlag(1, yTrace->isChecked());
819 saver->setTraceFlag(2, zTrace->isChecked());
822 void KRotationSetup::lengthEnteredSlot(const QString& s)
824 saver->setTraceLengthSeconds(s.toDouble());
826 void KRotationSetup::LzEnteredSlot(const QString& s)
828 saver->setLz(s.toDouble());
829 if (saver!=0) saver->initData();
831 void KRotationSetup::thetaEnteredSlot(const QString& s)
833 saver->setInitEulerTheta(s.toDouble());
834 if (saver!=0) saver->initData();