Message ID | 20200922100400.30766-5-david.plowman@raspberrypi.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi David, On Tue, Sep 22, 2020 at 11:03:58AM +0100, David Plowman wrote: > 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> > --- > include/libcamera/geometry.h | 20 ++++++ > src/libcamera/geometry.cpp | 131 +++++++++++++++++++++++++++++++++++ > 2 files changed, 151 insertions(+) > > diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h > index 02fb63c..0447ee3 100644 > --- a/include/libcamera/geometry.h > +++ b/include/libcamera/geometry.h > @@ -13,6 +13,8 @@ > > namespace libcamera { > > +class Rectangle; > + > class Size > { > public: > @@ -93,8 +95,17 @@ public: > std::max(height, expand.height) > }; > } > + > + Size alignedDownToAspectRatio(const Size &ratio) const; > + Size alignedUpToAspectRatio(const Size &ratio) const; > + > + Rectangle centredTo(const Rectangle ®ion, > + int offsetX = 0, int offsetY = 0) const; > }; > > +Size operator*(const Size &size, float f); > +Size operator/(const Size &size, float f); > + > bool operator==(const Size &lhs, const Size &rhs); > bool operator<(const Size &lhs, const Size &rhs); > > @@ -176,6 +187,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 +199,10 @@ public: > > bool isNull() const { return !width && !height; } > const std::string toString() const; > + > + Size size() const; > + > + Rectangle boundedTo(const Rectangle &boundary) const; > }; > > bool operator==(const Rectangle &lhs, const Rectangle &rhs); > diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp > index b12e1a6..0c058dd 100644 > --- a/src/libcamera/geometry.cpp > +++ b/src/libcamera/geometry.cpp > @@ -143,6 +143,90 @@ const std::string Size::toString() const > * height of this size and the \a expand size > */ > > +/** > + * \brief Align down to the aspect ratio given by \a ratio > + * \param[in] ratio The size whose aspect ratio to align down to > + * \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::alignedDownToAspectRatio(const Size &ratio) const > +{ > + Size result; result is not used, doesn't the compiler complain ? > + > + 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 Align up to the aspect ratio given by \a ratio > + * \param[in] ratio The size whose aspect ratio to align up to > + * \return A Size whose width and height are equal to the width and height > + * of this Size aligned up to the aspect ratio of \a ratio > + */ > +Size Size::alignedUpToAspectRatio(const Size &ratio) const > +{ > + Size result; > + > + 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 Centre a rectangle of this size within another rectangular region, > + * with optional offsets > + * \param[in] region The rectangular region relative to which the returned > + * rectangle can be position > + * \param[in] offsetX The X offset of the mid-point of the returned rectangle > + * relative to the mid-point of the region > + * \param[in] offsetY The Y offset of the mid-point of the returned rectangle > + * relative to the mid-point of the region > + * > + * A Rectangle of this object's size is positioned within the Rectangle > + * given by \a region. It is positioned so that its mid-point coincides > + * with the mid-point of \a region, and is then further offset by the > + * values \a offsetX and \a offsetY. > + * > + * \return A Rectangle with the horizontal and vertical sizes of > + * this Size instance, centred with offsets within a region > + */ > +Rectangle Size::centredTo(const Rectangle ®ion, int offsetX, int offsetY) const > +{ > + int x = (region.width - width) / 2 + region.x + offsetX; > + int y = (region.height - height) / 2 + region.y + offsetY; > + > + return Rectangle(x, y, width, height); > +} > + > +/** > + * \brief Scale size up by the given factor Doesn't doxygen complain for a missing \return statement ? > + */ > +Size operator*(const Size &size, float f) > +{ > + return Size(size.width * f, size.height * f); > +} > + > +/** > + * \brief Scale size down by the given factor Here too > + */ > +Size operator/(const Size &size, float f) > +{ > + return Size(size.width / f, size.height / f); > +} > + > /** > * \brief Compare sizes for equality > * \return True if the two sizes are equal, false otherwise > @@ -365,6 +449,12 @@ bool operator==(const SizeRange &lhs, const SizeRange &rhs) > * \param[in] height The height > */ > > +/** > + * \fn Rectangle::Rectangle(const Size &size) > + * \brief Construct a Rectangle with zero offsets and the given size nit: "the given \a size" > + * \param[in] size The desired Rectangle size > + */ > + > /** > * \var Rectangle::x > * \brief The horizontal coordinate of the rectangle's top-left corner > @@ -404,6 +494,47 @@ const std::string Rectangle::toString() const > return ss.str(); > } > > +/** > + * \brief Retrieve the size of this rectangle > + * \return A Size reporting the Rectangle horizontal and vertical sizes > + */ > +Size Rectangle::size() const > +{ > + return Size(width, height); > +} > + > +/** > + * \brief Bound a Rectangle so as not to exceeed another Rectangle > + * \param[in] boundary The limit that the returned Rectangle will not exceed > + * > + * The Rectangle is bounded so that it does not exceeed 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 bounary, 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. > + * > + * We note that this is not a conventional Rectangle intersection function. > + * > + * \return A Rectangle that does not extend beyond a boundary Rectangle > + */ > +Rectangle Rectangle::boundedTo(const Rectangle &boundary) const > +{ > + Rectangle result(*this); > + > + result.width = std::min(result.width, boundary.width); > + result.x = std::clamp<int>(result.x, boundary.x, > + boundary.x + boundary.width - result.width); > + > + result.height = std::min(result.height, boundary.height); > + result.y = std::clamp<int>(result.y, boundary.y, > + boundary.y + boundary.height - result.height); > + > + return result; > +} > + nit aparts, very nice! Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Thanks j > /** > * \brief Compare rectangles for equality > * \return True if the two rectangles are equal, false otherwise > -- > 2.20.1 > > _______________________________________________ > libcamera-devel mailing list > libcamera-devel@lists.libcamera.org > https://lists.libcamera.org/listinfo/libcamera-devel
diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index 02fb63c..0447ee3 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -13,6 +13,8 @@ namespace libcamera { +class Rectangle; + class Size { public: @@ -93,8 +95,17 @@ public: std::max(height, expand.height) }; } + + Size alignedDownToAspectRatio(const Size &ratio) const; + Size alignedUpToAspectRatio(const Size &ratio) const; + + Rectangle centredTo(const Rectangle ®ion, + int offsetX = 0, int offsetY = 0) const; }; +Size operator*(const Size &size, float f); +Size operator/(const Size &size, float f); + bool operator==(const Size &lhs, const Size &rhs); bool operator<(const Size &lhs, const Size &rhs); @@ -176,6 +187,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 +199,10 @@ public: bool isNull() const { return !width && !height; } const std::string toString() const; + + Size size() const; + + Rectangle boundedTo(const Rectangle &boundary) const; }; bool operator==(const Rectangle &lhs, const Rectangle &rhs); diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index b12e1a6..0c058dd 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -143,6 +143,90 @@ const std::string Size::toString() const * height of this size and the \a expand size */ +/** + * \brief Align down to the aspect ratio given by \a ratio + * \param[in] ratio The size whose aspect ratio to align down to + * \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::alignedDownToAspectRatio(const Size &ratio) const +{ + Size result; + + 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 Align up to the aspect ratio given by \a ratio + * \param[in] ratio The size whose aspect ratio to align up to + * \return A Size whose width and height are equal to the width and height + * of this Size aligned up to the aspect ratio of \a ratio + */ +Size Size::alignedUpToAspectRatio(const Size &ratio) const +{ + Size result; + + 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 Centre a rectangle of this size within another rectangular region, + * with optional offsets + * \param[in] region The rectangular region relative to which the returned + * rectangle can be position + * \param[in] offsetX The X offset of the mid-point of the returned rectangle + * relative to the mid-point of the region + * \param[in] offsetY The Y offset of the mid-point of the returned rectangle + * relative to the mid-point of the region + * + * A Rectangle of this object's size is positioned within the Rectangle + * given by \a region. It is positioned so that its mid-point coincides + * with the mid-point of \a region, and is then further offset by the + * values \a offsetX and \a offsetY. + * + * \return A Rectangle with the horizontal and vertical sizes of + * this Size instance, centred with offsets within a region + */ +Rectangle Size::centredTo(const Rectangle ®ion, int offsetX, int offsetY) const +{ + int x = (region.width - width) / 2 + region.x + offsetX; + int y = (region.height - height) / 2 + region.y + offsetY; + + return Rectangle(x, y, width, height); +} + +/** + * \brief Scale size up by the given factor + */ +Size operator*(const Size &size, float f) +{ + return Size(size.width * f, size.height * f); +} + +/** + * \brief Scale size down by the given factor + */ +Size operator/(const Size &size, float f) +{ + return Size(size.width / f, size.height / f); +} + /** * \brief Compare sizes for equality * \return True if the two sizes are equal, false otherwise @@ -365,6 +449,12 @@ bool operator==(const SizeRange &lhs, const SizeRange &rhs) * \param[in] height The height */ +/** + * \fn Rectangle::Rectangle(const Size &size) + * \brief Construct a Rectangle with zero offsets and the given size + * \param[in] size The desired Rectangle size + */ + /** * \var Rectangle::x * \brief The horizontal coordinate of the rectangle's top-left corner @@ -404,6 +494,47 @@ const std::string Rectangle::toString() const return ss.str(); } +/** + * \brief Retrieve the size of this rectangle + * \return A Size reporting the Rectangle horizontal and vertical sizes + */ +Size Rectangle::size() const +{ + return Size(width, height); +} + +/** + * \brief Bound a Rectangle so as not to exceeed another Rectangle + * \param[in] boundary The limit that the returned Rectangle will not exceed + * + * The Rectangle is bounded so that it does not exceeed 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 bounary, 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. + * + * We note that this is not a conventional Rectangle intersection function. + * + * \return A Rectangle that does not extend beyond a boundary Rectangle + */ +Rectangle Rectangle::boundedTo(const Rectangle &boundary) const +{ + Rectangle result(*this); + + result.width = std::min(result.width, boundary.width); + result.x = std::clamp<int>(result.x, boundary.x, + boundary.x + boundary.width - result.width); + + result.height = std::min(result.height, boundary.height); + result.y = std::clamp<int>(result.y, boundary.y, + boundary.y + boundary.height - result.height); + + return result; +} + /** * \brief Compare rectangles for equality * \return True if the two rectangles are equal, false otherwise
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> --- include/libcamera/geometry.h | 20 ++++++ src/libcamera/geometry.cpp | 131 +++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+)