alignedbox.h

Back to Rectangles

pastel/sys/alignedbox/

// Description: Axis-aligned box

#ifndef PASTELSYS_ALIGNEDBOX_H
#define PASTELSYS_ALIGNEDBOX_H

#include "pastel/sys/mytypes.h"
#include "pastel/sys/vector.h"
#include "pastel/sys/math/constants.h"
#include "pastel/sys/vector.h"
#include "pastel/sys/topology.h"

#include <boost/operators.hpp>

namespace Pastel
{

    //! An axis-aligned box
    template <typename Real, integer N = Dynamic>
    class AlignedBox
        : boost::multipliable<AlignedBox<Real, N>, Real
        , boost::dividable<AlignedBox<Real, N>, Real
        , boost::addable<AlignedBox<Real, N>, Vector<Real, N>
        , boost::subtractable<AlignedBox<Real, N>, Vector<Real, N>
        , boost::equality_comparable<AlignedBox<Real, N>
        > > > > >
    {
    private:
        PASTEL_STATIC_ASSERT(N == Dynamic || N > 0);

    public:
        using Real_ = Real;

        static constexpr integer N_ = N;

        // Using default copy constructor.
        // Using default assignment.

        //! Constructs a unit box centered at the origin.
        explicit AlignedBox(integer dimension = N)
            : min_(Dimension(dimension), (Real)Infinity())
            , max_(Dimension(dimension), -(Real)Infinity())
            , minTopology_(ofDimension(dimension), Topology::Closed)
            , maxTopology_(ofDimension(dimension), Topology::Open)
        {
            PENSURE2((N == Dynamic && dimension > 0) || 
                (N != Dynamic && dimension == N), dimension, N);
        }

        //! Constructs a singular box (min = max = that).
        explicit AlignedBox(const Vector<Real, N>& that)
            : min_(that)
            , max_(that)
            , minTopology_(ofDimension(that.n()), Topology::Closed)
            , maxTopology_(ofDimension(that.n()), Topology::Open)
        {
        }

        //! Constructs a box using the given points.
        AlignedBox(
            const Vector<Real, N>& min,
            const Vector<Real, N>& max)
            : min_(min)
            , max_(max)
            , minTopology_(ofDimension(min.n()), Topology::Closed)
            , maxTopology_(ofDimension(max.n()), Topology::Open)
        {
        }

        template <
            integer N_ = N,
            RequiresC<(N_ == 1)> = 0
            >
        AlignedBox(
            const Real& xMin, 
            const Real& xMax)
            : min_(xMin)
            , max_(xMax)
            , minTopology_(ofDimension(min_.n()), Topology::Closed)
            , maxTopology_(ofDimension(max_.n()), Topology::Open)
        {
        }

        template <
            integer N_ = N,
            RequiresC<(N_ == 2)> = 0
            >
        AlignedBox(
            const Real& xMin, const Real& yMin,
            const Real& xMax, const Real& yMax)
            : min_(xMin, yMin)
            , max_(xMax, yMax)
            , minTopology_(ofDimension(min_.n()), Topology::Closed)
            , maxTopology_(ofDimension(max_.n()), Topology::Open)
        {
        }

        template <
            integer N_ = N,
            RequiresC<(N_ == 3)> = 0
            >
        AlignedBox(
            const Real& xMin, const Real& yMin, const Real& zMin,
            const Real& xMax, const Real& yMax, const Real& zMax)
            : min_(xMin, yMin, zMin)
            , max_(xMax, yMax, zMax)
            , minTopology_(ofDimension(min_.n()), Topology::Closed)
            , maxTopology_(ofDimension(max_.n()), Topology::Open)
        {
        }

        template <
            integer N_ = N,
            RequiresC<(N_ == 4)> = 0>
        AlignedBox(
            const Real& xMin, const Real& yMin, const Real& zMin, const Real& wMin,
            const Real& xMax, const Real& yMax, const Real& zMax, const Real& wMax)
            : min_(xMin, yMin, zMin, wMin)
            , max_(xMax, yMax, zMax, wMax)
            , minTopology_(ofDimension(min_.n()), Topology::Closed)
            , maxTopology_(ofDimension(max_.n()), Topology::Open)
        {
        }

        //! Returns whether the i:th projection contains any points.
        bool empty(integer i) const
        {
            PENSURE_OP(i, >=, 0);
            PENSURE_OP(i, <, n());

            if (min_[i] >= max_[i])
            {
                if (min_[i] > max_[i] ||
                    minTopology_[i] == Topology::Open ||
                    maxTopology_[i] == Topology::Open)
                {
                    return true;
                }
            }

            return false;
        }

        //! Returns whether the box contains any points.
        bool empty() const
        {
            integer d = n();
            for (integer i = 0;i < d;++i)
            {
                if (empty(i))
                {
                    return true;
                }
            }

            return false;
        }

        //! Swaps two aligned boxes.

        void swap(AlignedBox<Real, N>& that)
        {
            using std::swap;

            min_.swap(that.min_);
            max_.swap(that.max_);
            minTopology_.swap(that.minTopology_);
            maxTopology_.swap(that.maxTopology_);
        }

        integer n() const
        {
            return min_.size();
        }

        //! Sets the corner points of the box.
        void set(
            const Vector<Real, N>& min,
            const Vector<Real, N>& max)
        {
            min_ = min;
            max_ = max;
        }

        //! Sets the minimum point of the box.
        void setMin(const Vector<Real, N>& min)
        {
            min_ = min;
        }

        //! Returns the minimum point of the box.
        Vector<Real, N>& min()
        {
            return min_;
        }

        //! Returns the minimum point of the box.
        const Vector<Real, N>& min() const
        {
            return min_;
        }

        //! Sets the maximum point of the box.
        void setMax(const Vector<Real, N>& max)
        {
            max_ = max;
        }

        //! Returns the maximum point of the box.
        Vector<Real, N>& max()
        {
            return max_;
        }

        //! Returns the maximum point of the box.
        const Vector<Real, N>& max() const
        {
            return max_;
        }

        //! Returns the topology of the minimums.
        Tuple<Topology, N>& minTopology()
        {
            return minTopology_;
        }

        //! Returns the topology of the minimums.
        const Tuple<Topology, N>& minTopology() const
        {
            return minTopology_;
        }

        //! Returns the topology of the maximums.
        Tuple<Topology, N>& maxTopology()
        {
            return maxTopology_;
        }

        //! Returns the topology of the maximums.
        const Tuple<Topology, N>& maxTopology() const
        {
            return maxTopology_;
        }

        //! Returns max() - min().
        VectorSubtraction<Real, N, 
            Vector<Real, N>, 
            Vector<Real, N> >
            extent() const
        {
            return max_ - min_;
        }

        Real extent(integer index) const
        {
            return max_[index] - min_[index];
        }

        Vector<Real, N> at(
            const Vector<Real, N>& coordinates) const
        {
            return Vector<Real, N>(
                (1 - coordinates) * min_ +
                coordinates * max_);
        }

        //! Translates the box by the given vector.
        AlignedBox<Real, N>& operator+=(
            const Vector<Real, N>& right)
        {
            min_ += right;
            max_ += right;

            return *this;
        }

        //! Translates the box backwards by the given vector.
        AlignedBox<Real, N>& operator-=(
            const Vector<Real, N>& right)
        {
            min_ -= right;
            max_ -= right;

            return *this;
        }

        //! Scales up the box without affecting position.
        AlignedBox<Real, N>& operator*=(
            const Real& that)
        {
            Vector<Real, N> translation =
                (max_ - min_) * ((that - 1) / 2);

            min_ -= translation;
            max_ += translation;

            return *this;
        }

        //! Scales down the box without affecting position.
        AlignedBox<Real, N>& operator/=(
            const Real& that)
        {
            return (*this *= inverse(that));
        }

        template <integer N_ = N, RequiresC<(N_ == 1)> = 0>
        void set(
            const Real& xMin,
            const Real& xMax)
        {
            set(Vector<Real, N>(xMin),
                Vector<Real, N>(xMax));
        }

        template <integer N_ = N, RequiresC<(N_ == 2)> = 0>
        void set(
            const Real& xMin, const Real& yMin,
            const Real& xMax, const Real& yMax)
        {
            set(Vector<Real, N>(xMin, yMin),
                Vector<Real, N>(xMax, yMax));
        }

        template <integer N_ = N, RequiresC<(N_ == 3)> = 0>
        void set(
            const Real& xMin, const Real& yMin, const Real& zMin,
            const Real& xMax, const Real& yMax, const Real& zMax)
        {
            set(Vector<Real, N>(xMin, yMin, zMin),
                Vector<Real, N>(xMax, yMax, zMax));
        }

        template <integer N_ = N, RequiresC<(N_ == 4)> = 0>
        void set(
            const Real& xMin, const Real& yMin, const Real& zMin, const Real& wMin,
            const Real& xMax, const Real& yMax, const Real& zMax, const Real& wMax)
        {
            set(Vector<Real, N>(xMin, yMin, zMin, wMin),
                Vector<Real, N>(xMax, yMax, zMax, wMax));
        }

        template <integer N_ = N, RequiresC<(N_ >= 1)> = 0>
        Real width() const
        {
            return extent()[0];
        }

        template <integer N_ = N, RequiresC<(N_ >= 2)> = 0>
        Real height() const
        {
            return extent()[1];
        }

        template <integer N_ = N, RequiresC<(N_ >= 3)> = 0>
        Real depth() const
        {
            return extent()[2];
        }

        bool operator==(const AlignedBox& that) const
        {
            return 
                min_ == that.min_ &&
                max_ == that.max_ &&
                minTopology_ == that.minTopology_ &&
                maxTopology_ == that.maxTopology_;
        }

    private:
        Vector<Real, N> min_;
        Vector<Real, N> max_;
        Tuple<Topology, N> minTopology_;
        Tuple<Topology, N> maxTopology_;
    };

    template <typename Real, integer N>
    void swap(AlignedBox<Real, N>& left,
        AlignedBox<Real, N>& right);

    using AlignedBox1 = AlignedBox<real, 1>;
    using AlignedBox2 = AlignedBox<real, 2>;
    using AlignedBox3 = AlignedBox<real, 3>;
    using AlignedBox4 = AlignedBox<real, 4>;
    using AlignedBoxD = AlignedBox<real, Dynamic>;

    using AlignedBox1i = AlignedBox<integer, 1>;
    using AlignedBox2i = AlignedBox<integer, 2>;
    using AlignedBox3i = AlignedBox<integer, 3>;
    using AlignedBox4i = AlignedBox<integer, 4>;
    using AlignedBoxDi = AlignedBox<integer, Dynamic>;

}

#include "pastel/sys/alignedbox/alignedbox.hpp"
#include "pastel/sys/alignedbox/alignedbox_tools.h"

#endif