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.
130 lines
4.9 KiB
130 lines
4.9 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/TIQuery.h>
|
|
#include <Mathematics/OrientedBox.h>
|
|
#include <Mathematics/DistPointSegment.h>
|
|
#include <Mathematics/IntrHalfspace2Polygon2.h>
|
|
#include <Mathematics/Sector2.h>
|
|
|
|
// The OrientedBox2 object is considered to be a solid.
|
|
|
|
namespace gte
|
|
{
|
|
template <typename Real>
|
|
class TIQuery<Real, OrientedBox2<Real>, Sector2<Real>>
|
|
{
|
|
public:
|
|
struct Result
|
|
{
|
|
bool intersect;
|
|
};
|
|
|
|
Result operator()(OrientedBox2<Real> const& box, Sector2<Real> const& sector)
|
|
{
|
|
Result result;
|
|
|
|
// Determine whether the vertex is inside the box.
|
|
Vector2<Real> CmV = box.center - sector.vertex;
|
|
Vector2<Real> P{ Dot(box.axis[0], CmV), Dot(box.axis[1], CmV) };
|
|
if (std::fabs(P[0]) <= box.extent[0] && std::fabs(P[1]) <= box.extent[1])
|
|
{
|
|
// The vertex is inside the box.
|
|
result.intersect = true;
|
|
return result;
|
|
}
|
|
|
|
// Test whether the box is outside the right ray boundary of the
|
|
// sector.
|
|
Vector2<Real> U0
|
|
{
|
|
+sector.cosAngle * sector.direction[0] + sector.sinAngle * sector.direction[1],
|
|
-sector.sinAngle * sector.direction[0] + sector.cosAngle * sector.direction[1]
|
|
};
|
|
Vector2<Real> N0 = Perp(U0);
|
|
Real prjcen0 = Dot(N0, CmV);
|
|
Real radius0 = box.extent[0] * std::fabs(Dot(N0, box.axis[0]))
|
|
+ box.extent[1] * std::fabs(Dot(N0, box.axis[1]));
|
|
if (prjcen0 > radius0)
|
|
{
|
|
result.intersect = false;
|
|
return result;
|
|
}
|
|
|
|
// Test whether the box is outside the ray of the left boundary
|
|
// of the sector.
|
|
Vector2<Real> U1
|
|
{
|
|
+sector.cosAngle * sector.direction[0] - sector.sinAngle * sector.direction[1],
|
|
+sector.sinAngle * sector.direction[0] + sector.cosAngle * sector.direction[1]
|
|
};
|
|
Vector2<Real> N1 = -Perp(U1);
|
|
Real prjcen1 = Dot(N1, CmV);
|
|
Real radius1 = box.extent[0] * std::fabs(Dot(N1, box.axis[0]))
|
|
+ box.extent[1] * std::fabs(Dot(N1, box.axis[1]));
|
|
if (prjcen1 > radius1)
|
|
{
|
|
result.intersect = false;
|
|
return result;
|
|
}
|
|
|
|
// Initialize the polygon of intersection to be the box.
|
|
Vector2<Real> e0U0 = box.extent[0] * box.axis[0];
|
|
Vector2<Real> e1U1 = box.extent[1] * box.axis[1];
|
|
std::vector<Vector2<Real>> polygon;
|
|
polygon.reserve(8);
|
|
polygon.push_back(box.center - e0U0 - e1U1);
|
|
polygon.push_back(box.center + e0U0 - e1U1);
|
|
polygon.push_back(box.center + e0U0 + e1U1);
|
|
polygon.push_back(box.center - e0U0 + e1U1);
|
|
|
|
FIQuery<Real, Halfspace<2, Real>, std::vector<Vector2<Real>>> hpQuery;
|
|
typename FIQuery<Real, Halfspace<2, Real>, std::vector<Vector2<Real>>>::Result hpResult;
|
|
Halfspace<2, Real> halfspace;
|
|
|
|
// Clip the box against the right-ray sector boundary.
|
|
if (prjcen0 >= -radius0)
|
|
{
|
|
halfspace.normal = -N0;
|
|
halfspace.constant = Dot(halfspace.normal, sector.vertex);
|
|
hpResult = hpQuery(halfspace, polygon);
|
|
polygon = std::move(hpResult.polygon);
|
|
}
|
|
|
|
// Clip the box against the left-ray sector boundary.
|
|
if (prjcen1 >= -radius1)
|
|
{
|
|
halfspace.normal = -N1;
|
|
halfspace.constant = Dot(halfspace.normal, sector.vertex);
|
|
hpResult = hpQuery(halfspace, polygon);
|
|
polygon = std::move(hpResult.polygon);
|
|
}
|
|
|
|
DCPQuery<Real, Vector2<Real>, Segment2<Real>> psQuery;
|
|
typename DCPQuery<Real, Vector2<Real>, Segment2<Real>>::Result psResult;
|
|
int const numVertices = static_cast<int>(polygon.size());
|
|
if (numVertices >= 2)
|
|
{
|
|
for (int i0 = numVertices - 1, i1 = 0; i1 < numVertices; i0 = i1++)
|
|
{
|
|
Segment2<Real> segment(polygon[i0], polygon[i1]);
|
|
psResult = psQuery(sector.vertex, segment);
|
|
if (psResult.distance <= sector.radius)
|
|
{
|
|
result.intersect = true;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
result.intersect = false;
|
|
return result;
|
|
}
|
|
};
|
|
}
|
|
|