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.
141 lines
5.1 KiB
141 lines
5.1 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/FIQuery.h>
|
|
#include <Mathematics/TIQuery.h>
|
|
#include <Mathematics/Hyperplane.h>
|
|
#include <Mathematics/Line.h>
|
|
#include <Mathematics/Vector3.h>
|
|
|
|
namespace gte
|
|
{
|
|
template <typename Real>
|
|
class TIQuery<Real, Plane3<Real>, Plane3<Real>>
|
|
{
|
|
public:
|
|
struct Result
|
|
{
|
|
bool intersect;
|
|
};
|
|
|
|
Result operator()(Plane3<Real> const& plane0, Plane3<Real> const& plane1)
|
|
{
|
|
// If Cross(N0,N1) is zero, then either planes are parallel and
|
|
// separated or the same plane. In both cases, 'false' is
|
|
// returned. Otherwise, the planes intersect. To avoid subtle
|
|
// differences in reporting between Test() and Find(), the same
|
|
// parallel test is used. Mathematically,
|
|
// |Cross(N0,N1)|^2 = Dot(N0,N0)*Dot(N1,N1)-Dot(N0,N1)^2
|
|
// = 1 - Dot(N0,N1)^2
|
|
// The last equality is true since planes are required to have
|
|
// unit-length normal vectors. The test |Cross(N0,N1)| = 0 is the
|
|
// same as |Dot(N0,N1)| = 1.
|
|
|
|
Result result;
|
|
Real dot = Dot(plane0.normal, plane1.normal);
|
|
if (std::fabs(dot) < (Real)1)
|
|
{
|
|
result.intersect = true;
|
|
return result;
|
|
}
|
|
|
|
// The planes are parallel. Check whether they are coplanar.
|
|
Real cDiff;
|
|
if (dot >= (Real)0)
|
|
{
|
|
// Normals are in same direction, need to look at c0-c1.
|
|
cDiff = plane0.constant - plane1.constant;
|
|
}
|
|
else
|
|
{
|
|
// Normals are in opposite directions, need to look at c0+c1.
|
|
cDiff = plane0.constant + plane1.constant;
|
|
}
|
|
|
|
result.intersect = (std::fabs(cDiff) == (Real)0);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <typename Real>
|
|
class FIQuery<Real, Plane3<Real>, Plane3<Real>>
|
|
{
|
|
public:
|
|
struct Result
|
|
{
|
|
bool intersect;
|
|
|
|
// If 'intersect' is true, the intersection is either a line or
|
|
// the planes are the same. When a line, 'line' is valid. When
|
|
// the same plane, 'plane' is set to one of the planes.
|
|
bool isLine;
|
|
Line3<Real> line;
|
|
Plane3<Real> plane;
|
|
};
|
|
|
|
Result operator()(Plane3<Real> const& plane0, Plane3<Real> const& plane1)
|
|
{
|
|
// If N0 and N1 are parallel, either the planes are parallel and
|
|
// separated or the same plane. In both cases, 'false' is
|
|
// returned. Otherwise, the intersection line is
|
|
// L(t) = t*Cross(N0,N1)/|Cross(N0,N1)| + c0*N0 + c1*N1
|
|
// for some coefficients c0 and c1 and for t any real number (the
|
|
// line parameter). Taking dot products with the normals,
|
|
// d0 = Dot(N0,L) = c0*Dot(N0,N0) + c1*Dot(N0,N1) = c0 + c1*d
|
|
// d1 = Dot(N1,L) = c0*Dot(N0,N1) + c1*Dot(N1,N1) = c0*d + c1
|
|
// where d = Dot(N0,N1). These are two equations in two unknowns.
|
|
// The solution is
|
|
// c0 = (d0 - d*d1)/det
|
|
// c1 = (d1 - d*d0)/det
|
|
// where det = 1 - d^2.
|
|
|
|
Result result;
|
|
|
|
Real dot = Dot(plane0.normal, plane1.normal);
|
|
if (std::fabs(dot) >= (Real)1)
|
|
{
|
|
// The planes are parallel. Check if they are coplanar.
|
|
Real cDiff;
|
|
if (dot >= (Real)0)
|
|
{
|
|
// Normals are in same direction, need to look at c0-c1.
|
|
cDiff = plane0.constant - plane1.constant;
|
|
}
|
|
else
|
|
{
|
|
// Normals are in opposite directions, need to look at
|
|
// c0+c1.
|
|
cDiff = plane0.constant + plane1.constant;
|
|
}
|
|
|
|
if (std::fabs(cDiff) == (Real)0)
|
|
{
|
|
// The planes are coplanar.
|
|
result.intersect = true;
|
|
result.isLine = false;
|
|
result.plane = plane0;
|
|
return result;
|
|
}
|
|
|
|
// The planes are parallel but distinct.
|
|
result.intersect = false;
|
|
return result;
|
|
}
|
|
|
|
Real invDet = (Real)1 / ((Real)1 - dot * dot);
|
|
Real c0 = (plane0.constant - dot * plane1.constant) * invDet;
|
|
Real c1 = (plane1.constant - dot * plane0.constant) * invDet;
|
|
result.intersect = true;
|
|
result.isLine = true;
|
|
result.line.origin = c0 * plane0.normal + c1 * plane1.normal;
|
|
result.line.direction = UnitCross(plane0.normal, plane1.normal);
|
|
return result;
|
|
}
|
|
};
|
|
}
|
|
|