/* * 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 Danny Robson */ #include "region.hpp" #include "debug.hpp" #include "types/casts.hpp" #include #include //----------------------------------------------------------------------------- using namespace util; //----------------------------------------------------------------------------- template region::region (T _x, T _y, size_type _w, size_type _h): x (_x), y (_y), w (_w), h (_h) { DEBUG_ONLY (sanity ()); } template region& region::operator+= (const vector<2> &rhs) { x += rhs.x; y += rhs.y; return *this; } //----------------------------------------------------------------------------- template typename region::size_type region::area (void) const { return w * h; } template typename region::size_type region::diameter (void) const { return static_cast (sqrt (w * w + h * h)); } template void region::scale (double factor) { x -= (w * factor - w) / 2.0; y -= (h * factor - h) / 2.0; w *= factor; h *= factor; } template bool region::empty (void) const { return almost_equal (area (), 0); } //----------------------------------------------------------------------------- template point<2> region::base (void) const { return { static_cast (x), static_cast (y) }; } template point<2> region::centre (void) const { double cx = x + static_cast(w / 2.0), cy = y + static_cast(h / 2.0); return { cx, cy }; } template point<2> region::closest (point<2> 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 region::includes (const point<2> &p) const { return p.x >= x && p.y >= y && p.x - x <= w && p.y - y <= h; } template bool region::contains (const point<2> &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 region::overlaps (const region &rhs) const { return x < rhs.x + rhs.w && rhs.x < x + w && y < rhs.y + rhs.h && rhs.y < y + h; } //----------------------------------------------------------------------------- template void region::constrain (point2 &p) const { p.x = std::min (std::max (static_cast (p.x), x), x + w); p.y = std::min (std::max (static_cast (p.y), y), y + h); } template point2 region::constrained (const point2 &p) const { point2 v; v.x = std::min (std::max (static_cast (p.x), x), x + w); v.y = std::min (std::max (static_cast (p.y), y), y + h); return v; } //----------------------------------------------------------------------------- template region region::overlap (const 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 region (newx1, newy1, nw, nh); } //----------------------------------------------------------------------------- template bool 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 region::sanity (void) const { CHECK_SOFT (w > 0); CHECK_SOFT (h > 0); static_assert(!std::is_floating_point::value, "Floating point types need width and height checks"); } //----------------------------------------------------------------------------- // The desired iterator semantics have been difficult to nail down; is it // edge-inclusive, left-bottom inclusive, purely exclusive, integral only? // The code has been left here because it was a little annoying to write and // we're likely to need it again some day. #if 0 template typename region::iterator& region::iterator::operator++ (void) { if (++x > static_cast (w)) { x = a; ++y; } return *this; } template typename region::iterator& region::iterator::operator* (void) { return *this; } template bool region::iterator::operator== (const iterator &rhs) const { return almost_equal (rhs.x, x) && almost_equal (rhs.y, y); } template bool region::iterator::operator!= (const iterator &rhs) const { return !(*this == rhs); } template typename region::iterator region::begin (void) { return { x, y, x, w, h }; } template typename region::iterator region::end (void) { return { x, y + sign_cast (h) + 1, x, w, h }; } #endif namespace util { template <> void region::sanity (void) const { CHECK (w >= 0 && h >= 0); } template <> void region::sanity (void) const { CHECK (w >= 0 && h >= 0); } } //----------------------------------------------------------------------------- template const region region::MAX (std::numeric_limits::lowest (), std::numeric_limits::lowest (), std::numeric_limits::has_infinity ? std::numeric_limits::infinity () : std::numeric_limits::max (), std::numeric_limits::has_infinity ? std::numeric_limits::infinity () : std::numeric_limits::max ()); template const region region::UNIT (0, 0, 1, 1); //----------------------------------------------------------------------------- template std::ostream& util::operator<< (std::ostream &os, const 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 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< double>&); }