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.

222 lines
8.6 KiB

3 months ago
// 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/IntrLine2Line2.h>
#include <Mathematics/Ray.h>
namespace gte
{
template <typename Real>
class TIQuery<Real, Ray2<Real>, Ray2<Real>>
{
public:
struct Result
{
bool intersect;
// The number is 0 (no intersection), 1 (rays intersect in a
// single point), 2 (rays are collinear and intersect in a
// segment; ray directions are opposite of each other), or
// std::numeric_limits<int>::max() (intersection is a ray; ray
// directions are the same).
int numIntersections;
};
Result operator()(Ray2<Real> const& ray0, Ray2<Real> const& ray1)
{
Result result;
FIQuery<Real, Line2<Real>, Line2<Real>> llQuery;
Line2<Real> line0(ray0.origin, ray0.direction);
Line2<Real> line1(ray1.origin, ray1.direction);
auto llResult = llQuery(line0, line1);
if (llResult.numIntersections == 1)
{
// Test whether the line-line intersection is on the rays.
if (llResult.line0Parameter[0] >= (Real)0
&& llResult.line1Parameter[0] >= (Real)0)
{
result.intersect = true;
result.numIntersections = 1;
}
else
{
result.intersect = false;
result.numIntersections = 0;
}
}
else if (llResult.numIntersections == std::numeric_limits<int>::max())
{
if (Dot(ray0.direction, ray1.direction) > (Real)0)
{
// The rays are collinear and in the same direction, so
// they must overlap.
result.intersect = true;
result.numIntersections = std::numeric_limits<int>::max();
}
else
{
// The rays are collinear but in opposite directions.
// Test whether they overlap. Ray0 has interval
// [0,+infinity) and ray1 has interval (-infinity,t]
// relative to ray0.direction.
Vector2<Real> diff = ray1.origin - ray0.origin;
Real t = Dot(ray0.direction, diff);
if (t > (Real)0)
{
result.intersect = true;
result.numIntersections = 2;
}
else if (t < (Real)0)
{
result.intersect = false;
result.numIntersections = 0;
}
else // t == 0
{
result.intersect = true;
result.numIntersections = 1;
}
}
}
else
{
result.intersect = false;
result.numIntersections = 0;
}
return result;
}
};
template <typename Real>
class FIQuery<Real, Ray2<Real>, Ray2<Real>>
{
public:
struct Result
{
bool intersect;
// The number is 0 (no intersection), 1 (rays intersect in a
// single point), 2 (rays are collinear and intersect in a
// segment; ray directions are opposite of each other), or
// std::numeric_limits<int>::max() (intersection is a ray; ray
// directions are the same).
int numIntersections;
// If numIntersections is 1, the intersection is
// point[0] = ray0.origin + ray0Parameter[0] * ray0.direction
// = ray1.origin + ray1Parameter[0] * ray1.direction
// If numIntersections is 2, the segment of intersection is formed
// by the ray origins,
// ray0Parameter[0] = ray1Parameter[0] = 0
// point[0] = ray0.origin
// = ray1.origin + ray1Parameter[1] * ray1.direction
// point[1] = ray1.origin
// = ray0.origin + ray0Parameter[1] * ray0.direction
// where ray0Parameter[1] >= 0 and ray1Parameter[1] >= 0.
// If numIntersections is maxInt, let
// ray1.origin = ray0.origin + t * ray0.direction
// then
// ray0Parameter[] = { max(t,0), +maxReal }
// ray1Parameter[] = { -min(t,0), +maxReal }
// point[0] = ray0.origin + ray0Parameter[0] * ray0.direction
Real ray0Parameter[2], ray1Parameter[2];
Vector2<Real> point[2];
};
Result operator()(Ray2<Real> const& ray0, Ray2<Real> const& ray1)
{
Result result;
FIQuery<Real, Line2<Real>, Line2<Real>> llQuery;
Line2<Real> line0(ray0.origin, ray0.direction);
Line2<Real> line1(ray1.origin, ray1.direction);
auto llResult = llQuery(line0, line1);
if (llResult.numIntersections == 1)
{
// Test whether the line-line intersection is on the rays.
if (llResult.line0Parameter[0] >= (Real)0
&& llResult.line1Parameter[0] >= (Real)0)
{
result.intersect = true;
result.numIntersections = 1;
result.ray0Parameter[0] = llResult.line0Parameter[0];
result.ray1Parameter[0] = llResult.line1Parameter[0];
result.point[0] = llResult.point;
}
else
{
result.intersect = false;
result.numIntersections = 0;
}
}
else if (llResult.numIntersections == std::numeric_limits<int>::max())
{
// Compute t for which ray1.origin =
// ray0.origin + t*ray0.direction.
Real maxReal = std::numeric_limits<Real>::max();
Vector2<Real> diff = ray1.origin - ray0.origin;
Real t = Dot(ray0.direction, diff);
if (Dot(ray0.direction, ray1.direction) > (Real)0)
{
// The rays are collinear and in the same direction, so
// they must overlap.
result.intersect = true;
result.numIntersections = std::numeric_limits<int>::max();
if (t >= (Real)0)
{
result.ray0Parameter[0] = t;
result.ray0Parameter[1] = maxReal;
result.ray1Parameter[0] = (Real)0;
result.ray1Parameter[1] = maxReal;
result.point[0] = ray1.origin;
}
else
{
result.ray0Parameter[0] = (Real)0;
result.ray0Parameter[1] = maxReal;
result.ray1Parameter[0] = -t;
result.ray1Parameter[1] = maxReal;
result.point[0] = ray0.origin;
}
}
else
{
// The rays are collinear but in opposite directions.
// Test whether they overlap. Ray0 has interval
// [0,+infinity) and ray1 has interval (-infinity,t1]
// relative to ray0.direction.
if (t >= (Real)0)
{
result.intersect = true;
result.numIntersections = 2;
result.ray0Parameter[0] = (Real)0;
result.ray0Parameter[1] = t;
result.ray1Parameter[0] = (Real)0;
result.ray1Parameter[1] = t;
result.point[0] = ray0.origin;
result.point[1] = ray1.origin;
}
else
{
result.intersect = false;
result.numIntersections = 0;
}
}
}
else
{
result.intersect = false;
result.numIntersections = 0;
}
return result;
}
};
}