Files
pip/libs/main/math/pimathvector.h
2026-03-20 16:31:30 +03:00

913 lines
40 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\file pimathvector.h
//! \~\ingroup Math
//! \~\brief
//! \~english Math vector
//! \~russian Математический вектор
/*
PIP - Platform Independent Primitives
Math vector
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIMATHVECTOR_H
#define PIMATHVECTOR_H
#include "pimathbase.h"
#include "pimathcomplex.h"
template<uint Cols, uint Rows, typename Type>
class PIMathMatrixT;
#define PIMATHVECTOR_ZERO_CMP (1E-100)
/// Vector templated
#define PIMV_FOR for (uint i = 0; i < Size; ++i)
//! \~\ingroup Math
//! \~\brief
//! \~english Fixed-size mathematical vector with compile-time size
//! \~russian Вектор математический фиксированного размера с размером во время компиляции
//! \details
//! \~english Provides vector operations including arithmetic, normalization, angles, cross product, and dot product
//! \~russian Предоставляет операции вектора включая арифметику, нормализацию, углы, векторное произведение и скалярное произведение
//! \tparam Size The fixed size of the vector
//! \tparam Type The element type (arithmetic or complex)
template<uint Size, typename Type = double>
class PIP_EXPORT PIMathVectorT {
typedef PIMathVectorT<Size, Type> _CVector;
static_assert(std::is_arithmetic<Type>::value || is_complex<Type>::value, "Type must be arithmetic or complex");
static_assert(Size > 0, "Size must be > 0");
public:
//! \~english Constructs a vector and fills every coordinate with \a v.
//! \~russian Создает вектор и заполняет все координаты значением \a v.
PIMathVectorT(const Type & v = Type()) { PIMV_FOR c[i] = v; }
//! \~english Constructs a fixed-size vector from a dynamic one of the same size.
//! \~russian Создает вектор фиксированного размера из динамического вектора той же длины.
PIMathVectorT(const PIVector<Type> & val) {
assert(Size == val.size());
PIMV_FOR c[i] = val[i];
}
//! \~english Constructs a vector from an initializer list with exactly \a Size elements.
//! \~russian Создает вектор из списка инициализации ровно с \a Size элементами.
PIMathVectorT(std::initializer_list<Type> init_list) {
assert(Size == init_list.size());
PIMV_FOR c[i] = init_list.begin()[i];
}
//! \~english Builds the displacement vector from point \a st to point \a fn.
//! \~russian Строит вектор смещения от точки \a st к точке \a fn.
static _CVector fromTwoPoints(const _CVector & st, const _CVector & fn) {
_CVector tv;
PIMV_FOR tv[i] = fn[i] - st[i];
return tv;
}
//! \~english Returns the compile-time vector dimension.
//! \~russian Возвращает размерность вектора, заданную во время компиляции.
constexpr uint size() const { return Size; }
//! \~english Fills all coordinates with \a v.
//! \~russian Заполняет все координаты значением \a v.
_CVector & fill(const Type & v) {
PIMV_FOR c[i] = v;
return *this;
}
//! \~english Adds \a v to every coordinate.
//! \~russian Прибавляет \a v к каждой координате.
_CVector & move(const Type & v) {
PIMV_FOR c[i] += v;
return *this;
}
//! \~english Adds another vector component-wise.
//! \~russian Прибавляет другой вектор покомпонентно.
_CVector & move(const _CVector & v) {
PIMV_FOR c[i] += v[i];
return *this;
}
//! \~english Swaps two coordinates in place.
//! \~russian Меняет местами две координаты.
_CVector & swapElements(uint f, uint s) {
piSwap<Type>(c[f], c[s]);
return *this;
}
//! \~english Returns the squared Euclidean length.
//! \~russian Возвращает квадрат евклидовой длины.
Type lengthSqr() const {
Type tv(0);
PIMV_FOR tv += c[i] * c[i];
return tv;
}
//! \~english Returns the Euclidean length. Available for arithmetic element types.
//! \~russian Возвращает евклидову длину. Доступно для арифметических типов элементов.
Type length() const {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) return std::sqrt(lengthSqr());
// if (is_complex<Type>::value) return 1000.; // std::sqrt(lengthSqr());
}
//! \~english Returns the Manhattan length. Available for arithmetic element types.
//! \~russian Возвращает манхэттенскую длину. Доступно для арифметических типов элементов.
Type manhattanLength() const {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
Type tv(0);
PIMV_FOR tv += piAbs<Type>(c[i]);
return tv;
}
}
//! \~english Returns the cosine of the angle to \a v.
//! \~russian Возвращает косинус угла к вектору \a v.
Type angleCos(const _CVector & v) const {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
Type tv = v.length() * length();
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
return dot(v) / tv;
}
}
//! \~english Returns the sine of the angle to \a v.
//! \~russian Возвращает синус угла к вектору \a v.
Type angleSin(const _CVector & v) const {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
Type tv = angleCos(v);
return std::sqrt(Type(1) - tv * tv);
}
}
//! \~english Returns the angle to \a v in radians.
//! \~russian Возвращает угол к вектору \a v в радианах.
Type angleRad(const _CVector & v) const {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
return std::acos(angleCos(v));
}
}
//! \~english Returns the angle to \a v in degrees.
//! \~russian Возвращает угол к вектору \a v в градусах.
Type angleDeg(const _CVector & v) const {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
return toDeg(angleRad(v));
}
}
//! \~english Returns the elevation angle from this point to \a v in degrees.
//! \~russian Возвращает угол возвышения от этой точки к \a v в градусах.
Type angleElevation(const _CVector & v) const {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
return 90.0 - angleDeg(v - *this);
}
}
//! \~english Returns the projection of this vector onto \a v.
//! \~russian Возвращает проекцию этого вектора на \a v.
_CVector projection(const _CVector & v) {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
Type tv = v.length();
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
return v * (dot(v) / tv);
}
}
//! \~english Normalizes this vector in place.
//! \~russian Нормализует этот вектор на месте.
_CVector & normalize() {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
Type tv = length();
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
if (tv == Type(1)) return *this;
PIMV_FOR c[i] /= tv;
return *this;
}
}
//! \~english Returns a normalized copy of this vector.
//! \~russian Возвращает нормализованную копию этого вектора.
_CVector normalized() {
_CVector tv(*this);
tv.normalize();
return tv;
}
//! \~english Returns true when all coordinates are zero.
//! \~russian Возвращает true, если все координаты равны нулю.
bool isNull() const {
PIMV_FOR if (c[i] != Type{}) return false;
return true;
}
//! \~english Returns true when this vector is orthogonal to \a v.
//! \~russian Возвращает true, если этот вектор ортогонален \a v.
bool isOrtho(const _CVector & v) const { return ((*this) ^ v) == Type{}; }
//! \~english Returns writable access to a coordinate.
//! \~russian Возвращает доступ на запись к координате.
Type & operator[](uint index) { return c[index]; }
//! \~english Returns read-only access to a coordinate.
//! \~russian Возвращает доступ только для чтения к координате.
const Type & operator[](uint index) const { return c[index]; }
//! \~english Returns a coordinate by value.
//! \~russian Возвращает координату по значению.
Type at(uint index) const { return c[index]; }
//! \~english Returns writable access to a coordinate.
//! \~russian Возвращает доступ на запись к координате.
inline Type & element(uint index) { return c[index]; }
//! \~english Returns read-only access to a coordinate.
//! \~russian Возвращает доступ только для чтения к координате.
inline const Type & element(uint index) const { return c[index]; }
//! \~english Assigns the same value to all coordinates.
//! \~russian Присваивает всем координатам одно и то же значение.
_CVector & operator=(const Type & v) {
PIMV_FOR c[i] = v;
return *this;
}
//! \~english Compares two vectors component-wise.
//! \~russian Сравнивает два вектора покомпонентно.
bool operator==(const _CVector & v) const {
PIMV_FOR if (c[i] != v[i]) return false;
return true;
}
//! \~english Returns true when vectors differ in at least one coordinate.
//! \~russian Возвращает true, если векторы различаются хотя бы по одной координате.
bool operator!=(const _CVector & v) const { return !(*this == c); }
//! \~english Adds \a v component-wise.
//! \~russian Прибавляет \a v покомпонентно.
void operator+=(const _CVector & v) { PIMV_FOR c[i] += v[i]; }
//! \~english Subtracts \a v component-wise.
//! \~russian Вычитает \a v покомпонентно.
void operator-=(const _CVector & v) { PIMV_FOR c[i] -= v[i]; }
//! \~english Multiplies all coordinates by \a v.
//! \~russian Умножает все координаты на \a v.
void operator*=(const Type & v) { PIMV_FOR c[i] *= v; }
//! \~english Divides all coordinates by \a v.
//! \~russian Делит все координаты на \a v.
void operator/=(const Type & v) {
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
PIMV_FOR c[i] /= v;
}
//! \~english Returns the vector with inverted sign.
//! \~russian Возвращает вектор с противоположным знаком.
_CVector operator-() const {
_CVector tv;
PIMV_FOR tv[i] = -c[i];
return tv;
}
//! \~english Returns the component-wise sum with \a v.
//! \~russian Возвращает покомпонентную сумму с \a v.
_CVector operator+(const _CVector & v) const {
_CVector tv(*this);
PIMV_FOR tv[i] += v[i];
return tv;
}
//! \~english Returns the component-wise difference with \a v.
//! \~russian Возвращает покомпонентную разность с \a v.
_CVector operator-(const _CVector & v) const {
_CVector tv(*this);
PIMV_FOR tv[i] -= v[i];
return tv;
}
//! \~english Returns a copy scaled by \a v.
//! \~russian Возвращает копию, масштабированную на \a v.
_CVector operator*(const Type & v) const {
_CVector tv(*this);
PIMV_FOR tv[i] *= v;
return tv;
}
//! \~english Returns a copy divided by \a v.
//! \~russian Возвращает копию, поделенную на \a v.
_CVector operator/(const Type & v) const {
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
_CVector tv = _CVector(*this);
PIMV_FOR tv[i] /= v;
return tv;
}
//! \~english Returns the 3D cross product with \a v.
//! \~russian Возвращает 3D-векторное произведение с \a v.
_CVector cross(const _CVector & v) const {
static_assert(Size == 3, "cross product avalible only for 3D vectors");
_CVector tv;
tv[0] = c[1] * v[2] - v[1] * c[2];
tv[1] = v[0] * c[2] - c[0] * v[2];
tv[2] = c[0] * v[1] - v[0] * c[1];
return tv;
}
//! \~english Returns the scalar product with \a v.
//! \~russian Возвращает скалярное произведение с \a v.
Type dot(const _CVector & v) const {
Type tv{};
PIMV_FOR tv += c[i] * v[i];
return tv;
}
//! \~english Returns the component-wise product with \a v.
//! \~russian Возвращает покомпонентное произведение с \a v.
_CVector mul(const _CVector & v) const {
_CVector tv(*this);
PIMV_FOR tv[i] *= v[i];
return tv;
}
//! \~english Returns a copy scaled by \a v.
//! \~russian Возвращает копию, масштабированную на \a v.
_CVector mul(const Type & v) const { return (*this) * v; }
//! \~english Returns the component-wise division by \a v.
//! \~russian Возвращает покомпонентное деление на \a v.
_CVector div(const _CVector & v) const {
_CVector tv(*this);
PIMV_FOR {
assert(std::abs(v[i]) > PIMATHVECTOR_ZERO_CMP);
tv[i] /= v[i];
}
return tv;
}
//! \~english Returns a copy divided by \a v.
//! \~russian Возвращает копию, поделенную на \a v.
_CVector div(const Type & v) const { return (*this) / v; }
//! \~english Returns the vector as a 1 x Size matrix.
//! \~russian Возвращает вектор как матрицу 1 x Size.
PIMathMatrixT<1, Size, Type> transposed() const {
PIMathMatrixT<1, Size, Type> ret;
PIMV_FOR ret[0][i] = c[i];
return ret;
}
//! \~english Returns the distance from this 2D point to the line through \a lp0 and \a lp1.
//! \~russian Возвращает расстояние от этой 2D-точки до прямой через \a lp0 и \a lp1.
Type distToLine(const _CVector & lp0, const _CVector & lp1) {
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
if (std::is_arithmetic<Type>::value) {
_CVector a(lp0, lp1);
Type tv = a.length();
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
_CVector b(lp0, *this);
return piAbs<Type>(a[0] * b[1] - a[1] * b[0]) / tv;
}
}
//! \~english Converts this vector to another dimension and element type.
//! \~russian Преобразует этот вектор к другой размерности и типу элементов.
template<uint Size1, typename Type1>
PIMathVectorT<Size1, Type1> turnTo() const {
PIMathVectorT<Size1, Type1> tv;
uint sz = piMin<uint>(Size, Size1);
for (uint i = 0; i < sz; ++i)
tv[i] = c[i];
return tv;
}
//! \~english Returns this vector with another element type.
//! \~russian Возвращает этот вектор с другим типом элементов.
template<typename T>
PIMathVectorT<Size, T> toType() const {
PIMathVectorT<Size, T> ret;
PIMV_FOR ret[i] = element(i);
return ret;
}
//! \~english Returns a subvector starting at \a offset and zero-fills coordinates outside the source range.
//! \~russian Возвращает подвектор, начиная с \a offset, и заполняет нулями координаты вне исходного диапазона.
template<uint SubSize>
PIMathVectorT<SubSize, Type> subvector(int offset = 0) const {
PIMathVectorT<SubSize, Type> ret;
for (int i = 0; i < (int)SubSize; ++i) {
int si = i + offset;
if (si < 0 || si >= (int)Size) continue;
ret[i] = element(si);
}
return ret;
}
//! \~english Writes \a v into this vector starting at \a index and ignores coordinates outside the destination range.
//! \~russian Записывает \a v в этот вектор, начиная с \a index, и игнорирует координаты вне диапазона назначения.
template<uint SubSize>
PIMathVectorT<Size, Type> & setSubvector(int index, const PIMathVectorT<SubSize, Type> & v) {
for (int i = 0; i < (int)SubSize; ++i) {
int si = i + index;
if (si < 0 || si >= (int)Size) continue;
element(si) = v[i];
}
return *this;
}
//! \~english Returns the cross product of \a v1 and \a v2.
//! \~russian Возвращает векторное произведение \a v1 и \a v2.
static _CVector cross(const _CVector & v1, const _CVector & v2) { return v1.cross(v2); }
//! \~english Returns the scalar product of \a v1 and \a v2.
//! \~russian Возвращает скалярное произведение \a v1 и \a v2.
static Type dot(const _CVector & v1, const _CVector & v2) { return v1.dot(v2); }
//! \~english Returns the component-wise product of \a v1 and \a v2.
//! \~russian Возвращает покомпонентное произведение \a v1 и \a v2.
static _CVector mul(const _CVector & v1, const _CVector & v2) { return v1.mul(v2); }
//! \~english Returns \a v2 scaled by \a v1.
//! \~russian Возвращает \a v2, масштабированный на \a v1.
static _CVector mul(const Type & v1, const _CVector & v2) { return v2 * v1; }
//! \~english Returns \a v1 scaled by \a v2.
//! \~russian Возвращает \a v1, масштабированный на \a v2.
static _CVector mul(const _CVector & v1, const Type & v2) { return v1 * v2; }
//! \~english Returns the component-wise division of \a v1 by \a v2.
//! \~russian Возвращает покомпонентное деление \a v1 на \a v2.
static _CVector div(const _CVector & v1, const _CVector & v2) { return v1.div(v2); }
//! \~english Returns \a v1 divided by scalar \a v2.
//! \~russian Возвращает \a v1, поделенный на скаляр \a v2.
static _CVector div(const _CVector & v1, const Type & v2) { return v1 / v2; }
private:
Type c[Size];
};
//! \~english Multiplies a fixed-size vector by a scalar from the left.
//! \~russian Умножает вектор фиксированного размера на скаляр слева.
template<uint Size, typename Type>
inline PIMathVectorT<Size, Type> operator*(const Type & x, const PIMathVectorT<Size, Type> & v) {
return v * x;
}
//! \~english Writes a fixed-size vector to \a PICout.
//! \~russian Записывает вектор фиксированного размера в \a PICout.
template<uint Size, typename Type>
inline PICout operator<<(PICout s, const PIMathVectorT<Size, Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Vector{";
PIMV_FOR {
s << v[i];
if (i < Size - 1) s << ", ";
}
s << "}";
s.restoreControls();
return s;
}
//! \~english Two-dimensional fixed-size vector of \c int.
//! \~russian Двумерный вектор фиксированного размера из \c int.
typedef PIMathVectorT<2u, int> PIMathVectorT2i;
//! \~english Three-dimensional fixed-size vector of \c int.
//! \~russian Трехмерный вектор фиксированного размера из \c int.
typedef PIMathVectorT<3u, int> PIMathVectorT3i;
//! \~english Four-dimensional fixed-size vector of \c int.
//! \~russian Четырехмерный вектор фиксированного размера из \c int.
typedef PIMathVectorT<4u, int> PIMathVectorT4i;
//! \~english Two-dimensional fixed-size vector of \c double.
//! \~russian Двумерный вектор фиксированного размера из \c double.
typedef PIMathVectorT<2u, double> PIMathVectorT2d;
//! \~english Three-dimensional fixed-size vector of \c double.
//! \~russian Трехмерный вектор фиксированного размера из \c double.
typedef PIMathVectorT<3u, double> PIMathVectorT3d;
//! \~english Four-dimensional fixed-size vector of \c double.
//! \~russian Четырехмерный вектор фиксированного размера из \c double.
typedef PIMathVectorT<4u, double> PIMathVectorT4d;
#undef PIMV_FOR
#define PIMV_FOR for (uint i = 0; i < c.size(); ++i)
//! \~\ingroup Math
//! \~\brief
//! \~english Template class for dynamic-size mathematical vector
//! \~russian Шаблонный класс для математического вектора динамического размера
//! \details
//! \~english Provides vector operations including arithmetic, normalization, angles, cross product, and dot product for dynamic-size
//! vectors
//! \~russian Предоставляет операции вектора включая арифметику, нормализацию, углы, векторное произведение и скалярное произведение для
//! векторов динамического размера
//! \tparam Type The element type (arithmetic or complex)
template<typename Type>
class PIP_EXPORT PIMathVector {
typedef PIMathVector<Type> _CVector;
template<typename P, typename Type1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMathVector<Type1> & v);
template<typename P, typename Type1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMathVector<Type1> & v);
public:
//! \~english Constructs a vector of \a size elements initialized with \a new_value.
//! \~russian Создает вектор из \a size элементов, инициализированных значением \a new_value.
PIMathVector(const uint size = 0, const Type & new_value = Type()) { c.resize(size, new_value); }
//! \~english Constructs a vector from a raw \a PIVector.
//! \~russian Создает вектор из контейнера \a PIVector.
PIMathVector(const PIVector<Type> & val) { c = val; }
//! \~english Move-constructs a vector from a raw \a PIVector.
//! \~russian Создает вектор перемещением из контейнера \a PIVector.
PIMathVector(PIVector<Type> && val): c(std::move(val)) {}
//! \~english Constructs a vector from an initializer list.
//! \~russian Создает вектор из списка инициализации.
PIMathVector(std::initializer_list<Type> init_list) { c = PIVector<Type>(init_list); }
//! \~english Constructs a dynamic vector from a fixed-size one.
//! \~russian Создает динамический вектор из вектора фиксированного размера.
template<uint Size>
PIMathVector(const PIMathVectorT<Size, Type> & val) {
c.resize(Size);
PIMV_FOR c[i] = val[i];
}
//! \~english Builds the displacement vector from point \a st to point \a fn.
//! \~russian Строит вектор смещения от точки \a st к точке \a fn.
static PIMathVector fromTwoPoints(const _CVector & st, const _CVector & fn) {
assert(st.size() == fn.size());
_CVector v(st.size());
for (uint i = 0; i < v.size(); ++i)
v.c[i] = fn[i] - st[i];
}
//! \~english Returns a vector of \a size zeros.
//! \~russian Возвращает вектор из \a size нулей.
static PIMathVector zeros(const uint size) { return PIMathVector(size, Type()); }
//! \~english Returns a vector of \a size ones.
//! \~russian Возвращает вектор из \a size единиц.
static PIMathVector ones(const uint size) { return PIMathVector(size, Type(1)); }
//! \~english Returns a vector filled by the arithmetic progression [\a start, \a stop) with step \a step.
//! \~russian Возвращает вектор, заполненный арифметической прогрессией [\a start, \a stop) с шагом \a step.
static PIMathVector arange(const Type start, const Type stop, const Type step = Type(1)) {
PIVector<Type> v;
for (Type i = start; i < stop; i += step)
v << i;
return PIMathVector(std::move(v));
}
//! \~english Returns the current vector size.
//! \~russian Возвращает текущий размер вектора.
uint size() const { return c.size(); }
//! \~english Resizes the vector and fills new coordinates with \a new_value.
//! \~russian Изменяет размер вектора и заполняет новые координаты значением \a new_value.
_CVector & resize(uint size, const Type & new_value = Type()) {
c.resize(size, new_value);
return *this;
}
//! \~english Returns a resized copy of this vector.
//! \~russian Возвращает копию этого вектора с другим размером.
_CVector resized(uint size, const Type & new_value = Type()) {
_CVector tv = _CVector(*this);
tv.resize(size, new_value);
return tv;
}
//! \~english Fills all coordinates with \a v.
//! \~russian Заполняет все координаты значением \a v.
_CVector & fill(const Type & v) {
c.fill(v);
return *this;
}
//! \~english Adds \a v to every coordinate.
//! \~russian Прибавляет \a v к каждой координате.
_CVector & move(const Type & v) {
PIMV_FOR c[i] += v;
return *this;
}
//! \~english Adds another vector component-wise.
//! \~russian Прибавляет другой вектор покомпонентно.
_CVector & move(const _CVector & v) {
assert(c.size() == v.size());
PIMV_FOR c[i] += v[i];
return *this;
}
//! \~english Swaps two coordinates in place.
//! \~russian Меняет местами две координаты.
_CVector & swapElements(uint f, uint s) {
piSwap<Type>(c[f], c[s]);
return *this;
}
//! \~english Returns the squared Euclidean length.
//! \~russian Возвращает квадрат евклидовой длины.
Type lengthSqr() const {
Type tv(0);
PIMV_FOR tv += c[i] * c[i];
return tv;
}
//! \~english Returns the Euclidean length.
//! \~russian Возвращает евклидову длину.
Type length() const { return std::sqrt(lengthSqr()); }
//! \~english Returns the Manhattan length.
//! \~russian Возвращает манхэттенскую длину.
Type manhattanLength() const {
Type tv(0);
PIMV_FOR tv += piAbs<Type>(c[i]);
return tv;
}
//! \~english Returns the cosine of the angle to \a v.
//! \~russian Возвращает косинус угла к вектору \a v.
Type angleCos(const _CVector & v) const {
assert(c.size() == v.size());
Type tv = v.length() * length();
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
return dot(v) / tv;
}
//! \~english Returns the sine of the angle to \a v.
//! \~russian Возвращает синус угла к вектору \a v.
Type angleSin(const _CVector & v) const {
assert(c.size() == v.size());
Type tv = angleCos(v);
return std::sqrt(Type(1) - tv * tv);
}
//! \~english Returns the angle to \a v in radians.
//! \~russian Возвращает угол к вектору \a v в радианах.
Type angleRad(const _CVector & v) const { return std::acos(angleCos(v)); }
//! \~english Returns the angle to \a v in degrees.
//! \~russian Возвращает угол к вектору \a v в градусах.
Type angleDeg(const _CVector & v) const { return toDeg(angleRad(v)); }
//! \~english Returns the projection of this vector onto \a v.
//! \~russian Возвращает проекцию этого вектора на \a v.
_CVector projection(const _CVector & v) {
assert(c.size() == v.size());
Type tv = v.length();
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
return v * (dot(v) / tv);
}
//! \~english Normalizes this vector in place.
//! \~russian Нормализует этот вектор на месте.
_CVector & normalize() {
Type tv = length();
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
if (tv == Type(1)) return *this;
PIMV_FOR c[i] /= tv;
return *this;
}
//! \~english Returns a normalized copy of this vector.
//! \~russian Возвращает нормализованную копию этого вектора.
_CVector normalized() {
_CVector tv(*this);
tv.normalize();
return tv;
}
//! \~english Returns true when all coordinates are zero.
//! \~russian Возвращает true, если все координаты равны нулю.
bool isNull() const {
PIMV_FOR if (c[i] != Type(0)) return false;
return true;
}
//! \~english Returns true when the vector contains allocated storage.
//! \~russian Возвращает true, если у вектора есть выделенное хранилище.
bool isValid() const { return !c.isEmpty(); }
//! \~english Returns true when this vector is orthogonal to \a v.
//! \~russian Возвращает true, если этот вектор ортогонален \a v.
bool isOrtho(const _CVector & v) const { return dot(v) == Type(0); }
//! \~english Returns writable access to a coordinate.
//! \~russian Возвращает доступ на запись к координате.
Type & operator[](uint index) { return c[index]; }
//! \~english Returns read-only access to a coordinate.
//! \~russian Возвращает доступ только для чтения к координате.
const Type & operator[](uint index) const { return c[index]; }
//! \~english Returns a coordinate by value.
//! \~russian Возвращает координату по значению.
Type at(uint index) const { return c[index]; }
//! \~english Assigns the same value to all coordinates.
//! \~russian Присваивает всем координатам одно и то же значение.
_CVector & operator=(const Type & v) {
PIMV_FOR c[i] = v;
return *this;
}
//! \~english Compares two vectors component-wise.
//! \~russian Сравнивает два вектора покомпонентно.
bool operator==(const _CVector & v) const { return c == v.c; }
//! \~english Returns true when vectors differ in at least one coordinate.
//! \~russian Возвращает true, если векторы различаются хотя бы по одной координате.
bool operator!=(const _CVector & v) const { return c != v.c; }
//! \~english Adds \a v component-wise.
//! \~russian Прибавляет \a v покомпонентно.
void operator+=(const _CVector & v) {
assert(c.size() == v.size());
PIMV_FOR c[i] += v[i];
}
//! \~english Subtracts \a v component-wise.
//! \~russian Вычитает \a v покомпонентно.
void operator-=(const _CVector & v) {
assert(c.size() == v.size());
PIMV_FOR c[i] -= v[i];
}
//! \~english Multiplies all coordinates by \a v.
//! \~russian Умножает все координаты на \a v.
void operator*=(const Type & v) { PIMV_FOR c[i] *= v; }
//! \~english Divides all coordinates by \a v.
//! \~russian Делит все координаты на \a v.
void operator/=(const Type & v) {
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
PIMV_FOR c[i] /= v;
}
//! \~english Returns the vector with inverted sign.
//! \~russian Возвращает вектор с противоположным знаком.
_CVector operator-() const {
_CVector tv(c.size());
PIMV_FOR tv[i] = -c[i];
return tv;
}
//! \~english Returns the component-wise sum with \a v.
//! \~russian Возвращает покомпонентную сумму с \a v.
_CVector operator+(const _CVector & v) const {
assert(c.size() == v.size());
_CVector tv(*this);
PIMV_FOR tv[i] += v[i];
return tv;
}
//! \~english Returns the component-wise difference with \a v.
//! \~russian Возвращает покомпонентную разность с \a v.
_CVector operator-(const _CVector & v) const {
assert(c.size() == v.size());
_CVector tv(*this);
PIMV_FOR tv[i] -= v[i];
return tv;
}
//! \~english Returns a copy scaled by \a v.
//! \~russian Возвращает копию, масштабированную на \a v.
_CVector operator*(const Type & v) const {
_CVector tv(*this);
PIMV_FOR tv[i] *= v;
return tv;
}
//! \~english Returns a copy divided by \a v.
//! \~russian Возвращает копию, поделенную на \a v.
_CVector operator/(const Type & v) const {
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
_CVector tv(*this);
PIMV_FOR tv[i] /= v;
return tv;
}
//! \~english Returns the 3D cross product with \a v.
//! \~russian Возвращает 3D-векторное произведение с \a v.
_CVector cross(const _CVector & v) const {
assert(c.size() == 3);
assert(v.size() == 3);
_CVector tv(3);
tv[0] = c[1] * v[2] - v[1] * c[2];
tv[1] = c[2] * v[0] - v[2] * c[0];
tv[2] = c[0] * v[1] - v[0] * c[1];
return tv;
}
//! \~english Returns the scalar product with \a v.
//! \~russian Возвращает скалярное произведение с \a v.
Type dot(const _CVector & v) const {
assert(c.size() == v.size());
Type tv(0);
PIMV_FOR tv += c[i] * v[i];
return tv;
}
//! \~english Returns the component-wise product with \a v.
//! \~russian Возвращает покомпонентное произведение с \a v.
_CVector mul(const _CVector & v) const {
assert(c.size() == v.size());
_CVector tv(*this);
PIMV_FOR tv[i] *= v[i];
return tv;
}
//! \~english Returns a copy scaled by \a v.
//! \~russian Возвращает копию, масштабированную на \a v.
_CVector mul(const Type & v) const { return (*this) * v; }
//! \~english Returns the component-wise division by \a v.
//! \~russian Возвращает покомпонентное деление на \a v.
_CVector div(const _CVector & v) const {
assert(c.size() == v.size());
_CVector tv(*this);
PIMV_FOR {
assert(std::abs(v[i]) > PIMATHVECTOR_ZERO_CMP);
tv[i] /= v[i];
}
return tv;
}
//! \~english Returns a copy divided by \a v.
//! \~russian Возвращает копию, поделенную на \a v.
_CVector div(const Type & v) const { return (*this) / v; }
//! \~english Returns the distance from this 2D point to the line through \a lp0 and \a lp1.
//! \~russian Возвращает расстояние от этой 2D-точки до прямой через \a lp0 и \a lp1.
Type distToLine(const _CVector & lp0, const _CVector & lp1) {
assert(c.size() == lp0.size());
assert(c.size() == lp1.size());
_CVector a = _CVector::fromTwoPoints(lp0, lp1);
Type tv = a.length();
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
_CVector b = _CVector::fromTwoPoints(lp0, *this);
return piAbs<Type>(a[0] * b[1] - a[1] * b[0]) / tv;
}
//! \~english Returns the underlying \a PIVector copy.
//! \~russian Возвращает копию базового контейнера \a PIVector.
PIVector<Type> toVector() const { return c; }
//! \~english Applies \a f to every coordinate without modifying the vector.
//! \~russian Применяет \a f к каждой координате без изменения вектора.
void forEach(std::function<void(const Type &)> f) const { c.forEach(std::move(f)); }
//! \~english Applies \a f to every coordinate and returns this vector.
//! \~russian Применяет \a f к каждой координате и возвращает этот вектор.
_CVector & forEach(std::function<void(Type &)> f) {
c.forEach(std::move(f));
return *this;
}
//! \~english Returns a writable pointer to contiguous vector data.
//! \~russian Возвращает указатель на непрерывные данные вектора для записи.
inline Type * data() { return c.data(); }
//! \~english Returns a read-only pointer to contiguous vector data.
//! \~russian Возвращает указатель на непрерывные данные вектора только для чтения.
inline const Type * data() const { return c.data(); }
//! \~english Returns the cross product of \a v1 and \a v2.
//! \~russian Возвращает векторное произведение \a v1 и \a v2.
static _CVector cross(const _CVector & v1, const _CVector & v2) { return v1.cross(v2); }
//! \~english Returns the scalar product of \a v1 and \a v2.
//! \~russian Возвращает скалярное произведение \a v1 и \a v2.
static Type dot(const _CVector & v1, const _CVector & v2) { return v1.dot(v2); }
//! \~english Returns the component-wise product of \a v1 and \a v2.
//! \~russian Возвращает покомпонентное произведение \a v1 и \a v2.
static _CVector mul(const _CVector & v1, const _CVector & v2) { return v1.mul(v2); }
//! \~english Returns \a v2 scaled by \a v1.
//! \~russian Возвращает \a v2, масштабированный на \a v1.
static _CVector mul(const Type & v1, const _CVector & v2) { return v2 * v1; }
//! \~english Returns \a v1 scaled by \a v2.
//! \~russian Возвращает \a v1, масштабированный на \a v2.
static _CVector mul(const _CVector & v1, const Type & v2) { return v1 * v2; }
//! \~english Returns the component-wise division of \a v1 by \a v2.
//! \~russian Возвращает покомпонентное деление \a v1 на \a v2.
static _CVector div(const _CVector & v1, const _CVector & v2) { return v1.div(v2); }
//! \~english Returns \a v1 divided by scalar \a v2.
//! \~russian Возвращает \a v1, поделенный на скаляр \a v2.
static _CVector div(const _CVector & v1, const Type & v2) { return v1 / v2; }
private:
PIVector<Type> c;
};
//! \~english Multiplies a dynamic vector by a scalar from the left.
//! \~russian Умножает динамический вектор на скаляр слева.
template<typename Type>
inline PIMathVector<Type> operator*(const Type & x, const PIMathVector<Type> & v) {
return v * x;
}
#undef PIMV_FOR
#ifdef PIP_STD_IOSTREAM
template<typename Type>
inline std::ostream & operator<<(std::ostream & s, const PIMathVector<Type> & v) {
s << "{";
for (uint i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
return s;
}
#endif
//! \~english Writes a dynamic vector to \a PICout.
//! \~russian Записывает динамический вектор в \a PICout.
template<typename Type>
inline PICout operator<<(PICout s, const PIMathVector<Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Vector{";
for (uint i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControls();
return s;
}
//! \~english Serializes a dynamic vector into a \a PIBinaryStream.
//! \~russian Сериализует динамический вектор в \a PIBinaryStream.
template<typename P, typename T>
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMathVector<T> & v) {
s << v.c;
return s;
}
//! \~english Deserializes a dynamic vector from a \a PIBinaryStream.
//! \~russian Десериализует динамический вектор из \a PIBinaryStream.
template<typename P, typename T>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMathVector<T> & v) {
s >> v.c;
return s;
}
//! \~english Dynamic vector of \c int.
//! \~russian Динамический вектор из \c int.
typedef PIMathVector<int> PIMathVectori;
//! \~english Dynamic vector of \c double.
//! \~russian Динамический вектор из \c double.
typedef PIMathVector<double> PIMathVectord;
#endif // PIMATHVECTOR_H