sphere_volume.hpp

Back to Volume

pastel/geometry/volume/

#ifndef PASTELGEOMETRY_SPHERE_VOLUME_HPP
#define PASTELGEOMETRY_SPHERE_VOLUME_HPP

#include "pastel/geometry/volume/sphere_volume.h"
#include "pastel/geometry/area/sphere_area.h"

#include "pastel/sys/math/factorial.h"
#include "pastel/sys/math/gamma.h"
#include "pastel/sys/math/powers.h"

namespace Pastel
{

    template <typename Real>
    Real lnVolumeUnitSphereManhattan(integer n)
    {
        PENSURE_OP(n, >, 0);

        // See volumeUnitSphereManhattan() for the derivation 
        // of the volume.

        // ln(volume(S))
        // = ln(2^n / n!)
        // = n ln(2) - ln(n!)

        return n * constantLn2<Real>() - lnFactorial<Real>(n);
    }

    template <typename Real>
    Real volumeUnitSphereManhattan(integer n)
    {
        ENSURE_OP(n, >, 0);

        // The volume of Manhattan unit sphere is
        // 2^n / n!.

        switch(n)
        {
        case 1:
            // 2^1 / 1! = 2
            return 2;
            break;
        case 2:
            // 2^2 / 2! = 2
            return 2;
            break;
        case 3:
            // 2^3 / 3! = 8 / 6 = 4 / 3
            return (Real)4 / 3;
            break;
        };

        return std::pow((Real)2, (Real)n) / gamma<Real>(n + 1);
    } 

    template <typename Real>
    Real lnVolumeUnitSphere(integer n)
    {
        ENSURE_OP(n, >, 0);

        // See volumeUnitSphere() for the derivation 
        // of the volume.

        // ln(volume(S))
        // = ln(pi^(n / 2) / gamma(n / 2 + 1))
        // = (n / 2) ln(pi) - ln(gamma(n / 2 + 1))

        Real nHalf = (Real)n / 2;
        return nHalf * std::log(constantPi<Real>()) - lnGamma<Real>(nHalf + 1);
    }

    template <typename Real>
    Real volumeUnitSphere(integer n)
    {
        ENSURE_OP(n, >, 0);

        // The volume of the Euclidean unit sphere is
        // pi^(n / 2) / gamma(n / 2 + 1).

        switch(n)
        {
        case 1:
            // pi^(0.5) / gamma(1.5) 
            // = pi^(0.5) / (0.5 gamma(0.5))
            // = pi^(0.5) / (0.5 pi^(0.5))
            // = 1 / 0.5 
            // = 2
            return 2;
            break;
        case 2:
            // pi / gamma(2)
            // = pi / 1!
            // = pi
            return constantPi<Real>();
            break;
        case 3:
            // pi^(1.5) / gamma(2.5)
            // = pi^(1.5) / (1.5 gamma(1.5))
            // = pi^(1.5) / (1.5 * 0.5 * gamma(0.5))
            // = pi^(1.5) / (1.5 * 0.5 * pi^(0.5))
            // = pi / ((3 / 2) * (1 / 2))
            // = pi / (3 / 4)
            // = (4 / 3) pi
            return ((Real)4 / 3) * constantPi<Real>();
            break;
        };

        Real nHalf = (Real)n / 2;
        return std::pow(constantPi<Real>(), nHalf) / gamma<Real>(nHalf + 1);
    } 

    template <typename Real>
    Real lnVolumeUnitSphereMinkowski(
        integer n, 
        const NoDeduction<Real>& power)
    {
        PENSURE_OP(n, >, 0);
        PENSURE_OP(power, >, 0);

        Real inversePower = inverse(power);

        // From Wikipedia "Volume of an n-ball"
        return 
            lnGamma<Real>(inversePower + 1) - 
            lnGamma<Real>(n * inversePower + 1) +
            n * constantLn2<Real>();
    }

    template <typename Real>
    Real lnVolumeUnitSphereInfinity(integer n)
    {
        PENSURE_OP(n, >, 0);

        // See volumeUnitSphereInfinity() for the
        // derivation of the volume.

        // ln(volume(S)) 
        // = ln(2^n)
        // = n ln(2)

        return n * constantLn2<Real>();
    }

    template <typename Real>
    Real volumeUnitSphereInfinity(integer n)
    {
        PENSURE_OP(n, >, 0);

        // S = {x in R^n : max(|x_1|, ..., |x_n|) <= 1}
        //   = [-1, 1]^n
        // => 
        // volume(S) = 2^n

        return std::pow((Real)2, (Real)n);
    }

    template <typename Real, integer N>
    Real volume(const Sphere<Real, N>& sphere)
    {
        return volumeUnitSphere<Real>(sphere.n()) * 
            std::pow(sphere.radius(), sphere.n());
    }

}

#endif