123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- #pragma once
- #include <Mathematics/Vector3.h>
- #include <Mathematics/Cone.h>
- #include <Mathematics/Line.h>
- #include <Mathematics/QFNumber.h>
- #include <Mathematics/IntrIntervals.h>
- namespace WwiseGTE
- {
- template <typename Real>
- class FIQuery<Real, Line3<Real>, Cone3<Real>>
- {
- public:
-
-
- using QFN1 = QFNumber<Real, 1>;
-
- using IIQuery = FIIntervalInterval<QFN1>;
- struct Result
- {
-
-
-
-
- static int const isEmpty = 0;
-
-
- static int const isPoint = 1;
-
-
- static int const isSegment = 2;
-
-
-
-
-
- static int const isRayPositive = 3;
-
-
-
-
-
- static int const isRayNegative = 4;
- Result()
- :
- intersect(false),
- type(Result::isEmpty)
- {
-
- }
- void ComputePoints(Vector3<Real> const& origin, Vector3<Real> const& direction)
- {
- switch (type)
- {
- case Result::isEmpty:
- for (int i = 0; i < 3; ++i)
- {
- P[0][i] = QFN1();
- P[1][i] = P[0][i];
- }
- break;
- case Result::isPoint:
- for (int i = 0; i < 3; ++i)
- {
- P[0][i] = origin[i] + direction[i] * t[0];
- P[1][i] = P[0][i];
- }
- break;
- case Result::isSegment:
- for (int i = 0; i < 3; ++i)
- {
- P[0][i] = origin[i] + direction[i] * t[0];
- P[1][i] = origin[i] + direction[i] * t[1];
- }
- break;
- case Result::isRayPositive:
- for (int i = 0; i < 3; ++i)
- {
- P[0][i] = origin[i] + direction[i] * t[0];
- P[1][i] = QFN1(direction[i], 0, t[0].d);
- }
- break;
- case Result::isRayNegative:
- for (int i = 0; i < 3; ++i)
- {
- P[0][i] = origin[i] + direction[i] * t[1];
- P[1][i] = QFN1(direction[i], 0, t[1].d);
- }
- break;
- default:
- LogError("Invalid case.");
- break;
- }
- }
- template <typename OutputType>
- static void Convert(QFN1 const& input, OutputType& output)
- {
- output = static_cast<Real>(input);
- }
- template <typename OutputType>
- static void Convert(Vector3<QFN1> const& input, Vector3<OutputType>& output)
- {
- for (int i = 0; i < 3; ++i)
- {
- output[i] = static_cast<Real>(input[i]);
- }
- }
- bool intersect;
- int type;
- std::array<QFN1, 2> t;
- std::array<Vector3<QFN1>, 2> P;
- };
- Result operator()(Line3<Real> const& line, Cone3<Real> const& cone)
- {
- Result result;
- DoQuery(line.origin, line.direction, cone, result);
- result.ComputePoints(line.origin, line.direction);
- result.intersect = (result.type != Result::isEmpty);
- return result;
- }
- protected:
-
-
-
- void DoQuery(Vector3<Real> const& lineOrigin, Vector3<Real> const& lineDirection,
- Cone3<Real> const& cone, Result& result)
- {
-
-
-
- if (Dot(lineDirection, cone.ray.direction) >= (Real)0)
- {
- DoQuerySpecial(lineOrigin, lineDirection, cone, result);
- }
- else
- {
- DoQuerySpecial(lineOrigin, -lineDirection, cone, result);
- result.t[0] = -result.t[0];
- result.t[1] = -result.t[1];
- std::swap(result.t[0], result.t[1]);
- if (result.type == Result::isRayPositive)
- {
- result.type = Result::isRayNegative;
- }
- }
- }
- void DoQuerySpecial(Vector3<Real> const& lineOrigin, Vector3<Real> const& lineDirection,
- Cone3<Real> const& cone, Result& result)
- {
-
-
-
-
-
- Vector3<Real> PmV = lineOrigin - cone.ray.origin;
- Real UdU = Dot(lineDirection, lineDirection);
- Real DdU = Dot(cone.ray.direction, lineDirection);
- Real DdPmV = Dot(cone.ray.direction, PmV);
- Real UdPmV = Dot(lineDirection, PmV);
- Real PmVdPmV = Dot(PmV, PmV);
- Real c2 = DdU * DdU - cone.cosAngleSqr * UdU;
- Real c1 = DdU * DdPmV - cone.cosAngleSqr * UdPmV;
- Real c0 = DdPmV * DdPmV - cone.cosAngleSqr * PmVdPmV;
- if (c2 != (Real)0)
- {
- Real discr = c1 * c1 - c0 * c2;
- if (discr < (Real)0)
- {
- CaseC2NotZeroDiscrNeg(result);
- }
- else if (discr > (Real)0)
- {
- CaseC2NotZeroDiscrPos(c1, c2, discr, DdU, DdPmV, cone, result);
- }
- else
- {
- CaseC2NotZeroDiscrZero(c1, c2, UdU, UdPmV, DdU, DdPmV, cone, result);
- }
- }
- else if (c1 != (Real)0)
- {
- CaseC2ZeroC1NotZero(c0, c1, DdU, DdPmV, cone, result);
- }
- else
- {
- CaseC2ZeroC1Zero(c0, UdU, UdPmV, DdU, DdPmV, cone, result);
- }
- }
- void CaseC2NotZeroDiscrNeg(Result& result)
- {
-
-
- SetEmpty(result);
- }
- void CaseC2NotZeroDiscrPos(Real const& c1, Real const& c2, Real const& discr,
- Real const& DdU, Real const& DdPmV, Cone3<Real> const& cone, Result& result)
- {
-
-
- Real x = -c1 / c2;
- Real y = (c2 > (Real)0 ? (Real)1 / c2 : (Real)-1 / c2);
- std::array<QFN1, 2> t = { QFN1(x, -y, discr), QFN1(x, y, discr) };
-
-
-
- std::array<QFN1, 2> h = { t[0] * DdU + DdPmV, t[1] * DdU + DdPmV };
- QFN1 zero(0, 0, discr);
- if (h[0] >= zero)
- {
-
-
- SetSegmentClamp(t, h, DdU, DdPmV, cone, result);
- }
- else if (h[1] <= zero)
- {
-
-
- SetEmpty(result);
- }
- else
- {
-
-
- SetRayClamp(h[1], DdU, DdPmV, cone, result);
- }
- }
- void CaseC2NotZeroDiscrZero(Real const& c1, Real const& c2,
- Real const& UdU, Real const& UdPmV, Real const& DdU, Real const& DdPmV,
- Cone3<Real> const& cone, Result& result)
- {
- Real t = -c1 / c2;
- if (t * UdU + UdPmV == (Real)0)
- {
-
-
-
- if (c2 < (Real)0)
- {
-
-
- SetPointClamp(QFN1(t, 0, 0), QFN1(0, 0, 0), cone, result);
- }
- else
- {
-
-
- SetRayClamp(QFN1(0, 0, 0), DdU, DdPmV, cone, result);
- }
- }
- else
- {
-
-
- Real h = t * DdU + DdPmV;
- if (h >= (Real)0)
- {
-
- SetPointClamp(QFN1(t, 0, 0), QFN1(h, 0, 0), cone, result);
- }
- else
- {
-
- SetEmpty(result);
- }
- }
- }
- void CaseC2ZeroC1NotZero(Real const& c0, Real const& c1, Real const& DdU,
- Real const& DdPmV, Cone3<Real> const& cone, Result& result)
- {
-
-
-
-
- Real t = (Real)-0.5 * c0 / c1;
- Real h = t * DdU + DdPmV;
- if (h > (Real)0)
- {
-
-
-
- SetRayClamp(QFN1(h, 0, 0), DdU, DdPmV, cone, result);
- }
- else
- {
-
-
- SetEmpty(result);
- }
- }
- void CaseC2ZeroC1Zero(Real const& c0, Real const& UdU, Real const& UdPmV,
- Real const& DdU, Real const& DdPmV, Cone3<Real> const& cone, Result& result)
- {
- if (c0 != (Real)0)
- {
-
-
- SetEmpty(result);
- }
- else
- {
-
-
-
-
- Real t = -UdPmV / UdU;
- Real h = t * DdU + DdPmV;
- SetRayClamp(QFN1(h, 0, 0), DdU, DdPmV, cone, result);
- }
- }
- void SetEmpty(Result& result)
- {
- result.type = Result::isEmpty;
- result.t[0] = QFN1();
- result.t[1] = QFN1();
- }
- void SetPoint(QFN1 const& t, Result& result)
- {
- result.type = Result::isPoint;
- result.t[0] = t;
- result.t[1] = result.t[0];
- }
- void SetSegment(QFN1 const& t0, QFN1 const& t1, Result& result)
- {
- result.type = Result::isSegment;
- result.t[0] = t0;
- result.t[1] = t1;
- }
- void SetRayPositive(QFN1 const& t, Result& result)
- {
- result.type = Result::isRayPositive;
- result.t[0] = t;
- result.t[1] = QFN1(+1, 0, t.d);
- }
- void SetRayNegative(QFN1 const& t, Result& result)
- {
- result.type = Result::isRayNegative;
- result.t[0] = QFN1(-1, 0, t.d);
- result.t[1] = t;
- }
- void SetPointClamp(QFN1 const& t, QFN1 const& h,
- Cone3<Real> const& cone, Result& result)
- {
- if (cone.HeightInRange(h.x[0]))
- {
-
- SetPoint(t, result);
- }
- else
- {
-
- SetEmpty(result);
- }
- }
- void SetSegmentClamp(std::array<QFN1, 2> const& t, std::array<QFN1, 2> const& h,
- Real const& DdU, Real const& DdPmV, Cone3<Real> const& cone, Result& result)
- {
- std::array<QFN1, 2> hrange =
- {
- QFN1(cone.GetMinHeight(), 0, h[0].d),
- QFN1(cone.GetMaxHeight(), 0, h[0].d)
- };
- if (h[1] > h[0])
- {
- auto iir = (cone.IsFinite() ? IIQuery()(h, hrange) : IIQuery()(h, hrange[0], true));
- if (iir.numIntersections == 2)
- {
-
- SetSegment((iir.overlap[0] - DdPmV) / DdU, (iir.overlap[1] - DdPmV) / DdU, result);
- }
- else if (iir.numIntersections == 1)
- {
-
- SetPoint((iir.overlap[0] - DdPmV) / DdU, result);
- }
- else
- {
-
- SetEmpty(result);
- }
- }
- else
- {
- if (hrange[0] <= h[0] && (cone.IsFinite() ? h[0] <= hrange[1] : true))
- {
-
-
- SetSegment(t[0], t[1], result);
- }
- else
- {
-
-
- SetEmpty(result);
- }
- }
- }
- void SetRayClamp(QFN1 const& h, Real const& DdU, Real const& DdPmV,
- Cone3<Real> const& cone, Result& result)
- {
- std::array<QFN1, 2> hrange =
- {
- QFN1(cone.GetMinHeight(), 0, h.d),
- QFN1(cone.GetMaxHeight(), 0, h.d)
- };
- if (cone.IsFinite())
- {
- auto iir = IIQuery()(hrange, h, true);
- if (iir.numIntersections == 2)
- {
-
- SetSegment((iir.overlap[0] - DdPmV) / DdU, (iir.overlap[1] - DdPmV) / DdU, result);
- }
- else if (iir.numIntersections == 1)
- {
-
- SetPoint((iir.overlap[0] - DdPmV) / DdU, result);
- }
- else
- {
-
- SetEmpty(result);
- }
- }
- else
- {
-
- SetRayPositive((std::max(hrange[0], h) - DdPmV) / DdU, result);
- }
- }
- };
- }
|