// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef PXR_BASE_GF_RECT2I_H #define PXR_BASE_GF_RECT2I_H /// \file gf/rect2i.h /// \ingroup group_gf_LinearAlgebra #include "pxr/pxr.h" #include "pxr/base/gf/math.h" #include "pxr/base/gf/vec2i.h" #include "pxr/base/gf/api.h" #include #include PXR_NAMESPACE_OPEN_SCOPE /// \class GfRect2i /// \ingroup group_gf_LinearAlgebra /// /// A 2D rectangle with integer coordinates for windowing operations. /// /// A rectangle is internally represented as an upper left corner and a /// bottom right corner, but it is normally expressed as an upper left /// corner and a size. /// /// Note that the size (width and height) of a rectangle might be /// different from what you are used to. If the top left corner and the /// bottom right corner are the same, then the height and the width of /// the rectangle will both be one. /// /// Specifically, width = right - left + 1 and /// height = bottom - top + 1. The design corresponds to /// rectangular spaces used by drawing functions, where /// the width and height denote a number of pixels. For example, /// drawing a rectangle with width and height one draws a single pixel. /// /// The default coordinate system has origin (0,0) in the top left /// corner, the positive direction of the y axis is downward and the /// positive x axis is to the right. /// class GfRect2i { public: /// Constructs an empty rectangle. GfRect2i(): _lower(0,0), _higher(-1,-1) { } /// Constructs a rectangle with \p topLeft as the top left corner and \p /// bottomRight as the bottom right corner. GfRect2i(const GfVec2i& topLeft, const GfVec2i& bottomRight) : _lower(topLeft), _higher(bottomRight) { } /// Constructs a rectangle with \p topLeft as the top left corner and with /// the indicated width and height. GfRect2i(const GfVec2i& topLeft, int width, int height) : _lower(topLeft), _higher(topLeft + GfVec2i(width-1, height-1)) { } /// Returns true if the rectangle is a null rectangle. /// /// A null rectangle has both the width and the height set to 0, that is /// \code /// GetRight() == GetLeft() - 1 /// \endcode /// and /// \code /// GetBottom() == GetTop() - 1 /// \endcode /// Remember that if \c GetRight() and \c GetLeft() return the same value /// then the rectangle has width 1, and similarly for the height. /// /// A null rectangle is both empty, and not valid. bool IsNull() const { return GetWidth() == 0 && GetHeight() == 0; } /// Returns true if the rectangle is empty. /// /// An empty rectangle has its left side strictly greater than its right /// side or its top strictly greater than its bottom. /// /// An empty rectangle is not valid. bool IsEmpty() const { return GetWidth() <= 0 || GetHeight() <= 0; } /// Return true if the rectangle is valid (equivalently, not empty). bool IsValid() const { return !IsEmpty(); } /// Returns a normalized rectangle, i.e. one that has a non-negative width /// and height. /// /// \c GetNormalized() swaps left and right to ensure a non-negative /// width, and similarly for top and bottom. GF_API GfRect2i GetNormalized() const; /// Returns the lower corner of the rectangle. const GfVec2i& GetLower() const { return _lower; } /// Returns the upper corner of the rectangle. const GfVec2i& GetHigher() const { return _higher; } /// Return the X value of the left edge. int GetLeft() const { return _lower[0]; } /// Set the X value of the left edge. void SetLeft(int x) { _lower[0] = x; } /// Return the X value of the right edge. int GetRight() const { return _higher[0]; } /// Set the X value of the right edge. void SetRight(int x) { _higher[0] = x; } /// Return the Y value of the top edge. int GetTop() const { return _lower[1]; } /// Set the Y value of the top edge. void SetTop(int y) { _lower[1] = y; } /// Return the Y value of the bottom edge. int GetBottom() const { return _higher[1]; } /// Set the Y value of the bottom edge. void SetBottom(int y) { _higher[1] = y; } /// Sets the lower corner of the rectangle. void SetLower(const GfVec2i& lower) { _lower = lower; } /// Sets the upper corner of the rectangle. void SetHigher(const GfVec2i& higher) { _higher = higher; } /// Returns the center point of the rectangle. GfVec2i GetCenter() const { return (_lower + _higher) / 2; } /// Move the rectangle by \p displ. void Translate(const GfVec2i& displacement) { _lower += displacement; _higher += displacement; } /// Return the area of the rectangle. unsigned long GetArea() const { return (unsigned long)GetWidth() * (unsigned long)GetHeight(); } /// Returns the size of the rectangle as a vector (width,height). GfVec2i GetSize() const { return GfVec2i(GetWidth(), GetHeight()); } /// Returns the width of the rectangle. /// /// \note If the left and right sides are coincident, the width is one. int GetWidth() const { return (_higher[0] - _lower[0]) + 1; } /// Returns the height of the rectangle. /// /// \note If the top and bottom sides are coincident, the height is one. int GetHeight() const { return (_higher[1] - _lower[1]) + 1; } /// Computes the intersection of two rectangles. GfRect2i GetIntersection(const GfRect2i& that) const { if(IsEmpty()) return *this; else if(that.IsEmpty()) return that; else return GfRect2i(GfVec2i(GfMax(_lower[0], that._lower[0]), GfMax(_lower[1], that._lower[1])), GfVec2i(GfMin(_higher[0], that._higher[0]), GfMin(_higher[1], that._higher[1]))); } /// Computes the intersection of two rectangles. /// \deprecated Use GetIntersection() instead GfRect2i Intersect(const GfRect2i& that) const { return GetIntersection(that); } /// Computes the union of two rectangles. GfRect2i GetUnion(const GfRect2i& that) const { if(IsEmpty()) return that; else if(that.IsEmpty()) return *this; else return GfRect2i(GfVec2i(GfMin(_lower[0], that._lower[0]), GfMin(_lower[1], that._lower[1])), GfVec2i(GfMax(_higher[0], that._higher[0]), GfMax(_higher[1], that._higher[1]))); } /// Computes the union of two rectangles /// \deprecated Use GetUnion() instead. GfRect2i Union(const GfRect2i& that) const { return GetUnion(that); } /// Returns true if the specified point in the rectangle. bool Contains(const GfVec2i& p) const { return ((p[0] >= _lower[0]) && (p[0] <= _higher[0]) && (p[1] >= _lower[1]) && (p[1] <= _higher[1])); } friend inline size_t hash_value(const GfRect2i &r) { size_t h = 0; boost::hash_combine(h, r._lower); boost::hash_combine(h, r._higher); return h; } /// Returns true if \p r1 and \p r2 are equal. friend bool operator==(const GfRect2i& r1, const GfRect2i& r2) { return r1._lower == r2._lower && r1._higher == r2._higher; } /// Returns true if \p r1 and \p r2 are different. friend bool operator!=(const GfRect2i& r1, const GfRect2i& r2) { return !(r1 == r2); } /// Computes the union of two rectangles. /// \see GetUnion() GfRect2i operator += (const GfRect2i& that) { *this = GetUnion(that); return *this; } friend GfRect2i operator + (const GfRect2i r1, const GfRect2i& r2) { GfRect2i tmp(r1); tmp += r2; return tmp; } private: GfVec2i _lower, _higher; }; /// Output a GfRect2i using the format [(x y):(x y)]. /// \ingroup group_gf_DebuggingOutput GF_API std::ostream& operator<<(std::ostream&, const GfRect2i&); PXR_NAMESPACE_CLOSE_SCOPE #endif