/* * 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/assert.hpp" #include "coord/iostream.hpp" #include using cruft::region; //----------------------------------------------------------------------------- template cruft::region::region (extent_t _extent): region (point_t::origin (), _extent) { CHECK_SANITY (*this); } //----------------------------------------------------------------------------- template cruft::region::region (point_t _p, extent_t _e): p (_p), e (_e) { CHECK_SANITY (*this); } //----------------------------------------------------------------------------- template cruft::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)); CHECK_SANITY (*this); } //----------------------------------------------------------------------------- template typename cruft::region::extent_t cruft::region::magnitude (void) const { return e; } //----------------------------------------------------------------------------- template typename cruft::region::extent_t cruft::region::magnitude (extent_t _e) { e = _e; return e; } //----------------------------------------------------------------------------- template bool cruft::region::empty (void) const { return almost_zero (area ()); } //----------------------------------------------------------------------------- template typename cruft::region::point_t cruft::region::base (void) const { return p; } //----------------------------------------------------------------------------- template typename cruft::region::point_t cruft::region::away (void) const { return p + e; } //----------------------------------------------------------------------------- template typename cruft::region::point_t cruft::region::centre (void) const { return p + e / T{2}; } //----------------------------------------------------------------------------- template typename cruft::region::point_t cruft::region::closest (point_t q) const { return clamp (q, p, p + e); } //----------------------------------------------------------------------------- // FIXME: This will fail with an actual infinite range (NaNs will be generated // in the conditionals). template bool cruft::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 { return closest (q); } //----------------------------------------------------------------------------- template cruft::region cruft::region::intersection (region rhs) const { // find the intersection corners point_t a, b; for (size_t i = 0; i < S; ++i) { a[i] = cruft::max (p[i], rhs.p[i]); b[i] = cruft::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 cruft::region::covers (region r) const noexcept { return all (p <= r.p) && all (p + e >= r.p + r.e); } /////////////////////////////////////////////////////////////////////////////// template cruft::region cruft::region::inset (T mag) const { return inset (cruft::vector {mag}); } //----------------------------------------------------------------------------- template cruft::region cruft::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 cruft::region cruft::region::expand (vector v) const { return { p - v, e + v * T{2} }; } //----------------------------------------------------------------------------- template cruft::region cruft::region::expand (T mag) const { return expand (vector {mag}); } /////////////////////////////////////////////////////////////////////////////// template cruft::region cruft::region::operator+ (vector rhs) const { return { p + rhs, e }; } //----------------------------------------------------------------------------- template cruft::region cruft::region::operator- (vector rhs) const { return { p - rhs, e }; } /////////////////////////////////////////////////////////////////////////////// template bool cruft::region::operator== (region rhs) const { return p == rhs.p && e == rhs.e; } /////////////////////////////////////////////////////////////////////////////// template cruft::region<2,T> cruft::rotate90 (cruft::region<2,T> obj, int steps) { CHECK_LIMIT (steps, 0, 3); switch (steps) { case 0: return obj; case 1: return region2 { point2 { T(obj.p.x - obj.e.h), obj.p.y }, extent2 { obj.e.h, obj.e.w, } }; case 2: return region2 { point2 { obj.p.x, T(obj.p.y - obj.e.h), }, obj.e, }; case 3: return region2 { obj.p, extent2 { obj.e.h, obj.e.w, }, }; } unreachable(); } //----------------------------------------------------------------------------- template cruft::region2 cruft::rotate90 (cruft::region2, int); template cruft::region2 cruft::rotate90 (cruft::region2, int); template cruft::region2 cruft::rotate90 (cruft::region2, int); /////////////////////////////////////////////////////////////////////////////// template std::ostream& cruft::operator<< (std::ostream &os, const cruft::region &rhs) { return os << "{ position: " << rhs.p << ", extent: " << rhs.e << " }"; } /////////////////////////////////////////////////////////////////////////////// namespace cruft::debug { template struct validator> { static bool is_valid (const cruft::region &r) { return cruft::debug::is_valid (r.p) && cruft::debug::is_valid (r.e); } }; } /////////////////////////////////////////////////////////////////////////////// #define INSTANTIATE_S_T(S,T) \ template struct cruft::region; \ template std::ostream& cruft::operator<< (std::ostream&, const region&); \ template struct cruft::debug::validator>; #define INSTANTIATE(T) \ INSTANTIATE_S_T(2,T) \ INSTANTIATE_S_T(3,T) INSTANTIATE(i16); INSTANTIATE(i32); INSTANTIATE(i64); INSTANTIATE(u16) INSTANTIATE(u32) INSTANTIATE(u64) INSTANTIATE(f32) INSTANTIATE(f64)