40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński/**
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * \file
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * \brief Axis-aligned rectangle
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *//*
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Authors:
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Michael Sloan <mgsloan@gmail.com>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Krzysztof Kosiński <tweenk.pl@gmail.com>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Copyright 2007-2011 Authors
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * This library is free software; you can redistribute it and/or
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * modify it either under the terms of the GNU Lesser General Public
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * License version 2.1 as published by the Free Software Foundation
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * (the "LGPL") or, at your option, under the terms of the Mozilla
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Public License Version 1.1 (the "MPL"). If you do not alter this
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * notice, a recipient may use your version of this file under either
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * the MPL or the LGPL.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * You should have received a copy of the LGPL along with this library
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * in the file COPYING-LGPL-2.1; if not, output to the Free Software
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * You should have received a copy of the MPL along with this library
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * in the file COPYING-MPL-1.1
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * The contents of this file are subject to the Mozilla Public License
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Version 1.1 (the "License"); you may not use this file except in
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * compliance with the License. You may obtain a copy of the License at
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * http://www.mozilla.org/MPL/
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * OF ANY KIND, either express or implied. See the LGPL or the MPL for
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * the specific language governing rights and limitations.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Authors of original rect class:
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Lauris Kaplinski <lauris@kaplinski.com>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Nathan Hurst <njh@mail.csse.monash.edu.au>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * bulia byak <buliabyak@users.sf.net>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * MenTaLguY <mental@rydia.net>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński#ifndef LIB2GEOM_SEEN_GENERIC_RECT_H
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński#define LIB2GEOM_SEEN_GENERIC_RECT_H
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński#include <limits>
b63c6af7aa7f869de42730cf0ffd8b6077d778c5Krzysztof Kosiński#include <iostream>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński#include <boost/optional.hpp>
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński#include <2geom/coord.h>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskinamespace Geom {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskitemplate <typename C>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiclass GenericOptRect;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński/**
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @brief Axis aligned, non-empty, generic rectangle.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @ingroup Primitives
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskitemplate <typename C>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiclass GenericRect
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński : CoordTraits<C>::RectOps
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński{
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::IntervalType CInterval;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::PointType CPoint;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::RectType CRect;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::OptRectType OptCRect;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiprotected:
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński CInterval f[2];
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskipublic:
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński typedef CInterval D1Value;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński typedef CInterval &D1Reference;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński typedef CInterval const &D1ConstReference;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @name Create rectangles.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @{
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Create a rectangle that contains only the point at (0,0). */
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński GenericRect() { f[X] = f[Y] = CInterval(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Create a rectangle from X and Y intervals. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericRect(CInterval const &a, CInterval const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[X] = a;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[Y] = b;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Create a rectangle from two points. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericRect(CPoint const &a, CPoint const &b) {
827bc501341bcc5c344c0422f13422bc368151b4Krzysztof Kosiński f[X] = CInterval(a[X], b[X]);
827bc501341bcc5c344c0422f13422bc368151b4Krzysztof Kosiński f[Y] = CInterval(a[Y], b[Y]);
827bc501341bcc5c344c0422f13422bc368151b4Krzysztof Kosiński }
827bc501341bcc5c344c0422f13422bc368151b4Krzysztof Kosiński /** @brief Create rectangle from coordinates of two points. */
827bc501341bcc5c344c0422f13422bc368151b4Krzysztof Kosiński GenericRect(C x0, C y0, C x1, C y1) {
827bc501341bcc5c344c0422f13422bc368151b4Krzysztof Kosiński f[X] = CInterval(x0, x1);
827bc501341bcc5c344c0422f13422bc368151b4Krzysztof Kosiński f[Y] = CInterval(y0, y1);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Create a rectangle from a range of points.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * The resulting rectangle will contain all ponts from the range.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * The return type of iterators must be convertible to Point.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * The range must not be empty. For possibly empty ranges, see OptRect.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @param start Beginning of the range
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @param end End of the range
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @return Rectangle that contains all points from [start, end). */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński template <typename InputIterator>
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński static CRect from_range(InputIterator start, InputIterator end) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński assert(start != end);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński CPoint p1 = *start++;
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński CRect result(p1, p1);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński for (; start != end; ++start) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński result.expandTo(*start);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return result;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Create a rectangle from a C-style array of points it should contain. */
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński static CRect from_array(CPoint const *c, unsigned n) {
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński CRect result = GenericRect<C>::from_range(c, c+n);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return result;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński /** @brief Create rectangle from origin and dimensions. */
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński static CRect from_xywh(C x, C y, C w, C h) {
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński CPoint xy(x, y);
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński CPoint wh(w, h);
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński CRect result(xy, xy + wh);
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński return result;
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński }
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński /** @brief Create rectangle from origin and dimensions. */
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński static CRect from_xywh(CPoint const &xy, CPoint const &wh) {
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński CRect result(xy, xy + wh);
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński return result;
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński }
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński /// Create infinite rectangle.
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński static CRect infinite() {
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński CPoint p0(std::numeric_limits<C>::min(), std::numeric_limits<C>::min());
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński CPoint p1(std::numeric_limits<C>::max(), std::numeric_limits<C>::max());
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński CRect result(p0, p1);
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński return result;
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @name Inspect dimensions.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @{
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński CInterval &operator[](unsigned i) { return f[i]; }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński CInterval const &operator[](unsigned i) const { return f[i]; }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński CInterval &operator[](Dim2 d) { return f[d]; }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński CInterval const &operator[](Dim2 d) const { return f[d]; }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Get the corner of the rectangle with smallest coordinate values.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * In 2Geom standard coordinate system, this means upper left. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski CPoint min() const { CPoint p(f[X].min(), f[Y].min()); return p; }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Get the corner of the rectangle with largest coordinate values.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * In 2Geom standard coordinate system, this means lower right. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski CPoint max() const { CPoint p(f[X].max(), f[Y].max()); return p; }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Return the n-th corner of the rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Returns corners in the direction of growing angles, starting from
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * the one given by min(). For the standard coordinate system used
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * in 2Geom (+Y downwards), this means clockwise starting from
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * the upper left. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński CPoint corner(unsigned i) const {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński switch(i % 4) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński case 0: return CPoint(f[X].min(), f[Y].min());
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński case 1: return CPoint(f[X].max(), f[Y].min());
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński case 2: return CPoint(f[X].max(), f[Y].max());
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński default: return CPoint(f[X].min(), f[Y].max());
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński //We should probably remove these - they're coord sys gnostic
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Return top coordinate of the rectangle (+Y is downwards). */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C top() const { return f[Y].min(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Return bottom coordinate of the rectangle (+Y is downwards). */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C bottom() const { return f[Y].max(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Return leftmost coordinate of the rectangle (+X is to the right). */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C left() const { return f[X].min(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Return rightmost coordinate of the rectangle (+X is to the right). */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C right() const { return f[X].max(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Get the horizontal extent of the rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C width() const { return f[X].extent(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Get the vertical extent of the rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C height() const { return f[Y].extent(); }
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński /** @brief Get the ratio of width to height of the rectangle. */
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński Coord aspectRatio() const { return Coord(width()) / Coord(height()); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Get rectangle's width and height as a point.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @return Point with X coordinate corresponding to the width and the Y coordinate
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * corresponding to the height of the rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński CPoint dimensions() const { return CPoint(f[X].extent(), f[Y].extent()); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Get the point in the geometric center of the rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński CPoint midpoint() const { return CPoint(f[X].middle(), f[Y].middle()); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Compute rectangle's area. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C area() const { return f[X].extent() * f[Y].extent(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Check whether the rectangle has zero area. */
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński bool hasZeroArea() const { return f[X].isSingular() || f[Y].isSingular(); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Get the larger extent (width or height) of the rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C maxExtent() const { return std::max(f[X].extent(), f[Y].extent()); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Get the smaller extent (width or height) of the rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński C minExtent() const { return std::min(f[X].extent(), f[Y].extent()); }
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński /** @brief Clamp point to the rectangle. */
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński CPoint clamp(CPoint const &p) const {
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński CPoint result(f[X].clamp(p[X]), f[Y].clamp(p[Y]));
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński return result;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński }
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński /** @brief Get the nearest point on the edge of the rectangle. */
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński CPoint nearestEdgePoint(CPoint const &p) const {
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński CPoint result = p;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński if (!contains(p)) {
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński result = clamp(p);
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński } else {
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński C cx = f[X].nearestEnd(p[X]);
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński C cy = f[Y].nearestEnd(p[Y]);
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński if (std::abs(cx - p[X]) <= std::abs(cy - p[Y])) {
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński result[X] = cx;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński } else {
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński result[Y] = cy;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński }
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński }
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński return result;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @name Test other rectangles and points for inclusion.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @{
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Check whether the rectangles have any common points. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool intersects(GenericRect<C> const &r) const {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return f[X].intersects(r[X]) && f[Y].intersects(r[Y]);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Check whether the rectangle includes all points in the given rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool contains(GenericRect<C> const &r) const {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return f[X].contains(r[X]) && f[Y].contains(r[Y]);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Check whether the rectangles have any common points.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Empty rectangles will not intersect with any other rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński inline bool intersects(OptCRect const &r) const;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Check whether the rectangle includes all points in the given rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Empty rectangles will be contained in any non-empty rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński inline bool contains(OptCRect const &r) const;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Check whether the given point is within the rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool contains(CPoint const &p) const {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return f[X].contains(p[X]) && f[Y].contains(p[Y]);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @name Modify the rectangle.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @{
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen /** @brief Set the minimum X coordinate of the rectangle. */
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen void setLeft(C val) {
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen f[X].setMin(val);
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen }
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen /** @brief Set the maximum X coordinate of the rectangle. */
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen void setRight(C val) {
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen f[X].setMax(val);
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen }
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen /** @brief Set the minimum Y coordinate of the rectangle. */
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen void setTop(C val) {
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen f[Y].setMin(val);
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen }
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen /** @brief Set the maximum Y coordinate of the rectangle. */
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen void setBottom(C val) {
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen f[Y].setMax(val);
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen }
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński /** @brief Set the upper left point of the rectangle. */
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński void setMin(CPoint const &p) {
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński f[X].setMin(p[X]);
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński f[Y].setMin(p[Y]);
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński }
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński /** @brief Set the lower right point of the rectangle. */
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński void setMax(CPoint const &p) {
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński f[X].setMax(p[X]);
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński f[Y].setMax(p[Y]);
ef494f75ca77f36881ad59e94263a07c146c3649Krzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Enlarge the rectangle to contain the given point. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński void expandTo(CPoint const &p) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[X].expandTo(p[X]); f[Y].expandTo(p[Y]);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Enlarge the rectangle to contain the argument. */
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński void unionWith(CRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[X].unionWith(b[X]); f[Y].unionWith(b[Y]);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Enlarge the rectangle to contain the argument.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Unioning with an empty rectangle results in no changes. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński void unionWith(OptCRect const &b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Expand the rectangle in both directions by the specified amount.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * Note that this is different from scaling. Negative values wil shrink the
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * rectangle. If <code>-amount</code> is larger than
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * half of the width, the X interval will contain only the X coordinate
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * of the midpoint; same for height. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński void expandBy(C amount) {
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski expandBy(amount, amount);
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski }
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski /** @brief Expand the rectangle in both directions.
c8589a6c7367d09fa756755cef0dd448c7328a71Johan B. C. Engelen * Note that this is different from scaling. Negative values wil shrink the
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * rectangle. If <code>-x</code> is larger than
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * half of the width, the X interval will contain only the X coordinate
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * of the midpoint; same for height. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski void expandBy(C x, C y) {
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski f[X].expandBy(x); f[Y].expandBy(y);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Expand the rectangle by the coordinates of the given point.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * This will expand the width by the X coordinate of the point in both directions
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * and the height by Y coordinate of the point. Negative coordinate values will
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * shrink the rectangle. If <code>-p[X]</code> is larger than half of the width,
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * the X interval will contain only the X coordinate of the midpoint;
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * same for height. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski void expandBy(CPoint const &p) {
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski expandBy(p[X], p[Y]);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @name Operators
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @{
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Offset the rectangle by a vector. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericRect<C> &operator+=(CPoint const &p) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[X] += p[X];
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[Y] += p[Y];
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return *this;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Offset the rectangle by the negation of a vector. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericRect<C> &operator-=(CPoint const &p) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[X] -= p[X];
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński f[Y] -= p[Y];
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return *this;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Union two rectangles. */
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński GenericRect<C> &operator|=(CRect const &o) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński unionWith(o);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return *this;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericRect<C> &operator|=(OptCRect const &o) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński unionWith(o);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return *this;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Test for equality of rectangles. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski bool operator==(CRect const &o) const { return f[X] == o[X] && f[Y] == o[Y]; }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński};
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński/**
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @brief Axis-aligned generic rectangle that can be empty.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * @ingroup Primitives
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskitemplate <typename C>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiclass GenericOptRect
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński : public boost::optional<typename CoordTraits<C>::RectType>
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski , boost::equality_comparable< typename CoordTraits<C>::OptRectType
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski , boost::equality_comparable< typename CoordTraits<C>::OptRectType, typename CoordTraits<C>::RectType
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński , boost::orable< typename CoordTraits<C>::OptRectType
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński , boost::andable< typename CoordTraits<C>::OptRectType
d6519bf53baba32bd74436ad9c85f1fa2c6b6ae9Krzysztof Kosiński , boost::andable< typename CoordTraits<C>::OptRectType, typename CoordTraits<C>::RectType
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski > > > > >
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński{
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::IntervalType CInterval;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::OptIntervalType OptCInterval;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::PointType CPoint;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::RectType CRect;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef typename CoordTraits<C>::OptRectType OptCRect;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński typedef boost::optional<CRect> Base;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskipublic:
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński typedef CInterval D1Value;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński typedef CInterval &D1Reference;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński typedef CInterval const &D1ConstReference;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @name Create potentially empty rectangles.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @{
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericOptRect() : Base() {}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericOptRect(GenericRect<C> const &a) : Base(CRect(a)) {}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericOptRect(CPoint const &a, CPoint const &b) : Base(CRect(a, b)) {}
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski GenericOptRect(C x0, C y0, C x1, C y1) : Base(CRect(x0, y0, x1, y1)) {}
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// Creates an empty OptRect when one of the argument intervals is empty.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericOptRect(OptCInterval const &x_int, OptCInterval const &y_int) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński if (x_int && y_int) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *this = CRect(*x_int, *y_int);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński // else, stay empty.
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Create a rectangle from a range of points.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * The resulting rectangle will contain all ponts from the range.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * If the range contains no points, the result will be an empty rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * The return type of iterators must be convertible to the corresponding
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * point type (Point or IntPoint).
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * @param start Beginning of the range
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * @param end End of the range
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * @return Rectangle that contains all points from [start, end). */
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński template <typename InputIterator>
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński static OptCRect from_range(InputIterator start, InputIterator end) {
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński OptCRect result;
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński for (; start != end; ++start) {
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński result.expandTo(*start);
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński return result;
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @name Check other rectangles and points for inclusion.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @{
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński /** @brief Check for emptiness. */
a16a494f042310ee849a6f717ffea70846f1f22cKrzysztof Kosiński inline bool empty() const { return !*this; };
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Check whether the rectangles have any common points.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Empty rectangles will not intersect with any other rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool intersects(CRect const &r) const { return r.intersects(*this); }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Check whether the rectangle includes all points in the given rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Empty rectangles will be contained in any non-empty rectangle. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool contains(CRect const &r) const { return *this && (*this)->contains(r); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Check whether the rectangles have any common points.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Empty rectangles will not intersect with any other rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Two empty rectangles will not intersect each other. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool intersects(OptCRect const &r) const { return *this && (*this)->intersects(r); }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Check whether the rectangle includes all points in the given rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Empty rectangles will be contained in any non-empty rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * An empty rectangle will not contain other empty rectangles. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool contains(OptCRect const &r) const { return *this && (*this)->contains(r); }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Check whether the given point is within the rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * An empty rectangle will not contain any points. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński bool contains(CPoint const &p) const { return *this && (*this)->contains(p); }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @name Modify the potentially empty rectangle.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @{
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Enlarge the rectangle to contain the argument.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * If this rectangle is empty, after callng this method it will
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * be equal to the argument. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński void unionWith(CRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński if (*this) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński (*this)->unionWith(b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński } else {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *this = b;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Enlarge the rectangle to contain the argument.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * Unioning with an empty rectangle results in no changes.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * If this rectangle is empty, after calling this method it will
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * be equal to the argument. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński void unionWith(OptCRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński if (b) unionWith(*b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Leave only the area overlapping with the argument.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * If the rectangles do not have any points in common, after calling
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * this method the rectangle will be empty. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński void intersectWith(CRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński if (!*this) return;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński OptCInterval x = (**this)[X] & b[X], y = (**this)[Y] & b[Y];
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński if (x && y) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *this = CRect(*x, *y);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński } else {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *(static_cast<Base*>(this)) = boost::none;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Leave only the area overlapping with the argument.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * If the argument is empty or the rectangles do not have any points
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * in common, after calling this method the rectangle will be empty. */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński void intersectWith(OptCRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński if (b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński intersectWith(*b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński } else {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński *(static_cast<Base*>(this)) = boost::none;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Create or enlarge the rectangle to contain the given point.
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * If the rectangle is empty, after calling this method it will be non-empty
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński * and it will contain only the given point. */
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński void expandTo(CPoint const &p) {
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński if (*this) {
f8636873701abf3499cb186e37375ba3d271618cJohan Engelen (*this)->expandTo(p);
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński } else {
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński *this = CRect(p, p);
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @}
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @name Operators
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @{
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Union with @a b */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericOptRect<C> &operator|=(OptCRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński unionWith(b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return *this;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Intersect with @a b */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericOptRect<C> &operator&=(CRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński intersectWith(b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return *this;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /** @brief Intersect with @a b */
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński GenericOptRect<C> &operator&=(OptCRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński intersectWith(b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return *this;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski /** @brief Test for equality.
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski * All empty rectangles are equal. */
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski bool operator==(OptCRect const &other) const {
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski if (!*this != !other) return false;
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski return *this ? (**this == *other) : true;
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski }
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski bool operator==(CRect const &other) const {
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski if (!*this) return false;
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski return **this == other;
7bda77e763c0af49270427593108b66455dfd125Krzysztof Kosinski }
d1bde559850436556ebee2e70e10f1cfc8aff636Krzysztof Kosiński /// @}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński};
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskitemplate <typename C>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiinline void GenericRect<C>::unionWith(OptCRect const &b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński if (b) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński unionWith(*b);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński }
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskitemplate <typename C>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiinline bool GenericRect<C>::intersects(OptCRect const &r) const {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return r && intersects(*r);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskitemplate <typename C>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiinline bool GenericRect<C>::contains(OptCRect const &r) const {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return !r || contains(*r);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskitemplate <typename C>
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosińskiinline std::ostream &operator<<(std::ostream &out, GenericRect<C> const &r) {
b63c6af7aa7f869de42730cf0ffd8b6077d778c5Krzysztof Kosiński out << "Rect " << r[X] << " x " << r[Y];
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński return out;
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński}
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński} // end namespace Geom
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński#endif // LIB2GEOM_SEEN_RECT_H
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński/*
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński Local Variables:
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński mode:c++
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński c-file-style:"stroustrup"
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński indent-tabs-mode:nil
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński fill-column:99
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński End:
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński*/
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :