/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2010-2017 Danny Robson */ #ifndef CRUFT_UTIL_REGION_HPP #define CRUFT_UTIL_REGION_HPP #include "./extent.hpp" #include "./point.hpp" #include "./vector.hpp" #include "./types/traits.hpp" #include namespace util { /** * A two-dimensional rectangle, with size and position. */ template struct region { using extent_t = util::extent; using point_t = util::point; using value_type = T; //--------------------------------------------------------------------- static constexpr size_t dimension = S; static constexpr size_t elements = extent_t::elements + point_t::elements; point_t p; extent_t e; //--------------------------------------------------------------------- region () = default; explicit region (extent_t); region (point_t, extent_t); region (point_t, point_t); //--------------------------------------------------------------------- template constexpr region cast (void) const { return { p.template cast (), e.template cast () }; } //--------------------------------------------------------------------- T area (void) const; T diameter (void) const; extent_t magnitude (void) const; extent_t magnitude (extent_t); bool empty (void) const; //--------------------------------------------------------------------- point_t base (void) const; point_t away (void) const; point_t centre (void) const; point_t closest (point_t) const; //--------------------------------------------------------------------- // exclusive of borders bool intersects (region) const; // Compute binary region combinations region intersection (region) const; // Test if a region lies completely within our space bool covers (region) const noexcept; /// Test if a point lies within our space. Inclusive of borders constexpr bool inclusive (point q) const noexcept { return all (p <= q && p + e >= q); } /// test if a point lies within our space, exclusive of the /// bottom-right border constexpr bool exclusive (point q) const noexcept { return all (p <= q && p + e > q); } // Move a point to be within the region bounds point_t constrain (point_t) const noexcept; //--------------------------------------------------------------------- // Compute a region `mag` units into the region region inset (T mag) const; region inset (vector mag) const; region expand (T mag) const; region expand (vector) const; // arithmetic operators region operator+ (vector) const; region operator- (vector) const; // Logical comparison operators bool operator ==(region rhs) const; bool operator !=(region rhs) const { return !(*this == rhs); } // Utility constants static constexpr region max (void) { return { util::point {std::numeric_limits::lowest () / 2}, util::extent {std::numeric_limits::max ()} }; } static constexpr region unit (void) { return { point_t::origin (), extent_t {1} }; } static constexpr region zero (void) { return { point_t {0}, extent_t {0} }; } class iterator { public: using iterator_category = std::forward_iterator_tag; using difference_type = std::size_t; using value_type = point_t; using pointer = value_type*; using reference = value_type&; iterator (point_t _lo, point_t _hi): cursor (_lo), lo (_lo), hi (_hi) { ; } const point_t& operator* (void) const& { return cursor; } iterator& operator++ (void) { cursor[0] += 1; for (size_t s = 0; s < S-1; ++s) { if (cursor[s] <= hi[s]) return *this; cursor[s] = lo[s]; cursor[s+1]++; } return *this; } bool operator== (const iterator &rhs) const { return cursor == rhs.cursor; } bool operator!= (const iterator &rhs) const { return cursor != rhs.cursor; } private: point_t cursor, lo, hi; }; auto step (void) const { point_t last = p; last[S-1] = (p + e)[S-1] + 1; return util::view { iterator { p, p + e }, iterator { last, p + e } }; }; void sanity (void) const; }; /////////////////////////////////////////////////////////////////////////// /// constructs the minimal region that encompasses a region and a point. template region make_union (region r, point p) { const auto p0 = select (r.p < p, r.p, p); const auto p1 = select (r.away () > p, r.away (), p); return { p0, p1 }; } template T distance2 (region r, point p) { auto const clamped = util::max ( util::min (p, r.p + r.e), r.p ); return distance2 (r.p, clamped); } template T distance2 (point p, region r) { return distance2 (r, p); } template bool intersects (util::region const area, util::point const query) { return area.inclusive (query); } ///------------------------------------------------------------------------ /// returns true if the supplied point lies within the supplied region /// inclusive of borders. template bool intersects (util::point const query, util::region const area) { return intersects (area, query); } /////////////////////////////////////////////////////////////////////////// /// returns a uniformly randomly sampled point within the supplied region template util::point sample (region shape, GeneratorT &&gen) { return shape.p + sample (shape.e, std::forward (gen)).template as (); } /////////////////////////////////////////////////////////////////////////// template using region2 = region<2,T>; template using region3 = region<3,T>; using region2u = region2; using region2i = region2; using region2f = region2; using region2d = region2; /////////////////////////////////////////////////////////////////////////// template std::ostream& operator<< (std::ostream&, const util::region&); } #endif