/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2014/01/24
/// 
/// @brief  ２Ｄ系 数学関連
/// 
/// ****************************************************************************

#pragma once

#include "CPL_MathBase.h"


namespace CPL {
namespace Math {

template<class T_Type = float>
class D2 {
  typedef T_Type*       type_ptr;
  typedef T_Type const* type_cptr;
public:

  // _____________________________________________________________________________
  /// @brief ベクトル
  ///
  // *****************************************************************************
  template<class T_Type>
  class Vector_
    : public Core::Point2<T_Type>
  {
    typedef Core::Point2<T_Type> type_base;
  public:
    operator type_ptr ()       { return &this->get(); }
    operator type_cptr() const { return &this->get(); }
    Vector_(){}
    Vector_( type_cptr p )        : type_base( p[0], p[1] ) {}
    Vector_( T_Type x, T_Type y ) : type_base(x,y) {}
    Vector_( const Vector_& vec ) : type_base(vec) {}
    Vector_( const Core::Point2<T_Type>& vec ) : type_base(vec) {}
    template<class T_Vec>
    Vector_( T_Vec const& in_vector )
      : type_base( static_cast<T_Type const*>(&in_vector.get()) )
    {}
    
    typedef Vector_*        ptr;
    typedef Vector_ const* cptr;
    typedef Vector_&        ref;
    typedef Vector_ const& cref;
  };
  typedef Vector_<T_Type> Vector;




  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルのコピー
  ///
  /// @param[out] out_vector
  ///   : コピー先の２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector
  ///   : コピー元の２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return なし。
  ///
  /// @note 
  /// out_vector = in_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecCopy( type_ptr out_vector, type_cptr in_vector )
  {
    out_vector[0] = in_vector[0];
    out_vector[1] = in_vector[1];
  }


