IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Précision de calculs trigo.


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Octobre 2004
    Messages
    616
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 616
    Par défaut Précision de calculs trigo.
    Bonsoir, je doit gérer une lasse caméra dans un projet en openGL . Je susi entrain de mettre au point plusieurs fonctions et l'une me pose problème. J'ai reprit le code d'un tutorial sur le web (qui semble très correct), le résultat escompté est là, mais au bout de quelques itératins des imprécisions apparaissent et les calculs sont faussé ( mes valeurs en X et Z finissent pas tendre vers zéro )

    Voila la fonction qui fait une rotation selon un angle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void Camera::RotationY(float Angle)
    {
    	// Set Angle in Rad.
    	Angle = static_cast<float>( (Angle/180)*M_PI );
     
    	m_Position.x = (m_Position.x - m_Focalisation->x)*cosf(Angle) - (m_Position.z - m_Focalisation->z)*sinf(Angle) + m_Focalisation->x  ;
    	//m_Position.y = 0 ;
    	m_Position.z = (m_Position.x - m_Focalisation->x)*sinf(Angle) + (m_Position.z - m_Focalisation->z)*cosf(Angle) + m_Focalisation->z ;
     
    }
    Je lui passe la valeur 10 par exemple, suffsament de fois pour faire un tour, puis2.... à chaque tour je constate que je me rapproche de mes axes ( X et Z diminue eet tendent vers zéro ). Au bout d'a peine 5 tour je suis deja tres proche de mes axes ....

    Je pense que cea vient soit de mon approximation de PI, soit des fonction cos et sin ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    #define M_PI     3.14159265358979323846
    cos et sin proviennent de math.h .... enfin <cmath> .

    edit : mes vecteurs de positions , focalisations sont des floats .

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Le problème est surtout dû au nombre de bits disponibles pour représenter une valeur en virgule flottante...

    Sur PC (32 bits), on peut généralement considérer que
    • Les float sont codés sur 32 bits dont :
      • 23 bits pour la mantisse
      • 8 bits pour l'exposant
      • 1 bit pour le signe
    • Les type double sont codés sur 64 bits dont :
      • 52 bits pour la mantisse
      • 11 bits pour l'exposant
      • 1 bit pour le signe

    Comme, en plus, il y a des problèmes pour représenter certaines valeurs sous forme binaire, tous les éléments sont présents pour arriver au résultat que tu rencontre...

    L'idéal est donc, en gros, de préférer l'utilisation d'un double - voir d'un long double si ton système le supporte - car la précision en est bien meilleure, et permet donc de limiter - à défaut de l'éviter- le problème
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Surtout on ne fait *jamais* ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	m_Position.x = (m_Position.x - m_Focalisation->x)*cosf(Angle) - (m_Position.z - m_Focalisation->z)*sinf(Angle) + m_Focalisation->x  ;
    	//m_Position.y = 0 ;
    	m_Position.z = (m_Position.x - m_Focalisation->x)*sinf(Angle) + (m_Position.z - m_Focalisation->z)*cosf(Angle) + m_Focalisation->z ;
    Sachant que l'utilisation de flottant induit obligatoirement une erreur, incrémenter "régulièrement" une variable par une valeur flottante augmente d'autant l'erreur en question...

    En général le code de la gestion des rotations est plutôt le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    class Camera
    {
          float angleX;
     
          inline void RotationX(float angle)
          {
                angle = (angle*M_PI/180.0f);
     
                angleX += angle;
     
                // histoire de pas avoir trop d'erreur après plusieurs tours
                while (angleX < -M_PI) angleX += M_2PI;
                while (angleX > M_PI) angleX -= M_2PI;
     
                // calcul position en *absolu* 
          }
    };

  4. #4
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Si les donnees sont en degres, accumuler les degres et ne faire la transformation en radian qu'a la fin (ca evite de cumuler l'erreur introduite par PI qui n'est pas representable exactement).

  5. #5
    Membre éclairé
    Inscrit en
    Octobre 2004
    Messages
    616
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 616
    Par défaut
    Merci pour vos réponses :

    Effectivement les double ou long double ne suffisent aps à résoudre le problème. Par contre j'ai du mal à comprendre vos deux derniers messages pour résoudre cela.

    @nicroman, je ne vois pas ce que signifie le "calcul en absolue"

    Si les donnees sont en degres, accumuler les degres et ne faire la transformation en radian qu'a la fin
    A la fin? Quelle fin?


    Pour le moment j'ai juste une fonction qui effectue une rotation d'un certain angle, je ne stock nul part cet angle dans ma classe rotation . Donc je ne vois pas trop le rapport de vos méthodes avec ma classe. Dois-je changer totalement de méthode? (J'ai suivit un tutorial trouvé sur le net)

    Ma classe caméra dont voici le code reprend très exactement la facons de faire du tuto :

    Camera.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    #include <Tools/Logger.hpp>
    #include <Engine/Math/Vector3D.hpp>
    #include <string>
     
    #include <windows.h>
    #include <gl/gl.h>
    #include <gl/glu.h>
     
    #define M_PI     3.14159265358979323846
     
    #ifndef CAMERA_HPP
    #define CAMERA_HPP
     
    	class Camera
    	{	
    		public:
    			// Position of the cam
    			Camera(Vector3D<float> Pos);
    			Camera(float x, float y, float z );
     
     
    		   ~Camera();
     
    		   void SetOrientation(Vector3D<float> Orientation);
     
    		   void SetPosition(Vector3D<float> Position);
     
    		   void SetFocalisation(Vector3D<float> * Focalisation);
     
    		   void Focalize();
     
    		   void Distance(float Dist);
     
    		   void DistanceOffset(float Dist);
     
    		   void RotationY(float Angle);
     
    		private :
    			// up
    			Vector3D<float> m_Orientation ;
    			// Focus
    			Vector3D<float> * m_Focalisation ;
     
    			Vector3D<float> m_Position ;
     
    			Vector3D<float> m_DefaultFocus ;
    	}; 
     
    #endif // CAMERA
    camera.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
     
    #include <Engine/Camera.hpp>
     
    // Vector as param for position
    Camera::Camera(Vector3D<float> Pos) : m_DefaultFocus(0.0, 0.0, 0.0 ), m_Orientation(0.0, 1.0, 0.0), m_Focalisation(&m_DefaultFocus) , m_Position( Pos.x, Pos.y, Pos.z )
    {
     
    }
     
    // Float's as param for position
    Camera::Camera(float x, float y, float z ) : m_DefaultFocus(0.0, 0.0, 0.0 ), m_Orientation(0.0, 1.0, 0.0), m_Focalisation(&m_DefaultFocus) , m_Position( x, y, z )
    {
     
    }
     
    Camera::~Camera()
    {
     
     
    }
     
    void Camera::SetPosition(Vector3D<float> Position)
    {
    	m_Position = Position ;
    }
     
    void Camera::SetOrientation(Vector3D<float> Orientation)
    {
    	m_Orientation = Orientation ;
    }
     
    void Camera::SetFocalisation(Vector3D<float> * Focalisation)
    {
    	m_Focalisation = Focalisation ;
    }
     
    // Set the camera in the openGL scene.
    void Camera::Focalize()
    {
    	gluLookAt( m_Position.x, m_Position.y , m_Position.z ,
    			   m_Focalisation->x, m_Focalisation->y, m_Focalisation->z,
    			   m_Orientation.x, m_Orientation.y, m_Orientation.z );	
    }
     
    // Move closer or away from the focalisation source.
    // Dist = distance from the source. ( >=0 )
    void Camera::Distance(float Dist)
    {
    	Vector3D<float> Temp = m_Position - *m_Focalisation ;
    	float Norm = Temp.Length() ;
     
    	m_Position.x = (Dist/Norm)*(m_Position.x - m_Focalisation->x) + m_Focalisation->x ;
    	m_Position.y = (Dist/Norm)*(m_Position.y - m_Focalisation->y) + m_Focalisation->y ;
    	m_Position.z = (Dist/Norm)*(m_Position.z - m_Focalisation->z) + m_Focalisation->z ;
    }
     
    // Move closer or away from the focalisation source.
    // Dist = distance from the actual position of camera
    void Camera::DistanceOffset( float Dist)
    {
    	Vector3D<float> Temp = m_Position - *m_Focalisation ;
    	float Norm = Temp.Length() ;
     
    	// Dont go behind the focus !
    	if ( Norm + Dist >= 0.0 )
    	{
    		m_Position.x = (Dist/Norm)*(m_Position.x - m_Focalisation->x) + m_Position.x ;
    		m_Position.y = (Dist/Norm)*(m_Position.y - m_Focalisation->y) + m_Position.y ;
    		m_Position.z = (Dist/Norm)*(m_Position.z - m_Focalisation->z) + m_Position.z ;
    	}
     
    }
     
    // Rotation on the y axis
    // Angle is in degree
    void Camera::RotationY(float Angle)
    {
    	// Set Angle in Rad.
    	Angle = static_cast<float>( (Angle/180)*M_PI );
     
    	m_Position.x = (m_Position.x - m_Focalisation->x)*cosf(Angle) - (m_Position.z - m_Focalisation->z)*sinf(Angle) + m_Focalisation->x  ;
    	//m_Position.y = 0 ;
    	m_Position.z = (m_Position.x - m_Focalisation->x)*sinf(Angle) + (m_Position.z - m_Focalisation->z)*cosf(Angle) + m_Focalisation->z ;
     
    }

  6. #6
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Clad3 Voir le message
    Dois-je changer totalement de méthode?
    - Plutôt que de stocker un objet et de le transformer, tu stockes un objet et une transformation. Quand tu en as besoin, tu appliques la transformation. Ça évite une source d'accumulation d'erreurs.

    - Utilise pour la transformation les unités utilisateurs (degré pour les angles apparemment). Ça évite une autre source d'accumulation d'erreurs.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] Améliorer la précision des fonctions trigo
    Par candrau dans le forum MATLAB
    Réponses: 3
    Dernier message: 12/01/2012, 10h10
  2. scipy.poly1d : précision du calcul des racines
    Par ryced dans le forum Calcul scientifique
    Réponses: 5
    Dernier message: 25/01/2010, 10h04
  3. précision de calcul de fsolve
    Par Nabuchodonosor15 dans le forum MATLAB
    Réponses: 3
    Dernier message: 22/07/2009, 13h34
  4. Choisir la précision pour calculs en nombres flottants
    Par ciol2.6.12 dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 02/06/2008, 14h14
  5. Précision de calcul
    Par Mucho dans le forum Général Java
    Réponses: 10
    Dernier message: 21/02/2008, 14h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo