123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- // 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/IntrConvexPolygonHyperplane.h>
- #include <Mathematics/Triangle.h>
- #include <Mathematics/Vector2.h>
- // The test-intersection queries are based on the document
- // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
- // The find-intersection query for stationary triangles is based on clipping
- // one triangle against the edges of the other to compute the intersection
- // set (if it exists). The find-intersection query for moving triangles is
- // based on the previously mentioned document about the method of separating
- // axes.
- namespace WwiseGTE
- {
- // Test whether two triangles intersect using the method of separating
- // axes. The set of intersection, if it exists, is not computed. The
- // input triangles' vertices must be counterclockwise ordered.
- template <typename Real>
- class TIQuery<Real, Triangle2<Real>, Triangle2<Real>>
- {
- public:
- struct Result
- {
- bool intersect;
- };
- Result operator()(Triangle2<Real> const& triangle0, Triangle2<Real> const& triangle1)
- {
- Result result =
- {
- !Separated(triangle0, triangle1) && !Separated(triangle1, triangle0)
- };
- return result;
- }
- protected:
- // The triangle vertices are projected to t-values for the line P+t*D.
- // The D-vector is nonzero but does not have to be unit length. The
- // return value is +1 if all t >= 0, -1 if all t <= 0, but 0 otherwise
- // in which case the line splits the triangle into two subtriangles,
- // each of positive area.
- int WhichSide(Triangle2<Real> const& triangle, Vector2<Real> const& P, Vector2<Real> const& D) const
- {
- int positive = 0, negative = 0;
- for (int i = 0; i < 3; ++i)
- {
- Real t = Dot(D, triangle.v[i] - P);
- if (t > (Real)0)
- {
- ++positive;
- }
- else if (t < (Real)0)
- {
- --negative;
- }
- if (positive && negative)
- {
- // The triangle has vertices strictly on both sides of
- // the line, so the line splits the triangle into two
- // subtriangles each of positive area.
- return 0;
- }
- }
- // Either positive > 0 or negative > 0 but not both are positive.
- return (positive > 0 ? +1 : -1);
- }
- bool Separated(Triangle2<Real> const& triangle0, Triangle2<Real> const& triangle1) const
- {
- // Test edges of triangle0 for separation. Because of the
- // counterclockwise ordering, the projection interval for
- // triangle0 is [T,0] for some T < 0. Determine whether
- // triangle1 is on the positive side of the line; if it is,
- // the triangles are separated.
- for (int i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
- {
- // The potential separating axis is P+t*D.
- Vector2<Real> P = triangle0.v[i0];
- Vector2<Real> D = Perp(triangle0.v[i1] - triangle0.v[i0]);
- if (WhichSide(triangle1, P, D) > 0)
- {
- // The triangle1 projection interval is [a,b] where a > 0,
- // so the triangles are separated.
- return true;
- }
- }
- return false;
- }
- };
- // Find the convex polygon, segment or point of intersection of two
- // triangles. The input triangles' vertices must be counterclockwise
- // ordered.
- template <typename Real>
- class FIQuery<Real, Triangle2<Real>, Triangle2<Real>>
- {
- public:
- struct Result
- {
- // An intersection exists iff intersection.size() > 0.
- std::vector<Vector2<Real>> intersection;
- };
- Result operator()(Triangle2<Real> const& triangle0, Triangle2<Real> const& triangle1)
- {
- Result result;
- // Start with triangle1 and clip against the edges of triangle0.
- std::vector<Vector2<Real>> polygon =
- {
- triangle1.v[0], triangle1.v[1], triangle1.v[2]
- };
- typedef FIQuery<Real, std::vector<Vector<2, Real>>, Hyperplane<2, Real>> PPQuery;
- PPQuery ppQuery;
- for (int i1 = 2, i0 = 0; i0 < 3; i1 = i0++)
- {
- // Create the clipping line for the current edge. The edge
- // normal N points inside the triangle.
- Vector2<Real> P = triangle0.v[i0];
- Vector2<Real> N = Perp(triangle0.v[i1] - triangle0.v[i0]);
- Hyperplane<2, Real> clippingLine(N, Dot(N, P));
- // Do the clipping operation.
- auto ppResult = ppQuery(polygon, clippingLine);
- if (ppResult.positivePolygon.size() == 0)
- {
- // The current clipped polygon is outside triangle0.
- return result;
- }
- polygon = std::move(ppResult.positivePolygon);
- }
- result.intersection = polygon;
- return result;
- }
- };
- }
|