#ifndef LINE_UTILS_H
#define LINE_UTILS_H

/*!
  \file
  \brief 直線関連の関数

  「ゲームプログラミングのためのリアルタイム衝突判定」(ELSEVIER) より

  \author Satofumi KAMIMURA

  $Id: LineUtils.h 1970 2011-11-09 06:53:29Z satofumi $
*/

#include "LineTypes.h"
#include "MathUtils.h"


namespace
{
  template <class T>
  double signed2DTriangleArea(const qrk::Point<T>& a,
                              const qrk::Point<T>& b,
                              const qrk::Point<T>& c)
  {
    return ((a.x - c.x) * (b.y - c.y)) - ((a.y - c.y) * (b.x - c.x));
  }
}


namespace qrk
{
  class Angle;


  /*!
    \brief 線分の交差判定

    \param[in] p 線分の交差点
    \param[in] a 線分
    \param[in] b 線分
  */
  template <class T>
  bool isCrossLines(Point<T>& p, const Line<T>& a, const Line<T>& b)
  {
    double a1 = signed2DTriangleArea(a.start, a.end, b.end);
    double a2 = signed2DTriangleArea(a.start, a.end, b.start);

    double a_1_2 = a1 * a2;
    if ((a_1_2) <= 0.0) {
      double a3 = signed2DTriangleArea(b.start, b.end, a.start);
      double a4 = a3 + a2 - a1;

      double a_3_4 = a3 * a4;
      if (a_3_4 <= 0.0) {

        double diff = a3 - a4;
        if (diff == 0.0) {
          // 直線が重なっているときは、a 開始位置を交差点として返す
          p = a.start;
        } else {
          double t = 1.0 * a3 / diff;
          Point<double> diff = a.end - a.start;
          p = (t * diff) + a.start;
        }
        return true;
      }
    }
    return false;
  }


  template <class T>
  double norm(const T& a)
  {
    return sqrt((a.x * a.x) + (a.y * a.y));
  }


  /*!
    \brief 線分の距離計算

    \return 線分の距離
  */
  template <class T>
  double length(const T& a, const T& b)
  {
    double x_diff = a.x - b.x;
    double y_diff = a.y - b.y;

    return sqrt((x_diff * x_diff) + (y_diff * y_diff));
  }


  template <class T>
  Angle lineAngle(const Point<T>& a, const Point<T>& b)
  {
    double angle_radian = atan2(a.y - b.y, a.x - b.x);
    return rad(angle_radian);
  }
}

#endif /* !LINE_UTILS_H */
