/*******************************************************************************
;*******************************************************************************
;**                                                                           **
;**                  COPYRIGHT 2001-2012 NUANCE COMMUNICATIONS                **
;**                                                                           **
;**               NUANCE COMMUNICATIONS PROPRIETARY INFORMATION               **
;**                                                                           **
;**     This software is supplied under the terms of a license agreement      **
;**     or non-disclosure agreement with Nuance Communications and may not    **
;**     be copied or disclosed except in accordance with the terms of that    **
;**     agreement.                                                            **
;**                                                                           **
;*******************************************************************************
;**                                                                           **
;**     FileName: et9ageometry.h                                              **
;**                                                                           **
;**  Description: Point and vector utilities.                                 **
;**                                                                           **
;*******************************************************************************
;******************************************************************************/

#ifndef Geometry_H
#define Geometry_H

#include "et9abuildconfig.h"

#include "et9aswapitypes.h"
#include "et9auidefaults.h"

/*/ Maximum number of points in a polygon */
#define     MAX_POLYGON_POINTS      (8)

/*MCI the following funky names courtesy of too many definitions */
/* utility macros */
#define absGeo(x)       ((x) >= 0  ? (x) : -(x))

#define NORM_VECTOR_LEN 115     /* Normalize vector length to 115 (~360/pi) so that */
                                /* distance between ends of vectors is approximately */
                                /* twice the difference in slope in degrees */
#define RIGHT_ANGLE_VECTOR_SLOPE_DIF    162 /* Hypotenuse of right triangle with sides legth 115 */
#define W_DISTANCE8_MAX         0xFFFF      /* Maximum unsigned weighted distance (BYTE2 value) */
#define DISTANCE8_MAX           0xFFFF      /* Maximum unsigned BYTE2 value */
#define DISTANCE128_MAX         0xFFFF      /* Maximum unsigned BYTE2 value */

/* This exponent, and it's associated values, are used to improve precision of distance calculations. */
#define PRECISION_ADJ_EXP       11                          /* exponent used for precision adjustment */
#define PRECISION_ADJ_VAL       2048        /* 2^<EXP>, pre-calculated for performance */
#define PRECISION_ADJ_S_MULT_F  0.11303     /* some crazy multiplier for the distance formula */
#define PRECISION_ADJ_L_MULT_F  0.52865     /* some crazy multiplier for the distance formula */
#define PRECISION_ADJ_S_MULT    231         /* (0.11303 * 2^<EXP>), pre-calculated for performance */
#define PRECISION_ADJ_L_MULT    1083        /* (0.52865 * 2^<EXP>), pre-calculated for performance */

/* These are the old values for distance calculations, changed due to overflowing a 32-bit BYTE4. */
/*#define PRECISION_ADJ_EXP       12          // exponent used for precision adjustment, 2^<EXP>=<VAL> */
/*#define PRECISION_ADJ_VAL       4096        // integer value for precision adjustment, 2^<EXP>=<VAL> */
/*#define PRECISION_ADJ_S_MULT    463         // (0.11303 * 2^<EXP>) */
/*#define PRECISION_ADJ_L_MULT    2165        // (0.52865 * 2^<EXP>) */

/* Define return values for intersectionPoint() method */
#define NON_INTERSECTING        0
#define CHECK_P1                1
#define CHECK_P2                2
#define CHECK_P3                3
#define CHECK_P4                4
#define INTERSECTING            5
#define PARALLEL                6

/*================================================================== */
/*  SWPoint Class Definition */
/*================================================================== */

struct _SWPoint_s {

    SBYTE2 x, y;
};

/*================================================================== */
/*  _SWVector Class Definition */
/*================================================================== */

struct _SWVector_s {

    _SWPoint sPoint;

