fork download
  1.  
  2. namespace h3d {
  3. /**
  4. * N次元ベクトルクラス。
  5. * @param N ベクトルの次元数。
  6. */
  7. template <unsigned int N>
  8. class Vector {
  9. public:
  10. /** 成分の配列。N個。 */
  11. double f[N];
  12.  
  13. /**
  14. * すべての成分をゼロクリアする。
  15. */
  16. void clear();
  17.  
  18. /**
  19. * 二つのベクトルの内積を計算する。
  20. * @param vec 右側のベクトル。
  21. * @return 計算した内積。
  22. */
  23. double inpro(const Vector& rhs) const;
  24.  
  25. /**
  26. * 二つのベクトルが不等価かどうかを判定する。
  27. * @param vec 別のベクトル。
  28. * @return 不等価ならtrue, 不等価ではないならfalse。
  29. */
  30. bool operator !=(const Vector& vec) const;
  31.  
  32. /**
  33. * スカラー値で乗算する。
  34. * @param sca 乗数となるスカラー値。
  35. * @return 乗算したベクトル。
  36. */
  37. Vector operator *(const double& sca) const;
  38.  
  39. /**
  40. * スカラー値で乗算して、代入する。
  41. * @param sca 乗数となるスカラー値。
  42. * @return 代入したベクトル。
  43. */
  44. Vector& operator *=(const double& sca);
  45.  
  46. /**
  47. * 二つのベクトルを加算する。
  48. * @param rhs 右側のベクトル。
  49. * @return 加算したベクトル。
  50. */
  51. Vector operator +(const Vector& rhs) const;
  52.  
  53. /**
  54. * ベクトルを加算して、代入する。
  55. * @param rhs 右側のベクトル。
  56. * @return 代入したベクトル。
  57. */
  58. Vector& operator +=(const Vector& rhs);
  59.  
  60. /**
  61. * すべての成分の符号を反転する。
  62. * @return 符号を反転したベクトル。
  63. */
  64. Vector operator -() const;
  65.  
  66. /**
  67. * 二つのベクトルを減算する。
  68. * @param rhs 右側のベクトル。
  69. * @return 減算したベクトル。
  70. */
  71. Vector operator -(const Vector& rhs) const;
  72.  
  73. /**
  74. * ベクトルを減算して、代入する。
  75. * @param rhs 右側のベクトル。
  76. * @return 代入したベクトル。
  77. */
  78. Vector& operator -=(const Vector& rhs);
  79.  
  80. /**
  81. * スカラー値で除算する。
  82. * @param sca 除数となるスカラー値。
  83. * @return 除算したベクトル。
  84. */
  85. Vector operator /(const double& sca) const;
  86.  
  87. /**
  88. * スカラー値で除算して、代入する。
  89. * @param sca 除数となるスカラー値。
  90. * @return 代入したベクトル。
  91. */
  92. Vector& operator /=(const double& sca);
  93.  
  94. /**
  95. * 二つのベクトルが等価かどうかを判定する。
  96. * @param vec 別のベクトル。
  97. * @return 等価ならtrue, 等価ではないならfalse。
  98. */
  99. bool operator ==(const Vector& vec) const;
  100.  
  101. /**
  102. * 基底を直交化する。
  103. * @param vecs 直交化する基底。
  104. */
  105. static void ortho(Vector<N>* vecs);
  106.  
  107. /**
  108. * 二つのベクトルの外積を計算する。
  109. * @param vec 右側のベクトル。
  110. * @return 計算した外積。
  111. */
  112. Vector outpro(const Vector& rhs) const;
  113.  
  114. /**
  115. * 別のベクトルに対する垂直成分を計算する。
  116. * @param vec このベクトルに対する垂直成分を計算する。
  117. * @return 計算した垂直成分。
  118. */
  119. Vector perp(const Vector& vec) const;
  120.  
  121. /**
  122. * 別のベクトルに射影する。
  123. * @param vec このベクトル上に射影する。
  124. * @return 射影したベクトル。
  125. */
  126. Vector project(const Vector& vec) const;
  127. };
  128.  
  129. /**
  130. * 二つの3次元ベクトルの外積を計算する。3次元ベクトル専用。
  131. * @param rhs 右側のベクトル。
  132. * @return 計算した外積。
  133. */
  134. template <>
  135. Vector<3> Vector<3>::outpro(const Vector<3>& rhs) const;
  136. };
  137.  
  138. namespace h3d {
  139. /**
  140. * 二つの数が近いかどうかを判定する。
  141. * @param x 一つ目の数。
  142. * @param y 二つ目の数。
  143. * @return 近いならtrue, 遠いならfalse。
  144. */
  145. inline bool near(const double& x, const double& y);
  146. };
  147.  
  148. #include <iostream>
  149. #include <string>
  150.  
  151. namespace h3d {
  152. using std::cout;
  153. using std::endl;
  154. using std::string;
  155.  
  156. #define ASSERT(pred) assert(#pred, (pred));
  157.  
  158. #define DEBUG_PRINT(val) cout << #val << "=" << (val) << endl;
  159.  
  160. /**
  161. * アサーションを実行する。
  162. * 成功なら標準出力に結果を出力する。
  163. * @param pred_str 判定する式を表した文字列。
  164. * @param pred_res 判定結果。trueなら成功,falseなら失敗と判定する。
  165. * @throw string 失敗ならメッセージをスローする。
  166. */
  167. inline void assert(const string& pred_str, const bool& pred_res) throw(string);
  168. };
  169.  
  170. namespace h3d {
  171. class Test { public: virtual void run() const = 0; };
  172. };
  173.  
  174. namespace h3d {
  175. class Test1 : public Test {
  176. public:
  177. virtual void run() const override;
  178. };
  179. };
  180.  
  181. #include <memory>
  182. #include <vector>
  183.  
  184. namespace h3d {
  185. using std::shared_ptr;
  186. using std::vector;
  187.  
  188. class TestSet {
  189. public:
  190. TestSet();
  191. void run() const;
  192. protected:
  193. vector<shared_ptr<Test>> tests;
  194. };
  195. };
  196.  
  197. ////////////////////////////////////////////////////////////////////////////////
  198.  
  199. #include <cmath>
  200.  
  201. namespace h3d {
  202. using std::sqrt;
  203.  
  204. void Test1::run() const {
  205. Vector<3> p{2.0, 2.0, 1.0}, q{1.0, -2.0, 0.0};
  206. ASSERT(near(p.f[0], 2.0))
  207. ASSERT(near(p.f[1], 2.0))
  208. ASSERT(near(p.f[2], 1.0))
  209. ASSERT(near(q.f[0], 1.0))
  210. ASSERT(near(q.f[1], -2.0))
  211. ASSERT(near(q.f[2], 0.0))
  212. ASSERT(p == (Vector<3>{2.0, 2.0, 1.0}))
  213. ASSERT(q == (Vector<3>{1.0, -2.0, 0.0}))
  214. ASSERT(p != (Vector<3>{1.0, -2.0, 0.0}))
  215. ASSERT(q != (Vector<3>{2.0, 2.0, 1.0}))
  216. ASSERT(-p == (Vector<3>{-2.0, -2.0, -1.0}))
  217. ASSERT(-q == (Vector<3>{-1.0, 2.0, 0.0}))
  218. ASSERT(p * 2.0 == (Vector<3>{4.0, 4.0, 2.0}))
  219. ASSERT(q * -3.0 == (Vector<3>{-3.0, 6.0, 0.0}))
  220. ASSERT(p / 2.0 == (Vector<3>{1.0, 1.0, 0.5}))
  221. ASSERT(q / -3.0 == (Vector<3>{1.0 / -3.0, -2.0 / -3.0, 0.0}))
  222. ASSERT(p + q == (Vector<3>{3.0, 0.0, 1.0}))
  223. ASSERT(q + p == (Vector<3>{3.0, 0.0, 1.0}))
  224. ASSERT(p - q == (Vector<3>{1.0, 4.0, 1.0}))
  225. ASSERT(q - p == (Vector<3>{-1.0, -4.0, -1.0}))
  226. Vector<3> r = p;
  227. ASSERT((r *= 3.0) == (Vector<3>{6.0, 6.0, 3.0}))
  228. ASSERT((r /= -2.0) == (Vector<3>{-3.0, -3.0, -1.5}))
  229. ASSERT((r += (Vector<3>{5.0, -1.0, 0.0})) == (Vector<3>{2.0, -4.0, -1.5}))
  230. ASSERT((r -= (Vector<3>{0.0, -2.0, 4.0})) == (Vector<3>{2.0, -2.0, -5.5}))
  231. ASSERT(near(p.inpro(q), -2.0))
  232. ASSERT(p.outpro(q) == (Vector<3>{2.0, 1.0, -6.0}))
  233. ASSERT(p.project(q) == (Vector<3>{-0.4, 0.8, 0.0}))
  234. ASSERT(q.project(p) == (Vector<3>{-4.0 / 9.0, -4.0 / 9.0, -2.0 / 9.0}))
  235. ASSERT(p.perp(q) == (Vector<3>{2.4, 1.2, 1.0}))
  236. ASSERT(q.perp(p) == (Vector<3>{1.0 + 4.0 / 9.0, -2.0 + 4.0 / 9.0, 2.0 / 9.0}))
  237. Vector<3> e[3] = {
  238. {sqrt(2.0) / 2.0, sqrt(2.0) / 2.0, 0.0},
  239. {-1.0, 1.0, -1.0},
  240. {0.0, -2.0, -2.0},
  241. };
  242. Vector<3>::ortho(e);
  243. ASSERT(e[0] == (Vector<3>{sqrt(2.0) / 2.0, sqrt(2.0) / 2.0, 0.0}))
  244. ASSERT(e[1] == (Vector<3>{-1.0, 1.0, -1.0}))
  245. ASSERT(e[2] == (Vector<3>{1.0, -1.0, -2.0}))
  246. }
  247. };
  248.  
  249. #include <memory>
  250.  
  251. namespace h3d {
  252. using std::shared_ptr;
  253.  
  254. TestSet::TestSet() {
  255. this->tests.push_back(shared_ptr<Test>(new Test1));
  256. }
  257.  
  258. void TestSet::run() const { for (auto iter : this->tests) iter->run(); }
  259. };
  260.  
  261. #include <utility>
  262.  
  263. namespace h3d {
  264. using std::move;
  265.  
  266. template <unsigned int N>
  267. void Vector<N>::clear() {
  268. for (auto i = 0; i < N; i++) this->f[i] = 0.0;
  269. }
  270.  
  271. template <unsigned int N>
  272. double Vector<N>::inpro(const Vector& rhs) const {
  273. double res = 0;
  274. // 対応する成分同士の積を求めて、合計する。
  275. for (auto i = 0; i < N; i++) res += this->f[i] * rhs.f[i];
  276. return res;
  277. }
  278.  
  279. template <unsigned int N>
  280. bool Vector<N>::operator !=(const Vector& vec) const {
  281. return !operator ==(vec);
  282. }
  283.  
  284. template <unsigned int N>
  285. Vector<N> Vector<N>::operator *(const double& sca) const {
  286. Vector<N> res;
  287. // それぞれの成分にスカラー値を掛ける。
  288. for (auto i = 0; i < N; i++) res.f[i] = this->f[i] * sca;
  289. return move(res);
  290. }
  291.  
  292. template <unsigned int N>
  293. Vector<N>& Vector<N>::operator *=(const double& sca) {
  294. // それぞれの成分にスカラー値を掛ける。
  295. for (auto i = 0; i < N; i++) this->f[i] *= sca;
  296. return *this;
  297. }
  298.  
  299. template <unsigned int N>
  300. Vector<N> Vector<N>::operator +(const Vector& rhs) const {
  301. Vector<N> res;
  302. // 対応する成分同士で加算する。
  303. for (auto i = 0; i < N; i++) res.f[i] = this->f[i] + rhs.f[i];
  304. return move(res);
  305. }
  306.  
  307. template <unsigned int N>
  308. Vector<N>& Vector<N>::operator +=(const Vector& rhs) {
  309. // 対応する成分同士で加算する。
  310. for (auto i = 0; i < N; i++) this->f[i] += rhs.f[i];
  311. return *this;
  312. }
  313.  
  314. template <unsigned int N>
  315. Vector<N> Vector<N>::operator -() const {
  316. Vector<N> res;
  317. // すべての成分の符号を反転する。
  318. for (auto i = 0; i < N; i++) res.f[i] = -this->f[i];
  319. return move(res);
  320. }
  321.  
  322. template <unsigned int N>
  323. Vector<N> Vector<N>::operator -(const Vector& rhs) const {
  324. Vector<N> res;
  325. // 対応する成分同士で減算する。
  326. for (auto i = 0; i < N; i++) res.f[i] = this->f[i] - rhs.f[i];
  327. return move(res);
  328. }
  329.  
  330. template <unsigned int N>
  331. Vector<N>& Vector<N>::operator -=(const Vector& rhs) {
  332. // 対応する成分同士で減算する。
  333. for (auto i = 0; i < N; i++) this->f[i] -= rhs.f[i];
  334. return *this;
  335. }
  336.  
  337. template <unsigned int N>
  338. Vector<N> Vector<N>::operator /(const double& sca) const {
  339. Vector<N> res;
  340. // それぞれの成分をスカラー値で割る。
  341. for (auto i = 0; i < N; i++) res.f[i] = this->f[i] / sca;
  342. return move(res);
  343. }
  344.  
  345. template <unsigned int N>
  346. Vector<N>& Vector<N>::operator /=(const double& sca) {
  347. // それぞれの成分をスカラー値で割る。
  348. for (auto i = 0; i < N; i++) this->f[i] /= sca;
  349. return *this;
  350. }
  351.  
  352. template <unsigned int N>
  353. bool Vector<N>::operator ==(const Vector& vec) const {
  354. bool res = true;
  355. if (&vec != this) {
  356. // すべての対応する成分が近ければ等価と判定する。
  357. for (auto i = 0; i < N; i++) {
  358. if (!near(this->f[i], vec.f[i])) {
  359. res = false;
  360. break;
  361. }
  362. }
  363. }
  364. return res;
  365. }
  366.  
  367. template <unsigned int N>
  368. void Vector<N>::ortho(Vector<N>* vecs) {
  369. // グラム・シュミットの直交化法。
  370. for (auto i = 2; i < N; i++) {
  371. Vector<N> sum;
  372. sum.clear();
  373. for (auto j = 0; j < i; j++) sum += vecs[i].project(vecs[j]);
  374. vecs[i] -= sum;
  375. }
  376. }
  377.  
  378. template <>
  379. Vector<3> Vector<3>::outpro(const Vector<3>& rhs) const {
  380. // それぞれの成分について、対応する列を除いた2×2の行列式を計算する。
  381. // P×Q = < Py・Qz - Pz・Qy, Pz・Qx - Px・Qz, Px・Qy - Py・Qx >
  382. return move(Vector<3>{
  383. this->f[1] * rhs.f[2] - this->f[2] * rhs.f[1],
  384. this->f[2] * rhs.f[0] - this->f[0] * rhs.f[2],
  385. this->f[0] * rhs.f[1] - this->f[1] * rhs.f[0],
  386. });
  387. }
  388.  
  389. template <unsigned int N>
  390. Vector<N> Vector<N>::perp(const Vector& vec) const {
  391. // 元のベクトルから、投影したベクトルを引けば、垂直成分が残る。
  392. return move(*this - project(vec));
  393. }
  394.  
  395. template <unsigned int N>
  396. Vector<N> Vector<N>::project(const Vector& vec) const {
  397. // PをQ上に射影した結果は次式で与えられる。
  398. // P・Q
  399. // -----・Q
  400. // |Q|^2
  401. return move(vec * inpro(vec) / vec.inpro(vec));
  402. }
  403. };
  404.  
  405. namespace h3d {
  406. inline bool near(const double& x, const double& y) {
  407. static const double THRESHOLD = 0.0000001;
  408. double dif = x - y;
  409. return dif > -THRESHOLD && dif < THRESHOLD;
  410. }
  411. };
  412.  
  413. #include <iostream>
  414. #include <string>
  415.  
  416. namespace h3d {
  417. using std::cout;
  418. using std::endl;
  419. using std::string;
  420.  
  421. inline void assert(const string& pred_str, const bool& pred_res) throw(string) {
  422. if (pred_res) cout << "アサート成功: " << pred_str << endl;
  423. else throw "アサート失敗: " + pred_str;
  424. }
  425. };
  426.  
  427. #include <iostream>
  428. #include <string>
  429.  
  430. int main() {
  431. using std::cerr;
  432. using std::endl;
  433. using std::string;
  434.  
  435. try {
  436. h3d::TestSet().run();
  437. }
  438. catch (const string& msg) {
  439. cerr << msg << endl;
  440. return 1;
  441. }
  442. return 0;
  443. }
  444.  
