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.
 
 

273 lines
8.8 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/Triangle.h>
#include <Mathematics/Vector3.h>
namespace gte
{
template <typename Real>
class TIQuery<Real, Plane3<Real>, Triangle3<Real>>
{
public:
struct Result
{
bool intersect;
// The number is 0 (no intersection), 1 (plane and triangle
// intersect at a single point [vertex]), 2 (plane and triangle
// intersect in a segment), or 3 (triangle is in the plane).
// When the number is 2, the segment is either interior to the
// triangle or is an edge of the triangle, the distinction stored
// in 'isInterior'.
int numIntersections;
bool isInterior;
};
Result operator()(Plane3<Real> const& plane, Triangle3<Real> const& triangle)
{
Result result;
// Determine on which side of the plane the vertices lie. The
// table of possibilities is listed next with n = numNegative,
// p = numPositive, and z = numZero.
//
// n p z intersection
// ------------------------------------
// 0 3 0 none
// 0 2 1 vertex
// 0 1 2 edge
// 0 0 3 triangle in the plane
// 1 2 0 segment (2 edges clipped)
// 1 1 1 segment (1 edge clipped)
// 1 0 2 edge
// 2 1 0 segment (2 edges clipped)
// 2 0 1 vertex
// 3 0 0 none
Real s[3];
int numPositive = 0, numNegative = 0, numZero = 0;
for (int i = 0; i < 3; ++i)
{
s[i] = Dot(plane.normal, triangle.v[i]) - plane.constant;
if (s[i] > (Real)0)
{
++numPositive;
}
else if (s[i] < (Real)0)
{
++numNegative;
}
else
{
++numZero;
}
}
if (numZero == 0 && numPositive > 0 && numNegative > 0)
{
result.intersect = true;
result.numIntersections = 2;
result.isInterior = true;
return result;
}
if (numZero == 1)
{
result.intersect = true;
for (int i = 0; i < 3; ++i)
{
if (s[i] == (Real)0)
{
if (numPositive == 2 || numNegative == 2)
{
result.numIntersections = 1;
}
else
{
result.numIntersections = 2;
result.isInterior = true;
}
break;
}
}
return result;
}
if (numZero == 2)
{
result.intersect = true;
result.numIntersections = 2;
result.isInterior = false;
return result;
}
if (numZero == 3)
{
result.intersect = true;
result.numIntersections = 3;
}
else
{
result.intersect = false;
result.numIntersections = 0;
}
return result;
}
};
template <typename Real>
class FIQuery<Real, Plane3<Real>, Triangle3<Real>>
{
public:
struct Result
{
bool intersect;
// The number is 0 (no intersection), 1 (plane and triangle
// intersect at a single point [vertex]), 2 (plane and triangle
// intersect in a segment), or 3 (triangle is in the plane).
// When the number is 2, the segment is either interior to the
// triangle or is an edge of the triangle, the distinction stored
// in 'isInterior'.
int numIntersections;
bool isInterior;
Vector3<Real> point[3];
};
Result operator()(Plane3<Real> const& plane, Triangle3<Real> const& triangle)
{
Result result;
// Determine on which side of the plane the vertices lie. The
// table of possibilities is listed next with n = numNegative,
// p = numPositive, and z = numZero.
//
// n p z intersection
// ------------------------------------
// 0 3 0 none
// 0 2 1 vertex
// 0 1 2 edge
// 0 0 3 triangle in the plane
// 1 2 0 segment (2 edges clipped)
// 1 1 1 segment (1 edge clipped)
// 1 0 2 edge
// 2 1 0 segment (2 edges clipped)
// 2 0 1 vertex
// 3 0 0 none
Real s[3];
int numPositive = 0, numNegative = 0, numZero = 0;
for (int i = 0; i < 3; ++i)
{
s[i] = Dot(plane.normal, triangle.v[i]) - plane.constant;
if (s[i] > (Real)0)
{
++numPositive;
}
else if (s[i] < (Real)0)
{
++numNegative;
}
else
{
++numZero;
}
}
if (numZero == 0 && numPositive > 0 && numNegative > 0)
{
result.intersect = true;
result.numIntersections = 2;
result.isInterior = true;
Real sign = (Real)3 - numPositive * (Real)2;
for (int i0 = 0; i0 < 3; ++i0)
{
if (sign * s[i0] > (Real)0)
{
int i1 = (i0 + 1) % 3, i2 = (i0 + 2) % 3;
Real t1 = s[i1] / (s[i1] - s[i0]);
Real t2 = s[i2] / (s[i2] - s[i0]);
result.point[0] = triangle.v[i1] + t1 *
(triangle.v[i0] - triangle.v[i1]);
result.point[1] = triangle.v[i2] + t2 *
(triangle.v[i0] - triangle.v[i2]);
break;
}
}
return result;
}
if (numZero == 1)
{
result.intersect = true;
for (int i0 = 0; i0 < 3; ++i0)
{
if (s[i0] == (Real)0)
{
int i1 = (i0 + 1) % 3, i2 = (i0 + 2) % 3;
result.point[0] = triangle.v[i0];
if (numPositive == 2 || numNegative == 2)
{
result.numIntersections = 1;
}
else
{
result.numIntersections = 2;
result.isInterior = true;
Real t = s[i1] / (s[i1] - s[i2]);
result.point[1] = triangle.v[i1] + t *
(triangle.v[i2] - triangle.v[i1]);
}
break;
}
}
return result;
}
if (numZero == 2)
{
result.intersect = true;
result.numIntersections = 2;
result.isInterior = false;
for (int i0 = 0; i0 < 3; ++i0)
{
if (s[i0] != (Real)0)
{
int i1 = (i0 + 1) % 3, i2 = (i0 + 2) % 3;
result.point[0] = triangle.v[i1];
result.point[1] = triangle.v[i2];
break;
}
}
return result;
}
if (numZero == 3)
{
result.intersect = true;
result.numIntersections = 3;
result.point[0] = triangle.v[0];
result.point[1] = triangle.v[1];
result.point[2] = triangle.v[2];
}
else
{
result.intersect = false;
result.numIntersections = 0;
}
return result;
}
};
}