fork download
  1. namespace h3d {
  2. /** 使用する浮動小数点数型。 */
  3. using FLOAT = double;
  4.  
  5. /**
  6. * 二つの数が近いかどうかを判定する。
  7. * @param lhs 左側(Left Hand Side)の数。
  8. * @param rhs 右側(Right Hand Side)の数。
  9. * @return 近いならtrue, 遠いならfalse。
  10. */
  11. template<typename X>
  12. inline bool nearEqual(const X& lhs, const X& rhs);
  13. };
  14.  
  15. #include <iostream>
  16.  
  17. namespace h3d {
  18. using std::ostream;
  19.  
  20. /**
  21. * N次元ベクトルクラス。
  22. * @param N ベクトルの次元数。
  23. * @param C 成分(Component)の型。省略ならFLOAT。
  24. * この型で実体化したnearEqualを使う。
  25. */
  26. template<unsigned int N, typename C = FLOAT>
  27. class Vector {
  28. public:
  29. /** 成分(Component)の配列。N個。 */
  30. C c[N];
  31.  
  32. /**
  33. * 各成分をゼロクリアする。
  34. */
  35. inline void clear();
  36.  
  37. /**
  38. * 次元を一つ拡張(EXTend)する。
  39. * @param ext_comp 追加する成分(COMPonent)。
  40. * @return 拡張したベクトル。
  41. */
  42. inline Vector<N + 1, C> ext(const C& ext_comp = 1.0) const;
  43.  
  44. /**
  45. * 内積(INner PROduct)を計算する。
  46. * @param rhs 右側(Right Hand Side)のベクトル。
  47. * @return 計算した内積。
  48. */
  49. inline C inpro(const Vector& rhs) const;
  50.  
  51. /**
  52. * 長さを取得する。
  53. * @return 取得した長さ。
  54. */
  55. inline double norm() const;
  56.  
  57. /**
  58. * 正規化し、長さを1にする。
  59. * @return 正規化したベクトル。
  60. */
  61. inline Vector normalize() const;
  62.  
  63. /**
  64. * 二つのベクトルが等しくないかどうかを判定する。
  65. * @param rhs 右側(Right Hand Side)のベクトル。
  66. * @return 等しくないならtrue, 等しいならfalse。
  67. */
  68. inline bool operator !=(const Vector& rhs) const;
  69.  
  70. /**
  71. * スカラー値で乗算する。
  72. * @param rhs 乗数となる右側(Right Hand Side)のスカラー値。
  73. * @return 乗算したベクトル。
  74. */
  75. inline Vector operator *(const C& rhs) const;
  76.  
  77. /**
  78. * スカラー値で乗算して、代入する。
  79. * @param rhs 乗数となる右側(Right Hand Side)のスカラー値。
  80. * @return 乗算して、代入したベクトル。
  81. */
  82. inline Vector& operator *=(const C& rhs);
  83.  
  84. /**
  85. * ベクトルを加算する。
  86. * @param rhs 加数となる右側(Right Hand Side)のベクトル。
  87. * @return 加算したベクトル。
  88. */
  89. inline Vector operator +(const Vector& rhs) const;
  90.  
  91. /**
  92. * ベクトルを加算して、代入する。
  93. * @param rhs 加数となる右側(Right Hand Side)のベクトル。
  94. * @return 加算して、代入したベクトル。
  95. */
  96. inline Vector& operator +=(const Vector& rhs);
  97.  
  98. /**
  99. * 各成分の符号を反転する。
  100. * @return 符号を反転したベクトル。
  101. */
  102. inline Vector operator -() const;
  103.  
  104. /**
  105. * ベクトルを減算する。
  106. * @param rhs 減数となる右側(Right Hand Side)のベクトル。
  107. * @return 減算したベクトル。
  108. */
  109. inline Vector operator -(const Vector& rhs) const;
  110.  
  111. /**
  112. * ベクトルを減算して、代入する。
  113. * @param rhs 減数となる右側(Right Hand Side)のベクトル。
  114. * @return 減算して、代入したベクトル。
  115. */
  116. inline Vector& operator -=(const Vector& rhs);
  117.  
  118. /**
  119. * スカラー値で除算する。
  120. * @param rhs 除数となる右側(Right Hand Side)のスカラー値。
  121. * @return 除算したベクトル。
  122. */
  123. inline Vector operator /(const C& rhs) const;
  124.  
  125. /**
  126. * スカラー値で除算して、代入する。
  127. * @param rhs 除数となる右側(Right Hand Side)のスカラー値。
  128. * @return 除算して、代入したベクトル。
  129. */
  130. inline Vector& operator /=(const C& rhs);
  131.  
  132. /**
  133. * 二つのベクトルが等しいかどうかを判定する。
  134. * @param rhs 右側(Right Hand Side)のベクトル
  135. * @return 等しいならtrue, 等しくないならfalse。
  136. */
  137. inline bool operator ==(const Vector& rhs) const;
  138.  
  139. /**
  140. * 3次元ベクトルの外積(OUTer PROduct)を計算する。
  141. * @param rhs 右側(Right Hand Side)のベクトル。
  142. * @return 計算した外積。
  143. */
  144. inline Vector outpro(const Vector& rhs) const;
  145.  
  146. /**
  147. * 次元を一つ切り縮める(TRUNCate)。
  148. * @return 切り縮めたベクトル。
  149. */
  150. inline Vector<N - 1, C> trunc() const;
  151.  
  152. /**
  153. * ゼロベクトルを取得する。
  154. * @return 取得したゼロベクトル。
  155. */
  156. static constexpr Vector ZERO();
  157. };
  158.  
  159. /**
  160. * N次元ベクトルを出力する。
  161. * @param N ベクトルの次元数。
  162. * @param C 成分(Component)の型。
  163. * @param out 出力先となるストリーム。
  164. * @param vec 出力するベクトル。
  165. * @return 出力したストリーム。
  166. */
  167. template<unsigned int N, typename C>
  168. inline ostream& operator <<(ostream& out, const Vector<N, C>& vec);
  169.  
  170. /** 浮動小数点数の2次元ゼロベクトル。 */
  171. template<>
  172. constexpr Vector<2> Vector<2>::ZERO() {
  173. return Vector<2>{0.0, 0.0};
  174. }
  175.  
  176. /** 浮動小数点数の3次元ゼロベクトル。 */
  177. template<>
  178. constexpr Vector<3> Vector<3>::ZERO() {
  179. return Vector<3>{0.0, 0.0, 0.0};
  180. }
  181.  
  182. /** 浮動小数点数の4次元ゼロベクトル。 */
  183. template<>
  184. constexpr Vector<4> Vector<4>::ZERO() {
  185. return Vector<4>{0.0, 0.0, 0.0, 0.0};
  186. }
  187. };
  188.  
  189. #include <iostream>
  190. #include <string>
  191. #include <tuple>
  192.  
  193. namespace h3d {
  194. using std::ostream;
  195. using std::string;
  196. using std::tuple;
  197.  
  198. /**
  199. * N次多項式クラス。
  200. * 0次(定数項)からN次までのN + 1個の係数を格納する。
  201. * 例) 3x^2 - 2x + 4 → c[0] = 4, c[1] = -2, c[2] = 3
  202. * @param N 多項式の次数。項の数より一つ小さい。
  203. * @param C 係数(Coefficient)の型。省略ならFLOAT。
  204. * この型で実体化したnearEqualを使う。
  205. */
  206. template<unsigned int N, typename C = FLOAT>
  207. class PolyExp {
  208. public:
  209. /** 各項の係数(Coefficient)を格納する N + 1 次元ベクトル。成分のインデックスが次数に対応する。 */
  210. Vector<N + 1, C> c;
  211.  
  212. /**
  213. * 多項式を作る。
  214. */
  215. inline PolyExp() = default;
  216.  
  217. /**
  218. * 係数ベクトルから多項式を作る。
  219. * @param coef_vec 係数ベクトル(COEFficient VECtor)。
  220. * 定数項以外の係数はゼロクリアする。
  221. */
  222. inline explicit PolyExp(const Vector<N + 1, C>& coef_vec);
  223.  
  224. /**
  225. * 定数項の係数から多項式を作ることで、CからPolyExpへの型変換を行う。
  226. * @param const_coef 定数項の係数(COEFficient)。
  227. * 定数項以外の係数はゼロクリアする。
  228. */
  229. inline PolyExp(const C& const_coef);
  230.  
  231. /**
  232. * 二つの多項式が等しくないかどうかを判定する。
  233. * @param rhs 右側(Right Hand Side)の多項式。
  234. * @return 等しくないならtrue, 等しいならfalse。
  235. */
  236. inline bool operator !=(const PolyExp& rhs) const;
  237.  
  238. /**
  239. * スカラー値で乗算する。
  240. * @param rhs 乗数となる右側(Right Hand Side)のスカラー値。
  241. * @return 乗算した多項式。
  242. */
  243. inline PolyExp operator *(const C& rhs) const;
  244.  
  245. /**
  246. * 多項式で乗算する。
  247. * @param rhs 乗数となる右側(Right Hand Side)の多項式。
  248. * @return 乗算した多項式。
  249. */
  250. inline PolyExp operator *(const PolyExp& rhs) const throw(string);
  251.  
  252. /**
  253. * スカラー値で乗算して、代入する。
  254. * @param rhs 乗数となる右側(Right Hand Side)のスカラー値。
  255. * @return 乗算して、代入した多項式。
  256. */
  257. inline PolyExp& operator *=(const C& rhs);
  258.  
  259. /**
  260. * 多項式で乗算して、代入する。
  261. * @param rhs 乗数となる右側(Right Hand Side)のスカラー値。
  262. * @return 乗算して、代入した多項式。
  263. */
  264. inline PolyExp& operator *=(const PolyExp& rhs) throw(string);
  265.  
  266. /**
  267. * 多項式を加算する。
  268. * @param rhs 加数となる右側(Right Hand Side)の多項式。
  269. * @return 加算した多項式。
  270. */
  271. inline PolyExp operator +(const PolyExp& rhs) const;
  272.  
  273. /**
  274. * 多項式を加算して、代入する。
  275. * @param rhs 加数となる右側(Right Hand Side)の多項式。
  276. * @return 加算して、代入した多項式。
  277. */
  278. inline PolyExp& operator +=(const PolyExp& rhs);
  279.  
  280. /**
  281. * 各係数の符号を反転する。
  282. * @return 符号を反転した多項式。
  283. */
  284. inline PolyExp operator -() const;
  285.  
  286. /**
  287. * 多項式を減算する。
  288. * @param rhs 減数となる右側(Right Hand Side)の多項式。
  289. * @return 減算した多項式。
  290. */
  291. inline PolyExp operator -(const PolyExp& rhs) const;
  292.  
  293. /**
  294. * 多項式を減算して、代入する。
  295. * @param rhs 減数となる右側(Right Hand Side)の多項式。
  296. * @return 減算して、代入した多項式。
  297. */
  298. inline PolyExp& operator -=(const PolyExp& rhs);
  299.  
  300. /**
  301. * スカラー値で除算する。
  302. * @param rhs 除数となる右側(Right Hand Side)のスカラー値。
  303. * @return 除算した多項式。
  304. */
  305. inline PolyExp operator /(const C& rhs) const;
  306.  
  307. /**
  308. * スカラー値で除算して、代入する。
  309. * @param rhs 除数となる右側(Right Hand Side)のスカラー値。
  310. * @return 除算して、代入した多項式。
  311. */
  312. inline PolyExp& operator /=(const C& rhs);
  313.  
  314. /**
  315. * 二つの多項式が等しいかどうかを判定する。
  316. * @param rhs 右側(Right Hand Side)の多項式
  317. * @return 等しいならtrue, 等しくないならfalse。
  318. */
  319. inline bool operator ==(const PolyExp& rhs) const;
  320.  
  321. /**
  322. * 実数根(RooTS)を計算する。
  323. * @return 計算した実数根。昇順にソートされている。
  324. * 一つ目が実数根の個数。二つ目が実数根を格納したベクトル。
  325. */
  326. inline tuple<unsigned int, Vector<N, C>> rts() const;
  327. };
  328.  
  329. /**
  330. * 多項式の実数根を計算するクラス。
  331. * @param N 多項式の次数。
  332. * @param C 係数(Coefficient)の型。
  333. */
  334. template<unsigned int N, typename C>
  335. class PolyExpRoots {
  336. public:
  337. /** インスタンスを作ることはできない。 */
  338. PolyExpRoots() = delete;
  339.  
  340. /**
  341. * 多項式の実数根を計算する。
  342. * @param poly_exp 計算する多項式(POLYnominal EXPression)。
  343. * @return 計算した実数根。昇順にソートされている。
  344. * 一つ目が実数根の個数。二つ目が実数根を格納したベクトル。
  345. */
  346. inline static tuple<unsigned int, Vector<N, C>> calculate(const PolyExp<N, C>& poly_exp);
  347. };
  348.  
  349. /**
  350. * 2次多項式の実数根を計算するクラス。
  351. * @param C 係数(Coefficient)の型。
  352. */
  353. template<typename C>
  354. class PolyExpRoots<2, C> {
  355. public:
  356. /** インスタンスを作ることはできない。 */
  357. PolyExpRoots() = delete;
  358.  
  359. /**
  360. * 2次多項式の実数根を計算する。
  361. * @param poly_exp 計算する2次多項式(POLYnominal EXPression)。
  362. * @return 計算した実数根。昇順にソートされている。
  363. * 一つ目が実数根の個数。二つ目が実数根を格納したベクトル。
  364. */
  365. inline static tuple<unsigned int, Vector<2, C>> calculate(const PolyExp<2, C>& poly_exp);
  366. };
  367.  
  368. /**
  369. * 3次多項式の実数根を計算するクラス。
  370. * @param C 係数(Coefficient)の型。
  371. */
  372. template<typename C>
  373. class PolyExpRoots<3, C> {
  374. public:
  375. /** インスタンスを作ることはできない。 */
  376. PolyExpRoots() = delete;
  377.  
  378. /**
  379. * 3次多項式の実数根を計算する。
  380. * @param poly_exp 計算する3次多項式(POLYnominal EXPression)。
  381. * @return 計算した実数根。昇順にソートされている。
  382. * 一つ目が実数根の個数。二つ目が実数根を格納したベクトル。
  383. */
  384. inline static tuple<unsigned int, Vector<3, C>> calculate(const PolyExp<3, C>& poly_exp);
  385. };
  386.  
  387. /**
  388. * N次多項式を出力する。
  389. * @param N 多項式の次元数。
  390. * @param out 出力先となるストリーム。
  391. * @param poly_exp 出力する多項式。
  392. * @return 出力したストリーム。
  393. */
  394. template<unsigned int N, typename C>
  395. inline ostream& operator <<(ostream& out, const PolyExp<N, C>& poly_exp);
  396. };
  397.  
  398. namespace h3d {
  399. /**
  400. * polygonToTrianglesのラムダの説明用の関数型。
  401. * @param tri_vert1_ind 分割した三角形の一つ目の頂点インデックス。
  402. * @param tri_vert2_ind 分割した三角形の二つ目の頂点インデックス。
  403. * @param tri_vert3_ind 分割した三角形の三つ目の頂点インデックス。
  404. */
  405. using POLY2TRI_LAMBDA = void (*)(const unsigned int& tri_vert1_ind, const unsigned int& tri_vert2_ind, const unsigned int& tri_vert3_ind);
  406.  
  407. /** 原点。 */
  408. constexpr Vector<3> O_POINT{0.0, 0.0, 0.0};
  409. /** X軸。 */
  410. constexpr Vector<3> X_AXIS {1.0, 0.0, 0.0};
  411. /** Y軸。 */
  412. constexpr Vector<3> Y_AXIS {0.0, 1.0, 0.0};
  413. /** Z軸。 */
  414. constexpr Vector<3> Z_AXIS {0.0, 0.0, 1.0};
  415.  
  416. /**
  417. * 角度を弧度に変換する。
  418. * @param ang 変換する角度(ANGle)。
  419. * @return 変換した弧度。
  420. */
  421. inline FLOAT angleToRadian(const FLOAT& ang);
  422.  
  423. /**
  424. * 多角形を三角形に分割する。
  425. * @param poly_begin 多角形の始端の頂点インデックスを指す反復子。
  426. * @param poly_end 多角形の終端の頂点インデックスを指す反復子。
  427. * @param lambda 分割した三角形ごとに呼び出す{@link h3d::POLY2TRI_LAMBDA ラムダ}。
  428. */
  429. template<typename PI, typename L>
  430. inline void polygonToTriangles(PI poly_begin, PI poly_end, L lambda);
  431. };
  432.  
  433. #include <iostream>
  434. #include <string>
  435. #include <tuple>
  436.  
  437. namespace h3d {
  438. using std::ostream;
  439. using std::string;
  440. using std::tuple;
  441.  
  442. /**
  443. * N次元正方行列クラス。
  444. * @param N 行列の次元数。
  445. * @param C 成分(Component)の型。省略ならFLOAT。
  446. * この型で実体化したnearEqualを使う。
  447. */
  448. template<unsigned int N, typename C = FLOAT>
  449. class Matrix {
  450. public:
  451. /** 成分(Component)の配列。N×N個。 */
  452. C c[N][N];
  453.  
  454. /**
  455. * 各成分をゼロクリアする。
  456. */
  457. inline void clear();
  458.  
  459. /**
  460. * 行列式(DETerminant)を計算する。
  461. * @return 計算した行列式。
  462. */
  463. inline C det() const;
  464.  
  465. /**
  466. * 固有値(EIGenVALueS)を計算する。
  467. * @return 計算した固有値を格納したベクトル。昇順にソートされている。
  468. * @throw string 行列が非正則ならメッセージをスローする。
  469. */
  470. inline Vector<N, C> eigvals() const throw(string);
  471.  
  472. /**
  473. * 固有ベクトル(EIGenVECtorS)を計算する。
  474. * @return 計算した固有ベクトルを格納したベクトル。
  475. * 各固有ベクトルは正規化されている。
  476. * @throw string 行列が非正則ならメッセージをスローする。
  477. */
  478. inline Vector<N, Vector<N, C>> eigvecs() const throw(string);
  479.  
  480. /**
  481. * 次元を一つ拡張(EXTend)する。
  482. * @param ext_mat この行列(MATrix)から最後の行と列の成分をコピーする。
  483. * @return 拡張した行列。
  484. */
  485. inline Matrix<N + 1, C> ext(const Matrix<N + 1, C>& ext_mat = Matrix<N + 1, C>::IDENTITY()) const;
  486.  
  487. /**
  488. * 単位行列を取得する。
  489. * @return 単位行列。
  490. */
  491. static constexpr Matrix IDENTITY();
  492.  
  493. /**
  494. * 逆行列(INVerse matrix)を計算する。
  495. * @return 計算した逆行列。
  496. * @throw string 行列が非正則ならメッセージをスローする。
  497. */
  498. inline Matrix inv() const throw(string);
  499.  
  500. /**
  501. * 二つの行列が等しくないかどうかを判定する。
  502. * @param rhs 右側の行列。
  503. * @return 等しくないならtrue, 等しいならfalse。
  504. */
  505. inline bool operator !=(const Matrix& rhs) const;
  506.  
  507. /**
  508. * 行列で乗算する。
  509. * @param rhs 乗数となる右側(Right Hand Side)の行列。
  510. * @return 乗算した行列。
  511. */
  512. inline Matrix operator *(const Matrix& rhs) const;
  513.  
  514. /**
  515. * ベクトルで乗算する。
  516. * @param rhs 乗数となる右側(Right Hand Side)のベクトル。
  517. * @return 計算したベクトル。
  518. */
  519. inline Vector<N> operator *(const Vector<N>& rhs) const;
  520.  
  521. /**
  522. * スカラー値で乗算する。
  523. * @param rhs 乗数となる右側(Right Hand Side)のスカラー値。
  524. * @return 乗算した行列。
  525. */
  526. inline Matrix operator *(const C& rhs) const;
  527.  
  528. /**
  529. * 行列で乗算して、代入する。
  530. * @param rhs 乗数となる右側(Right Hand Side)の行列。
  531. * @return 乗算して、代入した行列。
  532. */
  533. inline Matrix operator *=(const Matrix& rhs);
  534.  
  535. /**
  536. * スカラー値で乗算して、代入する。
  537. * @param rhs 乗数となる右側(Right Hand Side)のスカラー値。
  538. * @return 乗算して、代入した行列。
  539. */
  540. inline Matrix operator *=(const C& rhs);
  541.  
  542. /**
  543. * 行列を加算する。
  544. * @param rhs 加数となる右側(Right Hand Side)の行列。
  545. * @return 加算した行列。
  546. */
  547. inline Matrix operator +(const Matrix& rhs) const;
  548.  
  549. /**
  550. * 行列を加算して、代入する。
  551. * @param rhs 加数となる右側(Right Hand Side)の行列。
  552. * @return 加算して、代入した行列。
  553. */
  554. inline Matrix operator +=(const Matrix& rhs);
  555.  
  556. /**
  557. * すべての成分の符号を反転する。
  558. * @return 符号を反転した行列。
  559. */
  560. inline Matrix operator -() const;
  561.  
  562. /**
  563. * 行列を減算する。
  564. * @param rhs 減数となる右側(Right Hand Side)の行列。
  565. * @return 減算した行列。
  566. */
  567. inline Matrix operator -(const Matrix& rhs) const;
  568.  
  569. /**
  570. * 行列を減算して、代入する。
  571. * @param rhs 減数となる右側(Right Hand Side)の行列。
  572. * @return 減算して、代入した行列。
  573. */
  574. inline Matrix operator -=(const Matrix& rhs);
  575.  
  576. /**
  577. * スカラー値で除算する。
  578. * @param rhs 除数となる右側(Right Hand Side)のスカラー値。
  579. * @return 除算した行列。
  580. */
  581. inline Matrix operator /(const C& rhs) const;
  582.  
  583. /**
  584. * スカラー値で除算して、代入する。
  585. * @param rhs 除数となる右側(Right Hand Side)のスカラー値。
  586. * @return 除算して、代入した行列。
  587. */
  588. inline Matrix operator /=(const C& rhs);
  589.  
  590. /**
  591. * 二つの行列が等しいかどうかを判定する。
  592. * @param rhs 右側(Right Hand Side)の行列。
  593. * @return 等しいならtrue, 等しくないならfalse。
  594. */
  595. inline bool operator ==(const Matrix& rhs) const;
  596.  
  597. /**
  598. * 被約形にする。連立1次方程式の解を計算するときに使う。
  599. * @param con_col 定数ベクトル。省略ならゼロベクトル。
  600. * @return 被約系にした行列と定数ベクトル。一つ目は行列, 二つ目は定数ベクトル。
  601. */
  602. inline tuple<Matrix, Vector<N, C>> reduce(const Vector<N, C>& con_col = Vector<N, C>::ZERO()) const;
  603.  
  604. /**
  605. * 行と列を取り除いて、小行列(SUBmatrix)を作る。
  606. * @param row 取り除く行。
  607. * @param col 取り除く列。
  608. * @return 作った行列。
  609. */
  610. inline Matrix<N - 1, C> sub(const unsigned int& row, const unsigned int& col) const;
  611.  
  612. /**
  613. * 次元を一つ切り縮める(TRUNCate)。
  614. * @return 切り縮めた行列。
  615. */
  616. inline Matrix<N - 1, C> trunc() const;
  617. };
  618.  
  619. /**
  620. * N次元正方行列式計算クラス。
  621. * @param N 行列の次元数。
  622. * @param C 成分(Component)の型。
  623. */
  624. template<unsigned int N, typename C>
  625. class MatrixDeterminant {
  626. public:
  627. /** インスタンスを作ることはできない。 */
  628. MatrixDeterminant() = delete;
  629.  
  630. /**
  631. * 行列式を計算する。
  632. * @param mat 計算する行列。
  633. * @return 計算した行列式。
  634. */
  635. inline static C calculate(const Matrix<N, C>& mat);
  636. };
  637.  
  638. /**
  639. * 2次元正方行列式計算クラス。
  640. * @param C 成分(Component)の型。
  641. */
  642. template<typename C>
  643. class MatrixDeterminant<2, C> {
  644. public:
  645. /** インスタンスを作ることはできない。 */
  646. MatrixDeterminant() = delete;
  647.  
  648. /**
  649. * 2次元正方行列式を計算する。
  650. * @param mat 計算する2次元行列。
  651. * @return 計算した行列式。
  652. */
  653. inline static C calculate(const Matrix<2, C>& mat);
  654. };
  655.  
  656. /**
  657. * N次元正方行列を出力する。
  658. * @param N 行列の次元数。
  659. * @param C 成分(Component)の型。
  660. * @param out 出力先となるストリーム。
  661. * @param mat 出力する行列。
  662. * @return 出力したストリーム。
  663. */
  664. template<unsigned int N, typename C>
  665. inline ostream& operator <<(ostream& out, const Matrix<N, C>& mat);
  666.  
  667. /** 浮動小数点数の2次元単位行列。 */
  668. template<>
  669. constexpr Matrix<2> Matrix<2>::IDENTITY() {
  670. return Matrix<2>{
  671. 1.0, 0.0,
  672. 0.0, 1.0,
  673. };
  674. }
  675.  
  676. /** 浮動小数点数の3次元単位行列。 */
  677. template<>
  678. constexpr Matrix<3> Matrix<3>::IDENTITY() {
  679. return Matrix<3>{
  680. 1.0, 0.0, 0.0,
  681. 0.0, 1.0, 0.0,
  682. 0.0, 0.0, 1.0,
  683. };
  684. }
  685.  
  686. /** 浮動小数点数の4次元単位行列。 */
  687. template<>
  688. constexpr Matrix<4> Matrix<4>::IDENTITY() {
  689. return Matrix<4>{
  690. 1.0, 0.0, 0.0, 0.0,
  691. 0.0, 1.0, 0.0, 0.0,
  692. 0.0, 0.0, 1.0, 0.0,
  693. 0.0, 0.0, 0.0, 1.0,
  694. };
  695. }
  696. };
  697.  
  698. namespace h3d {
  699. /**
  700. * 拡大・縮小行列を作る。
  701. * @param coef 各座標の係数(COEFficient)。
  702. * coef > 1.0 なら拡大, coef < 1.0 なら縮小。
  703. * @return 作った拡大・縮小行列。
  704. */
  705. Matrix<3> scaling(const Vector<3>& coef);
  706.  
  707. /**
  708. * 回転行列を作る。
  709. * @param axis この軸の周りを回転する。
  710. * @param rad 回転する弧度(RADian)。
  711. * @return 作った回転行列。
  712. */
  713. Matrix<3> rotation(const Vector<3>& axis, const FLOAT& rad);
  714.  
  715. /**
  716. * 平行移動行列を作る。
  717. * @param os 変換後の位置から変換前の位置を引いた差分(OffSet)。
  718. * @return 作った平行移動行列。
  719. */
  720. Matrix<4> translation(const Vector<3>& os);
  721.  
  722. /**
  723. * ビュー行列を作る。
  724. * ビュー行列はワールド空間からカメラ空間への変換を行う。
  725. * @param eye_pos 目の位置(POSition)。
  726. * @param cent_pt 視界の中央(CENTer)にある点(PoinT)。
  727. * @param up_dir 上方向(UP DIRection)。省略ならY軸。
  728. * @return 作ったビュー行列。
  729. */
  730. Matrix<4> view(const Vector<3>& eye_pos, const Vector<3>& cent_pt, const Vector<3>& up_dir = Y_AXIS);
  731.  
  732. /**
  733. * 透視射影行列を作る。
  734. * 透視射影行列はカメラ空間からクリップ空間への変換を行う。
  735. * @param hori_fov 水平視野角(HORIzontal Field Of View)。弧度。
  736. * @param asp_rat アスペクト比(ASPect RATio)。
  737. * @param near_dist 近平面までの距離(DISTance)。
  738. * @param far_dist 遠平面までの距離(DISTance)。
  739. */
  740. Matrix<4> perspectiveProjection(const double& hori_fov, const double& asp_rat, const double& near_dist, const double& far_dist);
  741. };
  742.  
  743. #include <iostream>
  744. #include <string>
  745.  
  746. namespace h3d {
  747. using std::cout;
  748. using std::endl;
  749. using std::string;
  750.  
  751. #define ASSERT(pred) assert(#pred, (pred));
  752.  
  753. #define PRINT(val) cout << #val << "=" << (val) << endl;
  754.  
  755. /**
  756. * アサーションを実行する。
  757. * 成功なら標準出力に結果を出力する。
  758. * @param pred_str 判定する述語(PREDicate)を記述した文字列(STRing)。
  759. * @param pred_res 判定する述語(PREDicate)の結果(RESult)。
  760. * trueなら成功,falseなら失敗と判定する。
  761. * @throw string 失敗ならメッセージをスローする。
  762. */
  763. inline void assert(const string& pred_str, const bool& pred_res) throw(string);
  764. };
  765.  
  766. #include <string>
  767.  
  768. namespace h3d {
  769. using std::string;
  770.  
  771. class Test { public: virtual void run() const throw(string) = 0; };
  772. };
  773.  
  774. #include <memory>
  775. #include <string>
  776. #include <vector>
  777.  
  778. namespace h3d {
  779. using std::shared_ptr;
  780. using std::string;
  781. using std::vector;
  782.  
  783. class TestSet {
  784. public:
  785. TestSet();
  786. void run() const throw(string);
  787. protected:
  788. vector<shared_ptr<Test>> tests;
  789. };
  790. };
  791.  
  792. #include <string>
  793.  
  794. namespace h3d {
  795. using std::string;
  796.  
  797. class Test2 : public Test {
  798. public:
  799. virtual void run() const throw(string) override;
  800. };
  801. };
  802.  
  803. #include <string>
  804.  
  805. namespace h3d {
  806. using std::string;
  807.  
  808. class Test5 : public Test {
  809. public:
  810. virtual void run() const throw(string) override;
  811. };
  812. };
  813.  
  814.  
  815. ////////////////////////////////////////////////////////////////////////////////
  816.  
  817. #include <iostream>
  818. #include <string>
  819.  
  820. namespace h3d {
  821. using std::cout;
  822. using std::endl;
  823. using std::string;
  824.  
  825. inline void assert(const string& pred_str, const bool& pred_res) throw(string) {
  826. if (pred_res) cout << "アサート成功: " << pred_str << endl;
  827. else throw "アサート失敗: " + pred_str;
  828. }
  829. };
  830.  
  831. namespace h3d {
  832. template<typename X>
  833. inline bool nearEqual(const X& lhs, const X& rhs) {
  834. return lhs == rhs;
  835. }
  836.  
  837. template<>
  838. inline bool nearEqual<FLOAT>(const FLOAT& lhs, const FLOAT& rhs) {
  839. static const FLOAT THRESHOLD = 0.00000000000001;
  840. FLOAT dif = lhs - rhs;
  841. return dif > -THRESHOLD && dif < THRESHOLD;
  842. }
  843. };
  844.  
  845. #include <cmath>
  846.  
  847. namespace h3d {
  848. inline FLOAT angleToRadian(const FLOAT& ang) { return M_PI * ang / 180.0; }
  849.  
  850. template<typename PI, typename L>
  851. inline void polygonToTriangles(PI poly_begin, PI poly_end, L lambda) {
  852. // アルゴリズムを示す。
  853. // 1. 始端から始める。
  854. // 2. 現在位置から二つ先が終端以上なら終了する。
  855. // 3. 始端なら、現在位置のものを一つ目の頂点インデックスとして、5に飛ぶ。
  856. // 4. 始端ではないなら、一つ前の位置のものを一つ目の頂点インデックスとする。
  857. // 5. 一つ次の位置に進んで、現在位置のものを二つ目の頂点インデックスとする。
  858. // 6. 一つ次の位置に進んで、現在位置のものを三つ目の頂点インデックスとする。
  859. // 7. ラムダを呼ぶ。
  860. // 8. 一つ前の位置に戻って、2に飛ぶ。
  861. for (auto iter = poly_begin; iter + 2 < poly_end;) {
  862. unsigned int tri_vert1_ind, tri_vert2_ind, tri_vert3_ind;
  863. if (iter == poly_begin) tri_vert1_ind = *iter;
  864. else tri_vert1_ind = *(iter - 1);
  865. tri_vert2_ind = *++iter;
  866. tri_vert3_ind = *(++iter)--;
  867. lambda(tri_vert1_ind, tri_vert2_ind, tri_vert3_ind);
  868. }
  869. }
  870. };
  871.  
  872. #include <algorithm>
  873. #include <iostream>
  874. #include <tuple>
  875. #include <utility>
  876.  
  877. namespace h3d {
  878. using std::fill;
  879. using std::get;
  880. using std::make_tuple;
  881. using std::swap;
  882. using std::tuple;
  883.  
  884. template<unsigned int N, typename C>
  885. inline void Matrix<N, C>::clear() {
  886. // 各成分をゼロクリアする。
  887. fill((C*)this->c, (C*)this->c + N * N, 0.0);
  888. }
  889.  
  890. template<unsigned int N, typename C>
  891. inline C Matrix<N, C>::det() const {
  892. return MatrixDeterminant<N, C>::calculate(*this);
  893. }
  894.  
  895. template<unsigned int N, typename C>
  896. inline Vector<N, C> Matrix<N, C>::eigvals() const throw(string) {
  897. // 特性多項式を作る。
  898. Matrix<N, PolyExp<N, C>> ch_mat;
  899. for (auto row = 0; row < N; row++) {
  900. for (auto col = 0; col < N; col++) {
  901. PolyExp<N, C> comp(this->c[row][col]);
  902. if (row == col) comp.c.c[1] = -1.0;
  903. ch_mat.c[row][col] = comp;
  904. }
  905. }
  906. PolyExp<N, C> ch_poly_exp(ch_mat.det());
  907. // 特性多項式の実数根を計算する。
  908. tuple<unsigned int, Vector<N, C>> rts = ch_poly_exp.rts();
  909. // 行列が非正則なら、N個の実数根を持たない(?)。
  910. if (get<0>(rts) < N) throw string("行列が非正則。");
  911. return get<1>(rts);
  912. }
  913.  
  914. template<unsigned int N, typename C>
  915. inline Vector<N, Vector<N, C>> Matrix<N, C>::eigvecs() const throw(string) {
  916. Vector<N, Vector<N, C>> res;
  917. // 固有値を計算する。
  918. Vector<N, C> eigvals_res(eigvals());
  919. // 固有値ごとに反復する。
  920. for (auto i = 0; i < N; i++) {
  921. // 被約係数行列を作る。
  922. Matrix rdc_coef_mat(*this);
  923. for (auto j = 0; j < N; j++) rdc_coef_mat.c[j][j] -= eigvals_res.c[i];
  924. rdc_coef_mat = get<0>(rdc_coef_mat.reduce());
  925.  
  926. // (M - λI)V = 0 を解く。
  927.  
  928. // 主対角成分ごとに反復する。
  929. for (auto j = 0; j < N; j++) {
  930. // 先導成分を含むならスキップする。
  931. if (!nearEqual(rdc_coef_mat.c[j][j], 0.0)) continue;
  932. // 固有ベクトルの成分ごとに反復する。
  933. for (auto k = 0; k < N; k++) {
  934. // 主対角に対応する成分は1、それ以外は対応する行の成分の符号を反転したもの。
  935. if (k == j) res.c[i].c[k] = 1.0;
  936. else res.c[i].c[k] = -rdc_coef_mat.c[k][j];
  937. }
  938. break;
  939. }
  940. // 正規化する。
  941. res.c[i] = res.c[i].normalize();
  942. }
  943. return res;
  944. }
  945.  
  946. template<unsigned int N, typename C>
  947. inline Matrix<N + 1, C> Matrix<N, C>::ext(const Matrix<N + 1, C>& ext_mat) const {
  948. Matrix<N + 1, C> res;
  949. // 結果の各成分ごとに反復する。
  950. for (auto row = 0; row < N + 1; row++) {
  951. for (auto col = 0; col < N + 1; col++) {
  952. // 行と列がN以内ならこの行列, それ以外なら引数の行列から成分をコピーする。
  953. if (row < N && col < N) res.c[row][col] = this->c[row][col];
  954. else res.c[row][col] = ext_mat.c[row][col];
  955. }
  956. }
  957. return res;
  958. }
  959.  
  960. template<unsigned int N, typename C>
  961. inline Matrix<N, C> Matrix<N, C>::inv() const throw(string) {
  962. // まず行列式を計算し、正則であることを確かめる。
  963. C det_res = det();
  964. if (nearEqual(det_res, 0.0)) throw string("行列が非正則。");
  965. // 行列式の逆数を計算しておく。
  966. C inv_det = 1.0 / det_res;
  967. Matrix<N, C> res;
  968. // 各成分ごとに反復する。
  969. for (auto row = 0; row < N; row++) {
  970. for (auto col = 0; col < N; col++) {
  971. // 行列式の逆数に、対角の小行列式を乗算する。
  972. res.c[row][col] = inv_det * sub(col, row).det();
  973. // (-1)^(row + col)
  974. if (((row + col) & 0x1) == 1)
  975. res.c[row][col] = -res.c[row][col];
  976. }
  977. }
  978. return res;
  979. }
  980.  
  981. template<unsigned int N, typename C>
  982. inline bool Matrix<N, C>::operator !=(const Matrix& rhs) const {
  983. return !operator ==(rhs);
  984. }
  985.  
  986. template<unsigned int N, typename C>
  987. inline Matrix<N, C> Matrix<N, C>::operator *(const Matrix& rhs) const {
  988. Matrix<N, C> res;
  989. // 結果の各成分ごとに反復する。
  990. for (auto row = 0; row < N; row++) {
  991. for (auto col = 0; col < N; col++) {
  992. res.c[row][col] = 0.0;
  993. // 左側は対応する行の各成分, 右側は対応する列の各成分ごとに反復して、乗算する。
  994. for (auto i = 0; i < N; i++)
  995. res.c[row][col] += this->c[row][i] * rhs.c[i][col];
  996. }
  997. }
  998. return res;
  999. }
  1000.  
  1001. template<unsigned int N, typename C>
  1002. inline Vector<N> Matrix<N, C>::operator *(const Vector<N>& rhs) const {
  1003. Vector<N> res;
  1004. // ベクトルの各成分ごとに反復する。
  1005. for (auto i = 0; i < N; i++) {
  1006. res.c[i] = 0.0;
  1007. // 左側の行列は、対応する行の各成分ごとに反復して、乗算する。
  1008. for (auto j = 0; j < N; j++)
  1009. res.c[i] += this->c[i][j] * rhs.c[j];
  1010. }
  1011. return res;
  1012. }
  1013.  
  1014. template<unsigned int N, typename C>
  1015. inline Matrix<N, C> Matrix<N, C>::operator *(const C& rhs) const {
  1016. Matrix<N, C> res;
  1017. // 各成分にスカラー値を乗算する。
  1018. for (auto row = 0; row < N; row++) {
  1019. for (auto col = 0; col < N; col++)
  1020. res.c[row][col] = this->c[row][col] * rhs;
  1021. }
  1022. return res;
  1023. }
  1024.  
  1025. template<unsigned int N, typename C>
  1026. inline Matrix<N, C> Matrix<N, C>::operator *=(const Matrix& rhs) {
  1027. return *this = operator *(rhs);
  1028. }
  1029.  
  1030. template<unsigned int N, typename C>
  1031. inline Matrix<N, C> Matrix<N, C>::operator *=(const C& rhs) {
  1032. return *this = operator *(rhs);
  1033. }
  1034.  
  1035. template<unsigned int N, typename C>
  1036. inline Matrix<N, C> Matrix<N, C>::operator +(const Matrix& rhs) const {
  1037. Matrix<N, C> res;
  1038. // 対応する成分同士で加算する。
  1039. for (auto row = 0; row < N; row++) {
  1040. for (auto col = 0; col < N; col++)
  1041. res.c[row][col] = this->c[row][col] + rhs.c[row][col];
  1042. }
  1043. return res;
  1044. }
  1045.  
  1046. template<unsigned int N, typename C>
  1047. inline Matrix<N, C> Matrix<N, C>::operator +=(const Matrix& rhs) {
  1048. return *this = operator +(rhs);
  1049. }
  1050.  
  1051. template<unsigned int N, typename C>
  1052. inline Matrix<N, C> Matrix<N, C>::operator -() const {
  1053. Matrix<N, C> res;
  1054. // 各成分の符号を反転する。
  1055. for (auto row = 0; row < N; row++) {
  1056. for (auto col = 0; col < N; col++)
  1057. res.c[row][col] = -this->c[row][col];
  1058. }
  1059. return res;
  1060. }
  1061.  
  1062. template<unsigned int N, typename C>
  1063. inline Matrix<N, C> Matrix<N, C>::operator -(const Matrix& rhs) const {
  1064. return operator +(-rhs);
  1065. }
  1066.  
  1067. template<unsigned int N, typename C>
  1068. inline Matrix<N, C> Matrix<N, C>::operator -=(const Matrix& rhs) {
  1069. return *this = operator -(rhs);
  1070. }
  1071.  
  1072. template<unsigned int N, typename C>
  1073. inline Matrix<N, C> Matrix<N, C>::operator /(const C& rhs) const {
  1074. return operator *(1.0 / rhs);
  1075. }
  1076.  
  1077. template<unsigned int N, typename C>
  1078. inline Matrix<N, C> Matrix<N, C>::operator /=(const C& rhs) {
  1079. return *this = operator /(rhs);
  1080. }
  1081.  
  1082. template<unsigned int N, typename C>
  1083. bool Matrix<N, C>::operator ==(const Matrix& rhs) const {
  1084. bool res = true;
  1085. if (&rhs != this) {
  1086. // 各成分ごとに反復する。
  1087. for (auto row = 0; row < N; row++) {
  1088. for (auto col = 0; col < N; col++) {
  1089. // 対応する成分同士が近ければ等しいと判定する。
  1090. if (!nearEqual(this->c[row][col], rhs.c[row][col])) {
  1091. res = false;
  1092. break;
  1093. }
  1094. }
  1095. if (!res) break;
  1096. }
  1097. }
  1098. return res;
  1099. }
  1100.  
  1101. template<unsigned int N, typename C>
  1102. inline tuple<Matrix<N, C>, Vector<N, C>> Matrix<N, C>::reduce(const Vector<N, C>& con_col) const {
  1103. Matrix<N, C> res_mat(*this);
  1104. Vector<N, C> res_con_col(con_col);
  1105. // カレント行インデックスを初期化する。
  1106. auto i = 0;
  1107. // 各列ごとに反復する。
  1108. for (auto j = 0; j < N; j++) {
  1109. // ゼロではない成分を探索する。
  1110. auto k = i;
  1111. for (; k < N; k++) {
  1112. if (!nearEqual(res_mat.c[k][j], 0.0)) break;
  1113. }
  1114. // ゼロではない成分が見つからなければ次の列に移る。
  1115. if (k >= N) continue;
  1116. // 見つかった行がカレント行でなければ、二つの行を入れ替える。
  1117. // 例) ↓カレント列
  1118. // | 0 5|5| ←カレント行
  1119. // |*2 4|6| ←見つかった行
  1120. // ↓二つの行を入れ替える。
  1121. // |*2 4|6| ←カレント行
  1122. // | 0 5|5|
  1123. if (k != i) {
  1124. for (auto s = 0; s < N; s++)
  1125. swap(res_mat.c[k][s], res_mat.c[i][s]);
  1126. swap(res_con_col.c[k], res_con_col.c[i]);
  1127. }
  1128. // カレント行の先導成分を1にするために、先導成分の逆数を各成分に掛ける。
  1129. // 例) ↓カレント列
  1130. // |*2 4|6| ←カレント行
  1131. // | 2 6|9|
  1132. // ↓先導成分2の逆数である1/2を各成分に掛ける。
  1133. // |*1 2|3| ←カレント行
  1134. // | 2 6|9|
  1135. C inv_ij_comp = 1.0 / res_mat.c[i][j];
  1136. for (auto s = j; s < N; s++)
  1137. res_mat.c[i][s] *= inv_ij_comp;
  1138. res_con_col.c[i] *= inv_ij_comp;
  1139.  
  1140. // カレント列の各成分が、カレント行以外はゼロになるようにする。
  1141. // 例) ↓カレント列
  1142. // | 1 2|3| ←カレント行
  1143. // |*2 6|9| ←ゼロにしたい行
  1144. // ↓ゼロにしたい行にカレント行×-2を加える。
  1145. // | 1 2|3| ←カレント行
  1146. // |*0 2|3| ←ゼロにしたい行
  1147.  
  1148. // 各行ごとに反復する。
  1149. for (auto r = 0; r < N; r++) {
  1150. // カレント行ならスキップする。
  1151. if (r == i) continue;
  1152. // 係数を計算しておく。ゼロならスキップ。
  1153. C coef = -res_mat.c[r][j];
  1154. if (nearEqual(coef, 0.0)) continue;
  1155. // 各列ごとに反復して、ゼロにしたい行の成分にカレント行の成分×係数を加える。
  1156. for (auto s = j; s < N; s++)
  1157. res_mat.c[r][s] += res_mat.c[i][s] * coef;
  1158. res_con_col.c[r] += res_con_col.c[i] * coef;
  1159. }
  1160. i++;
  1161. }
  1162. return make_tuple(res_mat, res_con_col);
  1163. }
  1164.  
  1165. template<unsigned int N, typename C>
  1166. inline Matrix<N - 1, C> Matrix<N, C>::sub(const unsigned int& row, const unsigned int& col) const {
  1167. Matrix<N - 1, C> sub;
  1168. auto sub_row = 0;
  1169. // この行列の各成分ごとに反復する。
  1170. // 取り除く行と列については処理をスキップする。
  1171. for (auto sup_row = 0; sup_row < N; sup_row++) {
  1172. if (sup_row == row) continue;
  1173. auto sub_col = 0;
  1174. for (auto sup_col = 0; sup_col < N; sup_col++) {
  1175. if (sup_col == col) continue;
  1176. // 対応する成分をコピーする。
  1177. sub.c[sub_row][sub_col] = this->c[sup_row][sup_col];
  1178. sub_col++;
  1179. }
  1180. sub_row++;
  1181. }
  1182. return sub;
  1183. }
  1184.  
  1185. template<unsigned int N, typename C>
  1186. inline Matrix<N - 1, C> Matrix<N, C>::trunc() const {
  1187. Matrix<N - 1, C> res;
  1188. // 結果の各成分ごとに反復する。
  1189. for (auto row = 0; row < N - 1; row++) {
  1190. // 対応する成分をコピーする。
  1191. for (auto col = 0; col < N - 1; col++)
  1192. res.c[row][col] = this->c[row][col];
  1193. }
  1194. return res;
  1195. }
  1196.  
  1197. template<unsigned int N, typename C>
  1198. inline C MatrixDeterminant<N, C>::calculate(const Matrix<N, C>& mat) {
  1199. C res = 0.0;
  1200. // 1行目の各成分ごとに反復する。
  1201. for (auto col = 0; col < N; col++) {
  1202. // 成分に、それと対応する小行列式を乗算する。
  1203. C cofac = mat.c[0][col] * mat.sub(0, col).det();
  1204. // (-1)^col
  1205. if ((col & 0x1) == 1) cofac = -cofac;
  1206. // 結果に余因子を加算する。
  1207. res += cofac;
  1208. }
  1209. return res;
  1210. }
  1211.  
  1212. template<typename C>
  1213. inline C MatrixDeterminant<2, C>::calculate(const Matrix<2, C>& mat) {
  1214. // 再帰的な行列式計算の終着点。
  1215. // 2×2の行列式を計算する。
  1216. return mat.c[0][0] * mat.c[1][1] - mat.c[0][1] * mat.c[1][0];
  1217. }
  1218.  
  1219. template<unsigned int N, typename C>
  1220. inline ostream& operator <<(ostream& out, const Matrix<N, C>& mat) {
  1221. out << "{";
  1222. for (auto row = 0; row < N; row++) {
  1223. out << "{";
  1224. for (auto col = 0; col < N; col++) out << mat.c[row][col] << ", ";
  1225. out << "}, ";
  1226. }
  1227. out << "}";
  1228. }
  1229. };
  1230.  
  1231. #include <algorithm>
  1232. #include <cmath>
  1233. #include <iostream>
  1234. #include <tuple>
  1235.  
  1236. namespace h3d {
  1237. using std::acos;
  1238. using std::cbrt;
  1239. using std::cos;
  1240. using std::make_tuple;
  1241. using std::ostream;
  1242. using std::pow;
  1243. using std::sort;
  1244. using std::tuple;
  1245.  
  1246. template<unsigned int N, typename C>
  1247. inline PolyExp<N, C>::PolyExp(const Vector<N + 1, C>& coef_vec) : c(coef_vec) {}
  1248.  
  1249. template<unsigned int N, typename C>
  1250. inline PolyExp<N, C>::PolyExp(const C& const_coef) {
  1251. this->c.clear();
  1252. this->c.c[0] = const_coef;
  1253. }
  1254.  
  1255. template<unsigned int N, typename C>
  1256. inline bool PolyExp<N, C>::operator !=(const PolyExp& rhs) const {
  1257. return !operator ==(rhs);
  1258. }
  1259.  
  1260. template<unsigned int N, typename C>
  1261. inline PolyExp<N, C> PolyExp<N, C>::operator *(const C& rhs) const {
  1262. return PolyExp(this->c * rhs);
  1263. }
  1264.  
  1265. template<unsigned int N, typename C>
  1266. inline PolyExp<N, C> PolyExp<N, C>::operator *(const PolyExp& rhs) const throw(string) {
  1267. PolyExp<N, C> res;
  1268. res.c.clear();
  1269. // 左側の各係数と右側の各係数の組み合わせごとに反復して、乗算する。
  1270. for (auto i = 0; i < N + 1; i++) {
  1271. if (!nearEqual(this->c.c[i], 0.0)) {
  1272. for (auto j = 0; j < N + 1; j++) {
  1273. if (!nearEqual(rhs.c.c[j], 0.0)) {
  1274. if (i + j >= N + 1) throw string("多項式の次数が足りない。");
  1275. res.c.c[i + j] += this->c.c[i] * rhs.c.c[j];
  1276. }
  1277. }
  1278. }
  1279. }
  1280. return res;
  1281. }
  1282.  
  1283. template<unsigned int N, typename C>
  1284. inline PolyExp<N, C>& PolyExp<N, C>::operator *=(const C& rhs) {
  1285. return *this = operator *(rhs);
  1286. }
  1287.  
  1288. template<unsigned int N, typename C>
  1289. inline PolyExp<N, C>& PolyExp<N, C>::operator *=(const PolyExp& rhs) throw(string) {
  1290. return *this = operator *(rhs);
  1291. }
  1292.  
  1293. template<unsigned int N, typename C>
  1294. inline PolyExp<N, C> PolyExp<N, C>::operator +(const PolyExp& rhs) const {
  1295. return PolyExp(this->c + rhs.c);
  1296. }
  1297.  
  1298. template<unsigned int N, typename C>
  1299. inline PolyExp<N, C>& PolyExp<N, C>::operator +=(const PolyExp& rhs) {
  1300. return *this = operator +(rhs);
  1301. }
  1302.  
  1303. template<unsigned int N, typename C>
  1304. inline PolyExp<N, C> PolyExp<N, C>::operator -() const {
  1305. return PolyExp(-this->c);
  1306. }
  1307.  
  1308. template<unsigned int N, typename C>
  1309. inline PolyExp<N, C> PolyExp<N, C>::operator -(const PolyExp& rhs) const {
  1310. return operator +(-rhs);
  1311. }
  1312.  
  1313. template<unsigned int N, typename C>
  1314. inline PolyExp<N, C>& PolyExp<N, C>::operator -=(const PolyExp& rhs) {
  1315. return *this = operator -(rhs);
  1316. }
  1317.  
  1318. template<unsigned int N, typename C>
  1319. inline PolyExp<N, C> PolyExp<N, C>::operator /(const C& rhs) const {
  1320. return operator *(1.0 / rhs);
  1321. }
  1322.  
  1323. template<unsigned int N, typename C>
  1324. inline PolyExp<N, C>& PolyExp<N, C>::operator /=(const C& rhs) {
  1325. return *this = operator /(rhs);
  1326. }
  1327.  
  1328. template<unsigned int N, typename C>
  1329. inline bool PolyExp<N, C>::operator ==(const PolyExp& rhs) const {
  1330. return this->c == rhs.c;
  1331. }
  1332.  
  1333. template<unsigned int N, typename C>
  1334. inline tuple<unsigned int, Vector<N, C>> PolyExp<N, C>::rts() const {
  1335. return PolyExpRoots<N, C>::calculate(*this);
  1336. }
  1337.  
  1338. template<typename C>
  1339. inline tuple<unsigned int, Vector<2, C>> PolyExpRoots<2, C>::calculate(const PolyExp<2, C>& poly_exp) {
  1340. unsigned int res_rts_cnt = 0;
  1341. Vector<2, C> res_rts;
  1342. // 各係数をわかりやすい名前の変数に代入する。
  1343. // ax^2 + bx + c
  1344. C a = poly_exp.c.c[2], b = poly_exp.c.c[1], c = poly_exp.c.c[0];
  1345. // 判別式を計算する。
  1346. // d = b^2 - 4ac
  1347. C d = b * b - 4.0 * a * c;
  1348. // 1 / 2a
  1349. C inv_a2 = 1.0 / (a + a);
  1350. // d = 0 なら重根。正なら二つの実数根を持つ。
  1351. if (nearEqual(d, 0.0)) {
  1352. res_rts_cnt = 1;
  1353. res_rts.c[0] = -b * inv_a2;
  1354. }
  1355. else if (d > 0.0) {
  1356. res_rts_cnt = 2;
  1357. res_rts.c[0] = (-b + sqrt(d)) * inv_a2;
  1358. res_rts.c[1] = (-b - sqrt(d)) * inv_a2;
  1359. sort(res_rts.c, res_rts.c + 2);
  1360. }
  1361. return make_tuple(res_rts_cnt, res_rts);
  1362. }
  1363.  
  1364. template<typename C>
  1365. inline tuple<unsigned int, Vector<3, C>> PolyExpRoots<3, C>::calculate(const PolyExp<3, C>& poly_exp) {
  1366. unsigned int res_rts_cnt = 0;
  1367. Vector<3, C> res_rts;
  1368. // 3次の係数が1になるように除算を行う。
  1369. PolyExp<3, C> poly_exp2(poly_exp / poly_exp.c.c[3]);
  1370. // 各係数をわかりやすい名前の変数に代入する。
  1371. // t^3 + at^2 + bt + c
  1372. C a = poly_exp2.c.c[2], b = poly_exp2.c.c[1], c = poly_exp2.c.c[0];
  1373. // a
  1374. // t = x - ---
  1375. // 3
  1376. // とすると、
  1377. // x^3 + px + q
  1378. // が得られる。ただし、
  1379. // 1
  1380. // p = - ---a^2 + b
  1381. // 3
  1382. // 2 1
  1383. // q = ----a^3 - ---ab + c
  1384. // 27 3
  1385. // である。
  1386. // xの根を求められたら、a/3を引けば、tの根を得られる。
  1387. C a2p = a * a, a3p = a2p * a;
  1388. C p = -a2p / 3.0 + b, q = a3p * 2.0 / 27.0 - a * b / 3.0 + c;
  1389. C pd = p / 3.0, qd = q / 2.0;
  1390. C pd3p = pd * pd * pd, qd2p = qd * qd;
  1391. C dd = pd3p + qd2p;
  1392. if (nearEqual(dd, 0.0) || dd > 0) {
  1393. C r = cbrt(-qd + sqrt(dd));
  1394. if (nearEqual(dd, 0.0)) {
  1395. res_rts_cnt = 2;
  1396. res_rts.c[0] = r + r;
  1397. res_rts.c[1] = -r;
  1398. if (nearEqual(res_rts.c[0], res_rts.c[1])) res_rts_cnt = 1;
  1399. else sort(res_rts.c, res_rts.c + 2);
  1400. }
  1401. else {
  1402. C s = cbrt(-qd - sqrt(dd));
  1403. res_rts_cnt = 1;
  1404. res_rts.c[0] = r + s;
  1405. }
  1406. }
  1407. else {
  1408. res_rts_cnt = 3;
  1409. C theta = acos(-qd / sqrt(-pd3p)) / 3.0;
  1410. C u = sqrt(-pd), u2m = u + u;
  1411. res_rts.c[0] = cos(theta) * u2m;
  1412. res_rts.c[1] = cos(theta + M_PI * 2.0 / 3.0) * u2m;
  1413. res_rts.c[2] = cos(theta - M_PI * 2.0 / 3.0) * u2m;
  1414. sort(res_rts.c, res_rts.c + 3);
  1415. }
  1416. C a3d = a / 3.0;
  1417. for (auto i = 0; i < res_rts_cnt; i++) res_rts.c[i] -= a3d;
  1418. return make_tuple(res_rts_cnt, res_rts);
  1419. }
  1420.  
  1421. template<unsigned int N, typename C>
  1422. inline ostream& operator <<(ostream& out, const PolyExp<N, C>& poly_exp) {
  1423. out << "{";
  1424. for (auto c : poly_exp.c) out << c << ", ";
  1425. out << "}";
  1426. }
  1427. };
  1428.  
  1429. #include <cmath>
  1430.  
  1431. namespace h3d {
  1432. using std::tan;
  1433.  
  1434. Matrix<3> scaling(const Vector<3>& coef) {
  1435. // 主対角成分に係数を配置する。
  1436. // |a 0 0|
  1437. // |0 b 0|
  1438. // |0 0 c|
  1439. Matrix<3> res(Matrix<3>::IDENTITY());
  1440. for (auto i = 0; i < 3; i++) res.c[i][i] = coef.c[i];
  1441. return res;
  1442. }
  1443.  
  1444. Matrix<3> rotation(const Vector<3>& axis, const FLOAT& rad) {
  1445. // 公式に従って行列を作る。
  1446. Vector<3> nmz_axis = axis.normalize();
  1447. FLOAT xx = nmz_axis.c[0] * nmz_axis.c[0];
  1448. FLOAT xy = nmz_axis.c[0] * nmz_axis.c[1];
  1449. FLOAT xz = nmz_axis.c[0] * nmz_axis.c[2];
  1450. FLOAT yy = nmz_axis.c[1] * nmz_axis.c[1];
  1451. FLOAT yz = nmz_axis.c[1] * nmz_axis.c[2];
  1452. FLOAT zz = nmz_axis.c[2] * nmz_axis.c[2];
  1453. FLOAT s = sin(rad);
  1454. FLOAT c = cos(rad);
  1455. FLOAT d = 1.0 - c;
  1456. FLOAT xxd = xx * d;
  1457. FLOAT xyd = xy * d;
  1458. FLOAT zs = nmz_axis.c[2] * s;
  1459. FLOAT xzd = xz * d;
  1460. FLOAT ys = nmz_axis.c[1] * s;
  1461. FLOAT yyd = yy * d;
  1462. FLOAT yzd = yz * d;
  1463. FLOAT xs = nmz_axis.c[0] * s;
  1464. FLOAT zzd = zz * d;
  1465. return Matrix<3>{
  1466. c + xxd, xyd - zs, xzd + ys,
  1467. xyd + zs, c + yyd, yzd - xs,
  1468. xzd - ys, yzd + xs, c + zzd,
  1469. };
  1470. }
  1471.  
  1472. Matrix<4> translation(const Vector<3>& os) {
  1473. // 単位行列の第4列に平行移動量を配置する。
  1474. // |1 0 0 x|
  1475. // |0 1 0 y|
  1476. // |0 0 1 z|
  1477. // |0 0 0 1|
  1478. Matrix<4> res(Matrix<4>::IDENTITY());
  1479. for (auto i = 0; i < 3; i++) res.c[i][3] = os.c[i];
  1480. return res;
  1481. }
  1482.  
  1483. Matrix<4> view(const Vector<3>& eye_pos, const Vector<3>& cent_pt, const Vector<3>& up_dir) {
  1484. // ビュー行列は、目の位置までの平行移動→視線回転→上方向回転の順序で変換を行う。
  1485.  
  1486. // 目の位置が原点にくるように平行移動行列を作る。
  1487. Matrix<4> eye_pos_trl(translation(-eye_pos));
  1488.  
  1489. // 視線についての回転行列を作る。視線が逆Z軸になるように回転する。
  1490.  
  1491. Matrix<3> ec_iz_rot(Matrix<3>::IDENTITY());
  1492. Vector<3> nmz_ec = (cent_pt - eye_pos).normalize();
  1493. // 視線と逆Z軸の法線を計算する。
  1494. Vector<3> ec_iz_nml = nmz_ec.outpro(-Z_AXIS);
  1495. // 視線と逆Z軸が平行ではないなら、法線まわりに視線と逆Z軸がなす角度で回転する。
  1496. if (ec_iz_nml != Vector<3>::ZERO())
  1497. ec_iz_rot = rotation(ec_iz_nml, acos(nmz_ec.inpro(-Z_AXIS)));
  1498. // 視線がZ軸なら、Y軸まわりに反転する。
  1499. else if (nmz_ec == Z_AXIS) ec_iz_rot = rotation(Y_AXIS, M_PI);
  1500.  
  1501. // 上方向についての回転行列を作る。上方向がY軸になるように回転する。
  1502.  
  1503. Matrix<3> u_y_rot(Matrix<3>::IDENTITY());
  1504. Vector<3> nmz_up_dir = up_dir.normalize();
  1505. // 上方向とY軸の法線を計算する。
  1506. Vector<3> u_y_nml = nmz_up_dir.outpro(Y_AXIS);
  1507. // 上方向とY軸が平行ではないなら、法線まわりに上方向とY軸がなす角度で回転する。
  1508. if (u_y_nml != Vector<3>::ZERO())
  1509. u_y_rot = rotation(u_y_nml, acos(nmz_up_dir.inpro(Y_AXIS)));
  1510. // 上方向が逆Y軸なら、Z軸まわりに反転する。
  1511. else if (nmz_up_dir == -Y_AXIS) u_y_rot = rotation(Z_AXIS, M_PI);
  1512.  
  1513. // 作った3つの行列を連結する。右から順に配置する。
  1514. return (u_y_rot * ec_iz_rot).ext() * eye_pos_trl;
  1515. }
  1516.  
  1517. Matrix<4> perspectiveProjection(const double& hori_fov, const double& asp_rat, const double& near_dist, const double& far_dist) {
  1518. // 焦点距離(FOCal DISTance)。
  1519. double foc_dist = 1.0 / tan(hori_fov / 2.0);
  1520. // 右平面と近平面が交差するX座標。
  1521. double right_x = near_dist / foc_dist;
  1522. // 上平面と近平面が交差するY座標。
  1523. double top_y = asp_rat * near_dist / foc_dist;
  1524.  
  1525. // 公式に従って行列を作る。
  1526. double n2 = near_dist + near_dist;
  1527. double n2f = n2 * far_dist;
  1528. double fsn = far_dist - near_dist;
  1529. double fan = far_dist + near_dist;
  1530. double wid = right_x + right_x;
  1531. double hei = top_y + top_y;
  1532. return Matrix<4>{
  1533. n2 / wid, 0.0, 0.0, 0.0,
  1534. 0.0, n2 / hei, 0.0, 0.0,
  1535. 0.0, 0.0, -fan / fsn, -n2f / fsn,
  1536. 0.0, 0.0, -1.0, 0.0,
  1537. };
  1538. }
  1539. };
  1540.  
  1541. #include <algorithm>
  1542. #include <cmath>
  1543. #include <iostream>
  1544.  
  1545. namespace h3d {
  1546. using std::copy;
  1547. using std::fill;
  1548. using std::ostream;
  1549. using std::sqrt;
  1550.  
  1551. template<unsigned int N, typename C>
  1552. inline void Vector<N, C>::clear() {
  1553. // 各成分をゼロクリアする。
  1554. fill(this->c, this->c + N, 0.0);
  1555. }
  1556.  
  1557. template<unsigned int N, typename C>
  1558. inline Vector<N + 1, C> Vector<N, C>::ext(const C& ext_comp) const {
  1559. Vector<N + 1, C> res;
  1560. // このベクトルからN個の成分をコピーして、最後は引数の成分をコピーする。
  1561. copy(this->c, this->c + N, res.c);
  1562. res.c[N] = ext_comp;
  1563. return res;
  1564. }
  1565.  
  1566. template<unsigned int N, typename C>
  1567. inline C Vector<N, C>::inpro(const Vector& rhs) const {
  1568. C res = 0.0;
  1569. // 対応する成分同士の積を求めて、合計する。
  1570. for (auto i = 0; i < N; i++) res += this->c[i] * rhs.c[i];
  1571. return res;
  1572. }
  1573.  
  1574. template<unsigned int N, typename C>
  1575. inline double Vector<N, C>::norm() const {
  1576. return sqrt(this->inpro(*this));
  1577. }
  1578.  
  1579. template<unsigned int N, typename C>
  1580. inline Vector<N, C> Vector<N, C>::normalize() const {
  1581. return *this / norm();
  1582. }
  1583.  
  1584. template<unsigned int N, typename C>
  1585. inline bool Vector<N, C>::operator !=(const Vector& rhs) const {
  1586. return !operator ==(rhs);
  1587. }
  1588.  
  1589. template<unsigned int N, typename C>
  1590. inline Vector<N, C> Vector<N, C>::operator *(const C& rhs) const {
  1591. Vector<N, C> res;
  1592. // 各成分にスカラー値を乗算する。
  1593. for (auto i = 0; i < N; i++) res.c[i] = this->c[i] * rhs;
  1594. return res;
  1595. }
  1596.  
  1597. template<unsigned int N, typename C>
  1598. inline Vector<N, C>& Vector<N, C>::operator *=(const C& rhs) {
  1599. return *this = operator *(rhs);
  1600. }
  1601.  
  1602. template<unsigned int N, typename C>
  1603. inline Vector<N, C> Vector<N, C>::operator +(const Vector& rhs) const {
  1604. Vector<N, C> res;
  1605. // 対応する成分同士で加算する。
  1606. for (auto i = 0; i < N; i++) res.c[i] = this->c[i] + rhs.c[i];
  1607. return res;
  1608. }
  1609.  
  1610. template<unsigned int N, typename C>
  1611. inline Vector<N, C>& Vector<N, C>::operator +=(const Vector& rhs) {
  1612. return *this = operator +(rhs);
  1613. }
  1614.  
  1615. template<unsigned int N, typename C>
  1616. inline Vector<N, C> Vector<N, C>::operator -() const {
  1617. Vector<N, C> res;
  1618. // 各成分の符号を反転する。
  1619. for (auto i = 0; i < N; i++) res.c[i] = -this->c[i];
  1620. return res;
  1621. }
  1622.  
  1623. template<unsigned int N, typename C>
  1624. inline Vector<N, C> Vector<N, C>::operator -(const Vector& rhs) const {
  1625. return operator +(-rhs);
  1626. }
  1627.  
  1628. template<unsigned int N, typename C>
  1629. inline Vector<N, C>& Vector<N, C>::operator -=(const Vector& rhs) {
  1630. return *this = operator -(rhs);
  1631. }
  1632.  
  1633. template<unsigned int N, typename C>
  1634. inline Vector<N, C> Vector<N, C>::operator /(const C& rhs) const {
  1635. return operator *(1.0 / rhs);
  1636. }
  1637.  
  1638. template<unsigned int N, typename C>
  1639. inline Vector<N, C>& Vector<N, C>::operator /=(const C& rhs) {
  1640. return *this = operator /(rhs);
  1641. }
  1642.  
  1643. template<unsigned int N, typename C>
  1644. inline bool Vector<N, C>::operator ==(const Vector& rhs) const {
  1645. bool res = true;
  1646. if (&rhs != this) {
  1647. // 各成分ごとに反復して、対応する成分同士が近ければ等しいと判定する。
  1648. for (auto i = 0; i < N; i++) {
  1649. if (!nearEqual(this->c[i], rhs.c[i])) {
  1650. res = false;
  1651. break;
  1652. }
  1653. }
  1654. }
  1655. return res;
  1656. }
  1657.  
  1658. template<unsigned int N, typename C>
  1659. inline Vector<N, C> Vector<N, C>::outpro(const Vector& rhs) const {
  1660. // 各成分について、対応する列を除いた2×2の行列式を計算する。
  1661. // P×Q = < Py・Qz - Pz・Qy, Pz・Qx - Px・Qz, Px・Qy - Py・Qx >
  1662. return Vector<N, C>{
  1663. this->c[1] * rhs.c[2] - this->c[2] * rhs.c[1],
  1664. this->c[2] * rhs.c[0] - this->c[0] * rhs.c[2],
  1665. this->c[0] * rhs.c[1] - this->c[1] * rhs.c[0],
  1666. };
  1667. }
  1668.  
  1669. template<unsigned int N, typename C>
  1670. inline Vector<N - 1, C> Vector<N, C>::trunc() const {
  1671. Vector<N - 1, C> res;
  1672. copy(this->c, this->c + N - 1, res.c);
  1673. return res;
  1674. }
  1675.  
  1676. template<unsigned int N, typename C>
  1677. inline ostream& operator <<(ostream& out, const Vector<N, C>& vec) {
  1678. out << "{";
  1679. for (auto c : vec.c) out << c << ", ";
  1680. out << "}";
  1681. }
  1682. };
  1683.  
  1684. #include <memory>
  1685. #include <string>
  1686.  
  1687. namespace h3d {
  1688. using std::shared_ptr;
  1689. using std::string;
  1690.  
  1691. TestSet::TestSet() {
  1692. this->tests.push_back(shared_ptr<Test>(new Test2));
  1693. this->tests.push_back(shared_ptr<Test>(new Test5));
  1694. }
  1695.  
  1696. void TestSet::run() const throw(string) { for (auto iter : this->tests) iter->run(); }
  1697. };
  1698.  
  1699. #include <cmath>
  1700. #include <tuple>
  1701.  
  1702. namespace h3d {
  1703. using std::cos;
  1704. using std::get;
  1705. using std::make_tuple;
  1706. using std::sin;
  1707. using std::sqrt;
  1708. using std::tuple;
  1709.  
  1710. void Test2::run() const throw(string) {
  1711. ASSERT(nearEqual(Matrix<2>::IDENTITY().c[0][0], 1.0))
  1712. ASSERT(nearEqual(Matrix<2>::IDENTITY().c[0][1], 0.0))
  1713. ASSERT(nearEqual(Matrix<2>::IDENTITY().c[1][0], 0.0))
  1714. ASSERT(nearEqual(Matrix<2>::IDENTITY().c[1][1], 1.0))
  1715. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[0][0], 1.0))
  1716. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[0][1], 0.0))
  1717. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[0][2], 0.0))
  1718. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[1][0], 0.0))
  1719. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[1][1], 1.0))
  1720. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[1][2], 0.0))
  1721. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[2][0], 0.0))
  1722. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[2][1], 0.0))
  1723. ASSERT(nearEqual(Matrix<3>::IDENTITY().c[2][2], 1.0))
  1724. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[0][0], 1.0))
  1725. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[0][1], 0.0))
  1726. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[0][2], 0.0))
  1727. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[0][3], 0.0))
  1728. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[1][0], 0.0))
  1729. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[1][1], 1.0))
  1730. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[1][2], 0.0))
  1731. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[1][3], 0.0))
  1732. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[2][0], 0.0))
  1733. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[2][1], 0.0))
  1734. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[2][2], 1.0))
  1735. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[2][3], 0.0))
  1736. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[3][0], 0.0))
  1737. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[3][1], 0.0))
  1738. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[3][2], 0.0))
  1739. ASSERT(nearEqual(Matrix<4>::IDENTITY().c[3][3], 1.0))
  1740.  
  1741. Matrix<2> f{
  1742. 1.0, -2.0,
  1743. -3.0, 4.0,
  1744. }, g{
  1745. -9.0, 8.0,
  1746. 7.0, -6.0,
  1747. };
  1748.  
  1749. ASSERT(nearEqual(f.c[0][0], 1.0))
  1750. ASSERT(nearEqual(f.c[0][1], -2.0))
  1751. ASSERT(nearEqual(f.c[1][0], -3.0))
  1752. ASSERT(nearEqual(f.c[1][1], 4.0))
  1753. ASSERT(nearEqual(g.c[0][0], -9.0))
  1754. ASSERT(nearEqual(g.c[0][1], 8.0))
  1755. ASSERT(nearEqual(g.c[1][0], 7.0))
  1756. ASSERT(nearEqual(g.c[1][1], -6.0))
  1757.  
  1758. ASSERT(f.ext() == (Matrix<3>{
  1759. 1.0, -2.0, 0.0,
  1760. -3.0, 4.0, 0.0,
  1761. 0.0, 0.0, 1.0,
  1762. }))
  1763. ASSERT(f.ext((Matrix<3>{
  1764. 3.0, -8.0, 5.0,
  1765. -2.0, 7.0, 4.0,
  1766. 1.0, -5.0, 0.0,
  1767. })) == (Matrix<3>{
  1768. 1.0, -2.0, 5.0,
  1769. -3.0, 4.0, 4.0,
  1770. 1.0, -5.0, 0.0,
  1771. }))
  1772. ASSERT(f.trunc() == (Matrix<1>{
  1773. 1.0,
  1774. }))
  1775.  
  1776. ASSERT(f == (Matrix<2>{
  1777. 1.0, -2.0,
  1778. -3.0, 4.0,
  1779. }))
  1780. ASSERT(g == (Matrix<2>{
  1781. -9.0, 8.0,
  1782. 7.0, -6.0,
  1783. }))
  1784. ASSERT(f != (Matrix<2>{
  1785. -9.0, 8.0,
  1786. 7.0, -6.0,
  1787. }))
  1788. ASSERT(g != (Matrix<2>{
  1789. 1.0, -2.0,
  1790. -3.0, 4.0,
  1791. }))
  1792.  
  1793. ASSERT(-f == (Matrix<2>{
  1794. -1.0, 2.0,
  1795. 3.0, -4.0,
  1796. }))
  1797. ASSERT(-g == (Matrix<2>{
  1798. 9.0, -8.0,
  1799. -7.0, 6.0,
  1800. }))
  1801. ASSERT(f + g == (Matrix<2>{
  1802. -8.0, 6.0,
  1803. 4.0, -2.0,
  1804. }))
  1805. ASSERT(f - g == (Matrix<2>{
  1806. 10.0, -10.0,
  1807. -10.0, 10.0,
  1808. }))
  1809. ASSERT(f * g == (Matrix<2>{
  1810. -23.0, 20.0,
  1811. 55.0, -48.0,
  1812. }))
  1813. ASSERT(g * f == (Matrix<2>{
  1814. -33.0, 50.0,
  1815. 25.0, -38.0,
  1816. }))
  1817. ASSERT(f * Matrix<2>::IDENTITY() == (Matrix<2>{
  1818. 1.0, -2.0,
  1819. -3.0, 4.0,
  1820. }))
  1821. ASSERT(Matrix<2>::IDENTITY() * g == (Matrix<2>{
  1822. -9.0, 8.0,
  1823. 7.0, -6.0,
  1824. }))
  1825. ASSERT(f * 3.0 == (Matrix<2>{
  1826. 3.0, -6.0,
  1827. -9.0, 12.0,
  1828. }))
  1829. ASSERT(g / -2.0 == (Matrix<2>{
  1830. 4.5, -4.0,
  1831. -3.5, 3.0,
  1832. }))
  1833.  
  1834. Matrix<2> h;
  1835. h = f;
  1836. ASSERT(h == (Matrix<2>{
  1837. 1.0, -2.0,
  1838. -3.0, 4.0,
  1839. }))
  1840. ASSERT((h += (Matrix<2>{
  1841. 0.1, -0.2,
  1842. -0.3, 0.4,
  1843. })) == (Matrix<2>{
  1844. 1.1, -2.2,
  1845. -3.3, 4.4,
  1846. }))
  1847. ASSERT((h -= (Matrix<2>{
  1848. -0.9, 0.8,
  1849. 0.7, -0.6,
  1850. })) == (Matrix<2>{
  1851. 2.0, -3.0,
  1852. -4.0, 5.0,
  1853. }))
  1854. ASSERT((h *= (Matrix<2>{
  1855. -4.0, 3.0,
  1856. -2.0, 1.0,
  1857. })) == (Matrix<2>{
  1858. -2.0, 3.0,
  1859. 6.0, -7.0,
  1860. }))
  1861. ASSERT((h *= 3.0) == (Matrix<2>{
  1862. -6.0, 9.0,
  1863. 18.0, -21.0,
  1864. }))
  1865. ASSERT((h /= -2.0) == (Matrix<2>{
  1866. 3.0, -4.5,
  1867. -9.0, 10.5,
  1868. }))
  1869. h.clear();
  1870. ASSERT(nearEqual(h.c[0][0], 0.0))
  1871. ASSERT(nearEqual(h.c[0][1], 0.0))
  1872. ASSERT(nearEqual(h.c[1][0], 0.0))
  1873. ASSERT(nearEqual(h.c[1][1], 0.0))
  1874.  
  1875. ASSERT(nearEqual((Matrix<2>{
  1876. 2.0, 7.0,
  1877. -3.0, 0.5,
  1878. }).det(), 22.0))
  1879. ASSERT(nearEqual((Matrix<3>{
  1880. 0.0, 0.0, 1.0,
  1881. 0.0, 1.0, 0.0,
  1882. 1.0, 0.0, 0.0,
  1883. }).det(), -1.0))
  1884. ASSERT(nearEqual((Matrix<3>{
  1885. 0.5, sqrt(3.0) / 2.0, 0.0,
  1886. -sqrt(3.0) / 2.0, 0.5, 0.0,
  1887. 0.0, 0.0, 1.0,
  1888. }).det(), 1.0))
  1889. ASSERT(nearEqual((Matrix<3>{
  1890. 5, 7, 1,
  1891. 17, 2, 64,
  1892. 10, 14, 2,
  1893. }).det(), 0.0))
  1894.  
  1895. ASSERT((Matrix<3>{
  1896. 2.0, 0.0, 0.0,
  1897. 0.0, 3.0, 0.0,
  1898. 0.0, 0.0, 4.0,
  1899. }).inv() == (Matrix<3>{
  1900. 12.0, 0.0, 0.0,
  1901. 0.0, 8.0, 0.0,
  1902. 0.0, 0.0, 6.0,
  1903. }) / 24.0)
  1904. ASSERT((Matrix<3>{
  1905. 2.0, 0.0, 0.0,
  1906. 0.0, 3.0, 0.0,
  1907. 0.0, 0.0, 4.0,
  1908. }) * ((Matrix<3>{
  1909. 12.0, 0.0, 0.0,
  1910. 0.0, 8.0, 0.0,
  1911. 0.0, 0.0, 6.0,
  1912. }) / 24.0) == Matrix<3>::IDENTITY())
  1913. ASSERT((Matrix<3>{
  1914. 1.0, 0.0, 0.0,
  1915. 0.0, 2.0, 2.0,
  1916. 3.0, 0.0, 8.0,
  1917. }).inv() == (Matrix<3>{
  1918. 16.0, 0.0, 0.0,
  1919. 6.0, 8.0, -2.0,
  1920. -6.0, 0.0, 2.0,
  1921. }) / 16.0)
  1922. ASSERT((Matrix<3>{
  1923. 1.0, 0.0, 0.0,
  1924. 0.0, 2.0, 2.0,
  1925. 3.0, 0.0, 8.0,
  1926. }) * ((Matrix<3>{
  1927. 16.0, 0.0, 0.0,
  1928. 6.0, 8.0, -2.0,
  1929. -6.0, 0.0, 2.0,
  1930. }) / 16.0) == Matrix<3>::IDENTITY())
  1931. FLOAT theta_rad = angleToRadian(60.0);
  1932. FLOAT cos_res = cos(theta_rad);
  1933. FLOAT sin_res = sin(theta_rad);
  1934. ASSERT((Matrix<3>{
  1935. cos_res, 0.0, -sin_res,
  1936. 0.0, 1.0, 0.0,
  1937. sin_res, 0.0, cos_res,
  1938. }).inv() == (Matrix<3>{
  1939. cos_res, 0.0, sin_res,
  1940. 0.0, 1.0, 0.0,
  1941. -sin_res, 0.0, cos_res,
  1942. }))
  1943. ASSERT((Matrix<3>{
  1944. cos_res, 0.0, -sin_res,
  1945. 0.0, 1.0, 0.0,
  1946. sin_res, 0.0, cos_res,
  1947. }) * (Matrix<3>{
  1948. cos_res, 0.0, sin_res,
  1949. 0.0, 1.0, 0.0,
  1950. -sin_res, 0.0, cos_res,
  1951. }) == Matrix<3>::IDENTITY())
  1952. ASSERT((Matrix<4>{
  1953. 1.0, 0.0, 0.0, 4.0,
  1954. 0.0, 1.0, 0.0, 3.0,
  1955. 0.0, 0.0, 1.0, 7.0,
  1956. 0.0, 0.0, 0.0, 1.0,
  1957. }).inv() == (Matrix<4>{
  1958. 1.0, 0.0, 0.0, -4.0,
  1959. 0.0, 1.0, 0.0, -3.0,
  1960. 0.0, 0.0, 1.0, -7.0,
  1961. 0.0, 0.0, 0.0, 1.0,
  1962. }))
  1963. ASSERT((Matrix<4>{
  1964. 1.0, 0.0, 0.0, 4.0,
  1965. 0.0, 1.0, 0.0, 3.0,
  1966. 0.0, 0.0, 1.0, 7.0,
  1967. 0.0, 0.0, 0.0, 1.0,
  1968. }) * (Matrix<4>{
  1969. 1.0, 0.0, 0.0, -4.0,
  1970. 0.0, 1.0, 0.0, -3.0,
  1971. 0.0, 0.0, 1.0, -7.0,
  1972. 0.0, 0.0, 0.0, 1.0,
  1973. }) == Matrix<4>::IDENTITY())
  1974.  
  1975. ASSERT((Matrix<2>{
  1976. 1.0, -3.0,
  1977. -4.0, 6.0,
  1978. }) * (Vector<2>{2.0, 5.0}) == (Vector<2>{-13.0, 22.0}))
  1979. ASSERT((Matrix<2>{
  1980. 0.0, 8.0,
  1981. -9.0, 3.0,
  1982. }) * (Vector<2>{1.0, -4.0}) == (Vector<2>{-32.0, -21.0}))
  1983.  
  1984. ASSERT((Matrix<3>{
  1985. 3.0, 2.0, -3.0,
  1986. 4.0, -3.0, 6.0,
  1987. 1.0, 0.0, -1.0,
  1988. }).reduce((Vector<3>{
  1989. 5.0,
  1990. 1.0,
  1991. 3.0,
  1992. })) == make_tuple((Matrix<3>{
  1993. 1.0, 0.0, 0.0,
  1994. 0.0, 1.0, 0.0,
  1995. 0.0, 0.0, 1.0,
  1996. }), (Vector<3>{
  1997. 13.0 / 10.0,
  1998. -2.0,
  1999. -17.0 / 10.0,
  2000. })))
  2001. ASSERT((Matrix<3>{
  2002. 2.0, 1.0, 3.0,
  2003. 0.0, 1.0, -1.0,
  2004. 1.0, 3.0, -1.0,
  2005. }).reduce() == make_tuple((Matrix<3>{
  2006. 1.0, 0.0, 2.0,
  2007. 0.0, 1.0, -1.0,
  2008. 0.0, 0.0, 0.0,
  2009. }), (Vector<3>{
  2010. 0.0,
  2011. 0.0,
  2012. 0.0,
  2013. })))
  2014. ASSERT((Matrix<3>{
  2015. 4.0, 3.0, 2.0,
  2016. 1.0, -1.0, -3.0,
  2017. 2.0, 3.0, 4.0,
  2018. }).reduce() == make_tuple((Matrix<3>{
  2019. 1.0, 0.0, -1.0,
  2020. 0.0, 1.0, 2.0,
  2021. 0.0, 0.0, 0.0,
  2022. }), (Vector<3>{
  2023. 0.0,
  2024. 0.0,
  2025. 0.0,
  2026. })))
  2027.  
  2028.  
  2029. ASSERT((Matrix<2>{
  2030. 1.0, 1.0,
  2031. 3.0, -1.0,
  2032. }).eigvals() == (Vector<2>{-2.0, 2.0}))
  2033. ASSERT((Matrix<3>{
  2034. 2.0, 1.0, 0.0,
  2035. 1.0, 1.0, 0.0,
  2036. 0.0, 0.0, -1.0,
  2037. }).eigvals() == (Vector<3>{-1.0, (3.0 - sqrt(5.0)) / 2.0, (3.0 + sqrt(5.0)) / 2.0}))
  2038. ASSERT((Matrix<3>{
  2039. 2.0, 0.0, 0.0,
  2040. 5.0, 2.0, 3.0,
  2041. -4.0, 3.0, 2.0,
  2042. }).eigvals() == (Vector<3>{-1.0, 2.0, 5.0}))
  2043.  
  2044. ASSERT((Matrix<2>{
  2045. 1.0, 1.0,
  2046. 3.0, -1.0,
  2047. }).eigvecs() == (Vector<2, Vector<2>>{
  2048. (Vector<2>{-1.0 / 3.0 / (sqrt(10.0) / 3.0), 1.0 / (sqrt(10.0) / 3.0)}),
  2049. (Vector<2>{1.0 / sqrt(2.0), 1.0 / sqrt(2.0)}),
  2050. }))
  2051. ASSERT((Matrix<3>{
  2052. 2.0, 0.0, 0.0,
  2053. 5.0, 2.0, 3.0,
  2054. -4.0, 3.0, 2.0,
  2055. }).eigvecs() == (Vector<3, Vector<3>>{
  2056. (Vector<3>{0.0 / sqrt(2.0), -1.0 / sqrt(2.0), 1.0 / sqrt(2.0)}),
  2057. (Vector<3>{-3.0 / 5.0 / sqrt(2.0), -4.0 / 5.0 / sqrt(2.0), 1.0 / sqrt(2.0)}),
  2058. (Vector<3>{0.0 / sqrt(2.0), 1.0 / sqrt(2.0), 1.0 / sqrt(2.0)}),
  2059. }))
  2060. }
  2061. };
  2062.  
  2063. #include <cmath>
  2064. #include <tuple>
  2065.  
  2066. namespace h3d {
  2067. using std::get;
  2068. using std::tuple;
  2069.  
  2070. void Test5::run() const throw(string) {
  2071. PolyExp<2> a{Vector<3>{1.0, -2.0, 3.0}};
  2072. ASSERT((PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}).c ==
  2073. (Vector<3>{3.0, -2.0, 1.0}))
  2074. ASSERT(-(PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) ==
  2075. (PolyExp<2>{Vector<3>{-3.0, 2.0, -1.0}}))
  2076. ASSERT((PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) * 2.0 ==
  2077. (PolyExp<2>{Vector<3>{6.0, -4.0, 2.0}}))
  2078. ASSERT((PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) / 2.0 ==
  2079. (PolyExp<2>{Vector<3>{1.5, -1.0, 0.5}}))
  2080. ASSERT((PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) +
  2081. (PolyExp<2>{Vector<3>{-5.0, 1.0, 0.0}}) ==
  2082. (PolyExp<2>{Vector<3>{-2.0, -1.0, 1.0}}))
  2083. ASSERT((PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) -
  2084. (PolyExp<2>{Vector<3>{-5.0, 1.0, 0.0}}) ==
  2085. (PolyExp<2>{Vector<3>{8.0, -3.0, 1.0}}))
  2086. ASSERT((PolyExp<2>{Vector<3>{4.0, 2.0, 0.0}}) *
  2087. (PolyExp<2>{Vector<3>{-3.0, 1.0, 0.0}}) ==
  2088. (PolyExp<2>{Vector<3>{-12.0, -2.0, 2.0}}))
  2089.  
  2090. tuple<unsigned int, Vector<2>> rts_res2;
  2091. rts_res2 = (PolyExp<2>{Vector<3>{2.0, -4.0, 2.0}}).rts();
  2092. ASSERT(get<0>(rts_res2) == 1)
  2093. ASSERT(nearEqual(get<1>(rts_res2).c[0], 1.0))
  2094. rts_res2 = (PolyExp<2>{Vector<3>{-3.0, -6.0, -3.0}}).rts();
  2095. ASSERT(get<0>(rts_res2) == 1)
  2096. ASSERT(nearEqual(get<1>(rts_res2).c[0], -1.0))
  2097. rts_res2 = (PolyExp<2>{Vector<3>{-2.0, 0.0, 2.0}}).rts();
  2098. ASSERT(get<0>(rts_res2) == 2)
  2099. ASSERT(nearEqual(get<1>(rts_res2).c[0], -1.0))
  2100. ASSERT(nearEqual(get<1>(rts_res2).c[1], 1.0))
  2101. rts_res2 = (PolyExp<2>{Vector<3>{18.0, -3.0, -3.0}}).rts();
  2102. ASSERT(get<0>(rts_res2) == 2)
  2103. ASSERT(nearEqual(get<1>(rts_res2).c[0], -3.0))
  2104. ASSERT(nearEqual(get<1>(rts_res2).c[1], 2.0))
  2105.  
  2106. tuple<unsigned int, Vector<3>> rts_res3;
  2107. rts_res3 = (PolyExp<3>{Vector<4>{-2.0, 6.0, -6.0, 2.0}}).rts();
  2108. ASSERT(get<0>(rts_res3) == 1)
  2109. ASSERT(nearEqual(get<1>(rts_res3).c[0], 1.0))
  2110. rts_res3 = (PolyExp<3>{Vector<4>{2.0, 3.0, 0.0, -1.0}}).rts();
  2111. ASSERT(get<0>(rts_res3) == 2)
  2112. ASSERT(nearEqual(get<1>(rts_res3).c[0], -1.0))
  2113. ASSERT(nearEqual(get<1>(rts_res3).c[1], 2.0))
  2114. rts_res3 = (PolyExp<3>{Vector<4>{180.0, 51.0, -12.0, -3.0}}).rts();
  2115. ASSERT(get<0>(rts_res3) == 3)
  2116. ASSERT(nearEqual(get<1>(rts_res3).c[0], -5.0))
  2117. ASSERT(nearEqual(get<1>(rts_res3).c[1], -3.0))
  2118. ASSERT(nearEqual(get<1>(rts_res3).c[2], 4.0))
  2119. }
  2120. };
  2121.  
  2122. #include <iostream>
  2123. #include <string>
  2124.  
  2125. int main() {
  2126. using std::cerr;
  2127. using std::endl;
  2128. using std::string;
  2129.  
  2130. try {
  2131. h3d::TestSet().run();
  2132. }
  2133. catch (const string& msg) {
  2134. cerr << msg << endl;
  2135. return 1;
  2136. }
  2137. return 0;
  2138. }
  2139.  
