123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- #pragma once
- #include <Mathematics/ArbitraryPrecision.h>
- #include <Mathematics/ApprOrthogonalPlane3.h>
- #include <Mathematics/RootsPolynomial.h>
- #include <Mathematics/GaussNewtonMinimizer.h>
- #include <Mathematics/LevenbergMarquardtMinimizer.h>
- namespace WwiseGTE
- {
- template <typename Real>
- class ApprTorus3
- {
- public:
- ApprTorus3()
- {
-
-
-
-
-
-
-
-
-
- mFFunction = [this](GVector<Real> const& P, GVector<Real>& F)
- {
- Real csTheta = std::cos(P[3]);
- Real snTheta = std::sin(P[3]);
- Real csPhi = std::cos(P[4]);
- Real snPhi = std::sin(P[4]);
- Vector<3, Real> C = { P[0], P[1], P[2] };
- Vector<3, Real> N = { csTheta * snPhi, snTheta * snPhi, csPhi };
- Real u = P[5];
- Real v = P[6];
- for (int i = 0; i < mNumPoints; ++i)
- {
- Vector<3, Real> D = C - mPoints[i];
- Real DdotD = Dot(D, D), NdotD = Dot(N, D);
- Real sum = DdotD + v;
- F[i] = sum * sum - (Real)4 * u * (DdotD - NdotD * NdotD);
- }
- };
-
-
-
-
-
- mJFunction = [this](GVector<Real> const& P, GMatrix<Real>& J)
- {
- Real const r2(2), r4(4), r8(8);
- Real csTheta = std::cos(P[3]);
- Real snTheta = std::sin(P[3]);
- Real csPhi = std::cos(P[4]);
- Real snPhi = std::sin(P[4]);
- Vector<3, Real> C = { P[0], P[1], P[2] };
- Vector<3, Real> N = { csTheta * snPhi, snTheta * snPhi, csPhi };
- Real u = P[5];
- Real v = P[6];
- for (int row = 0; row < mNumPoints; ++row)
- {
- Vector<3, Real> D = C - mPoints[row];
- Real DdotD = Dot(D, D), NdotD = Dot(N, D);
- Real sum = DdotD + v;
- Vector<3, Real> dNdTheta{ -snTheta * snPhi, csTheta * snPhi, (Real)0 };
- Vector<3, Real> dNdPhi{ csTheta * csPhi, snTheta * csPhi, -snPhi };
- Vector<3, Real> temp = r4 * sum * D - r8 * u * (D - NdotD * N);
- J(row, 0) = temp[0];
- J(row, 1) = temp[1];
- J(row, 2) = temp[2];
- J(row, 3) = r8 * u * Dot(dNdTheta, D);
- J(row, 4) = r8 * u * Dot(dNdPhi, D);
- J(row, 5) = -r4 * u * (DdotD - NdotD * NdotD);
- J(row, 6) = r2 * sum;
- }
- };
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- std::pair<bool, Real>
- operator()(int numPoints, Vector<3, Real> const* points,
- Vector<3, Real>& C, Vector<3, Real>& N, Real& r0, Real& r1) const
- {
- ApprOrthogonalPlane3<Real> fitter;
- if (!fitter.Fit(numPoints, points))
- {
- return std::make_pair(false, std::numeric_limits<Real>::max());
- }
- C = fitter.GetParameters().first;
- N = fitter.GetParameters().second;
- Real const zero(0);
- Real a0 = zero, a1 = zero, a2 = zero, b0 = zero;
- Real c0 = zero, c1 = zero, c2 = zero, c3 = (Real)numPoints;
- for (int i = 0; i < numPoints; ++i)
- {
- Vector<3, Real> delta = points[i] - C;
- Real dot = Dot(N, delta);
- Real L = Dot(delta, delta), L2 = L * L, L3 = L * L2;
- Real S = (Real)4 * (L - dot * dot), S2 = S * S;
- a2 += S;
- a1 += S * L;
- a0 += S * L2;
- b0 += S2;
- c2 += L;
- c1 += L2;
- c0 += L3;
- }
- Real d1 = a2;
- Real d0 = a1;
- a1 *= (Real)2;
- c2 *= (Real)3;
- c1 *= (Real)3;
- Real invB0 = (Real)1 / b0;
- Real e0 = a0 * invB0;
- Real e1 = a1 * invB0;
- Real e2 = a2 * invB0;
- Rational f0 = c0 - d0 * e0;
- Rational f1 = c1 - d1 * e0 - d0 * e1;
- Rational f2 = c2 - d1 * e1 - d0 * e2;
- Rational f3 = c3 - d1 * e2;
- std::map<Real, int> rmMap;
- RootsPolynomial<Real>::SolveCubic(f0, f1, f2, f3, rmMap);
- Real hmin = std::numeric_limits<Real>::max();
- Real umin = zero, vmin = zero;
- for (auto const& element : rmMap)
- {
- Real v = element.first;
- if (v > zero)
- {
- Real u = e0 + v * (e1 + v * e2);
- if (u > v)
- {
- Real h = zero;
- for (int i = 0; i < numPoints; ++i)
- {
- Vector<3, Real> delta = points[i] - C;
- Real dot = Dot(N, delta);
- Real L = Dot(delta, delta);
- Real S = (Real)4 * (L - dot * dot);
- Real sum = v + L;
- Real term = sum * sum - S * u;
- h += term * term;
- }
- if (h < hmin)
- {
- hmin = h;
- umin = u;
- vmin = v;
- }
- }
- }
- }
- if (hmin == std::numeric_limits<Real>::max())
- {
- return std::make_pair(false, std::numeric_limits<Real>::max());
- }
- r0 = std::sqrt(umin);
- r1 = std::sqrt(umin - vmin);
- return std::make_pair(true, hmin);
- }
-
-
-
-
-
-
-
-
- typename GaussNewtonMinimizer<Real>::Result
- operator()(int numPoints, Vector<3, Real> const* points,
- size_t maxIterations, Real updateLengthTolerance, Real errorDifferenceTolerance,
- bool useTorusInputAsInitialGuess,
- Vector<3, Real>& C, Vector<3, Real>& N, Real& r0, Real& r1) const
- {
- mNumPoints = numPoints;
- mPoints = points;
- GaussNewtonMinimizer<Real> minimizer(7, mNumPoints, mFFunction, mJFunction);
- if (!useTorusInputAsInitialGuess)
- {
- operator()(numPoints, points, C, N, r0, r1);
- }
- GVector<Real> initial(7);
-
- initial[0] = C[0];
- initial[1] = C[1];
- initial[2] = C[2];
-
-
- if (std::fabs(N[2]) < (Real)1)
- {
- initial[3] = std::atan2(N[1], N[0]);
- initial[4] = std::acos(N[2]);
- }
- else
- {
- initial[3] = (Real)0;
- initial[4] = (Real)0;
- }
-
- initial[5] = r0 * r0;
- initial[6] = initial[5] - r1 * r1;
- auto result = minimizer(initial, maxIterations, updateLengthTolerance,
- errorDifferenceTolerance);
-
-
-
- C[0] = result.minLocation[0];
- C[1] = result.minLocation[1];
- C[2] = result.minLocation[2];
- Real theta = result.minLocation[3];
- Real phi = result.minLocation[4];
- Real csTheta = std::cos(theta);
- Real snTheta = std::sin(theta);
- Real csPhi = std::cos(phi);
- Real snPhi = std::sin(phi);
- N[0] = csTheta * snPhi;
- N[1] = snTheta * snPhi;
- N[2] = csPhi;
- Real u = result.minLocation[5];
- Real v = result.minLocation[6];
- r0 = std::sqrt(u);
- r1 = std::sqrt(u - v);
- mNumPoints = 0;
- mPoints = nullptr;
- return result;
- }
-
-
-
-
-
-
-
-
- typename LevenbergMarquardtMinimizer<Real>::Result
- operator()(int numPoints, Vector<3, Real> const* points,
- size_t maxIterations, Real updateLengthTolerance, Real errorDifferenceTolerance,
- Real lambdaFactor, Real lambdaAdjust, size_t maxAdjustments,
- bool useTorusInputAsInitialGuess,
- Vector<3, Real>& C, Vector<3, Real>& N, Real& r0, Real& r1) const
- {
- mNumPoints = numPoints;
- mPoints = points;
- LevenbergMarquardtMinimizer<Real> minimizer(7, mNumPoints, mFFunction, mJFunction);
- if (!useTorusInputAsInitialGuess)
- {
- operator()(numPoints, points, C, N, r0, r1);
- }
- GVector<Real> initial(7);
-
- initial[0] = C[0];
- initial[1] = C[1];
- initial[2] = C[2];
-
-
- if (std::fabs(N[2]) < (Real)1)
- {
- initial[3] = std::atan2(N[1], N[0]);
- initial[4] = std::acos(N[2]);
- }
- else
- {
- initial[3] = (Real)0;
- initial[4] = (Real)0;
- }
-
- initial[5] = r0 * r0;
- initial[6] = initial[5] - r1 * r1;
- auto result = minimizer(initial, maxIterations, updateLengthTolerance,
- errorDifferenceTolerance, lambdaFactor, lambdaAdjust, maxAdjustments);
-
-
-
- C[0] = result.minLocation[0];
- C[1] = result.minLocation[1];
- C[2] = result.minLocation[2];
- Real theta = result.minLocation[3];
- Real phi = result.minLocation[4];
- Real csTheta = std::cos(theta);
- Real snTheta = std::sin(theta);
- Real csPhi = std::cos(phi);
- Real snPhi = std::sin(phi);
- N[0] = csTheta * snPhi;
- N[1] = snTheta * snPhi;
- N[2] = csPhi;
- Real u = result.minLocation[5];
- Real v = result.minLocation[6];
- r0 = std::sqrt(u);
- r1 = std::sqrt(u - v);
- mNumPoints = 0;
- mPoints = nullptr;
- return result;
- }
- private:
- typedef BSRational<UIntegerAP32> Rational;
- mutable int mNumPoints;
- mutable Vector<3, Real> const* mPoints;
- std::function<void(GVector<Real> const&, GVector<Real>&)> mFFunction;
- std::function<void(GVector<Real> const&, GMatrix<Real>&)> mJFunction;
- };
- }
|