summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Klug <stefan.klug@ideasonboard.com>2025-02-06 15:10:08 +0100
committerStefan Klug <stefan.klug@ideasonboard.com>2025-02-12 14:26:27 +0100
commite506b45822472c23368809f4bfe0289826c5756a (patch)
tree42387802a2b368cdca4b9b0933f25fe70d1edce3
parentbea2db5e6190e008dec880f2cc02172115126007 (diff)
libcamera: Copy Vector class files from libipa
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> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r--include/libcamera/internal/vector.h370
-rw-r--r--src/libcamera/vector.cpp351
-rw-r--r--test/vector.cpp100
3 files changed, 821 insertions, 0 deletions
diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h
new file mode 100644
index 00000000..fe33c9d6
--- /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 00000000..8019f8cf
--- /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 00000000..8e4ec77d
--- /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)