Success #stdin #stdout 0s 3500KB
stdin
Standard input is empty
stdout
アサート成功: nearEqual(Matrix<2>::IDENTITY().c[0][0], 1.0)
アサート成功: nearEqual(Matrix<2>::IDENTITY().c[0][1], 0.0)
アサート成功: nearEqual(Matrix<2>::IDENTITY().c[1][0], 0.0)
アサート成功: nearEqual(Matrix<2>::IDENTITY().c[1][1], 1.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[0][0], 1.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[0][1], 0.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[0][2], 0.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[1][0], 0.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[1][1], 1.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[1][2], 0.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[2][0], 0.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[2][1], 0.0)
アサート成功: nearEqual(Matrix<3>::IDENTITY().c[2][2], 1.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[0][0], 1.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[0][1], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[0][2], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[0][3], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[1][0], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[1][1], 1.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[1][2], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[1][3], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[2][0], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[2][1], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[2][2], 1.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[2][3], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[3][0], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[3][1], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[3][2], 0.0)
アサート成功: nearEqual(Matrix<4>::IDENTITY().c[3][3], 1.0)
アサート成功: nearEqual(f.c[0][0], 1.0)
アサート成功: nearEqual(f.c[0][1], -2.0)
アサート成功: nearEqual(f.c[1][0], -3.0)
アサート成功: nearEqual(f.c[1][1], 4.0)
アサート成功: nearEqual(g.c[0][0], -9.0)
アサート成功: nearEqual(g.c[0][1], 8.0)
アサート成功: nearEqual(g.c[1][0], 7.0)
アサート成功: nearEqual(g.c[1][1], -6.0)
アサート成功: f.ext() == (Matrix<3>{ 1.0, -2.0, 0.0, -3.0, 4.0, 0.0, 0.0, 0.0, 1.0, })
アサート成功: f.ext((Matrix<3>{ 3.0, -8.0, 5.0, -2.0, 7.0, 4.0, 1.0, -5.0, 0.0, })) == (Matrix<3>{ 1.0, -2.0, 5.0, -3.0, 4.0, 4.0, 1.0, -5.0, 0.0, })
アサート成功: f.trunc() == (Matrix<1>{ 1.0, })
アサート成功: f == (Matrix<2>{ 1.0, -2.0, -3.0, 4.0, })
アサート成功: g == (Matrix<2>{ -9.0, 8.0, 7.0, -6.0, })
アサート成功: f != (Matrix<2>{ -9.0, 8.0, 7.0, -6.0, })
アサート成功: g != (Matrix<2>{ 1.0, -2.0, -3.0, 4.0, })
アサート成功: -f == (Matrix<2>{ -1.0, 2.0, 3.0, -4.0, })
アサート成功: -g == (Matrix<2>{ 9.0, -8.0, -7.0, 6.0, })
アサート成功: f + g == (Matrix<2>{ -8.0, 6.0, 4.0, -2.0, })
アサート成功: f - g == (Matrix<2>{ 10.0, -10.0, -10.0, 10.0, })
アサート成功: f * g == (Matrix<2>{ -23.0, 20.0, 55.0, -48.0, })
アサート成功: g * f == (Matrix<2>{ -33.0, 50.0, 25.0, -38.0, })
アサート成功: f * Matrix<2>::IDENTITY() == (Matrix<2>{ 1.0, -2.0, -3.0, 4.0, })
アサート成功: Matrix<2>::IDENTITY() * g == (Matrix<2>{ -9.0, 8.0, 7.0, -6.0, })
アサート成功: f * 3.0 == (Matrix<2>{ 3.0, -6.0, -9.0, 12.0, })
アサート成功: g / -2.0 == (Matrix<2>{ 4.5, -4.0, -3.5, 3.0, })
アサート成功: h == (Matrix<2>{ 1.0, -2.0, -3.0, 4.0, })
アサート成功: (h += (Matrix<2>{ 0.1, -0.2, -0.3, 0.4, })) == (Matrix<2>{ 1.1, -2.2, -3.3, 4.4, })
アサート成功: (h -= (Matrix<2>{ -0.9, 0.8, 0.7, -0.6, })) == (Matrix<2>{ 2.0, -3.0, -4.0, 5.0, })
アサート成功: (h *= (Matrix<2>{ -4.0, 3.0, -2.0, 1.0, })) == (Matrix<2>{ -2.0, 3.0, 6.0, -7.0, })
アサート成功: (h *= 3.0) == (Matrix<2>{ -6.0, 9.0, 18.0, -21.0, })
アサート成功: (h /= -2.0) == (Matrix<2>{ 3.0, -4.5, -9.0, 10.5, })
アサート成功: nearEqual(h.c[0][0], 0.0)
アサート成功: nearEqual(h.c[0][1], 0.0)
アサート成功: nearEqual(h.c[1][0], 0.0)
アサート成功: nearEqual(h.c[1][1], 0.0)
アサート成功: nearEqual((Matrix<2>{ 2.0, 7.0, -3.0, 0.5, }).det(), 22.0)
アサート成功: nearEqual((Matrix<3>{ 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, }).det(), -1.0)
アサート成功: nearEqual((Matrix<3>{ 0.5, sqrt(3.0) / 2.0, 0.0, -sqrt(3.0) / 2.0, 0.5, 0.0, 0.0, 0.0, 1.0, }).det(), 1.0)
アサート成功: nearEqual((Matrix<3>{ 5, 7, 1, 17, 2, 64, 10, 14, 2, }).det(), 0.0)
アサート成功: (Matrix<3>{ 2.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 4.0, }).inv() == (Matrix<3>{ 12.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 6.0, }) / 24.0
アサート成功: (Matrix<3>{ 2.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 4.0, }) * ((Matrix<3>{ 12.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 6.0, }) / 24.0) == Matrix<3>::IDENTITY()
アサート成功: (Matrix<3>{ 1.0, 0.0, 0.0, 0.0, 2.0, 2.0, 3.0, 0.0, 8.0, }).inv() == (Matrix<3>{ 16.0, 0.0, 0.0, 6.0, 8.0, -2.0, -6.0, 0.0, 2.0, }) / 16.0
アサート成功: (Matrix<3>{ 1.0, 0.0, 0.0, 0.0, 2.0, 2.0, 3.0, 0.0, 8.0, }) * ((Matrix<3>{ 16.0, 0.0, 0.0, 6.0, 8.0, -2.0, -6.0, 0.0, 2.0, }) / 16.0) == Matrix<3>::IDENTITY()
アサート成功: (Matrix<3>{ cos_res, 0.0, -sin_res, 0.0, 1.0, 0.0, sin_res, 0.0, cos_res, }).inv() == (Matrix<3>{ cos_res, 0.0, sin_res, 0.0, 1.0, 0.0, -sin_res, 0.0, cos_res, })
アサート成功: (Matrix<3>{ cos_res, 0.0, -sin_res, 0.0, 1.0, 0.0, sin_res, 0.0, cos_res, }) * (Matrix<3>{ cos_res, 0.0, sin_res, 0.0, 1.0, 0.0, -sin_res, 0.0, cos_res, }) == Matrix<3>::IDENTITY()
アサート成功: (Matrix<4>{ 1.0, 0.0, 0.0, 4.0, 0.0, 1.0, 0.0, 3.0, 0.0, 0.0, 1.0, 7.0, 0.0, 0.0, 0.0, 1.0, }).inv() == (Matrix<4>{ 1.0, 0.0, 0.0, -4.0, 0.0, 1.0, 0.0, -3.0, 0.0, 0.0, 1.0, -7.0, 0.0, 0.0, 0.0, 1.0, })
アサート成功: (Matrix<4>{ 1.0, 0.0, 0.0, 4.0, 0.0, 1.0, 0.0, 3.0, 0.0, 0.0, 1.0, 7.0, 0.0, 0.0, 0.0, 1.0, }) * (Matrix<4>{ 1.0, 0.0, 0.0, -4.0, 0.0, 1.0, 0.0, -3.0, 0.0, 0.0, 1.0, -7.0, 0.0, 0.0, 0.0, 1.0, }) == Matrix<4>::IDENTITY()
アサート成功: (Matrix<2>{ 1.0, -3.0, -4.0, 6.0, }) * (Vector<2>{2.0, 5.0}) == (Vector<2>{-13.0, 22.0})
アサート成功: (Matrix<2>{ 0.0, 8.0, -9.0, 3.0, }) * (Vector<2>{1.0, -4.0}) == (Vector<2>{-32.0, -21.0})
アサート成功: (Matrix<3>{ 3.0, 2.0, -3.0, 4.0, -3.0, 6.0, 1.0, 0.0, -1.0, }).reduce((Vector<3>{ 5.0, 1.0, 3.0, })) == make_tuple((Matrix<3>{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, }), (Vector<3>{ 13.0 / 10.0, -2.0, -17.0 / 10.0, }))
アサート成功: (Matrix<3>{ 2.0, 1.0, 3.0, 0.0, 1.0, -1.0, 1.0, 3.0, -1.0, }).reduce() == make_tuple((Matrix<3>{ 1.0, 0.0, 2.0, 0.0, 1.0, -1.0, 0.0, 0.0, 0.0, }), (Vector<3>{ 0.0, 0.0, 0.0, }))
アサート成功: (Matrix<3>{ 4.0, 3.0, 2.0, 1.0, -1.0, -3.0, 2.0, 3.0, 4.0, }).reduce() == make_tuple((Matrix<3>{ 1.0, 0.0, -1.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, }), (Vector<3>{ 0.0, 0.0, 0.0, }))
アサート成功: (Matrix<2>{ 1.0, 1.0, 3.0, -1.0, }).eigvals() == (Vector<2>{-2.0, 2.0})
アサート成功: (Matrix<3>{ 2.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, -1.0, }).eigvals() == (Vector<3>{-1.0, (3.0 - sqrt(5.0)) / 2.0, (3.0 + sqrt(5.0)) / 2.0})
アサート成功: (Matrix<3>{ 2.0, 0.0, 0.0, 5.0, 2.0, 3.0, -4.0, 3.0, 2.0, }).eigvals() == (Vector<3>{-1.0, 2.0, 5.0})
アサート成功: (Matrix<2>{ 1.0, 1.0, 3.0, -1.0, }).eigvecs() == (Vector<2, Vector<2>>{ (Vector<2>{-1.0 / 3.0 / (sqrt(10.0) / 3.0), 1.0 / (sqrt(10.0) / 3.0)}), (Vector<2>{1.0 / sqrt(2.0), 1.0 / sqrt(2.0)}), })
アサート成功: (Matrix<3>{ 2.0, 0.0, 0.0, 5.0, 2.0, 3.0, -4.0, 3.0, 2.0, }).eigvecs() == (Vector<3, Vector<3>>{ (Vector<3>{0.0 / sqrt(2.0), -1.0 / sqrt(2.0), 1.0 / sqrt(2.0)}), (Vector<3>{-3.0 / 5.0 / sqrt(2.0), -4.0 / 5.0 / sqrt(2.0), 1.0 / sqrt(2.0)}), (Vector<3>{0.0 / sqrt(2.0), 1.0 / sqrt(2.0), 1.0 / sqrt(2.0)}), })
アサート成功: (PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}).c == (Vector<3>{3.0, -2.0, 1.0})
アサート成功: -(PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) == (PolyExp<2>{Vector<3>{-3.0, 2.0, -1.0}})
アサート成功: (PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) * 2.0 == (PolyExp<2>{Vector<3>{6.0, -4.0, 2.0}})
アサート成功: (PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) / 2.0 == (PolyExp<2>{Vector<3>{1.5, -1.0, 0.5}})
アサート成功: (PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) + (PolyExp<2>{Vector<3>{-5.0, 1.0, 0.0}}) == (PolyExp<2>{Vector<3>{-2.0, -1.0, 1.0}})
アサート成功: (PolyExp<2>{Vector<3>{3.0, -2.0, 1.0}}) - (PolyExp<2>{Vector<3>{-5.0, 1.0, 0.0}}) == (PolyExp<2>{Vector<3>{8.0, -3.0, 1.0}})
アサート成功: (PolyExp<2>{Vector<3>{4.0, 2.0, 0.0}}) * (PolyExp<2>{Vector<3>{-3.0, 1.0, 0.0}}) == (PolyExp<2>{Vector<3>{-12.0, -2.0, 2.0}})
アサート成功: get<0>(rts_res2) == 1
アサート成功: nearEqual(get<1>(rts_res2).c[0], 1.0)
アサート成功: get<0>(rts_res2) == 1
アサート成功: nearEqual(get<1>(rts_res2).c[0], -1.0)
アサート成功: get<0>(rts_res2) == 2
アサート成功: nearEqual(get<1>(rts_res2).c[0], -1.0)
アサート成功: nearEqual(get<1>(rts_res2).c[1], 1.0)
アサート成功: get<0>(rts_res2) == 2
アサート成功: nearEqual(get<1>(rts_res2).c[0], -3.0)
アサート成功: nearEqual(get<1>(rts_res2).c[1], 2.0)
アサート成功: get<0>(rts_res3) == 1
アサート成功: nearEqual(get<1>(rts_res3).c[0], 1.0)
アサート成功: get<0>(rts_res3) == 2
アサート成功: nearEqual(get<1>(rts_res3).c[0], -1.0)
アサート成功: nearEqual(get<1>(rts_res3).c[1], 2.0)
アサート成功: get<0>(rts_res3) == 3
アサート成功: nearEqual(get<1>(rts_res3).c[0], -5.0)
アサート成功: nearEqual(get<1>(rts_res3).c[1], -3.0)
アサート成功: nearEqual(get<1>(rts_res3).c[2], 4.0)