[PATCH v6 1/4] ipa: libipa: Add Vector class

Paul Elder paul.elder at ideasonboard.com
Fri Jun 7 10:42:58 CEST 2024


Add a vector class to libipa. The original purpose of this is to replace
the floating-point Point class that Raspberry Pi used in their Pwl, as
that implementation of Point seemed more akin to a Vector than a Point.

This is added to libipa instead of to geometry.h to avoid public API
issues, plus this is not expected to be needed by applications.

Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>

---
No change in v6

New in v5
---
 src/ipa/libipa/vector.cpp | 162 ++++++++++++++++++++++++++++++
 src/ipa/libipa/vector.h   | 206 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 368 insertions(+)
 create mode 100644 src/ipa/libipa/vector.cpp
 create mode 100644 src/ipa/libipa/vector.h

diff --git a/src/ipa/libipa/vector.cpp b/src/ipa/libipa/vector.cpp
new file mode 100644
index 000000000..bdc3c447c
--- /dev/null
+++ b/src/ipa/libipa/vector.cpp
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi Ltd
+ * Copyright (C) 2024, Paul Elder <paul.elder at 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 R Number of rows in the vector
+ */
+
+/**
+ * \fn Vector::Vector()
+ * \brief Construct an identity vector
+ */
+
+/**
+ * \fn Vector::Vector(const std::array<T, R> &data)
+ * \brief Construct vector from supplied data
+ * \param data Data from which to construct a vector
+ *
+ * \a data is a one-dimensional vector and will be turned into a vector in
+ * row-major order. The size of \a data must be equal to the product of the
+ * number of rows and columns of the vector (RxC).
+ */
+
+/**
+ * \fn Vector::readYaml
+ * \brief Populate the vector with yaml data
+ * \param yaml Yaml data to populate the vector with
+ *
+ * Any existing data in the vector will be overwritten. The size of the data
+ * read from \a yaml must be equal to the product of the number of rows and
+ * columns of the vector (RxC).
+ *
+ * The yaml data is expected to be a list with elements of type T.
+ *
+ * \return 0 on success, negative error code otherwise
+ */
+
+/**
+ * \fn Vector::toString
+ * \brief Assemble and return a string describing the vector
+ * \return A string describing the vector
+ */
+
+/**
+ * \fn T Vector::operator[](size_t i) const
+ * \brief Index to a row in the vector
+ * \param i Index of row to retrieve
+ *
+ * This operator[] returns a Span, which can then be indexed into again with
+ * another operator[], allowing a convenient m[i][j] to access elements of the
+ * vector. Note that the lifetime of the Span returned by this first-level
+ * operator[] is bound to that of the Vector itself, so it is not recommended
+ * to save the Span that is the result of this operator[].
+ *
+ * \return Row \a i from the vector, as a Span
+ */
+
+/**
+ * \fn T &Vector::operator[](size_t i)
+ * \copydoc Vector::operator[](size_t i) const
+ */
+
+/**
+ * \fn Vector::x()
+ * \brief Convenience function to access the first element of the vector
+ */
+
+/**
+ * \fn Vector::y()
+ * \brief Convenience function to access the second element of the vector
+ */
+
+/**
+ * \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 Subtract one vector from another
+ * \param[in] other The other vector
+ * \return The difference of \a other from this vector
+ */
+
+/**
+ * \fn Vector::operator+()
+ * \brief Add two vectors together
+ * \param[in] other The other vector
+ * \return The sum of the two vectors
+ */
+
+/**
+ * \fn Vector::operator*(const Vector<T, R> &other) const
+ * \brief Compute the dot product
+ * \param[in] other The other vector
+ * \return The dot product of the two vectors
+ */
+
+/**
+ * \fn Vector::operator*(T factor) const
+ * \brief Scale up the vector
+ * \param[in] factor The factor
+ * \return The vector scaled up by \a factor
+ */
+
+/**
+ * \fn Vector::operator/()
+ * \brief Scale down the vector
+ * \param[in] factor The factor
+ * \return The vector scaled down by \a factor
+ */
+
+/**
+ * \fn Vector::len2()
+ * \brief Get the squared length of the vector
+ * \return The squared length of the vector
+ */
+
+/**
+ * \fn Vector::len()
+ * \brief Get the length of the vector
+ * \return The length of the vector
+ */
+
+/**
+ * \fn bool operator==(const Vector<T, R> &lhs, const Vector<T, R> &rhs)
+ * \brief Compare vectors for equality
+ * \return True if the two vectors are equal, false otherwise
+ */
+
+/**
+ * \fn bool operator!=(const Vector<T, R> &lhs, const Vector<T, R> &rhs)
+ * \brief Compare vectors for inequality
+ * \return True if the two vectors are not equal, false otherwise
+ */
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/vector.h b/src/ipa/libipa/vector.h
new file mode 100644
index 000000000..87aad28b5
--- /dev/null
+++ b/src/ipa/libipa/vector.h
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi Ltd
+ * Copyright (C) 2024, Paul Elder <paul.elder at ideasonboard.com>
+ *
+ * Vector and related operations
+ */
+#pragma once
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <sstream>
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/span.h>
+
+#include "libcamera/internal/yaml_parser.h"
+
+namespace libcamera {
+
+LOG_DECLARE_CATEGORY(Vector)
+
+namespace ipa {
+
+#ifndef __DOXYGEN__
+template<typename T, unsigned int R,
+	 std::enable_if_t<std::is_arithmetic_v<T> && R >= 2> * = nullptr>
+#else
+template<typename T, unsigned int R>
+#endif /* __DOXYGEN__ */
+class Vector
+{
+public:
+	Vector() = default;
+
+	Vector(const std::array<T, R> &data)
+	{
+		ASSERT(data.size() == R);
+
+		for (unsigned int i = 0; i < R; i++)
+			data_[i] = data[i];
+	}
+
+	~Vector() = default;
+
+	int readYaml(const libcamera::YamlObject &yaml)
+	{
+		if (yaml.size() != R) {
+			LOG(Vector, Error)
+				<< "Wrong number of values in vector: expected "
+				<< R << ", got " << yaml.size();
+			return -EINVAL;
+		}
+
+		unsigned int i = 0;
+		for (const auto &x : yaml.asList()) {
+			auto value = x.get<T>();
+			if (!value) {
+				LOG(Vector, Error) << "Failed to read vector value";
+				return -EINVAL;
+			}
+
+			data_[i++] = *value;
+		}
+
+		return 0;
+	}
+
+	const std::string toString() const
+	{
+		std::stringstream out;
+
+		out << "Vector { ";
+		for (unsigned int i = 0; i < R; i++) {
+			out << (*this)[i];
+			out << ((i + 1 < R) ? ", " : " ");
+		}
+		out << " }";
+
+		return out.str();
+	}
+
+	const T operator[](size_t i) const
+	{
+		return data_[i];
+	}
+
+	T &operator[](size_t i)
+	{
+		return data_[i];
+	}
+
+	const T x() const
+	{
+		return data_[0];
+	}
+
+	const T y() const
+	{
+		return data_[1];
+	}
+
+	constexpr Vector<T, R> operator-() const
+	{
+		Vector<T, R> ret;
+		for (unsigned int i = 0; i < R; i++)
+			ret[i] = -data_[i];
+		return ret;
+	}
+
+	constexpr Vector<T, R> operator-(const Vector<T, R> &other) const
+	{
+		Vector<T, R> ret;
+		for (unsigned int i = 0; i < R; i++)
+			ret[i] = data_[i] - other[i];
+		return ret;
+	}
+
+	constexpr Vector<T, R> operator+(const Vector<T, R> &other) const
+	{
+		Vector<T, R> ret;
+		for (unsigned int i = 0; i < R; i++)
+			ret[i] = data_[i] + other[i];
+		return ret;
+	}
+
+	constexpr T operator*(const Vector<T, R> &other) const
+	{
+		T ret = 0;
+		for (unsigned int i = 0; i < R; i++)
+			ret += data_[i] * other[i];
+		return ret;
+	}
+
+	constexpr Vector<T, R> operator*(T factor) const
+	{
+		Vector<T, R> ret;
+		for (unsigned int i = 0; i < R; i++)
+			ret[i] = data_[i] * factor;
+		return ret;
+	}
+
+	constexpr Vector<T, R> operator/(T factor) const
+	{
+		Vector<T, R> ret;
+		for (unsigned int i = 0; i < R; i++)
+			ret[i] = data_[i] / factor;
+		return ret;
+	}
+
+	constexpr T len2() const
+	{
+		T ret = 0;
+		for (unsigned int i = 0; i < R; i++)
+			ret += data_[i] * data_[i];
+		return ret;
+	}
+
+	constexpr double len() const
+	{
+		return std::sqrt(len2());
+	}
+
+private:
+	std::array<T, R> data_;
+};
+
+#ifndef __DOXYGEN__
+template<typename T, unsigned int R,
+	 std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
+#endif /* __DOXYGEN__ */
+bool operator==(const Vector<T, R> &lhs, const Vector<T, R> &rhs)
+{
+	for (unsigned int i = 0; i < R; i++)
+		if (lhs[i] != rhs[i])
+			return false;
+
+	return true;
+}
+
+#ifndef __DOXYGEN__
+template<typename T, unsigned int R,
+	 std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
+#endif /* __DOXYGEN__ */
+bool operator!=(const Vector<T, R> &lhs, const Vector<T, R> &rhs)
+{
+	for (unsigned int i = 0; i < R; i++)
+		if (lhs[i] != rhs[i])
+			return true;
+
+	return false;
+}
+
+} /* namespace ipa */
+
+#ifndef __DOXYGEN__
+template<typename T, unsigned int R>
+std::ostream &operator<<(std::ostream &out, const ipa::Vector<T, R> &v)
+{
+	out << v.toString();
+	return out;
+}
+#endif /* __DOXYGEN__ */
+
+} /* namespace libcamera */
-- 
2.39.2



More information about the libcamera-devel mailing list