/*!
  \file
  \brief Coordinate のテスト

  \author Satofumi KAMIMURA

  $Id: TestCoordinate.cpp 1601 2010-01-04 15:09:50Z satofumi $
*/

#include "TestCoordinate.h"
#include "Coordinate.h"

using namespace qrk;
using namespace std;


CPPUNIT_TEST_SUITE_REGISTRATION(TestCoordinate);
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TestCoordinate, "TestCoordinate");


// 座標系の初期化テスト
void TestCoordinate::initializeTest(void)
{
  // デフォルトの親がグローバル座標かのテスト
  Coordinate* root = Coordinate::root();
  Coordinate coordinate;
  Coordinate* parent = coordinate.parent();
  CPPUNIT_ASSERT_EQUAL(root, parent);

  // 子座標系が存在しないかのテスト
  set<Coordinate*> children = coordinate.children();
  CPPUNIT_ASSERT_EQUAL(true, children.empty());

  // 原点位置が親座標系の (0, 0, deg(0)) かをテスト
  Position<long> offset = root->offset(&coordinate);
  CPPUNIT_ASSERT_EQUAL(Position<long>(0, 0, deg(0)), offset);
}


void TestCoordinate::setOriginToTest(void)
{
  // 原点位置を設定し、取得できるかのテスト
  Coordinate* root = Coordinate::root();
  Coordinate coordinate;

  coordinate.setOriginTo(root, Position<long>(1, 2, deg(3)));
  Position<long> offset = root->offset(&coordinate);
  CPPUNIT_ASSERT_EQUAL(Position<long>(1, 2, deg(3)), offset);

  // 再設定できるかのテスト
  coordinate.setOriginTo(root, Position<long>(4, 5, deg(6)));
  offset = root->offset(&coordinate);
  CPPUNIT_ASSERT_EQUAL(Position<long>(4, 5, deg(6)), offset);
}


void TestCoordinate::treeTest(void)
{
  // ２階層のツリー構造を表現できるかのテスト
  Coordinate parent;
  Coordinate child;
  Coordinate grandchild;

  grandchild.setOriginTo(&child, Position<long>(0, 0, deg(0)));
  child.setOriginTo(&parent, Position<long>(0, 0, deg(0)));
  CPPUNIT_ASSERT_EQUAL(&child, grandchild.parent());
  CPPUNIT_ASSERT_EQUAL(&parent, child.parent());

  // 設定した子座標系を取得できるかのテスト
  set<Coordinate*> children = parent.children();
  CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), children.size());
  CPPUNIT_ASSERT(children.find(&child) != children.end());

  // 複数の子座標系を設定して取得できるかのテスト
  Coordinate* child_2nd = new Coordinate;
  child_2nd->setOriginTo(&parent, Position<long>(0, 0, deg(0)));
  children = parent.children();
  CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), children.size());
  CPPUNIT_ASSERT(children.find(child_2nd) != children.end());

  // 削除したときに、子座標系の登録も削除されるかのテスト
  delete child_2nd;
  children = parent.children();
  CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), children.size());
  CPPUNIT_ASSERT(children.find(&child) != children.end());

  // 親を再設定したときに、子座標系の登録が削除されるかのテスト
  grandchild.setOriginTo(&parent, Position<long>(0, 0, deg(0)));
  children = child.children();
  CPPUNIT_ASSERT_EQUAL(true, children.empty());
}


// 簡単な位置変換のテスト
void TestCoordinate::basicConvertTest(void)
{
  Coordinate* root = Coordinate::root();
  Coordinate coordinate;

  // (100, 100, 0) に配置した子の座標系の (100, 0, 90) の点の位置を親座標系から取得
  coordinate.setOriginTo(root, Position<long>(100, 100, deg(0)));
  Position<long> offset =
    root->pointPosition(&coordinate, Position<long>(100, 0, deg(90)));
  CPPUNIT_ASSERT_EQUAL(Position<long>(200, 100, deg(90)), offset);

  // (100, 100, 90) に配置した子の座標系の (100, 0, 90) の点の位置を親座標系から取得
  coordinate.setOriginTo(root, Position<long>(100, 100, deg(90)));
  offset = root->pointPosition(&coordinate, Position<long>(100, 0, deg(90)));
  CPPUNIT_ASSERT_EQUAL(Position<long>(100, 200, deg(180)), offset);

  // (100, 100, 0) に配置した子の座標系で、親座標系の (100, 0, 90) の点がどこかを取得
  coordinate.setOriginTo(root, Position<long>(100, 100, deg(0)));
  offset = coordinate.pointPosition(root, Position<long>(100, 0, deg(90)));
  CPPUNIT_ASSERT_EQUAL(Position<long>(0, -100, deg(90)), offset);

  // (100, 100, 90) に配置した子の座標系で、親座標系の (100, 0, 90) の点がどこかを取得
  coordinate.setOriginTo(root, Position<long>(100, 100, deg(90)));
  offset = coordinate.pointPosition(root, Position<long>(100, 0, deg(90)));
  CPPUNIT_ASSERT_EQUAL(Position<long>(-100, 0, deg(0)), offset);
}


void TestCoordinate::pointPositionTest(void)
{
  // １階層はなれた座標系位置の計算テスト
  Coordinate* root = Coordinate::root();
  Coordinate coordinate_1st;
  coordinate_1st.setOriginTo(root, Position<long>(10, 100, deg(90)));
  Position<long> offset =
    coordinate_1st.pointPosition(root, Position<long>(20, 30, deg(180)));
  CPPUNIT_ASSERT_EQUAL(Position<long>(-70, -10, deg(90)), offset);

  // ２階層はなれた座標系位置の計算テスト
  Coordinate coordinate_2nd;
  coordinate_2nd.setOriginTo(&coordinate_1st, Position<long>(20, 200, deg(90)));
  offset = coordinate_2nd.pointPosition(root,
                                        Position<long>(30, 40, deg(270)));
  CPPUNIT_ASSERT_EQUAL(Position<long>(-220, 80, deg(90)), offset);

  // グローバル座標系をまたいだ座標系での計算テスト
  Coordinate coordinate_3rd;
  coordinate_3rd.setOriginTo(root, Position<long>(-10, -20, deg(-90)));
  offset = coordinate_3rd.pointPosition(&coordinate_2nd,
                                        Position<long>(0, 110, deg(90)));
  CPPUNIT_ASSERT_EQUAL(Position<long>(-30, -180, deg(360)), offset);
}
