movable.h 11.2 KB
/**
 * \file movable.h
 *
 * \brief Definition eines Templates für bewegte Objekte
 *
 * Organisiert, verwaltet und steuert die Bewegung bewegter Objekte.
 *
 * \author Georg Steffers <georg@steffers.org> [gs]
 *
 * \date 19.12.2003
 *
 * \version 19.12.2003 [gs]: erste Implementation aus gra_app gezogen.
 * \version 21.12.2003 [gs]: Bug in rotate_im_axis(double, vertex, vertex)
 *                           gefixt. Dort wurden immer die Objektkoordinaten
 *                           auf den Weltursprung verschoben und nicht die
 *                           Vektorbasis wie es eigentlich sein sollte.
 */

/* 
 * Copyright (C)2003 Georg Steffers
 *
 * 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) any later version.
 * 
 * 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.
 * 
 * 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  02111-1307  USA
 */

#ifndef __movable_h__
#define __movable_h__

#include "vertex.h"
#include "../math/Mmn.h"

/**
 * \brief Ein Interface f&uuml;r bewegte Objekte
 *
 * alle Objektklassen, die auch Kind dieses komplett &ouml;ffentlichen
 * Interfaces sind lassen sich dadurch rotieren und bewegen, das man die
 * Rotations- und Bewegungsgeschwindigkeit bez&uuml;glich der lokalen,
 * bzw. der Weltkoordinaten angibt.
 * jeder Aufruf der Methode update aktualisiert dann die Positionen der
 * Vektoren dieses Objekts.
 */
class movable {
   protected:
      vertex vrp;    //!< \brief \<Punkt\> (view reference point) 
                     //! das Zentrum des Objekts
      vertex vfw_t;  //!< \<Punkt\> Spitze von \ref vfw
      vertex vup_t;  //!< \<Punkt\> Spitze von \ref vup
      vertex vri_t;  //!< \<Punkt\> Spitze von \ref vri
      vertex vfw;    //!< \brief \<Vektor\> (vektor forward) 
                     //! Objektkoordinatensystem z
      vertex vup;    //!< \brief \<Vektor\> (vektor up) 
                     //! Objektkoordinatensystem y
      vertex vri;    //!< \brief \<Vektor\> (vektor right) 
                     //! Objektkoordinatensystem x

      Mmn<double> t_mat; //!< Die aktuelle Transformationsmatrize
      
      //! \brief Geschwinidigkeiten
      //! relativ zu Weltkoordinaten
      double speed_x, speed_y, speed_z, rot_speed_x, rot_speed_y, rot_speed_z;
      //! \brief Geschwinidigkeiten
      //! relativ zu Objekt
      double speed_vfw, speed_vri, speed_vup, 
             rot_speed_vfw, rot_speed_vri, rot_speed_vup;


      time_t last_transform;     //!<\brief Zeitpunkt der letzten Transformation
                                 //!
                                 //! Damit l&auml;&szlig;t sich der genaue
                                 //! Zeitraum seit der letzten Transformation
                                 //! berechnen und in alle Transformations
                                 //! Berechnungen mit einf&uuml;gen, so das
                                 //! wir wirkliche Echtzeit bekommen.

      //! Speed-Falloffs pro Sekunde
      double speed_x_falloff, 
             speed_y_falloff, 
             speed_z_falloff, 
             rot_speed_x_falloff, 
             rot_speed_y_falloff, 
             rot_speed_z_falloff;
      double speed_vfw_falloff, 
             speed_vri_falloff, 
             speed_vup_falloff, 
             rot_speed_vfw_falloff, 
             rot_speed_vri_falloff, 
             rot_speed_vup_falloff;

      //! \brief Konstruktor
      //!
      //! privater Kontruktor, da man von dem Interface
      //! keinen Eigenen Instanzen bilden k&ouml;nnen soll.
      movable() {
         vrp=vertex(0,0,0,1);
         vfw_t=vertex(0,0,1,1);
         vup_t=vertex(0,1,0,1);
         vri_t=vertex(1,0,0,1);
         vfw=vfw_t-vrp;
         vup=vup_t-vrp;
         vri=vri_t-vrp;
         t_mat=Mmn<double>(4);
      }

