You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
6.7 KiB
295 lines
6.7 KiB
/******************************************************************************
|
|
* Project: GDAL Vector abstraction
|
|
* Purpose:
|
|
* Author: Javier Jimenez Shaw
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2024, Javier Jimenez Shaw
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
****************************************************************************/
|
|
|
|
#ifndef GDAL_VECTORX_H_INCLUDED
|
|
#define GDAL_VECTORX_H_INCLUDED
|
|
|
|
/*! @cond Doxygen_Suppress */
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <functional>
|
|
|
|
namespace gdal
|
|
{
|
|
|
|
/**
|
|
* @brief Template class to abstract a vector
|
|
*
|
|
* Inspired by Eigen3 Vector class, but much simpler.
|
|
* For GDAL internal use for now.
|
|
*
|
|
* @tparam T type of the values stored
|
|
* @tparam N size of the container/vector
|
|
*/
|
|
template <typename T, std::size_t N> class VectorX
|
|
{
|
|
public:
|
|
using value_type = T;
|
|
using size_type = std::size_t;
|
|
using self_type = VectorX<T, N>;
|
|
|
|
/** Size of the container */
|
|
static constexpr size_type size() noexcept
|
|
{
|
|
return N;
|
|
}
|
|
|
|
VectorX()
|
|
{
|
|
}
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
template <typename... Args> VectorX(Args... args) : _values({args...})
|
|
{
|
|
static_assert(N == sizeof...(Args),
|
|
"Invalid number of constructor params");
|
|
}
|
|
|
|
/** Container as an std::array */
|
|
const std::array<T, N> &array() const
|
|
{
|
|
return _values;
|
|
}
|
|
|
|
T &operator[](const size_type &pos)
|
|
{
|
|
return _values[pos];
|
|
}
|
|
|
|
const T &operator[](const size_type &pos) const
|
|
{
|
|
return _values[pos];
|
|
}
|
|
|
|
T x() const
|
|
{
|
|
static_assert(N >= 1, "Invalid template size for x()");
|
|
return _values[0];
|
|
}
|
|
|
|
T y() const
|
|
{
|
|
static_assert(N >= 2, "Invalid template size for y()");
|
|
return _values[1];
|
|
}
|
|
|
|
T z() const
|
|
{
|
|
static_assert(N >= 3, "Invalid template size for z()");
|
|
return _values[2];
|
|
}
|
|
|
|
T &x()
|
|
{
|
|
static_assert(N >= 1, "Invalid template size for x()");
|
|
return _values[0];
|
|
}
|
|
|
|
T &y()
|
|
{
|
|
static_assert(N >= 2, "Invalid template size for y()");
|
|
return _values[1];
|
|
}
|
|
|
|
T &z()
|
|
{
|
|
static_assert(N >= 3, "Invalid template size for z()");
|
|
return _values[2];
|
|
}
|
|
|
|
/** Fill all elements of the vector with the same value
|
|
* @return this
|
|
*/
|
|
self_type &fill(T arg)
|
|
{
|
|
for (size_t i = 0; i < N; i++)
|
|
(*this)[i] = arg;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Apply the unary operator to all the elements
|
|
* @param op unary operator to apply to every element
|
|
* @return a new object with the computed values
|
|
*/
|
|
template <class UnaryOp> self_type apply(UnaryOp op) const
|
|
{
|
|
self_type res;
|
|
for (size_t i = 0; i < N; i++)
|
|
res[i] = op(_values[i]);
|
|
return res;
|
|
}
|
|
|
|
self_type floor() const
|
|
{
|
|
return apply([](const value_type &v) { return std::floor(v); });
|
|
}
|
|
|
|
self_type ceil() const
|
|
{
|
|
return apply([](const value_type &v) { return std::ceil(v); });
|
|
}
|
|
|
|
/** Compute the scalar product of two vectors */
|
|
T scalarProd(const self_type &arg) const
|
|
{
|
|
T accum{};
|
|
for (size_t i = 0; i < N; i++)
|
|
accum += _values[i] * arg[i];
|
|
return accum;
|
|
}
|
|
|
|
/** Compute the norm squared of the vector */
|
|
T norm2() const
|
|
{
|
|
return scalarProd(*this);
|
|
}
|
|
|
|
/**
|
|
* @brief cast the type to a different one, and convert the elements
|
|
*
|
|
* @tparam U output value type
|
|
* @return VectorX<U, N> object of new type, where all elements are casted
|
|
*/
|
|
template <typename U> VectorX<U, N> cast() const
|
|
{
|
|
VectorX<U, N> res;
|
|
for (size_t i = 0; i < N; i++)
|
|
res[i] = static_cast<U>(_values[i]);
|
|
return res;
|
|
}
|
|
|
|
self_type operator+(T arg) const
|
|
{
|
|
return operatorImpl<std::plus<T>>(arg);
|
|
}
|
|
|
|
self_type &operator+=(T arg)
|
|
{
|
|
return operatorEqImpl<std::plus<T>>(arg);
|
|
}
|
|
|
|
self_type operator-(T arg) const
|
|
{
|
|
return operatorImpl<std::minus<T>>(arg);
|
|
}
|
|
|
|
self_type &operator-=(T arg)
|
|
{
|
|
return operatorEqImpl<std::minus<T>>(arg);
|
|
}
|
|
|
|
self_type operator-() const
|
|
{
|
|
return apply([](const value_type &v) { return -v; });
|
|
}
|
|
|
|
template <typename U> self_type operator*(U arg) const
|
|
{
|
|
self_type res;
|
|
for (size_t i = 0; i < N; i++)
|
|
res[i] = T(_values[i] * arg);
|
|
return res;
|
|
}
|
|
|
|
self_type operator*(T arg) const
|
|
{
|
|
return operatorImpl<std::multiplies<T>>(arg);
|
|
}
|
|
|
|
template <typename U> self_type operator/(U arg) const
|
|
{
|
|
self_type res;
|
|
for (size_t i = 0; i < N; i++)
|
|
res[i] = T(_values[i] / arg);
|
|
return res;
|
|
}
|
|
|
|
self_type operator/(T arg) const
|
|
{
|
|
return operatorImpl<std::divides<T>>(arg);
|
|
}
|
|
|
|
self_type operator+(const self_type &arg) const
|
|
{
|
|
return operatorImpl<std::plus<T>>(arg);
|
|
}
|
|
|
|
self_type operator-(const self_type &arg) const
|
|
{
|
|
return operatorImpl<std::minus<T>>(arg);
|
|
}
|
|
|
|
friend VectorX<T, N> operator+(T t, const VectorX<T, N> &arg)
|
|
{
|
|
VectorX<T, N> res;
|
|
for (size_t i = 0; i < N; i++)
|
|
res._values[i] = t + arg._values[i];
|
|
return res;
|
|
}
|
|
|
|
friend VectorX<T, N> operator-(T t, const VectorX<T, N> &arg)
|
|
{
|
|
VectorX<T, N> res;
|
|
for (size_t i = 0; i < N; i++)
|
|
res._values[i] = t - arg._values[i];
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
std::array<T, N> _values{};
|
|
|
|
template <class Op> self_type operatorImpl(T arg) const
|
|
{
|
|
self_type res;
|
|
auto op = Op();
|
|
for (size_t i = 0; i < N; i++)
|
|
res[i] = op(_values[i], arg);
|
|
return res;
|
|
}
|
|
|
|
template <class Op> self_type &operatorEqImpl(T arg)
|
|
{
|
|
auto op = Op();
|
|
for (size_t i = 0; i < N; i++)
|
|
_values[i] = op(_values[i], arg);
|
|
return *this;
|
|
}
|
|
|
|
template <class Op> self_type operatorImpl(const self_type &arg) const
|
|
{
|
|
self_type res;
|
|
auto op = Op();
|
|
for (size_t i = 0; i < N; i++)
|
|
res[i] = op(_values[i], arg[i]);
|
|
return res;
|
|
}
|
|
|
|
template <class Op> self_type &operatorEqImpl(const self_type &arg)
|
|
{
|
|
auto op = Op();
|
|
for (size_t i = 0; i < N; i++)
|
|
_values[i] = op(_values[i], arg[i]);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
using Vector2d = VectorX<double, 2>;
|
|
using Vector2i = VectorX<int, 2>;
|
|
using Vector3d = VectorX<double, 3>;
|
|
using Vector3i = VectorX<int, 3>;
|
|
} // namespace gdal
|
|
|
|
/*! @endcond */
|
|
|
|
#endif /* ndef GDAL_VECTORX_H_INCLUDED */
|