/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2024, Paul Elder * * Vector and related operations */ #pragma once #include #include #include #include #include #include #include #include #include #include "libcamera/internal/yaml_parser.h" #include "matrix.h" namespace libcamera { LOG_DECLARE_CATEGORY(Vector) namespace ipa { #ifndef __DOXYGEN__ template> * = nullptr> #else template #endif /* __DOXYGEN__ */ class Vector { public: constexpr Vector() = default; constexpr explicit Vector(T scalar) { data_.fill(scalar); } constexpr Vector(const std::array &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 operator-() const { Vector 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 &other) const { T ret = 0; for (unsigned int i = 0; i < Rows; i++) ret += data_[i] * other[i]; return ret; } #ifndef __DOXYGEN__ template= 1>> #endif /* __DOXYGEN__ */ constexpr const T &x() const { return data_[0]; } #ifndef __DOXYGEN__ template= 2>> #endif /* __DOXYGEN__ */ constexpr const T &y() const { return data_[1]; } #ifndef __DOXYGEN__ template= 3>> #endif /* __DOXYGEN__ */ constexpr const T &z() const { return data_[2]; } #ifndef __DOXYGEN__ template= 1>> #endif /* __DOXYGEN__ */ constexpr T &x() { return data_[0]; } #ifndef __DOXYGEN__ template= 2>> #endif /* __DOXYGEN__ */ constexpr T &y() { return data_[1]; } #ifndef __DOXYGEN__ template= 3>> #endif /* __DOXYGEN__ */ constexpr T &z() { return data_[2]; } #ifndef __DOXYGEN__ template= 1>> #endif /* __DOXYGEN__ */ constexpr const T &r() const { return data_[0]; } #ifndef __DOXYGEN__ template= 2>> #endif /* __DOXYGEN__ */ constexpr const T &g() const { return data_[1]; } #ifndef __DOXYGEN__ template= 3>> #endif /* __DOXYGEN__ */ constexpr const T &b() const { return data_[2]; } #ifndef __DOXYGEN__ template= 1>> #endif /* __DOXYGEN__ */ constexpr T &r() { return data_[0]; } #ifndef __DOXYGEN__ template= 2>> #endif /* __DOXYGEN__ */ constexpr T &g() { return data_[1]; } #ifndef __DOXYGEN__ template= 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 constexpr R sum() const { return std::accumulate(data_.begin(), data_.end(), R{}); } private: template 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 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 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 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 data_; }; template using RGB = Vector; template Vector operator*(const Matrix &m, const Vector &v) { Vector 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 bool operator==(const Vector &lhs, const Vector &rhs) { for (unsigned int i = 0; i < Rows; i++) { if (lhs[i] != rhs[i]) return false; } return true; } template bool operator!=(const Vector &lhs, const Vector &rhs) { return !(lhs == rhs); } #ifndef __DOXYGEN__ bool vectorValidateYaml(const YamlObject &obj, unsigned int size); #endif /* __DOXYGEN__ */ } /* namespace ipa */ #ifndef __DOXYGEN__ template std::ostream &operator<<(std::ostream &out, const ipa::Vector &v) { out << "Vector { "; for (unsigned int i = 0; i < Rows; i++) { out << v[i]; out << ((i + 1 < Rows) ? ", " : " "); } out << " }"; return out; } template struct YamlObject::Getter> { std::optional> get(const YamlObject &obj) const { if (!ipa::vectorValidateYaml(obj, Rows)) return std::nullopt; ipa::Vector vector; unsigned int i = 0; for (const YamlObject &entry : obj.asList()) { const auto value = entry.get(); if (!value) return std::nullopt; vector[i++] = *value; } return vector; } }; #endif /* __DOXYGEN__ */ } /* namespace libcamera */