   public:
      virtual const Mmn<double>& get_t_mat(void) { return t_mat; }

      virtual void reset(void) {
         vrp.reset();
         vfw_t.reset();
         vup_t.reset();
         vri_t.reset();
         vfw=vfw_t-vrp;
         vup=vup_t-vrp;
         vri=vri_t-vrp;

         t_mat=Mmn<double>(4);
      }

      /** 
       * \param t_st Transformationsstufe
       */
      virtual void transform(unsigned t_st) {
         vrp.transform(t_mat, t_st);
         vfw_t.transform(t_mat, t_st);
         vup_t.transform(t_mat, t_st);
         vri_t.transform(t_mat, t_st);
         vfw=vfw_t-vrp;
         vup=vup_t-vrp;
         vri=vri_t-vrp;
      }

      void print(void) {
         t_mat.print();
      }

      const vertex& get_vrp(void) { 
         return vrp; 
      }

      const vertex& get_vfw_t(void) { 
         return vfw_t; 
      }

      const vertex& get_vup_t(void) { 
         return vup_t; 
      }

      const vertex& get_vri_t(void) { 
         return vri_t; 
      }

      const vertex& get_vfw(void) { 
         return vfw; 
      }

      const vertex& get_vup(void) { 
         return vup; 
      }

      const vertex& get_vri(void) { 
         return vri; 
      }

