/** @file * * 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. * * Copyright (C) 2004 Georg Drenkhahn, Georg.Drenkhahn@gmx.net * * 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) version 3 or * any later version accepted by the membership of KDE e.V. (or its successor * approved by the membership of KDE e.V.), which shall act as a proxy defined * in Section 14 of version 3 of the license. * * 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. */ #ifndef ROTATION2_H #define ROTATION2_H // Qt headers #include #include #include // GL headers #include #include // KDE headers #include #include // Eigen2 from KDE support #include // import most common Eigen types using namespace Eigen; // own extension of typdefed vector types of Eigen2 typedef Matrix Vector12d; #include "rkodesolver.h" // KRotationSetupUi #include "ui_rotationcfg.h" //-------------------------------------------------------------------- /** @brief ODE solver for the Euler equations. * * Class implements RkOdeSolver to solve the Euler equations of motion * tor the rotating object. */ class EulerOdeSolver : public RkOdeSolver { public: /** @brief Constructor for the ODE solver for the Euler equations. * @param t Time in seconds, integration variable * @param dt Initial time increment in seconds for integration, auto adjusted * later to guarantee precision * @param A Moment of inertia along 1. figure axis * @param B Moment of inertia along 2. figure axis * @param C Moment of inertia along 3. figure axis * @param y Vector of 12 elements containing the initial rotation vector * omega (elements 0 to 2), and the initial rotating systems coordinate * vectors e1, e2, e3 (elements 3 to 5, 6 to 8, and 9 to 11). * @param eps Relative precision per integration step, see * RkOdeSolver::RkOdeSolver(). */ EulerOdeSolver( const double& t, const double& dt, const double& A, const double& B, const double& C, Vector12d& y, const double& eps); protected: /** @brief ODE function for the Euler equation system * @param x time in seconds * @param y Vector of 12 elements containing the rotation vector omega * (elements 0 to 2), and the rotating systems coordinate vectors e1, e2, e3 * (elements 3 to 5, 6 to 8, and 9 to 11). * @return derivation dy/dx */ Vector12d f(const double& x, const Vector12d& y) const; private: /** Moments of inertia along the three figure axes */ double m_A, m_B, m_C; }; //-------------------------------------------------------------------- /* forward declaration */ class KRotationSaver; //-------------------------------------------------------------------- /** @brief GL widget class for the KRotation screen saver * * Class implements QGLWidget to display the KRotation screen saver. */ class RotationGLWidget : public QGLWidget { Q_OBJECT public: /** @brief Constructor of KRotation's GL widget * @param parent parent widget, passed to QGLWidget's constructor * @param omega current rotation vector * @param e trace data * @param J 3 vector with momenta of inertia with respect to the 3 figure * axes. */ RotationGLWidget( QWidget* parent, const KRotationSaver& saver); protected: /** Called if scenery (GL view) must be updated */ virtual void paintGL(); /** Called if gl widget was resized. Method makes adjustments for new * perspective */ virtual void resizeGL(int w, int h); /** Setup the GL environment */ virtual void initializeGL(); private: /** @brief Draw 3D arrow * @param total_length total length of arrow * @param head_length length of arrow head (cone) * @param base_width width of arrow base * @param head_width width of arrow head (cone) * * The arrow is drawn from the coordinates zero point along th z direction. * The cone's tip is located at (0,0,@a total_length). */ void myGlArrow( GLfloat total_length, GLfloat head_length, GLfloat base_width, GLfloat head_width); /** Draw the traces in the GL area */ void draw_traces (void); private: // Private attributes /** Eye position distance from coordinate zero point */ GLfloat m_eyeR; /** Eye position theta angle from z axis */ GLfloat m_eyeTheta; /** Eye position phi angle (longitude) */ GLfloat m_eyePhi; /** Box size */ Vector3d m_boxSize; /** GL object list of fixed coordinate systems axses */ GLuint m_fixedAxses; /** GL object list of rotating coordinate systems axses */ GLuint m_bodyAxses; /** Light position distance from coordinate zero point */ GLfloat m_lightR; /** Light position theta angle from z axis */ GLfloat m_lightTheta; /** Light position phi angle (longitude) */ GLfloat m_lightPhi; /** Length of the rotating coordinate system axses */ GLfloat m_bodyAxsesLength; /** Length of the fixed coordinate system axses */ GLfloat m_fixedAxsesLength; /** reference to screen saver */ const KRotationSaver& m_saver; }; //-------------------------------------------------------------------- /** @brief Main class of the KRotation screen saver * * This class implements KScreenSaver for the KRotation screen saver. */ class KRotationSaver : public KScreenSaver { Q_OBJECT public: /* public member functions */ /** @brief Constructor of the KRotation screen saver object * @param drawable Id of the window in which the screen saver is drawed * * Initial settings are read from disk, the GL widget is set up and displayed * and the eq. of motion solver is started. */ KRotationSaver(WId drawable); /** @brief Destructor of the KPendulum screen saver object * * Only KPendulumSaver::solver is destoyed. */ ~KRotationSaver(); /** read the saved settings from disk */ void readSettings(); /** init physical quantities and set up the ode solver */ void initData(); /** Returns length of traces in seconds of visibility, parameter from setup * dialog */ inline double traceLengthSeconds(void) const { return m_traceLengthSeconds; } /** Sets the length of traces in seconds of visibility. */ void setTraceLengthSeconds(const double& t); /** Flags indicating if the traces for x,y,z are shown. Only relevant if * ::randomTraces is not set to true. Parameter from setup dialog */ inline bool traceFlag(unsigned int n) const { return m_traceFlag[n]; } /** (Un)Sets the x,y,z traces flags. */ inline void setTraceFlag(unsigned int n, const bool& flag) { m_traceFlag[n] = flag; } /** If flag is set to true the traces will be (de)activated randomly all 10 * seconds. Parameter from setup dialog */ inline bool randomTraces(void) const { return m_randomTraces; } /** (Un)Sets the random trace flag. */ inline void setRandomTraces(const bool& flag) { m_randomTraces = flag; } /** Returns the angular momentum. */ inline double Lz(void) const { return m_Lz; } /** Sets the angular momentum. */ void setLz(const double& Lz); /** Returns initial eulerian angle theta of the top body at t=0 sec. */ inline double initEulerTheta(void) const { return m_initEulerTheta; } /** Set the initial eulerian angle theta of the top body at t=0 sec. */ void setInitEulerTheta(const double& theta); /** Returns constant reference to m_omega */ inline const Vector3d& omega(void) const { return m_omega; } /** Returns constant reference to m_e */ inline const std::deque& e(void) const { return m_e; } /** Returns constant reference to m_J */ inline const Vector3d& J(void) const { return m_J; } /* public static class member variables */ /** Lower argument limit for setTraceLengthSeconds() */ static const double sm_traceLengthSecondsLimitLower; /** Upper argument limit for setTraceLengthSeconds() */ static const double sm_traceLengthSecondsLimitUpper; /** Default value of KRotationSaver::m_traceLengthSeconds */ static const double sm_traceLengthSecondsDefault; /** Default values for KRotationSaver::m_traceFlag */ static const bool sm_traceFlagDefault[3]; /** Default value for KRotationSaver::m_randomTraces */ static const bool sm_randomTracesDefault; /** Lower argument limit for setLz() */ static const double sm_LzLimitLower; /** Upper argument limit for setLz() */ static const double sm_LzLimitUpper; /** Default value for KRotationSaver::m_Lz */ static const double sm_LzDefault; /** Lower argument limit for setInitEulerTheta() */ static const double sm_initEulerThetaLimitLower; /** Upper argument limit for setInitEulerTheta() */ static const double sm_initEulerThetaLimitUpper; /** Default value for KRotationSaver::m_initEulerTheta */ static const double sm_initEulerThetaDefault; public slots: /** slot is called if integration should proceed by ::sm_deltaT */ void doTimeStep(); /** slot is called if setup dialog changes in size and the GL area should be * adjusted */ void resizeGlArea(QResizeEvent* e); private: /** Time step size for the integration in milliseconds. Used in * ::KRotationSaver and ::RotationGLWidget. */ static const unsigned int sm_deltaT; /** The ode solver which is used to integrate the equations of motion */ EulerOdeSolver* m_solver; /** Gl widget of simulation */ RotationGLWidget* m_glArea; /** Timer for the real time integration of the Euler equations */ QTimer* m_timer; /** current rotation vector */ Vector3d m_omega; /** deque of matrices of figure axes in fixed frame coordinates. Each matrix * column represents an axis vector */ std::deque m_e; /** Momentum of inertia along figure axes */ const Vector3d m_J; /** Length of traces in seconds of visibility, parameter from setup dialog */ double m_traceLengthSeconds; /** Flags indicating if the traces for x,y,z are shown. Only relevant if * ::randomTraces is not set to true. Parameter from setup dialog */ bool m_traceFlag[3]; /** If flag is set to true the traces will be (de)activated randomly all 10 * seconds. Parameter from setup dialog */ bool m_randomTraces; /** Angular momentum. This is a constant of motion and points always into * positive z direction. Parameter from setup dialog */ double m_Lz; /** Initial eulerian angles phi of the top body at t=0s */ double m_initEulerPhi; /** Initial eulerian angles psi of the top body at t=0s */ double m_initEulerPsi; /** Initial eulerian angles theta of the top body at t=0 sec. Parameter from * setup dialog */ double m_initEulerTheta; }; class RotationWidget : public QWidget, public Ui::RotationWidget { public: RotationWidget( QWidget *parent = 0L ) : QWidget( parent ) { setupUi( this ); } }; //-------------------------------------------------------------------- /** @brief KRotation screen saver setup dialog. * * This class handles the KRotation screen saver setup dialog. */ class KRotationSetup : public KDialog { Q_OBJECT public: KRotationSetup(QWidget* parent = NULL); ~KRotationSetup(); public slots: /// slot for the OK Button: save settings and exit void okButtonClickedSlot(void); /// slot for the About Button: show the About dialog void aboutButtonClickedSlot(void); void randomTracesToggled(bool state); void xTraceToggled(bool state); void yTraceToggled(bool state); void zTraceToggled(bool state); void lengthEnteredSlot(const QString& s); void LzEnteredSlot(const QString& s); void thetaEnteredSlot(const QString& s); private: /// the screen saver widget which is displayed in the preview area KRotationSaver* m_saver; RotationWidget *cfg; }; #endif