LCOV - code coverage report
Current view: top level - rbc/shapes - Capsule.hpp (source / functions) Coverage Total Hit
Test: coverage_clean.info Lines: 0.0 % 14 0
Test Date: 2026-03-30 03:13:12 Functions: 0.0 % 2 0

            Line data    Source code
       1              : #pragma once
       2              : #include <math3d/math3d.hpp>
       3              : #include "rbc/AABB.hpp"
       4              : 
       5              : namespace rbc
       6              : {
       7              :     // ── Capsule ───────────────────────────────────────────────────────────────
       8              :     // A cylinder of radius `radius` capped with two hemispheres.
       9              :     // In local space the principal axis is Y.
      10              :     //   Top hemisphere centre  = (0, +half_height, 0)
      11              :     //   Bottom hemisphere centre = (0, -half_height, 0)
      12              :     // Total height = 2*(half_height + radius).
      13              :     struct Capsule
      14              :     {
      15              :         m3d::scalar half_height; // distance from centre to each cap centre
      16              :         m3d::scalar radius;
      17              : 
      18              :         Capsule() : half_height(0.5), radius(0.25) {}
      19              :         Capsule(m3d::scalar half_height, m3d::scalar radius)
      20              :             : half_height(half_height), radius(radius) {}
      21              : 
      22              :         inline bool operator==(const Capsule &o) const
      23              :         { return half_height == o.half_height && radius == o.radius; }
      24              :         inline bool operator!=(const Capsule &o) const { return !(*this == o); }
      25              :     };
      26              : 
      27              :     // ── World-space endpoints (convenience, used by collision algorithms) ─────
      28              :     inline void capsule_endpoints(const Capsule &c, const m3d::tf &tf,
      29              :                                   m3d::vec3 &p1_out, m3d::vec3 &p2_out)
      30              :     {
      31              :         const m3d::vec3 axis = tf.rotate_vector(m3d::vec3(0, c.half_height, 0));
      32              :         p1_out = tf.pos + axis;
      33              :         p2_out = tf.pos - axis;
      34              :     }
      35              : 
      36              :     // ── Support function (local space, axis = local Y) ────────────────────────
      37              :     // Capsule = Minkowski sum of segment [(0,-h,0),(0,+h,0)] and sphere of radius r.
      38              :     // Support = endpoint in dir.y sign direction, then nudge by r·normalize(dir).
      39            0 :     inline m3d::vec3 support(const Capsule &c, const m3d::vec3 &dir)
      40              :     {
      41              :         const m3d::vec3 endpoint(0.0,
      42            0 :                                   (dir.y >= 0.0 ? c.half_height : -c.half_height),
      43            0 :                                   0.0);
      44            0 :         const m3d::scalar len = m3d::length(dir);
      45            0 :         if (len < m3d::EPSILON) return endpoint;
      46            0 :         return endpoint + (dir / len) * c.radius;
      47              :     }
      48              : 
      49              :     inline m3d::scalar compute_volume(const Capsule &c)
      50              :     {
      51              :         // Cylinder + two hemispheres
      52              :         const m3d::scalar r = c.radius, h = c.half_height;
      53              :         return m3d::PI * r * r * (2.0 * h + (4.0 / 3.0) * r);
      54              :     }
      55              : 
      56              :     // Inertia tensor about the capsule's local axes (unit density).
      57              :     inline m3d::smat3 compute_inertia_tensor(const Capsule &c)
      58              :     {
      59              :         // References: Game Physics, Eberly; moment integrals for capsule.
      60              :         const m3d::scalar r  = c.radius, h = c.half_height;
      61              :         const m3d::scalar r2 = r * r;
      62              :         const m3d::scalar h2 = h * h;
      63              :         const m3d::scalar mass = compute_volume(c); // unit density
      64              : 
      65              :         // Cylinder mass and hemisphere mass fractions
      66              :         const m3d::scalar m_cyl  = m3d::PI * r2 * 2.0 * h;
      67              :         const m3d::scalar m_hemi = mass - m_cyl; // = (4/3)*pi*r³ total for both caps
      68              : 
      69              :         // About the principal axis (Y): Iyy
      70              :         const m3d::scalar Iyy = (m_cyl * r2 / 2.0) +
      71              :                                   (m_hemi * 2.0 * r2 / 5.0);
      72              : 
      73              :         // About a transverse axis (X or Z): Ixx
      74              :         // Cylinder contribution
      75              :         const m3d::scalar Ixx_cyl = m_cyl * (r2 / 4.0 + h2 / 3.0);
      76              :         // Hemisphere contribution (using parallel axis theorem, d = h + 3r/8 from cap centre)
      77              :         const m3d::scalar d_hemi  = h + 3.0 * r / 8.0;
      78              :         const m3d::scalar Ixx_hemi = m_hemi * (2.0 * r2 / 5.0 + d_hemi * d_hemi);
      79              :         const m3d::scalar Ixx = Ixx_cyl + Ixx_hemi;
      80              : 
      81              :         return m3d::smat3(Ixx, Iyy, Ixx, 0.0, 0.0, 0.0);
      82              :     }
      83              : 
      84              :     // ── Tight AABB ────────────────────────────────────────────────────────────
      85              :     // World axis of the capsule, then union of two sphere-radius boxes at endpoints.
      86            0 :     inline AABB compute_aabb(const Capsule &c, const m3d::tf &tf)
      87              :     {
      88            0 :         const m3d::vec3 axis = tf.rotate_vector(m3d::vec3(0, c.half_height, 0));
      89            0 :         const m3d::vec3 p1   = tf.pos + axis;
      90            0 :         const m3d::vec3 p2   = tf.pos - axis;
      91            0 :         const m3d::vec3 r(c.radius, c.radius, c.radius);
      92              :         return {
      93            0 :             m3d::vec3(m3d::min(p1.x, p2.x), m3d::min(p1.y, p2.y), m3d::min(p1.z, p2.z)) - r,
      94            0 :             m3d::vec3(m3d::max(p1.x, p2.x), m3d::max(p1.y, p2.y), m3d::max(p1.z, p2.z)) + r
      95            0 :         };
      96              :     }
      97              : } // namespace rbc
        

Generated by: LCOV version 2.0-1