ToolsMath.cpp 7.2 KB

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