123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- // 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/FIQuery.h>
- #include <Mathematics/TIQuery.h>
- #include <Mathematics/IntrConvexPolygonHyperplane.h>
- #include <Mathematics/Triangle.h>
- #include <Mathematics/OrientedBox.h>
- #include <Mathematics/Vector3.h>
- // The test-intersection query is based on the document
- // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
- // The find-intersection query clips the triangle against the faces of
- // the oriented box.
- namespace WwiseGTE
- {
- template <typename Real>
- class TIQuery<Real, Triangle3<Real>, OrientedBox3<Real>>
- {
- public:
- struct Result
- {
- bool intersect;
- };
- Result operator()(Triangle3<Real> const& triangle, OrientedBox3<Real> const& box)
- {
- Result result;
- Real min0, max0, min1, max1;
- Vector3<Real> D, edge[3];
- // Test direction of triangle normal.
- edge[0] = triangle.v[1] - triangle.v[0];
- edge[1] = triangle.v[2] - triangle.v[0];
- D = Cross(edge[0], edge[1]);
- min0 = Dot(D, triangle.v[0]);
- max0 = min0;
- GetProjection(D, box, min1, max1);
- if (max1 < min0 || max0 < min1)
- {
- result.intersect = false;
- return result;
- }
- // Test direction of box faces.
- for (int i = 0; i < 3; ++i)
- {
- D = box.axis[i];
- GetProjection(D, triangle, min0, max0);
- Real DdC = Dot(D, box.center);
- min1 = DdC - box.extent[i];
- max1 = DdC + box.extent[i];
- if (max1 < min0 || max0 < min1)
- {
- result.intersect = false;
- return result;
- }
- }
- // Test direction of triangle-box edge cross products.
- edge[2] = edge[1] - edge[0];
- for (int i0 = 0; i0 < 3; ++i0)
- {
- for (int i1 = 0; i1 < 3; ++i1)
- {
- D = Cross(edge[i0], box.axis[i1]);
- GetProjection(D, triangle, min0, max0);
- GetProjection(D, box, min1, max1);
- if (max1 < min0 || max0 < min1)
- {
- result.intersect = false;
- return result;
- }
- }
- }
- result.intersect = true;
- return result;
- }
- private:
- void GetProjection(Vector3<Real> const& axis, Triangle3<Real> const& triangle, Real& imin, Real& imax)
- {
- Real dot[3] =
- {
- Dot(axis, triangle.v[0]),
- Dot(axis, triangle.v[1]),
- Dot(axis, triangle.v[2])
- };
- imin = dot[0];
- imax = imin;
- if (dot[1] < imin)
- {
- imin = dot[1];
- }
- else if (dot[1] > imax)
- {
- imax = dot[1];
- }
- if (dot[2] < imin)
- {
- imin = dot[2];
- }
- else if (dot[2] > imax)
- {
- imax = dot[2];
- }
- }
- void GetProjection(Vector3<Real> const& axis, OrientedBox3<Real> const& box, Real& imin, Real& imax)
- {
- Real origin = Dot(axis, box.center);
- Real maximumExtent =
- std::fabs(box.extent[0] * Dot(axis, box.axis[0])) +
- std::fabs(box.extent[1] * Dot(axis, box.axis[1])) +
- std::fabs(box.extent[2] * Dot(axis, box.axis[2]));
- imin = origin - maximumExtent;
- imax = origin + maximumExtent;
- }
- };
- template <typename Real>
- class FIQuery<Real, Triangle3<Real>, OrientedBox3<Real>>
- {
- public:
- struct Result
- {
- std::vector<Vector3<Real>> insidePolygon;
- std::vector<std::vector<Vector3<Real>>> outsidePolygons;
- };
- Result operator()(Triangle3<Real> const& triangle, OrientedBox3<Real> const& box)
- {
- Result result;
- // Start with the triangle and clip it against each face of the
- // box. The largest number of vertices for the polygon of
- // intersection is 7.
- result.insidePolygon.resize(3);
- for (int i = 0; i < 3; ++i)
- {
- result.insidePolygon[i] = triangle.v[i];
- }
- typedef FIQuery<Real, std::vector<Vector<3, Real>>, Hyperplane<3, Real>> PPQuery;
- Plane3<Real> plane;
- PPQuery ppQuery;
- typename PPQuery::Result ppResult;
- for (int dir = -1; dir <= 1; dir += 2)
- {
- for (int side = 0; side < 3; ++side)
- {
- // Create a plane for the box face that points inside the box.
- plane.normal = ((Real)dir) * box.axis[side];
- plane.constant = Dot(plane.normal, box.center) - box.extent[side];
- ppResult = ppQuery(result.insidePolygon, plane);
- switch (ppResult.configuration)
- {
- case PPQuery::Configuration::SPLIT:
- result.insidePolygon = ppResult.positivePolygon;
- result.outsidePolygons.push_back(ppResult.negativePolygon);
- break;
- case PPQuery::Configuration::POSITIVE_SIDE_VERTEX:
- case PPQuery::Configuration::POSITIVE_SIDE_EDGE:
- case PPQuery::Configuration::POSITIVE_SIDE_STRICT:
- // The result.insidePolygon is already
- // ppResult.positivePolygon, but to make it clear,
- // assign it here.
- result.insidePolygon = ppResult.positivePolygon;
- break;
- case PPQuery::Configuration::NEGATIVE_SIDE_VERTEX:
- case PPQuery::Configuration::NEGATIVE_SIDE_EDGE:
- case PPQuery::Configuration::NEGATIVE_SIDE_STRICT:
- result.insidePolygon.clear();
- result.outsidePolygons.push_back(ppResult.negativePolygon);
- return result;
- case PPQuery::Configuration::CONTAINED:
- // A triangle coplanar with a box face will be
- // processed as if it is inside the box.
- result.insidePolygon = ppResult.intersection;
- break;
- default:
- result.insidePolygon.clear();
- result.outsidePolygons.clear();
- break;
- }
- }
- }
- return result;
- }
- };
- }
|