/* * 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 (point<2,T> _point, extent _size): x (_point.x), y (_point.y), w (_size.w), h (_size.h) { ; } //----------------------------------------------------------------------------- template util::region::region (position_type _x, position_type _y, size_type _w, size_type _h): x (_x), y (_y), w (_w), h (_h) { ; } //----------------------------------------------------------------------------- template typename util::region::size_type util::region::area (void) const { return w * h; } //----------------------------------------------------------------------------- template typename util::region::size_type util::region::diameter (void) const { return static_cast (std::sqrt (w * w + h * h)); } //----------------------------------------------------------------------------- template util::extent::size_type> util::region::size (void) const { return { w, h }; } //----------------------------------------------------------------------------- template void util::region::scale (T factor) { x -= (w * factor - w) / T{2}; y -= (h * factor - h) / T{2}; w = w * factor; h = h * factor; } //----------------------------------------------------------------------------- template bool util::region::empty (void) const { return almost_zero (area ()); } //----------------------------------------------------------------------------- template util::point<2,T> util::region::base (void) const { return { x, y }; } //----------------------------------------------------------------------------- template util::point<2,T> util::region::far (void) const { return { x + w, y + h }; } //----------------------------------------------------------------------------- template util::point<2,T> util::region::centre (void) const { T cx = x + w / T{2}, cy = y + h / T{2}; return point<2,T> { cx, cy }; } //----------------------------------------------------------------------------- template util::point<2,T> util::region::closest (point<2,T> p) const { return { p.x < x ? x : p.x > x + w ? x + w : p.x, p.y < y ? y : p.y > y + h ? y + h : p.y }; } //----------------------------------------------------------------------------- template bool util::region::includes (const point<2,T> &p) const { return p.x >= x && p.y >= y && p.x - x <= w && p.y - y <= h; } //----------------------------------------------------------------------------- template bool util::region::contains (const point<2,T> &p) const { return p.x > x && p.y > y && p.x - x < w && p.y - y < h; } //----------------------------------------------------------------------------- // FIXME: This will fail with an actual infinite range (NaNs will be generated // in the conditionals). template bool util::region::intersects (const util::region &rhs) const { return x < rhs.x + rhs.w && rhs.x < x + w && y < rhs.y + rhs.h && rhs.y < y + h; } //----------------------------------------------------------------------------- template void util::region::constrain (point<2,T> &p) const { p.x = std::min (std::max (p.x, x), x + w); p.y = std::min (std::max (p.y, y), y + h); } //----------------------------------------------------------------------------- template util::point<2,T> util::region::constrained (const point<2,T> &p) const { point<2,T> v; v.x = std::min (std::max (p.x, x), x + w); v.y = std::min (std::max (p.y, y), y + h); return v; } //----------------------------------------------------------------------------- template util::region util::region::intersection (const util::region &rhs) const { T newx1 = max (x, rhs.x), newy1 = max (y, rhs.y), newx2 = min (x + sign_cast (w), rhs.x + sign_cast (rhs.w)), newy2 = min (y + sign_cast (h), rhs.y + sign_cast (rhs.h)); if (newx2 < newx1 || newy2 < newy1) throw std::logic_error ("No overlap"); size_type nw = sign_cast (newx2 - newx1); size_type nh = sign_cast (newy2 - newy1); return util::region (newx1, newy1, nw, nh); } //----------------------------------------------------------------------------- template util::region util::region::inset (T mag) { CHECK_GE (w - x, 2 * mag); CHECK_GE (h - y, 2 * mag); return { x + mag, y + mag, w - 2 * mag, h - 2 * mag }; } //----------------------------------------------------------------------------- template util::region& util::region::expand (T _w, T _h) { x -= _w; y -= _h; w += _w * 2; h += _h * 2; return *this; } //----------------------------------------------------------------------------- template util::region& util::region::expand (T mag) { return expand (mag, mag); } //----------------------------------------------------------------------------- template util::region util::region::expanded (T _w, T _h) const { return { x - _w, y - _h, w + _w * 2, h + _h * 2, }; } //----------------------------------------------------------------------------- template util::region util::region::expanded (T mag) const { return expanded (mag, mag); } //----------------------------------------------------------------------------- template bool util::region::operator== (const region& rhs) const { return almost_equal (x, rhs.x) && almost_equal (y, rhs.y) && almost_equal (w, rhs.w) && almost_equal (h, rhs.h); } //----------------------------------------------------------------------------- template void util::region::sanity (void) const { CHECK_GE (w, 0); CHECK_GE (h, 0); static_assert(!std::is_floating_point::value, "Floating point types need width and height checks"); } //----------------------------------------------------------------------------- namespace util { template <> void region::sanity (void) const { CHECK_GE (w, 0); CHECK_GE (h, 0); } template <> void region::sanity (void) const { CHECK_GE (w, 0); CHECK_GE (h, 0); } } ///---------------------------------------------------------------------------- /// 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::lowest () / 2, std::numeric_limits::max (), std::numeric_limits::max () ); template const util::region util::region::UNIT (0, 0, 1, 1); //----------------------------------------------------------------------------- template std::ostream& util::operator<< (std::ostream &os, const util::region &rhs) { os << "region(" << rhs.x << ", " << rhs.y << ", " << rhs.w << ", " << rhs.h << ")"; return os; } //----------------------------------------------------------------------------- namespace util { template struct region; template struct region; template struct region; template struct region; template std::ostream& operator<< (std::ostream&, const region< int32_t>&); template std::ostream& operator<< (std::ostream&, const region< int64_t>&); template std::ostream& operator<< (std::ostream&, const region&); template std::ostream& operator<< (std::ostream&, const region&); template std::ostream& operator<< (std::ostream&, const region< float>&); template std::ostream& operator<< (std::ostream&, const region< double>&); }