/*
Program wxLine.CPP
Purpose Mainly used for calculating crossings
Last Update 05-12-1995
*/

#ifdef __GNUG__
#pragma implementation "liner.cpp"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include <math.h>

#include <stdlib.h>

#include "wx/canvas/liner.h"

wxLine::wxLine( double x1, double y1, double x2, double y2 )
{
    m_AA = 0.0;
    m_BB = 0.0;
    m_CC = 0.0;

    m_a=wxPoint2DDouble(x1,y1);
    m_b=wxPoint2DDouble(x2,y2);
    if (m_a==m_b)
        assert(0);

    m_valid_parameters = FALSE;
}

wxLine::~wxLine()
{
}

wxLine::wxLine(const wxPoint2DDouble& a,const wxPoint2DDouble& b)
{
    if (a==b)
        assert(0);

    m_a=a;
    m_b=b;
    m_valid_parameters = FALSE;
}



// ActionOnTable1
// This function decide which action must be taken, after PointInLine
// has given the results of two points in relation to a wxLine. See table 1 in the report
//
// input Result_beginPoint:
//          Result_endPoint :
//       The results can be R_R_LEFT_SIDE, R_R_RIGHT_SIDE, R_R_ON_AREA, R_R_IN_AREA
//
// return -1: Illegal combination
//         0: No action, no crosspoints
//         1: Investigate results points in relation to the other wxLine
//         2: endPoint is a crosspoint, no further investigation
//         3: beginPoint is a crosspoint, no further investigation
//            4: beginPoint and endPoint are crosspoints, no further investigation
//         5: beginPoint is a crosspoint, need further investigation
//         6: endPoint is a crosspoint, need further investigation
int wxLine::ActionOnTable1(R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint)
{
    // beginPoint and endPoint are crosspoints
    if (
         (Result_beginPoint == R_IN_AREA)
         &&
         (Result_endPoint == R_IN_AREA)
        )
        return 4;
   // there are no crosspoints, no action
    if (
         (
          (Result_beginPoint == R_LEFT_SIDE)
          &&
          (Result_endPoint == R_LEFT_SIDE)
         )
         ||
         (
          (Result_beginPoint == R_RIGHT_SIDE)
          &&
          (Result_endPoint == R_RIGHT_SIDE)
         )
        )
        return 0;
    // maybe there is a crosspoint, further investigation needed
    if (
         (
          (Result_beginPoint == R_LEFT_SIDE)
          &&
          (
            (Result_endPoint == R_RIGHT_SIDE)
            ||
            (Result_endPoint == R_ON_AREA)
          )
         )
         ||
         (
          (Result_beginPoint == R_RIGHT_SIDE)
          &&
          (
            (Result_endPoint == R_LEFT_SIDE)
            ||
            (Result_endPoint == R_ON_AREA)
          )
         )
         ||
         (
          (Result_beginPoint == R_ON_AREA)
          &&
          (
            (Result_endPoint == R_LEFT_SIDE)
            ||
            (Result_endPoint == R_RIGHT_SIDE)
            ||
            (Result_endPoint == R_ON_AREA)
          )
         )
        )
        return 1;
    //there is a crosspoint
    if (
         (
          (Result_beginPoint == R_LEFT_SIDE)
          ||
          (Result_beginPoint == R_RIGHT_SIDE)
         )
         &&
         (Result_endPoint == R_IN_AREA)
        )
        return 2;
    // there is a crosspoint
    if (
         (Result_beginPoint == R_IN_AREA)
         &&
         (
          (Result_endPoint == R_LEFT_SIDE)
          ||
          (Result_endPoint == R_RIGHT_SIDE)
         )
        )
        return 3;
    // beginPoint is a crosspoint, further investigation needed
    if (
         (Result_beginPoint == R_IN_AREA)
         &&
         (Result_endPoint == R_ON_AREA)
        )
        return 5;
    // endPoint is a crosspoint, further investigation needed
    if (
         (Result_beginPoint == R_ON_AREA)
         &&
         (Result_endPoint == R_IN_AREA)
        )
        return 6;
    // All other combinations are illegal
    return -1;
}


