ApprParallelLines2.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.3.2019.12.27
  7. #pragma once
  8. // Least-squares fit of two parallel lines to points that presumably are
  9. // clustered on the lines. The algorithm is described in
  10. // https://www.geometrictools.com/Documentation/FitParallelLinesToPoints2D.pdf
  11. #include <Mathematics/Polynomial1.h>
  12. #include <Mathematics/RootsPolynomial.h>
  13. #include <Mathematics/Vector2.h>
  14. namespace WwiseGTE
  15. {
  16. template <typename Real>
  17. class ApprParallelLines2
  18. {
  19. public:
  20. ApprParallelLines2()
  21. :
  22. mR0(0), mR1(1), mR2(2), mR3(3), mR4(4), mR5(5), mR6(6)
  23. {
  24. // The constants are set here in case Real is a rational type,
  25. // which avoids construction costs for those types.
  26. }
  27. void Fit(std::vector<Vector2<Real>> const& P, unsigned int maxIterations,
  28. Vector2<Real>& C, Vector2<Real>& V, Real& radius)
  29. {
  30. // Compute the average of the samples.
  31. size_t const n = P.size();
  32. Real const invN = static_cast<Real>(1) / static_cast<Real>(n);
  33. std::vector<Vector2<Real>> PAdjust = P;
  34. Vector2<Real> A{ mR0, mR0 };
  35. for (auto const& sample : PAdjust)
  36. {
  37. A += sample;
  38. }
  39. A *= invN;
  40. // Subtract the average from the samples so that the replacement
  41. // points have zero average.
  42. for (auto& sample : PAdjust)
  43. {
  44. sample -= A;
  45. }
  46. // Compute the Zpq terms.
  47. ZValues data(PAdjust);
  48. // Compute F(sigma,gamma) = f0(sigma) + gamma * f1(sigma).
  49. Polynomial1<Real> f0, f1;
  50. ComputeF(data, f0, f1);
  51. Polynomial1<Real> freduced0(4), freduced1(3);
  52. for (int i = 0; i <= 4; ++i)
  53. {
  54. freduced0[i] = f0[2 * i];
  55. }
  56. for (int i = 0; i <= 3; ++i)
  57. {
  58. freduced1[i] = f1[2 * i + 1];
  59. }
  60. // Evaluate the error function at any (sigma,gamma). Choose (0,1)
  61. // so that we do not have to process a root sigma=0 later.
  62. Real minSigma = mR0, minGamma = mR1;
  63. Real minK = data.Z03 / (mR2 * data.Z02);
  64. Real minKSqr = minK * minK;
  65. Real minRSqr = minKSqr + data.Z02;
  66. Real minError = data.Z04 - mR4 * minK * data.Z03 + (mR4 * minKSqr - data.Z02) * data.Z02;
  67. if (f1 != Polynomial1<Real>{ mR0 })
  68. {
  69. Polynomial1<Real> sigmaSqrPoly{ mR0, mR0, mR1 };
  70. Polynomial1<Real> f0Sqr = f0 * f0, f1Sqr = f1 * f1;
  71. Polynomial1<Real> h = sigmaSqrPoly * f1Sqr + (f0Sqr - f1Sqr);
  72. Polynomial1<Real> hreduced(8);
  73. for (int i = 0; i <= 8; ++i)
  74. {
  75. hreduced[i] = h[2 * i];
  76. }
  77. std::array<Real, 8> roots;
  78. int numRoots = RootsPolynomial<Real>::Find(8, &hreduced[0],
  79. maxIterations, roots.data());
  80. for (int i = 0; i < numRoots; ++i)
  81. {
  82. Real sigmaSqr = roots[i];
  83. if (sigmaSqr > mR0)
  84. {
  85. Real sigma = std::sqrt(sigmaSqr);
  86. Real gamma = -freduced0(sigmaSqr) / (sigma * freduced1(sigmaSqr));
  87. UpdateParameters(data, sigma, sigmaSqr, gamma,
  88. minSigma, minGamma, minK, minRSqr, minError);
  89. }
  90. }
  91. }
  92. else
  93. {
  94. Polynomial1<Real> hreduced(4);
  95. for (int i = 0; i <= 4; ++i)
  96. {
  97. hreduced[i] = f0[2 * i];
  98. }
  99. std::array<Real, 4> roots;
  100. int numRoots = RootsPolynomial<Real>::Find(4, &hreduced[0],
  101. maxIterations, roots.data());
  102. for (int i = 0; i < numRoots; ++i)
  103. {
  104. Real sigmaSqr = roots[i];
  105. if (sigmaSqr > mR0)
  106. {
  107. Real sigma = std::sqrt(sigmaSqr);
  108. Real gamma = std::sqrt(sigma);
  109. UpdateParameters(data, sigma, sigmaSqr, gamma,
  110. minSigma, minGamma, minK, minRSqr, minError);
  111. gamma = -gamma;
  112. UpdateParameters(data, sigma, sigmaSqr, gamma,
  113. minSigma, minGamma, minK, minRSqr, minError);
  114. }
  115. }
  116. }
  117. // Compute the minimizers V, C and radius. The center minK*U must have
  118. // A added to it because the inputs P had A subtracted from them. The
  119. // addition no longer guarantees that Dot(V,C) = 0, so the V-component
  120. // of A+minK*U is projected out so that the returned center has only a
  121. // U-component.
  122. V = Vector2<Real>{ minGamma, minSigma };
  123. C = A + minK * Vector2<Real>{ -minSigma, minGamma };
  124. C -= Dot(C, V) * V;
  125. radius = std::sqrt(minRSqr);
  126. }
  127. private:
  128. struct ZValues
  129. {
  130. ZValues(std::vector<Vector2<Real>> const& P)
  131. :
  132. Z20(0), Z11(0), Z02(0),
  133. Z30(0), Z21(0), Z12(0), Z03(0),
  134. Z40(0), Z31(0), Z22(0), Z13(0), Z04(0)
  135. {
  136. Real const invN = static_cast<Real>(1) / static_cast<Real>(P.size());
  137. for (auto const& sample : P)
  138. {
  139. Real xx = sample[0] * sample[0];
  140. Real xy = sample[0] * sample[1];
  141. Real yy = sample[1] * sample[1];
  142. Real xxx = xx * sample[0];
  143. Real xxy = xy * sample[0];
  144. Real xyy = xy * sample[1];
  145. Real yyy = yy * sample[1];
  146. Real xxxx = xxx * sample[0];
  147. Real xxxy = xxx * sample[1];
  148. Real xxyy = xx * yy;
  149. Real xyyy = yyy * sample[0];
  150. Real yyyy = yyy * sample[1];
  151. Z20 += xx;
  152. Z11 += xy;
  153. Z02 += yy;
  154. Z30 += xxx;
  155. Z21 += xxy;
  156. Z12 += xyy;
  157. Z03 += yyy;
  158. Z40 += xxxx;
  159. Z31 += xxxy;
  160. Z22 += xxyy;
  161. Z13 += xyyy;
  162. Z04 += yyyy;
  163. }
  164. Z20 *= invN;
  165. Z11 *= invN;
  166. Z02 *= invN;
  167. Z30 *= invN;
  168. Z21 *= invN;
  169. Z12 *= invN;
  170. Z03 *= invN;
  171. Z40 *= invN;
  172. Z31 *= invN;
  173. Z22 *= invN;
  174. Z13 *= invN;
  175. Z04 *= invN;
  176. }
  177. Real Z20, Z11, Z02;
  178. Real Z30, Z21, Z12, Z03;
  179. Real Z40, Z31, Z22, Z13, Z04;
  180. };
  181. // Given two polynomials A0+gamma*B0 and A1+gamma*B1, the product is
  182. // [A0*A1+(1-sigma^2)*B0*B1] + gamma*[A0*B1+B0*A1] = A2+gamma*B2.
  183. void ComputeProduct(
  184. Polynomial1<Real> const& A0, Polynomial1<Real> const& B0,
  185. Polynomial1<Real> const& A1, Polynomial1<Real> const& B1,
  186. Polynomial1<Real>& A2, Polynomial1<Real>& B2)
  187. {
  188. Polynomial1<Real> gammaSqr{ mR1, mR0, -mR1 };
  189. A2 = A0 * A1 + gammaSqr * B0 * B1;
  190. B2 = A0 * B1 + B0 * A1;
  191. }
  192. void ComputeF(ZValues const& data, Polynomial1<Real>& f0, Polynomial1<Real>& f1)
  193. {
  194. // Compute the apq and bpq terms.
  195. Polynomial1<Real> a11(2);
  196. a11[0] = data.Z11;
  197. a11[2] = -mR2 * data.Z11;
  198. Polynomial1<Real> b11(1);
  199. b11[1] = data.Z02 - data.Z20;
  200. Polynomial1<Real> a20(2);
  201. a20[0] = data.Z02;
  202. a20[2] = data.Z20 - data.Z02;
  203. Polynomial1<Real> b20(1);
  204. b20[1] = -mR2 * data.Z11;
  205. Polynomial1<Real> a30(3);
  206. a30[1] = -mR3;
  207. a30[3] = mR3 * data.Z12 - data.Z30;
  208. Polynomial1<Real> b30(2);
  209. b30[0] = data.Z03;
  210. b30[2] = mR3 * data.Z21 - data.Z03;
  211. Polynomial1<Real> a21(3);
  212. a21[1] = data.Z03 - mR2 * data.Z21;
  213. a21[3] = mR3 * data.Z21 - data.Z03;
  214. Polynomial1<Real> b21(2);
  215. b21[0] = data.Z12;
  216. b21[2] = data.Z30 - mR3 * data.Z12;
  217. Polynomial1<Real> a40(4);
  218. a40[0] = data.Z04;
  219. a40[2] = mR6 * data.Z22 - mR2 * data.Z04;
  220. a40[4] = data.Z40 - mR6 * data.Z22 + data.Z04;
  221. Polynomial1<Real> b40(3);
  222. b40[1] = -mR4 * data.Z13;
  223. b40[3] = mR4 * (data.Z13 - data.Z31);
  224. Polynomial1<Real> a31(4);
  225. a31[0] = data.Z13;
  226. a31[2] = mR3 * data.Z31 - mR5 * data.Z13;
  227. a31[4] = mR4 * (data.Z13 - data.Z31);
  228. Polynomial1<Real> b31(3);
  229. b31[1] = data.Z04 - mR3 * data.Z22;
  230. b31[3] = mR6 * data.Z22 - data.Z40 - data.Z04;
  231. // Compute S20^2 = c0 + gamma*d0.
  232. Polynomial1<Real> c0, d0;
  233. ComputeProduct(a20, b20, a20, b20, c0, d0);
  234. // Compute S31 * S20^2 = c1 + gamma*d1.
  235. Polynomial1<Real> c1, d1;
  236. ComputeProduct(a31, b31, c0, d0, c1, d1);
  237. // Compute S21 * S20 = c2 + gamma*d2.
  238. Polynomial1<Real> c2, d2;
  239. ComputeProduct(a21, b21, a20, b20, c2, d2);
  240. // Compute S30 * (S21 * S20) = c3 + gamma*d3.
  241. Polynomial1<Real> c3, d3;
  242. ComputeProduct(a30, b30, c2, d2, c3, d3);
  243. // Compute S30 * S11 = c4 + gamma*d4.
  244. Polynomial1<Real> c4, d4;
  245. ComputeProduct(a30, b30, a11, b11, c4, d4);
  246. // Compute S30 * (S30 * S11) = c5 + gamma*d5.
  247. Polynomial1<Real> c5, d5;
  248. ComputeProduct(a30, b30, c4, d4, c5, d5);
  249. // Compute S20^2 * S11 = c6 + gamma*d6.
  250. Polynomial1<Real> c6, d6;
  251. ComputeProduct(c0, d0, a11, b11, c6, d6);
  252. // Compute S20 * (S20^2 * S11) = c7 + gamma*d7.
  253. Polynomial1<Real> c7, d7;
  254. ComputeProduct(a20, b20, c6, d6, c7, d7);
  255. // Compute F = 2*S31*S20^2 - 3*S30*S21*S20 + S30^2*S11
  256. // - 2*S20^3*S11 = f0 + gamma*f1, where f0 is even of degree 8
  257. // and f1 is odd of degree 7.
  258. f0 = mR2 * (c1 - c7) - mR3 * c3 + c5;
  259. f1 = mR2 * (d1 - d7) - mR3 * d3 + d5;
  260. }
  261. void UpdateParameters(ZValues const& data, Real const& sigma, Real const& sigmaSqr,
  262. Real const& gamma, Real& minSigma, Real& minGamma, Real& minK,
  263. Real& minRSqr, Real& minError)
  264. {
  265. // Rather than evaluate apq(sigma) and bpq(sigma), the
  266. // polynomials are evaluated at sigmaSqr to avoid the
  267. // rounding errors that are inherent by computing
  268. // s = sqrt(ssqr); ssqr = s * s;
  269. Real A20 = data.Z02 + (data.Z20 - data.Z02) * sigmaSqr;
  270. Real B20 = -mR2 * data.Z11 * sigma;
  271. Real S20 = A20 + gamma * B20;
  272. Real A30 = -sigma * (mR3 * data.Z12 + (data.Z30 - mR3 * data.Z12) * sigmaSqr);
  273. Real B30 = data.Z03 + (mR3 * data.Z21 - data.Z03) * sigmaSqr;
  274. Real S30 = A30 + gamma * B30;
  275. Real A40 = data.Z04 + ((mR6 * data.Z22 - mR2 * data.Z04)
  276. + (data.Z40 - mR6 * data.Z22 + data.Z04) * sigmaSqr) * sigmaSqr;
  277. Real B40 = -mR4 * sigma * (data.Z13 + (data.Z31 - data.Z13) * sigmaSqr);
  278. Real S40 = A40 + gamma * B40;
  279. Real k = S30 / (mR2 * S20);
  280. Real ksqr = k * k;
  281. Real rsqr = ksqr + S20;
  282. Real error = S40 - mR4 * k * S30 + (mR4 * ksqr - S20) * S20;
  283. if (error < minError)
  284. {
  285. minSigma = sigma;
  286. minGamma = gamma;
  287. minK = k;
  288. minRSqr = rsqr;
  289. minError = error;
  290. }
  291. }
  292. Real const mR0, mR1, mR2, mR3, mR4, mR5, mR6;
  293. };
  294. }