You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

202 lines
6.6 KiB

// David Eberly, Geometric Tools, Redmond WA 98052
// Copyright (c) 1998-2021
// 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/Vector2.h>
// Given a polygon as an order list of vertices (x[i],y[i]) for 0 <= i < N
// and a test point (xt,yt), return 'true' if (xt,yt) is in the polygon and
// 'false' if it is not. All queries require that the number of vertices
// satisfies N >= 3.
namespace gte
{
template <typename Real>
class PointInPolygon2
{
public:
// The class object stores a copy of 'points', so be careful about
// the persistence of 'points' when you have created a
// PointInPolygon2 object.
PointInPolygon2(int numPoints, Vector2<Real> const* points)
:
mNumPoints(numPoints),
mPoints(points)
{
}
// Simple polygons (ray-intersection counting).
bool Contains(Vector2<Real> const& p) const
{
bool inside = false;
for (int i = 0, j = mNumPoints - 1; i < mNumPoints; j = i++)
{
Vector2<Real> const& U0 = mPoints[i];
Vector2<Real> const& U1 = mPoints[j];
Real rhs, lhs;
if (p[1] < U1[1]) // U1 above ray
{
if (U0[1] <= p[1]) // U0 on or below ray
{
lhs = (p[1] - U0[1]) * (U1[0] - U0[0]);
rhs = (p[0] - U0[0]) * (U1[1] - U0[1]);
if (lhs > rhs)
{
inside = !inside;
}
}
}
else if (p[1] < U0[1]) // U1 on or below ray, U0 above ray
{
lhs = (p[1] - U0[1]) * (U1[0] - U0[0]);
rhs = (p[0] - U0[0]) * (U1[1] - U0[1]);
if (lhs < rhs)
{
inside = !inside;
}
}
}
return inside;
}
// Algorithms for convex polygons. The input polygons must have
// vertices in counterclockwise order.
// O(N) algorithm (which-side-of-edge tests)
bool ContainsConvexOrderN(Vector2<Real> const& p) const
{
for (int i1 = 0, i0 = mNumPoints - 1; i1 < mNumPoints; i0 = i1++)
{
Real nx = mPoints[i1][1] - mPoints[i0][1];
Real ny = mPoints[i0][0] - mPoints[i1][0];
Real dx = p[0] - mPoints[i0][0];
Real dy = p[1] - mPoints[i0][1];
if (nx * dx + ny * dy > (Real)0)
{
return false;
}
}
return true;
}
// O(log N) algorithm (bisection and recursion, like BSP tree)
bool ContainsConvexOrderLogN(Vector2<Real> const& p) const
{
return SubContainsPoint(p, 0, 0);
}
// The polygon must have exactly four vertices. This method is like
// the O(log N) and uses three which-side-of-segment test instead of
// four which-side-of-edge tests. If the polygon does not have four
// vertices, the function returns false.
bool ContainsQuadrilateral(Vector2<Real> const& p) const
{
if (mNumPoints != 4)
{
return false;
}
Real nx = mPoints[2][1] - mPoints[0][1];
Real ny = mPoints[0][0] - mPoints[2][0];
Real dx = p[0] - mPoints[0][0];
Real dy = p[1] - mPoints[0][1];
if (nx * dx + ny * dy > (Real)0)
{
// P potentially in <V0,V1,V2>
nx = mPoints[1][1] - mPoints[0][1];
ny = mPoints[0][0] - mPoints[1][0];
if (nx * dx + ny * dy > (Real)0.0)
{
return false;
}
nx = mPoints[2][1] - mPoints[1][1];
ny = mPoints[1][0] - mPoints[2][0];
dx = p[0] - mPoints[1][0];
dy = p[1] - mPoints[1][1];
if (nx * dx + ny * dy > (Real)0)
{
return false;
}
}
else
{
// P potentially in <V0,V2,V3>
nx = mPoints[0][1] - mPoints[3][1];
ny = mPoints[3][0] - mPoints[0][0];
if (nx * dx + ny * dy > (Real)0)
{
return false;
}
nx = mPoints[3][1] - mPoints[2][1];
ny = mPoints[2][0] - mPoints[3][0];
dx = p[0] - mPoints[3][0];
dy = p[1] - mPoints[3][1];
if (nx * dx + ny * dy > (Real)0)
{
return false;
}
}
return true;
}
private:
// For recursion in ContainsConvexOrderLogN.
bool SubContainsPoint(Vector2<Real> const& p, int i0, int i1) const
{
Real nx, ny, dx, dy;
int diff = i1 - i0;
if (diff == 1 || (diff < 0 && diff + mNumPoints == 1))
{
nx = mPoints[i1][1] - mPoints[i0][1];
ny = mPoints[i0][0] - mPoints[i1][0];
dx = p[0] - mPoints[i0][0];
dy = p[1] - mPoints[i0][1];
return nx * dx + ny * dy <= (Real)0;
}
// Bisect the index range.
int mid;
if (i0 < i1)
{
mid = (i0 + i1) >> 1;
}
else
{
mid = (i0 + i1 + mNumPoints) >> 1;
if (mid >= mNumPoints)
{
mid -= mNumPoints;
}
}
// Determine which side of the splitting line contains the point.
nx = mPoints[mid][1] - mPoints[i0][1];
ny = mPoints[i0][0] - mPoints[mid][0];
dx = p[0] - mPoints[i0][0];
dy = p[1] - mPoints[i0][1];
if (nx * dx + ny * dy > (Real)0)
{
// P potentially in <V(i0),V(i0+1),...,V(mid-1),V(mid)>
return SubContainsPoint(p, i0, mid);
}
else
{
// P potentially in <V(mid),V(mid+1),...,V(i1-1),V(i1)>
return SubContainsPoint(p, mid, i1);
}
}
int mNumPoints;
Vector2<Real> const* mPoints;
};
}