// ActionOnTable2
// This function decide which action must be taken, after PointInLine
// has given the results of two points in relation to a wxLine. It can only give a
// correct decision if first the relation of the points from the wxLine
// are investigated in relation to the wxLine wich can be constucted from the points.
//
// input Result_beginPoint:
//          Result_endPoint :
//       The results can be R_LEFT_SIDE, R_RIGHT_SIDE, R_ON_AREA, R_IN_AREA
//
// return -1: Illegal combination
//         0: No action, no crosspoints
//         1: Calculate crosspoint
//         2: endPoint is a crosspoint
//         3: beginPoint is a crosspoint
//         4: beginPoint and endPoint are crosspoints
int wxLine::ActionOnTable2(R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint)
{
    // beginPoint and eindpoint are crosspoints
    if (
         (Result_beginPoint == R_IN_AREA)
         &&
         (Result_endPoint == R_IN_AREA)
        )
        return 4;
    // there are no crosspoints
    if (
         (
          (Result_beginPoint == R_LEFT_SIDE)
          &&
          (
            (Result_endPoint == R_LEFT_SIDE)
            ||
            (Result_endPoint == R_ON_AREA)
          )
         )
         ||
         (
          (Result_beginPoint == R_RIGHT_SIDE)
          &&
          (
            (Result_endPoint == R_RIGHT_SIDE)
            ||
            (Result_endPoint == R_ON_AREA)
          )
         )
         ||
         (
          (Result_beginPoint == R_ON_AREA)
          &&
          (
            (Result_endPoint == R_LEFT_SIDE)
            ||
            (Result_endPoint == R_RIGHT_SIDE)
            ||
            (Result_endPoint == R_ON_AREA)
          )
         )
        )
        return 0;
    // there is a real intersection, which must be calculated
    if (
         (
          (Result_beginPoint == R_LEFT_SIDE)
          &&
          (Result_endPoint == R_RIGHT_SIDE)
         )
         ||
         (
          (Result_beginPoint == R_RIGHT_SIDE)
          &&
          (Result_endPoint == R_LEFT_SIDE)
         )
        )
        return 1;
    // endPoint is a crosspoint
    if (
         (
          (Result_beginPoint == R_LEFT_SIDE)
          ||
          (Result_beginPoint == R_RIGHT_SIDE)
          ||
          (Result_beginPoint == R_ON_AREA)
         )
         &&
         (Result_endPoint == R_IN_AREA)
        )
        return 2;
    // beginPoint is a crosspoint
    if (
         (Result_beginPoint == R_IN_AREA)
         &&
         (
          (Result_endPoint == R_LEFT_SIDE)
          ||
          (Result_endPoint == R_RIGHT_SIDE)
          ||
          (Result_endPoint == R_ON_AREA)
         )
        )
        return 3;
    // All other combinations are illegal
    return -1;
}

// Calculate the Y when the X is given
double wxLine::Calculate_Y(double X)
{
    CalculateLineParameters();
    if (m_AA != 0)
        return -(m_AA * X + m_CC) / m_BB;
    else
        // horizontal wxLine
        return m_a.m_y;
}

void wxLine::Virtual_Point(wxPoint2DDouble& a_point,double distance)  const
{
    assert(m_valid_parameters);

    //calculate the distance using the slope of the wxLine
   //and rotate 90 degrees

    a_point.m_y=a_point.m_y + (distance * -m_BB);
    a_point.m_x=a_point.m_x - (distance * m_AA );
}



//
// Calculate the lineparameters for the wxLine if nessecary
//
void wxLine::CalculateLineParameters()
{
    // if not valid_parameters calculate the parameters
    if (!m_valid_parameters)
    {
        double length;

        // bp AND ep may not be the same
        if (m_a == m_b)
            assert (0);

        m_AA = (m_b.m_y - m_a.m_y); // A = (Y2-Y1)
        m_BB = (m_a.m_x - m_b.m_x); // B = (X1-X2)

        // the parameters A end B can now be normalized
        length = sqrt(m_AA*m_AA + m_BB*m_BB);

        assert(length !=0);

        m_AA = (m_AA / length);
        m_BB = (m_BB / length);

        m_CC = -((m_AA * m_a.m_x) + (m_a.m_y * m_BB));

        m_valid_parameters = TRUE;
    }
}


