123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // 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/Logger.h>
- #include <Mathematics/FIQuery.h>
- #include <Mathematics/TIQuery.h>
- #include <Mathematics/DistPoint3Plane3.h>
- #include <Mathematics/Circle3.h>
- #include <Mathematics/Cylinder3.h>
- #include <Mathematics/Ellipse3.h>
- #include <Mathematics/Line.h>
- namespace WwiseGTE
- {
- template <typename Real>
- class TIQuery<Real, Plane3<Real>, Cylinder3<Real>>
- {
- public:
- struct Result
- {
- bool intersect;
- };
- // The cylinder must have finite height.
- Result operator()(Plane3<Real> const& plane, Cylinder3<Real> const& cylinder)
- {
- LogAssert(cylinder.height != std::numeric_limits<Real>::max(),
- "Cylinder height must be finite.");
- Result result;
- // Compute extremes of signed distance Dot(N,X)-d for points on
- // the cylinder. These are
- // min = (Dot(N,C)-d) - r*sqrt(1-Dot(N,W)^2) - (h/2)*|Dot(N,W)|
- // max = (Dot(N,C)-d) + r*sqrt(1-Dot(N,W)^2) + (h/2)*|Dot(N,W)|
- DCPQuery<Real, Vector3<Real>, Plane3<Real>> vpQuery;
- Real distance = vpQuery(cylinder.axis.origin, plane).distance;
- Real absNdW = std::fabs(Dot(plane.normal, cylinder.axis.direction));
- Real root = std::sqrt(std::max((Real)1 - absNdW * absNdW, (Real)0));
- Real term = cylinder.radius * root + (Real)0.5 * cylinder.height * absNdW;
- // Intersection occurs if and only if 0 is in the interval
- // [min,max].
- result.intersect = (distance <= term);
- return result;
- }
- };
- template <typename Real>
- class FIQuery<Real, Plane3<Real>, Cylinder3<Real>>
- {
- public:
- struct Result
- {
- bool intersect;
- // The type of intersection.
- // 0: none
- // 1: single line (cylinder is tangent to plane), line[0] valid
- // 2: two parallel lines (plane cuts cylinder in two lines)
- // 3: circle (cylinder axis perpendicular to plane)
- // 4: ellipse (cylinder axis neither parallel nor perpendicular)
- int type;
- Line3<Real> line[2];
- Circle3<Real> circle;
- Ellipse3<Real> ellipse;
- };
- // The cylinder must have infinite height.
- Result operator()(Plane3<Real> const& plane, Cylinder3<Real> const& cylinder)
- {
- LogAssert(cylinder.height != std::numeric_limits<Real>::max(),
- "Cylinder height must be finite.");
- Result result;
- DCPQuery<Real, Vector3<Real>, Plane3<Real>> vpQuery;
- Real sdistance = vpQuery(cylinder.axis.origin, plane).signedDistance;
- Vector3<Real> center = cylinder.axis.origin - sdistance * plane.normal;
- Real cosTheta = Dot(cylinder.axis.direction, plane.normal);
- Real absCosTheta = std::fabs(cosTheta);
- if (absCosTheta > (Real)0)
- {
- // The cylinder axis intersects the plane in a unique point.
- result.intersect = true;
- if (absCosTheta < (Real)1)
- {
- result.type = 4;
- result.ellipse.normal = plane.normal;
- result.ellipse.center = cylinder.axis.origin -
- (sdistance / cosTheta) * cylinder.axis.direction;
- result.ellipse.axis[0] = cylinder.axis.direction -
- cosTheta * plane.normal;
- Normalize(result.ellipse.axis[0]);
- result.ellipse.axis[1] = UnitCross(plane.normal,
- result.ellipse.axis[0]);
- result.ellipse.extent[0] = cylinder.radius / absCosTheta;
- result.ellipse.extent[1] = cylinder.radius;
- }
- else
- {
- result.type = 3;
- result.circle.normal = plane.normal;
- result.circle.center = center;
- result.circle.radius = cylinder.radius;
- }
- }
- else
- {
- // The cylinder is parallel to the plane.
- Real distance = std::fabs(sdistance);
- if (distance < cylinder.radius)
- {
- result.intersect = true;
- result.type = 2;
- Vector3<Real> offset = Cross(cylinder.axis.direction, plane.normal);
- Real extent = std::sqrt(cylinder.radius * cylinder.radius - sdistance * sdistance);
- result.line[0].origin = center - extent * offset;
- result.line[0].direction = cylinder.axis.direction;
- result.line[1].origin = center + extent * offset;
- result.line[1].direction = cylinder.axis.direction;
- }
- else if (distance == cylinder.radius)
- {
- result.intersect = true;
- result.type = 1;
- result.line[0].origin = center;
- result.line[0].direction = cylinder.axis.direction;
- }
- else
- {
- result.intersect = false;
- result.type = 0;
- }
- }
- return result;
- }
- };
- }
|