      /**
       * \brief direkte Ver&auml;nderung der Position &uuml;ber eine
       *        vorberechnete Matrize.
       * \param trans_mat Eine komplette vorberechnete Transformationsmatrix
       */
      void move_im(const Mmn<double>& trans_mat) {
         t_mat=trans_mat%t_mat;
      }
      /**
       * \brief Verschiebung &uuml;ber (lokale) Objekkoordinaten
       * \param axe Achse entlang der verschoben wird
       * \param step wie weit verschoben wird
       */
      void translate_im_axe(vertex axe, double step) {
         axe=axe.norm()*step;
         t_mat=mat_translate(axe[X], axe[Y], axe[Z])%t_mat;
      }
      /**
       * \brief Verschiebung &uuml;ber (globale) Weltkoordinaten
       * \param x Verschiebung in VRI 
       * \param y Verschiebung in VUP 
       * \param z Verschiebung in VFW 
       */
      void translate_im_global(double x, double y, double z) {
         t_mat=mat_translate(x, y, z)%t_mat;
      }
      /**
       * \brief Drehung &uuml;ber (lokale) Objekkoordinaten vfw
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_vfw(double angle) {
         vfw_t.transform(t_mat, 1);
         vrp.transform(t_mat, 1);

         rotate_im_axis(angle, vfw_t, vrp);

         vfw_t.reset();
         vrp.reset();
      }
      /**
       * \brief Drehung &uuml;ber (lokale) Objekkoordinaten vup
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_vup(double angle) {
         vup_t.transform(t_mat, 1);
         vrp.transform(t_mat, 1);

         rotate_im_axis(angle, vup_t, vrp);

         vup_t.reset();
         vrp.reset();
      }
      /**
       * \brief Drehung &uuml;ber (lokale) Objekkoordinaten vri
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_vri(double angle) {
         vri_t.transform(t_mat, 1);
         vrp.transform(t_mat, 1);

         rotate_im_axis(angle, vri_t, vrp);

         vri_t.reset();
         vrp.reset();
      }
      /**
       * \brief Drehung um X-Achse im Weltkoordinaten-Zentrum
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_g_x(double angle) {
         t_mat=mat_rot_x(angle)%t_mat;
      }
      /**
       * \brief Drehung um Y-Achse im Weltkoordinaten-Zentrum
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_g_y(double angle) {
         t_mat=mat_rot_y(angle)%t_mat;
      }
      /**
       * \brief Drehung um Z-Achse im Weltkoordinaten-Zentrum
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_g_z(double angle) {
         t_mat=mat_rot_z(angle)%t_mat;
      }
      /**
       * \brief Drehung um X-Achse im Objektkoordinaten-Zentrum
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_l_x(double angle) {
         Mmn<double> mat_center(4);
         Mmn<double> mat_reset(4);

         mat_center.a(0,3)=-t_mat.a(0,3);
         mat_center.a(1,3)=-t_mat.a(1,3);
         mat_center.a(2,3)=-t_mat.a(2,3);

         mat_reset.a(0,3)=t_mat.a(0,3);
         mat_reset.a(1,3)=t_mat.a(1,3);
         mat_reset.a(2,3)=t_mat.a(2,3);

         t_mat=mat_reset%mat_rot_x(angle)%mat_center%t_mat;
      }
      /**
       * \brief Drehung um Y-Achse im Objektkoordinaten-Zentrum
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_l_y(double angle) {
         Mmn<double> mat_center(4);
         Mmn<double> mat_reset(4);

         mat_center.a(0,3)=-t_mat.a(0,3);
         mat_center.a(1,3)=-t_mat.a(1,3);
         mat_center.a(2,3)=-t_mat.a(2,3);

         mat_reset.a(0,3)=t_mat.a(0,3);
         mat_reset.a(1,3)=t_mat.a(1,3);
         mat_reset.a(2,3)=t_mat.a(2,3);

         t_mat=mat_reset%mat_rot_y(angle)%mat_center%t_mat;
      }
      /**
       * \brief Drehung um Z-Achse im Objektkoordinaten-Zentrum
       * \param angle Wieviel Grad soll gedreht werden
       */
      void rotate_im_l_z(double angle) {
         Mmn<double> mat_center(4);
         Mmn<double> mat_reset(4);

         mat_center.a(0,3)=-t_mat.a(0,3);
         mat_center.a(1,3)=-t_mat.a(1,3);
         mat_center.a(2,3)=-t_mat.a(2,3);

         mat_reset.a(0,3)=t_mat.a(0,3);
         mat_reset.a(1,3)=t_mat.a(1,3);
         mat_reset.a(2,3)=t_mat.a(2,3);

         t_mat=mat_reset%mat_rot_z(angle)%mat_center%t_mat;
      }
      /**
       * \brief Drehung um eine beliebige Achse
       * \param angle Wieviel Grad soll gedreht werden
       * \param axe Die Achse um die gedreht werden soll als 
       *        Ursprungsvektor (also einer der in WC(0,0,0) beginnt)
       */
      void rotate_im_axis(double angle, const vertex& axe) {
         t_mat=mat_rot_axe(angle, axe.get_t())%t_mat;
      }

      /**
       * \brief Drehung um Z-Achse im Objektkoordinaten-Zentrum
       * \param angle Wieviel Grad soll gedreht werden
       * \param tip Vertexspitze der Rotationsachse
       * \param base Vertexbasis der Rotationsachse
       */
      void rotate_im_axis(double angle, vertex tip, vertex base) {
         Mmn<double> mat_center(4);
         Mmn<double> mat_reset(4);

         mat_center.a(0,3)=-base[X];
         mat_center.a(1,3)=-base[Y];
         mat_center.a(2,3)=-base[Z];

         mat_reset.a(0,3)=base[X];
         mat_reset.a(1,3)=base[Y];
         mat_reset.a(2,3)=base[Z];

//         if(angle==0 || angle==180) {
//            cout << "------------------------------\n";
//            cout << "Winkel: " << angle << "Grad\n";
//            t_mat.print();
//         }
         t_mat=mat_reset%mat_rot_axe(angle, (tip-base).get_t())%mat_center%t_mat;
//         if(angle==0 || angle==180) {
//            t_mat.print();
//            cout << "------------------------------\n";
//         }
      }
      // sowohl für translatio, als auch für Rotation sollte ich denke
      // ich eigene Methoden für jede Richtung schreiben.!!!
};

#endif // __movable_h__