blob: a414076941e0d8967122dc2eebcb70cbe64af25f [file] [edit]
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WLCS_GEOMETRY_RECTANGLE_H_
#define WLCS_GEOMETRY_RECTANGLE_H_
#include "forward.h"
#include "point.h"
#include "size.h"
#include "displacement.h"
#include <ostream>
namespace wlcs
{
namespace generic
{
template<typename T>
struct Rectangle
{
constexpr Rectangle() = default;
constexpr Rectangle(Point<T> const& top_left, Size<T> const& size)
: top_left{top_left}, size{size}
{
}
/**
* The bottom right boundary point of the rectangle.
*
* Note that the returned point is *not* included in the rectangle
* area, that is, the rectangle is represented as [top_left,bottom_right).
*/
Point<T> bottom_right() const
{
return top_left + as_displacement(size);
}
Point<T> top_right() const
{
return top_left + as_delta(size.width);
}
Point<T> bottom_left() const
{
return top_left + as_delta(size.height);
}
bool contains(Point<T> const& p) const
{
if (size.width == decltype(size.width){} || size.height == decltype(size.height){})
return false;
auto br = bottom_right();
return p.x >= left() && p.x < br.x &&
p.y >= top() && p.y < br.y;
}
/**
* Test if the rectangle contains another.
*
* Note that an empty rectangle can still contain other empty rectangles,
* which are treated as points or lines of thickness zero.
*/
bool contains(Rectangle<T> const& r) const
{
return r.left() >= left() &&
r.left() + as_delta(r.size.width) <= left() + as_delta(size.width) &&
r.top() >= top() &&
r.top() + as_delta(r.size.height) <= top() + as_delta(size.height);
}
bool overlaps(Rectangle<T> const& r) const
{
bool disjoint = r.left() >= right()
|| r.right() <= left()
|| r.top() >= bottom()
|| r.bottom() <= top()
|| size.width == decltype(size.width){}
|| size.height == decltype(size.height){}
|| r.size.width == decltype(r.size.width){}
|| r.size.height == decltype(r.size.height){};
return !disjoint;
}
X<T> left() const { return top_left.x; }
X<T> right() const { return bottom_right().x; }
Y<T> top() const { return top_left.y; }
Y<T> bottom() const { return bottom_right().y; }
Point<T> top_left;
Size<T> size;
};
template<typename T>
Rectangle<T> intersection_of(Rectangle<T> const& a, Rectangle<T> const& b)
{
auto const max_left = std::max(a.left(), b.left());
auto const min_right = std::min(a.right(), b.right());
auto const max_top = std::max(a.top(), b.top());
auto const min_bottom = std::min(a.bottom(), b.bottom());
if (max_left < min_right && max_top < min_bottom)
return {{max_left, max_top},
{(min_right - max_left).as_value(),
(min_bottom - max_top).as_value()}};
else
return {};
}
template<typename T>
inline constexpr bool operator == (Rectangle<T> const& lhs, Rectangle<T> const& rhs)
{
return lhs.top_left == rhs.top_left && lhs.size == rhs.size;
}
template<typename T>
inline constexpr bool operator != (Rectangle<T> const& lhs, Rectangle<T> const& rhs)
{
return lhs.top_left != rhs.top_left || lhs.size != rhs.size;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, Rectangle<T> const& value)
{
out << '(' << value.top_left << ", " << value.size << ')';
return out;
}
}
}
#endif // WLCS_GEOMETRY_RECTANGLE_H_