libcamera: Add geometry helper functions
These functions are aimed at making it easier to calculate cropping rectangles, particularly in order to implement digital zoom. Signed-off-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
committed by
Laurent Pinchart
parent
a16edeb384
commit
63624bc85a
@@ -13,6 +13,38 @@
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
class Rectangle;
|
||||
|
||||
class Point
|
||||
{
|
||||
public:
|
||||
constexpr Point()
|
||||
: x(0), y(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Point(int xpos, int ypos)
|
||||
: x(xpos), y(ypos)
|
||||
{
|
||||
}
|
||||
|
||||
int x;
|
||||
int y;
|
||||
|
||||
const std::string toString() const;
|
||||
|
||||
constexpr Point operator-() const
|
||||
{
|
||||
return { -x, -y };
|
||||
}
|
||||
};
|
||||
|
||||
bool operator==(const Point &lhs, const Point &rhs);
|
||||
static inline bool operator!=(const Point &lhs, const Point &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
class Size
|
||||
{
|
||||
public:
|
||||
@@ -93,6 +125,17 @@ public:
|
||||
std::max(height, expand.height)
|
||||
};
|
||||
}
|
||||
|
||||
Size boundedToAspectRatio(const Size &ratio) const;
|
||||
Size expandedToAspectRatio(const Size &ratio) const;
|
||||
|
||||
Rectangle centeredTo(const Point ¢er) const;
|
||||
|
||||
Size operator*(float factor) const;
|
||||
Size operator/(float factor) const;
|
||||
|
||||
Size &operator*=(float factor);
|
||||
Size &operator/=(float factor);
|
||||
};
|
||||
|
||||
bool operator==(const Size &lhs, const Size &rhs);
|
||||
@@ -176,6 +219,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
constexpr explicit Rectangle(const Size &size)
|
||||
: x(0), y(0), width(size.width), height(size.height)
|
||||
{
|
||||
}
|
||||
|
||||
int x;
|
||||
int y;
|
||||
unsigned int width;
|
||||
@@ -183,6 +231,26 @@ public:
|
||||
|
||||
bool isNull() const { return !width && !height; }
|
||||
const std::string toString() const;
|
||||
|
||||
Point center() const;
|
||||
|
||||
Size size() const
|
||||
{
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
Point topLeft() const
|
||||
{
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
Rectangle &scaleBy(const Size &numerator, const Size &denominator);
|
||||
Rectangle &translateBy(const Point &point);
|
||||
|
||||
Rectangle boundedTo(const Rectangle &bound) const;
|
||||
Rectangle enclosedIn(const Rectangle &boundary) const;
|
||||
Rectangle scaledBy(const Size &numerator, const Size &denominator) const;
|
||||
Rectangle translatedBy(const Point &point) const;
|
||||
};
|
||||
|
||||
bool operator==(const Rectangle &lhs, const Rectangle &rhs);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libcamera/internal/log.h"
|
||||
|
||||
/**
|
||||
* \file geometry.h
|
||||
* \brief Data structures related to geometric objects
|
||||
@@ -17,6 +19,70 @@
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
/**
|
||||
* \class Point
|
||||
* \brief Describe a point in two-dimensional space
|
||||
*
|
||||
* The Point structure defines a point in two-dimensional space with integer
|
||||
* precision. The coordinates of a Point may be negative as well as positive.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn Point::Point()
|
||||
* \brief Construct a Point with x and y set to 0
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn Point::Point(int xpos, int ypos)
|
||||
* \brief Construct a Point at given \a xpos and \a ypos values
|
||||
* \param[in] xpos The x-coordinate
|
||||
* \param[in] ypos The y-coordinate
|
||||
*/
|
||||
|
||||
/**
|
||||
* \var Point::x
|
||||
* \brief The x-coordinate of the Point
|
||||
*/
|
||||
|
||||
/**
|
||||
* \var Point::y
|
||||
* \brief The y-coordinate of the Point
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Assemble and return a string describing the point
|
||||
* \return A string describing the point
|
||||
*/
|
||||
const std::string Point::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "(" << x << "," << y << ")";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn Point Point::operator-() const
|
||||
* \brief Negate a Point by negating both its x and y coordinates
|
||||
* \return The negated point
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Compare points for equality
|
||||
* \return True if the two points are equal, false otherwise
|
||||
*/
|
||||
bool operator==(const Point &lhs, const Point &rhs)
|
||||
{
|
||||
return lhs.x == rhs.x && lhs.y == rhs.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn bool operator!=(const Point &lhs, const Point &rhs)
|
||||
* \brief Compare points for inequality
|
||||
* \return True if the two points are not equal, false otherwise
|
||||
*/
|
||||
|
||||
/**
|
||||
* \struct Size
|
||||
* \brief Describe a two-dimensional size
|
||||
@@ -143,6 +209,117 @@ const std::string Size::toString() const
|
||||
* height of this size and the \a expand size
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Bound the size down to match the aspect ratio given by \a ratio
|
||||
* \param[in] ratio The size whose aspect ratio must be matched
|
||||
*
|
||||
* The behaviour of this function is undefined if either the width or the
|
||||
* height of the \a ratio is zero.
|
||||
*
|
||||
* \return A Size whose width and height are equal to the width and height
|
||||
* of this Size aligned down to the aspect ratio of \a ratio
|
||||
*/
|
||||
Size Size::boundedToAspectRatio(const Size &ratio) const
|
||||
{
|
||||
ASSERT(ratio.width && ratio.height);
|
||||
|
||||
uint64_t ratio1 = static_cast<uint64_t>(width) *
|
||||
static_cast<uint64_t>(ratio.height);
|
||||
uint64_t ratio2 = static_cast<uint64_t>(ratio.width) *
|
||||
static_cast<uint64_t>(height);
|
||||
|
||||
if (ratio1 > ratio2)
|
||||
return { static_cast<unsigned int>(ratio2 / ratio.height), height };
|
||||
else
|
||||
return { width, static_cast<unsigned int>(ratio1 / ratio.width) };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Expand the size to match the aspect ratio given by \a ratio
|
||||
* \param[in] ratio The size whose aspect ratio must be matched
|
||||
*
|
||||
* The behaviour of this function is undefined if either the width or the
|
||||
* height of the \a ratio is zero.
|
||||
*
|
||||
* \return A Size whose width and height are equal to the width and height
|
||||
* of this Size expanded up to the aspect ratio of \a ratio
|
||||
*/
|
||||
Size Size::expandedToAspectRatio(const Size &ratio) const
|
||||
{
|
||||
ASSERT(ratio.width && ratio.height);
|
||||
|
||||
uint64_t ratio1 = static_cast<uint64_t>(width) *
|
||||
static_cast<uint64_t>(ratio.height);
|
||||
uint64_t ratio2 = static_cast<uint64_t>(ratio.width) *
|
||||
static_cast<uint64_t>(height);
|
||||
|
||||
if (ratio1 < ratio2)
|
||||
return { static_cast<unsigned int>(ratio2 / ratio.height), height };
|
||||
else
|
||||
return { width, static_cast<unsigned int>(ratio1 / ratio.width) };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Center a rectangle of this size at a given Point
|
||||
* \param[in] center The center point the Rectangle is to have
|
||||
*
|
||||
* A Rectangle of this object's size is positioned so that its center
|
||||
* is at the given Point.
|
||||
*
|
||||
* \return A Rectangle of this size, centered at the given Point.
|
||||
*/
|
||||
Rectangle Size::centeredTo(const Point ¢er) const
|
||||
{
|
||||
int x = center.x - width / 2;
|
||||
int y = center.y - height / 2;
|
||||
|
||||
return { x, y, width, height };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Scale size up by the given factor
|
||||
* \param[in] factor The factor
|
||||
* \return The scaled Size
|
||||
*/
|
||||
Size Size::operator*(float factor) const
|
||||
{
|
||||
return Size(width * factor, height * factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Scale size down by the given factor
|
||||
* \param[in] factor The factor
|
||||
* \return The scaled Size
|
||||
*/
|
||||
Size Size::operator/(float factor) const
|
||||
{
|
||||
return Size(width / factor, height / factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Scale this size up by the given factor in place
|
||||
* \param[in] factor The factor
|
||||
* \return A reference to this object
|
||||
*/
|
||||
Size &Size::operator*=(float factor)
|
||||
{
|
||||
width *= factor;
|
||||
height *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Scale this size down by the given factor in place
|
||||
* \param[in] factor The factor
|
||||
* \return A reference to this object
|
||||
*/
|
||||
Size &Size::operator/=(float factor)
|
||||
{
|
||||
width /= factor;
|
||||
height /= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Compare sizes for equality
|
||||
* \return True if the two sizes are equal, false otherwise
|
||||
@@ -365,6 +542,13 @@ bool operator==(const SizeRange &lhs, const SizeRange &rhs)
|
||||
* \param[in] height The height
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn Rectangle::Rectangle(const Size &size)
|
||||
* \brief Construct a Rectangle of \a size with its top left corner located
|
||||
* at (0,0)
|
||||
* \param[in] size The desired Rectangle size
|
||||
*/
|
||||
|
||||
/**
|
||||
* \var Rectangle::x
|
||||
* \brief The horizontal coordinate of the rectangle's top-left corner
|
||||
@@ -404,6 +588,156 @@ const std::string Rectangle::toString() const
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieve the center point of this rectangle
|
||||
* \return The center Point
|
||||
*/
|
||||
Point Rectangle::center() const
|
||||
{
|
||||
return { x + static_cast<int>(width / 2), y + static_cast<int>(height / 2) };
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn Size Rectangle::size() const
|
||||
* \brief Retrieve the size of this rectangle
|
||||
* \return The Rectangle size
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn Point Rectangle::topLeft() const
|
||||
* \brief Retrieve the coordinates of the top left corner of this Rectangle
|
||||
* \return The Rectangle's top left corner
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Apply a non-uniform rational scaling in place to this Rectangle
|
||||
* \param[in] numerator The numerators of the x and y scaling factors
|
||||
* \param[in] denominator The denominators of the x and y scaling factors
|
||||
*
|
||||
* A non-uniform scaling is applied in place such the resulting x
|
||||
* coordinates are multiplied by numerator.width / denominator.width,
|
||||
* and similarly for the y coordinates (using height in place of width).
|
||||
*
|
||||
* \return A reference to this object
|
||||
*/
|
||||
Rectangle &Rectangle::scaleBy(const Size &numerator, const Size &denominator)
|
||||
{
|
||||
x = static_cast<int64_t>(x) * numerator.width / denominator.width;
|
||||
y = static_cast<int64_t>(y) * numerator.height / denominator.height;
|
||||
width = static_cast<uint64_t>(width) * numerator.width / denominator.width;
|
||||
height = static_cast<uint64_t>(height) * numerator.height / denominator.height;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Translate this Rectangle in place by the given Point
|
||||
* \param[in] point The amount to translate the Rectangle by
|
||||
*
|
||||
* The Rectangle is translated in the x-direction by the point's x coordinate
|
||||
* and in the y-direction by the point's y coordinate.
|
||||
*
|
||||
* \return A reference to this object
|
||||
*/
|
||||
Rectangle &Rectangle::translateBy(const Point &point)
|
||||
{
|
||||
x += point.x;
|
||||
y += point.y;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Calculate the intersection of this Rectangle with another
|
||||
* \param[in] bound The Rectangle that is intersected with this Rectangle
|
||||
*
|
||||
* This method calculates the standard intersection of two rectangles. If the
|
||||
* rectangles do not overlap in either the x or y direction, then the size
|
||||
* of that dimension in the result (its width or height) is set to zero. Even
|
||||
* when one dimension is set to zero, note that the other dimension may still
|
||||
* have a positive value if there was some overlap.
|
||||
*
|
||||
* \return A Rectangle that is the intersection of the input rectangles
|
||||
*/
|
||||
Rectangle Rectangle::boundedTo(const Rectangle &bound) const
|
||||
{
|
||||
int topLeftX = std::max(x, bound.x);
|
||||
int topLeftY = std::max(y, bound.y);
|
||||
int bottomRightX = std::min<int>(x + width, bound.x + bound.width);
|
||||
int bottomRightY = std::min<int>(y + height, bound.y + bound.height);
|
||||
|
||||
unsigned int newWidth = std::max(bottomRightX - topLeftX, 0);
|
||||
unsigned int newHeight = std::max(bottomRightY - topLeftY, 0);
|
||||
|
||||
return { topLeftX, topLeftY, newWidth, newHeight };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enclose a Rectangle so as not to exceed another Rectangle
|
||||
* \param[in] boundary The limit that the returned Rectangle will not exceed
|
||||
*
|
||||
* The Rectangle is modified so that it does not exceed the given \a boundary.
|
||||
* This process involves translating the Rectangle if any of its edges
|
||||
* lie beyond \a boundary, so that those edges then lie along the boundary
|
||||
* instead.
|
||||
*
|
||||
* If either width or height are larger than \a boundary, then the returned
|
||||
* Rectangle is clipped to be no larger. But other than this, the
|
||||
* Rectangle is not clipped or reduced in size, merely translated.
|
||||
*
|
||||
* Note that this is not a conventional Rectangle intersection function
|
||||
* which is provided by boundedTo().
|
||||
*
|
||||
* \return A Rectangle that does not extend beyond a boundary Rectangle
|
||||
*/
|
||||
Rectangle Rectangle::enclosedIn(const Rectangle &boundary) const
|
||||
{
|
||||
/* We can't be bigger than the boundary rectangle. */
|
||||
Rectangle result = boundedTo(Rectangle{ x, y, boundary.size() });
|
||||
|
||||
result.x = std::clamp<int>(result.x, boundary.x,
|
||||
boundary.x + boundary.width - result.width);
|
||||
result.y = std::clamp<int>(result.y, boundary.y,
|
||||
boundary.y + boundary.height - result.height);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Apply a non-uniform rational scaling to this Rectangle
|
||||
* \param[in] numerator The numerators of the x and y scaling factors
|
||||
* \param[in] denominator The denominators of the x and y scaling factors
|
||||
*
|
||||
* A non-uniform scaling is applied such the resulting x
|
||||
* coordinates are multiplied by numerator.width / denominator.width,
|
||||
* and similarly for the y coordinates (using height in place of width).
|
||||
*
|
||||
* \return The non-uniformly scaled Rectangle
|
||||
*/
|
||||
Rectangle Rectangle::scaledBy(const Size &numerator, const Size &denominator) const
|
||||
{
|
||||
int scaledX = static_cast<int64_t>(x) * numerator.width / denominator.width;
|
||||
int scaledY = static_cast<int64_t>(y) * numerator.height / denominator.height;
|
||||
unsigned int scaledWidth = static_cast<uint64_t>(width) * numerator.width / denominator.width;
|
||||
unsigned int scaledHeight = static_cast<uint64_t>(height) * numerator.height / denominator.height;
|
||||
|
||||
return { scaledX, scaledY, scaledWidth, scaledHeight };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Translate a Rectangle by the given amounts
|
||||
* \param[in] point The amount to translate the Rectangle by
|
||||
*
|
||||
* The Rectangle is translated in the x-direction by the point's x coordinate
|
||||
* and in the y-direction by the point's y coordinate.
|
||||
*
|
||||
* \return The translated Rectangle
|
||||
*/
|
||||
Rectangle Rectangle::translatedBy(const Point &point) const
|
||||
{
|
||||
return { x + point.x, y + point.y, width, height };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Compare rectangles for equality
|
||||
* \return True if the two rectangles are equal, false otherwise
|
||||
|
||||
Reference in New Issue
Block a user