// Checks if a wxLine intersect with another wxLine
// inout    wxLine : another wxLine
//          Marge: optional, standard on MARGE (declared in MISC.CPP)
//
// return   true : wxLines are crossing
//          false: wxLines are not crossing
//
bool wxLine::CheckIntersect (wxLine& lijn, double Marge)
{
    double distance=0;

   // bp AND ep may not be the same
   if (m_a == m_b)
      assert (0);

    int Take_Action1, Take_Action2;
    bool Total_Result=FALSE;
    R_PointStatus Result_beginPoint,Result_endPoint;

    Result_beginPoint = PointInLine(lijn.m_a,distance,Marge);
    Result_endPoint   = PointInLine(lijn.m_b,distance,Marge);
    Take_Action1 = ActionOnTable1(Result_beginPoint,Result_endPoint);
    switch (Take_Action1)
    {
        case 0: Total_Result = FALSE ; break;
        case 1: {
                        Result_beginPoint = lijn.PointInLine(m_a,distance,Marge);
                        Result_endPoint   = lijn.PointInLine(m_b,distance,Marge);
                        Take_Action2 = ActionOnTable2(Result_beginPoint,Result_endPoint);
                        switch (Take_Action2)
                        {
                            case 0: Total_Result = FALSE; break;
                            case 1: case 2: case 3: case 4: Total_Result = TRUE; break;
                        }
                  }; break; // This break belongs to the switch(Take_Action1)
        case 2: case 3: case 4: case 5: case 6: Total_Result = TRUE; break;
    }
    return Total_Result; //This is the final decision
}


//
// Get the beginPoint from the wxLine
// usage: Point aPoint = a_line.GetBeginPoint()
//
wxPoint2DDouble wxLine::GetBeginPoint()
{
  return m_a;
}


//
// Get the endPoint from the wxLine
// usage: Point aPoint = a_line.GetEndPoint()
//
wxPoint2DDouble wxLine::GetEndPoint()
{
    return m_b;
}

// Intersects two wxLines
// input    wxLine : another wxLine
//          Marge: optional, standard on MARGE
//
// return   0: If there are no crossings
//          1: If there is one crossing
//          2: If there are two crossings
int wxLine::Intersect(wxLine& lijn, wxPoint2DDouble& c1 ,wxPoint2DDouble& c2 , double Marge)
{
    double distance=0;

    // bp AND ep may not be the same
    if (m_a == m_b)
        assert (0);

    R_PointStatus Result_beginPoint,Result_endPoint;
    int Take_Action1, Take_Action2, Number_of_Crossings = 0;

    Result_beginPoint = PointInLine(lijn.m_a,distance,Marge);
    Result_endPoint   = PointInLine(lijn.m_b,distance,Marge);

    Take_Action1 = ActionOnTable1(Result_beginPoint,Result_endPoint);
// 0: No action, no crosspoints
// 1: Investigate results points in relation to the other wxLine
// 2: endPoint is a crosspoint, no further investigation
// 3: beginPoint is a crosspoint, no further investigation
// 4: beginPoint and endPoint are crosspoints, no further investigation
// 5: beginPoint is a crosspoint, need further investigation
// 6: endPoint is a crosspoint, need further investigation

    // The first switch will insert a crosspoint immediatly
    switch (Take_Action1)
    {
        case 2: case 6: c1=lijn.m_b;
                        Number_of_Crossings = 1;
                        break;
        case 3: case 5: c1=lijn.m_a;
                        Number_of_Crossings = 1;
                        break;
        case 4:         c1=lijn.m_a;
                        c2=lijn.m_b;
                        Number_of_Crossings = 2;
                        break;
        default:
                        break;
    }

    // This switch wil investigate the points of this wxLine in relation to lijn
    // 1: Investigate results points in relation to the other wxLine
    // 5: beginPoint is a crosspoint, need further investigation
    // 6: endPoint is a crosspoint, need further investigation
    switch (Take_Action1)
    {
        case 1: case 5: case 6:
        {
            Result_beginPoint = lijn.PointInLine(m_a,distance,Marge);
            Result_endPoint   = lijn.PointInLine(m_b,distance,Marge);
                Take_Action2 = ActionOnTable2(Result_beginPoint,Result_endPoint);
            // return -1: Illegal combination
            //         0: No action, no crosspoints
            //         1: Calculate crosspoint
            //         2: endPoint is a crosspoint
            //         3: beginPoint is a crosspoint
            //         4: beginPoint and endPoint are crosspoints
            switch (Take_Action2)
            {
                // for the cases see the returnvalue of ActionTable2
                case 1: {   // begin of scope to calculate the intersection
                            double X, Y, Denominator;
                            CalculateLineParameters();
                            Denominator  = (m_AA * lijn.m_BB) - (lijn.m_AA * m_BB);
                            // Denominator may not be 0
                            assert(Denominator != 0.0);
                            // Calculate intersection of both linesegments
                            X = ((m_BB * lijn.m_CC) - (lijn.m_BB * m_CC)) / Denominator;
                            Y = ((lijn.m_AA * m_CC) - (m_AA * lijn.m_CC)) / Denominator;

                            c1.m_x=X;
                            c1.m_y=Y;
                         }
                         Number_of_Crossings++;
                         break;
                case 2:  c2=m_a;
                         Number_of_Crossings++;
                         break;
                case 3:  c2=m_b;
                         Number_of_Crossings++;
                         break;
                case 4:  c1=m_a;
                         c2=m_b;
                         Number_of_Crossings = 2;
                         break;
            }
        };
        break;
        default:
             break;
    }
    return Number_of_Crossings; //This is de final number of crossings
}

