Message ID | 20250206141018.236272-2-stefan.klug@ideasonboard.com |
---|---|
State | Accepted |
Commit | e506b45822472c23368809f4bfe0289826c5756a |
Headers | show |
Series |
|
Related | show |
Quoting Stefan Klug (2025-02-06 14:10:08) > Prepare the move of the Vector class from libipa to libcamera by copying > the relevant files into the corresponding libcamera directories. The > files are copied without modification. No modification makes this easy: Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com> But I think there are a few checkstyle issues in this file. It might be a good time to clean the file up as we're here. 29ce46bb9f92ed742df64305e68afee811ef7605 libcamera: Copy Vector class files from libipa --------------------------------------------------------------------------------------- Header include/libcamera/internal/vector.h added without corresponding update to include/libcamera/internal/meson.build --- include/libcamera/internal/vector.h +++ include/libcamera/internal/vector.h @@ -179,52 +179,88 @@ #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> #endif /* __DOXYGEN__ */ - constexpr const T &x() const { return data_[0]; } + constexpr const T &x() const + { + return data_[0]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> #endif /* __DOXYGEN__ */ - constexpr const T &y() const { return data_[1]; } + constexpr const T &y() const + { + return data_[1]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> #endif /* __DOXYGEN__ */ - constexpr const T &z() const { return data_[2]; } + constexpr const T &z() const + { + return data_[2]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> #endif /* __DOXYGEN__ */ - constexpr T &x() { return data_[0]; } + constexpr T &x() + { + return data_[0]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> #endif /* __DOXYGEN__ */ - constexpr T &y() { return data_[1]; } + constexpr T &y() + { + return data_[1]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> #endif /* __DOXYGEN__ */ - constexpr T &z() { return data_[2]; } + constexpr T &z() + { + return data_[2]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> #endif /* __DOXYGEN__ */ - constexpr const T &r() const { return data_[0]; } + constexpr const T &r() const + { + return data_[0]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> #endif /* __DOXYGEN__ */ - constexpr const T &g() const { return data_[1]; } + constexpr const T &g() const + { + return data_[1]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> #endif /* __DOXYGEN__ */ - constexpr const T &b() const { return data_[2]; } + constexpr const T &b() const + { + return data_[2]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> #endif /* __DOXYGEN__ */ - constexpr T &r() { return data_[0]; } + constexpr T &r() + { + return data_[0]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> #endif /* __DOXYGEN__ */ - constexpr T &g() { return data_[1]; } + constexpr T &g() + { + return data_[1]; + } #ifndef __DOXYGEN__ template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> #endif /* __DOXYGEN__ */ - constexpr T &b() { return data_[2]; } + constexpr T &b() + { + return data_[2]; + } constexpr double length2() const { --- test/vector.cpp +++ test/vector.cpp @@ -14,12 +14,12 @@ using namespace libcamera::ipa; -#define ASSERT_EQ(a, b) \ -if ((a) != (b)) { \ - std::cout << #a " != " #b << " (line " << __LINE__ << ")" \ - << std::endl; \ - return TestFail; \ -} +#define ASSERT_EQ(a, b) \ + if ((a) != (b)) { \ + std::cout << #a " != " #b << " (line " << __LINE__ << ")" \ + << std::endl; \ + return TestFail; \ + } class VectorTest : public Test { @@ -35,7 +35,7 @@ ASSERT_EQ(v1.length(), 0.0); ASSERT_EQ(v1.length2(), 0.0); - Vector<double, 3> v2{{ 1.0, 4.0, 8.0 }}; + Vector<double, 3> v2{ { 1.0, 4.0, 8.0 } }; ASSERT_EQ(v2[0], 1.0); ASSERT_EQ(v2[1], 4.0); @@ -57,41 +57,41 @@ ASSERT_EQ(v2, v3); - v3 = Vector<double, 3>{{ 4.0, 4.0, 4.0 }}; + v3 = Vector<double, 3>{ { 4.0, 4.0, 4.0 } }; - ASSERT_EQ(v2 + v3, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); - ASSERT_EQ(v2 + 4.0, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); - ASSERT_EQ(v2 - v3, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); - ASSERT_EQ(v2 - 4.0, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); - ASSERT_EQ(v2 * v3, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); - ASSERT_EQ(v2 * 4.0, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); - ASSERT_EQ(v2 / v3, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); - ASSERT_EQ(v2 / 4.0, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); + ASSERT_EQ(v2 + v3, (Vector<double, 3>{ { 5.0, 8.0, 12.0 } })); + ASSERT_EQ(v2 + 4.0, (Vector<double, 3>{ { 5.0, 8.0, 12.0 } })); + ASSERT_EQ(v2 - v3, (Vector<double, 3>{ { -3.0, 0.0, 4.0 } })); + ASSERT_EQ(v2 - 4.0, (Vector<double, 3>{ { -3.0, 0.0, 4.0 } })); + ASSERT_EQ(v2 * v3, (Vector<double, 3>{ { 4.0, 16.0, 32.0 } })); + ASSERT_EQ(v2 * 4.0, (Vector<double, 3>{ { 4.0, 16.0, 32.0 } })); + ASSERT_EQ(v2 / v3, (Vector<double, 3>{ { 0.25, 1.0, 2.0 } })); + ASSERT_EQ(v2 / 4.0, (Vector<double, 3>{ { 0.25, 1.0, 2.0 } })); - ASSERT_EQ(v2.min(v3), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); - ASSERT_EQ(v2.min(4.0), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); - ASSERT_EQ(v2.max(v3), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); - ASSERT_EQ(v2.max(4.0), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); + ASSERT_EQ(v2.min(v3), (Vector<double, 3>{ { 1.0, 4.0, 4.0 } })); + ASSERT_EQ(v2.min(4.0), (Vector<double, 3>{ { 1.0, 4.0, 4.0 } })); + ASSERT_EQ(v2.max(v3), (Vector<double, 3>{ { 4.0, 4.0, 8.0 } })); + ASSERT_EQ(v2.max(4.0), (Vector<double, 3>{ { 4.0, 4.0, 8.0 } })); ASSERT_EQ(v2.dot(v3), 52.0); v2 += v3; - ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 5.0, 8.0, 12.0 } })); v2 -= v3; - ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 1.0, 4.0, 8.0 } })); v2 *= v3; - ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 4.0, 16.0, 32.0 } })); v2 /= v3; - ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 1.0, 4.0, 8.0 } })); v2 += 4.0; - ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 5.0, 8.0, 12.0 } })); v2 -= 4.0; - ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 1.0, 4.0, 8.0 } })); v2 *= 4.0; - ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 4.0, 16.0, 32.0 } })); v2 /= 4.0; - ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + ASSERT_EQ(v2, (Vector<double, 3>{ { 1.0, 4.0, 8.0 } })); return TestPass; } --- 5 potential issues detected, please review To reduce future checkstyle noise, I'd be fine applying that diff to this commit as part of the move (documenting that only checkstyle/formatting updates are made during the copy). > > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com> > --- > include/libcamera/internal/vector.h | 370 ++++++++++++++++++++++++++++ > src/libcamera/vector.cpp | 351 ++++++++++++++++++++++++++ > test/vector.cpp | 100 ++++++++ > 3 files changed, 821 insertions(+) > create mode 100644 include/libcamera/internal/vector.h > create mode 100644 src/libcamera/vector.cpp > create mode 100644 test/vector.cpp > > diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h > new file mode 100644 > index 000000000000..fe33c9d6fbd1 > --- /dev/null > +++ b/include/libcamera/internal/vector.h > @@ -0,0 +1,370 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> > + * > + * Vector and related operations > + */ > +#pragma once > + > +#include <algorithm> > +#include <array> > +#include <cmath> > +#include <functional> > +#include <numeric> > +#include <optional> > +#include <ostream> > + > +#include <libcamera/base/log.h> > +#include <libcamera/base/span.h> > + > +#include "libcamera/internal/matrix.h" > +#include "libcamera/internal/yaml_parser.h" > + > +namespace libcamera { > + > +LOG_DECLARE_CATEGORY(Vector) > + > +namespace ipa { > + > +#ifndef __DOXYGEN__ > +template<typename T, unsigned int Rows, > + std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr> > +#else > +template<typename T, unsigned int Rows> > +#endif /* __DOXYGEN__ */ > +class Vector > +{ > +public: > + constexpr Vector() = default; > + > + constexpr explicit Vector(T scalar) > + { > + data_.fill(scalar); > + } > + > + constexpr Vector(const std::array<T, Rows> &data) > + { > + for (unsigned int i = 0; i < Rows; i++) > + data_[i] = data[i]; > + } > + > + const T &operator[](size_t i) const > + { > + ASSERT(i < data_.size()); > + return data_[i]; > + } > + > + T &operator[](size_t i) > + { > + ASSERT(i < data_.size()); > + return data_[i]; > + } > + > + constexpr Vector<T, Rows> operator-() const > + { > + Vector<T, Rows> ret; > + for (unsigned int i = 0; i < Rows; i++) > + ret[i] = -data_[i]; > + return ret; > + } > + > + constexpr Vector operator+(const Vector &other) const > + { > + return apply(*this, other, std::plus<>{}); > + } > + > + constexpr Vector operator+(T scalar) const > + { > + return apply(*this, scalar, std::plus<>{}); > + } > + > + constexpr Vector operator-(const Vector &other) const > + { > + return apply(*this, other, std::minus<>{}); > + } > + > + constexpr Vector operator-(T scalar) const > + { > + return apply(*this, scalar, std::minus<>{}); > + } > + > + constexpr Vector operator*(const Vector &other) const > + { > + return apply(*this, other, std::multiplies<>{}); > + } > + > + constexpr Vector operator*(T scalar) const > + { > + return apply(*this, scalar, std::multiplies<>{}); > + } > + > + constexpr Vector operator/(const Vector &other) const > + { > + return apply(*this, other, std::divides<>{}); > + } > + > + constexpr Vector operator/(T scalar) const > + { > + return apply(*this, scalar, std::divides<>{}); > + } > + > + Vector &operator+=(const Vector &other) > + { > + return apply(other, [](T a, T b) { return a + b; }); > + } > + > + Vector &operator+=(T scalar) > + { > + return apply(scalar, [](T a, T b) { return a + b; }); > + } > + > + Vector &operator-=(const Vector &other) > + { > + return apply(other, [](T a, T b) { return a - b; }); > + } > + > + Vector &operator-=(T scalar) > + { > + return apply(scalar, [](T a, T b) { return a - b; }); > + } > + > + Vector &operator*=(const Vector &other) > + { > + return apply(other, [](T a, T b) { return a * b; }); > + } > + > + Vector &operator*=(T scalar) > + { > + return apply(scalar, [](T a, T b) { return a * b; }); > + } > + > + Vector &operator/=(const Vector &other) > + { > + return apply(other, [](T a, T b) { return a / b; }); > + } > + > + Vector &operator/=(T scalar) > + { > + return apply(scalar, [](T a, T b) { return a / b; }); > + } > + > + constexpr Vector min(const Vector &other) const > + { > + return apply(*this, other, [](T a, T b) { return std::min(a, b); }); > + } > + > + constexpr Vector min(T scalar) const > + { > + return apply(*this, scalar, [](T a, T b) { return std::min(a, b); }); > + } > + > + constexpr Vector max(const Vector &other) const > + { > + return apply(*this, other, [](T a, T b) { return std::max(a, b); }); > + } > + > + constexpr Vector max(T scalar) const > + { > + return apply(*this, scalar, [](T a, T b) -> T { return std::max(a, b); }); > + } > + > + constexpr T dot(const Vector<T, Rows> &other) const > + { > + T ret = 0; > + for (unsigned int i = 0; i < Rows; i++) > + ret += data_[i] * other[i]; > + return ret; > + } > + > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> > +#endif /* __DOXYGEN__ */ > + constexpr const T &x() const { return data_[0]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> > +#endif /* __DOXYGEN__ */ > + constexpr const T &y() const { return data_[1]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> > +#endif /* __DOXYGEN__ */ > + constexpr const T &z() const { return data_[2]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> > +#endif /* __DOXYGEN__ */ > + constexpr T &x() { return data_[0]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> > +#endif /* __DOXYGEN__ */ > + constexpr T &y() { return data_[1]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> > +#endif /* __DOXYGEN__ */ > + constexpr T &z() { return data_[2]; } > + > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> > +#endif /* __DOXYGEN__ */ > + constexpr const T &r() const { return data_[0]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> > +#endif /* __DOXYGEN__ */ > + constexpr const T &g() const { return data_[1]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> > +#endif /* __DOXYGEN__ */ > + constexpr const T &b() const { return data_[2]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> > +#endif /* __DOXYGEN__ */ > + constexpr T &r() { return data_[0]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> > +#endif /* __DOXYGEN__ */ > + constexpr T &g() { return data_[1]; } > +#ifndef __DOXYGEN__ > + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> > +#endif /* __DOXYGEN__ */ > + constexpr T &b() { return data_[2]; } > + > + constexpr double length2() const > + { > + double ret = 0; > + for (unsigned int i = 0; i < Rows; i++) > + ret += data_[i] * data_[i]; > + return ret; > + } > + > + constexpr double length() const > + { > + return std::sqrt(length2()); > + } > + > + template<typename R = T> > + constexpr R sum() const > + { > + return std::accumulate(data_.begin(), data_.end(), R{}); > + } > + > +private: > + template<class BinaryOp> > + static constexpr Vector apply(const Vector &lhs, const Vector &rhs, BinaryOp op) > + { > + Vector result; > + std::transform(lhs.data_.begin(), lhs.data_.end(), > + rhs.data_.begin(), result.data_.begin(), > + op); > + > + return result; > + } > + > + template<class BinaryOp> > + static constexpr Vector apply(const Vector &lhs, T rhs, BinaryOp op) > + { > + Vector result; > + std::transform(lhs.data_.begin(), lhs.data_.end(), > + result.data_.begin(), > + [&op, rhs](T v) { return op(v, rhs); }); > + > + return result; > + } > + > + template<class BinaryOp> > + Vector &apply(const Vector &other, BinaryOp op) > + { > + auto itOther = other.data_.begin(); > + std::for_each(data_.begin(), data_.end(), > + [&op, &itOther](T &v) { v = op(v, *itOther++); }); > + > + return *this; > + } > + > + template<class BinaryOp> > + Vector &apply(T scalar, BinaryOp op) > + { > + std::for_each(data_.begin(), data_.end(), > + [&op, scalar](T &v) { v = op(v, scalar); }); > + > + return *this; > + } > + > + std::array<T, Rows> data_; > +}; > + > +template<typename T> > +using RGB = Vector<T, 3>; > + > +template<typename T, unsigned int Rows, unsigned int Cols> > +Vector<T, Rows> operator*(const Matrix<T, Rows, Cols> &m, const Vector<T, Cols> &v) > +{ > + Vector<T, Rows> result; > + > + for (unsigned int i = 0; i < Rows; i++) { > + T sum = 0; > + for (unsigned int j = 0; j < Cols; j++) > + sum += m[i][j] * v[j]; > + result[i] = sum; > + } > + > + return result; > +} > + > +template<typename T, unsigned int Rows> > +bool operator==(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) > +{ > + for (unsigned int i = 0; i < Rows; i++) { > + if (lhs[i] != rhs[i]) > + return false; > + } > + > + return true; > +} > + > +template<typename T, unsigned int Rows> > +bool operator!=(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) > +{ > + return !(lhs == rhs); > +} > + > +#ifndef __DOXYGEN__ > +bool vectorValidateYaml(const YamlObject &obj, unsigned int size); > +#endif /* __DOXYGEN__ */ > + > +} /* namespace ipa */ > + > +#ifndef __DOXYGEN__ > +template<typename T, unsigned int Rows> > +std::ostream &operator<<(std::ostream &out, const ipa::Vector<T, Rows> &v) > +{ > + out << "Vector { "; > + for (unsigned int i = 0; i < Rows; i++) { > + out << v[i]; > + out << ((i + 1 < Rows) ? ", " : " "); > + } > + out << " }"; > + > + return out; > +} > + > +template<typename T, unsigned int Rows> > +struct YamlObject::Getter<ipa::Vector<T, Rows>> { > + std::optional<ipa::Vector<T, Rows>> get(const YamlObject &obj) const > + { > + if (!ipa::vectorValidateYaml(obj, Rows)) > + return std::nullopt; > + > + ipa::Vector<T, Rows> vector; > + > + unsigned int i = 0; > + for (const YamlObject &entry : obj.asList()) { > + const auto value = entry.get<T>(); > + if (!value) > + return std::nullopt; > + vector[i++] = *value; > + } > + > + return vector; > + } > +}; > +#endif /* __DOXYGEN__ */ > + > +} /* namespace libcamera */ > diff --git a/src/libcamera/vector.cpp b/src/libcamera/vector.cpp > new file mode 100644 > index 000000000000..8019f8cfdc85 > --- /dev/null > +++ b/src/libcamera/vector.cpp > @@ -0,0 +1,351 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> > + * > + * Vector and related operations > + */ > + > +#include "vector.h" > + > +#include <libcamera/base/log.h> > + > +/** > + * \file vector.h > + * \brief Vector class > + */ > + > +namespace libcamera { > + > +LOG_DEFINE_CATEGORY(Vector) > + > +namespace ipa { > + > +/** > + * \class Vector > + * \brief Vector class > + * \tparam T Type of numerical values to be stored in the vector > + * \tparam Rows Number of dimension of the vector (= number of elements) > + */ > + > +/** > + * \fn Vector::Vector() > + * \brief Construct an uninitialized vector > + */ > + > +/** > + * \fn Vector::Vector(T scalar) > + * \brief Construct a vector filled with a \a scalar value > + * \param[in] scalar The scalar value > + */ > + > +/** > + * \fn Vector::Vector(const std::array<T, Rows> &data) > + * \brief Construct vector from supplied data > + * \param data Data from which to construct a vector > + * > + * The size of \a data must be equal to the dimension size Rows of the vector. > + */ > + > +/** > + * \fn T Vector::operator[](size_t i) const > + * \brief Index to an element in the vector > + * \param i Index of element to retrieve > + * \return Element at index \a i from the vector > + */ > + > +/** > + * \fn T &Vector::operator[](size_t i) > + * \copydoc Vector::operator[](size_t i) const > + */ > + > +/** > + * \fn Vector::operator-() const > + * \brief Negate a Vector by negating both all of its coordinates > + * \return The negated vector > + */ > + > +/** > + * \fn Vector::operator+(Vector const &other) const > + * \brief Calculate the sum of this vector and \a other element-wise > + * \param[in] other The other vector > + * \return The element-wise sum of this vector and \a other > + */ > + > +/** > + * \fn Vector::operator+(T scalar) const > + * \brief Calculate the sum of this vector and \a scalar element-wise > + * \param[in] scalar The scalar > + * \return The element-wise sum of this vector and \a other > + */ > + > +/** > + * \fn Vector::operator-(Vector const &other) const > + * \brief Calculate the difference of this vector and \a other element-wise > + * \param[in] other The other vector > + * \return The element-wise subtraction of \a other from this vector > + */ > + > +/** > + * \fn Vector::operator-(T scalar) const > + * \brief Calculate the difference of this vector and \a scalar element-wise > + * \param[in] scalar The scalar > + * \return The element-wise subtraction of \a scalar from this vector > + */ > + > +/** > + * \fn Vector::operator*(const Vector &other) const > + * \brief Calculate the product of this vector and \a other element-wise > + * \param[in] other The other vector > + * \return The element-wise product of this vector and \a other > + */ > + > +/** > + * \fn Vector::operator*(T scalar) const > + * \brief Calculate the product of this vector and \a scalar element-wise > + * \param[in] scalar The scalar > + * \return The element-wise product of this vector and \a scalar > + */ > + > +/** > + * \fn Vector::operator/(const Vector &other) const > + * \brief Calculate the quotient of this vector and \a other element-wise > + * \param[in] other The other vector > + * \return The element-wise division of this vector by \a other > + */ > + > +/** > + * \fn Vector::operator/(T scalar) const > + * \brief Calculate the quotient of this vector and \a scalar element-wise > + * \param[in] scalar The scalar > + * \return The element-wise division of this vector by \a scalar > + */ > + > +/** > + * \fn Vector::operator+=(Vector const &other) > + * \brief Add \a other element-wise to this vector > + * \param[in] other The other vector > + * \return This vector > + */ > + > +/** > + * \fn Vector::operator+=(T scalar) > + * \brief Add \a scalar element-wise to this vector > + * \param[in] scalar The scalar > + * \return This vector > + */ > + > +/** > + * \fn Vector::operator-=(Vector const &other) > + * \brief Subtract \a other element-wise from this vector > + * \param[in] other The other vector > + * \return This vector > + */ > + > +/** > + * \fn Vector::operator-=(T scalar) > + * \brief Subtract \a scalar element-wise from this vector > + * \param[in] scalar The scalar > + * \return This vector > + */ > + > +/** > + * \fn Vector::operator*=(const Vector &other) > + * \brief Multiply this vector by \a other element-wise > + * \param[in] other The other vector > + * \return This vector > + */ > + > +/** > + * \fn Vector::operator*=(T scalar) > + * \brief Multiply this vector by \a scalar element-wise > + * \param[in] scalar The scalar > + * \return This vector > + */ > + > +/** > + * \fn Vector::operator/=(const Vector &other) > + * \brief Divide this vector by \a other element-wise > + * \param[in] other The other vector > + * \return This vector > + */ > + > +/** > + * \fn Vector::operator/=(T scalar) > + * \brief Divide this vector by \a scalar element-wise > + * \param[in] scalar The scalar > + * \return This vector > + */ > + > +/** > + * \fn Vector::min(const Vector &other) const > + * \brief Calculate the minimum of this vector and \a other element-wise > + * \param[in] other The other vector > + * \return The element-wise minimum of this vector and \a other > + */ > + > +/** > + * \fn Vector::min(T scalar) const > + * \brief Calculate the minimum of this vector and \a scalar element-wise > + * \param[in] scalar The scalar > + * \return The element-wise minimum of this vector and \a scalar > + */ > + > +/** > + * \fn Vector::max(const Vector &other) const > + * \brief Calculate the maximum of this vector and \a other element-wise > + * \param[in] other The other vector > + * \return The element-wise maximum of this vector and \a other > + */ > + > +/** > + * \fn Vector::max(T scalar) const > + * \brief Calculate the maximum of this vector and \a scalar element-wise > + * \param[in] scalar The scalar > + * \return The element-wise maximum of this vector and \a scalar > + */ > + > +/** > + * \fn Vector::dot(const Vector<T, Rows> &other) const > + * \brief Compute the dot product > + * \param[in] other The other vector > + * \return The dot product of the two vectors > + */ > + > +/** > + * \fn constexpr T &Vector::x() > + * \brief Convenience function to access the first element of the vector > + * \return The first element of the vector > + */ > + > +/** > + * \fn constexpr T &Vector::y() > + * \brief Convenience function to access the second element of the vector > + * \return The second element of the vector > + */ > + > +/** > + * \fn constexpr T &Vector::z() > + * \brief Convenience function to access the third element of the vector > + * \return The third element of the vector > + */ > + > +/** > + * \fn constexpr const T &Vector::x() const > + * \copydoc Vector::x() > + */ > + > +/** > + * \fn constexpr const T &Vector::y() const > + * \copydoc Vector::y() > + */ > + > +/** > + * \fn constexpr const T &Vector::z() const > + * \copydoc Vector::z() > + */ > + > +/** > + * \fn constexpr T &Vector::r() > + * \brief Convenience function to access the first element of the vector > + * \return The first element of the vector > + */ > + > +/** > + * \fn constexpr T &Vector::g() > + * \brief Convenience function to access the second element of the vector > + * \return The second element of the vector > + */ > + > +/** > + * \fn constexpr T &Vector::b() > + * \brief Convenience function to access the third element of the vector > + * \return The third element of the vector > + */ > + > +/** > + * \fn constexpr const T &Vector::r() const > + * \copydoc Vector::r() > + */ > + > +/** > + * \fn constexpr const T &Vector::g() const > + * \copydoc Vector::g() > + */ > + > +/** > + * \fn constexpr const T &Vector::b() const > + * \copydoc Vector::b() > + */ > + > +/** > + * \fn Vector::length2() > + * \brief Get the squared length of the vector > + * \return The squared length of the vector > + */ > + > +/** > + * \fn Vector::length() > + * \brief Get the length of the vector > + * \return The length of the vector > + */ > + > +/** > + * \fn Vector::sum() const > + * \brief Calculate the sum of all the vector elements > + * \tparam R The type of the sum > + * > + * The type R of the sum defaults to the type T of the elements, but can be set > + * explicitly to use a different type in case the type T would risk > + * overflowing. > + * > + * \return The sum of all the vector elements > + */ > + > +/** > + * \fn Vector<T, Rows> operator*(const Matrix<T, Rows, Cols> &m, const Vector<T, Cols> &v) > + * \brief Multiply a matrix by a vector > + * \tparam T Numerical type of the contents of the matrix and vector > + * \tparam Rows The number of rows in the matrix > + * \tparam Cols The number of columns in the matrix (= rows in the vector) > + * \param m The matrix > + * \param v The vector > + * \return Product of matrix \a m and vector \a v > + */ > + > +/** > + * \typedef RGB > + * \brief A Vector of 3 elements representing an RGB pixel value > + */ > + > +/** > + * \fn bool operator==(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) > + * \brief Compare vectors for equality > + * \return True if the two vectors are equal, false otherwise > + */ > + > +/** > + * \fn bool operator!=(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) > + * \brief Compare vectors for inequality > + * \return True if the two vectors are not equal, false otherwise > + */ > + > +#ifndef __DOXYGEN__ > +bool vectorValidateYaml(const YamlObject &obj, unsigned int size) > +{ > + if (!obj.isList()) > + return false; > + > + if (obj.size() != size) { > + LOG(Vector, Error) > + << "Wrong number of values in YAML vector: expected " > + << size << ", got " << obj.size(); > + return false; > + } > + > + return true; > +} > +#endif /* __DOXYGEN__ */ > + > +} /* namespace ipa */ > + > +} /* namespace libcamera */ > diff --git a/test/vector.cpp b/test/vector.cpp > new file mode 100644 > index 000000000000..8e4ec77d7820 > --- /dev/null > +++ b/test/vector.cpp > @@ -0,0 +1,100 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Copyright (C) 2024, Ideas on Board Oy > + * > + * Vector tests > + */ > + > +#include "../src/ipa/libipa/vector.h" > + > +#include <cmath> > +#include <iostream> > + > +#include "test.h" > + > +using namespace libcamera::ipa; > + > +#define ASSERT_EQ(a, b) \ > +if ((a) != (b)) { \ > + std::cout << #a " != " #b << " (line " << __LINE__ << ")" \ > + << std::endl; \ > + return TestFail; \ > +} > + > +class VectorTest : public Test > +{ > +protected: > + int run() > + { > + Vector<double, 3> v1{ 0.0 }; > + > + ASSERT_EQ(v1[0], 0.0); > + ASSERT_EQ(v1[1], 0.0); > + ASSERT_EQ(v1[2], 0.0); > + > + ASSERT_EQ(v1.length(), 0.0); > + ASSERT_EQ(v1.length2(), 0.0); > + > + Vector<double, 3> v2{{ 1.0, 4.0, 8.0 }}; > + > + ASSERT_EQ(v2[0], 1.0); > + ASSERT_EQ(v2[1], 4.0); > + ASSERT_EQ(v2[2], 8.0); > + > + ASSERT_EQ(v2.x(), 1.0); > + ASSERT_EQ(v2.y(), 4.0); > + ASSERT_EQ(v2.z(), 8.0); > + > + ASSERT_EQ(v2.r(), 1.0); > + ASSERT_EQ(v2.g(), 4.0); > + ASSERT_EQ(v2.b(), 8.0); > + > + ASSERT_EQ(v2.length2(), 81.0); > + ASSERT_EQ(v2.length(), 9.0); > + ASSERT_EQ(v2.sum(), 13.0); > + > + Vector<double, 3> v3{ v2 }; > + > + ASSERT_EQ(v2, v3); > + > + v3 = Vector<double, 3>{{ 4.0, 4.0, 4.0 }}; > + > + ASSERT_EQ(v2 + v3, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); > + ASSERT_EQ(v2 + 4.0, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); > + ASSERT_EQ(v2 - v3, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); > + ASSERT_EQ(v2 - 4.0, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); > + ASSERT_EQ(v2 * v3, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); > + ASSERT_EQ(v2 * 4.0, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); > + ASSERT_EQ(v2 / v3, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); > + ASSERT_EQ(v2 / 4.0, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); > + > + ASSERT_EQ(v2.min(v3), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); > + ASSERT_EQ(v2.min(4.0), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); > + ASSERT_EQ(v2.max(v3), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); > + ASSERT_EQ(v2.max(4.0), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); > + > + ASSERT_EQ(v2.dot(v3), 52.0); > + > + v2 += v3; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); > + v2 -= v3; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); > + v2 *= v3; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); > + v2 /= v3; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); > + > + v2 += 4.0; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); > + v2 -= 4.0; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); > + v2 *= 4.0; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); > + v2 /= 4.0; > + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); > + > + return TestPass; > + } > +}; > + > +TEST_REGISTER(VectorTest) > -- > 2.43.0 >
diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h new file mode 100644 index 000000000000..fe33c9d6fbd1 --- /dev/null +++ b/include/libcamera/internal/vector.h @@ -0,0 +1,370 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> + * + * Vector and related operations + */ +#pragma once + +#include <algorithm> +#include <array> +#include <cmath> +#include <functional> +#include <numeric> +#include <optional> +#include <ostream> + +#include <libcamera/base/log.h> +#include <libcamera/base/span.h> + +#include "libcamera/internal/matrix.h" +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(Vector) + +namespace ipa { + +#ifndef __DOXYGEN__ +template<typename T, unsigned int Rows, + std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr> +#else +template<typename T, unsigned int Rows> +#endif /* __DOXYGEN__ */ +class Vector +{ +public: + constexpr Vector() = default; + + constexpr explicit Vector(T scalar) + { + data_.fill(scalar); + } + + constexpr Vector(const std::array<T, Rows> &data) + { + for (unsigned int i = 0; i < Rows; i++) + data_[i] = data[i]; + } + + const T &operator[](size_t i) const + { + ASSERT(i < data_.size()); + return data_[i]; + } + + T &operator[](size_t i) + { + ASSERT(i < data_.size()); + return data_[i]; + } + + constexpr Vector<T, Rows> operator-() const + { + Vector<T, Rows> ret; + for (unsigned int i = 0; i < Rows; i++) + ret[i] = -data_[i]; + return ret; + } + + constexpr Vector operator+(const Vector &other) const + { + return apply(*this, other, std::plus<>{}); + } + + constexpr Vector operator+(T scalar) const + { + return apply(*this, scalar, std::plus<>{}); + } + + constexpr Vector operator-(const Vector &other) const + { + return apply(*this, other, std::minus<>{}); + } + + constexpr Vector operator-(T scalar) const + { + return apply(*this, scalar, std::minus<>{}); + } + + constexpr Vector operator*(const Vector &other) const + { + return apply(*this, other, std::multiplies<>{}); + } + + constexpr Vector operator*(T scalar) const + { + return apply(*this, scalar, std::multiplies<>{}); + } + + constexpr Vector operator/(const Vector &other) const + { + return apply(*this, other, std::divides<>{}); + } + + constexpr Vector operator/(T scalar) const + { + return apply(*this, scalar, std::divides<>{}); + } + + Vector &operator+=(const Vector &other) + { + return apply(other, [](T a, T b) { return a + b; }); + } + + Vector &operator+=(T scalar) + { + return apply(scalar, [](T a, T b) { return a + b; }); + } + + Vector &operator-=(const Vector &other) + { + return apply(other, [](T a, T b) { return a - b; }); + } + + Vector &operator-=(T scalar) + { + return apply(scalar, [](T a, T b) { return a - b; }); + } + + Vector &operator*=(const Vector &other) + { + return apply(other, [](T a, T b) { return a * b; }); + } + + Vector &operator*=(T scalar) + { + return apply(scalar, [](T a, T b) { return a * b; }); + } + + Vector &operator/=(const Vector &other) + { + return apply(other, [](T a, T b) { return a / b; }); + } + + Vector &operator/=(T scalar) + { + return apply(scalar, [](T a, T b) { return a / b; }); + } + + constexpr Vector min(const Vector &other) const + { + return apply(*this, other, [](T a, T b) { return std::min(a, b); }); + } + + constexpr Vector min(T scalar) const + { + return apply(*this, scalar, [](T a, T b) { return std::min(a, b); }); + } + + constexpr Vector max(const Vector &other) const + { + return apply(*this, other, [](T a, T b) { return std::max(a, b); }); + } + + constexpr Vector max(T scalar) const + { + return apply(*this, scalar, [](T a, T b) -> T { return std::max(a, b); }); + } + + constexpr T dot(const Vector<T, Rows> &other) const + { + T ret = 0; + for (unsigned int i = 0; i < Rows; i++) + ret += data_[i] * other[i]; + return ret; + } + +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> +#endif /* __DOXYGEN__ */ + constexpr const T &x() const { return data_[0]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> +#endif /* __DOXYGEN__ */ + constexpr const T &y() const { return data_[1]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> +#endif /* __DOXYGEN__ */ + constexpr const T &z() const { return data_[2]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> +#endif /* __DOXYGEN__ */ + constexpr T &x() { return data_[0]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> +#endif /* __DOXYGEN__ */ + constexpr T &y() { return data_[1]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> +#endif /* __DOXYGEN__ */ + constexpr T &z() { return data_[2]; } + +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> +#endif /* __DOXYGEN__ */ + constexpr const T &r() const { return data_[0]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> +#endif /* __DOXYGEN__ */ + constexpr const T &g() const { return data_[1]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> +#endif /* __DOXYGEN__ */ + constexpr const T &b() const { return data_[2]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 1>> +#endif /* __DOXYGEN__ */ + constexpr T &r() { return data_[0]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 2>> +#endif /* __DOXYGEN__ */ + constexpr T &g() { return data_[1]; } +#ifndef __DOXYGEN__ + template<bool Dependent = false, typename = std::enable_if_t<Dependent || Rows >= 3>> +#endif /* __DOXYGEN__ */ + constexpr T &b() { return data_[2]; } + + constexpr double length2() const + { + double ret = 0; + for (unsigned int i = 0; i < Rows; i++) + ret += data_[i] * data_[i]; + return ret; + } + + constexpr double length() const + { + return std::sqrt(length2()); + } + + template<typename R = T> + constexpr R sum() const + { + return std::accumulate(data_.begin(), data_.end(), R{}); + } + +private: + template<class BinaryOp> + static constexpr Vector apply(const Vector &lhs, const Vector &rhs, BinaryOp op) + { + Vector result; + std::transform(lhs.data_.begin(), lhs.data_.end(), + rhs.data_.begin(), result.data_.begin(), + op); + + return result; + } + + template<class BinaryOp> + static constexpr Vector apply(const Vector &lhs, T rhs, BinaryOp op) + { + Vector result; + std::transform(lhs.data_.begin(), lhs.data_.end(), + result.data_.begin(), + [&op, rhs](T v) { return op(v, rhs); }); + + return result; + } + + template<class BinaryOp> + Vector &apply(const Vector &other, BinaryOp op) + { + auto itOther = other.data_.begin(); + std::for_each(data_.begin(), data_.end(), + [&op, &itOther](T &v) { v = op(v, *itOther++); }); + + return *this; + } + + template<class BinaryOp> + Vector &apply(T scalar, BinaryOp op) + { + std::for_each(data_.begin(), data_.end(), + [&op, scalar](T &v) { v = op(v, scalar); }); + + return *this; + } + + std::array<T, Rows> data_; +}; + +template<typename T> +using RGB = Vector<T, 3>; + +template<typename T, unsigned int Rows, unsigned int Cols> +Vector<T, Rows> operator*(const Matrix<T, Rows, Cols> &m, const Vector<T, Cols> &v) +{ + Vector<T, Rows> result; + + for (unsigned int i = 0; i < Rows; i++) { + T sum = 0; + for (unsigned int j = 0; j < Cols; j++) + sum += m[i][j] * v[j]; + result[i] = sum; + } + + return result; +} + +template<typename T, unsigned int Rows> +bool operator==(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) +{ + for (unsigned int i = 0; i < Rows; i++) { + if (lhs[i] != rhs[i]) + return false; + } + + return true; +} + +template<typename T, unsigned int Rows> +bool operator!=(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) +{ + return !(lhs == rhs); +} + +#ifndef __DOXYGEN__ +bool vectorValidateYaml(const YamlObject &obj, unsigned int size); +#endif /* __DOXYGEN__ */ + +} /* namespace ipa */ + +#ifndef __DOXYGEN__ +template<typename T, unsigned int Rows> +std::ostream &operator<<(std::ostream &out, const ipa::Vector<T, Rows> &v) +{ + out << "Vector { "; + for (unsigned int i = 0; i < Rows; i++) { + out << v[i]; + out << ((i + 1 < Rows) ? ", " : " "); + } + out << " }"; + + return out; +} + +template<typename T, unsigned int Rows> +struct YamlObject::Getter<ipa::Vector<T, Rows>> { + std::optional<ipa::Vector<T, Rows>> get(const YamlObject &obj) const + { + if (!ipa::vectorValidateYaml(obj, Rows)) + return std::nullopt; + + ipa::Vector<T, Rows> vector; + + unsigned int i = 0; + for (const YamlObject &entry : obj.asList()) { + const auto value = entry.get<T>(); + if (!value) + return std::nullopt; + vector[i++] = *value; + } + + return vector; + } +}; +#endif /* __DOXYGEN__ */ + +} /* namespace libcamera */ diff --git a/src/libcamera/vector.cpp b/src/libcamera/vector.cpp new file mode 100644 index 000000000000..8019f8cfdc85 --- /dev/null +++ b/src/libcamera/vector.cpp @@ -0,0 +1,351 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> + * + * Vector and related operations + */ + +#include "vector.h" + +#include <libcamera/base/log.h> + +/** + * \file vector.h + * \brief Vector class + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Vector) + +namespace ipa { + +/** + * \class Vector + * \brief Vector class + * \tparam T Type of numerical values to be stored in the vector + * \tparam Rows Number of dimension of the vector (= number of elements) + */ + +/** + * \fn Vector::Vector() + * \brief Construct an uninitialized vector + */ + +/** + * \fn Vector::Vector(T scalar) + * \brief Construct a vector filled with a \a scalar value + * \param[in] scalar The scalar value + */ + +/** + * \fn Vector::Vector(const std::array<T, Rows> &data) + * \brief Construct vector from supplied data + * \param data Data from which to construct a vector + * + * The size of \a data must be equal to the dimension size Rows of the vector. + */ + +/** + * \fn T Vector::operator[](size_t i) const + * \brief Index to an element in the vector + * \param i Index of element to retrieve + * \return Element at index \a i from the vector + */ + +/** + * \fn T &Vector::operator[](size_t i) + * \copydoc Vector::operator[](size_t i) const + */ + +/** + * \fn Vector::operator-() const + * \brief Negate a Vector by negating both all of its coordinates + * \return The negated vector + */ + +/** + * \fn Vector::operator+(Vector const &other) const + * \brief Calculate the sum of this vector and \a other element-wise + * \param[in] other The other vector + * \return The element-wise sum of this vector and \a other + */ + +/** + * \fn Vector::operator+(T scalar) const + * \brief Calculate the sum of this vector and \a scalar element-wise + * \param[in] scalar The scalar + * \return The element-wise sum of this vector and \a other + */ + +/** + * \fn Vector::operator-(Vector const &other) const + * \brief Calculate the difference of this vector and \a other element-wise + * \param[in] other The other vector + * \return The element-wise subtraction of \a other from this vector + */ + +/** + * \fn Vector::operator-(T scalar) const + * \brief Calculate the difference of this vector and \a scalar element-wise + * \param[in] scalar The scalar + * \return The element-wise subtraction of \a scalar from this vector + */ + +/** + * \fn Vector::operator*(const Vector &other) const + * \brief Calculate the product of this vector and \a other element-wise + * \param[in] other The other vector + * \return The element-wise product of this vector and \a other + */ + +/** + * \fn Vector::operator*(T scalar) const + * \brief Calculate the product of this vector and \a scalar element-wise + * \param[in] scalar The scalar + * \return The element-wise product of this vector and \a scalar + */ + +/** + * \fn Vector::operator/(const Vector &other) const + * \brief Calculate the quotient of this vector and \a other element-wise + * \param[in] other The other vector + * \return The element-wise division of this vector by \a other + */ + +/** + * \fn Vector::operator/(T scalar) const + * \brief Calculate the quotient of this vector and \a scalar element-wise + * \param[in] scalar The scalar + * \return The element-wise division of this vector by \a scalar + */ + +/** + * \fn Vector::operator+=(Vector const &other) + * \brief Add \a other element-wise to this vector + * \param[in] other The other vector + * \return This vector + */ + +/** + * \fn Vector::operator+=(T scalar) + * \brief Add \a scalar element-wise to this vector + * \param[in] scalar The scalar + * \return This vector + */ + +/** + * \fn Vector::operator-=(Vector const &other) + * \brief Subtract \a other element-wise from this vector + * \param[in] other The other vector + * \return This vector + */ + +/** + * \fn Vector::operator-=(T scalar) + * \brief Subtract \a scalar element-wise from this vector + * \param[in] scalar The scalar + * \return This vector + */ + +/** + * \fn Vector::operator*=(const Vector &other) + * \brief Multiply this vector by \a other element-wise + * \param[in] other The other vector + * \return This vector + */ + +/** + * \fn Vector::operator*=(T scalar) + * \brief Multiply this vector by \a scalar element-wise + * \param[in] scalar The scalar + * \return This vector + */ + +/** + * \fn Vector::operator/=(const Vector &other) + * \brief Divide this vector by \a other element-wise + * \param[in] other The other vector + * \return This vector + */ + +/** + * \fn Vector::operator/=(T scalar) + * \brief Divide this vector by \a scalar element-wise + * \param[in] scalar The scalar + * \return This vector + */ + +/** + * \fn Vector::min(const Vector &other) const + * \brief Calculate the minimum of this vector and \a other element-wise + * \param[in] other The other vector + * \return The element-wise minimum of this vector and \a other + */ + +/** + * \fn Vector::min(T scalar) const + * \brief Calculate the minimum of this vector and \a scalar element-wise + * \param[in] scalar The scalar + * \return The element-wise minimum of this vector and \a scalar + */ + +/** + * \fn Vector::max(const Vector &other) const + * \brief Calculate the maximum of this vector and \a other element-wise + * \param[in] other The other vector + * \return The element-wise maximum of this vector and \a other + */ + +/** + * \fn Vector::max(T scalar) const + * \brief Calculate the maximum of this vector and \a scalar element-wise + * \param[in] scalar The scalar + * \return The element-wise maximum of this vector and \a scalar + */ + +/** + * \fn Vector::dot(const Vector<T, Rows> &other) const + * \brief Compute the dot product + * \param[in] other The other vector + * \return The dot product of the two vectors + */ + +/** + * \fn constexpr T &Vector::x() + * \brief Convenience function to access the first element of the vector + * \return The first element of the vector + */ + +/** + * \fn constexpr T &Vector::y() + * \brief Convenience function to access the second element of the vector + * \return The second element of the vector + */ + +/** + * \fn constexpr T &Vector::z() + * \brief Convenience function to access the third element of the vector + * \return The third element of the vector + */ + +/** + * \fn constexpr const T &Vector::x() const + * \copydoc Vector::x() + */ + +/** + * \fn constexpr const T &Vector::y() const + * \copydoc Vector::y() + */ + +/** + * \fn constexpr const T &Vector::z() const + * \copydoc Vector::z() + */ + +/** + * \fn constexpr T &Vector::r() + * \brief Convenience function to access the first element of the vector + * \return The first element of the vector + */ + +/** + * \fn constexpr T &Vector::g() + * \brief Convenience function to access the second element of the vector + * \return The second element of the vector + */ + +/** + * \fn constexpr T &Vector::b() + * \brief Convenience function to access the third element of the vector + * \return The third element of the vector + */ + +/** + * \fn constexpr const T &Vector::r() const + * \copydoc Vector::r() + */ + +/** + * \fn constexpr const T &Vector::g() const + * \copydoc Vector::g() + */ + +/** + * \fn constexpr const T &Vector::b() const + * \copydoc Vector::b() + */ + +/** + * \fn Vector::length2() + * \brief Get the squared length of the vector + * \return The squared length of the vector + */ + +/** + * \fn Vector::length() + * \brief Get the length of the vector + * \return The length of the vector + */ + +/** + * \fn Vector::sum() const + * \brief Calculate the sum of all the vector elements + * \tparam R The type of the sum + * + * The type R of the sum defaults to the type T of the elements, but can be set + * explicitly to use a different type in case the type T would risk + * overflowing. + * + * \return The sum of all the vector elements + */ + +/** + * \fn Vector<T, Rows> operator*(const Matrix<T, Rows, Cols> &m, const Vector<T, Cols> &v) + * \brief Multiply a matrix by a vector + * \tparam T Numerical type of the contents of the matrix and vector + * \tparam Rows The number of rows in the matrix + * \tparam Cols The number of columns in the matrix (= rows in the vector) + * \param m The matrix + * \param v The vector + * \return Product of matrix \a m and vector \a v + */ + +/** + * \typedef RGB + * \brief A Vector of 3 elements representing an RGB pixel value + */ + +/** + * \fn bool operator==(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) + * \brief Compare vectors for equality + * \return True if the two vectors are equal, false otherwise + */ + +/** + * \fn bool operator!=(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs) + * \brief Compare vectors for inequality + * \return True if the two vectors are not equal, false otherwise + */ + +#ifndef __DOXYGEN__ +bool vectorValidateYaml(const YamlObject &obj, unsigned int size) +{ + if (!obj.isList()) + return false; + + if (obj.size() != size) { + LOG(Vector, Error) + << "Wrong number of values in YAML vector: expected " + << size << ", got " << obj.size(); + return false; + } + + return true; +} +#endif /* __DOXYGEN__ */ + +} /* namespace ipa */ + +} /* namespace libcamera */ diff --git a/test/vector.cpp b/test/vector.cpp new file mode 100644 index 000000000000..8e4ec77d7820 --- /dev/null +++ b/test/vector.cpp @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Ideas on Board Oy + * + * Vector tests + */ + +#include "../src/ipa/libipa/vector.h" + +#include <cmath> +#include <iostream> + +#include "test.h" + +using namespace libcamera::ipa; + +#define ASSERT_EQ(a, b) \ +if ((a) != (b)) { \ + std::cout << #a " != " #b << " (line " << __LINE__ << ")" \ + << std::endl; \ + return TestFail; \ +} + +class VectorTest : public Test +{ +protected: + int run() + { + Vector<double, 3> v1{ 0.0 }; + + ASSERT_EQ(v1[0], 0.0); + ASSERT_EQ(v1[1], 0.0); + ASSERT_EQ(v1[2], 0.0); + + ASSERT_EQ(v1.length(), 0.0); + ASSERT_EQ(v1.length2(), 0.0); + + Vector<double, 3> v2{{ 1.0, 4.0, 8.0 }}; + + ASSERT_EQ(v2[0], 1.0); + ASSERT_EQ(v2[1], 4.0); + ASSERT_EQ(v2[2], 8.0); + + ASSERT_EQ(v2.x(), 1.0); + ASSERT_EQ(v2.y(), 4.0); + ASSERT_EQ(v2.z(), 8.0); + + ASSERT_EQ(v2.r(), 1.0); + ASSERT_EQ(v2.g(), 4.0); + ASSERT_EQ(v2.b(), 8.0); + + ASSERT_EQ(v2.length2(), 81.0); + ASSERT_EQ(v2.length(), 9.0); + ASSERT_EQ(v2.sum(), 13.0); + + Vector<double, 3> v3{ v2 }; + + ASSERT_EQ(v2, v3); + + v3 = Vector<double, 3>{{ 4.0, 4.0, 4.0 }}; + + ASSERT_EQ(v2 + v3, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + ASSERT_EQ(v2 + 4.0, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + ASSERT_EQ(v2 - v3, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); + ASSERT_EQ(v2 - 4.0, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); + ASSERT_EQ(v2 * v3, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + ASSERT_EQ(v2 * 4.0, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + ASSERT_EQ(v2 / v3, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); + ASSERT_EQ(v2 / 4.0, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); + + ASSERT_EQ(v2.min(v3), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); + ASSERT_EQ(v2.min(4.0), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); + ASSERT_EQ(v2.max(v3), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); + ASSERT_EQ(v2.max(4.0), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); + + ASSERT_EQ(v2.dot(v3), 52.0); + + v2 += v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + v2 -= v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + v2 *= v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + v2 /= v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + + v2 += 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + v2 -= 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + v2 *= 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + v2 /= 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + + return TestPass; + } +}; + +TEST_REGISTER(VectorTest)
Prepare the move of the Vector class from libipa to libcamera by copying the relevant files into the corresponding libcamera directories. The files are copied without modification. Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com> --- include/libcamera/internal/vector.h | 370 ++++++++++++++++++++++++++++ src/libcamera/vector.cpp | 351 ++++++++++++++++++++++++++ test/vector.cpp | 100 ++++++++ 3 files changed, 821 insertions(+) create mode 100644 include/libcamera/internal/vector.h create mode 100644 src/libcamera/vector.cpp create mode 100644 test/vector.cpp