1 //============================================================================
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 // Developed by Georg Drenkhahn, georg-d@users.sourceforge.net
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 //============================================================================
37 #include <qcheckbox.h>
38 #include <qlineedit.h>
39 #include <qvalidator.h>
42 #include <QResizeEvent>
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
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(
94 std::valarray
<double> &y_
,
96 : RkOdeSolver
<double>(t_
,y_
,dt_
,eps_
),
101 std::valarray
<double> EulerOdeSolver::f(
103 const std::valarray
<double> &y
) const
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.
122 + omega_body
[2] * e3
);
125 std::valarray
<double> ypr(y
.size());
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'
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
);
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),
158 lightR(10), lightTheta(M_PI
/4), lightPhi(0),
166 // set up initial rotation matrix as unit matrix, only non-constant elements
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!
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
));
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
);
207 glEnable(GL_LIGHTING
);
209 // set positon of light0
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
222 fixedAxses
= glGenLists(1); // list to be returned
223 glNewList(fixedAxses
, GL_COMPILE
);
225 // fixed coordinate system axes
231 qglColor(QColor(Qt::blue
));
232 myGlArrow(fixedAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
235 qglColor(QColor(Qt::red
));
236 glRotatef(90, 0, 1, 0);
238 myGlArrow(fixedAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
241 qglColor(QColor(Qt::green
));
243 glRotatef(-90, 1, 0, 0);
244 myGlArrow(fixedAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
248 // end of axes object list
253 bodyAxses
= glGenLists(1); // list to be returned
254 glNewList(bodyAxses
, GL_COMPILE
);
257 qglColor(QColor(Qt::blue
));
258 myGlArrow(bodyAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
261 qglColor(QColor(Qt::red
));
263 glRotatef(90, 0, 1, 0);
264 myGlArrow(bodyAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
268 qglColor(QColor(Qt::green
));
270 glRotatef(-90, 1, 0, 0);
271 myGlArrow(bodyAxsesLength
, 0.5f
, 0.03f
, 0.1f
);
277 void RotationGLWidget::draw_traces(void)
279 if (e1
.size()==0 && e2
.size()==0 && e3
.size()==0)
283 glScalef(bodyAxsesLength
, bodyAxsesLength
, bodyAxsesLength
);
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
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
);
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
=
307 static_cast<std::deque
<vec3
<double> >::difference_type
>
311 for (; eit
< e
.end()-1; ++eit
)
313 glVertex3f((*eit
)[0], (*eit
)[1], (*eit
)[2]);
314 // decrease transparency for tail section
318 (1.0 - double(eit
-tail
)/(0.1*e
.size()));
320 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, em
);
321 glVertex3f((*(eit
+1))[0], (*(eit
+1))[1], (*(eit
+1))[2]);
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
340 GLfloat
const em
[] = {0,0,0,1};
341 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, em
);
344 vec3
<double> rotvec
=
345 vec3
<double>::crossprod(vec3
<double>(0,0,1), omega
).normalize();
347 180./M_PI
* vec3
<double>::angle(vec3
<double>(0,0,1), omega
);
349 glRotatef(rotdeg
, rotvec
[0], rotvec
[1], rotvec
[2]);
350 qglColor(QColor(Qt::white
));
351 myGlArrow(7, .5f
, .1f
, 0.2f
);
355 glCallList(fixedAxses
);
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();
375 glMultMatrixf(rotmat
);
377 glCallList(bodyAxses
);
379 glScalef(boxSize
[0]/2, boxSize
[1]/2, boxSize
[2]/2);
384 qglColor(QColor(Qt::blue
));
386 glVertex3f( 1, 1, 1);
387 glVertex3f(-1, 1, 1);
388 glVertex3f(-1, -1, 1);
389 glVertex3f( 1, -1, 1);
392 glVertex3f( 1, 1, -1);
393 glVertex3f(-1, 1, -1);
394 glVertex3f(-1, -1, -1);
395 glVertex3f( 1, -1, -1);
397 qglColor(QColor(Qt::green
));
399 glVertex3f( 1, 1, 1);
400 glVertex3f( 1, 1, -1);
401 glVertex3f(-1, 1, -1);
402 glVertex3f(-1, 1, 1);
405 glVertex3f( 1, -1, 1);
407 glVertex3f( 1, -1, -1);
408 glVertex3f(-1, -1, -1);
409 glVertex3f(-1, -1, 1);
411 qglColor(QColor(Qt::red
));
413 glVertex3f(-1, 1, 1);
414 glVertex3f(-1, 1, -1);
415 glVertex3f(-1, -1, -1);
416 glVertex3f(-1, -1, 1);
419 glVertex3f( 1, 1, 1);
420 glVertex3f( 1, 1, -1);
421 glVertex3f( 1, -1, -1);
422 glVertex3f( 1, -1, 1);
432 void RotationGLWidget::resizeGL(int w
, int h
)
434 // Prevent a divide by zero
437 // set the new view port
438 glViewport(0, 0, (GLint
)w
, (GLint
)h
);
440 // set up projection matrix
441 glMatrixMode(GL_PROJECTION
);
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
449 eyeR
* sin(eyeTheta
) * sin(eyePhi
),
450 eyeR
* sin(eyeTheta
) * cos(eyePhi
),
451 eyeR
* cos(eyeTheta
),
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();
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);
469 gluDeleteQuadric(quadAx
);
473 //-----------------------------------------------------------------------------
474 // KRotationSaver: screen saver class
475 //-----------------------------------------------------------------------------
477 KRotationSaver::KRotationSaver(WId id
)
479 J(4,2,3), // fixed box sizes!
485 m_traceLengthSeconds(traceLengthSecondsDefault
),
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
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
;
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
555 if (solver
!=0) delete solver
;
557 solver
= new EulerOdeSolver(
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
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
->readBoolEntry("x trace", traceFlagDefault
[0]));
574 setTraceFlag(1, config
->readBoolEntry("y trace", traceFlagDefault
[1]));
575 setTraceFlag(2, config
->readBoolEntry("z trace", traceFlagDefault
[2]));
576 setRandomTraces(config
->readBoolEntry("random traces", randomTracesDefault
));
577 setTraceLengthSeconds(
578 config
->readDoubleNumEntry("length", traceLengthSecondsDefault
));
580 config
->readDoubleNumEntry("Lz", LzDefault
));
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
)
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;
627 void KRotationSaver::doTimeStep()
629 // integrate a step ahead
630 solver
->integrate(0.001*deltaT
);
633 std::valarray
<double> y
= solver
->Y();
635 std::deque
<vec3
<double> >::size_type
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
=
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
)
658 // only set the 1. element
659 e
.front() = y
[std::slice(3*j
+3, 3, 1)];
660 // and delete all other emements
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;
674 if (counter
> unsigned(10.0/(0.001*deltaT
)))
677 for (int i
=0; i
<3; ++i
)
678 m_traceFlag
[i
] = rand()%2==1 ? true : false;
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
706 lengthEdit
->setValidator(
707 new QDoubleValidator(
708 KRotationSaver::traceLengthSecondsLimitLower
,
709 KRotationSaver::traceLengthSecondsLimitUpper
,
711 LzEdit
->setValidator(
712 new QDoubleValidator(
713 KRotationSaver::LzLimitLower
,
714 KRotationSaver::LzLimitUpper
,
716 thetaEdit
->setValidator(
717 new QDoubleValidator(
718 KRotationSaver::initEulerThetaLimitLower
,
719 KRotationSaver::initEulerThetaLimitUpper
,
722 // set tool tips of editable fields
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)
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)
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)
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());
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
765 connect(preview
, SIGNAL(resized(QResizeEvent
*)),
766 saver
, SLOT(resizeGlArea(QResizeEvent
*)));
769 KRotationSetup::~KRotationSetup()
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());
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 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
);
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();