ellipsoid.hpp

Back to Ellipsoid

pastel/geometry/shape/

#ifndef PASTELGEOMETRY_ELLIPSOID_HPP
#define PASTELGEOMETRY_ELLIPSOID_HPP

#include "pastel/geometry/shape/ellipsoid.h"

#include "pastel/math/matrix/matrix_inverse.h"

namespace Pastel
{

    template <typename Real>
    Matrix<Real> ellipsoidQuadraticForm(
        const Matrix<Real>& basis)
    {
        // An origin-centered ellipsoid Q is given by the set:
        // Q = {p | f(p) = 1}
        // where
        // f(p) = p^T S p
        // S is in R^(n x n) and symmetric positive semi-definite
        // p is in R^n
        //
        // We would like to transform Q by a linear transformation L.
        // Let us try to find how this affects the coefficient matrix:
        // L(Q) = {Lp | f(p) = 1}
        //      = {p | f(L^-1 p) = 1}
        //      = {p | p^T L^-T S L^-1 p = 1}
        //      = {p | p^T S' p = 1}
        // where
        // S' = L^-T S L^-1
        //
        // Thus we see that to transform an ellipsoid by a linear
        // transformation we just need to multiply its
        // coefficient matrix with proper matrices from both sides.
        //
        // Clearly L^-T S L^-1 is symmetric:
        // (L^-T S L^-1)^T = L^-T S^T L^-1 = L^-T S L^-1
        // To see it is positive semi-definite, let
        // the spectral decomposition of S = M^T A M. Now:
        // (for all x:)
        // x^T L^-T S L^-1 x
        // = x^T L^-T M^T A M L^-1 x
        // = x^T L^-T M^T sqrt(A^T) sqrt(A) M L^-1 x
        // = (sqrt(A) M L^-1 x)^T (sqrt(A) M L^-1 x)
        // = |sqrt(A) M L^-1 x|^2 >= 0
        //
        // Thus the image of an ellipsoid under a linear transformation
        // is an ellipsoid.
        //
        // The unit sphere is given by S = I. Thus if we are given
        // a linear transformation of this sphere then
        // the resulting quadric has S' = L^-T L^-1 = (L L^T)^-1.

        return inverse(basis * transpose(basis));
    }

    template <typename Real>
    AlignedBox<Real> ellipsoidBoundingAlignedBox(
        const Matrix<Real>& quadraticForm)
    {
        // TODO: What if the 'quadraticForm'
        // is not invertible?

        // I credit 'Dave' from sci.math for
        // the solution of this problem. Discussions
        // with Dave Eberly in comp.graphics.algorithms
        // were also helpful.
        //
        // Let
        // p : R^n -> R: p(x) = x^T S x
        // S symmetric and positive semi-definite
        //
        // Note that:
        // gradient(p)(x) = 2Sx
        //
        // We wish to compute the bounds of the ellipsoid
        // E = {x in R^n : p(x) = 1}
        // along a unit vector n. To do this, we use
        // Lagrange multipliers to solve a constrained
        // maximization problem.
        //
        // We wish to maximize the length of the
        // projection to n:
        //
        // f(x) = n^T x
        //
        // with the constraint that the vector
        // lies on the ellipsoid:
        //
        // x^T S x = 1
        //
        // To solve this, we transform the problem
        // to an unconstrained problem of maximizing:
        //
        // h(x, t) = n^T x + t (x^T S x - 1)
        //
        // The gradient of h is given by:
        // g(x, t) = n + 2t Sx
        //
        // The derivative of h w.r.t. t is:
        // (dh/dt)(x, t) = x^T S x - 1
        //
        // We set these derivatives to zero to
        // find the maximum:
        //
        // n + 2t Sx = 0    (1)
        // x^T S x - 1 = 0  (2)
        //
        // (1)
        // => x = -S^-1 n / 2t
        //
        // (1) => (2)
        // (1 / (4t^2)) n^T S^-T S S^-1 n - 1
        // = (1 / (4t^2)) n^T S^-T n - 1 = 0
        // =>
        // n^T S^-T n / 4 = t^2
        // =>
        // n^T S^-1 n / 4 = t^2
        // =>
        // t = +/- sqrt(n^T S^-1 n) / 2
        //
        // (2) => (1)
        // x = +/- S^-1 n / sqrt(n^T S^-1 n)
        //
        // We are only interested in the length along
        // the vector n:
        //
        // n^T x = +/- n^T S^-1 n / sqrt(n^T S^-1 n)
        // = +/- sqrt(n^T S^-1 n)
        //
        // We shall now use this formula for the standard
        // basis axes. In this case:
        //
        // e_i^T x = +/- sqrt(e_i^T S^-1 e_i)
        // = +/- sqrt(S^-1(i, i))

        Vector<Real> radius = 
            sqrt(diagonal(inverse(quadraticForm)));

        return AlignedBox<Real>(-radius, radius);
    }

}

#endif