// Copyright (c) Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Math/Rectangle.h"
///
/// Represents a rectangle that has been transformed by an arbitrary render transform.
///
struct RotatedRectangle
{
public:
///
/// The transformed top left corner.
///
Float2 TopLeft;
///
/// The transformed X extent (right-left).
///
Float2 ExtentX;
///
/// The transformed Y extent (bottom-top).
///
Float2 ExtentY;
public:
///
/// Initializes a new instance of the struct.
///
RotatedRectangle()
{
}
///
/// Initializes a new instance of the struct.
///
/// The aligned rectangle.
explicit RotatedRectangle(const Rectangle& rect)
: TopLeft(rect.GetUpperLeft())
, ExtentX(rect.GetWidth(), 0.0f)
, ExtentY(0.0f, rect.GetHeight())
{
}
///
/// Initializes a new instance of the struct.
///
/// The top left corner.
/// The extent on X axis.
/// The extent on Y axis.
RotatedRectangle(const Float2& topLeft, const Float2& extentX, const Float2& extentY)
: TopLeft(topLeft)
, ExtentX(extentX)
, ExtentY(extentY)
{
}
public:
///
/// Convert rotated rectangle to the axis-aligned rectangle that builds rotated rectangle bounding box.
///
/// The bounds rectangle.
Rectangle ToBoundingRect() const
{
Float2 points[4] =
{
TopLeft,
TopLeft + ExtentX,
TopLeft + ExtentY,
TopLeft + ExtentX + ExtentY
};
return Rectangle::FromPoints(points, 4);
}
///
/// Determines whether the specified location is contained within this rotated rectangle.
///
/// The location to test.
/// true if the specified location is contained by this rotated rectangle; otherwise, false.
bool ContainsPoint(const Float2& location) const
{
const Float2 offset = location - TopLeft;
const float det = Float2::Cross(ExtentX, ExtentY);
const float s = Float2::Cross(offset, ExtentX) / -det;
if (Math::IsInRange(s, 0.0f, 1.0f))
{
const float t = Float2::Cross(offset, ExtentY) / det;
return Math::IsInRange(t, 0.0f, 1.0f);
}
return false;
}
///
/// Calculates a rectangle that contains the shared part of both rectangles.
///
/// The first rectangle.
/// The second rectangle.
/// Rectangle that contains shared part of a and b rectangles.
static RotatedRectangle Shared(const RotatedRectangle& a, const Rectangle& b)
{
// Clip the rotated rectangle bounds within the given AABB
RotatedRectangle result = a;
result.TopLeft = Float2::Max(a.TopLeft, b.GetTopLeft());
// TODO: do a little better math below (in case of actually rotated rectangle)
result.ExtentX.X = Math::Min(result.TopLeft.X + result.ExtentX.X, b.GetRight()) - result.TopLeft.X;
result.ExtentY.Y = Math::Min(result.TopLeft.Y + result.ExtentY.Y, b.GetBottom()) - result.TopLeft.Y;
return result;
}
public:
bool operator ==(const RotatedRectangle& other) const
{
return
TopLeft == other.TopLeft &&
ExtentX == other.ExtentX &&
ExtentY == other.ExtentY;
}
};
template<>
struct TIsPODType
{
enum { Value = true };
};