//
// test if a point lies in the linesegment. If the point isn't on the wxLine
// the function returns a value that indicates on which side of the
// wxLine the point is (in linedirection from first point to second point
//
// returns R_LEFT_SIDE, when point lies on the left side of the wxLine
//         R_RIGHT_SIDE, when point lies on the right side of the wxLine
//         R_ON_AREA, when point lies on the infinite wxLine within a range
//         R_IN_AREA, when point lies in the area of the linesegment
//        the returnvalues are declared in (wxLine.H)
R_PointStatus wxLine::PointInLine(const wxPoint2DDouble& a_Point, double& Distance,double Marge)
{
    Distance=0;

    // Point may not be the same
    assert(m_a != m_b);

    int Result_ofm_BBox=FALSE;
    R_PointStatus Result_of_Online;

    //quick test if point is begin or endpoint
    if (a_Point == m_a || a_Point == m_b)
        return R_IN_AREA;

    // Checking if point is in bounding-box with marge
    double xmin=wxMin(m_a.m_x,m_b.m_x);
    double xmax=wxMax(m_a.m_x,m_b.m_x);
    double ymin=wxMin(m_a.m_y,m_b.m_y);
    double ymax=wxMax(m_a.m_y,m_b.m_y);

    if (  a_Point.m_x >= (xmin - Marge) && a_Point.m_x <= (xmax + Marge) &&
          a_Point.m_y >= (ymin - Marge) && a_Point.m_y <= (ymax + Marge) )
        Result_ofm_BBox=TRUE;

    // Checking if point is on the infinite wxLine
    Result_of_Online = PointOnLine(a_Point, Distance, Marge);

    // point in boundingbox of the wxLine and is on the wxLine then the point is R_IN_AREA
    if ((Result_ofm_BBox) && (Result_of_Online == R_ON_AREA))
        return R_IN_AREA;
    else
        return Result_of_Online;
}


