Files
ViewDesignEngine/include/vde/collision/gjk.h
T

123 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file gjk.h
* @brief GJK (GilbertJohnsonKeerthi) 碰撞检测算法
*
* 检测任意凸形状之间的碰撞与最近距离。
* 通过 Minkowski 差和支撑函数迭代逼近最近点对。
*
* @ingroup collision
*/
#pragma once
#include "vde/core/point.h"
#include <functional>
#include <optional>
namespace vde::collision {
using core::Point3D;
using core::Vector3D;
/**
* @brief 支撑函数类型
*
* 给定方向向量 d,返回形状在该方向上最远点的坐标:
* @code{.cpp}
* Point3D support(const Vector3D& d) {
* return argmax_{v ∈ shape} dot(v, d);
* }
* @endcode
*
* 支撑函数是 GJK / EPA 算法的核心抽象。
* 只要实现了支撑函数,即可用于任意凸形状的碰撞检测。
*/
using SupportFunc = std::function<Point3D(const Vector3D&)>;
/**
* @brief GJK 完整检测结果
*/
struct GJKResult {
bool intersect; /**< 两凸体是否相交 */
double distance; /**< 最近距离(不相交时 >0,相交时为 0) */
Point3D point_a; /**< 形状 A 上的最近点 */
Point3D point_b; /**< 形状 B 上的最近点 */
};
/**
* @brief GJK 相交检测(仅判断是否碰撞)
*
* 构造 Minkowski 差 A − B,在原点附近迭代构建单纯形。
* 若原点在 Minkowski 差内 → 碰撞。
*
* 算法流程:
* 1. 取初始方向(如 a.center b.center
* 2. 计算支撑点并加入单纯形
* 3. 判断单纯形是否包含原点
* 4. 若不包含,更新搜索方向并迭代
* 5. 若方向无法收敛 → 不相交
*
* 时间复杂度 O(n),其中 n 为迭代次数(通常 < 20 对于紧凑形状)。
*
* @param shape_a 形状 A 的支撑函数
* @param shape_b 形状 B 的支撑函数
* @return 相交返回 true
*
* @code{.cpp}
* auto sphere_support = [&](const Vector3D& d) {
* return center + radius * d.normalized();
* };
* auto box_support = [&](const Vector3D& d) {
* return center + Vector3D{
* half_extent.x * (d.x > 0 ? 1 : -1),
* half_extent.y * (d.y > 0 ? 1 : -1),
* half_extent.z * (d.z > 0 ? 1 : -1)
* };
* };
* if (gjk_intersect(sphere_support, box_support)) { ... }
* @endcode
*
* @see gjk_distance, gjk_full, SupportFunc
*/
bool gjk_intersect(const SupportFunc& shape_a, const SupportFunc& shape_b);
/**
* @brief GJK 最近距离查询
*
* 在 gjk_intersect 基础上,不相交时额外调用 EPA (Expanding Polytope Algorithm)
* 计算两形状之间的精确最近距离。
*
* @param shape_a 形状 A 的支撑函数
* @param shape_b 形状 B 的支撑函数
* @return 最近距离(相交时返回 0),始终 ≥ 0
*
* @see gjk_intersect, gjk_full
*/
double gjk_distance(const SupportFunc& shape_a, const SupportFunc& shape_b);
/**
* @brief GJK 完整检测:碰撞状态、距离、最近点对
*
* 融合 gjk_intersect 和 gjk_distance,一次调用返回
* 碰撞状态、最近距离及两形状上的最近点。
*
* @param shape_a 形状 A 的支撑函数
* @param shape_b 形状 B 的支撑函数
* @return GJKResult 包含碰撞状态、距离、最近点对
*
* @note 对于连续碰撞检测 (CCD) 或需要分离向量的场景,
* 使用此函数可同时获取碰撞信息和穿透深度方向。
*
* @code{.cpp}
* auto result = gjk_full(a_support, b_support);
* if (result.intersect) {
* // 穿透,分离方向 = (point_b - point_a).normalized()
* } else {
* double gap = result.distance; // 间隙
* }
* @endcode
*
* @see gjk_intersect, gjk_distance
*/
GJKResult gjk_full(const SupportFunc& shape_a, const SupportFunc& shape_b);
} // namespace vde::collision