    SBYTE2   length;
    BYTE1    octant;            /* slope octant of vector */
};

    /* Constructors */
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_Z(_SWPoint *pThis)                                { pThis->x=pThis->y=0; }
    /* Point */
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_SB1SB1(_SWPoint *pThis, SBYTE1 a, SBYTE1 b)       { pThis->x = (SBYTE2)a; pThis->y = (SBYTE2)b; }
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_B1B1(_SWPoint *pThis, BYTE1 a, BYTE1 b)           { pThis->x = (SBYTE2)a; pThis->y = (SBYTE2)b; }
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_SB2SB2(_SWPoint *pThis, SBYTE2 a, SBYTE2 b)       { pThis->x = a; pThis->y = b; }
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_B2B2(_SWPoint *pThis, BYTE2 a, BYTE2 b)           { pThis->x = (SBYTE2)a; pThis->y = (SBYTE2)b; }
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_SB4SB4(_SWPoint *pThis, SBYTE4 a, SBYTE4 b)       { pThis->x = (SBYTE2)a; pThis->y = (SBYTE2)b; }
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_B4B4(_SWPoint *pThis, BYTE4 a, BYTE4 b)           { pThis->x = (SBYTE2)a; pThis->y = (SBYTE2)b; }
    ET9PRIVATE void ET9FARCALL _SWPoint_Construct_PP(_SWPoint *pThis, _SWPoint *a, _SWPoint *b)     { pThis->x = (SBYTE2)(b->x - a->x); pThis->y = (SBYTE2)(b->y - a->y); }

    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Construct_SSB1SB1(SBYTE1 x, SBYTE1 y)                   { _SWPoint result; _SWPoint_Construct_SB1SB1(&result, x, y); return result; }
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Construct_SSB2SB2(SBYTE2 x, SBYTE2 y)                   { _SWPoint result; _SWPoint_Construct_SB2SB2(&result, x, y); return result; }

    /* Comparison */
    ET9PRIVATE ET9BOOL ET9FARCALL _SWPoint_Equals(const _SWPoint *pThis, const _SWPoint *p1) { return (ET9BOOL)(pThis->x == p1->x && pThis->y == p1->y); }
    ET9PRIVATE ET9BOOL ET9FARCALL _SWPoint_NotEquals(const _SWPoint *pThis, const _SWPoint *p1) { return (ET9BOOL)(pThis->x != p1->x || pThis->y != p1->y); }

    /*================================================================== */
    /* SWPoint Class Methods */
    /*================================================================== */

    /* Addition */
    ET9PRIVATE _SWPoint * ET9FARCALL _SWPoint_AddAssign(_SWPoint *pThis, const _SWPoint *);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Add_P(const _SWPoint *, const _SWPoint *);
    /* Subtraction */
    ET9PRIVATE _SWPoint * ET9FARCALL _SWPoint_SubAssign(_SWPoint *pThis, const _SWPoint *);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Sub_P(const _SWPoint *pThis, const _SWPoint *);
    /* Multiplication */
    ET9PRIVATE _SWPoint * ET9FARCALL _SWPoint_MultAssign_SB2(_SWPoint *pThis, SBYTE2);
    ET9PRIVATE _SWPoint * ET9FARCALL _SWPoint_MultAssign_D(_SWPoint *pThis, double);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Mult_SB2P(SBYTE2, const _SWPoint *);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Mult_DP(double, const _SWPoint *);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Mult_SB2(const _SWPoint *, SBYTE2);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Mult_D(const _SWPoint *, double);
    /* Division */
    ET9PRIVATE _SWPoint * ET9FARCALL _SWPoint_DivAssign(_SWPoint *pThis, SBYTE2);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Div_SB2(const _SWPoint *, SBYTE2);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Div_D(const _SWPoint *, double);
    /* Vector difference of _SWPoint's */
    ET9PRIVATE _SWVector ET9FARCALL _SWPoint_VSub_P(const _SWPoint *pThis, const _SWPoint *);
    /* Translation by a vector */
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Add_V(const _SWPoint *pThis, const _SWVector *);
    ET9PRIVATE _SWPoint ET9FARCALL _SWPoint_Sub_V(const _SWPoint *pThis, const _SWVector *);
    ET9PRIVATE _SWPoint * ET9FARCALL _SWPoint_AddAssign_V(_SWPoint *pThis, const _SWVector *);
    ET9PRIVATE _SWPoint * ET9FARCALL _SWPoint_SubAssign_V(_SWPoint *pThis, const _SWVector *);

    /* Distance between Points */
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_distance(const _SWPoint *pThis, const _SWPoint *);             /* Approx Integer Distance */
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_roughDistance(const _SWPoint *pThis, const _SWPoint *);        /* Euclidean distance rough approximation */
    ET9PRIVATE BYTE4 ET9FARCALL _SWPoint_preciseDistance(const _SWPoint *pThis, const _SWPoint *);      /* Integer + 12-bit Fractional Distance * 4096 */
    ET9PRIVATE BYTE4 ET9FARCALL _SWPoint_preciseDistance_PP(_SWPoint a, _SWPoint b)                     { return _SWPoint_preciseDistance(&a, &b); }
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_distance8(const _SWPoint *pThis, const _SWPoint *P);           /* Distance * 8 for scoring */
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_distance128(const _SWPoint *pThis, const _SWPoint *P);         /* Distance * 128 for data validation metric */
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_distance2y8(const _SWScreenGeometry *pScreenGeometry, const _SWPoint *pThis, const _SWPoint *P );          /* Distance * 8 with Y component doubled for scoring */
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_distanceHalfx2y8(const _SWScreenGeometry *pScreenGeometry, const _SWPoint *pThis, const _SWPoint *P);      /* Distance * 8 with X component halved and Y component doubled for scoring */
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_distanceHalfx8(const _SWPoint *pThis, const _SWPoint *P);      /* Distance * 8 with X component halved for scoring */
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_secondDif(const _SWPoint *pThis, const _SWPoint *prev, const _SWPoint *follow);
    ET9PRIVATE BYTE2 ET9FARCALL _SWPoint_distanceFromSL(BYTE4 S, BYTE4 L); /* Euclidean distance approximation from delta-X and delta-Y */

    ET9PRIVATE double ET9FARCALL distanceF(const _SWPoint *pThis, const _SWPoint *);            /* Approx float Distance */
    ET9PRIVATE SBYTE2 ET9FARCALL intersectionPoint(const _SWScreenGeometry *pScreenGeometry, _SWPoint *pThis, const _SWPoint *p1, const _SWPoint *p2, const _SWPoint *p3, const _SWPoint *p4);


    ET9PRIVATE void ET9FARCALL _SWVector_normalize(_SWVector *pThis);               /* save original length, convert Vector to length NORM_VECTOR_LEN */
    ET9PRIVATE void ET9FARCALL _SWVector_calcOctant(_SWVector *pThis);              /* generate octant value */

    /* Constructors same as Point class */
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_Z(_SWVector *pThis)                            { _SWPoint_Construct_Z(&pThis->sPoint); pThis->length = 0; pThis->octant = 0; }
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_SB1SB1(_SWVector *pThis, SBYTE1 a, SBYTE1 b)   { _SWPoint_Construct_SB1SB1(&pThis->sPoint, a, b); _SWVector_calcOctant(pThis); _SWVector_normalize(pThis); }
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_B1B1(_SWVector *pThis, BYTE1 a, BYTE1 b)       { _SWPoint_Construct_B1B1(&pThis->sPoint, a, b); _SWVector_calcOctant(pThis); _SWVector_normalize(pThis); }
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_SB2SB2(_SWVector *pThis, SBYTE2 a, SBYTE2 b)   { _SWPoint_Construct_SB2SB2(&pThis->sPoint, a, b); _SWVector_calcOctant(pThis); _SWVector_normalize(pThis); }
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_B2B2(_SWVector *pThis, BYTE2 a, BYTE2 b)       { _SWPoint_Construct_B2B2(&pThis->sPoint, a, b); _SWVector_calcOctant(pThis); _SWVector_normalize(pThis); }
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_SB4SB4(_SWVector *pThis, SBYTE4 a, SBYTE4 b)   { _SWPoint_Construct_SB4SB4(&pThis->sPoint, a, b); _SWVector_calcOctant(pThis); _SWVector_normalize(pThis); }
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_PP(_SWVector *pThis, const _SWPoint *a, const _SWPoint *b)
    { _SWPoint_Construct_SB2SB2(&pThis->sPoint, (SBYTE2)(b->x - a->x), (SBYTE2)(b->y - a->y)); _SWVector_calcOctant(pThis); _SWVector_normalize(pThis); }
    ET9PRIVATE void ET9FARCALL _SWVector_Construct_PPC( _SWVector *pThis, const _SWPoint *a, const _SWPoint *b, const ET9BOOL calcNorm)
    {
        _SWPoint_Construct_SB2SB2(&pThis->sPoint, (SBYTE2)(b->x - a->x), (SBYTE2)(b->y - a->y));
        _SWVector_calcOctant(pThis);
        if (calcNorm)
            _SWVector_normalize(pThis);
    }

    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Construct_SSB1SB1(SBYTE1 a, SBYTE1 b)               { _SWVector result; _SWVector_Construct_SB1SB1(&result, a, b); return result; }
    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Construct_SPP(const _SWPoint *a, const _SWPoint *b) { _SWVector result; _SWVector_Construct_PP(&result, a, b); return result; }

    /* Unary minus */
    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Inverse(const _SWVector *pThis);

    /* Multiplication */
    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Mult_SB2V(SBYTE2, const _SWVector *);
    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Mult_DV(double, const _SWVector *);
    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Mult_SB2(const _SWVector *, SBYTE2);
    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Mult_D(const _SWVector *, double);
    /* Division */
    _SWVector ET9FARCALL _SWVector_Div_SB2(const _SWVector *, SBYTE2);
    ET9PRIVATE _SWVector ET9FARCALL _SWVector_Div_D(const _SWVector *, double);
    ET9PRIVATE _SWVector * ET9FARCALL _SWVector_DivAssign(_SWVector *pThis, double);      /* _SWVector scalar div */

    /* _SWVector Properties */
    ET9PRIVATE BYTE2   ET9FARCALL _SWVector_Distance(const _SWVector *pThis, const _SWVector *);            /* return absolute separation distance between vectors */
    ET9PRIVATE BYTE2   ET9FARCALL _SWVector_similarSlope(const _SWVector *pThis, const _SWVector *);        /* return separation distance between vectors */
    ET9PRIVATE ET9BOOL ET9FARCALL _SWVector_similarSlope_B2(const _SWVector *pThis, const _SWVector *, BYTE2);
    ET9PRIVATE SBYTE2  ET9FARCALL _SWVector_slopeDifference(const _SWVector *pThis, const _SWVector *);
    ET9PRIVATE SBYTE2  ET9FARCALL _SWVector_signedSlopeDifference(const _SWVector *pThis, const _SWVector *);
    ET9PRIVATE SBYTE2  ET9FARCALL _SWVector_verticalSlopeDifference(const _SWVector *pThis);

    ET9PRIVATE BYTE2   ET9FARCALL _SWVector_oppositeSlope(const _SWVector *pThis, const _SWVector *);     /* return separation distance between vectors */

#endif /* Geometry_H */
