/* * 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 */ #include "region.hpp" #include "debug.hpp" #include "coord/iostream.hpp" #include using util::region; //----------------------------------------------------------------------------- template util::region::region (extent_t _extent): region (point_t::origin (), _extent) { debug::sanity (*this); } //----------------------------------------------------------------------------- template util::region::region (point_t _p, extent_t _e): p (_p), e (_e) { debug::sanity (*this); } //----------------------------------------------------------------------------- template util::region::region (point_t _a, point_t _b): region (_a, extent_t { _b - _a }) { // This check must allow for zero area (but non-zero dimension) regions. // Some code paths need to support this degenerate case. It's ugly but // simplifies generalisation. eg, vertical linear bezier curves. CHECK (all (_a <= _b)); debug::sanity (*this); } //----------------------------------------------------------------------------- template T util::region::area (void) const { return e.area (); } //----------------------------------------------------------------------------- template T util::region::diameter (void) const { return e.diameter (); } //----------------------------------------------------------------------------- template typename util::region::extent_t util::region::magnitude (void) const { return e; } //----------------------------------------------------------------------------- template typename util::region::extent_t util::region::magnitude (extent_t _e) { e = _e; return e; } //----------------------------------------------------------------------------- template bool util::region::empty (void) const { return almost_zero (area ()); } //----------------------------------------------------------------------------- template typename util::region::point_t util::region::base (void) const { return p; } //----------------------------------------------------------------------------- template typename util::region::point_t util::region::away (void) const { return p + e; } //----------------------------------------------------------------------------- template typename util::region::point_t util::region::centre (void) const { return p + e / T{2}; } //----------------------------------------------------------------------------- template typename util::region::point_t util::region::closest (point_t q) const { point_t out; for (size_t i = 0; i < S; ++i) out[i] = q[i] < p[i] ? p[i] : q[i] > p[i] ? p[i] + e[i] : q[i]; return out; } //----------------------------------------------------------------------------- // FIXME: This will fail with an actual infinite range (NaNs will be generated // in the conditionals). template bool util::region::intersects (region rhs) const { for (size_t i = 0; i < S; ++i) if ( p[i] >= rhs.p[i] + rhs.e[i] || rhs.p[i] >= p[i] + e[i]) { return false; } return true; } //----------------------------------------------------------------------------- template typename region::point_t region::constrain (point_t q) const noexcept { for (size_t i = 0; i < S; ++i) q[i] = clamp (q[i], p[i], p[i] + e[i]); return q; } //----------------------------------------------------------------------------- template util::region util::region::intersection (region rhs) const { // find the intersection corners point_t a, b; for (size_t i = 0; i < S; ++i) { a[i] = util::max (p[i], rhs.p[i]); b[i] = util::min (p[i] + e[i], rhs.p[i] + rhs.e[i]); if (b[i] < a[i]) throw std::logic_error ("no overlap"); } return { a, b }; } //----------------------------------------------------------------------------- template bool util::region::covers (region r) const noexcept { return all (p <= r.p) && all (p + e >= r.p + r.e); } /////////////////////////////////////////////////////////////////////////////// template util::region util::region::inset (T mag) const { return inset (util::vector {mag}); } //----------------------------------------------------------------------------- template util::region util::region::inset (vector mag) const { // ensure we have enough space to trim off our total extent CHECK (all (e >= T{2} * mag)); return { p + mag, e - T{2} * mag }; } //----------------------------------------------------------------------------- template util::region util::region::expand (vector v) const { return { p - v, e + v * T{2} }; } //----------------------------------------------------------------------------- template util::region util::region::expand (T mag) const { return expand (vector {mag}); } /////////////////////////////////////////////////////////////////////////////// template util::region util::region::operator+ (vector rhs) const { return { p + rhs, e }; } //----------------------------------------------------------------------------- template util::region util::region::operator- (vector rhs) const { return { p - rhs, e }; } /////////////////////////////////////////////////////////////////////////////// template bool util::region::operator== (region rhs) const { return p == rhs.p && e == rhs.e; } /////////////////////////////////////////////////////////////////////////////// template std::ostream& util::operator<< (std::ostream &os, const util::region &rhs) { return os << "{ position: " << rhs.p << ", extent: " << rhs.e << " }"; } /////////////////////////////////////////////////////////////////////////////// namespace util::debug { template struct validator> { static bool is_valid (const util::region &r) { return util::debug::is_valid (r.p) && util::debug::is_valid (r.e); } }; } /////////////////////////////////////////////////////////////////////////////// #define INSTANTIATE_S_T(S,T) \ template struct util::region; \ template std::ostream& util::operator<< (std::ostream&, const region&); \ template struct util::debug::validator>; #define INSTANTIATE(T) \ INSTANTIATE_S_T(2,T) \ INSTANTIATE_S_T(3,T) INSTANTIATE(int16_t); INSTANTIATE(int32_t); INSTANTIATE(int64_t); INSTANTIATE(uint16_t) INSTANTIATE(uint32_t) INSTANTIATE(uint64_t) INSTANTIATE(float) INSTANTIATE(double)