//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1992, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Classes for window system geometry
//----------------------------------------------------------------------------
 
#if !defined(OWL_GEOMETRY_H)
#define OWL_GEOMETRY_H
 
#include <owl/private/defs.h>
#if defined(BI_HAS_PRAGMA_ONCE)
# pragma once
#endif
 
#if !defined(UNIX)
#if !defined(OWL_OBJSTRM_H)
# include <owl/objstrm.h>    // Need persist streaming classes & operators
#endif
#endif
 
#include <owl/private/strmdefs.h>
#include <algorithm>
#include <vector>
#include <array>
#include <utility> // swap
#include <type_traits> // is_same_v
#include <cstddef> // offsetof
#include <cmath> // lround
 
namespace owl {
 
//
// Forward declare some of the classes defined in this file
//
class _OWLCLASS TSize;
class _OWLCLASS TRect;
 
//
// Integer square root for area calculations. Is fairly fast.
//
_OWLFUNC(int16)  Sqrt(int32 val);
_OWLFUNC(int)  Sqrt(int64 val);
 
} // OWL namespace
 
//
// Get base window system geometry structs compatible with MSW
//
#include <owl/wsysinc.h>
 
namespace owl {
 
/// \cond NoSuppressDoxygenWarning
#include <owl/preclass.h>
/// \endcond
 
/// \addtogroup graphics_group
/// @{
 
/// General use absolute 2-D rectangular location enum
//
/// TAbsLocation contains general-use absolute two-dimensional rectangular
/// locations. It is used primarily to describe the locations of a gadget window,
/// such as a toolbar or a status bar, within a decorated frame.
//
enum TAbsLocation {
  alNone   = 0,          ///< No location specified
  alTop    = 1,          ///< Refers to top edge of frame
  alBottom = 2,          ///< Refers to bottom edge of frame
  alLeft   = 3,          ///< Refers to left edge of frame
  alRight  = 4,          ///< Refers to right edge of frame
};
 
//
/// \class TPoint
// ~~~~~ ~~~~~~
/// TPoint is a support class, derived from tagPOINT. The tagPOINT struct is defined
/// as
/// \code
/// struct tagPOINT {
///    int x;
///    int y;
/// };
/// \endcode
/// TPoint encapsulates the notion of a two-dimensional point that usually
/// represents a screen position. TPoint inherits two data members, the coordinates
/// x and y, from tagPOINT. Member functions and operators are provided for
/// comparing, assigning, and manipulating points. Overloaded << and >> operators
/// allow chained insertion and extraction of TPoint objects with streams.
//
class _OWLCLASS TPoint : public tagPOINT {
  public:
    // Constructors
    //
    TPoint();
    TPoint(int _x, int _y);
    TPoint(const tagPOINT & point);
    TPoint(const TPoint & point);
    TPoint(const tagSIZE & size);
 
#if defined(OWL5_COMPAT)
 
    [[deprecated]] explicit TPoint(LPARAM packedPoint);
 
#endif
 
    /// \name Factory functions
    /// \{
 
    static auto CreateFromPackedCoordinates(LPARAM packedPoint) -> TPoint;
 
    /// \}
 
    // Information functions/operators
    //
    bool        operator ==(const TPoint& other) const;
    bool        operator !=(const TPoint& other) const;
    int         X() const;
    int         Y() const;
    int         Magnitude() const;
 
    // Functions/binary-operators that return points or sizes
    //
    TPoint      OffsetBy(int dx, int dy) const;
    TPoint      operator +(const TSize& size) const;
    TSize       operator -(const TPoint& point) const;
    TPoint      operator -(const TSize& size) const;
    TPoint      operator -() const;
 
    // Functions/assignement-operators that modify this point
    //
    TPoint&     Offset(int dx, int dy);
    TPoint&     operator +=(const TSize& size);
    TPoint&     operator -=(const TSize& size);
};
 
_OWLCFUNC(ipstream&) operator >>(ipstream& is, TPoint& p);
_OWLCFUNC(tistream&)  operator >>(tistream& is, TPoint& p);
_OWLCFUNC(opstream&) operator <<(opstream& os, const TPoint& p);
_OWLCFUNC(tostream&)  operator <<(tostream& os, const TPoint& p);
 
//
/// \class TPointL
// ~~~~~ ~~~~~~~
/// TPointL is similar to TPoint, but uses long rather than int variables.
/// \todo Do we really need this? Isn't long same as int for 32-bit? What about 64-bit?
//
class _OWLCLASS TPointL : public POINTL {
  public:
    // Constructors
    //
    TPointL();
    TPointL(long _x, long _y);
    TPointL(const POINTL & point);
    TPointL(const TPointL & point);
 
    // Information functions/operators
    //
    bool        operator ==(const TPointL& other) const;
    bool        operator !=(const TPointL& other) const;
    long        X() const;
    long        Y() const;
 
    // Functions/binary-operators that return points or sizes
    //
    TPointL     OffsetBy(long dx, long dy) const;
    TPointL     operator +(const TSize& size) const;
    TPointL     operator -(const TPointL& point) const;
    TPointL     operator -(const TSize& size) const;
    TPointL     operator -() const;
 
    // Functions/assignement-operators that modify this point
    //
    TPointL&    Offset(long dx, long dy);
    TPointL&    operator +=(const TSize& size);
    TPointL&    operator -=(const TSize& size);
};
 
_OWLCFUNC(ipstream&) operator >>(ipstream& is, TPointL& p);
_OWLCFUNC(tistream&)  operator >>(tistream& is, TPointL& p);
_OWLCFUNC(opstream&) operator <<(opstream& os, const TPointL& p);
_OWLCFUNC(tostream&)  operator <<(tostream& os, const TPointL& p);
 
//
/// Base struct for the TPointF class
//
struct tPOINTF {
  float x;
  float y;
};
 
//
/// \class TPointF
// ~~~~~ ~~~~~~~
/// TPointF is similar to TPoint, but uses floating variables rather than integers.
//
class _OWLCLASS TPointF : public tPOINTF {
  public:
    // Constructors
    //
    TPointF();
    TPointF(float _x, float _y);
//    TPointF(const tagPOINTF & point) {x = point.x; y = point.y;}
    TPointF(const TPointF & point);
 
    // Information functions/operators
    //
    bool        operator ==(const TPointF& other) const;
    bool        operator !=(const TPointF& other) const;
    float       X() const;
    float       Y() const;
 
    // Functions/binary-operators that return points or sizes
    //
    TPointF     OffsetBy(float dx, float dy) const;
    TPointF     operator +(const TPointF& size) const;
    TPointF     operator -(const TPointF& point) const;
    TPointF     operator -() const;
 
    // Functions/assignement-operators that modify this point
    //
    TPointF&    Offset(float dx, float dy);
    TPointF&    operator +=(const TPointF& size);
    TPointF&    operator -=(const TPointF& size);
};
 
_OWLCFUNC(ipstream&) operator >>(ipstream& is, TPointF& p);
_OWLCFUNC(tistream&) operator >>(tistream& is, TPointF& p);
_OWLCFUNC(opstream&) operator <<(opstream& os, const TPointF& p);
_OWLCFUNC(tostream&) operator <<(tostream& os, const TPointF& p);
 
//
/// \class TSize
// ~~~~~ ~~~~~
/// The tagSIZE  struct is defined as
/// \code
/// struct tagSIZE {
///    int cx;
///    int cy;
/// };
/// \endcode
/// TSize encapsulates the notion of a two-dimensional quantity that usually
/// represents a displacement or the height and width of a rectangle. TSize inherits
/// the two data members cx and cy from tagSIZE. Member functions and operators are
/// provided for comparing, assigning, and manipulating sizes. Overloaded << and >>
/// operators allow chained insertion and extraction of TSize objects with streams.
//
// !CQ look at phasing out this class & using only TPoint
//
class _OWLCLASS TSize : public tagSIZE {
  public:
    // Constructors
    //
    TSize();
    TSize(int dx, int dy);
    TSize(const tagPOINT & point);
    TSize(const tagSIZE & size);
    TSize(const TSize & size);
 
#if defined(OWL5_COMPAT)
 
    [[deprecated]] explicit TSize(DWORD packedExtents);
 
#endif
 
    /// \name Factory functions
    /// \{
    
    static auto CreateFromPackedExtents(LPARAM packedExtents) -> TSize;
    static auto Square(int side) -> TSize;
 
    /// \}
 
    // Information functions/operators
    //
    bool        operator ==(const TSize& other) const;
    bool        operator !=(const TSize& other) const;
    int         X() const;
    int         Y() const;
    int         Magnitude() const;
    auto Area() const -> int;
 
    // Functions/binary-operators that return sizes
    //
    TSize      operator +(const TSize& size) const;
    TSize      operator -(const TSize& size) const;
    TSize      operator -() const;
 