Success #stdin #stdout 0s 3496KB
stdin
Standard input is empty
stdout
アサート成功: near(p.f[0], 2.0)
アサート成功: near(p.f[1], 2.0)
アサート成功: near(p.f[2], 1.0)
アサート成功: near(q.f[0], 1.0)
アサート成功: near(q.f[1], -2.0)
アサート成功: near(q.f[2], 0.0)
アサート成功: p == (Vector<3>{2.0, 2.0, 1.0})
アサート成功: q == (Vector<3>{1.0, -2.0, 0.0})
アサート成功: p != (Vector<3>{1.0, -2.0, 0.0})
アサート成功: q != (Vector<3>{2.0, 2.0, 1.0})
アサート成功: -p == (Vector<3>{-2.0, -2.0, -1.0})
アサート成功: -q == (Vector<3>{-1.0, 2.0, 0.0})
アサート成功: p * 2.0 == (Vector<3>{4.0, 4.0, 2.0})
アサート成功: q * -3.0 == (Vector<3>{-3.0, 6.0, 0.0})
アサート成功: p / 2.0 == (Vector<3>{1.0, 1.0, 0.5})
アサート成功: q / -3.0 == (Vector<3>{1.0 / -3.0, -2.0 / -3.0, 0.0})
アサート成功: p + q == (Vector<3>{3.0, 0.0, 1.0})
アサート成功: q + p == (Vector<3>{3.0, 0.0, 1.0})
アサート成功: p - q == (Vector<3>{1.0, 4.0, 1.0})
アサート成功: q - p == (Vector<3>{-1.0, -4.0, -1.0})
アサート成功: (r *= 3.0) == (Vector<3>{6.0, 6.0, 3.0})
アサート成功: (r /= -2.0) == (Vector<3>{-3.0, -3.0, -1.5})
アサート成功: (r += (Vector<3>{5.0, -1.0, 0.0})) == (Vector<3>{2.0, -4.0, -1.5})
アサート成功: (r -= (Vector<3>{0.0, -2.0, 4.0})) == (Vector<3>{2.0, -2.0, -5.5})
アサート成功: near(p.inpro(q), -2.0)
アサート成功: p.outpro(q) == (Vector<3>{2.0, 1.0, -6.0})
アサート成功: p.project(q) == (Vector<3>{-0.4, 0.8, 0.0})
アサート成功: q.project(p) == (Vector<3>{-4.0 / 9.0, -4.0 / 9.0, -2.0 / 9.0})
アサート成功: p.perp(q) == (Vector<3>{2.4, 1.2, 1.0})
アサート成功: q.perp(p) == (Vector<3>{1.0 + 4.0 / 9.0, -2.0 + 4.0 / 9.0, 2.0 / 9.0})
アサート成功: e[0] == (Vector<3>{sqrt(2.0) / 2.0, sqrt(2.0) / 2.0, 0.0})
アサート成功: e[1] == (Vector<3>{-1.0, 1.0, -1.0})
アサート成功: e[2] == (Vector<3>{1.0, -1.0, -2.0})