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.

152 lines
5.4 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/IntrPlane3Plane3.h>
#include <Mathematics/Circle3.h>
namespace gte
{
template <typename Real>
class TIQuery<Real, Plane3<Real>, Circle3<Real>>
{
public:
struct Result
{
bool intersect;
};
Result operator()(Plane3<Real> const& plane, Circle3<Real> const& circle)
{
Result result;
// Construct the plane of the circle.
Plane3<Real> cPlane(circle.normal, circle.center);
// Compute the intersection of this plane with the input plane.
FIQuery<Real, Plane3<Real>, Plane3<Real>> ppQuery;
auto ppResult = ppQuery(plane, cPlane);
if (!ppResult.intersect)
{
// Planes are parallel and nonintersecting.
result.intersect = false;
return result;
}
if (!ppResult.isLine)
{
// Planes are the same, the circle is the common intersection
// set.
result.intersect = true;
return result;
}
// The planes intersect in a line. Locate one or two points that
// are on the circle and line. If the line is t*D+P, the circle
// center is C, and the circle radius is r, then
// r^2 = |t*D+P-C|^2 = |D|^2*t^2 + 2*Dot(D,P-C)*t + |P-C|^2
// This is a quadratic equation of the form
// a2*t^2 + 2*a1*t + a0 = 0.
Vector3<Real> diff = ppResult.line.origin - circle.center;
Real a2 = Dot(ppResult.line.direction, ppResult.line.direction);
Real a1 = Dot(diff, ppResult.line.direction);
Real a0 = Dot(diff, diff) - circle.radius * circle.radius;
// Real-valued roots imply an intersection.
Real discr = a1 * a1 - a0 * a2;
result.intersect = (discr >= (Real)0);
return result;
}
};
template <typename Real>
class FIQuery<Real, Plane3<Real>, Circle3<Real>>
{
public:
struct Result
{
bool intersect;
// If 'intersect' is true, the intersection is either 1 or 2 points
// or the entire circle. When points, 'numIntersections' and
// 'point' are valid. When a circle, 'circle' is set to the incoming
// circle.
bool isPoints;
int numIntersections;
Vector3<Real> point[2];
Circle3<Real> circle;
};
Result operator()(Plane3<Real> const& plane, Circle3<Real> const& circle)
{
Result result;
// Construct the plane of the circle.
Plane3<Real> cPlane(circle.normal, circle.center);
// Compute the intersection of this plane with the input plane.
FIQuery<Real, Plane3<Real>, Plane3<Real>> ppQuery;
auto ppResult = ppQuery(plane, cPlane);
if (!ppResult.intersect)
{
// Planes are parallel and nonintersecting.
result.intersect = false;
return result;
}
if (!ppResult.isLine)
{
// Planes are the same, the circle is the common intersection
// set.
result.intersect = true;
result.isPoints = false;
result.circle = circle;
return result;
}
// The planes intersect in a line. Locate one or two points that
// are on the circle and line. If the line is t*D+P, the circle
// center is C, and the circle radius is r, then
// r^2 = |t*D+P-C|^2 = |D|^2*t^2 + 2*Dot(D,P-C)*t + |P-C|^2
// This is a quadratic equation of the form
// a2*t^2 + 2*a1*t + a0 = 0.
Vector3<Real> diff = ppResult.line.origin - circle.center;
Real a2 = Dot(ppResult.line.direction, ppResult.line.direction);
Real a1 = Dot(diff, ppResult.line.direction);
Real a0 = Dot(diff, diff) - circle.radius * circle.radius;
Real discr = a1 * a1 - a0 * a2;
if (discr < (Real)0)
{
// No real roots, the circle does not intersect the plane.
result.intersect = false;
return result;
}
result.isPoints = true;
Real inv = ((Real)1) / a2;
if (discr == (Real)0)
{
// One repeated root, the circle just touches the plane.
result.numIntersections = 1;
result.point[0] = ppResult.line.origin - (a1 * inv) * ppResult.line.direction;
return result;
}
// Two distinct, real-valued roots, the circle intersects the
// plane in two points.
Real root = std::sqrt(discr);
result.numIntersections = 2;
result.point[0] = ppResult.line.origin - ((a1 + root) * inv) * ppResult.line.direction;
result.point[1] = ppResult.line.origin - ((a1 - root) * inv) * ppResult.line.direction;
return result;
}
};
}