    // Functions/assignement-operators that modify this size
    //
    TSize&     operator +=(const TSize& size);
    TSize&     operator -=(const TSize& size);
};
 
_OWLCFUNC(auto) operator *(int f, const TSize& s) -> TSize;
_OWLCFUNC(auto) operator *(const TSize& s, int f) -> TSize;
_OWLCFUNC(auto) operator /(const TSize& s, int d) -> TSize;
template <class T> _OWLCFUNC(auto) operator *(T f, const TSize& s) -> TSize;
template <class T> _OWLCFUNC(auto) operator *(const TSize& s, T f) -> TSize;
template <class T> _OWLCFUNC(auto) operator /(const TSize& s, T d) -> TSize;
_OWLCFUNC(ipstream&) operator >>(ipstream& is, TSize& s);
_OWLCFUNC(tistream&) operator >>(tistream& os, TSize& s);
_OWLCFUNC(opstream&) operator <<(opstream& os, const TSize& s);
_OWLCFUNC(tostream&) operator <<(tostream& os, const TSize& s);
 
//
/// A mathematical class derived from RECT.
///
/// The RECT type is defined as
///
/// \code
/// typedef struct tagRECT {
///    int left;
///    int top;
///    int right;
///    int bottom;
/// } RECT;
/// \endcode
///
/// TRect encapsulates the properties of rectangles with sides parallel to the x-
/// and y-axes. In ObjectWindows, these rectangles define the boundaries of windows,
/// boxes, and clipping regions. TRect inherits four data members from RECT: `left`,
/// `top`, `right`, and `bottom`. These represent the top left and bottom right
/// coordinates of the rectangle. Note that `x` increases from left to right, and `y`
/// increases from top to bottom.
///
/// TRect places no restrictions on the relative positions of top left and bottom
/// right, so it is legal to have `left > right` and `top > bottom`. However, many
/// manipulations --- such as determining width and height, and forming unions and
/// intersections --- are simplified by normalizing the TRect objects involved.
/// Normalizing a rectangle means interchanging the corner point coordinate values
/// so that `left < right` and `top < bottom`. Normalization does not alter the physical
/// properties of a rectangle. `myRect.Normalized` creates a normal form copy of `myRect`
/// without changing `myRect`, while `myRect.Normalize` changes `myRect` to normal form.
/// Both members return the normalized rectangle.
///
/// TRect constructors are provided to create rectangles from either four `int` values, two
/// TPoint objects, or one TPoint and one TSize object. In the latter case, the
/// TPoint object specifies the top left point (also known as the rectangle's
/// origin) and the TSize object supplies the width and height of the rectangle.
/// Member functions perform a variety of rectangle tests and manipulations.
/// Overloaded `<<` and `>>` operators allow chained insertion and extraction of TRect
/// objects with streams.
//
class _OWLCLASS TRect
  : public RECT 
{
  public:
 
    //
    /// Describes the position of corners, anchors, edges, subdivisions (half, quadrant, nonant)
    /// and surrounding cells.
    //
    enum class TAlignment
    {
      TopLeft, TopCenter, TopRight,
      MiddleLeft, MiddleCenter, MiddleRight,
      BottomLeft, BottomCenter, BottomRight
    };
 
    //
    /// Orientation of subdivisions of a rectangle.
    //
    enum class TOrientation
    {
      Horizontal, Vertical
    };
 
    using TCorners = std::array<TPoint, 4>;
    using TCornerAlignments = std::array<TAlignment, 4>;
    using TAnchors = std::array<TPoint, 9>;
    using TAnchorAlignments = std::array<TAlignment, 9>;
 
    using TEdges = std::array<TRect, 4>;
    using TEdgeAlignments = std::array<TAlignment, 4>;
 
    using THalves = std::array<TRect, 2>;
    using THalfAlignments = std::array<TAlignment, 2>;
    using TQuadrants = std::array<TRect, 4>;
    using TQuadrantAlignments = std::array<TAlignment, 4>;
    using TNonants = std::array<TRect, 9>;
    using TNonantAlignments = std::array<TAlignment, 9>;
 
    using TCells = std::array<TRect, 9>;
    using TCellAlignments = std::array<TAlignment, 9>;
 
    /// \name Constructors
    /// \{
 
    TRect();
    TRect(const TRect&) = default;
    TRect(const RECT&);
    TRect(int left, int top, int right, int bottom);
    TRect(const TPoint& topLeft, const TPoint& bottomRight);
    TRect(const TPoint& anchor, const TSize& extent, TAlignment anchorPosition = TAlignment::TopLeft);
 
    [[nodiscard]] static auto Create(const TPoint& anchor, const TSize& extent, TAlignment anchorPosition = TAlignment::TopLeft) -> TRect;
 
    /// \}
    /// \name Assignment functions and operators
    /// \{
 
    void SetNull();
    auto operator =(const TRect&) -> TRect& = default;
 
#if defined(OWL5_COMPAT)
 
    // Use the assignment operator instead of these functions.
 
    [[deprecated]] void SetEmpty();
    [[deprecated]] void Set(int left, int top, int right, int bottom);
    [[deprecated]] void SetWH(int , int top, int width, int height);
 
#endif
 
    /// \}
    /// \name Type conversion operators
    /// \{
 
    operator const TPoint*() const;
    operator TPoint*();
 
    /// \}
    /// \name Predicate functions and operators
    /// \{
 
    [[nodiscard]] auto operator ==(const TRect& other) const -> bool;
    [[nodiscard]] auto operator !=(const TRect& other) const -> bool;
    [[nodiscard]] auto IsNull() const -> bool;
    [[nodiscard]] auto IsEmpty() const -> bool;
    [[nodiscard]] auto IsNormal() const -> bool;
    [[nodiscard]] auto Contains(const TPoint& point) const -> bool;
    [[nodiscard]] auto Contains(const TRect& other) const -> bool;
    [[nodiscard]] auto Touches(const TRect& other) const -> bool;
 
    /// \}
    /// \name Basic properties
    /// \{
 
    [[nodiscard]] auto Left() const -> int;
    [[nodiscard]] auto X() const -> int;
    [[nodiscard]] auto Top() const -> int;
    [[nodiscard]] auto Y() const -> int;
    [[nodiscard]] auto Center() const -> int;
    [[nodiscard]] auto Middle() const -> int;
    [[nodiscard]] auto Right() const -> int;
    [[nodiscard]] auto Bottom() const -> int;
 
    [[nodiscard]] auto Width() const -> int;
    [[nodiscard]] auto Height() const -> int;
    [[nodiscard]] auto Size() const -> TSize;
    [[nodiscard]] auto Area() const -> int;
 
    /// \}
    /// \name Corner and anchor points
    /// \{
 
    [[nodiscard]] auto TopLeft() const -> TPoint;
    [[nodiscard]] auto TopCenter() const -> TPoint;
    [[nodiscard]] auto TopRight() const -> TPoint;
    [[nodiscard]] auto MiddleLeft() const -> TPoint;
    [[nodiscard]] auto MiddleCenter() const -> TPoint;
    [[nodiscard]] auto MiddleRight() const -> TPoint;
    [[nodiscard]] auto BottomLeft() const -> TPoint;
    [[nodiscard]] auto BottomCenter() const -> TPoint;
    [[nodiscard]] auto BottomRight() const -> TPoint;
 
    [[nodiscard]] auto TopLeft() -> TPoint&;
    [[nodiscard]] auto BottomRight() -> TPoint&;
 
    [[nodiscard]] auto Corner(TAlignment position) const -> TPoint;
    [[nodiscard]] auto Corners() const -> TCorners;
    [[nodiscard]] static auto CornerAlignments() -> TCornerAlignments;
 
    [[nodiscard]] auto Anchor(TAlignment position) const -> TPoint;
    [[nodiscard]] auto Anchors() const -> TAnchors;
    [[nodiscard]] static auto AnchorAlignments() -> TAnchorAlignments;
 
    /// \}
    /// \name Edges
    /// \{
 
    [[nodiscard]] auto TopEdge() const -> TRect;
    [[nodiscard]] auto LeftEdge() const -> TRect;
    [[nodiscard]] auto RightEdge() const -> TRect;
    [[nodiscard]] auto BottomEdge() const -> TRect;
 
    [[nodiscard]] auto Edge(TAlignment position) const -> TRect;
    [[nodiscard]] auto Edges() const -> TEdges;
    [[nodiscard]] static auto EdgeAlignments() -> TEdgeAlignments;
 
    /// \}
    /// \name Subdivisions
    /// \{
 
    [[nodiscard]] auto TopHalf() const -> TRect;
    [[nodiscard]] auto LeftHalf() const -> TRect;
    [[nodiscard]] auto RightHalf() const -> TRect;
    [[nodiscard]] auto BottomHalf() const -> TRect;
 
    [[nodiscard]] auto Half(TAlignment position) const -> TRect;
    [[nodiscard]] auto Halves(TOrientation) const -> THalves;
    [[nodiscard]] static auto HalfAlignments(TOrientation) -> THalfAlignments;
 
    [[nodiscard]] auto TopLeftQuadrant() const -> TRect;
    [[nodiscard]] auto TopRightQuadrant() const -> TRect;
    [[nodiscard]] auto BottomLeftQuadrant() const -> TRect;
    [[nodiscard]] auto BottomRightQuadrant() const -> TRect;
 
    [[nodiscard]] auto Quadrant(TAlignment position) const -> TRect;
    [[nodiscard]] auto Quadrants() const -> TQuadrants;
    [[nodiscard]] static auto QuadrantAlignments() -> TQuadrantAlignments;
 
    [[nodiscard]] auto TopLeftNonant() const -> TRect;
    [[nodiscard]] auto TopCenterNonant() const -> TRect;
    [[nodiscard]] auto TopRightNonant() const -> TRect;
    [[nodiscard]] auto MiddleLeftNonant() const -> TRect;
    [[nodiscard]] auto MiddleCenterNonant() const -> TRect;
    [[nodiscard]] auto MiddleRightNonant() const -> TRect;
    [[nodiscard]] auto BottomLeftNonant() const -> TRect;
    [[nodiscard]] auto BottomCenterNonant() const -> TRect;
    [[nodiscard]] auto BottomRightNonant() const -> TRect;
 
    [[nodiscard]] auto Nonant(TAlignment position) const -> TRect;
    [[nodiscard]] auto Nonants() const -> TNonants;
    [[nodiscard]] static auto NonantAlignments() -> TNonantAlignments;
 
    /// \}
    /// \name Superdivision cells
    /// Cells constitute the uniform 3x3 superstructure of which this rectangle is the middle center cell.
    /// \{
 
    [[nodiscard]] auto TopLeftCell() const -> TRect;
    [[nodiscard]] auto TopCenterCell() const -> TRect;
    [[nodiscard]] auto TopRightCell() const -> TRect;
    [[nodiscard]] auto MiddleLeftCell() const -> TRect;
    [[nodiscard]] auto MiddleCenterCell() const -> TRect;
    [[nodiscard]] auto MiddleRightCell() const -> TRect;
    [[nodiscard]] auto BottomLeftCell() const -> TRect;
    [[nodiscard]] auto BottomCenterCell() const -> TRect;
    [[nodiscard]] auto BottomRightCell() const -> TRect;
 
    [[nodiscard]] auto Cell(TAlignment cellPosition) const -> TRect;
    [[nodiscard]] auto Cells() const -> TCells;
    [[nodiscard]] static auto CellAlignments() -> TCellAlignments;
 
    [[nodiscard]] static auto CellCoordinate(TAlignment) -> TPoint;
    [[nodiscard]] static auto CellAlignment(const TPoint& cellCoordinate) -> TAlignment;
 
    /// \}
    /// \name Alignment functions
    /// \{
 
    [[nodiscard]] auto Centered(const TPoint& other) const -> TRect;
    [[nodiscard]] auto Centered(const TRect& other) const -> TRect;
 
    [[nodiscard]] auto AlignedTopLeft(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedTopCenter(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedTopRight(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedMiddleLeft(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedMiddleCenter(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedMiddleRight(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedBottomLeft(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedBottomCenter(const TRect& other) const -> TRect;
    [[nodiscard]] auto AlignedBottomRight(const TRect& other) const -> TRect;
 
    [[nodiscard]] auto Aligned(const TRect& other, TAlignment) const -> TRect;
 
    /// \}
    /// \name Alignment utility functions (static)
    /// \{
 
    [[nodiscard]] static auto IsLeft(TAlignment) -> bool;
    [[nodiscard]] static auto IsCenter(TAlignment) -> bool;
    [[nodiscard]] static auto IsRight(TAlignment) -> bool;
 
    [[nodiscard]] static auto IsTop(TAlignment) -> bool;
    [[nodiscard]] static auto IsMiddle(TAlignment) -> bool;
    [[nodiscard]] static auto IsBottom(TAlignment) -> bool;
 
    /// \}
    /// \name Non-mutating manipulation functions and operators
    /// \{
 
    [[nodiscard]] auto Normalized() const -> TRect;
    [[nodiscard]] auto OffsetBy(int dx, int dy) const -> TRect;
    [[nodiscard]] auto OffsetBy(const TSize& delta) const -> TRect;
    [[nodiscard]] auto MovedTo(int x, int y) const -> TRect;
    [[nodiscard]] auto MovedTo(const TPoint&) const -> TRect;
    [[nodiscard]] auto InflatedBy(int dx, int dy) const -> TRect;
    [[nodiscard]] auto InflatedBy(const TSize& delta) const -> TRect;
    [[nodiscard]] auto DeflatedBy(int dx, int dy) const -> TRect;
    [[nodiscard]] auto DeflatedBy(const TSize& delta) const -> TRect;
    [[nodiscard]] auto GrownUpBy(int delta) const -> TRect;
    [[nodiscard]] auto GrownLeftBy(int delta) const -> TRect;
    [[nodiscard]] auto GrownRightBy(int delta) const -> TRect;
    [[nodiscard]] auto GrownDownBy(int delta) const -> TRect;
    [[nodiscard]] auto GrownUpLeftBy(const TSize& delta) const -> TRect;
    [[nodiscard]] auto GrownUpRightBy(const TSize& delta) const -> TRect;
    [[nodiscard]] auto GrownDownLeftBy(const TSize& delta) const -> TRect;
    [[nodiscard]] auto GrownDownRightBy(const TSize& delta) const -> TRect;
    [[nodiscard]] auto GrownBy(int delta, TAlignment direction) const -> TRect;
    [[nodiscard]] auto GrownBy(const TSize& delta, TAlignment direction) const -> TRect;
    [[nodiscard]] auto Subtract(const TRect& other) const -> std::vector<TRect>;
 
#if defined(OWL5_COMPAT)
 
    [[deprecated]] auto Subtract(const TRect& other, TRect result[4]) const -> int;
 
#endif
 
    [[nodiscard]] auto operator +(const TSize& delta) const -> TRect;
    [[nodiscard]] auto operator -(const TSize& delta) const -> TRect;
    [[nodiscard]] auto operator &(const TRect& other) const -> TRect;
    [[nodiscard]] auto operator |(const TRect& other) const -> TRect;
 
    /// \}
    /// \name Mutating manipulation functions and operators
    /// \{
 
    auto Normalize() -> TRect&;
    auto Offset(int dx, int dy) -> TRect&;
    auto Offset(const TSize& delta) -> TRect&;
    auto MoveTo(int x, int y) -> TRect&;
    auto MoveTo(const TPoint& delta) -> TRect&;
    auto Inflate(int dx, int dy) -> TRect&;
    auto Inflate(const TSize& delta) -> TRect&;
    auto Deflate(int dx, int dy) -> TRect&;
    auto Deflate(const TSize& delta) -> TRect&;
    auto GrowUp(int delta) -> TRect&;
    auto GrowLeft(int delta) -> TRect&;
    auto GrowRight(int delta) -> TRect&;
    auto GrowDown(int delta) -> TRect&;
    auto GrowUpLeft(const TSize& delta) -> TRect&;
    auto GrowUpRight(const TSize& delta) -> TRect&;
    auto GrowDownLeft(const TSize& delta) -> TRect&;
    auto GrowDownRight(const TSize& delta) -> TRect&;
    auto Grow(int delta, TAlignment direction) -> TRect&;
    auto Grow(const TSize& delta, TAlignment direction) -> TRect&;
 
    auto operator +=(const TSize& delta) -> TRect&;
    auto operator -=(const TSize& delta) -> TRect&;
    auto operator &=(const TRect& other) -> TRect&;
    auto operator |=(const TRect& other) -> TRect&;
 
    /// \}
};
 
_OWLCFUNC(auto) operator >>(ipstream& is, TRect& r) -> ipstream&;
_OWLCFUNC(auto) operator >>(tistream& is, TRect& r) -> tistream&;
_OWLCFUNC(auto) operator <<(opstream& os, const TRect& r) -> opstream&;
_OWLCFUNC(auto) operator <<(tostream& os, const TRect& r) -> tostream&;
 
/// @}
 
/// \cond NoSuppressDoxygenWarning
#include <owl/posclass.h>
/// \endcond
 
//----------------------------------------------------------------------------
// Inlines
//
 
//----------------------------------------------------------------------------
// TPoint
//
 
 
 
 
//
/// Constructs an uninitialized point.
//
inline
TPoint::TPoint()
{
  x = 0;
  y = 0;
}
 
//
/// Creates a TPoint object with the given coordinates.
//
inline
TPoint::TPoint(int _x, int _y)
{
  x = _x;
  y = _y;
}
 
//
/// Creates a TPoint object with x = point.x,  y = point.y.
//
inline
TPoint::TPoint(const tagPOINT & point)
{
  x = point.x;
  y = point.y;
}
 
//
/// Makes a copy of the point.
//
inline
TPoint::TPoint(const TPoint & point)
{
  x = point.x;
  y = point.y;
}
 
//
/// Creates a TPoint object with x = size.cx and y = size.cy.
//
inline
TPoint::TPoint(const tagSIZE & size)
{
  x = size.cx;
  y = size.cy;
}
 
#if defined(OWL5_COMPAT)
 
//
/// Creates a point by extracting the signed 16-bit coordinates from the given argument.
/// 
/// \deprecated Use TPoint::CreateFromPackedCoordinates instead.
//
inline TPoint::TPoint(LPARAM packedPoint)
  : TPoint{CreateFromPackedCoordinates(packedPoint)}
{}
 
#endif
 
//
/// Creates a point by extracting the signed 16-bit coordinates from the given argument.
/// 
/// The low-order 16 bits of the given argument should contain the horizontal coordinate, and the
/// next 16 bits should contain the vertical coordinate. The coordinates should be encoded as
/// signed short integers.
//
inline auto TPoint::CreateFromPackedCoordinates(LPARAM packedPoint) -> TPoint
{
  return {static_cast<short>(packedPoint & 0xFFFF), static_cast<short>((packedPoint >> 16) & 0xFFFF)};
}
 
//
/// Returns the x coordinate of the point.
//
inline int
TPoint::X() const
{
  return x;
}
 
//
/// Returns the Y coordinate of the point.
//
inline int
TPoint::Y() const
{
  return y;
}
 
//
/// Calculates an offset to this point using the given displacement arguments.
/// Returns the point (x + dx, y + dy). This point is not changed.
//
inline TPoint
TPoint::OffsetBy(int dx, int dy) const
{
  return TPoint(x + dx, y + dy);
}
 
//
/// Returns the point (-x, -y). This point is not changed.
//
inline TPoint
TPoint::operator -() const
{
  return TPoint(-x, -y);
}
 
//
/// Returns true if this point is equal to the other point; otherwise returns false.
//
inline bool
TPoint::operator ==(const TPoint& other) const
{
  return ToBool(other.x == x && other.y == y);
}
 
//
/// Returns false if this point is equal to the other point; otherwise returns true.
//
inline bool
TPoint::operator !=(const TPoint& other) const
{
  return ToBool(other.x != x || other.y != y);
}
 
//
/// Calculates an offset to this point using the given size argument as the
/// displacement. Returns the point (x + size.cx, y + size.cy). This point is not
/// changed.
//
inline TPoint
TPoint::operator +(const TSize& size) const
{
  return TPoint(x + size.cx, y + size.cy);
}
 
//
/// Calculates a distance from this point to the point argument. Returns the TSize
/// object (x - point.x, y - point.y). This point is not changed.
//
inline TSize
TPoint::operator -(const TPoint& point) const
{
  return TSize(x - point.x, y - point.y);
}
 
//
/// Calculates a negative offset to this point using the given size argument as the
/// displacement. Returns the point (x - size.cx, y - size.cy). This point is not
/// changed.
//
inline TPoint
TPoint::operator -(const TSize& size) const
{
  return TPoint(x - size.cx, y - size.cy);
}
 
//
/// Offsets this point by the given delta values. This point is changed to (x +
/// dx, y + dy). Returns a reference to this point.
//
inline TPoint&
TPoint::Offset(int dx, int dy)
{
  x += dx;
  y += dy;
  return *this;
}
 
//
/// Offsets this point by the given size argument. This point is changed to(x +
/// size.cx, y + size.cy). Returns a reference to this point.
//
inline TPoint&
TPoint::operator +=(const TSize& size)
{
  x += size.cx;
  y += size.cy;
  return *this;
}
 
//
/// Negatively offsets this point by the given size argument. This point is changed
/// to (x - size.cx, y - size.cy). Returns a reference to this point.
//
inline TPoint&
TPoint::operator -=(const TSize& size)
{
  x -= size.cx;
  y -= size.cy;
  return *this;
}
 
//----------------------------------------------------------------------------
// TPointL
//
 
//
/// Default constructor that does nothing.
//
inline
TPointL::TPointL()
{
  x = 0;
  y = 0;
}
 
//
/// Constructs the point to a specific location.
//
inline
TPointL::TPointL(long _x, long _y)
{
  x = _x;
  y = _y;
}
 
//
/// Alias constructor that initializes from an existing point.
//
inline
TPointL::TPointL(const POINTL & point)
{
  x = point.x;
  y = point.y;
}
 
//
/// Copy constructor. Makes a copy of the location.
//
inline
TPointL::TPointL(const TPointL & point)
{
  x = point.x;
  y = point.y;
}
 
//
/// Returns the X component of the point.
//
inline long
TPointL::X() const
{
  return x;
}
 
//
/// Returns the Y component of the point.
//
inline long
TPointL::Y() const
{
  return y;
}
 
//
/// Returns the new point (x+dx, y+dy).  Creates a new point shifted by the offset,
/// preserving the original point.
//
inline TPointL
TPointL::OffsetBy(long dx, long dy) const
{
  return TPointL(x + dx, y + dy);
}
 
//
/// Returns the negative of the point.
//
inline TPointL
TPointL::operator -() const
{
  return TPointL(-x, -y);
}
 
//
/// Returns true if positions are the same.
//
inline bool
TPointL::operator ==(const TPointL& other) const
{
  return ToBool(other.x == x && other.y == y);
}
 
//
/// Returns true if the positions are not the same.
//
inline bool
TPointL::operator !=(const TPointL& other) const
{
  return ToBool(other.x != x || other.y != y);
}
 
//
/// Returns the new point (x+cx, y+cy).
//
inline TPointL
TPointL::operator +(const TSize& size) const
{
  return TPointL(x + size.cx, y + size.cy);
}
 
//
/// Returns the difference between the two points.
//
inline TPointL
TPointL::operator -(const TPointL& point) const
{
  return TPointL(x - point.x, y - point.y);
}
 
//
/// Return the new point (x-cx, y-cy).
//
inline TPointL
TPointL::operator -(const TSize& size) const
{
  return TPointL(x - size.cx, y - size.cy);
}
 
//
/// Returns the point (x+dx, y+dy), shifting the point by the offset.
//
inline TPointL&
TPointL::Offset(long dx, long dy)
{
  x += dx;
  y += dy;
  return *this;
}
 
//
/// Return the point (x+cx, y+cy).
//
inline TPointL&
TPointL::operator +=(const TSize& size)
{
  x += size.cx;
  y += size.cy;
  return *this;
}
 
//
/// Return the point (x-cx, y-cy).
//
inline TPointL&
TPointL::operator -=(const TSize& size)
{
  x -= size.cx;
  y -= size.cy;
  return *this;
}
 
 
//----------------------------------------------------------------------------
// TPointF
//
 
//
/// Default constructor that does nothing.
//
inline
TPointF::TPointF()
{
  x = 0.0f;
  y = 0.0f;
}
 
//
/// Constructor that initializes the location.
//
inline
TPointF::TPointF(float _x, float _y)
{
  x = _x;
  y = _y;
}
 
//
/// Constructor that copies the location.
//
inline
TPointF::TPointF(const TPointF & point)
{
  x = point.x;
  y = point.y;
}
 
//
/// Returns X component of the point.
//
inline float
TPointF::X() const
{
  return x;
}
 
//
/// Returns Y component of the point.
//
inline float
TPointF::Y() const
{
  return y;
}
 
//
/// Moves the point by an offset.
//
inline TPointF
TPointF::OffsetBy(float dx, float dy) const
{
  return TPointF(x + dx, y + dy);
}
 
//
/// Returns the negative of the point.
//
inline TPointF
TPointF::operator -() const
{
  return TPointF(-x, -y);
}
 
//
/// Returns true if the points are at the same location.
//
inline bool
TPointF::operator ==(const TPointF& other) const
{
  return ToBool(other.x == x && other.y == y);
}
 
//
/// Return true if the points are not at the same location.
//
inline bool
TPointF::operator !=(const TPointF& other) const
{
  return ToBool(other.x != x || other.y != y);
}
 
//
/// Returns a new point (x+cx, y+cy).
//
inline TPointF
TPointF::operator +(const TPointF& size) const
{
  return TPointF(x + size.x, y + size.y);
}
 
//
/// Returns a new point subtracted from the current point.
//
inline TPointF
TPointF::operator -(const TPointF& point) const
{
  return TPointF(x - point.x, y - point.y);
}
 
//
/// Moves the point by an offset.
//
inline TPointF&
TPointF::Offset(float dx, float dy)
{
  x += dx;
  y += dy;
  return *this;
}
 
//
/// Returns the new point moved by the offset.
//
inline TPointF&
TPointF::operator +=(const TPointF& size)
{
  x += size.x;
  y += size.y;
  return *this;
}
 
//
/// Returns the new point subtracted from the current.
//
inline TPointF&
TPointF::operator -=(const TPointF& size)
{
  x -= size.x;
  y -= size.y;
  return *this;
}
 
//----------------------------------------------------------------------------
// TRect
//
 
//
/// Creates a default (null) rectangle with all members set to 0.
/// Despite being empty, a default rectangle is considered to be in normal form (valid).
//
inline TRect::TRect()
  : RECT{}
{
  CHECK(IsNormal());
  CHECK(IsEmpty());
}
 
//
/// Copies the position and dimensions from an existing rectangle.
/// No checks are made on the validity (normal form) of the rectangle. Call TRect::Normalize to
/// ensure that the rectangle is in normal form.
//
inline TRect::TRect(const RECT& other)
  : RECT{other}
{
  static_assert(sizeof(other) == sizeof(*this), "Slicing in copy constructor is not allowed");
  WARN(!IsNormal(), _T("TRect::TRect: RECT has denormal form: ") << *this);
}
 
//
/// Sets all the position for all edges explicitly.
/// No checks are made on the validity (normal form) of the rectangle. Ensure that the passed
/// values form a normal rectangle, or call TRect::Normalize to change it into normal form.
//
inline TRect::TRect(int left, int top, int right, int bottom)
  : RECT{left, top, right, bottom}
{
  WARN(!IsNormal(), _T("TRect::TRect: Constructed from denormal values: ") << *this);
}
 
//
/// Creates a rectangle with the given top left and bottom right corners.
/// No checks are made on the validity (normal form) of the rectangle. Ensure that the passed
/// points form a normal rectangle, or call TRect::Normalize to change it into normal form.
//
inline TRect::TRect(const TPoint& topLeft, const TPoint& bottomRight)
  : RECT{topLeft.x, topLeft.y, bottomRight.x, bottomRight.y}
{
  WARN(!IsNormal(), _T("TRect::TRect: Constructed from denormal values: ") << *this);
}
 
//
/// Creates a rectangle with its top left corner at the given point, with width and height equal to
/// the given extent's dimensions.
///
/// No checks are made on the validity (normal form) of the rectangle. Ensure that the passed
/// values form a normal rectangle, or call TRect::Normalize to change it into normal form.
//
inline TRect::TRect(const TPoint& topLeft, const TSize& extent, TAlignment a)
  : RECT{Create(topLeft, extent, a)}
{
  WARN(!IsNormal(), _T("TRect::TRect: Constructed from denormal values: ") << *this);
}
 
inline auto TRect::Create(const TPoint& anchor, const TSize& extent, TAlignment anchorPosition) -> TRect
{
  // For center and middle we need to divide the extent in two. Since this is integer math,
  // this division may have a remainder. So to ensure the extent of the rectangle adds up to
  // the extent specified, we define some helper functions here. Note that half1 is rounded
  // down, hence will be the smaller of the two, if unequal, i.e. half1(x) <= half2(x) holds.
  //
  const auto half1 = [](int extent) { return extent / 2; };
  const auto half2 = [half1](int extent) { return extent - half1(extent); };
  static_assert(half1(42) + half2(42) == 42 && half1(65535) + half2(65535) == 65535);
 
  using T = TAlignment;
  switch (anchorPosition)
  {
  case T::TopLeft: return {anchor.x, anchor.y, anchor.x + extent.cx, anchor.y + extent.cy};
  case T::TopCenter: return {anchor.x - half1(extent.cx), anchor.y, anchor.x + half2(extent.cx), anchor.y + extent.cy};
  case T::TopRight: return {anchor.x - extent.cx, anchor.y, anchor.x, anchor.y + extent.cy};
  case T::MiddleLeft: return {anchor.x, anchor.y - half1(extent.cy), anchor.x + extent.cx, anchor.y + half2(extent.cy)};
  case T::MiddleCenter: return {anchor.x - half1(extent.cx), anchor.y - half1(extent.cy), anchor.x + half2(extent.cx), anchor.y + half2(extent.cy)};
  case T::MiddleRight: return {anchor.x - extent.cx, anchor.y - half1(extent.cy), anchor.x, anchor.y + half2(extent.cy)};
  case T::BottomLeft: return {anchor.x, anchor.y - extent.cy, anchor.x + extent.cx, anchor.y};
  case T::BottomCenter: return {anchor.x - half1(extent.cx), anchor.y - extent.cy, anchor.x + half2(extent.cx), anchor.y};
  case T::BottomRight: return {anchor.x - extent.cx, anchor.y - extent.cy, anchor.x, anchor.y};
  default: CHECK(false); return {};
  }
}
 
//
/// Sets the position of the left, top, right and bottom edges of the rectangle to 0.
/// \deprecated Use the assignment operator instead.
//
inline void TRect::SetNull()
{
  *this = {};
  CHECK(IsNormal());
}
 
#if defined(OWL5_COMPAT)
 
//
/// Empties this rectangle by setting all members to 0.
/// \deprecated Use the assignment operator instead.
//
inline void TRect::SetEmpty()
{
  SetNull();
}
 
//
/// Resets the rectangle with the given values.
/// \deprecated Use the assignment operator instead.
//
inline void TRect::Set(int left, int top, int right, int bottom)
{
  operator =({left, top, right, bottom});
}
 
//
/// Resets the rectangle with the given values.
/// \deprecated Use the assignment operator instead.
//
inline void TRect::SetWH(int left, int top, int width, int height)
{
  operator =({{left, top}, TSize{width, height}});
}
 
#endif
 
//
/// Converts the object to a pointer to the upper left point of the rectangle.
/// The pointer can be used as if it is pointing to an array of two points; the upper left point
/// and the bottom right point of this rectangle.
///
/// \note The pointer does **not** point to an array of all corner points.
///
/// \deprecated This function is special in that it performs a reinterpret_cast to pretend that the
/// TRect structure is an array of two TPoint objects. The function does static assertions that
/// will help ensure that this works out OK. However, you should prefer to access a TRect object
/// using the public accessors, the assignment operator, or using the public structure members
/// directly. This function invokes undefined behaviour (in C++ standard terms), and will likely
/// be removed in the future.
//
inline TRect::operator const TPoint*() const
{
  static_assert(offsetof(TPoint, y) - offsetof(TPoint, x) == offsetof(TRect, top) - offsetof(TRect, left) &&
    std::is_same_v<decltype(TPoint::x), decltype(TRect::left)> &&
    std::is_same_v<decltype(TPoint::y), decltype(TRect::top)> &&
    offsetof(TRect, right) == sizeof(TPoint),
    "Packing and/or type assumption failed");
  return reinterpret_cast<const TPoint*>(this);
}
 
//
/// Overload; see TRect::operator const TPoint*() const for more information.
//
inline TRect::operator TPoint*()
{
  static_assert(offsetof(TPoint, y) - offsetof(TPoint, x) == offsetof(TRect, top) - offsetof(TRect, left) &&
    std::is_same_v<decltype(TPoint::x), decltype(TRect::left)> &&
    std::is_same_v<decltype(TPoint::y), decltype(TRect::top)> &&
    offsetof(TRect, right) == sizeof(TPoint),
    "Packing and/or type assumption failed");
  return reinterpret_cast<TPoint*>(this);
}
 
//
/// Determines whether two rectangels are equal.
///
/// \returns `true` if this rectangle has identical corner coordinates to the other rectangle;
/// otherwise, returns `false`.
//
inline auto TRect::operator ==(const TRect& other) const -> bool
{
  return other.left == left && other.top == top
    && other.right == right && other.bottom == bottom;
}
 
//
/// Determines whether two rectangels are different.
///
/// \returns `false` if this rectangle has identical corner coordinates to the other rectangle;
/// otherwise, returns `true`.
//
inline auto TRect::operator !=(const TRect& other) const -> bool
{
  return !(other == *this);
}
 
//
/// Determines whether the rectangle is a default (null) rectangle.
///
/// \returns `true` if `left`, `right`, `top` and `bottom` are all 0; otherwise, returns `false`.
//
inline auto TRect::IsNull() const -> bool
{
  return left == 0 && right == 0 && top == 0 && bottom == 0;
}
 
//
/// Determines whether the rectangle has positive area.
///
/// \returns `true` if `left >= right` or `top >= bottom`; otherwise, returns `false`.
///
/// \note A denormal rectangle has negative area. Call TRect::Normalized (non-mutating) or
/// TRect::Normalize (mutating) to normalize a rectangle, so that it has 0 or positive area.
//
inline auto TRect::IsEmpty() const -> bool
{
  return left >= right || top >= bottom;
}
 
//
/// Determines whether the rectangle is in a valid state for operations that require the rectangle
/// to be in normal form, such as containment testing, intersections and bounding box calculation.
///
/// Call TRect::Normalized (non-mutating) or TRect::Normalize (mutating) to normalize a rectangle.
///
/// \returns `true` if `left <= right` and `top <= bottom`.
///
/// \note An empty rectangle is considered normal if `left == right && top <= bottom` or
/// `left <= right && top == bottom`, i.e. a normal rectangle reduced to an edge.
///
/// \sa TRect::Normalized for more information about denormal rectangles and normalization.
//
inline auto TRect::IsNormal() const -> bool
{
  return left <= right && top <= bottom;
}
 
//
/// Determines whether the given point lies within this rectangle.
///
/// \returns If this rectangle is empty, `false` is returned. Otherwise, the given
/// point is tested for containment within this rectangle, and the result is returned.
///
/// \note If the given point is on the left vertical or top horizontal edge of the rectangle,
/// it is considered contained within this rectangle, and `true` is returned. On the other hand, if
/// the point is on the right vertical or bottom horizontal edge, the point is *not* considered
/// contained within this rectangle, and `false` is returned.
//
inline auto TRect::Contains(const TPoint& point) const -> bool
{
  return point.x >= left && point.x < right && point.y >= top && point.y < bottom;
}
 
//
/// Determines whether the given rectangle lies on or within this rectangle.
///
/// \returns If either rectangle is empty, `false` is returned. Otherwise, the given rectangle is
/// tested for containment within this rectangle, and the result is returned.
///
/// \note Both rectangles are assumed to be in normal form, i.e. `left <= right` and
/// `top <= bottom`. Call TRect::Normalized (non-mutating) or TRect::Normalize (mutating) to
/// normalize the rectangles before calling this function.
//
inline auto TRect::Contains(const TRect& other) const -> bool
{
  return !IsEmpty() && !other.IsEmpty() &&
    other.left >= left && other.right <= right && other.top >= top && other.bottom <= bottom;
}
 
//
/// Determines whether the given rectangle shares any interior points with this rectangle.
///
/// \returns If either rectangle is not in normal form, `false` is returned. Otherwise, the
/// rectangles are tested for intersection, and the result is returned.
///
/// \sa Call TRect::Normalized (non-mutating) or TRect::Normalize (mutating) to normalize the
/// rectangles before calling this function.
//
inline auto TRect::Touches(const TRect& other) const -> bool
{
  return IsNormal() && other.IsNormal() && 
    other.right > left && other.left < right && other.bottom > top && other.top < bottom;
}
 
inline auto TRect::Left() const -> int
{
  return left;
}
 
inline auto TRect::X() const -> int
{
  return left;
}
 
inline auto TRect::Top() const -> int
{
  return top;
}
 
inline auto TRect::Y() const -> int
{
  return top;
}
 
inline auto TRect::Center() const -> int
{
  return (left + right) / 2;
}
 
inline auto TRect::Middle() const -> int
{
  return (top + bottom) / 2;
}
 
inline auto TRect::Right() const -> int
{
  return right;
}
 
inline auto TRect::Bottom() const -> int
{
  return bottom;
}
 
inline auto TRect::Width() const -> int
{
  return right - left;
}
 
inline auto TRect::Height() const -> int
{
  return bottom - top;
}
 
inline auto TRect::Size() const -> TSize
{
  return {Width(), Height()};
}
 
inline auto TRect::Area() const -> int
{
  return Width() * Height();
}
 
inline auto TRect::TopLeft() const -> TPoint
{
  return {left, top};
}
 
inline auto TRect::TopCenter() const -> TPoint
{
  return {Center(), top};
}
 
inline auto TRect::TopRight() const -> TPoint
{
  return {right, top};
}
 
inline auto TRect::MiddleLeft() const -> TPoint
{
  return {left, Middle()};
}
 
inline auto TRect::MiddleCenter() const -> TPoint
{
  return {Center(), Middle()};
}
 
inline auto TRect::MiddleRight() const -> TPoint
{
  return {right, Middle()};
}
 
inline auto TRect::BottomLeft() const -> TPoint
{
  return {left, bottom};
}
 
inline auto TRect::BottomCenter() const -> TPoint
{
  return {Center(), bottom};
}
 
inline auto TRect::BottomRight() const -> TPoint
{
  return {right, bottom};
}
 
//
/// Returns a mutable reference to the top left corner.
///
/// \deprecated This function is special in that it performs a reinterpret_cast to pretend that the
/// structure members TRect::left and TRect::top are part of a TPoint object. The function does
/// static assertions that will help ensure that this works out OK. However, you should prefer to
/// modify a TRect object using the assignment operator, or using the public structure members
/// individually. This function invokes undefined behaviour (in C++ standard terms), and will
/// likely be removed in the future, leaving only the type-safe const overload.
//
inline auto TRect::TopLeft() -> TPoint&
{
  static_assert(offsetof(TPoint, y) - offsetof(TPoint, x) == offsetof(TRect, top) - offsetof(TRect, left) &&
    std::is_same_v<decltype(TPoint::x), decltype(TRect::left)> &&
    std::is_same_v<decltype(TPoint::y), decltype(TRect::top)>,
    "Packing and/or type assumption failed");
  return *reinterpret_cast<TPoint*>(&left);
}
 
//
/// Returns a mutable reference to the bottom right corner.
///
/// \deprecated This function is special in that it performs a reinterpret_cast to pretend that the
/// structure members TRect::right and TRect::bottom are part of a TPoint object.
/// See TRect::TopLeft for more information.
//
inline auto TRect::BottomRight() -> TPoint&
{
  static_assert(offsetof(TPoint, y) - offsetof(TPoint, x) == offsetof(TRect, bottom) - offsetof(TRect, right) &&
    std::is_same_v<decltype(TPoint::x), decltype(TRect::right)> &&
    std::is_same_v<decltype(TPoint::y), decltype(TRect::bottom)>,
    "Packing and/or type assumption failed");
  return *reinterpret_cast<TPoint*>(&right);
}
 
inline auto TRect::Corner(TAlignment position) const -> TPoint
{
  using T = TAlignment;
  switch (position)
  {
  case T::TopLeft: return TopLeft();
  case T::TopRight: return TopRight();
  case T::BottomLeft: return BottomLeft();
  case T::BottomRight: return BottomRight();
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::Corners() const -> TCorners
{
  return {TopLeft(), BottomLeft(), BottomRight(), TopRight()};
}
 
inline auto TRect::CornerAlignments() -> TCornerAlignments
{
  using T = TAlignment;
  return {T::TopLeft, T::BottomLeft, T::BottomRight, T::TopRight};
}
 
inline auto TRect::Anchor(TAlignment position) const -> TPoint
{
  using T = TAlignment;
  switch (position)
  {
  case T::TopLeft: return TopLeft();
  case T::TopCenter: return TopCenter();
  case T::TopRight: return TopRight();
  case T::MiddleLeft: return MiddleLeft();
  case T::MiddleCenter: return MiddleCenter();
  case T::MiddleRight: return MiddleRight();
  case T::BottomLeft: return BottomLeft();
  case T::BottomCenter: return BottomCenter();
  case T::BottomRight: return BottomRight();
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::Anchors() const -> TAnchors
{
  return
  {
    TopLeft(), TopCenter(), TopRight(),
    MiddleLeft(), MiddleCenter(), MiddleRight(),
    BottomLeft(), BottomCenter(), BottomRight()
  };
}
 
inline auto TRect::AnchorAlignments() -> TAnchorAlignments
{
  using T = TAlignment;
  return
  {
    T::TopLeft, T::TopCenter, T::TopRight,
    T::MiddleLeft, T::MiddleCenter, T::MiddleRight,
    T::BottomLeft, T::BottomCenter, T::BottomRight
  };
}
 
inline auto TRect::TopEdge() const -> TRect
{
  return {TopLeft(), TopRight()};
}
 
inline auto TRect::LeftEdge() const -> TRect
{
  return {TopLeft(), BottomLeft()};
}
 
inline auto TRect::RightEdge() const -> TRect
{
  return {TopRight(), BottomRight()};
}
 
inline auto TRect::BottomEdge() const -> TRect
{
  return {BottomLeft(), BottomRight()};
}
 
inline auto TRect::Edge(TAlignment position) const -> TRect
{
  using T = TAlignment;
  switch (position)
  {
  case T::TopCenter: return TopEdge();
  case T::MiddleLeft: return LeftEdge();
  case T::MiddleRight: return RightEdge();
  case T::BottomCenter: return BottomEdge();
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::Edges() const -> TEdges
{
  return {TopEdge(), LeftEdge(), BottomEdge(), RightEdge()};
}
 
inline auto TRect::EdgeAlignments() -> TEdgeAlignments
{
  using T = TAlignment;
  return {T::TopCenter, T::MiddleLeft, T::BottomCenter, T::MiddleRight};
}
 
inline auto TRect::TopHalf() const -> TRect
{
  return {TopLeft(), MiddleRight()};
}
 
inline auto TRect::LeftHalf() const -> TRect
{
  return {TopLeft(), BottomCenter()};
}
 
inline auto TRect::RightHalf() const -> TRect
{
  return {TopCenter(), BottomRight()};
}
 
inline auto TRect::BottomHalf() const -> TRect
{
  return {MiddleLeft(), BottomRight()};
}
 
inline auto TRect::Half(TAlignment position) const -> TRect
{
  using T = TAlignment;
  switch (position)
  {
  case T::TopCenter: return TopHalf();
  case T::MiddleLeft: return LeftHalf();
  case T::MiddleRight: return RightHalf();
  case T::BottomCenter: return BottomHalf();
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::Halves(TOrientation o) const -> THalves
{
  return o == TOrientation::Horizontal ?
    THalves{TopHalf(), BottomHalf()} :
    THalves{LeftHalf(), RightHalf()};
}
 
inline auto TRect::HalfAlignments(TOrientation o) -> THalfAlignments
{
  using T = TAlignment;
  return o == TOrientation::Horizontal ?
    THalfAlignments{T::TopCenter, T::BottomCenter} :
    THalfAlignments{T::MiddleLeft, T::MiddleRight};
}
 
inline auto TRect::TopLeftQuadrant() const -> TRect
{
  return {TopLeft(), MiddleCenter()};
}
 
inline auto TRect::TopRightQuadrant() const -> TRect
{
  return {TopCenter(), MiddleRight()};
}
 
inline auto TRect::BottomLeftQuadrant() const -> TRect
{
  return {MiddleLeft(), BottomCenter()};
}
 
inline auto TRect::BottomRightQuadrant() const -> TRect
{
  return {MiddleCenter(), BottomRight()};
}
 
inline auto TRect::Quadrant(TAlignment position) const -> TRect
{
  using T = TAlignment;
  switch (position)
  {
  case T::TopLeft: return TopLeftQuadrant();
  case T::TopRight: return TopRightQuadrant();
  case T::BottomLeft: return BottomLeftQuadrant();
  case T::BottomRight: return BottomRightQuadrant();
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::Quadrants() const -> TQuadrants
{
  return {TopLeftQuadrant(), TopRightQuadrant(), BottomLeftQuadrant(), BottomRightQuadrant()};
}
 
inline auto TRect::QuadrantAlignments() -> TQuadrantAlignments
{
  using T = TAlignment;
  return {T::TopLeft, T::TopRight, T::BottomLeft, T::BottomRight};
}
 
inline auto TRect::TopLeftNonant() const -> TRect
{
  return Nonant(TAlignment::TopLeft);
}
 
inline auto TRect::TopCenterNonant() const -> TRect
{
  return Nonant(TAlignment::TopCenter);
}
 
inline auto TRect::TopRightNonant() const -> TRect
{
  return Nonant(TAlignment::TopRight);
}
 
inline auto TRect::MiddleLeftNonant() const -> TRect
{
  return Nonant(TAlignment::MiddleLeft);
}
 
inline auto TRect::MiddleCenterNonant() const -> TRect
{
  return Nonant(TAlignment::MiddleCenter);
}
 
inline auto TRect::MiddleRightNonant() const -> TRect
{
  return Nonant(TAlignment::MiddleRight);
}
 
inline auto TRect::BottomLeftNonant() const -> TRect
{
  return Nonant(TAlignment::BottomLeft);
}
 
inline auto TRect::BottomCenterNonant() const -> TRect
{
  return Nonant(TAlignment::BottomCenter);
}
 
inline auto TRect::BottomRightNonant() const -> TRect
{
  return Nonant(TAlignment::BottomRight);
}
 
inline auto TRect::Nonant(TAlignment position) const -> TRect
{
  // We need to divide the extent into three sections. Since this is integer math, this
  // division may have a remainder. So to ensure the extent of the nonants adds up to the
  // extent of the rectangle, we define some helper functions here. Note that third1 is rounded
  // down, while third2 rounds down half of the rest, and third3 gets the rest. This ensures
  // the remainder is distributed and not concentrated in third3, In other words, this holds:
  // third1(x) <= third2(x) <= third3, with third3(x) - third2(1) <= 1.
  //
  const auto third1 = [](int extent) { return extent / 3; };
  const auto third2 = [third1](int extent) { return (extent - third1(extent)) / 2; };
  const auto third3 = [third1, third2](int extent) { return extent - third1(extent) - third2(extent); };
  static_assert(third1(9) + third2(9) + third3(9) == 9 && third3(9) - third2(9) == 0 &&
    third1(10) + third2(10) + third3(10) == 10 && third3(10) - third2(10) == 1 &&
    third1(11) + third2(11) + third3(11) == 11 && third3(11) - third2(11) == 0);
 
  const auto cx = right - left;
  const auto cy = bottom - top;
 
  using T = TAlignment;
  switch (position)
  {
  case T::TopLeft: return {left, top, left + third1(cx), top + third1(cy)};
  case T::TopCenter: return {left + third1(cx), top, left + third1(cx) + third2(cx), top + third1(cy)};
  case T::TopRight: return {left + third1(cx) + third2(cx), top, left + cx, top + third1(cy)};
  case T::MiddleLeft: return {left, top + third1(cy), left + third1(cx), top + third1(cy) + third2(cy)};
  case T::MiddleCenter: return {left + third1(cx), top + third1(cy), left + third1(cx) + third2(cx), top + third1(cy) + third2(cy)};
  case T::MiddleRight: return {left + third1(cx) + third2(cx), top + third1(cy), left + cx, top + third1(cy) + third2(cy)};
  case T::BottomLeft: return {left, top + third1(cy) + third2(cy), left + third1(cx), top + cy};
  case T::BottomCenter: return {left + third1(cx), top + third1(cy) + third2(cy), left + third1(cx) + third2(cx), top + cy};
  case T::BottomRight: return {left + third1(cx) + third2(cx), top + third1(cy) + third2(cy), left + cx, top + cy};
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::Nonants() const -> TNonants
{
  return
  {
    TopLeftNonant(), TopCenterNonant(), TopRightNonant(),
    MiddleLeftNonant(), MiddleCenterNonant(), MiddleRightNonant(),
    BottomLeftNonant(), BottomCenterNonant(), BottomRightNonant()
  };
}
 
inline auto TRect::NonantAlignments() -> TNonantAlignments
{
  using T = TAlignment;
  return
  {
    T::TopLeft, T::TopCenter, T::TopRight,
    T::MiddleLeft, T::MiddleCenter, T::MiddleRight,
    T::BottomLeft, T::BottomCenter, T::BottomRight
  };
}
 
//
/// Returns a rectangle of same size, offset up and left by the size of this rectangle.
//
inline auto TRect::TopLeftCell() const -> TRect
{
  return OffsetBy(-Size());
}
 
//
/// Returns a rectangle of same size, offset up by the height of this rectangle.
//
inline auto TRect::TopCenterCell() const -> TRect
{
  return OffsetBy(0, -Height());
}
 
//
/// Returns a rectangle of same size, offset up and right by the size of this rectangle.
//
inline auto TRect::TopRightCell() const -> TRect
{
  return OffsetBy(Width(), -Height());
}
 
//
/// Returns a rectangle of the same size, offset left by the width of this rectangle.
//
inline auto TRect::MiddleLeftCell() const -> TRect
{
  return OffsetBy(-Width(), 0);
}
 
//
/// Returns a copy of this rectangle.
//
inline auto TRect::MiddleCenterCell() const -> TRect
{
  return *this;
}
 
//
/// Returns a rectangle of the same size, offset right by the width of this rectangle.
//
inline auto TRect::MiddleRightCell() const -> TRect
{
  return OffsetBy(Width(), 0);
}
 
//
/// Returns a rectangle of the same size, offset down and left by the size of this rectangle.
//
inline auto TRect::BottomLeftCell() const -> TRect
{
  return OffsetBy(-Width(), Height());
}
 
//
/// Returns a rectangle of the same size, offset down by the height of this rectangle.
//
inline auto TRect::BottomCenterCell() const -> TRect
{
  return OffsetBy(0, Height());
}
 
//
/// Returns a rectangle of the same size, offset down and right by the size of this rectangle.
//
inline auto TRect::BottomRightCell() const -> TRect
{
  return OffsetBy(Size());
}
 
inline auto TRect::Cell(TAlignment cellPosition) const -> TRect
{
  using T = TAlignment;
  switch (cellPosition)
  {
  case T::TopLeft: return TopLeftCell();
  case T::TopCenter: return TopCenterCell();
  case T::TopRight: return TopRightCell();
  case T::MiddleLeft: return MiddleLeftCell();
  case T::MiddleCenter: return MiddleCenterCell();
  case T::MiddleRight: return MiddleRightCell();
  case T::BottomLeft: return BottomLeftCell();
  case T::BottomCenter: return BottomCenterCell();
  case T::BottomRight: return BottomRightCell();
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::Cells() const -> TCells
{
  return
  {
    TopLeftCell(), TopCenterCell(), TopRightCell(),
    MiddleLeftCell(), MiddleCenterCell(), MiddleRightCell(),
    BottomLeftCell(), BottomCenterCell(), BottomRightCell()
  };
}
 
inline auto TRect::CellAlignments() -> TCellAlignments
{
  using T = TAlignment;
  return
  {
    T::TopLeft, T::TopCenter, T::TopRight,
    T::MiddleLeft, T::MiddleCenter, T::MiddleRight,
    T::BottomLeft, T::BottomCenter, T::BottomRight
  };
}
 
inline auto TRect::CellCoordinate(TAlignment a) -> TPoint
{
  return 
  {
    IsLeft(a) ? 0 : IsCenter(a) ? 1 : 2,
    IsTop(a) ? 0 : IsMiddle(a) ? 1 : 2
  };
}
 
inline auto TRect::CellAlignment(const TPoint& cellCoordinate) -> TAlignment
{
  PRECONDITION(cellCoordinate.x >= 0 && cellCoordinate.x < 3 && cellCoordinate.y >= 0 && cellCoordinate.y < 3);
  const auto a = CellAlignments();
  const auto i = cellCoordinate.x + cellCoordinate.y * 3; CHECK(i < static_cast<int>(a.size()));
  return a[i];
}
 
//
/// Calculates the centering of this rectangle around the given point.
///
/// Usage:
///
/// \code
/// msgWindow.MoveWindow(msgWindowRect.Centered(mousePointer)); // Center message window.
/// \endcode
///
/// \returns Returns the calculation as a new rectangle.
//
inline auto owl::TRect::Centered(const TPoint& center) const -> TRect
{
  return MovedTo(center - Size() / 2);
}
 
//
/// Calculates the centering of this rectangle relative to the given rectangle.
///
/// Usage:
///
/// \code
/// msgWindow.MoveWindow(msgWindowRect.Centered(parentRect)); // Center message window.
/// \endcode
///
/// \returns Returns the calculation as a new rectangle.
//
inline auto owl::TRect::Centered(const TRect& other) const -> TRect
{
  return Centered(other.MiddleCenter());
}
 
//
/// Calculates the alignment of this rectangle at the top left within the given rectangle.
//
inline auto TRect::AlignedTopLeft(const TRect& other) const -> TRect
{
  return MovedTo(other.TopLeft());
}
 
//
/// Calculates the alignment of this rectangle at the top center within the given rectangle.
//
inline auto TRect::AlignedTopCenter(const TRect& other) const -> TRect
{
  return MovedTo(other.TopCenter() - TSize{Width() / 2, 0});
}
 
//
/// Calculates the alignment of this rectangle at the top right within the given rectangle.
//
inline auto TRect::AlignedTopRight(const TRect& other) const -> TRect
{
  return MovedTo(other.TopRight() - TSize{Width(), 0});
}
 
//
/// Calculates the alignment of this rectangle at the middle left within the given rectangle.
/// That is, the rectangle is centered vertically, while horizonally aligned at the left edges.
//
inline auto TRect::AlignedMiddleLeft(const TRect& other) const -> TRect
{
  return MovedTo(other.MiddleLeft() - TSize{0, Height() / 2});
}
 
//
/// Calculates the alignment of this rectangle in the center of the given rectangle, so that the
/// center points of the rectangles coincides.
///
/// This function is equivalent to TRect::Centered(const TRect&) const.
//
inline auto TRect::AlignedMiddleCenter(const TRect& other) const -> TRect
{
  return Centered(other);
}
 
//
/// Calculates the alignment of this rectangle at the middle right within the given rectangle.
/// That is, the rectangle is centered vertically, while horizonally aligned at the right edges.
//
inline auto TRect::AlignedMiddleRight(const TRect& other) const -> TRect
{
  return MovedTo(other.MiddleRight() - TSize{Width(), Height() / 2});
}
 
//
/// Calculates the alignment of this rectangle at the bottom left within the given rectangle.
//
inline auto TRect::AlignedBottomLeft(const TRect& other) const -> TRect
{
  return MovedTo(other.BottomLeft() - TSize{0, Height()});
}
 
//
/// Calculates the alignment of this rectangle at the bottom center within the given rectangle.
//
inline auto TRect::AlignedBottomCenter(const TRect& other) const -> TRect
{
  return MovedTo(other.BottomCenter() - TSize{Width() / 2, Height()});
}
 
//
/// Calculates the alignment of this rectangle at the bottom right within the given rectangle.
//
inline auto TRect::AlignedBottomRight(const TRect& other) const -> TRect
{
  return MovedTo(other.BottomRight() - Size());
}
 
inline auto TRect::Aligned(const TRect& other, TAlignment a) const -> TRect
{
  using T = TAlignment;
  switch (a)
  {
  case T::TopLeft: return AlignedTopLeft(other);
  case T::TopCenter: return AlignedTopCenter(other);
  case T::TopRight: return AlignedTopRight(other);
  case T::MiddleLeft: return AlignedMiddleLeft(other);
  case T::MiddleCenter: return AlignedMiddleCenter(other);
  case T::MiddleRight: return AlignedMiddleRight(other);
  case T::BottomLeft: return AlignedBottomLeft(other);
  case T::BottomCenter: return AlignedBottomCenter(other);
  case T::BottomRight: return AlignedBottomRight(other);
  default: CHECK(false); return {};
  }
}
 
inline auto TRect::IsLeft(TAlignment a) -> bool
{
  using T = TAlignment;
  return a == T::TopLeft || a == T::MiddleLeft || a == T::BottomLeft;
}
 
inline auto TRect::IsCenter(TAlignment a) -> bool
{
  using T = TAlignment;
  return a == T::TopCenter || a == T::MiddleCenter || a == T::BottomCenter;
}
 
inline auto TRect::IsRight(TAlignment a) -> bool
{
  using T = TAlignment;
  return a == T::TopRight || a == T::MiddleRight || a == T::BottomRight;
}
 
inline auto TRect::IsTop(TAlignment a) -> bool
{
  using T = TAlignment;
  return a == T::TopLeft || a == T::TopCenter || a == T::TopRight;
}
 
inline auto TRect::IsMiddle(TAlignment a) -> bool
{
  using T = TAlignment;
  return a == T::MiddleLeft || a == T::MiddleCenter || a == T::MiddleRight;
}
 
inline auto TRect::IsBottom(TAlignment a) -> bool
{
  using T = TAlignment;
  return a == T::BottomLeft || a == T::BottomCenter || a == T::BottomRight;
}
 
//
/// Makes a new rectangle expressed in normal form based on this rectangle.
///
/// A denormal rectangle will have `left > right` or `top > bottom` or both. In such cases, many
/// manipulations (such as determining width and height) become unnecessarily complicated.
/// Normalizing a rectangle means interchanging the corner point values so that `left < right` and
/// `top < bottom`. The other properties of a rectangle are unchanged by this transformation.
///
/// \returns A normalized rectangle with the top left corner at `(min(left, right),
/// min(top, bottom))` and the bottom right corner at `(max(left, right), max(top, bottom))`.
/// This rectangle remains unchanged. 
///
/// \note Many calculations assume a rectangle in normal form. Some Windows API functions behave
/// erratically if an inside-out rectangle is passed.
//
inline auto TRect::Normalized() const -> TRect
{
  return TRect
  {
    std::min(left, right), std::min(top, bottom),
    std::max(left, right), std::max(top, bottom)
  };
}
 
//
/// Returns a rectangle offset by the given delta values.
/// The returned rectangle has a top left corner at `(left + dx, top + dy)` and a right bottom
/// corner at `(right + dx, bottom + dy)`. This rectangle remains unchanged.
//
inline auto TRect::OffsetBy(int dx, int dy) const -> TRect
{
  return TRect{left + dx, top + dy, right + dx, bottom + dy};
}
 
//
/// Overload; see TRect::OffsetBy(int dx, int dy) const for more information.
//
inline auto TRect::OffsetBy(const TSize& delta) const -> TRect
{
  return OffsetBy(delta.cx, delta.cy);
}
 
//
/// Returns a rectangle with the upper left corner positioned at the given coordinate.
/// The dimensions of the rectangle are the same as this. This rectangle remains unchanged.
//
inline auto TRect::MovedTo(int x, int y) const -> TRect
{
  return TRect(x, y, x + Width(), y + Height());
}
 
//
/// Overload; see TRect::MovedTo(int x, int y) const for more information.
//
inline auto TRect::MovedTo(const TPoint& origin) const -> TRect
{
  return MovedTo(origin.x, origin.y);
}
 
//
/// Returns a rectangle inflated by the given delta values.
/// The top left corner of the returned rectangle is `(left - dx, top - dy)`, while its bottom 
/// right corner is `(right + dx, bottom + dy)`. This rectangle remains unchanged.
//
inline auto TRect::InflatedBy(int dx, int dy) const -> TRect
{
  return TRect{left - dx, top - dy, right + dx, bottom + dy};
}
 
//
/// Overload; see TRect::InflatedBy(int dx, int dy) const for more information.
//
inline auto TRect::InflatedBy(const TSize& delta) const -> TRect
{
  return InflatedBy(delta.cx, delta.cy);
}
 
//
/// Equivalent to `r.InflatedBy(-dx, -dy)`.
/// See TRect::InflatedBy(int dx, int dy) const for more information.
//
inline auto TRect::DeflatedBy(int dx, int dy) const -> TRect
{
  return InflatedBy(-dx, -dy);
}
 
//
/// Overload; see TRect::DeflatedBy(int dx, int dy) const for more information.
//
inline auto TRect::DeflatedBy(const TSize& delta) const -> TRect
{
  return DeflatedBy(delta.cx, delta.cy);
}
 
inline auto TRect::GrownUpBy(int delta) const -> TRect
{
  return {left, top - delta, right, bottom};
}
 
inline auto TRect::GrownLeftBy(int delta) const -> TRect
{
  return {left - delta, top, right, bottom};
}
 
inline auto TRect::GrownRightBy(int delta) const -> TRect
{
  return {left, top, right + delta, bottom};
}
 
inline auto TRect::GrownDownBy(int delta) const -> TRect
{
  return {left, top, right, bottom + delta};
}
 
inline auto TRect::GrownUpLeftBy(const TSize& delta) const -> TRect
{
  return GrownUpBy(delta.cy).GrownLeftBy(delta.cx);
}
 
inline auto TRect::GrownUpRightBy(const TSize& delta) const -> TRect
{
  return GrownUpBy(delta.cy).GrownRightBy(delta.cx);
}
 
inline auto TRect::GrownDownLeftBy(const TSize& delta) const -> TRect
{
  return GrownDownBy(delta.cy).GrownLeftBy(delta.cx);
}
 
inline auto TRect::GrownDownRightBy(const TSize& delta) const -> TRect
{
  return GrownDownBy(delta.cy).GrownRightBy(delta.cx);
}
 
inline auto TRect::GrownBy(int delta, TAlignment direction) const -> TRect
{
  using T = TAlignment;
  switch (direction)
  {
  case T::TopLeft: return GrownUpLeftBy({delta, delta});
  case T::TopCenter: return GrownUpBy(delta);
  case T::TopRight: return GrownUpRightBy({delta, delta});
  case T::MiddleLeft: return GrownLeftBy(delta);
  case T::MiddleCenter: return InflatedBy({delta, delta});
  case T::MiddleRight: return GrownRightBy(delta);
  case T::BottomLeft: return GrownDownLeftBy({delta, delta});
  case T::BottomCenter: return GrownDownBy(delta);
  case T::BottomRight: return GrownDownRightBy({delta, delta});
  default: CHECK(false); return *this;
  }
}
 
inline auto TRect::GrownBy(const TSize& delta, TAlignment direction) const -> TRect
{
  using T = TAlignment;
  switch (direction)
  {
  case T::TopLeft: return GrownUpLeftBy(delta);
  case T::TopRight: return GrownUpRightBy(delta);
  case T::MiddleCenter: return InflatedBy(delta);
  case T::BottomLeft: return GrownDownLeftBy(delta);
  case T::BottomRight: return GrownDownRightBy(delta);
  default: CHECK(false); return *this;
  }
}
 
//
/// Returns a rectangle offset positively by the given delta.
/// The returned rectangle has a top left corner at `(left + delta.cx, top + delta.cy)` and a right
/// bottom corner at `(right + delta.cx, bottom + delta.cy)`. This rectangle remains unchanged.
//
inline auto TRect::operator +(const TSize& delta) const -> TRect
{
  return OffsetBy(delta.cx, delta.cy);
}
 
//
/// Returns a rectangle offset negatively by the given delta.
/// The returned rectangle has a top left corner at `(left - delta.cx, top - delta.cy)` and a right
/// bottom corner at (right - delta.cx, bottom - delta.cy). This rectangle remains unchanged.
//
inline auto TRect::operator -(const TSize& delta) const -> TRect
{
  return OffsetBy(-delta.cx, -delta.cy);
}
 
//
/// Forms the intersection of this rectangle and the given rectangle.
/// Both rectangles remain unchanged.
///
/// \returns If the two rectangles do not intersect (this is determined by a call to
/// TRect::Touches), the default (null) rectangle is returned. Otherwise, the intersection is
/// calculated and returned.
///
/// \note Both rectangles are assumed to be in normal form, i.e. `left <= right` and
/// `top <= bottom`. Call TRect::Normalized (non-mutating) or TRect::Normalize (mutating) to
/// normalize the rectangles before calling this function.
//
inline auto TRect::operator &(const TRect& other) const -> TRect
{
  return !Touches(other) ? TRect{} : TRect
  {
    std::max(left, other.left), std::max(top, other.top),
    std::min(right, other.right), std::min(bottom, other.bottom)
  };
}
 
//
/// Forms the bounding box of this rectangle and the given rectangle.
/// Both rectangles remain unchanged.
///
/// \returns If either rectangle is empty, the other is returned, unless both are empty, in which
/// case the default (null) rectangle is returned. If both rectangles are non-empty, the
/// bounding box is calculated and returned.
///
/// \note Both rectangles are assumed to be in normal form, i.e. `left <= right` and
/// `top <= bottom`. Call TRect::Normalized (non-mutating) or TRect::Normalize (mutating) to
/// normalize the rectangles before calling this function.
//
inline auto TRect::operator |(const TRect& other) const -> TRect
{
  return other.IsEmpty() ? (IsEmpty() ? TRect{} : *this) :
    IsEmpty() ? other :
    TRect
  {
    std::min(left, other.left), std::min(top, other.top),
    std::max(right, other.right), std::max(bottom, other.bottom)
  };
}
 
//
/// Equivalent to `r = r.Normalized()`.
/// See TRect::Normalized() const for more information.
//
inline auto TRect::Normalize() -> TRect&
{
  if (left > right)
    std::swap(left, right);
  if (top > bottom)
    std::swap(top, bottom);
  CHECK(IsNormal());
  return *this;
}
 
//
/// Equivalent to `r = r.OffsetBy()`.
/// See TRect::OffsetBy(int dx, int dy) const for more information.
//
inline auto TRect::Offset(int dx, int dy) -> TRect&
{
  left += dx;
  top += dy;
  right += dx;
  bottom += dy;
  return *this;
}
 
//
/// Overload; see TRect::Offset(int dx, int dy) for more information.
//
inline auto TRect::Offset(const TSize& delta) -> TRect&
{
  return Offset(delta.cx, delta.cy);
}
 
//
/// Equivalent to `r = r.MovedTo(x, y)`.
/// See TRect::MovedTo(int x, int y) const for more information.
//
inline auto TRect::MoveTo(int x, int y) -> TRect&
{
  right = x + Width();
  bottom = y + Height();
  left = x;
  top = y;
  return *this;
}
 
//
/// Overload; see TRect::MoveTo(int x, int y) for more information.
//
inline auto TRect::MoveTo(const TPoint& origin) -> TRect&
{
  return MoveTo(origin.x, origin.y);
}
 
//
/// Equivalent to `r = r.InflatedBy(dx, dy)`.
/// See TRect::InflatedBy(int dx, int dy) const for more information.
//
inline auto TRect::Inflate(int dx, int dy) -> TRect&
{
  left -= dx;
  top -= dy;
  right += dx;
  bottom += dy;
  return *this;
}
 
//
/// Overload; see TRect::Inflate(int dx, int dy) for more information.
//
inline auto TRect::Inflate(const TSize& delta) -> TRect&
{
  return Inflate(delta.cx, delta.cy);
}
 
//
/// Equivalent to `r.Inflate(-dx, -dy)`.
/// See TRect::Inflate(int dx, int dy) for more information.
//
inline auto TRect::Deflate(int dx, int dy) -> TRect&
{
  return Inflate(-dx, -dy);
}
 
//
/// Overload; see TRect::Deflate(int dx, int dy) for more information.
//
inline auto TRect::Deflate(const TSize& delta) -> TRect&
{
  return Deflate(delta.cx, delta.cy);
}
 
inline auto TRect::GrowUp(int delta) -> TRect&
{
  return top -= delta, *this;
}
 
inline auto TRect::GrowLeft(int delta) -> TRect&
{
  return left -= delta, *this;
}
 
inline auto TRect::GrowRight(int delta) -> TRect&
{
  return right += delta, *this;
}
 
inline auto TRect::GrowDown(int delta) -> TRect&
{
  return bottom += delta, *this;
}
 
inline auto TRect::GrowUpLeft(const TSize& delta) -> TRect&
{
  return GrowUp(delta.cy), GrowLeft(delta.cx), *this;
}
 
inline auto TRect::GrowUpRight(const TSize& delta) -> TRect&
{
  return GrowUp(delta.cy), GrowRight(delta.cx), *this;
}
 
inline auto TRect::GrowDownLeft(const TSize& delta) -> TRect&
{
  return GrowDown(delta.cy), GrowLeft(delta.cx), *this;
}
 
inline auto TRect::GrowDownRight(const TSize& delta) -> TRect&
{
  return GrowDown(delta.cy), GrowRight(delta.cx), *this;
}
 
inline auto TRect::Grow(int delta, TAlignment direction) -> TRect&
{
  using T = TAlignment;
  switch (direction)
  {
  case T::TopLeft: return GrowUpLeft({delta, delta});
  case T::TopCenter: return GrowUp(delta);
  case T::TopRight: return GrowUpRight({delta, delta});
  case T::MiddleLeft: return GrowLeft(delta);
  case T::MiddleCenter: return Inflate({delta, delta});
  case T::MiddleRight: return GrowRight(delta);
  case T::BottomLeft: return GrowDownLeft({delta, delta});
  case T::BottomCenter: return GrowDown(delta);
  case T::BottomRight: return GrowDownRight({delta, delta});
  default: CHECK(false); return *this;
  }
}
 
inline auto TRect::Grow(const TSize& delta, TAlignment direction) -> TRect&
{
  using T = TAlignment;
  switch (direction)
  {
  case T::TopLeft: return GrowUpLeft(delta);
  case T::TopRight: return GrowUpRight(delta);
  case T::MiddleCenter: return Inflate(delta);
  case T::BottomLeft: return GrowDownLeft(delta);
  case T::BottomRight: return GrowDownRight(delta);
  default: CHECK(false); return *this;
  }
}
 
//
/// Equivalent to `r = r + delta`.
/// See TRect::operator +(const TSize&) const for more information.
//
inline auto TRect::operator +=(const TSize& delta) -> TRect&
{
  Offset(delta.cx, delta.cy);
  return *this;
}
 
//
/// Equivalent to `r = r - delta`.
/// See TRect::operator -(const TSize&) const for more information.
//
inline auto TRect::operator -=(const TSize& delta) -> TRect&
{
  return *this += -delta;
}
 
//
/// Equivalent to `r = r & other`.
/// See TRect::operator &(const TRect& other) const for more information.
//
inline auto TRect::operator &=(const TRect& other) -> TRect&
{
  return operator=(*this & other);
}
 
//
/// Equivalent to `r = r | other`.
/// See TRect::operator |(const TRect& other) const for more information.
//
inline auto TRect::operator |=(const TRect& other) -> TRect&
{
  return operator=(*this | other);
}
 
//----------------------------------------------------------------------------
// TSize
//
 
//
/// Default constructor that does nothing.
//
inline
TSize::TSize()
{
  cx  = 0;
  cy  = 0;
}
 
//
/// Creates a TSize object with cx = dx and cy = dy.
//
inline
TSize::TSize(int dx, int dy)
{
  cx = dx;
  cy = dy;
}
 
//
/// Creates a TSize object with cx = point.x and cy = point.y.
//
inline
TSize::TSize(const tagPOINT & point)
{
  cx = point.x;
  cy = point.y;
}
 
//
/// Creates a TSize object with cx = size.cx and cy = size.cy.
//
inline
TSize::TSize(const tagSIZE & size)
{
  cx = size.cx;
  cy = size.cy;
}
 
//
/// Creates a TSize object with cx = size.cx and cy = size.cy.
//
inline
TSize::TSize(const TSize & size)
{
  cx = size.cx;
  cy = size.cy;
}
 
#if defined(OWL5_COMPAT)
 
//
/// Creates a size by extracting the unsigned 16-bit extents from the given argument.
///
/// \deprecated Use TSize::CreateFromPackedExtents instead.
//
inline
TSize::TSize(DWORD packedExtents)
  : TSize{CreateFromPackedExtents(packedExtents)}
{}
 
#endif
 
//
/// Creates a size by extracting the unsigned 16-bit extents from the given argument.
///
/// The low-order 16 bits of the given argument should contain the horizontal extent, and the next
/// 16 bits should contain the vertical extent. The extents should be encoded as unsigned short
/// integers.
//
inline auto TSize::CreateFromPackedExtents(LPARAM packedExtents) -> TSize
{
  return {LOWORD(packedExtents), HIWORD(packedExtents)};
}
 
//
/// Creates a TSize with same extent in both dimensions.
//
inline auto TSize::Square(int side) -> TSize
{
  return {side, side};
}
 
//
/// Returns the width.
//
inline int
TSize::X() const
{
  return cx;
}
 
//
/// Returns the height.
//
inline int
TSize::Y() const
{
  return cy;
}
 
//
/// Returns the TSize object (-cx, -cy). This object is not changed.
//
inline TSize
TSize::operator -() const
{
  return TSize(-cx, -cy);
}
 
//
/// Returns true if this TSize object is equal to the other TSize object; otherwise
/// returns false.
//
inline bool
TSize::operator ==(const TSize& other) const
{
  return ToBool(other.cx==cx && other.cy==cy);
}
 
//
/// Returns false if this TSize object is equal to the other TSize object; otherwise
/// returns true.
//
inline bool
TSize::operator !=(const TSize& other) const
{
  return ToBool(other.cx!=cx || other.cy!=cy);
}
 
//
/// Returns the area of a rectangle of this size.
//
inline auto TSize::Area() const -> int
{
  return TRect{{}, *this}.Area();
}
 
//
/// Calculates an offset to this TSize object using the given size argument as the
/// displacement. Returns the object (cx + size.cx, cy + size.cy). This TSize object
/// is not changed.
//
inline TSize
TSize::operator +(const TSize& size) const
{
  return TSize(cx+size.cx, cy+size.cy);
}
 
//
/// Calculates a negative offset to this TSize object using the given size argument
/// as the displacement. Returns the point (cx - size.cx, cy - size.cy). This object
/// is not changed.
//
inline TSize
TSize::operator -(const TSize& size) const
{
  return TSize(cx-size.cx, cy-size.cy);
}
 
//
/// Offsets this TSize object by the given size argument. This TSize object is
/// changed to (cx + size.cx, cy + size.cy). Returns a reference to this object.
//
inline TSize&
TSize::operator +=(const TSize& size)
{
  cx += size.cx;
  cy += size.cy;
  return *this;
}
 
//
/// Negatively offsets this TSize object by the given size argument. This object is
/// changed to (cx - size.cx, cy - size.cy). Returns a reference to this object.
//
inline TSize&
TSize::operator -=(const TSize& size)
{
  cx -= size.cx;
  cy -= size.cy;
  return *this;
}
 
inline _OWLCFUNC(auto) operator *(int f, const TSize& s) -> TSize
{ return {f * s.X(), f * s.Y()}; }
 
inline _OWLCFUNC(auto) operator *(const TSize& s, int f) -> TSize
{ return f * s; }
 
inline _OWLCFUNC(auto) operator /(const TSize& s, int d) -> TSize
{ return {s.X() / d, s.Y() / d}; }
 
template <class T>
inline _OWLCFUNC(auto) operator *(T f, const TSize& s) -> TSize
{ return {static_cast<int>(std::lround(f * s.X())), static_cast<int>(std::lround(f * s.Y()))}; }
 
template <class T>
inline _OWLCFUNC(auto) operator *(const TSize& s, T f) -> TSize
{ return f * s; }
 
template <class T>
inline _OWLCFUNC(auto) operator /(const TSize& s, T d) -> TSize
{ return {static_cast<int>(std::lround(s.X() / d)), static_cast<int>(std::lround(s.Y() / d))}; }
 
} // OWL namespace
 
#endif  // OWL_GEOMETRY_H

V524 It is odd that the body of '+' function is fully equivalent to the body of 'OffsetBy' function.

V550 An odd precise comparison: other.x == x. It's probably better to use a comparison with defined precision: fabs(A - B) < Epsilon.

V550 An odd precise comparison: other.y == y. It's probably better to use a comparison with defined precision: fabs(A - B) < Epsilon.

V550 An odd precise comparison: other.x != x. It's probably better to use a comparison with defined precision: fabs(A - B) > Epsilon.

V550 An odd precise comparison: other.y != y. It's probably better to use a comparison with defined precision: fabs(A - B) > Epsilon.