namespace h3d {
/**
* N次ベクトルクラス。
* @param N ベクトルの次数。
*/
template <unsigned int N>
class Vector {
public:
/** 成分の配列。N個。 */
double f[N];
/**
* 二つのベクトルの内積を計算する。
* @param vec 右側のベクトル。
* @return 計算した内積。
*/
double inpro(const Vector& rhs) const;
/**
* スカラー値との積を計算する。
* @param sca 乗数となるスカラー値。
* @return 計算したベクトル。
*/
Vector operator *(const double& sca) const;
/**
* スカラー値による除算を計算する。
* @param sca 除数となるスカラー値。
* @return 計算したベクトル。
*/
Vector operator /(const double& sca) const;
/**
* 二つのベクトルが等価かどうかを判定する。
* @param vec 別のベクトル。
* @return 等価ならtrue, 等価ではないならfalse。
*/
bool operator ==(const Vector& vec) const;
/**
* 二つのベクトルの外積を計算する。
* @param vec 右側のベクトル。
* @return 計算した外積。
*/
Vector outpro(const Vector& rhs) const;
/**
* 別のベクトルに射影する。
* @param vec このベクトル上に射影する。
* @return 射影したベクトル。
*/
Vector project(const Vector& vec) const;
};
/**
* 二つの3次ベクトルの外積を計算する。3次ベクトル専用。
* @param rhs 右側のベクトル。
* @return 計算した外積。
*/
template <>
Vector<3> Vector<3>::outpro(const Vector<3>& rhs) const;
};
namespace h3d {
/**
* 二つの数が近いかどうかを判定する。
* @param x 一つ目の数。
* @param y 二つ目の数。
* @return 近いならtrue, 遠いならfalse。
*/
inline bool near(const double& x, const double& y);
};
#include <iostream>
#include <string>
namespace h3d {
using std::cout;
using std::endl;
using std::string;
#define ASSERT(pred) assert(#pred, (pred));
#define DEBUG_PRINT(val) cout << #val << "=" << (val) << endl;
/**
* アサーションを実行する。
* 成功なら標準出力に結果を出力する。
* @param pred_str 判定する式を表した文字列。
* @param pred_res 判定結果。trueなら成功,falseなら失敗と判定する。
* @throw string 失敗ならメッセージをスローする。
*/
inline void assert(const string& pred_str, const bool& pred_res) throw(string);
};
namespace h3d {
class Test { public: virtual void run() const = 0; };
};
#include <memory>
#include <vector>
namespace h3d {
using std::shared_ptr;
using std::vector;
class TestSet {
public:
TestSet();
void run() const;
protected:
vector<shared_ptr<Test>> tests;
};
};
namespace h3d {
class Test1 : public Test {
public:
virtual void run() const override;
};
};
////////////////////////////////////////////////////////////////////////////////
namespace h3d {
void Test1::run() const {
Vector<3> p{2, 2, 1}, q{1, -2, 0};
ASSERT(near(p.f[0], 2))
ASSERT(near(p.f[1], 2))
ASSERT(near(p.f[2], 1))
ASSERT(near(q.f[0], 1))
ASSERT(near(q.f[1], -2))
ASSERT(near(q.f[2], 0))
ASSERT(p * 2 == (Vector<3>{2 * 2.0, 2 * 2.0, 1 * 2.0}))
ASSERT(q * -3 == (Vector<3>{1 * -3.0, -2 * -3.0, 0 * -3.0}))
ASSERT(p / 2 == (Vector<3>{2 / 2.0, 2 / 2.0, 1 / 2.0}))
ASSERT(q / -3 == (Vector<3>{1 / -3.0, -2 / -3.0, 0 / -3.0}))
ASSERT(near(p.inpro(q), -2))
ASSERT(p.outpro(q) == (Vector<3>{2, 1, -6}))
ASSERT(p.project(q) == q * -2 / 5)
ASSERT(q.project(p) == p * -2 / 9)
}
};
#include <memory>
namespace h3d {
using std::shared_ptr;
TestSet::TestSet() {
this->tests.push_back(shared_ptr<Test>(new Test1));
}
void TestSet::run() const { for (auto iter : this->tests) iter->run(); }
};
#include <utility>
namespace h3d {
using std::move;
template <unsigned int N>
double Vector<N>::inpro(const Vector& rhs) const {
double res = 0;
// 対応する成分同士の積を求めて、合計する。
for (auto i = 0; i < N; i++) res += this->f[i] * rhs.f[i];
return res;
}
template <unsigned int N>
Vector<N> Vector<N>::operator *(const double& sca) const {
Vector<N> res;
// それぞれの成分にスカラー値を掛ける。
for (auto i = 0; i < N; i++) res.f[i] = this->f[i] * sca;
return move(res);
}
template <unsigned int N>
Vector<N> Vector<N>::operator /(const double& sca) const {
Vector<N> res;
// それぞれの成分をスカラー値で割る。
for (auto i = 0; i < N; i++) res.f[i] = this->f[i] / sca;
return move(res);
}
template <unsigned int N>
bool Vector<N>::operator ==(const Vector& vec) const {
bool res = true;
if (&vec != this) {
// すべての対応する成分が近ければ等価と判定する。
for (auto i = 0; i < N; i++) {
if (!near(this->f[i], vec.f[i])) {
res = false;
break;
}
}
}
return res;
}
template <>
Vector<3> Vector<3>::outpro(const Vector<3>& rhs) const {
// それぞれの成分について、対応する列を除いた2×2の行列式を計算する。
// P×Q = < Py・Qz - Pz・Qy, Pz・Qx - Px・Qz, Px・Qy - Py・Qx >
return move(Vector<3>{
this->f[1] * rhs.f[2] - this->f[2] * rhs.f[1],
this->f[2] * rhs.f[0] - this->f[0] * rhs.f[2],
this->f[0] * rhs.f[1] - this->f[1] * rhs.f[0],
});
}
template <unsigned int N>
Vector<N> Vector<N>::project(const Vector& vec) const {
// PをQ上に射影した結果は次式で与えられる。
// P・Q
// -----・Q
// |Q|^2
return move(vec * inpro(vec) / vec.inpro(vec));
}
};
namespace h3d {
inline bool near(const double& x, const double& y) {
static const double NEAR_THRESHOLD = 0.0000001;
double dif = x - y;
return dif > -NEAR_THRESHOLD && dif < NEAR_THRESHOLD;
}
};
#include <iostream>
#include <string>
namespace h3d {
using std::cout;
using std::endl;
using std::string;
inline void assert(const string& pred_str, const bool& pred_res) throw(string) {
if (pred_res) cout << "アサート成功: " << pred_str << endl;
else throw "アサート失敗: " + pred_str;
}
};
#include <iostream>
#include <string>
int main() {
using std::cerr;
using std::endl;
using std::string;
try {
h3d::TestSet().run();
}
catch (const string& msg) {
cerr << msg << endl;
return 1;
}
return 0;
}