3 * KRotation screen saver for KDE
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.
9 * Copyright (C) 2004 Georg Drenkhahn, Georg.Drenkhahn@gmx.net
11 * This program is free software; you can redistribute it and/or modify it under
12 * the terms of the GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the License or (at your option) version 3 or
14 * any later version accepted by the membership of KDE e.V. (or its successor
15 * approved by the membership of KDE e.V.), which shall act as a proxy defined
16 * in Section 14 of version 3 of the license.
18 * This program is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
37 #include <QResizeEvent>
44 #include <KMessageBox>
46 // Eigen2 from KDE support
48 #include <Eigen/Geometry>
49 // import all Eigen types, Transform and Quaternion are not part of the
50 // namespace part published by USING_PART_OF_NAMESPACE_EIGEN
51 using namespace Eigen
;
53 // the screen saver preview area class
54 #include "sspreviewarea.h"
56 #include "rotation.h" // own interfaces
57 #include "rotation.moc"
59 /** Version number of this screen saver */
60 #define KROTATION_VERSION "2.0"
63 #define M_PI 3.14159265358979323846
66 // libkscreensaver interface
67 class KRotationSaverInterface
: public KScreenSaverInterface
70 virtual KAboutData
* aboutData()
72 return new KAboutData(
74 ki18n("Simulation of a force free rotating asymmetric body"),
76 ki18n("Simulation of a force free rotating asymmetric body"));
79 /** function to create screen saver object */
80 virtual KScreenSaver
* create(WId id
)
82 return new KRotationSaver(id
);
85 /** function to create setup dialog for screen saver */
86 virtual QDialog
* setup()
88 return new KRotationSetup();
92 int main(int argc
, char *argv
[])
94 KRotationSaverInterface kss
;
95 return kScreenSaverMain(argc
, argv
, kss
);
98 //-----------------------------------------------------------------------------
99 // EulerOdeSolver implementation
100 //-----------------------------------------------------------------------------
102 EulerOdeSolver::EulerOdeSolver(
110 : RkOdeSolver
<double,12>(t
, y
, dt
, eps
),
117 Vector12d
EulerOdeSolver::f(const double& x
, const Vector12d
& y
) const
122 // vec omega in body coor. sys.: omega_body = (p, q, r)
123 const Vector3d
omega_body(y
.start
<3>());
125 // body unit vectors in fixed frame coordinates
127 for (int i
=0; i
<3; ++i
)
129 e
.col(i
) = y
.segment
<3>(3+i
*3);
132 // vec omega in global fixed coor. sys.
133 const Vector3d omega
= e
* omega_body
;
139 ypr
[0] = -(m_C
-m_B
)/m_A
* omega_body
[1] * omega_body
[2]; // p'
140 ypr
[1] = -(m_A
-m_C
)/m_B
* omega_body
[2] * omega_body
[0]; // q'
141 ypr
[2] = -(m_B
-m_A
)/m_C
* omega_body
[0] * omega_body
[1]; // r'
144 for (int i
=0; i
<3; ++i
)
146 ypr
.segment
<3>(3+i
*3) = omega
.cross(e
.col(i
));
151 //-----------------------------------------------------------------------------
154 //-----------------------------------------------------------------------------
155 // Rotation: screen saver widget
156 //-----------------------------------------------------------------------------
158 RotationGLWidget::RotationGLWidget(
160 const KRotationSaver
& saver
)
165 m_boxSize(Vector3d::Ones()),
169 m_lightTheta(M_PI
/4),
171 m_bodyAxsesLength(6),
172 m_fixedAxsesLength(8),
175 /* Set the box sizes from the momenta of inertia. J is the 3 vector with
176 * momenta of inertia with respect to the 3 figure axes. */
178 const Vector3d
& J
= m_saver
.J();
180 /* the default values must be valid so that w,h,d are real! */
181 const GLfloat x2
= 6.0*(-J
[0] + J
[1] + J
[2]);
182 const GLfloat y2
= 6.0*( J
[0] - J
[1] + J
[2]);
183 const GLfloat z2
= 6.0*( J
[0] + J
[1] - J
[2]);
185 if ((x2
>=0) && (y2
>=0) && (z2
>=0))
187 m_boxSize
= Vector3d(std::sqrt(x2
), std::sqrt(y2
), std::sqrt(z2
));
191 kError() << "parameter error";
195 /* --------- protected methods ----------- */
197 void RotationGLWidget::initializeGL(void)
199 qglClearColor(QColor(Qt::black
)); // set color to clear the background
201 glClearDepth(1); // depth buffer setup
202 glEnable(GL_DEPTH_TEST
); // depth testing
203 glDepthFunc(GL_LEQUAL
); // type of depth test
205 glShadeModel(GL_SMOOTH
); // smooth color shading in poygons
207 // nice perspective calculation
208 glHint(GL_PERSPECTIVE_CORRECTION_HINT
, GL_NICEST
);
211 glEnable(GL_LIGHTING
);
213 // set position of light0
215 {m_lightR
* std::sin(m_lightTheta
) * std::sin(m_lightPhi
),
216 m_lightR
* std::sin(m_lightTheta
) * std::cos(m_lightPhi
),
217 m_lightR
* std::cos(m_lightTheta
), 1.};
218 glLightfv(GL_LIGHT0
, GL_POSITION
, lightPos
);
220 // enable setting the material colour by glColor()
221 glEnable(GL_COLOR_MATERIAL
);
223 // set up display lists
225 if (m_fixedAxses
== 0)
227 m_fixedAxses
= glGenLists(1); // list to be returned
229 glNewList(m_fixedAxses
, GL_COMPILE
);
231 // fixed coordinate system axes
237 qglColor(QColor(Qt::blue
));
238 myGlArrow(m_fixedAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
241 qglColor(QColor(Qt::red
));
242 glRotatef(90, 0, 1, 0);
244 myGlArrow(m_fixedAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
247 qglColor(QColor(Qt::green
));
249 glRotatef(-90, 1, 0, 0);
250 myGlArrow(m_fixedAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
254 // end of axes object list
258 if (m_bodyAxses
== 0)
260 m_bodyAxses
= glGenLists(1); // list to be returned
262 glNewList(m_bodyAxses
, GL_COMPILE
);
265 qglColor(QColor(Qt::blue
));
266 myGlArrow(m_bodyAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
269 qglColor(QColor(Qt::red
));
271 glRotatef(90, 0, 1, 0);
272 myGlArrow(m_bodyAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
276 qglColor(QColor(Qt::green
));
278 glRotatef(-90, 1, 0, 0);
279 myGlArrow(m_bodyAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
285 void RotationGLWidget::draw_traces(void)
287 const std::deque
<Matrix3d
>&e
= m_saver
.e();
289 // traces must contain at least 2 elements
296 glScalef(m_bodyAxsesLength
, m_bodyAxsesLength
, m_bodyAxsesLength
);
299 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
301 for (int j
=0; j
<3; ++j
)
303 if (m_saver
.traceFlag(j
))
306 GLfloat em
[4] = {0,0,0,1};
307 em
[j
] = 1; // set either red, green, blue emission colour
309 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, em
);
312 // set iterator of the tail part
313 std::deque
<Matrix3d
>::const_iterator eit
= e
.begin();
314 std::deque
<Matrix3d
>::const_iterator tail
=
316 static_cast<std::deque
<Matrix3d
>::difference_type
>
320 for (; eit
< e
.end()-1; ++eit
)
322 glVertex3f((*eit
)(0,j
), (*eit
)(1,j
), (*eit
)(2,j
));
323 // decrease transparency for tail section
328 (1.0 - double(eit
-tail
)/(0.1 * e
.size()));
331 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, em
);
332 glVertex3f((*(eit
+1))(0,j
), (*(eit
+1))(1,j
), (*(eit
+1))(2,j
));
343 void RotationGLWidget::paintGL(void)
345 // clear color and depth buffer
346 glClear(GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
348 glMatrixMode(GL_MODELVIEW
); // select modelview matrix
351 GLfloat
const em
[] = {0,0,0,1};
352 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, em
);
355 // calculate the transform which rotates the unit z vector onto omega
359 .setFromTwoVectors(Vector3d::UnitZ(), m_saver
.omega())
362 // draw the white omega arrow
363 qglColor(QColor(Qt::white
));
364 myGlArrow(7, .5f
, .1f
, 0.2f
);
367 // draw the fixed axes
368 glCallList(m_fixedAxses
);
371 // create transformation/rotation matrix from the body and its unit axes
374 Transform
<double,3>(m_saver
.e().front())
377 // draw the body unit axis
378 glCallList(m_bodyAxses
);
380 // scaling from a cube to the rotating body
381 glScalef(m_boxSize
[0]/2, m_boxSize
[1]/2, m_boxSize
[2]/2);
386 qglColor(QColor(Qt::blue
));
388 glVertex3f( 1, 1, 1);
389 glVertex3f(-1, 1, 1);
390 glVertex3f(-1, -1, 1);
391 glVertex3f( 1, -1, 1);
394 glVertex3f( 1, 1, -1);
395 glVertex3f(-1, 1, -1);
396 glVertex3f(-1, -1, -1);
397 glVertex3f( 1, -1, -1);
399 qglColor(QColor(Qt::green
));
401 glVertex3f( 1, 1, 1);
402 glVertex3f( 1, 1, -1);
403 glVertex3f(-1, 1, -1);
404 glVertex3f(-1, 1, 1);
407 glVertex3f( 1, -1, 1);
409 glVertex3f( 1, -1, -1);
410 glVertex3f(-1, -1, -1);
411 glVertex3f(-1, -1, 1);
413 qglColor(QColor(Qt::red
));
415 glVertex3f(-1, 1, 1);
416 glVertex3f(-1, 1, -1);
417 glVertex3f(-1, -1, -1);
418 glVertex3f(-1, -1, 1);
421 glVertex3f( 1, 1, 1);
422 glVertex3f( 1, 1, -1);
423 glVertex3f( 1, -1, -1);
424 glVertex3f( 1, -1, 1);
435 void RotationGLWidget::resizeGL(int w
, int h
)
437 kDebug() << "w=" << w
<< ", h=" << h
<< "\n";
439 // prevent division by zero
445 // set the new view port
446 glViewport(0, 0, (GLint
)w
, (GLint
)h
);
448 // set up projection matrix
449 glMatrixMode(GL_PROJECTION
);
452 gluPerspective(40.0f
, (GLdouble
)w
/(GLdouble
)h
, 1.0, 100.0f
);
454 // Viewing transformation, position for better view
455 // Theta is polar angle 0<Theta<Pi
457 m_eyeR
* std::sin(m_eyeTheta
) * std::sin(m_eyePhi
),
458 m_eyeR
* std::sin(m_eyeTheta
) * std::cos(m_eyePhi
),
459 m_eyeR
* std::cos(m_eyeTheta
),
464 /* --------- privat methods ----------- */
466 void RotationGLWidget::myGlArrow(
467 GLfloat total_length
, GLfloat head_length
,
468 GLfloat base_width
, GLfloat head_width
)
470 GLUquadricObj
* const quadAx
= gluNewQuadric();
473 quadAx
, base_width
, base_width
,
474 total_length
- head_length
, 10, 1);
475 glTranslatef(0, 0, total_length
- head_length
);
476 gluCylinder(quadAx
, head_width
, 0, head_length
, 10, 1);
478 gluDeleteQuadric(quadAx
);
482 //-----------------------------------------------------------------------------
483 // KRotationSaver: screen saver class
484 //-----------------------------------------------------------------------------
488 KRotationSaver::KRotationSaver(WId id
)
493 m_J(4,2,3), // fixed box sizes!
494 m_traceLengthSeconds(sm_traceLengthSecondsDefault
),
498 m_initEulerTheta(sm_initEulerThetaDefault
)
500 // no need to set our parent widget's background here, the GL widget sets its
501 // own background color
503 readSettings(); // read global settings
505 // init m_e1,m_e2,m_e3,m_omega, construct and init m_solver
508 // create gl widget w/o parent
509 m_glArea
= new RotationGLWidget(0, *this);
510 embed(m_glArea
); // embed gl widget and resize it
511 m_glArea
->show(); // show embedded gl widget
513 // set up cyclic timer
514 m_timer
= new QTimer(this);
515 m_timer
->start(sm_deltaT
);
516 connect(m_timer
, SIGNAL(timeout()), this, SLOT(doTimeStep()));
519 KRotationSaver::~KRotationSaver()
523 // m_timer is automatically deleted with parent KRotationSaver
528 void KRotationSaver::initData()
530 // rotation by phi around z = zhat axis
531 Matrix3d
et(AngleAxisd(m_initEulerPhi
, Vector3d::UnitZ()));
532 // rotation by theta around new x axis
533 et
= AngleAxisd(m_initEulerPhi
, et
.col(0)).toRotationMatrix() * et
;
534 // rotation by psi around new z axis
535 et
= AngleAxisd(m_initEulerPsi
, et
.col(2)).toRotationMatrix() * et
;
537 // set first vector in deque
538 m_e
.clear(); m_e
.push_front(et
);
540 /* calc L in body frame:
542 * determine unit-axes of fixed frame in body coordinates, invert the
543 * transformations above for unit vectors of the body frame */
545 // rotation by -psi along z axis
546 Matrix3d
e_body(AngleAxisd(-m_initEulerPsi
, Vector3d::UnitZ()));
547 // rotation by -theta along new x axis
548 e_body
= AngleAxisd(-m_initEulerTheta
, e_body
.col(0)).toRotationMatrix() * e_body
;
550 // omega_body = L_body * J_body^(-1)
551 // component-wise division because J_body is a diagonal matrix
552 Vector3d omega_body
= (m_Lz
* e_body
.col(2)).cwise() / m_J
;
554 // initial rotation vector
555 m_omega
= et
* omega_body
;
557 // assemble initial y for solver
559 y
.start
<3>() = omega_body
;
560 // 3 basis vectors of body system in fixed coordinates
561 y
.segment
<3>(3) = et
.col(0);
562 y
.segment
<3>(6) = et
.col(1);
563 y
.segment
<3>(9) = et
.col(2);
567 // deleting the solver is necessary when parameters are changed in the
568 // configuration dialog.
572 m_solver
= new EulerOdeSolver(
574 0.01, // first dt step size estimation
575 m_J
[0], m_J
[1], m_J
[2], // A,B,C
576 y
, // omega_body,e1,e2,e3
580 void KRotationSaver::readSettings()
582 // read configuration settings from config file
583 KConfigGroup
config(KGlobal::config(), "Settings");
585 // internal saver parameters are set to stored values or left at their
586 // default values if stored values are out of range
587 setTraceFlag(0, config
.readEntry("x trace", sm_traceFlagDefault
[0]));
588 setTraceFlag(1, config
.readEntry("y trace", sm_traceFlagDefault
[1]));
589 setTraceFlag(2, config
.readEntry("z trace", sm_traceFlagDefault
[2]));
590 setRandomTraces(config
.readEntry("random traces", sm_randomTracesDefault
));
591 setTraceLengthSeconds(
592 config
.readEntry("length", sm_traceLengthSecondsDefault
));
594 config
.readEntry("Lz", sm_LzDefault
));
596 config
.readEntry("theta", sm_initEulerThetaDefault
));
599 void KRotationSaver::setTraceLengthSeconds(const double& t
)
601 if ((t
>= sm_traceLengthSecondsLimitLower
)
602 && (t
<= sm_traceLengthSecondsLimitUpper
))
604 m_traceLengthSeconds
= t
;
608 void KRotationSaver::setLz(const double& Lz
)
610 if ((Lz
>= sm_LzLimitLower
) && (Lz
<= sm_LzLimitUpper
))
616 void KRotationSaver::setInitEulerTheta(const double& theta
)
618 if ((theta
>= sm_initEulerThetaLimitLower
)
619 && (theta
<= sm_initEulerThetaLimitUpper
))
621 m_initEulerTheta
= theta
;
627 void KRotationSaver::doTimeStep()
629 // integrate a step ahead
630 m_solver
->integrate(0.001*sm_deltaT
);
633 Vector12d y
= m_solver
->Y();
635 std::deque
<Vector3d
>::size_type
637 static_cast<std::deque
<Vector3d
>::size_type
>
638 ( m_traceLengthSeconds
/(0.001*sm_deltaT
) );
640 // construct matrix from solution vector
641 // read out new body coordinate system
643 for (int j
=0; j
<3; ++j
)
645 et
.col(j
) = y
.segment
<3>(3*j
+3);
650 if (max_vec_length
> 0)
653 while (m_e
.size() > max_vec_length
)
660 // only set the 1. element
662 // and delete all other emements
669 // current rotation vector omega
670 m_omega
= m_e
.front() * y
.start
<3>();
672 // set new random traces every 10 seconds
675 static unsigned int counter
=0;
677 if (counter
> unsigned(10.0/(0.001*sm_deltaT
)))
680 for (int i
=0; i
<3; ++i
)
682 m_traceFlag
[i
] = (rand()%2==1);
687 m_glArea
->updateGL();
689 // no need to restart timer here, it is a cyclic timer
692 // public slot of KRotationSaver, forward resize event to public slot of glArea
693 // to allow the resizing of the gl area withing the setup dialog
694 void KRotationSaver::resizeGlArea(QResizeEvent
* e
)
696 m_glArea
->resize(e
->size());
699 // public static class members
701 const double KRotationSaver::sm_traceLengthSecondsLimitLower
= 0.0;
702 const double KRotationSaver::sm_traceLengthSecondsLimitUpper
= 99.0;
703 const double KRotationSaver::sm_traceLengthSecondsDefault
= 3.0;
705 const bool KRotationSaver::sm_traceFlagDefault
[3] = {false, false, true};
706 const bool KRotationSaver::sm_randomTracesDefault
= true;
708 const double KRotationSaver::sm_LzLimitLower
= 0.0;
709 const double KRotationSaver::sm_LzLimitUpper
= 500.0;
710 const double KRotationSaver::sm_LzDefault
= 10.0;
712 const double KRotationSaver::sm_initEulerThetaLimitLower
= 0.0;
713 const double KRotationSaver::sm_initEulerThetaLimitUpper
= 180.0;
714 const double KRotationSaver::sm_initEulerThetaDefault
= 0.03;
716 // private static class members
718 const unsigned int KRotationSaver::sm_deltaT
= 20;
721 //-----------------------------------------------------------------------------
722 // KRotationSetup: dialog to setup screen saver parameters
723 //-----------------------------------------------------------------------------
725 KRotationSetup::KRotationSetup(QWidget
* parent
)
730 // the dialog should block, no other control center input should be possible
731 // until the dialog is closed
734 m_lengthEdit
->setValidator(
735 new QDoubleValidator(
736 KRotationSaver::sm_traceLengthSecondsLimitLower
,
737 KRotationSaver::sm_traceLengthSecondsLimitUpper
,
739 m_LzEdit
->setValidator(
740 new QDoubleValidator(
741 KRotationSaver::sm_LzLimitLower
,
742 KRotationSaver::sm_LzLimitUpper
,
744 m_thetaEdit
->setValidator(
745 new QDoubleValidator(
746 KRotationSaver::sm_initEulerThetaLimitLower
,
747 KRotationSaver::sm_initEulerThetaLimitUpper
,
750 // set tool tips of editable fields
751 m_lengthEdit
->setToolTip(
752 ki18n("Length of traces in seconds of visibility.\nValid values from %1 to %2.")
753 .subs(KRotationSaver::sm_traceLengthSecondsLimitLower
, 0, 'f', 2)
754 .subs(KRotationSaver::sm_traceLengthSecondsLimitUpper
, 0, 'f', 2)
756 m_LzEdit
->setToolTip(
757 ki18n("Angular momentum in z direction in arbitrary units.\nValid values from %1 to %2.")
758 .subs(KRotationSaver::sm_LzLimitLower
, 0, 'f', 2)
759 .subs(KRotationSaver::sm_LzLimitUpper
, 0, 'f', 2)
761 m_thetaEdit
->setToolTip(
762 ki18n("Gravitational constant in arbitrary units.\nValid values from %1 to %2.")
763 .subs(KRotationSaver::sm_initEulerThetaLimitLower
, 0, 'f', 2)
764 .subs(KRotationSaver::sm_initEulerThetaLimitUpper
, 0, 'f', 2)
767 // setting the background of m_preview widget is not necessary, it's content
768 // is overlayed with the embedded GL widget anyway
769 m_preview
->show(); // otherwise saver does not get correct size initially
771 // create screen saver and give it the WinID of the preview area in which it
773 m_saver
= new KRotationSaver(m_preview
->winId());
775 // read settings from saver and update GUI elements with these values, saver
776 // has read settings in its constructor
778 // set editable fields with stored values as defaults
779 m_xTrace
->setChecked(m_saver
->traceFlag(0));
780 m_yTrace
->setChecked(m_saver
->traceFlag(1));
781 m_zTrace
->setChecked(m_saver
->traceFlag(2));
782 m_randTraces
->setChecked(m_saver
->randomTraces());
784 text
.setNum(m_saver
->traceLengthSeconds());
785 m_lengthEdit
->setText(text
);
786 text
.setNum(m_saver
->Lz());
787 m_LzEdit
->setText(text
);
788 text
.setNum(m_saver
->initEulerTheta());
789 m_thetaEdit
->setText(text
);
791 // if the preview area is resized it emits the resized() event which is
792 // caught by m_saver. The embedded GLArea is resized to fit into the preview
794 connect(m_preview
, SIGNAL(resized(QResizeEvent
*)),
795 m_saver
, SLOT(resizeGlArea(QResizeEvent
*)));
797 connect(m_okButton
, SIGNAL(clicked()), this, SLOT(okButtonClickedSlot()));
798 connect(m_aboutButton
, SIGNAL(clicked()), this, SLOT(aboutButtonClickedSlot()));
800 connect(m_xTrace
, SIGNAL(toggled(bool)), this, SLOT(xTraceToggled(bool)));
801 connect(m_randTraces
, SIGNAL(toggled(bool)), this, SLOT(randomTracesToggled(bool)));
802 connect(m_yTrace
, SIGNAL(toggled(bool)), this, SLOT(yTraceToggled(bool)));
803 connect(m_zTrace
, SIGNAL(toggled(bool)), this, SLOT(zTraceToggled(bool)));
804 connect(m_lengthEdit
, SIGNAL(textChanged(QString
)), this, SLOT(lengthEnteredSlot(QString
)));
805 connect(m_LzEdit
, SIGNAL(textChanged(QString
)), this, SLOT(LzEnteredSlot(QString
)));
806 connect(m_thetaEdit
, SIGNAL(textChanged(QString
)), this, SLOT(thetaEnteredSlot(QString
)));
809 KRotationSetup::~KRotationSetup()
814 // Ok pressed - save settings and exit
815 void KRotationSetup::okButtonClickedSlot(void)
817 KConfigGroup
config(KGlobal::config(), "Settings");
818 config
.writeEntry("x trace", m_saver
->traceFlag(0));
819 config
.writeEntry("y trace", m_saver
->traceFlag(1));
820 config
.writeEntry("z trace", m_saver
->traceFlag(2));
821 config
.writeEntry("random traces", m_saver
->randomTraces());
822 config
.writeEntry("length", m_saver
->traceLengthSeconds());
823 config
.writeEntry("Lz", m_saver
->Lz());
824 config
.writeEntry("theta", m_saver
->initEulerTheta());
829 void KRotationSetup::aboutButtonClickedSlot(void)
831 KMessageBox::about(this, i18n("\
832 <h3>KRotation Screen Saver for KDE</h3>\
833 <p>Simulation of a force free rotating asymmetric body</p>\
834 <p>Copyright (c) Georg Drenkhahn 2004</p>\
835 <p><tt>Georg.Drenkhahn@gmx.net</tt></p>"));
838 void KRotationSetup::xTraceToggled(bool state
)
840 m_saver
->setTraceFlag(0, state
);
842 void KRotationSetup::yTraceToggled(bool state
)
844 m_saver
->setTraceFlag(1, state
);
846 void KRotationSetup::zTraceToggled(bool state
)
848 m_saver
->setTraceFlag(2, state
);
850 void KRotationSetup::randomTracesToggled(bool state
)
852 m_saver
->setRandomTraces(state
);
855 // restore settings from gui if random traces are turned off
856 m_saver
->setTraceFlag(0, m_xTrace
->isChecked());
857 m_saver
->setTraceFlag(1, m_yTrace
->isChecked());
858 m_saver
->setTraceFlag(2, m_zTrace
->isChecked());
861 void KRotationSetup::lengthEnteredSlot(const QString
& s
)
863 m_saver
->setTraceLengthSeconds(s
.toDouble());
865 void KRotationSetup::LzEnteredSlot(const QString
& s
)
867 m_saver
->setLz(s
.toDouble());
870 void KRotationSetup::thetaEnteredSlot(const QString
& s
)
872 m_saver
->setInitEulerTheta(s
.toDouble());