/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2010-2017 Danny Robson */ #ifndef CRUFT_UTIL_EXTENT_HPP #define CRUFT_UTIL_EXTENT_HPP #include "coord/fwd.hpp" #include "coord/base.hpp" #include "vector.hpp" #include "point.hpp" #include "random.hpp" #include namespace util { /** * A pure n-dimensional size, without positioning */ template struct extent : public ::util::coord::base> { using ::util::coord::base>::base; extent () = default; explicit extent (::util::vector); constexpr T area (void) const { return std::accumulate (std::begin (this->data), std::end (this->data), T {1}, std::multiplies ()); } constexpr T diameter (void) const { return static_cast ( std::sqrt ( std::accumulate (std::begin (this->data), std::end (this->data), T {0}, [] (auto a, auto b) { return a + b * b; }) ) ); } template constexpr U aspect (void) const { return static_cast (this->w) / this->h; } /// tests whether a point would lie within: /// region { origin, *this }, inclusive of borders. /// /// included for parity with util::region. constexpr bool inclusive (util::point p) const { return all (p >= T{0} && p <= *this); } /// tests whether a point would like within: /// region { origin, *this }, exclusive of the bottom-right border /// included for parity with util::region constexpr bool exclusive (point p) const { return all (p >= T{0} && p < *this); } ::util::extent expanded (::util::vector) const; ::util::extent expanded (T) const; ::util::extent contracted (::util::vector) const; ::util::extent contracted (T) const; bool empty (void) const; static constexpr ::util::extent max (void) { return extent { std::numeric_limits::max () }; } static constexpr ::util::extent min (void) { return extent { 0 }; } /////////////////////////////////////////////////////////////////////// class iterator { public: using iterator_category = std::forward_iterator_tag; using value_type = point; using difference_type = size_t; using pointer = value_type*; using reference = value_type&; iterator (point _cursor, extent _target): m_cursor (_cursor), m_target (_target) { ; } point& operator* () & { return m_cursor; } const point& operator* () const & { return m_cursor; } iterator& operator++ (void)& { ++m_cursor[0]; for (size_t i = 0; i < S - 1; ++i) { if (m_cursor[i] < m_target[i]) break; m_cursor[i] = 0; m_cursor[i+1]++; } return *this; } bool operator!= (const iterator &rhs) const { return m_cursor != rhs.m_cursor; } bool operator== (const iterator &rhs) const { return m_cursor == rhs.m_cursor; } private: point m_cursor; extent m_target; }; auto step (void) const { point last {0}; last[S-1] = this->data[S-1]; return util::view { iterator {point {0}, *this}, iterator {last, *this} }; } }; template util::point sample (util::extent shape) { return sample (shape, util::random::generator ()); } template util::point sample (util::extent shape, GeneratorT &&gen) { util::point p; for (size_t i = 0; i < S; ++i) p[i] = util::random::uniform (0, shape[i], gen); return p; } /////////////////////////////////////////////////////////////////////////// // convenience typedefs template using extent2 = extent<2,T>; template using extent3 = extent<3,T>; template using extentu = extent; template using extenti = extent; template using extentf = extent; template using extentd = extent; typedef extent2 extent2i; typedef extent2 extent2u; typedef extent2 extent2f; typedef extent2 extent2d; typedef extent3 extent3u; typedef extent3 extent3f; } #endif