Fonctions mathématiques simples : Quelques petites fonctions utiles en 2D.

Un regroupement de petites fonctions utiles en 2D.

Racine carrée moins gourmande

---- Cette fonction est sous licence GPL

(je modifie légèrement l'interface)

namespace gpl
{
/**
\brief Racine carre
 
\param number : X
 
\return racine carre de X
*/
inline float sqrt(float number) {
    long i;
    float x, y;
    const float f = 1.5F;
 
    x = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;
    i  = 0x5f3759df - ( i >> 1 );
    y  = * ( float * ) &i;
    y  = y * ( f - ( x * y * y ) );
    y  = y * ( f - ( x * y * y ) ); // si on veut plus de précision
    return number * y;
}
} // namespace gpl

Un peu d'histoire : John Carmack

Distance entre deux points

/*!
* \brief Distance entre deux points.
* \author Hiura
* \details Cette fonction nécessite que la fonction sqrt soit définie. Il est possible de procéder ainsi :
* \code 
#include <cmath>
using std::sqrt; // on pourrait utilisez la fonction de Carmack en notant a la place : "using gpl::sqrt;"
* \endcode
* \param x1 : abcisse du premier point.
* \param y1 : ordonnée du premier point.
* \param x2 : abcisse du deuxième point, par défaut nul.
* \param y2 : ordonnée du deuxième point, par défaut nul.
* \return Distance entre (x1;y1) et (x2;y2).
*/
inline float Distance(const float x1, const float y1, const float x2 = 0.f, const float y2 = 0.f)
{
    // Formule de calcul de la distance entre deux points :
    // sqrt( (x1 - x2)² + (y1 - y2)² )
 
    return sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
}
 
/*!
* \brief Distance entre deux points.
* \author Hiura
* \param p1 : Premier point.
* \param p2 : Deuxième point, par défaut nul.
* \return Distance entre p1 et p2.
*/
inline float Distance(const sf::Vector2f& p1, const sf::Vector2f& p2 = sf::Vector2f(0.f, 0.f))
{
    // Utilisation de l'autre fonction Distance.
    return Distance(p1.x, p1.y, p2.x, p2.y);
}

Degrés en Radians et inversement, en C et Cpp

En C :

#define pi 3.141592f
#define ToRad(X) ( pi*(X)/180.f )        // Convertir des degrés en radian
#define ToDeg(X) ( 180.f*(X)/pi )        // Convertir des radians en degrés
#define Carre(X) ((X)*(X))                   // au carré

Valeur absolue : Il existe abs ( dinkumware.com : abs ) de <math> en C. Néanmoins, une fonction performante serait :

/*!
* \author hiura
*/
 
float abs(const float f)
{
    if (f < 0)
        return -f;
    else
        return f;
    // Impossible d'arriver ici.
}

En C++, on préfère :

const float pi = 3.14159f; // valeur approximative de pi.
template <typename T>
inline T ToRad(const T f) // retourne la valeur de f en radian.
{
    return (f * pi) / 180.;
}
 
template <typename T>
inline T ToDeg(const T f) // retourne la valeur de f en degré.
{
    return (f * 180.) / pi;
}
 
// Pour le carré, il existe std::pow de <cmath>. Voir note #1.
// Mais "pow( x , 2)" s'avère plus gourmant qu'un "( x * x )", donc :
 
template <typename T>
inline T Carre(const T f) // retourne la valeur au carre.
{
    return ( f * f);
}
 
// Pour la valeur absolue, il existe std::abs de <cmath>. Voir note #2.

Note #1 : dinkumware.com : pow
Note #2 : dinkumware.com : abs

Exemple :

/*!
* \author hiura
*/
 
float d = 180.f;
float r = ToRad(d);
// Vérifions l'égalité :
if (ToDeg(r) == d)
    // Vrai!
else
    // Les fonctions ne fonctionnent pas! (ou erreur d'arrondi)

Translation

/**
\brief Translation d'un point selon un axe
 
\param distance : Longueur de la translation
\param angle : Angle de l'axe en degrés
\param p : Point a translaté
 
\return Point translaté
*/
inline sf::Vector2f Translate(const float distance, const float angle, const sf::Vector2f& p = sf::Vector2f(0.f, 0.f))
{
    // X -1 en y car le repère est inversé dans SFML
    return sf::Vector2f(p.x + distance * std::cos(ToRad(angle)), p.y - distance * std::sin(ToRad(angle)));
}

Il est aussi possible d'utiliser un vecteur de translation sur un point :

/*!
* \brief Translation d'un point par un vecteur directeur.
* \author hiura
* \param p : point à translater.
* \param v : vecteur de translation.
* \return nouveau point.
*/
inline sf::Vector2f Translate(const sf::Vector2f& p, const sf::Vector2f& v)
{
    return sf::Vector2f(p.x + v.x, p.y + v.y);
}

Angle entre deux vecteurs / droites

Calculer l'angle 'c' entre deux droites / vecteurs en mathématique est très facile. Par exemple si on a deux vecteurs ( 'a' et 'b' ), on sait que :

Par conséquent, on a sait que l'angle vaut :

On peut donc élaborer une fonction en Cpp facilement.

/*!
* \brief Calcul l'angle entre deux vecteurs / droites
* \author hiura
* \details Cette fonction a besoin d'une fonction sqrt, acos et carre.
* \param a : premier vecteur.
* \param b : deuxième vecteur, par défaut représente l'abcisse.
* \return l'angle entre a et b.
*/
float Angle(const sf::Vector2f& a, const sf::Vector2f& b = sf::Vector2f(1.f, 0.f))
{
    // Calcul de a · b .
    const float nominateur = a.x * b.x + a.y * b.y;
    // Calcul de ||a|| ||b|| .
    const float denominateur = sqrt( carre(a.x) + carre(a.y) ) * sqrt( carre(b.x) + carre(b.y) );
    if (denominateur == 0.f){ // évite une division par 0
        return 0.f; // les deux vecteurs sont nuls, l'angle est indéfini
    }
    // Retour de l'angle.
    return acos( nominateur / denominateur );
}

A noter que cette fonction serait très implémentée en tant que membre d'une classe Vecteur. A ce moment là, un seul argument serait nécessaire. Remplacer le calcul de ||v|| via une fonction membre 'Norme' serait aussi une bonne idée.

Angle formé par 2 points et Rotation

En donnant 1 point en paramètre : Angle de la droite passant par le point et l'origine avec l'axe des abcisses.

En donnant 2 points en paramètre : Angle de la droite passant par les 2 points et l'horizontale passant par le second point.

/**
\brief Angle (en degrés) de l'axe formé par 2 points
 
\param x1 : Abcisse du premier point
\param y1 : Ordonnée du premier point
\param x2 : Abcisse du second point
\param y2 : Ordonnée du second point
 
\return Angle de l'axe formé par 2 points
*/
inline float Angle(const float x1, const float y1, const float x2 = 0.f, const float y2 = 0.f)
{
    float x = x1 - x2;
    float y = y1 - y2;
 
    if (y == 0.f)
    {
        if (x >= 0.f)
            return 0.f;
        else
            return 180.f;
    }
 
    if (y >= 0.f)
    {
        return ( ToDeg( std::atan(y/x) ) + 270.f );
    }
    else
    {
        return ( ToDeg( std::atan(y/x) ) + 90.f );
    }
}
 
/**
\brief Angle (en degrés) de l'axe formé par 2 points
 
\param p1 Premier point
\param p2 Second point
 
\return Angle de l'axe formé par 2 points
*/
inline float Angle(const sf::Vector2f& p1, const sf::Vector2f& p2 = sf::Vector2f(0.f, 0.f))
{
    return Angle(p1.x, p1.y, p2.x, p2.y);
}
 
/**
\brief Rotation d'un point autour d'un autre
 
\param p : Point a rotationer
\param AddedAngle : Angle ajouté
\param center : Centre de rotation
 
\return Point rotationé
*/
inline sf::Vector2f Rotation(const sf::Vector2f& p, const float angle, const sf::Vector2f& center = sf::Vector2f(0.f, 0.f))
{
    float distance = Distance(p, center);
    return Translate(distance, angle, center);
}
 
/**
\brief Rotation d'un point autour d'un autre
 
\param p : Point a rotationer
\param AddedAngle : Angle ajouté
\param center : Centre de rotation
 
\return Point rotationé
*/
inline sf::Vector2f Rotate(const sf::Vector2f& p, const float AddedAngle, const sf::Vector2f& center = sf::Vector2f(0.f, 0.f))
{
    float angle = Angle(p, center);
    return Rotation(p, angle + AddedAngle, center);
}

Passage d'angle/longueur en coordonnées.

NOTE Ce code est sorti de son contexte et n'est pas compilable.




Il peut être utile de convertir un segment défini par un angle et une longueur, et partant d'une origine 0;0 en une valeur X;Y.

 
/**
 * Partie du code de Game Develop Player
 *    
 *  Par Florian "4ian" Rival
 *  
 */
 
#define PI 3.141592652653 //A remplacer par une constante
 
/*
 A l'origine, les variables X, Y, longueur, angle sont des membres d'une classe.
*/
 
 
////////////////////////////////////////////////////////////
/// Calcul de X et Y en fonction de l'angle et la longueur
////////////////////////////////////////////////////////////
void CalculXY()
{
    X = longueur * ( cos( angle * PI / 180 ) );
    Y = longueur * ( sin( angle * PI / 180 ) );
}
 
////////////////////////////////////////////////////////////
/// Calcul de l'angle et la longueur en fonction de X et Y
////////////////////////////////////////////////////////////
bool CalculAL()
{
    angle = atan2(Y,X);
    angle *= 180 / PI;
    longueur = sqrt( X*X + Y*Y );
}

Commentaires

Bien sûr, certaines fonctions peuvent être plus pratique en étant implantées différemments (en tant que fonctions membres etc.).

Pas mal d'autres fonctions du genre sont encore a écrire, alors si vous avez des idées n'hésitez pas!

 
fr/sources/fonctions_maths.txt · Last modified: 2008/06/08 10:34 by hiura
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki