/************************/
/* Routines de rotation */
/************************/

/* Fichier TRIGO.CPP */

#include "fctsys.h"
#include "trigo.h"




/************************************************************************/
bool DistanceTest( int seuil, int dx, int dy, int spot_cX, int spot_cY )
/************************************************************************/

/*
 *  Calcul de la distance du curseur souris a un segment de droite :
 *  ( piste, edge, contour module ..
 *  retourne:
 *      false si distance > seuil
 *      true  si distance <= seuil
 *  Variables utilisees ( doivent etre initialisees avant appel , et
 *  sont ramenees au repere centre sur l'origine du segment)
 *      dx, dy = coord de l'extremite segment.
 *      spot_cX,spot_cY = coord du curseur souris
 *  la recherche se fait selon 4 cas:
 *      segment horizontal
 *      segment vertical
 *      segment 45
 *      segment quelconque
 */
{
    int cXrot, cYrot,   /* coord du point (souris) dans le repere tourne */
        segX, segY;     /* coord extremite segment tj >= 0 */
    int pointX, pointY; /* coord point a tester dans repere modifie dans lequel
                         * segX et segY sont >=0 */

    segX = dx; segY = dy; pointX = spot_cX; pointY = spot_cY;

    /*Recalcul coord pour que le segment soit dans 1er quadrant (coord >= 0)*/
    if( segX < 0 )   /* mise en >0 par symetrie par rapport a l'axe Y */
    {
        segX = -segX; pointX = -pointX;
    }
    if( segY < 0 )   /* mise en > 0 par symetrie par rapport a l'axe X */
    {
        segY = -segY; pointY = -pointY;
    }


    if( segY == 0 ) /* piste Horizontale */
    {
        if( abs( pointY ) <= seuil )
        {
            if( (pointX >= 0) && (pointX <= segX) )
                return 1;
            /* Etude des extremites : cercle de rayon seuil */
            if( (pointX < 0) && (pointX >= -seuil) )
            {
                if( ( (pointX * pointX) + (pointY * pointY) ) <= (seuil * seuil) )
                    return true;
            }
            if( (pointX > segX) && ( pointX <= (segX + seuil) ) )
            {
                if( ( ( (pointX - segX) * (pointX - segX) ) + (pointY * pointY) ) <=
                   (seuil * seuil) )
                    return true;
            }
        }
    }
    else if( segX == 0 ) /* piste verticale */
    {
        if( abs( pointX ) <= seuil )
        {
            if( (pointY >= 0 ) && (pointY <= segY) )
                return true;
            if( (pointY < 0) && (pointY >= -seuil) )
            {
                if( ( (pointY * pointY) + (pointX * pointX) ) <= (seuil * seuil) )
                    return true;
            }
            if( (pointY > segY) && ( pointY <= (segY + seuil) ) )
            {
                if( ( ( (pointY - segY) * (pointY - segY) ) + (pointX * pointX) ) <=
                   (seuil * seuil) )
                    return true;
            }
        }
    }
    else if( segX == segY )    /* piste a 45 degre */
    {
        /* on fait tourner les axes de 45 degre. la souris a alors les
         *  coord : x1 = x*cos45 + y*sin45
         *      y1 = y*cos45 - x*sin45
         *  et le segment de piste est alors horizontal.
         *  recalcul des coord de la souris ( sin45 = cos45 = .707 = 7/10
         *  remarque : sin ou cos45 = .707, et lors du recalcul des coord
         *  dx45 et dy45, lec coeff .707 est neglige, dx et dy sont en fait .707 fois
         *  trop grands. (c.a.d trop petits)
         *  spot_cX,Y doit etre * par .707 * .707 = 0.5 */

        cXrot = (pointX + pointY) >> 1;
        cYrot = (pointY - pointX) >> 1;

        /* recalcul des coord de l'extremite du segment , qui sera vertical
         *  suite a l'orientation des axes sur l'ecran : dx45 = pointX (ou pointY)
         *  et est en fait 1,414 plus grand , et dy45 = 0 */

        // seuil doit etre * .707 pour tenir compte du coeff de reduction sur dx,dy
        seuil *= 7; seuil /= 10;
        if( abs( cYrot ) <= seuil ) /* ok sur axe vertical) */
        {
            if( (cXrot >= 0) && (cXrot <= segX) )
                return true;

            /* Etude des extremites : cercle de rayon seuil */
            if( (cXrot < 0) && (cXrot >= -seuil) )
            {
                if( ( (cXrot * cXrot) + (cYrot * cYrot) ) <= (seuil * seuil) )
                    return true;
            }
            if( (cXrot > segX) && ( cXrot <= (segX + seuil) ) )
            {
                if( ( ( (cXrot - segX) * (cXrot - segX) ) + (cYrot * cYrot) ) <= (seuil * seuil) )
                    return true;
            }
        }
    }
    else    /* orientation quelconque */
    {
        /* On fait un changement d'axe (rotation) de facon a ce que le segment
         * de piste soit horizontal dans le nouveau repere */
        int angle;

        angle = (int) ( atan2( (float) segY, (float) segX ) * 1800 / M_PI);
        cXrot = pointX; cYrot = pointY;

        RotatePoint( &cXrot, &cYrot, angle );   /* Rotation du point a tester */
        RotatePoint( &segX, &segY, angle );     /* Rotation du segment */

        /* la piste est Horizontale , par suite des modifs de coordonnes
         * et d'axe, donc segX = longueur du segment */

        if( abs( cYrot ) <= seuil ) /* ok sur axe vertical) */
        {
            if( (cXrot >= 0) && (cXrot <= segX) )
                return true;

            /* Etude des extremites : cercle de rayon seuil */
            if( (cXrot < 0) && (cXrot >= -seuil) )
            {
                if( ( (cXrot * cXrot) + (cYrot * cYrot) ) <= (seuil * seuil) )
                    return true;
            }
            if( (cXrot > segX) && ( cXrot <= (segX + seuil) ) )
            {
                if( ( ( (cXrot - segX) * (cXrot - segX) ) + (cYrot * cYrot) ) <= (seuil * seuil) )
                    return true;
            }
        }
    }
    return false;
}



