/* * 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-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, extent_t { _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 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 (vector {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 (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; } ///---------------------------------------------------------------------------- /// 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 ( util::point {std::numeric_limits::lowest () / 2}, util::extent {std::numeric_limits::max ()} ); template const util::region util::region::UNIT (util::point{0}, util::extent{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(uint16_t) INSTANTIATE(uint32_t) INSTANTIATE(uint64_t) INSTANTIATE(float) INSTANTIATE(double)