math.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // Begin License:
  2. // Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
  3. // All rights reserved.
  4. //
  5. // This file is part of the Carve CSG Library (http://carve-csg.com/)
  6. //
  7. // This file may be used under the terms of either the GNU General
  8. // Public License version 2 or 3 (at your option) as published by the
  9. // Free Software Foundation and appearing in the files LICENSE.GPL2
  10. // and LICENSE.GPL3 included in the packaging of this file.
  11. //
  12. // This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
  13. // INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
  14. // A PARTICULAR PURPOSE.
  15. // End:
  16. #if defined(HAVE_CONFIG_H)
  17. # include <carve_config.h>
  18. #endif
  19. #include <carve/math.hpp>
  20. #include <carve/matrix.hpp>
  21. #include <iostream>
  22. #include <limits>
  23. #include <stdio.h>
  24. #define M_2PI_3 2.0943951023931953
  25. #define M_SQRT_3_4 0.8660254037844386
  26. #define EPS std::numeric_limits<double>::epsilon()
  27. namespace carve {
  28. namespace math {
  29. struct Root {
  30. double root;
  31. int multiplicity;
  32. Root(double r) : root(r), multiplicity(1) {}
  33. Root(double r, int m) : root(r), multiplicity(m) {}
  34. };
  35. namespace {
  36. #if 0
  37. void cplx_sqrt(double re, double im,
  38. double &re_1, double &im_1,
  39. double &re_2, double &im_2) {
  40. if (re == 0.0 && im == 0.0) {
  41. re_1 = re_2 = re;
  42. im_1 = im_2 = im;
  43. } else {
  44. double d = sqrt(re * re + im * im);
  45. re_1 = sqrt((d + re) / 2.0);
  46. re_2 = re_1;
  47. im_1 = fabs(sqrt((d - re) / 2.0));
  48. im_2 = -im_1;
  49. }
  50. }
  51. #endif
  52. #if 0
  53. void cplx_cbrt(double re, double im,
  54. double &re_1, double &im_1,
  55. double &re_2, double &im_2,
  56. double &re_3, double &im_3) {
  57. if (re == 0.0 && im == 0.0) {
  58. re_1 = re_2 = re_3 = re;
  59. im_1 = im_2 = im_3 = im;
  60. } else {
  61. double r = cbrt(sqrt(re * re + im * im));
  62. double t = atan2(im, re) / 3.0;
  63. re_1 = r * cos(t);
  64. im_1 = r * sin(t);
  65. re_2 = r * cos(t + M_TWOPI / 3.0);
  66. im_2 = r * sin(t + M_TWOPI / 3.0);
  67. re_3 = r * cos(t + M_TWOPI * 2.0 / 3.0);
  68. im_3 = r * sin(t + M_TWOPI * 2.0 / 3.0);
  69. }
  70. }
  71. #endif
  72. void add_root(std::vector<Root> &roots, double root) {
  73. for (size_t i = 0; i < roots.size(); ++i) {
  74. if (roots[i].root == root) {
  75. roots[i].multiplicity++;
  76. return;
  77. }
  78. }
  79. roots.push_back(Root(root));
  80. }
  81. void linear_roots(double c1, double c0, std::vector<Root> &roots) {
  82. roots.push_back(Root(c0 / c1));
  83. }
  84. void quadratic_roots(double c2, double c1, double c0, std::vector<Root> &roots) {
  85. if (fabs(c2) < EPS) {
  86. linear_roots(c1, c0, roots);
  87. return;
  88. }
  89. double p = 0.5 * c1 / c2;
  90. double dis = p * p - c0 / c2;
  91. if (dis > 0.0) {
  92. dis = sqrt(dis);
  93. if (-p - dis != -p + dis) {
  94. roots.push_back(Root(-p - dis));
  95. roots.push_back(Root(-p + dis));
  96. } else {
  97. roots.push_back(Root(-p, 2));
  98. }
  99. }
  100. }
  101. void cubic_roots(double c3, double c2, double c1, double c0, std::vector<Root> &roots) {
  102. int n_sol = 0;
  103. double _r[3];
  104. if (fabs(c3) < EPS) {
  105. quadratic_roots(c2, c1, c0, roots);
  106. return;
  107. }
  108. if (fabs(c0) < EPS) {
  109. quadratic_roots(c3, c2, c1, roots);
  110. add_root(roots, 0.0);
  111. return;
  112. }
  113. double xN = -c2 / (3.0 * c3);
  114. double yN = c0 + xN * (c1 + xN * (c2 + c3 * xN));
  115. double delta_sq = (c2 * c2 - 3.0 * c3 * c1) / (9.0 * c3 * c3);
  116. double h_sq = 4.0 / 9.0 * (c2 * c2 - 3.0 * c3 * c1) * (delta_sq * delta_sq);
  117. double dis = yN * yN - h_sq;
  118. if (dis > EPS) {
  119. // One real root, two complex roots.
  120. double dis_sqrt = sqrt(dis);
  121. double r_p = yN - dis_sqrt;
  122. double r_q = yN + dis_sqrt;
  123. double p = cbrt(fabs(r_p)/(2.0 * c3));
  124. double q = cbrt(fabs(r_q)/(2.0 * c3));
  125. if (r_p > 0.0) p = -p;
  126. if (r_q > 0.0) q = -q;
  127. _r[0] = xN + p + q;
  128. n_sol = 1;
  129. double re = xN - p * .5 - q * .5;
  130. double im = p * M_SQRT_3_4 - q * M_SQRT_3_4;
  131. // root 2: xN + p * exp(M_2PI_3.i) + q * exp(-M_2PI_3.i);
  132. // root 3: complex conjugate of root 2
  133. if (im < EPS) {
  134. _r[1] = _r[2] = re;
  135. n_sol += 2;
  136. }
  137. } else if (dis < -EPS) {
  138. // Three distinct real roots.
  139. double theta = acos(-yN / sqrt(h_sq)) / 3.0;
  140. double delta = sqrt(c2 * c2 - 3.0 * c3 * c1) / (3.0 * c3);
  141. _r[0] = xN + (2.0 * delta) * cos(theta);
  142. _r[1] = xN + (2.0 * delta) * cos(M_2PI_3 - theta);
  143. _r[2] = xN + (2.0 * delta) * cos(M_2PI_3 + theta);
  144. n_sol = 3;
  145. } else {
  146. // Three real roots (two or three equal).
  147. double r = yN / (2.0 * c3);
  148. double delta = cbrt(r);
  149. _r[0] = xN + delta;
  150. _r[1] = xN + delta;
  151. _r[2] = xN - 2.0 * delta;
  152. n_sol = 3;
  153. }
  154. for (int i=0; i < n_sol; i++) {
  155. add_root(roots, _r[i]);
  156. }
  157. }
  158. }
  159. static void U(const Matrix3 &m,
  160. double l,
  161. double u[6],
  162. double &u_max,
  163. int &u_argmax) {
  164. u[0] = (m._22 - l) * (m._33 - l) - m._23 * m._23;
  165. u[1] = m._13 * m._23 - m._12 * (m._33 - l);
  166. u[2] = m._12 * m._23 - m._13 * (m._22 - l);
  167. u[3] = (m._11 - l) * (m._33 - l) - m._13 * m._13;
  168. u[4] = m._12 * m._13 - m._23 * (m._11 - l);
  169. u[5] = (m._11 - l) * (m._22 - l) - m._12 * m._12;
  170. u_max = -1.0;
  171. u_argmax = -1;
  172. for (int i = 0; i < 6; ++i) {
  173. if (u_max < fabs(u[i])) { u_max = fabs(u[i]); u_argmax = i; }
  174. }
  175. }
  176. static void eig1(const Matrix3 &m, double l, carve::geom::vector<3> &e) {
  177. double u[6];
  178. double u_max;
  179. int u_argmax;
  180. U(m, l, u, u_max, u_argmax);
  181. switch(u_argmax) {
  182. case 0:
  183. e.x = u[0]; e.y = u[1]; e.z = u[2]; break;
  184. case 1: case 3:
  185. e.x = u[1]; e.y = u[3]; e.z = u[4]; break;
  186. case 2: case 4: case 5:
  187. e.x = u[2]; e.y = u[4]; e.z = u[5]; break;
  188. }
  189. e.normalize();
  190. }
  191. static void eig2(const Matrix3 &m, double l, carve::geom::vector<3> &e1, carve::geom::vector<3> &e2) {
  192. double u[6];
  193. double u_max;
  194. int u_argmax;
  195. U(m, l, u, u_max, u_argmax);
  196. switch(u_argmax) {
  197. case 0: case 1:
  198. e1.x = -m._12; e1.y = m._11; e1.z = 0.0;
  199. e2.x = -m._13 * m._11; e2.y = -m._13 * m._12; e2.z = m._11 * m._11 + m._12 * m._12;
  200. break;
  201. case 2:
  202. e1.x = m._12; e1.y = 0.0; e1.z = -m._11;
  203. e2.x = -m._12 * m._11; e2.y = m._11 * m._11 + m._13 * m._13; e2.z = -m._12 * m._13;
  204. break;
  205. case 3: case 4:
  206. e1.x = 0.0; e1.y = -m._23; e1.z = -m._22;
  207. e2.x = m._22 * m._22 + m._23 * m._23; e2.y = -m._12 * m._22; e2.z = -m._12 * m._23;
  208. break;
  209. case 5:
  210. e1.x = 0.0; e1.y = -m._33; e1.z = m._23;
  211. e2.x = m._23 * m._23 + m._33 * m._33; e2.y = -m._13 * m._23; e2.z = -m._13 * m._33;
  212. }
  213. e1.normalize();
  214. e2.normalize();
  215. }
  216. #if 0
  217. static void eig3(const Matrix3 &m,
  218. double l,
  219. carve::geom::vector<3> &e1,
  220. carve::geom::vector<3> &e2,
  221. carve::geom::vector<3> &e3) {
  222. e1.x = 1.0; e1.y = 0.0; e1.z = 0.0;
  223. e2.x = 0.0; e2.y = 1.0; e2.z = 0.0;
  224. e3.x = 0.0; e3.y = 0.0; e3.z = 1.0;
  225. }
  226. #endif
  227. void eigSolveSymmetric(const Matrix3 &m,
  228. double &l1, carve::geom::vector<3> &e1,
  229. double &l2, carve::geom::vector<3> &e2,
  230. double &l3, carve::geom::vector<3> &e3) {
  231. double c0 =
  232. m._11 * m._22 * m._33 +
  233. 2.0 * m._12 * m._13 * m._23 -
  234. m._11 * m._23 * m._23 -
  235. m._22 * m._13 * m._13 -
  236. m._33 * m._12 * m._12;
  237. double c1 =
  238. m._11 * m._22 -
  239. m._12 * m._12 +
  240. m._11 * m._33 -
  241. m._13 * m._13 +
  242. m._22 * m._33 -
  243. m._23 * m._23;
  244. double c2 =
  245. m._11 +
  246. m._22 +
  247. m._33;
  248. double a = (3.0 * c1 - c2 * c2) / 3.0;
  249. double b = (-2.0 * c2 * c2 * c2 + 9.0 * c1 * c2 - 27.0 * c0) / 27.0;
  250. double Q = b * b / 4.0 + a * a * a / 27.0;
  251. if (fabs(Q) < 1e-16) {
  252. l1 = m._11; e1.x = 1.0; e1.y = 0.0; e1.z = 0.0;
  253. l2 = m._22; e2.x = 0.0; e2.y = 1.0; e2.z = 0.0;
  254. l3 = m._33; e3.x = 0.0; e3.y = 0.0; e3.z = 1.0;
  255. } else if (Q > 0) {
  256. l1 = l2 = c2 / 3.0 + cbrt(b / 2.0);
  257. l3 = c2 / 3.0 - 2.0 * cbrt(b / 2.0);
  258. eig2(m, l1, e1, e2);
  259. eig1(m, l3, e3);
  260. } else if (Q < 0) {
  261. double t = atan2(sqrt(-Q), -b / 2.0);
  262. double cos_t3 = cos(t / 3.0);
  263. double sin_t3 = sin(t / 3.0);
  264. double r = cbrt(sqrt(b * b / 4.0 - Q));
  265. l1 = c2 / 3.0 + 2 * r * cos_t3;
  266. l2 = c2 / 3.0 - r * (cos_t3 + M_SQRT_3 * sin_t3);
  267. l3 = c2 / 3.0 - r * (cos_t3 - M_SQRT_3 * sin_t3);
  268. eig1(m, l1, e1);
  269. eig1(m, l2, e2);
  270. eig1(m, l3, e3);
  271. }
  272. }
  273. void eigSolve(const Matrix3 &m, double &l1, double &l2, double &l3) {
  274. double c3, c2, c1, c0;
  275. std::vector<Root> roots;
  276. c3 = -1.0;
  277. c2 = m._11 + m._22 + m._33;
  278. c1 =
  279. -(m._22 * m._33 + m._11 * m._22 + m._11 * m._33)
  280. +(m._23 * m._32 + m._13 * m._31 + m._12 * m._21);
  281. c0 =
  282. +(m._11 * m._22 - m._12 * m._21) * m._33
  283. -(m._11 * m._23 - m._13 * m._21) * m._32
  284. +(m._12 * m._23 - m._13 * m._22) * m._31;
  285. cubic_roots(c3, c2, c1, c0, roots);
  286. for (size_t i = 0; i < roots.size(); i++) {
  287. Matrix3 M(m);
  288. M._11 -= roots[i].root;
  289. M._22 -= roots[i].root;
  290. M._33 -= roots[i].root;
  291. // solve M.v = 0
  292. }
  293. std::cerr << "n_roots=" << roots.size() << std::endl;
  294. for (size_t i = 0; i < roots.size(); i++) {
  295. fprintf(stderr, " %.24f(%d)", roots[i].root, roots[i].multiplicity);
  296. }
  297. std::cerr << std::endl;
  298. }
  299. }
  300. }