123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- #pragma once
- #include <Mathematics/ContOrientedBox3.h>
- #include <Mathematics/DistPointHyperellipsoid.h>
- #include <Mathematics/Matrix3x3.h>
- #include <Mathematics/MinimizeN.h>
- #include <Mathematics/Rotation.h>
- namespace WwiseGTE
- {
- template <typename Real>
- class ApprEllipsoid3
- {
- public:
- Real operator()(int numPoints, Vector3<Real> const* points,
- Vector3<Real>& center, Matrix3x3<Real>& rotate, Real diagonal[3]) const
- {
-
-
-
- std::function<Real(Real const*)> energy =
- [numPoints, points](Real const* input)
- {
- return Energy(numPoints, points, input);
- };
- MinimizeN<Real> minimizer(9, energy, 8, 8, 32);
-
-
- OrientedBox3<Real> box;
- GetContainer(numPoints, points, box);
- center = box.center;
- for (int i = 0; i < 3; ++i)
- {
- rotate.SetRow(i, box.axis[i]);
- diagonal[i] = box.extent[i];
- }
- Real angle[3];
- MatrixToAngles(rotate, angle);
- Real extent[3] =
- {
- diagonal[0] * std::fabs(rotate(0, 0)) +
- diagonal[1] * std::fabs(rotate(0, 1)) +
- diagonal[2] * std::fabs(rotate(0, 2)),
- diagonal[0] * std::fabs(rotate(1, 0)) +
- diagonal[1] * std::fabs(rotate(1, 1)) +
- diagonal[2] * std::fabs(rotate(1, 2)),
- diagonal[0] * std::fabs(rotate(2, 0)) +
- diagonal[1] * std::fabs(rotate(2, 1)) +
- diagonal[2] * std::fabs(rotate(2, 2))
- };
- Real v0[9] =
- {
- (Real)0.5 * diagonal[0],
- (Real)0.5 * diagonal[1],
- (Real)0.5 * diagonal[2],
- center[0] - extent[0],
- center[1] - extent[1],
- center[2] - extent[2],
- -(Real)GTE_C_PI,
- (Real)0,
- (Real)0
- };
- Real v1[9] =
- {
- (Real)2 * diagonal[0],
- (Real)2 * diagonal[1],
- (Real)2 * diagonal[2],
- center[0] + extent[0],
- center[1] + extent[1],
- center[2] + extent[2],
- (Real)GTE_C_PI,
- (Real)GTE_C_PI,
- (Real)GTE_C_PI
- };
- Real vInitial[9] =
- {
- diagonal[0],
- diagonal[1],
- diagonal[2],
- center[0],
- center[1],
- center[2],
- angle[0],
- angle[1],
- angle[2]
- };
- Real vMin[9], error;
- minimizer.GetMinimum(v0, v1, vInitial, vMin, error);
- diagonal[0] = vMin[0];
- diagonal[1] = vMin[1];
- diagonal[2] = vMin[2];
- center[0] = vMin[3];
- center[1] = vMin[4];
- center[2] = vMin[5];
- AnglesToMatrix(&vMin[6], rotate);
- return error;
- }
- private:
- static void MatrixToAngles(Matrix3x3<Real> const& rotate, Real angle[3])
- {
-
-
- Real const zero = (Real)0;
- Real const one = (Real)1;
- AxisAngle<3, Real> aa = Rotation<3, Real>(rotate);
- if (-one < aa.axis[2])
- {
- if (aa.axis[2] < one)
- {
- angle[0] = std::atan2(aa.axis[1], aa.axis[0]);
- angle[1] = std::acos(aa.axis[2]);
- }
- else
- {
- angle[0] = zero;
- angle[1] = zero;
- }
- }
- else
- {
- angle[0] = zero;
- angle[1] = (Real)GTE_C_PI;
- }
- }
- static void AnglesToMatrix(Real const angle[3], Matrix3x3<Real>& rotate)
- {
-
-
- Real cs0 = std::cos(angle[0]);
- Real sn0 = std::sin(angle[0]);
- Real cs1 = std::cos(angle[1]);
- Real sn1 = std::sin(angle[1]);
- AxisAngle<3, Real> aa;
- aa.axis = { cs0 * sn1, sn0 * sn1, cs1 };
- aa.angle = angle[2];
- rotate = Rotation<3, Real>(aa);
- }
- static Real Energy(int numPoints, Vector3<Real> const* points, Real const* input)
- {
-
- Matrix3x3<Real> rotate;
- AnglesToMatrix(&input[6], rotate);
-
-
- Real maxValue = std::max(std::max(input[0], input[1]), input[2]);
- Real invMax = (Real)1 / maxValue;
- Ellipsoid3<Real> ellipsoid(Vector3<Real>::Zero(), { Vector3<Real>::Unit(0),
- Vector3<Real>::Unit(1), Vector3<Real>::Unit(2) }, { invMax * input[0],
- invMax * input[1], invMax * input[2] });
-
-
- DCPQuery<Real, Vector3<Real>, Ellipsoid3<Real>> peQuery;
- Real energy = (Real)0;
- for (int i = 0; i < numPoints; ++i)
- {
- Vector3<Real> diff = points[i] -
- Vector3<Real>{ input[3], input[4], input[5] };
- Vector3<Real> prod = invMax * (diff * rotate);
- Real dist = peQuery(prod, ellipsoid).distance;
- energy += maxValue * dist;
- }
- return energy;
- }
- };
- }
|