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