123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- // 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/TIQuery.h>
- #include <Mathematics/FIQuery.h>
- #include <Mathematics/Hyperplane.h>
- #include <Mathematics/Vector.h>
- #include <list>
- #include <vector>
- // The intersection queries are based on the document
- // https://www.geometrictools.com/Documentation/ClipConvexPolygonByHyperplane.pdf
- namespace WwiseGTE
- {
- template <int N, typename Real>
- class TIQuery<Real, std::vector<Vector<N, Real>>, Hyperplane<N, Real>>
- {
- public:
- enum class Configuration
- {
- SPLIT,
- POSITIVE_SIDE_VERTEX,
- POSITIVE_SIDE_EDGE,
- POSITIVE_SIDE_STRICT,
- NEGATIVE_SIDE_VERTEX,
- NEGATIVE_SIDE_EDGE,
- NEGATIVE_SIDE_STRICT,
- CONTAINED,
- INVALID_POLYGON
- };
- struct Result
- {
- bool intersect;
- Configuration configuration;
- };
- Result operator()(std::vector<Vector<N, Real>> const& polygon, Hyperplane<N, Real> const& hyperplane)
- {
- Result result;
- size_t const numVertices = polygon.size();
- if (numVertices < 3)
- {
- // The convex polygon must have at least 3 vertices.
- result.intersect = false;
- result.configuration = Configuration::INVALID_POLYGON;
- return result;
- }
- // Determine on which side of the hyperplane each vertex lies.
- size_t numPositive = 0, numNegative = 0, numZero = 0;
- for (size_t i = 0; i < numVertices; ++i)
- {
- Real h = Dot(hyperplane.normal, polygon[i]) - hyperplane.constant;
- if (h > (Real)0)
- {
- ++numPositive;
- }
- else if (h < (Real)0)
- {
- ++numNegative;
- }
- else
- {
- ++numZero;
- }
- }
- if (numPositive > 0)
- {
- if (numNegative > 0)
- {
- result.intersect = true;
- result.configuration = Configuration::SPLIT;
- }
- else if (numZero == 0)
- {
- result.intersect = false;
- result.configuration = Configuration::POSITIVE_SIDE_STRICT;
- }
- else if (numZero == 1)
- {
- result.intersect = true;
- result.configuration = Configuration::POSITIVE_SIDE_VERTEX;
- }
- else // numZero > 1
- {
- result.intersect = true;
- result.configuration = Configuration::POSITIVE_SIDE_EDGE;
- }
- }
- else if (numNegative > 0)
- {
- if (numZero == 0)
- {
- result.intersect = false;
- result.configuration = Configuration::NEGATIVE_SIDE_STRICT;
- }
- else if (numZero == 1)
- {
- // The polygon touches the plane in a vertex or an edge.
- result.intersect = true;
- result.configuration = Configuration::NEGATIVE_SIDE_VERTEX;
- }
- else // numZero > 1
- {
- result.intersect = true;
- result.configuration = Configuration::NEGATIVE_SIDE_EDGE;
- }
- }
- else // numZero == numVertices
- {
- result.intersect = true;
- result.configuration = Configuration::CONTAINED;
- }
- return result;
- }
- };
- template <int N, typename Real>
- class FIQuery<Real, std::vector<Vector<N, Real>>, Hyperplane<N, Real>>
- {
- public:
- enum class Configuration
- {
- SPLIT,
- POSITIVE_SIDE_VERTEX,
- POSITIVE_SIDE_EDGE,
- POSITIVE_SIDE_STRICT,
- NEGATIVE_SIDE_VERTEX,
- NEGATIVE_SIDE_EDGE,
- NEGATIVE_SIDE_STRICT,
- CONTAINED,
- INVALID_POLYGON
- };
- struct Result
- {
- // The intersection is either empty, a single vertex, a single
- // edge or the polygon is contained by the hyperplane.
- Configuration configuration;
- std::vector<Vector<N, Real>> intersection;
- // If 'configuration' is POSITIVE_* or SPLIT, this polygon is the
- // portion of the query input 'polygon' on the positive side of
- // the hyperplane with possibly a vertex or edge on the hyperplane.
- std::vector<Vector<N, Real>> positivePolygon;
- // If 'configuration' is NEGATIVE_* or SPLIT, this polygon is the
- // portion of the query input 'polygon' on the negative side of
- // the hyperplane with possibly a vertex or edge on the hyperplane.
- std::vector<Vector<N, Real>> negativePolygon;
- };
- Result operator()(std::vector<Vector<N, Real>> const& polygon, Hyperplane<N, Real> const& hyperplane)
- {
- Result result;
- size_t const numVertices = polygon.size();
- if (numVertices < 3)
- {
- // The convex polygon must have at least 3 vertices.
- result.configuration = Configuration::INVALID_POLYGON;
- return result;
- }
- // Determine on which side of the hyperplane the vertices live.
- // The index maxPosIndex stores the index of the vertex on the
- // positive side of the hyperplane that is farthest from the
- // hyperplane. The index maxNegIndex stores the index of the
- // vertex on the negative side of the hyperplane that is farthest
- // from the hyperplane. If one or the other such vertex does not
- // exist, the corresponding index will remain its initial value of
- // max(size_t).
- std::vector<Real> height(numVertices);
- std::vector<size_t> zeroHeightIndices;
- zeroHeightIndices.reserve(numVertices);
- size_t numPositive = 0, numNegative = 0;
- Real maxPosHeight = -std::numeric_limits<Real>::max();
- Real maxNegHeight = std::numeric_limits<Real>::max();
- size_t maxPosIndex = std::numeric_limits<size_t>::max();
- size_t maxNegIndex = std::numeric_limits<size_t>::max();
- for (size_t i = 0; i < numVertices; ++i)
- {
- height[i] = Dot(hyperplane.normal, polygon[i]) - hyperplane.constant;
- if (height[i] > (Real)0)
- {
- ++numPositive;
- if (height[i] > maxPosHeight)
- {
- maxPosHeight = height[i];
- maxPosIndex = i;
- }
- }
- else if (height[i] < (Real)0)
- {
- ++numNegative;
- if (height[i] < maxNegHeight)
- {
- maxNegHeight = height[i];
- maxNegIndex = i;
- }
- }
- else
- {
- zeroHeightIndices.push_back(i);
- }
- }
- if (numPositive > 0)
- {
- if (numNegative > 0)
- {
- result.configuration = Configuration::SPLIT;
- bool doSwap = (maxPosHeight < -maxNegHeight);
- if (doSwap)
- {
- for (auto& h : height)
- {
- h = -h;
- }
- std::swap(maxPosIndex, maxNegIndex);
- }
- SplitPolygon(polygon, height, maxPosIndex, result);
- if (doSwap)
- {
- std::swap(result.positivePolygon, result.negativePolygon);
- }
- }
- else
- {
- size_t numZero = zeroHeightIndices.size();
- if (numZero == 0)
- {
- result.configuration = Configuration::POSITIVE_SIDE_STRICT;
- }
- else if (numZero == 1)
- {
- result.configuration = Configuration::POSITIVE_SIDE_VERTEX;
- result.intersection =
- {
- polygon[zeroHeightIndices[0]]
- };
- }
- else // numZero > 1
- {
- result.configuration = Configuration::POSITIVE_SIDE_EDGE;
- result.intersection =
- {
- polygon[zeroHeightIndices[0]],
- polygon[zeroHeightIndices[1]]
- };
- }
- result.positivePolygon = polygon;
- }
- }
- else if (numNegative > 0)
- {
- size_t numZero = zeroHeightIndices.size();
- if (numZero == 0)
- {
- result.configuration = Configuration::NEGATIVE_SIDE_STRICT;
- }
- else if (numZero == 1)
- {
- result.configuration = Configuration::NEGATIVE_SIDE_VERTEX;
- result.intersection =
- {
- polygon[zeroHeightIndices[0]]
- };
- }
- else // numZero > 1
- {
- result.configuration = Configuration::NEGATIVE_SIDE_EDGE;
- result.intersection =
- {
- polygon[zeroHeightIndices[0]],
- polygon[zeroHeightIndices[1]]
- };
- }
- result.negativePolygon = polygon;
- }
- else // numZero == numVertices
- {
- result.configuration = Configuration::CONTAINED;
- result.intersection = polygon;
- }
- return result;
- }
- protected:
- void SplitPolygon(std::vector<Vector<N, Real>> const& polygon,
- std::vector<Real> const& height, size_t maxPosIndex, Result& result)
- {
- // Find the largest contiguous subset of indices for which
- // height[i] >= 0.
- size_t const numVertices = polygon.size();
- std::list<Vector<N, Real>> positiveList;
- positiveList.push_back(polygon[maxPosIndex]);
- size_t end0 = maxPosIndex;
- size_t end0prev = std::numeric_limits<size_t>::max();
- for (size_t i = 0; i < numVertices; ++i)
- {
- end0prev = (end0 + numVertices - 1) % numVertices;
- if (height[end0prev] >= (Real)0)
- {
- positiveList.push_front(polygon[end0prev]);
- end0 = end0prev;
- }
- else
- {
- break;
- }
- }
- size_t end1 = maxPosIndex;
- size_t end1next = std::numeric_limits<size_t>::max();
- for (size_t i = 0; i < numVertices; ++i)
- {
- end1next = (end1 + 1) % numVertices;
- if (height[end1next] >= (Real)0)
- {
- positiveList.push_back(polygon[end1next]);
- end1 = end1next;
- }
- else
- {
- break;
- }
- }
- size_t index = end1next;
- std::list<Vector<N, Real>> negativeList;
- for (size_t i = 0; i < numVertices; ++i)
- {
- negativeList.push_back(polygon[index]);
- index = (index + 1) % numVertices;
- if (index == end0)
- {
- break;
- }
- }
- // Clip the polygon.
- if (height[end0] > (Real)0)
- {
- Real t = -height[end0prev] / (height[end0] - height[end0prev]);
- Real omt = (Real)1 - t;
- Vector<N, Real> V = omt * polygon[end0prev] + t * polygon[end0];
- positiveList.push_front(V);
- negativeList.push_back(V);
- result.intersection.push_back(V);
- }
- else
- {
- negativeList.push_back(polygon[end0]);
- result.intersection.push_back(polygon[end0]);
- }
- if (height[end1] > (Real)0)
- {
- Real t = -height[end1next] / (height[end1] - height[end1next]);
- Real omt = (Real)1 - t;
- Vector<N, Real> V = omt * polygon[end1next] + t * polygon[end1];
- positiveList.push_back(V);
- negativeList.push_front(V);
- result.intersection.push_back(V);
- }
- else
- {
- negativeList.push_front(polygon[end1]);
- result.intersection.push_back(polygon[end1]);
- }
- result.positivePolygon.reserve(positiveList.size());
- for (auto const& p : positiveList)
- {
- result.positivePolygon.push_back(p);
- }
- result.negativePolygon.reserve(negativeList.size());
- for (auto const& p : negativeList)
- {
- result.negativePolygon.push_back(p);
- }
- }
- };
- }
|