//
// test if a point lies on the wxLine. If the point isn't on the wxLine
// the function returns a value that indicates on which side of the
// wxLine the point is (in linedirection from first point to second point
//
// returns R_LEFT_SIDE, when point lies on the left side of the wxLine
//         R_ON_AREA, when point lies on the infinite wxLine within a range
//         R_RIGHT_SIDE, when point lies on the right side of the wxLine
//        R_LEFT_SIDE , R_RIGHT_SIDE , R_ON_AREA
R_PointStatus wxLine::PointOnLine(const wxPoint2DDouble& a_Point, double& Distance, double Marge)
{
    Distance=0;
    // Point may not be queal
    assert(m_a!=m_b);

    //quick test if point is begin or endpoint
    if (a_Point == m_a || a_Point == m_b)
        return R_ON_AREA;

    CalculateLineParameters();
    // calculate the distance of a_Point in relation to the wxLine
    Distance = (m_AA * a_Point.m_x)+(m_BB * a_Point.m_y) + m_CC;

    if (Distance < -Marge)
        return R_LEFT_SIDE;
    else
    {
        if (Distance > Marge)
            return R_RIGHT_SIDE;
        else
            return R_ON_AREA;
    }
}

// makes a wxLine same as these
// usage : wxLine1 = wxLine2;
wxLine& wxLine::operator=(const wxLine& a_line)
{
    m_AA = a_line.m_AA;
    m_BB = a_line.m_BB;
    m_CC = a_line.m_CC;

    m_a= a_line.m_a;
    m_b= a_line.m_b;
    m_valid_parameters = a_line.m_valid_parameters;
    return *this;
}

void wxLine::OffsetContour(const wxLine& nextline,double factor,wxPoint2DDouble& offsetpoint)  const
{
    wxPoint2DDouble offs_begin(m_a);
    wxPoint2DDouble offs_end(m_b);

    wxPoint2DDouble offs_bgn_next(nextline.m_a);
    wxPoint2DDouble offs_end_next(nextline.m_b);
    // make a wxPoint2DDouble from this point

    Virtual_Point(offs_begin,factor);
    Virtual_Point(offs_end,factor);
    wxLine  offs_currentline(offs_begin,offs_end);

    nextline.Virtual_Point(offs_bgn_next,factor);
    nextline.Virtual_Point(offs_end_next,factor);
    wxLine  offs_nextline(offs_bgn_next, offs_end_next);

    offs_nextline.CalculateLineParameters();
    offs_currentline.CalculateLineParameters();
    offs_currentline.Intersect(offs_nextline,offsetpoint);
}

// Return the position of the second wxLine compared to this wxLine
// Result = IS_ON | IS_LEFT | IS_RIGHT
// Here Left and Right is defined as being left or right from
// the this wxLine towards the center (common) node
// direction of vetors taken as begin to endpoint with end of this at
// begin of wxLine two
OUTPRODUCT wxLine::OutProduct(const wxLine& two,double accur)
{
    R_PointStatus uitp;
    double distance;
    if (two.m_a==two.m_b)
        assert(0);
    if (m_a==m_b)
        assert(0);

    uitp=PointOnLine(two.m_b, distance, accur);


    /*double uitp=  (_x - first._x) * (third._y - _y) -
                    (_y - first._y) * (third._x - _x);
    if (uitp>0) return IS_LEFT;
    if (uitp<0) return IS_RIGHT;
    return IS_ON;*/

    //depending on direction of this link (going to or coming from centre)
    if (uitp==R_LEFT_SIDE)
        return R_IS_LEFT;
    if (uitp==R_RIGHT_SIDE)
        return R_IS_RIGHT;
    return R_IS_ON;
}

// Intersects two lines if a crossing return TRUE
// else FALSE
bool wxLine::Intersect(wxLine& lijn,wxPoint2DDouble& crossing)
{
    // lijn must exist
    assert(m_valid_parameters);
    assert(lijn.m_valid_parameters);

    double X, Y, Denominator;
    Denominator  = (m_AA * lijn.m_BB) - (lijn.m_AA * m_BB);
    // Denominator may not be 0
    if (Denominator == 0.0)
        return FALSE;
    // Calculate intersection of both linesegments
    X = ((m_BB * lijn.m_CC) - (lijn.m_BB * m_CC)) / Denominator;
    Y = ((lijn.m_AA * m_CC) - (m_AA * lijn.m_CC)) / Denominator;

    crossing.m_x=X;
    crossing.m_y=Y;
    return TRUE;
}

