/* * This file is part of libgim. * * libgim is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * libgim is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with libgim. If not, see . * * Copyright 2010-2015 Danny Robson */ #include "region.hpp" #include "debug.hpp" #include "types/casts.hpp" #include #include //----------------------------------------------------------------------------- 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, _b - _a) { debug::sanity (*this); } //----------------------------------------------------------------------------- template util::region::region (std::array args) { std::copy (&args[0], &args[S], p.data); std::copy (&args[S], &args[S*2], e.data); } //----------------------------------------------------------------------------- template util::region::region (position_type _p, size_type _e): region (point_t {_p}, extent_t {_e}) { debug::sanity (*this); } //----------------------------------------------------------------------------- template typename util::region::size_type util::region::area (void) const { return e.area (); } //----------------------------------------------------------------------------- template typename util::region::size_type 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 void util::region::scale (T factor) { auto o = (e * factor - e) / T{2}; p -= o; e *= factor; } //----------------------------------------------------------------------------- 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; } //----------------------------------------------------------------------------- template bool util::region::includes (point_t q) const { for (size_t i = 0; i < S; ++i) if (q[i] < p[i] || q[i] > p[i] + e[i]) return false; return true; } //----------------------------------------------------------------------------- template bool util::region::contains (point_t q) const { for (size_t i = 0; i < S; ++i) if (q[i] <= p[i] || q[i] >= p[i] + e[i]) return false; return true; } //----------------------------------------------------------------------------- // 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 void util::region::constrain (point_t &q) const { for (size_t i = 0; i < S; ++i) q[i] = limit (q[i], p[i], p[i] + e[i]); } //----------------------------------------------------------------------------- template typename util::region::point_t util::region::constrained (point_t q) const { constrain (q); 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] = max (p[i], rhs.p[i]); b[i] = 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 util::region& util::region::resize (extent _e) { e = _e; return *this; } //----------------------------------------------------------------------------- template util::region util::region::inset (T mag) { // ensure we have enough space to inset CHECK (min (e) >= 2 * mag); return { p + mag, e - 2 * mag }; } //----------------------------------------------------------------------------- template util::region& util::region::expand (vector v) { p -= v; e += v * T{2}; return *this; } //----------------------------------------------------------------------------- template util::region& util::region::expand (T mag) { return expand ({mag}); } //----------------------------------------------------------------------------- template util::region util::region::expanded (vector v) const { return { p - v, e + v * T{2} }; } //----------------------------------------------------------------------------- template util::region util::region::expanded (T mag) const { return expanded ({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; } ///---------------------------------------------------------------------------- /// The largest specifiable finite region. /// /// Starts at half the minimum value to allow the width to cover some positive /// range rather than just cancelling out the lowest value for signed types. /// /// Specifically does not allow infinities. Use/define INFINITE when required. template const util::region util::region::MAX ( std::numeric_limits::lowest () / 2, std::numeric_limits::max () ); template const util::region util::region::UNIT ({0}, {1}); //----------------------------------------------------------------------------- template std::ostream& util::operator<< (std::ostream &os, const util::region &rhs) { os << "region(" << rhs.p << ", " << rhs.e << ")"; return os; } /////////////////////////////////////////////////////////////////////////////// namespace debug { template struct validator { static bool is_valid (const util::region &r) { CHECK_GE (r.area (), 0); CHECK_GE (min (r.e), 0); return r.area () >= 0 && min (r.e) >= 0; } }; } /////////////////////////////////////////////////////////////////////////////// #define INSTANTIATE_S_T(S,T) \ namespace util { \ template struct region; \ template std::ostream& operator<< (std::ostream&, const region&); \ } \ namespace debug { template struct debug::validator; } #define INSTANTIATE(T) \ INSTANTIATE_S_T(2,T) \ INSTANTIATE_S_T(3,T) INSTANTIATE(uint32_t) INSTANTIATE(uint64_t) INSTANTIATE(float) INSTANTIATE(double)