  // _____________________________________________________________________________
  /// @brief ３×３マトリクスのコピー
  ///
  /// @param[out] out_matrix
  ///   : コピー先のマトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix
  ///   : コピー元のマトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixCopy( type_ptr out_matrix, type_cptr in_matrix )
  {
    VecCopy_<T_Type,9>( out_matrix, in_matrix );
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルの長さの２乗を取得
  ///
  /// @param[in] in_vector : ２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return 各辺の２乗の和を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLengthSq( type_cptr in_vector )
  {
    return Squ(in_vector[0]) + Squ(in_vector[1]);
  }



  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルの長さの２乗を取得
  ///
  /// @param[in] in_X : ２Ｄベクトルのｘ成分を指定します。
  /// @param[in] in_Y : ２Ｄベクトルのｙ成分を指定します。
  ///
  /// @return 各辺の２乗の和を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLengthSq( T_Type in_X, T_Type in_Y )
  {
    return Squ(in_X) + Squ(in_Y);
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルの長さを取得
  ///
  /// @param[in] in_vector : ２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return ２Ｄベクトルの長さを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLength( type_cptr in_vector )
  {
    return sqrtf( GetVecLengthSq(in_vector) );
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルの長さを取得
  ///
  /// @param[in] in_X : ２Ｄベクトルのｘ成分を指定します。
  /// @param[in] in_Y : ２Ｄベクトルのｙ成分を指定します。
  ///
  /// @return ２Ｄベクトルの長さを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLength( T_Type in_X, T_Type in_Y )
  {
    T_Type l = GetVecLengthSq(in_X,in_Y);
    if( l > 0 )
    {
      return sqrtf( l );
    }
    else
    {
      return 0;
    }
  }


  // _____________________________________________________________________________
  /// @brief ベクトルを加算したものを取得
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector1
  ///   : 計算元データ列への２Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector2
  ///   : 加算データ列への２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  ///
  /// @note 
  /// out_vector = in_vector1 + in_vector2
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecAdd( type_ptr out_vector, type_cptr in_vector1, type_cptr in_vector2 )
  {
    out_vector[0] = in_vector1[0] + in_vector2[0];
    out_vector[1] = in_vector1[1] + in_vector2[1];
    return out_vector;
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルを加算
  ///
  /// @param[in,out] io_vector
  ///   : 計算元データの２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] io_vector_for_add
  ///   : 加算データの２Ｄベクトル（先頭の成分のアドレス）
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecAdd( type_ptr io_vector, type_cptr io_vector_for_add )
  {
    io_vector[0] += io_vector_for_add[0];
    io_vector[1] += io_vector_for_add[1];
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルを減算したものを取得
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する２Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector1
  ///   : 計算元データの２Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector2
  ///   : 減算データの２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  ///
  /// @note
  /// out_vector = in_vector1 - in_vector2
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecSub( type_ptr out_vector, type_cptr in_vector1, type_cptr in_vector2 )
  {
    out_vector[0] = in_vector1[0] - in_vector2[0];
    out_vector[1] = in_vector1[1] - in_vector2[1];
    return out_vector;
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルを減算
  ///
  /// @param[in,out] io_vector
  ///   : 計算元データの２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] io_vector_for_sub
  ///   : 加算データ２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @note 
  /// io_vector -= io_vector_for_sub
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecSub( type_ptr io_vector, type_cptr io_vector_for_sub )
  {
    io_vector[0] -= io_vector_for_sub[0];
    io_vector[1] -= io_vector_for_sub[1];
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄ単位ベクトルを取得
  ///
  /// @param[out] out_vector
  ///   : 計算元データの２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector
  ///   : 加算データの２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  ///
  /// @note
  /// out_vector = in_vector / length
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecNormalize( type_ptr out_vector, type_cptr in_vector )
  {
    T_Type len = GetVecLength(in_vector);
    if( len != 0 )
    {
      T_Type a = 1.0f / len;
      out_vector[0] = in_vector[0] * a;
      out_vector[1] = in_vector[1] * a;
    }
    return out_vector;
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄ単位ベクトルに変換
  ///
  /// @param[in,out] io_vector
  ///   : ２Ｄベクトル（先頭の成分のアドレス）を渡します。
  ///
  /// @note 
  /// io_vector /= length
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecNormalize( type_ptr io_vector )
  {
    if( AllZero_<T_Type,2>( io_vector ) )
    {
      io_vector[0] = static_cast<T_Type>(0);
      io_vector[1] = static_cast<T_Type>(1);
    }
    else
    {
      T_Type a = 1.0f / GetVecLength( io_vector );
      io_vector[ 0 ] *= a;
      io_vector[ 1 ] *= a;
    }
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルの内積を取得
  ///
  /// ２つのベクトルの角度がθのときのcosθを返します。
  ///
  /// @param[in] in_vector0
  ///   : １番目の２Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector1
  ///   : ２番目の２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return in_vector0 と in_vector1 の内積を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecDot( type_cptr in_vector0, type_cptr in_vector1 )
  {
    return in_vector0[0]*in_vector1[0] + in_vector0[1]*in_vector1[1];
  }


  // _____________________________________________________________________________
  /// @brief ２つの２Ｄベクトル間の角度を取得
  ///
  /// @param[in] in_vector0
  ///   : １番目の２Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector1
  ///   : ２番目の２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return in_vector0とin_vector1の角度（ラジアン単位）を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecAngle( type_cptr in_vector0, type_cptr in_vector1 )
  {
    return acosf( GetVecDot( in_vector0, in_vector1 ) );
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルのマトリクス変換後のｘ値を取得
  /// 
  /// @param[in] in_vector : ２Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix : ３ｘ３マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return 変換後のベクトルｘを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecTransformX( type_cptr in_vector, type_cptr in_matrix )
  {
    return in_vector[0]*in_matrix[0] + in_vector[1]*in_matrix[3] + in_matrix[6];
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルのマトリクス変換後のｙ値を取得
  /// 
  /// @param[in] in_vector : ２Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix : ３ｘ３マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return 変換後のベクトルｙを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecTransformY( type_cptr in_vector, type_cptr in_matrix )
  {
    return in_vector[0]*in_matrix[1] + in_vector[1]*in_matrix[4] + in_matrix[7];
  }


  // _____________________________________________________________________________
  /// @brief マトリクス変換後の２Ｄベクトルを取得
  ///
  /// @param[out] out_vector
  ///   : 変換後のベクトルを取得する領域を指すポインタを渡します。\n
  ///   : ※ in_vectorと同じアドレスを渡すと正しい値を返さないので注意。
  /// @param[in] in_vector
  ///   : 変換前のベクトルを指すポインタを指定します。\n
  ///   : ※ out_vectorと同じアドレスを渡すと正しい値を返さないので注意。
  /// @param[in] in_matrix
  ///   : 適用するマトリクスのポインタを指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecTransform( type_ptr out_vector, type_ptr in_vector, type_cptr in_matrix )
  {
    out_vector[0] = GetVecTransformX( in_vector, in_matrix );
    out_vector[1] = GetVecTransformY( in_vector, in_matrix );
    return out_vector;
  }

  // _____________________________________________________________________________
  /// @brief マトリクス変換後の２Ｄベクトルを取得
  ///
  /// @param[out] io_vector
  ///   : 変換するベクトルを指す領域を指すポインタを渡します。\n
  ///   : ※ in_vectorと同じアドレスを渡すと正しい値を返さないので注意を指定します。
  /// @param[in] in_matrix
  ///   : 適用するマトリクスのポインタを指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr VecTransform( type_ptr io_vector, type_cptr in_matrix )
  {
    T_Type v[2] = { io_vector[0], io_vector[1] };
    return GetVecTransform( io_vector, v, in_matrix );
  }


  // _____________________________________________________________________________
  /// @brief 単位マトリクスの取得
  ///
  /// @param[out] out_matrix : ３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixIdentity( type_ptr out_matrix )
  {
    out_matrix[0] = 1; out_matrix[1] = 0; out_matrix[2] = 0;
    out_matrix[3] = 0; out_matrix[4] = 1; out_matrix[5] = 0;
    out_matrix[6] = 0; out_matrix[7] = 0; out_matrix[8] = 1;
    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief マトリクス同士の乗算したマトリクスを取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix1
  ///   : 計算元３ｘ３マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix2
  ///   : 乗算する３ｘ３マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  ///
  /// @note 
  /// out_matrix = in_matrix1 * in_matrix2
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiply
      ( type_ptr  out_matrix
      , type_cptr in_matrix1
      , type_cptr in_matrix2
      )
  {
    auto m1 = in_matrix1;
    auto m2 = in_matrix2;
    out_matrix[0] = m1[0]*m2[0] + m1[1]*m2[3] + m1[2]*m2[6];
    out_matrix[1] = m1[0]*m2[1] + m1[1]*m2[4] + m1[2]*m2[7];
    out_matrix[2] = m1[0]*m2[2] + m1[1]*m2[5] + m1[2]*m2[8];
    out_matrix[3] = m1[3]*m2[0] + m1[4]*m2[3] + m1[5]*m2[6];
    out_matrix[4] = m1[3]*m2[1] + m1[4]*m2[4] + m1[5]*m2[7];
    out_matrix[5] = m1[3]*m2[2] + m1[4]*m2[5] + m1[5]*m2[8];
    out_matrix[6] = m1[6]*m2[0] + m1[7]*m2[3] + m1[8]*m2[6];
    out_matrix[7] = m1[6]*m2[1] + m1[7]*m2[4] + m1[8]*m2[7];
    out_matrix[8] = m1[6]*m2[2] + m1[7]*m2[5] + m1[8]*m2[8];
    return out_matrix;
  }



  // _____________________________________________________________________________
  /// @brief マトリクスの乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 計算元３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 乗算する３ｘ３マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @note
  /// io_matrix *= in_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiply( type_ptr io_matrix, type_cptr in_matrix )
  {
    T_Type m[9];
    MatrixCopy( m, io_matrix );
    GetMatrixMultiply( io_matrix, m, in_matrix );
  }



  
  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotZ( type_ptr out_matrix, T_Type in_cos, T_Type in_sin )
  {
    out_matrix[0]= in_cos; out_matrix[1]=in_sin; out_matrix[2]=0;
    out_matrix[3]=-in_sin; out_matrix[4]=in_cos; out_matrix[5]=0;
    out_matrix[6]=      0; out_matrix[7]=     0; out_matrix[8]=1;
    return out_matrix;
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを設定（デグリー仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : 角度。デグリー単位（0 - 360）
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotZdeg( type_ptr out_matrix, int in_rot_Z )
  {
    return GetMatrixRotZ( out_matrix, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを設定（ラジアン仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in]  in_rot_Z : 角度。ラジアン単位。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotZrad( type_ptr out_matrix, T_Type in_rot_Z )
  {
    return GetMatrixRotZ( out_matrix, cosf(in_rot_Z), sinf(in_rot_Z) );
  }



  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix : 計算元マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_cos : 計算済みcos値を指定します。。
  /// @param[in] in_sin : 計算済みsin値を指定します。。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotZ
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_cos
      , T_Type    in_sin
      )
  {
    T_Type msin = -in_sin;

    out_matrix[0] = in_matrix[0]*in_cos + in_matrix[1]*msin;
    out_matrix[1] = in_matrix[0]*in_sin + in_matrix[1]*in_cos;
    out_matrix[2] = in_matrix[2];
    out_matrix[3] = in_matrix[3]*in_cos + in_matrix[4]*msin;
    out_matrix[4] = in_matrix[3]*in_sin + in_matrix[4]*in_cos;
    out_matrix[5] = in_matrix[5];
    out_matrix[6] = in_matrix[6]*in_cos + in_matrix[7]*msin;
    out_matrix[7] = in_matrix[6]*in_sin + in_matrix[7]*in_cos;
    out_matrix[8] = in_matrix[8];

    return out_matrix;
  }





  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_rot_Z
  ///   : 角度を指定します。デグリー単位（0 - 360）
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotZdeg
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , int       in_rot_Z
      )
  {
    return GetMatrixMultiplyRotZ( out_matrix, in_matrix, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_rot_Z
  ///   : 角度を指定します。ラジアン単位。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotZrad
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_rot_Z
      )
  {
    return GetMatrixMultiplyRotZ( out_matrix, in_matrix, cosf(in_rot_Z), sinf(in_rot_Z) );
  }



  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換元３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotZ( type_ptr io_matrix, T_Type in_cos, T_Type in_sin )
  {
    T_Type msin = -in_sin;

    T_Type m00 = io_matrix[0];
    T_Type m01 = io_matrix[1];
    T_Type m10 = io_matrix[3];
    T_Type m11 = io_matrix[4];
    T_Type m20 = io_matrix[6];
    T_Type m21 = io_matrix[7];

    io_matrix[0] = m00*in_cos + m01*msin;
    io_matrix[1] = m00*in_sin + m01*in_cos;
    io_matrix[3] = m10*in_cos + m11*msin;
    io_matrix[4] = m10*in_sin + m11*in_cos;     
    io_matrix[6] = m20*in_cos + m21*msin;
    io_matrix[7] = m20*in_sin + m21*in_cos;
  }





  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換元３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : 角度を指定します。デグリー単位（0 - 360）
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotZdeg( type_ptr io_matrix, int in_rot_Z )
  {
    MatrixMultiplyRotZ( io_matrix, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換元３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : 角度を指定します。ラジアン単位。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotZrad( type_ptr io_matrix, T_Type in_rot_Z )
  {
    auto c = static_cast<T_Type>(cos( in_rot_Z ));
    auto s = static_cast<T_Type>(sin( in_rot_Z ));
    MatrixMultiplyRotZ( io_matrix, c, s );
  }




  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルのｚ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換元２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotZ( type_ptr io_vector, T_Type in_cos, T_Type in_sin )
  {
    T_Type m[9];
    GetMatrixRotZ( m, in_cos, in_sin );
    GetVecTransform( io_vector, m );
    return io_vector;
  }




  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルのｚ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 設定する２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : 角度を指定します。デグリー単位（0 - 360）
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotZdeg( type_ptr io_vector, int in_rot_Z )
  {
    return GetVecRotZ( io_vector, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルのｚ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 設定する２Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : 角度を指定します（ラジアン単位）。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotZrad( type_ptr io_vector, T_Type in_rot_Z )
  {
    auto c = cosf( in_rot_Z );
    auto s = sinf( in_rot_Z );
    return GetVecRotZ( io_vector, c, s );
  }



  // _____________________________________________________________________________
  /// @brief 平行移動マトリクスを設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_move_xy
  ///   : 移動量表す２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixTranslate( type_ptr out_matrix, type_cptr in_move_xy )
  {
    out_matrix[0]=            1; out_matrix[1]=            0; out_matrix[2]=0;
    out_matrix[3]=            0; out_matrix[4]=            1; out_matrix[5]=0;
    out_matrix[6]=in_move_xy[0]; out_matrix[7]=in_move_xy[1]; out_matrix[8]=1;
    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief マトリクスの平行移動処理
  ///
  /// @param[in,out] io_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_move_xy
  ///   : 移動量表す２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixTranslate( type_ptr io_matrix, type_cptr in_move_xy )
  {
    io_matrix[6] += in_move_xy[0];
    io_matrix[7] += in_move_xy[1];
  }


  // _____________________________________________________________________________
  /// @brief マトリクスの平行移動処理
  ///
  /// @param[in,out] io_matrix
  ///   : 取得用の３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_move_x : ｘ移動量を指定します。
  /// @param[in] in_move_y : ｙ移動量を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixTranslate( type_ptr io_matrix, T_Type in_move_x, T_Type in_move_y )
  {
    io_matrix[6] += in_move_x;
    io_matrix[7] += in_move_y;
  }


  // _____________________________________________________________________________
  /// @brief スケール行列の設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３×３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_xy
  ///   : 倍率を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixScaling( type_ptr out_matrix, type_cptr in_scale_xy )
  {
    auto x = in_scale_xy[0];
    auto y = in_scale_xy[1];
    out_matrix[0] = x; out_matrix[1] = 0; out_matrix[2] = 0;
    out_matrix[3] = 0; out_matrix[4] = y; out_matrix[5] = 0;
    out_matrix[6] = 0; out_matrix[7] = 0; out_matrix[8] = 1;
    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief スケール行列の設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３×３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_x : ｘ方向の倍率を指定します。
  /// @param[in] in_scale_y : ｙ方向の倍率を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixScaling( type_ptr out_matrix, T_Type in_scale_x, T_Type in_scale_y )
  {
    out_matrix[0]= in_scale_x; out_matrix[1]= 0;          out_matrix[2]=0;
    out_matrix[3]= 0;          out_matrix[4]= in_scale_y; out_matrix[5]=0;
    out_matrix[6]= 0;          out_matrix[7]= 0;          out_matrix[8]=1;
    return out_matrix;
  }



  // _____________________________________________________________________________
  /// @brief スケール行列の乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換用３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_xy
  ///   : 倍率を表す２Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr MatrixMultiplyScaling( type_ptr io_matrix, type_cptr in_scale_xy )
  {
    io_matrix[0] *= in_scale_xy[0];
    io_matrix[1] *= in_scale_xy[1];
    io_matrix[3] *= in_scale_xy[0];
    io_matrix[4] *= in_scale_xy[1];
    io_matrix[6] *= in_scale_xy[0];
    io_matrix[7] *= in_scale_xy[1];
    return io_matrix;
  }



  // _____________________________________________________________________________
  /// @brief スケール行列の乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換用３ｘ３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_x : ｘ方向の倍率を指定します。
  /// @param[in] in_scale_y : ｙ方向の倍率を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    MatrixMultiplyScaling( type_ptr io_matrix, T_Type in_scale_x, T_Type in_scale_y )
  {
    io_matrix[0] *= in_scale_x;
    io_matrix[1] *= in_scale_y;
    io_matrix[3] *= in_scale_x;
    io_matrix[4] *= in_scale_y;
    io_matrix[6] *= in_scale_x;
    io_matrix[7] *= in_scale_y;
    return io_matrix;
  }




  // _____________________________________________________________________________
  /// @brief 逆行列の取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の３×３マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 変換元の３ｘ３マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return
  /// 変換できた場合はout_matrixを返す。\n
  /// 失敗(0による除算等)した場合、nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixInverse( type_ptr out_matrix, type_cptr in_matrix )
  {
    Matrix& out_ = *(Matrix*)out_matrix;
    Matrix  in_  = *(Matrix*)in_matrix; // out_matrix == in_matrixでも計算できるようコピー

    T_Type tmp; //一時的なデータを蓄える
    int i, j, k; //カウンタ
    int n = 3;  //配列の次数
    // 単位行列を設定
    GetMatrixIdentity( out_ );
    //掃き出し法
    for( i = 0; i < n; i++ )
    {
      tmp = in_(i,i);
      if( tmp == 0 )
      {
        return nullptr;
      }
      tmp = 1.0f / tmp;
      for( j = 0; j < n; j++ )
      {
        in_(i,j) *= tmp;
        out_(i,j) *= tmp;
      }
      for( j = 0; j < n; j++ )
      {
        if( i != j )
        {
          tmp = in_(j,i);
          for( k = 0; k < n; k++ )
          {
            in_(j,k) -= in_(i,k) * tmp;
            out_(j,k) -= out_(i,k) * tmp;
          }
        }
      }
    }

    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief 線分から点への最近接点を取得
  ///
  /// @param[out] out_vector : 最近接点の座標取得用ポインタを渡します。
  /// @param[in]  in_point   : 点の座標を指定します。
  /// @param[in]  in_seg0    : 線分の始端座標を指定します。
  /// @param[in]  in_seg1    : 線分の終端座標を指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecClosestPointSegment
      ( type_ptr  out_vector
      , type_ptr  in_point
      , type_cptr in_seg0
      , type_cptr in_seg1
      )
  {
    const Vector& a = *reinterpret_cast<const Vector*>(in_seg0);
    const Vector& b = *reinterpret_cast<const Vector*>(in_seg1);
    const Vector& c  = *reinterpret_cast<const Vector*>(in_point);

    Vector ab = b - a;
    // パラメータ化されている位置の計算によりvsegにxyzを射影
    T_Type t = GetVecDot( c - a, ab ) / GetVecDot( ab, ab );
    // 線分の外側にある場合、ｔを最近接点までクランプ
    CPL::Clamp( t, (T_Type)0, (T_Type)1 );
    // クランプされているｔからの射影されている位置を計算
    *reinterpret_cast<Vector*>(out_vector) = a + ab * t;

    return out_vector;
  }




  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルの加算（構造体配列指定仕様）
  ///
  /// @param[in,out] io_xy_table_addr
  ///   : 変換するベクトル配列（先頭の２Ｄベクトルの先頭の成分のアドレス）を渡します。
  /// @param[in] io_vector_for_add
  ///   : 加算ベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_size
  ///   : 次のベクトルへのバイトオフセット（構造体サイズ）を指定します。\n
  ///   : ※ sizeof(io_xy_table_addr[0])byteでアライメントされます。
  /// @param[in] in_num
  ///   : 配列の要素数を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    VecAddTable
      ( type_ptr  io_xy_table_addr
      , type_cptr io_vector_for_add
      , long      in_size
      , long      in_num
      )
  {
    PRIVATE_CALL_TABLE_ARG2_
      ( io_xy_table_addr
      , io_vector_for_add
      , in_size
      , in_num
      , VecAdd
      );
  }


  // _____________________________________________________________________________
  /// @brief ２Ｄベクトルを減算（構造体配列指定仕様）
  ///
  /// @param[in,out] io_xy_table_addr
  ///   : 変換するベクトル配列（先頭の２Ｄベクトルの先頭の成分のアドレス）を渡します。
  /// @param[in] io_vector_for_sub
  ///   : 減算ベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_size
  ///   : 次のベクトルへのバイトオフセット（構造体サイズ）を指定します。\n
  ///   : ※ sizeof(io_xy_table_addr[0])byteでアライメントされます。
  /// @param[in] in_num
  ///   : 配列の要素数を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    VecSubTable
      ( type_ptr  io_xy_table_addr
      , type_cptr io_vector_for_sub
      , long      in_size
      , long      in_num
      )
  {
    PRIVATE_CALL_TABLE_ARG2_
      ( io_xy_table_addr
      , io_vector_for_sub
      , in_size
      , in_num
      , VecSub
      );
  }






  // _____________________________________________________________________________
  /// @brief マトリクス
  ///
  // *****************************************************************************
  class Matrix_
    : public CPL::Core::zzz_::Vector_< T_Type, 9, Matrix_ >
  {
  protected:

    // 使用禁止(ValuseSetで定義されているため)
    template<class T0>       Matrix_  operator / ( const T0& d )       { return Matrix_(); }
    template<class T0> const Matrix_  operator / ( const T0& d ) const { return Matrix_(); }
    template<class T0> void  operator /= ( const T0& d ){ _Division( d ); }
  public:
      union {
          struct {
              T_Type  _11, _12, _13;
              T_Type  _21, _22, _23;
              T_Type  _31, _32, _33;
          };
          T_Type m[3][3];
      };

    operator type_ptr()        { return &m[0][0]; }
    operator type_cptr() const { return &m[0][0]; }

    T_Type& operator ()( int row, int col )       { return m[ row ][ col ]; }
    T_Type  operator ()( int row, int col ) const { return m[ row ][ col ]; }

    void         operator =( const Matrix_& in_matrix ){ MatrixCopy( *this, in_matrix ); } // 代入コピー

    Matrix_& operator *= ( type_cptr      in_matrix   ){ MatrixMultiply( *this, in_matrix ); return *this; }
    Matrix_& operator *= ( Matrix_ const& in_matrix   ){ return (*this *= (type_cptr)in_matrix); }
    Matrix_& operator *= ( T_Type         in_value ){ for(int i=0;i<9;++i){this->get(i)*=in_value;}; return *this; }
    Matrix_  operator *  ( type_cptr      in_matrix   ) const { return Matrix_(*this) *= in_matrix; }
    Matrix_  operator *  ( Matrix_ const& in_matrix   ) const { return Matrix_(*this) *= in_matrix; }
    Matrix_  operator *  ( T_Type         in_value ) const { return Matrix_(*this) *= in_value; }

    void Identity(){ GetMatrixIdentity( *this ); }
    Matrix_& Mul      ( type_cptr in_matrix ){ return *this *= in_matrix; } // マトリクス乗算
    Matrix_& RotZdeg  ( int    in_rot_Z  ){ MatrixMultiplyRotZdeg( *this, in_rot_Z ); return *this; } // デグリー単位で回転
    Matrix_& RotZrad  ( T_Type in_rot_Z  ){ MatrixMultiplyRotZrad( *this, in_rot_Z ); return *this; } // ラジアン単位で回転
    Matrix_& Translate( T_Type in_move_x, T_Type in_move_y   ){ MatrixTranslate( *this, in_move_x, in_move_y ); return *this; } // 移動
    Matrix_& Translate( type_cptr in_ptr_move_xy             ){ MatrixTranslate( *this, in_ptr_move_xy );       return *this; } // 移動
    Matrix_& Scaling  ( T_Type in_scale_x, T_Type in_scale_y ){ MatrixMultiplyScaling( *this, in_scale_x, in_scale_y ); return *this; } // スケーリング
    Matrix_& Scaling  ( type_cptr in_ptr_scale_xy            ){ MatrixMultiplyScaling( *this, in_ptr_scale_xy );        return *this; } // スケーリング

    Matrix_(){}
    Matrix_( Initialize_ ){ Identity(); }
    Matrix_( type_cptr      in_ptr_mtx ){ MatrixCopy( *this, in_ptr_mtx ); }
    Matrix_( const Matrix_& in_matrix     ){ MatrixCopy( *this, in_matrix ); }

    typedef Matrix_*        ptr;
    typedef Matrix_ const* cptr;
    typedef Matrix_&        ref;
    typedef Matrix_ const& cref;
  };
  typedef Matrix_ Matrix;


  // _____________________________________________________________________________
  /// @brief ２Ｄ系 バウンディングボックス
  ///
  // *****************************************************************************
  class BBox {
    Vector m_min;
    Vector m_max;

  public:
    void SetMax( const Vector& xy  ){ m_max = xy; }
    void SetMax( T_Type x, T_Type y ){ m_max.Set(x,y); }
    void SetMin( const Vector& xy  ){ m_min = xy; }
    void SetMin( T_Type x, T_Type y ){ m_min.Set(x,y); }

    const Vector* GetMin() const { return &m_min; }
    const Vector* GetMax() const { return &m_max; }

    bool Hit( const Vector& in_xy ) const {
      if( m_min.x <= in_xy.x  &&  in_xy.x <= m_max.x  &&
          m_min.y <= in_xy.y  &&  in_xy.y <= m_max.y )
      {
        return true;
      }
      return false;
    }
    bool Hit( T_Type x, T_Type y ) const { return Hit(Vector(x,y)); }
    bool Hit( BBox const& in_box ) const
    {
      return (Hit(in_box.m_min) | Hit(in_box.m_max));
    }
    
    BBox& operator = ( BBox const& in_bbox )
    {
      m_min = *in_bbox.GetMin();
      m_max = *in_bbox.GetMax();

      return *this;
    }

    template<class T_RECT>
    T_RECT GetRECT() const
    {
      T_RECT rt = { m_min.x, m_min.y, m_max.x, m_max.y };
      return rt;
    }

    BBox(){}
    BBox( const Vector& in_vector_min, const Vector& in_vector_max )
      : m_min(in_vector_min), m_max(in_vector_max) {}
    BBox( const BBox& in_bbox )
    {
      *this = in_bbox;
    }
  };



  }; // class D2

} // namespace Math
} // namespace CPL
