ToolsMath.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include "../NR/ToolsMath.h"
  2. #include <cmath>
  3. #include <limits>
  4. //------------------------------------------------------//
  5. // Fonctions Mathématiques diverses (by CJ) //
  6. //------------------------------------------------------//
  7. // Calcul la distance entre 2 points
  8. double distance(dpoint pt1, dpoint pt2)
  9. {
  10. double dist;
  11. dist = std::sqrt((pt1.x - pt2.x) * (pt1.x - pt2.x) + (pt1.y - pt2.y) * (pt1.y - pt2.y));
  12. if (dist < 0.000001)
  13. {
  14. dist = 0;
  15. }
  16. return dist;
  17. }
  18. // Renvoie les coefficients p1 et d1 de la droite y = p1.x + b1, à partir de 2 points
  19. void GetCoeffDroite(dpoint pt1, dpoint pt2, double *p1, double *d1, double *b1)
  20. {
  21. // Leger bug pour des écarts très petits
  22. if (fabs(pt1.x - pt2.x) < 0.001)
  23. {
  24. pt1.x = pt2.x;
  25. }
  26. if (fabs(pt1.y - pt2.y) < 0.001)
  27. {
  28. pt1.y = pt2.y;
  29. }
  30. // Calcul des coefficients de la droite
  31. *p1 = (double)std::numeric_limits< int >::max();
  32. *d1 = pt2.x - pt1.x;
  33. if (*d1 != 0)
  34. {
  35. *p1 = (pt2.y - pt1.y) / (*d1);
  36. *b1 = pt1.y - ((*p1) * pt1.x);
  37. }
  38. }
  39. // Renvoie le point (sol1 ou sol2) le plus proche de p1
  40. dpoint leplusproche(dpoint vPoint, dpoint sol1, dpoint sol2)
  41. {
  42. double dist1, dist2;
  43. dpoint res;
  44. dist1 = distance(vPoint, sol1);
  45. dist2 = distance(vPoint, sol2);
  46. if (dist1 < dist2)
  47. {
  48. res.x = sol1.x;
  49. res.y = sol1.y;
  50. }
  51. else
  52. {
  53. res.x = sol2.x;
  54. res.y = sol2.y;
  55. }
  56. return res;
  57. }
  58. // Calcul des 2 points d'intersection entre un cercle et une droite définie par 2 points
  59. bool InterCercleDroite(dpoint p0, double r, dpoint d1, dpoint d2, dpoint *sr1, dpoint *sr2)
  60. {
  61. double a, b, d;
  62. double ka, kb, kc, delta;
  63. dpoint s1, s2;
  64. bool trouve;
  65. trouve = false;
  66. s1.x = -1;
  67. s1.y = -1;
  68. s2.x = -1;
  69. s2.y = -1;
  70. // Coefficient de la droite définie par 2 pts successifs
  71. // Droite y = a.x + b
  72. GetCoeffDroite(d1, d2, &a, &d, &b);
  73. if ((d != 0) && (a != 0))
  74. { // Cas normal
  75. ka = 1 + (a * a);
  76. kb = (2 * a * b) - (2 * p0.x) - (2 * a * p0.y);
  77. kc = (b * b) - (2 * b * p0.y) - ((r * r) - (p0.x * p0.x) - (p0.y * p0.y));
  78. delta = (kb * kb) - (4 * ka * kc);
  79. if (delta == 0)
  80. {
  81. s1.x = -kb / (2 * ka);
  82. s2.x = s1.x;
  83. }
  84. else if (delta > 0)
  85. {
  86. s1.x = (-kb - sqrt(delta)) / (2 * ka);
  87. s2.x = (-kb + sqrt(delta)) / (2 * ka);
  88. }
  89. if (delta >= 0)
  90. {
  91. s1.y = a * s1.x + b;
  92. s2.y = a * s2.x + b;
  93. trouve = true;
  94. }
  95. }
  96. else if (d == 0)
  97. { // La droite est verticale
  98. ka = 1;
  99. kb = -2 * p0.y;
  100. kc = (d1.x * d1.x) - (2 * d1.x * p0.x) - ((r * r) - (p0.x * p0.x) - (p0.y * p0.y));
  101. delta = (kb * kb) - (4 * ka * kc);
  102. if (delta == 0)
  103. {
  104. s1.y = -kb / (2 * ka);
  105. s2.y = s1.y;
  106. }
  107. else if (delta > 0)
  108. {
  109. s1.y = (-kb - sqrt(delta)) / (2 * ka);
  110. s2.y = (-kb + sqrt(delta)) / (2 * ka);
  111. }
  112. if (delta >= 0)
  113. {
  114. s1.x = d1.x;
  115. s2.x = d1.x;
  116. trouve = true;
  117. }
  118. }
  119. else if (a == 0)
  120. { // La droite est horizontale
  121. ka = 1;
  122. kb = -2 * p0.x;
  123. kc = (d1.y * d1.y) - (2 * d1.y * p0.y) - ((r * r) - (p0.x * p0.x) - (p0.y * p0.y));
  124. delta = (kb * kb) - (4 * ka * kc);
  125. if (delta == 0)
  126. {
  127. s1.x = -kb / (2 * ka);
  128. s2.x = s1.x;
  129. }
  130. else if (delta > 0)
  131. {
  132. s1.x = (-kb - sqrt(delta)) / (2 * ka);
  133. s2.x = (-kb + sqrt(delta)) / (2 * ka);
  134. }
  135. if (delta >= 0)
  136. {
  137. s1.y = d1.y;
  138. s2.y = d1.y;
  139. trouve = true;
  140. }
  141. }
  142. sr1->x = s1.x;
  143. sr1->y = s1.y;
  144. sr2->x = s2.x;
  145. sr2->y = s2.y;
  146. return trouve;
  147. }
  148. // Parabole y = a*x^2 + b*x + c (by FP)
  149. //
  150. // N : nombre de points (i.e. taille des vecteurs x[] et y[])
  151. // x : vecteurs des abscisses
  152. // y : vecteurs des ordonees
  153. // a, b, c : les 3 coefficients recherches
  154. void moindres_carres_parabole(int N, dpoint *points, double *a, double *b, double *c)
  155. {
  156. int i;
  157. double d, d1, d2, d3;
  158. double sx = 0.0;
  159. double sx2 = 0.0;
  160. double sx3 = 0.0;
  161. double sx4 = 0.0;
  162. double sy = 0.0;
  163. double syx = 0.0;
  164. double syx2 = 0.0;
  165. double x2;
  166. for ( i = 0; i < N; i++ )
  167. {
  168. sx += points[i].x;
  169. sx2 += ( x2 = points[i].x * points[i].x );
  170. sx3 += x2 * points[i].x;
  171. sx4 += x2 * x2;
  172. sy += points[i].y;
  173. syx += points[i].y * points[i].x;
  174. syx2 += points[i].y * x2;
  175. }
  176. d = sx4 * ( (double) N * sx2 - sx * sx ) + sx3 * ( sx * sx2 - (double) N * sx3 ) + sx2 * ( sx * sx3 - sx2 * sx2 );
  177. d1 = sx4 * ( sx2 * sy - sx * syx ) + sx3 * ( sx * syx2 - sx3 * sy) + sx2 * ( sx3 * syx - sx2 * syx2 );
  178. d2 = sx4 * ( (double) N * syx - sy * sx ) + sx3 * ( sy * sx2 - (double) N * syx2 ) + sx2 * ( syx2 * sx - syx * sx2 );
  179. d3 = syx2 * ( (double) N * sx2 - sx * sx ) + syx * ( sx * sx2 - (double) N * sx3 ) + sy * ( sx * sx3 - sx2 * sx2 );
  180. if (d != 0)
  181. {
  182. *c = d1 / d;
  183. *b = d2 / d;
  184. *a = d3 / d;
  185. }
  186. else
  187. {
  188. *a = *b = *c = 0;
  189. }
  190. }
  191. // Regression linéaire
  192. // Trouve les coefficients de la droite y = bx + a, à partir des points, par regression linéaire
  193. void RegressionLineaire(int n, dpoint *points, double *b, double *a)
  194. {
  195. // calculate the averages of arrays x and y
  196. double xa = 0, ya = 0;
  197. for (int i = 0; i < n; i++)
  198. {
  199. xa += points[i].x;
  200. ya += points[i].y;
  201. }
  202. if (n != 0)
  203. {
  204. xa /= n;
  205. ya /= n;
  206. }
  207. else
  208. {
  209. xa = 0;
  210. ya = 0;
  211. }
  212. // calculate auxiliary sums
  213. double xx = 0, yy = 0, xy = 0;
  214. for (int i = 0; i < n; i++)
  215. {
  216. double tmpx = points[i].x - xa, tmpy = points[i].y - ya;
  217. xx += tmpx * tmpx;
  218. yy += tmpy * tmpy;
  219. xy += tmpx * tmpy;
  220. }
  221. // calculate regression line parameters
  222. // make sure slope is not infinite
  223. // assert(fabs(xx) != 0);
  224. if (xx != 0)
  225. {
  226. *b = xy / xx;
  227. }
  228. else
  229. {
  230. *b = 0;
  231. }
  232. *a = ya - *b * xa;
  233. // Coefficient de regression
  234. // double coeff;
  235. // coeff = (fabs(yy) == 0) ? 1 : xy / sqrt(xx * yy);
  236. }
  237. // Calcul la distance orthogonale entre le point vpt
  238. // et la droite définie par les 2 points pt1 et pt2
  239. double distanceOrthPtDroite(dpoint vpt, dpoint pt1, dpoint pt2, dpoint *pres)
  240. {
  241. double p1, d1, b1, b2, dist;
  242. GetCoeffDroite(pt1, pt2, &p1, &d1, &b1);
  243. if ((p1 != 0) && (d1 != 0))
  244. {
  245. // Perpendiculaire qui passe par vpt
  246. b2 = vpt.y + ((1/p1) * vpt.x);
  247. // Point de rencontre (qui passe par pb)
  248. pres->x = (double) (b2 - b1) / (double) (p1 + (1/p1));
  249. pres->y = (double) p1 * (pres->x) + b1;
  250. }
  251. else if (p1 == 0)
  252. { // pt1-pt2 horizontale
  253. pres->x = vpt.x;
  254. pres->y = pt1.y;
  255. }
  256. else if (d1 == 0)
  257. { // verticale
  258. pres->x = pt1.x;
  259. pres->y = vpt.y;
  260. }
  261. dist = distance(*pres, vpt);
  262. return dist;
  263. }
  264. // Point in Polygon d'après FAQ comp.graphics
  265. bool PtInPolygon(double vx, double vy, dpoint *tpoint, int nbpoint)
  266. {
  267. int i, j;
  268. bool c;
  269. c = false;
  270. for (i = 0, j = nbpoint-1; i < nbpoint; j = i++)
  271. {
  272. if ((((tpoint[i].y <= vy) && (vy < tpoint[j].y)) ||
  273. ((tpoint[j].y <= vy) && (vy < tpoint[i].y))) &&
  274. (vx < (tpoint[j].x - tpoint[i].x) * (vy - tpoint[i].y) / (tpoint[j].y - tpoint[i].y) + tpoint[i].x))
  275. {
  276. c = !c;
  277. }
  278. }
  279. return c;
  280. }
  281. // Est ce que le point x, y est dans l'ellipse a, b
  282. bool PtInEllipse(double x, double y, double a, double b)
  283. {
  284. double result = 10.0;
  285. if ((a != 0.0) && (b != 0.0))
  286. {
  287. result = ((x / a) * (x / a)) + ((y / b) * (y / b));
  288. }
  289. if (result <= 1)
  290. {
  291. return true;
  292. }
  293. return false;
  294. }