ApprParaboloid3.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/LinearSystem.h>
  9. #include <Mathematics/Matrix.h>
  10. #include <Mathematics/Vector3.h>
  11. // Least-squares fit of a paraboloid to a set of point. The paraboloid is
  12. // of the form z = c0*x^2+c1*x*y+c2*y^2+c3*x+c4*y+c5. A successful fit is
  13. // indicated by return value of 'true'.
  14. //
  15. // Given a set of samples (x_i,y_i,z_i) for 0 <= i < N, and assuming
  16. // that the true values lie on a paraboloid
  17. // z = p0*x*x + p1*x*y + p2*y*y + p3*x + p4*y + p5 = Dot(P,Q(x,y))
  18. // where P = (p0,p1,p2,p3,p4,p5) and Q(x,y) = (x*x,x*y,y*y,x,y,1),
  19. // select P to minimize the sum of squared errors
  20. // E(P) = sum_{i=0}^{N-1} [Dot(P,Q_i)-z_i]^2
  21. // where Q_i = Q(x_i,y_i).
  22. //
  23. // The minimum occurs when the gradient of E is the zero vector,
  24. // grad(E) = 2 sum_{i=0}^{N-1} [Dot(P,Q_i)-z_i] Q_i = 0
  25. // Some algebra converts this to a system of 6 equations in 6 unknowns:
  26. // [(sum_{i=0}^{N-1} Q_i Q_i^t] P = sum_{i=0}^{N-1} z_i Q_i
  27. // The product Q_i Q_i^t is a product of the 6x1 matrix Q_i with the
  28. // 1x6 matrix Q_i^t, the result being a 6x6 matrix.
  29. //
  30. // Define the 6x6 symmetric matrix A = sum_{i=0}^{N-1} Q_i Q_i^t and the 6x1
  31. // vector B = sum_{i=0}^{N-1} z_i Q_i. The choice for P is the solution to
  32. // the linear system of equations A*P = B. The entries of A and B indicate
  33. // summations over the appropriate product of variables. For example,
  34. // s(x^3 y) = sum_{i=0}^{N-1} x_i^3 y_i.
  35. //
  36. // +- -++ + +- -+
  37. // | s(x^4) s(x^3 y) s(x^2 y^2) s(x^3) s(x^2 y) s(x^2) ||p0| |s(z x^2)|
  38. // | s(x^2 y^2) s(x y^3) s(x^2 y) s(x y^2) s(x y) ||p1| |s(z x y)|
  39. // | s(y^4) s(x y^2) s(y^3) s(y^2) ||p2| = |s(z y^2)|
  40. // | s(x^2) s(x y) s(x) ||p3| |s(z x) |
  41. // | s(y^2) s(y) ||p4| |s(z y) |
  42. // | s(1) ||p5| |s(z) |
  43. // +- -++ + +- -+
  44. namespace WwiseGTE
  45. {
  46. template <typename Real>
  47. class ApprParaboloid3
  48. {
  49. public:
  50. bool operator()(int numPoints, Vector3<Real> const* points, Real coefficients[6]) const
  51. {
  52. Matrix<6, 6, Real> A;
  53. Vector<6, Real> B;
  54. B.MakeZero();
  55. for (int i = 0; i < numPoints; i++)
  56. {
  57. Real x2 = points[i][0] * points[i][0];
  58. Real xy = points[i][0] * points[i][1];
  59. Real y2 = points[i][1] * points[i][1];
  60. Real zx = points[i][2] * points[i][0];
  61. Real zy = points[i][2] * points[i][1];
  62. Real x3 = points[i][0] * x2;
  63. Real x2y = x2 * points[i][1];
  64. Real xy2 = points[i][0] * y2;
  65. Real y3 = points[i][1] * y2;
  66. Real zx2 = points[i][2] * x2;
  67. Real zxy = points[i][2] * xy;
  68. Real zy2 = points[i][2] * y2;
  69. Real x4 = x2 * x2;
  70. Real x3y = x3 * points[i][1];
  71. Real x2y2 = x2 * y2;
  72. Real xy3 = points[i][0] * y3;
  73. Real y4 = y2 * y2;
  74. A(0, 0) += x4;
  75. A(0, 1) += x3y;
  76. A(0, 2) += x2y2;
  77. A(0, 3) += x3;
  78. A(0, 4) += x2y;
  79. A(0, 5) += x2;
  80. A(1, 2) += xy3;
  81. A(1, 4) += xy2;
  82. A(1, 5) += xy;
  83. A(2, 2) += y4;
  84. A(2, 4) += y3;
  85. A(2, 5) += y2;
  86. A(3, 3) += x2;
  87. A(3, 5) += points[i][0];
  88. A(4, 5) += points[i][1];
  89. B[0] += zx2;
  90. B[1] += zxy;
  91. B[2] += zy2;
  92. B[3] += zx;
  93. B[4] += zy;
  94. B[5] += points[i][2];
  95. }
  96. A(1, 0) = A(0, 1);
  97. A(1, 1) = A(0, 2);
  98. A(1, 3) = A(0, 4);
  99. A(2, 0) = A(0, 2);
  100. A(2, 1) = A(1, 2);
  101. A(2, 3) = A(1, 4);
  102. A(3, 0) = A(0, 3);
  103. A(3, 1) = A(1, 3);
  104. A(3, 2) = A(2, 3);
  105. A(3, 4) = A(1, 5);
  106. A(4, 0) = A(0, 4);
  107. A(4, 1) = A(1, 4);
  108. A(4, 2) = A(2, 4);
  109. A(4, 3) = A(3, 4);
  110. A(4, 4) = A(2, 5);
  111. A(5, 0) = A(0, 5);
  112. A(5, 1) = A(1, 5);
  113. A(5, 2) = A(2, 5);
  114. A(5, 3) = A(3, 5);
  115. A(5, 4) = A(4, 5);
  116. A(5, 5) = static_cast<Real>(numPoints);
  117. return LinearSystem<Real>().Solve(6, &A[0], &B[0], &coefficients[0]);
  118. }
  119. };
  120. }