/***********************************/
int ArcTangente( int dy, int dx )
/***********************************/

/* Retourne l'arc tangente en 0.1 degres du vecteur de coord dx, dy
 *  entre -1800 et 1800
 *  Analogue a atan2 ( mais plus rapide pour les calculs si
 *  l'angle est souvent 0, -1800, ou +- 900
 */
{
    double fangle;

    if( dy == 0 )
    {
        if( dx >= 0 )
            return 0;
        else
            return -1800;
    }

    if( dx == 0 )
    {
        if( dy >= 0 )
            return 900;
        else
            return -900;
    }

    if( dx == dy )
    {
        if( dx >= 0 )
            return 450;
        else
            return -1800 + 450;
    }

    if( dx == -dy )
    {
        if( dx >= 0 )
            return -450;
        else
            return 1800 - 450;
    }

    fangle = atan2( (double) dy, (double) dx ) / M_PI * 1800;
    return (int) round( fangle );
}


/*********************************************/
void RotatePoint( int* pX, int* pY, int angle )
/*********************************************/

/*
 *  Fonction surchargee!
 *  calcule les nouvelles coord du point de coord pX, pY,
 *  pour une rotation de centre 0, 0, et d'angle angle ( en 1/10 degre)
 */
{
    float fpx, fpy;
    int   tmp;

    while( angle < 0 )
        angle += 3600;

    while( angle >= 3600 )
        angle -= 3600;

    if( angle == 0 )
        return;

    /* Calcul des coord :
     *  coord:  xrot = y*sin + x*cos
     *          yrot = y*cos - x*sin
     */
    if( angle == 900 )          /* sin = 1, cos = 0 */
    {
        tmp = *pX;
        *pX = *pY;
        *pY = -tmp;
    }
    else if( angle == 1800 )    /* sin = 0, cos = -1 */
    {
        *pX = -*pX;
        *pY = -*pY;
    }
    else if( angle == 2700 )    /* sin = -1, cos = 0 */
    {
        tmp = *pX;
        *pX = -*pY;
        *pY = tmp;
    }
    else
    {
        fpx = (*pY * fsinus[angle])   + (*pX * fcosinus[angle]);
        fpy = (*pY * fcosinus[angle]) - (*pX * fsinus[angle]);

        *pX = (int) round( fpx ); 
        *pY = (int) round( fpy );
    }
}


/************************************************************/
void RotatePoint( int* pX, int* pY, int cx, int cy, int angle )
/*************************************************************/

/*
 *  Fonction surchargee!
 *  calcule les nouvelles coord du point de coord pX, pY,
 *  pour une rotation de centre cx, cy, et d'angle angle ( en 1/10 degre)
 */
{
    int ox, oy;

    ox = *pX - cx; 
    oy = *pY - cy;
    
    RotatePoint( &ox, &oy, angle );

    *pX = ox + cx;
    *pY = oy + cy;
}


/********************************************/
void RotatePoint( wxPoint* point, int angle )
/********************************************/

/*
 *  Fonction surchargee!
 *  calcule les nouvelles coord du point point,
 *  pour une rotation d'angle angle ( en 1/10 degre)
 */
{
    int ox, oy;

    ox = point->x; 
    oy = point->y;
    
    RotatePoint( &ox, &oy, angle );
    point->x = ox;
    point->y = oy;
}


/*****************************************************************/
void RotatePoint( wxPoint* point, const wxPoint& centre, int angle )
/*****************************************************************/

/*
 *  Fonction surchargee!
 *  calcule les nouvelles coord du point point,
 *  pour une rotation de centre centre, et d'angle angle ( en 1/10 degre)
 */
{
    int ox, oy;

    ox = point->x - centre.x; 
    oy = point->y - centre.y;
    
    RotatePoint( &ox, &oy, angle );
    point->x = ox + centre.x;
    point->y = oy + centre.y;
}



/*************************************************************************/
void RotatePoint( double* pX, double* pY, double cx, double cy, int angle )
/*************************************************************************/
{
    double ox, oy;

    ox = *pX - cx; 
    oy = *pY - cy;
    
    RotatePoint( &ox, &oy, angle );
    
    *pX = ox + cx;
    *pY = oy + cy;
}


/*************************************************/
void RotatePoint( double* pX, double* pY, int angle )
/*************************************************/

/* Calcul des coord :
 *      coord:  xrot = y*sin + x*cos
 *              yrot = y*cos - x*sin
 */
{
    double tmp;

    while( angle < 0 )
        angle += 3600;

    while( angle >= 3600 )
        angle -= 3600;

    if( angle == 0 )
        return;

    if( angle == 900 )          /* sin = 1, cos = 0 */
    {
        tmp = *pX;
        *pX = *pY;
        *pY = -tmp;
    }
    else if( angle == 1800 )    /* sin = 0, cos = -1 */
    {
        *pX = -*pX;
        *pY = -*pY;
    }
    else if( angle == 2700 )    /* sin = -1, cos = 0 */
    {
        tmp = *pX;
        *pX = -*pY;
        *pY = tmp;
    }
    else
    {
        double fpx = (*pY * fsinus[angle])   + (*pX * fcosinus[angle]);
        double fpy = (*pY * fcosinus[angle]) - (*pX * fsinus[angle]);
        
        *pX = fpx; 
        *pY = fpy;
    }
}