123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Delaunay2Mesh.h>
- #include <Mathematics/IntpQuadraticNonuniform2.h>
- #include <memory>
- // Interpolation of a scalar-valued function defined on a sphere. Although
- // the sphere lives in 3D, the interpolation is a 2D method whose input
- // points are angles (theta,phi) from spherical coordinates. The domains of
- // the angles are -pi <= theta <= pi and 0 <= phi <= pi.
- namespace WwiseGTE
- {
- template <typename InputType, typename ComputeType, typename RationalType>
- class IntpSphere2
- {
- public:
- // Construction and destruction. For complete spherical coverage,
- // include the two antipodal (theta,phi) points (-pi,0,F(-pi,0)) and
- // (-pi,pi,F(-pi,pi)) in the input data. These correspond to the
- // sphere poles x = 0, y = 0, and |z| = 1.
- ~IntpSphere2() = default;
- IntpSphere2(int numPoints, InputType const* theta, InputType const* phi, InputType const* F)
- :
- mMesh(mDelaunay)
- {
- // Copy the input data. The larger arrays are used to support
- // wrap-around in the Delaunay triangulation for the interpolator.
- int totalPoints = 3 * numPoints;
- mWrapAngles.resize(totalPoints);
- mWrapF.resize(totalPoints);
- for (int i = 0; i < numPoints; ++i)
- {
- mWrapAngles[i][0] = theta[i];
- mWrapAngles[i][1] = phi[i];
- mWrapF[i] = F[i];
- }
- // Use periodicity to get wrap-around in the Delaunay
- // triangulation.
- int i0 = 0, i1 = numPoints, i2 = 2 * numPoints;
- for (/**/; i0 < numPoints; ++i0, ++i1, ++i2)
- {
- mWrapAngles[i1][0] = mWrapAngles[i0][0] + (InputType)GTE_C_TWO_PI;
- mWrapAngles[i2][0] = mWrapAngles[i0][0] - (InputType)GTE_C_TWO_PI;
- mWrapAngles[i1][1] = mWrapAngles[i0][1];
- mWrapAngles[i2][1] = mWrapAngles[i0][1];
- mWrapF[i1] = mWrapF[i0];
- mWrapF[i2] = mWrapF[i0];
- }
- mDelaunay(totalPoints, &mWrapAngles[0], (ComputeType)0);
- mInterp = std::make_unique<IntpQuadraticNonuniform2<InputType, TriangleMesh>>(
- mMesh, &mWrapF[0], (InputType)1);
- }
- // Spherical coordinates are
- // x = cos(theta)*sin(phi)
- // y = sin(theta)*sin(phi)
- // z = cos(phi)
- // for -pi <= theta <= pi, 0 <= phi <= pi. The application can use
- // this function to convert unit length vectors (x,y,z) to (theta,phi).
- static void GetSphericalCoordinates(InputType x, InputType y, InputType z,
- InputType& theta, InputType& phi)
- {
- // Assumes (x,y,z) is unit length. Returns -pi <= theta <= pi and
- // 0 <= phiAngle <= pi.
- if (z < (InputType)1)
- {
- if (z > -(InputType)1)
- {
- theta = std::atan2(y, x);
- phi = std::acos(z);
- }
- else
- {
- theta = -(InputType)GTE_C_PI;
- phi = (InputType)GTE_C_PI;
- }
- }
- else
- {
- theta = -(InputType)GTE_C_PI;
- phi = (InputType)0;
- }
- }
- // The return value is 'true' if and only if the input point is in the
- // convex hull of the input (theta,pi) array, in which case the
- // interpolation is valid.
- bool operator()(InputType theta, InputType phi, InputType& F) const
- {
- Vector2<InputType> angles{ theta, phi };
- InputType thetaDeriv, phiDeriv;
- return (*mInterp)(angles, F, thetaDeriv, phiDeriv);
- }
- private:
- typedef Delaunay2Mesh<InputType, ComputeType, RationalType> TriangleMesh;
- std::vector<Vector2<InputType>> mWrapAngles;
- Delaunay2<InputType, ComputeType> mDelaunay;
- TriangleMesh mMesh;
- std::vector<InputType> mWrapF;
- std::unique_ptr<IntpQuadraticNonuniform2<InputType, TriangleMesh>> mInterp;
- };
- }
|