/* * 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-2016 Danny Robson */ #include "./region.hpp" #include "./debug.hpp" #include "./coord/iostream.hpp" //----------------------------------------------------------------------------- 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 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 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] = 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 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 - static_cast (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; } /////////////////////////////////////////////////////////////////////////////// template std::ostream& util::operator<< (std::ostream &os, const util::region &rhs) { return os << "{position: " << rhs.p << ", extent: " << rhs.e << "}"; } /////////////////////////////////////////////////////////////////////////////// namespace util { namespace 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)