//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * 指向性ボックステスト実装
 * @author Junpee
 */

#include "Test/stdafx.h"
#include "Geometry/Primitive/OrientedBoxTest.h"
#include "Geometry/Primitive/OrientedBox.h"

//------------------------------------------------------------------------------
// コンストラクタ
OrientedBoxTest::OrientedBoxTest(String name) : TestCase(name){
}
//------------------------------------------------------------------------------
// テストスィートの取得
Test* OrientedBoxTest::suite(){
	TestSuite* suite = new TestSuite("OrientedBoxTest");
	suite->addTest(new TestCaller(OrientedBoxTest, testConstructor));
	suite->addTest(new TestCaller(OrientedBoxTest, testFixedNumber));
	suite->addTest(new TestCaller(OrientedBoxTest, testSetValue));
	suite->addTest(new TestCaller(OrientedBoxTest, testGetValue));
	suite->addTest(new TestCaller(OrientedBoxTest, testBoxArithmetic));
	suite->addTest(new TestCaller(OrientedBoxTest, testTransform));
	suite->addTest(new TestCaller(OrientedBoxTest, testLogicalOperation));
	suite->addTest(new TestCaller(OrientedBoxTest, testToString));
	return suite;
}
//------------------------------------------------------------------------------
// コンストラクタテスト
void OrientedBoxTest::testConstructor(){
	TestEquals(60, (int)sizeof(OrientedBox));
	OrientedBox box0(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f);
	OrientedBox box1(Matrix33(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f),
		Vector3(-1.f, -2.f, -3.f), Vector3(1.f, 2.f, 3.f));
	TestAssert(box0 == box1);
	OrientedBox box2(box1);
	TestAssert(box0 == box2);
	box1 = box2;
	TestAssert(box0 == box1);
	float array[] = { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f };
	OrientedBox box4(array);
	TestAssert(box0 == box4);
}
//------------------------------------------------------------------------------
// 定数テスト
void OrientedBoxTest::testFixedNumber(){
	OrientedBox box0(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
		0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
	TestAssert(box0 == OrientedBox::zero);
	OrientedBox box1(1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f,
		0.f, 0.f, 0.f, 0.5f, 0.5f, 0.5f);
	TestAssert(box1 == OrientedBox::unit);
}
//------------------------------------------------------------------------------
// 値の設定テスト
void OrientedBoxTest::testSetValue(){
	OrientedBox box0(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f);
	OrientedBox box1;
	box1.set(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f);
	TestAssert(box0 == box1);
	box1.set(Matrix33(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f),
		Vector3(-1.f, -2.f, -3.f), Vector3(1.f, 2.f, 3.f));
	TestAssert(box0 == box1);
	float array[] = { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f };
	box1.set(array);
	TestAssert(box0 == box1);

	Matrix33 matrix;
	matrix.setRotationXYZ(Vector3(0.25f, 0.5f, 0.75f));
	box0.setRotationMatrix(matrix);
	box1.setRotationMatrix(matrix);
	TestAssert(box0 == box1);
	box1.setRotationXYZ(Vector3(0.25f, 0.5f, 0.75f));
	TestAssert(box0 == box1);

	Quaternion quaternion(1.f, 2.f, 3.f, 4.f);
	quaternion.normalize();
	matrix.setRotationQuaternion(quaternion);
	box0.setRotationMatrix(matrix);
	box1.setRotationQuaternion(quaternion);
	TestAssert(box0 == box1);

	box1.setCenter(Vector3(-1.f, -2.f, -3.f));
	TestAssert(box0 == box1);

	box1.setExtent(Vector3(1.f, 2.f, 3.f));
	TestAssert(box0 == box1);
}
//------------------------------------------------------------------------------
// 値の取得テスト
void OrientedBoxTest::testGetValue(){
	OrientedBox box0(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f);
	TestAssert(box0.getRotationMatrix() ==
		Matrix33(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f));
	TestAssert(box0.getCenter() == Vector3(-1.f, -2.f, -3.f));
	TestAssert(box0.getExtent() == Vector3(1.f, 2.f, 3.f));
	TestAssert(box0.getSize() == Vector3(2.f, 4.f, 6.f));

	TestAssert(box0.getAxisX() == Vector3(0.f, 1.f, 2.f));
	TestAssert(box0.getAxis(0) == box0.getAxisX());
	TestAssert(box0.getExtendedAxisX() == Vector3(0.f, 1.f, 2.f));
	TestAssert(box0.getExtendedAxis(0) == box0.getExtendedAxisX());

	TestAssert(box0.getAxisY() == Vector3(3.f, 4.f, 5.f));
	TestAssert(box0.getAxis(1) == box0.getAxisY());
	TestAssert(box0.getExtendedAxisY() == Vector3(6.f, 8.f, 10.f));
	TestAssert(box0.getExtendedAxis(1) == box0.getExtendedAxisY());

	TestAssert(box0.getAxisZ() == Vector3(6.f, 7.f, 8.f));
	TestAssert(box0.getAxis(2) == box0.getAxisZ());
	TestAssert(box0.getExtendedAxisZ() == Vector3(18.f, 21.f, 24.f));
	TestAssert(box0.getExtendedAxis(2) == box0.getExtendedAxisZ());

	TestEquals(24.f, box0.getEffectiveDiameter(Vector3(1.f, 0.f, 0.f)));
	TestEquals(30.f, box0.getEffectiveDiameter(Vector3(0.f, 1.f, 0.f)));
	TestEquals(36.f, box0.getEffectiveDiameter(Vector3(0.f, 0.f, 1.f)));

	TestAssert((box0.getEffectiveDiameter(Vector3(1.f, 0.f, 0.f)) * 0.5f) ==
		box0.getEffectiveRadius(Vector3(1.f, 0.f, 0.f)));
	TestAssert((box0.getEffectiveDiameter(Vector3(0.f, 1.f, 0.f)) * 0.5f) ==
		box0.getEffectiveRadius(Vector3(0.f, 1.f, 0.f)));
	TestAssert((box0.getEffectiveDiameter(Vector3(0.f, 0.f, 1.f)) * 0.5f) ==
		box0.getEffectiveRadius(Vector3(0.f, 0.f, 1.f)));


	OrientedBox box1(1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f,
		1.f, 2.f, 3.f, 1.f, 2.f, 3.f);
	TestAssert(box1.getCorner(0) == Vector3(0.f, 0.f, 0.f));
	TestAssert(box1.getCorner(1) == Vector3(0.f, 4.f, 0.f));
	TestAssert(box1.getCorner(2) == Vector3(2.f, 4.f, 0.f));
	TestAssert(box1.getCorner(3) == Vector3(2.f, 0.f, 0.f));
	TestAssert(box1.getCorner(4) == Vector3(2.f, 4.f, 6.f));
	TestAssert(box1.getCorner(5) == Vector3(0.f, 4.f, 6.f));
	TestAssert(box1.getCorner(6) == Vector3(0.f, 0.f, 6.f));
	TestAssert(box1.getCorner(7) == Vector3(2.f, 0.f, 6.f));

	Vector3 corner[8];
	box1.getCornerArray(corner);
	for(int i = 0; i < 8; i++){ TestAssert(corner[i] == box1.getCorner(i)); }

	box1.setRotationXYZ(Vector3(Math::halfPI, Math::halfPI, Math::halfPI));
	TestAssert(box1.getCorner(0).epsilonEquals(
		Vector3(4.f, 0.f, 2.f), Math::epsilon));
	TestAssert(box1.getCorner(1).epsilonEquals(
		Vector3(4.f, 4.f, 2.f), Math::epsilon));
	TestAssert(box1.getCorner(2).epsilonEquals(
		Vector3(4.f, 4.f, 4.f), Math::epsilon));
	TestAssert(box1.getCorner(3).epsilonEquals(
		Vector3(4.f, 0.f, 4.f), Math::epsilon));
	TestAssert(box1.getCorner(4).epsilonEquals(
		Vector3(-2.f, 4.f, 4.f), Math::epsilon));
	TestAssert(box1.getCorner(5).epsilonEquals(
		Vector3(-2.f, 4.f, 2.f), Math::epsilon));
	TestAssert(box1.getCorner(6).epsilonEquals(
		Vector3(-2.f, -0.f, 2.f), Math::epsilon));
	TestAssert(box1.getCorner(7).epsilonEquals(
		Vector3(-2.f, -0.f, 4.f), Math::epsilon));

	box1.getCornerArray(corner);
	for(int i = 0; i < 8; i++){ TestAssert(corner[i] == box1.getCorner(i)); }
}
//------------------------------------------------------------------------------
// ボックス演算
void OrientedBoxTest::testBoxArithmetic(){
	OrientedBox box0(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 0.f, 0.f, 0.f);
	TestAssert(box0.isZero());
	TestAssert(!box0.isUnit());
	OrientedBox box1(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 0.5f, 0.5f, 0.5f);
	TestAssert(!box1.isZero());
	TestAssert(box1.isUnit());
}
//------------------------------------------------------------------------------
// 変換テスト
void OrientedBoxTest::testTransform(){
	OrientedBox box0(1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f,
		1.f, 2.f, 3.f, 1.f, 2.f, 3.f);
	OrientedBox box1;

	Matrix33 mtx33;
	mtx33.setRotationXYZ(Vector3(Math::halfPI, Math::halfPI, Math::halfPI));
	box1 = box0.transform(mtx33);
	TestAssert(box1.epsilonEquals(OrientedBox(
		0.f, 0.f, 1.f, 0.f, 1.f, 0.f, -1.f, 0.f, 0.f,
		3.f, 2.f, -1.f, 1.f, 2.f, 3.f), Math::epsilon));

	mtx33.setScale(Vector3(1.f, 2.f, 1.f));
	mtx33.addRotationXYZ(Vector3(Math::halfPI, Math::halfPI, Math::halfPI));
	TestAssert(box0.scaledTransform(mtx33).epsilonEquals(
		AxisAlignedBox(0.f, 0.f, -2.f, 6.f, 8.f, 0.f), Math::epsilon));

	Matrix34 mtx43;
	mtx43.setRotationXYZ(Vector3(Math::halfPI, Math::halfPI, Math::halfPI));
	mtx43.addTranslation(1.f, 1.f, 1.f);
	box1 = box0.transform(mtx43);
	TestAssert(box1.epsilonEquals(OrientedBox(
		0.f, 0.f, 1.f, 0.f, 1.f, 0.f, -1.f, 0.f, 0.f,
		4.f, 3.f, 0.f, 1.f, 2.f, 3.f), Math::epsilon));

	mtx43.setScale(Vector3(1.f, 2.f, 1.f));
	mtx43.addRotationXYZ(Vector3(Math::halfPI, Math::halfPI, Math::halfPI));
	mtx43.addTranslation(1.f, 1.f, 1.f);
	TestAssert(box0.scaledTransform(mtx43).epsilonEquals(
		AxisAlignedBox(1.f, 1.f, -1.f, 7.f, 9.f, 1.f), Math::epsilon));

	Matrix44 mtx44;
	mtx44.setRotationXYZ(Vector3(Math::halfPI, Math::halfPI, Math::halfPI));
	mtx44.addTranslation(1.f, -1.f, 1.f);
	box1 = box0.transform(mtx44);
	TestAssert(box1.epsilonEquals(OrientedBox(
		0.f, 0.f, 1.f, 0.f, 1.f, 0.f, -1.f, 0.f, 0.f,
		4.f, 1.f, 0.f, 1.f, 2.f, 3.f), Math::epsilon));

	mtx44.setScale(Vector3(1.f, 2.f, 1.f));
	mtx44.addRotationXYZ(Vector3(Math::halfPI, Math::halfPI, Math::halfPI));
	mtx44.addTranslation(1.f, -1.f, 1.f);
	TestAssert(box0.scaledTransform(mtx44).epsilonEquals(
		AxisAlignedBox(1.f, -1.f, -1.f, 7.f, 7.f, 1.f), Math::epsilon));
}
//------------------------------------------------------------------------------
// 論理演算テスト
void OrientedBoxTest::testLogicalOperation(){
	OrientedBox box0(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f);
	OrientedBox box1(1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f,
		-2.f, -3.f, -4.f, 2.f, 3.f, 4.f);
	OrientedBox box2(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f);
	TestAssert(!(box0 == box1));
	TestAssert(box0 == box2);
	TestAssert(box0 != box1);
	TestAssert(!(box0 != box2));
	TestAssert(box0.epsilonEquals(box1, 1.f));
	TestAssert(box0 != box1);
	TestAssert(box0.notEpsilonEquals(box1, 0.5f));
	TestAssert(!box0.notEpsilonEquals(box1, 1.f));
	TestAssert(!box0.notEpsilonEquals(box2, 0.f));
}
//------------------------------------------------------------------------------
// 文字列テスト
void OrientedBoxTest::testToString(){
	OrientedBox box0(0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
		-1.f, -2.f, -3.f, 1.f, 2.f, 3.f);
	TestEquals("{ { ( 0.00000000, 1.00000000, 2.00000000 ) "
		"( 3.00000000, 4.00000000, 5.00000000 ) "
		"( 6.00000000, 7.00000000, 8.00000000 ) } "
		"( -1.00000000, -2.00000000, -3.00000000 ) "
		"( 1.00000000, 2.00000000, 3.00000000 ) }",
		box0.toString());
}
//------------------------------------------------------------------------------
