summaryrefslogtreecommitdiff
path: root/src/libcamera/geometry.cpp
diff options
context:
space:
mode:
authorDavid Plowman <david.plowman@raspberrypi.com>2020-10-26 17:19:06 +0000
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-10-27 00:51:59 +0200
commit63624bc85a5f765dc3899d4b3b72ad875894ca04 (patch)
tree49d56f3e509bd5608fcc3ae3c7b7c4e8fa3d197e /src/libcamera/geometry.cpp
parenta16edeb3848c6e6693bfaa24c5eb1744c5d9c445 (diff)
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>
Diffstat (limited to 'src/libcamera/geometry.cpp')
-rw-r--r--src/libcamera/geometry.cpp334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp
index b12e1a62..13644689 100644
--- a/src/libcamera/geometry.cpp
+++ b/src/libcamera/geometry.cpp
@@ -10,6 +10,8 @@
#include <sstream>
#include <stdint.h>
+#include "libcamera/internal/log.h"
+
/**
* \file geometry.h
* \brief Data structures related to geometric objects
@@ -18,6 +20,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
*
@@ -144,6 +210,117 @@ const std::string Size::toString() const
*/
/**
+ * \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 &center) 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
*/
@@ -366,6 +543,13 @@ bool operator==(const SizeRange &lhs, const SizeRange &rhs)
*/
/**
+ * \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
*/
@@ -405,6 +589,156 @@ const std::string Rectangle::toString() const
}
/**
+ * \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
*/