/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see .
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP
#include "geom/primitive/hyperplane.hpp"
#include "geom/primitive/hyperrectangle.hpp"
#include "geom/primitive/hypersphere.hpp"
#include "geom/primitive/ray.hpp"
#include
#include
namespace geom {
namespace primitive {
/**
* Ray-hyperplane intersection test.
*
* @param ray Ray.
* @param hyperplane Hyperplane.
*
* @return Distance along the ray to the point of intersection, or `std::nullopt` if no intersection occurred.
*/
/// @{
template
constexpr std::optional intersection(const ray& ray, const hyperplane& hyperplane) noexcept
{
const T cos_theta = math::dot(ray.direction, hyperplane.normal);
if (cos_theta != T{0})
{
const T t = -hyperplane.distance(ray.origin) / cos_theta;
if (t >= T{0})
return t;
}
return std::nullopt;
}
template
constexpr inline std::optional intersection(const hyperplane& hyperplane, const ray& ray) noexcept
{
return intersection(ray, hyperplane);
}
/// @}
/**
* Ray-hyperrectangle intersection test.
*
* @param ray Ray.
* @param hyperrectangle Hyperrectangle.
*
* @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred.
*/
/// @{
template
constexpr std::optional> intersection(const ray& ray, const hyperrectangle& hyperrectangle) noexcept
{
T t0 = -std::numeric_limits::infinity();
T t1 = std::numeric_limits::infinity();
for (std::size_t i = 0; i < N; ++i)
{
if (!ray.direction[i])
{
if (ray.origin[i] < hyperrectangle.min[i] || ray.origin[i] > hyperrectangle.max[i])
return std::nullopt;
}
else
{
T min = (hyperrectangle.min[i] - ray.origin[i]) / ray.direction[i];
T max = (hyperrectangle.max[i] - ray.origin[i]) / ray.direction[i];
t0 = std::max(t0, std::min(min, max));
t1 = std::min(t1, std::max(min, max));
}
}
if (t0 > t1 || t1 < T{0})
return std::nullopt;
return {t0, t1};
}
template
constexpr inline std::optional> intersection(const hyperrectangle& hyperrectangle, const ray& ray) noexcept
{
return intersection(ray, hyperrectangle);
}
/// @}
/**
* Ray-hypersphere intersection test.
*
* @param ray Ray.
* @param hypersphere Hypersphere.
*
* @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred.
*/
template
std::optional> intersection(const ray& ray, const hypersphere& hypersphere) noexcept
{
const math::vector displacement = ray.origin - hypersphere.center;
const T b = math::dot(displacement, ray.direction);
const T c = math::length_squared(displacement) - hypersphere.radius * hypersphere.radius;
T h = b * b - c;
if (h < T{0})
return std::nullopt;
h = std::sqrt(h);
return std::tuple{-b - h, -b + h};
}
/**
* Hyperrectangle-hyperrectangle intersection test.
*
* @param a First hyperrectangle.
* @param b Second hyperrectangle.
*
* @return `true` if an intersection occurred, `false` otherwise.
*/
template
constexpr inline bool intersection(const hyperrectangle& a, const hyperrectangle& b) noexcept
{
return a.intersects(b);
}
/**
* Hyperrectangle-hypersphere intersection test.
*
* @param hyperrectangle Hyperrectangle.
* @param hypersphere Hypersphere.
*
* @return `true` if an intersection occurred, `false` otherwise.
*/
/// @{
template
constexpr bool intersection(const hyperrectangle& hyperrectangle, const hypersphere& hypersphere) noexcept
{
T sqr_distance{0};
for (std::size_t i = 0; i < N; ++i)
{
if (hypersphere.center[i] < hyperrectangle.min[i])
{
const T difference = hyperrectangle.min[i] - hypersphere.center[i];
sqr_distance += difference * difference;
}
else if (hypersphere.center[i] > hyperrectangle.max[i])
{
const T difference = hypersphere.center[i] - hyperrectangle.max[i];
sqr_distance += difference * difference;
}
}
return sqr_distance <= hypersphere.radius * hypersphere.radius;
}
template
constexpr inline bool intersection(const hypersphere& hypersphere, const hyperrectangle& hyperrectangle) noexcept
{
return intersection(hyperrectangle, hypersphere);
}
/// @}
/**
* Hypersphere-hypersphere intersection test.
*
* @param a First hypersphere.
* @param b Second hypersphere.
*
* @return `true` if an intersection occurred, `false` otherwise.
*/
template
constexpr inline bool intersection(const hypersphere& a, const hypersphere& b) noexcept
{
return a.intersects(b);
}
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP