//! \addtogroup Math //! \{ //! \file pimathvector.h //! \brief //! \~english Math vector //! \~russian Математический вектор //! \details //! \~english Fixed-size and dynamic mathematical vector implementations. Provides PIMathVectorT for compile-time fixed-size vectors and //! PIMathVector for runtime dynamic-size vectors with support for arithmetic and complex number types. //! \~russian Реализации математических векторов фиксированного и динамического размера. Предоставляет PIMathVectorT для векторов //! фиксированного размера во время компиляции и PIMathVector для векторов динамического размера во время выполнения с поддержкой //! арифметических и комплексных типов чисел. //! \} /* PIP - Platform Independent Primitives PIMathVector 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 . */ #ifndef PIMATHVECTOR_H #define PIMATHVECTOR_H #include "pimathbase.h" #include "pimathcomplex.h" template class PIMathMatrixT; #define PIMATHVECTOR_ZERO_CMP (1E-100) /// Vector templated #define PIMV_FOR for (uint i = 0; i < Size; ++i) //! \~english Template class for fixed-size mathematical vector //! \~russian Шаблонный класс для математического вектора фиксированного размера //! \brief Fixed-size mathematical vector with compile-time size //! \~english Fixed-size mathematical vector with compile-time size //! \~russian Вектор математический фиксированного размера с размером во время компиляции //! \details 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 class PIP_EXPORT PIMathVectorT { typedef PIMathVectorT _CVector; static_assert(std::is_arithmetic::value || is_complex::value, "Type must be arithmetic or complex"); static_assert(Size > 0, "Size must be > 0"); public: //! \~english Constructor with default value for all elements //! \~russian Конструктор со значением по умолчанию для всех элементов //! \param v The value to initialize all elements PIMathVectorT(const Type & v = Type()) { PIMV_FOR c[i] = v; } //! \~english Constructor from PIVector //! \~russian Конструктор из PIVector //! \param val The PIVector to copy from PIMathVectorT(const PIVector & val) { assert(Size == val.size()); PIMV_FOR c[i] = val[i]; } //! \~english Constructor from initializer list //! \~russian Конструктор из списка инициализации //! \param init_list The initializer list to copy from PIMathVectorT(std::initializer_list init_list) { assert(Size == init_list.size()); PIMV_FOR c[i] = init_list.begin()[i]; } //! \~english Create vector from two points (st -> fn) //! \~russian Создать вектор из двух точек (st -> fn) //! \param st The start point //! \param fn The finish point //! \returns Vector from st to fn static _CVector fromTwoPoints(const _CVector & st, const _CVector & fn) { _CVector tv; PIMV_FOR tv[i] = fn[i] - st[i]; return tv; } //! \~english Get vector size //! \~russian Получить размер вектора //! \returns The fixed size of the vector constexpr uint size() const { return Size; } //! \~english Fill vector with a single value //! \~russian Заполнить вектор одним значением //! \param v The value to fill //! \returns Reference to this vector _CVector & fill(const Type & v) { PIMV_FOR c[i] = v; return *this; } //! \~english Add value to all elements //! \~russian Прибавить значение ко всем элементам //! \param v The value to add //! \returns Reference to this vector _CVector & move(const Type & v) { PIMV_FOR c[i] += v; return *this; } //! \~english Add vector to this vector //! \~russian Прибавить вектор к этому вектору //! \param v The vector to add //! \returns Reference to this vector _CVector & move(const _CVector & v) { PIMV_FOR c[i] += v[i]; return *this; } //! \~english Swap two elements //! \~russian Поменять два элемента местами //! \param f First element index //! \param s Second element index //! \returns Reference to this vector _CVector & swapElements(uint f, uint s) { piSwap(c[f], c[s]); return *this; } //! \~english Get squared length of vector //! \~russian Получить квадрат длины вектора //! \returns Sum of squares of all elements Type lengthSqr() const { Type tv(0); PIMV_FOR tv += c[i] * c[i]; return tv; } //! \~english Get length of vector //! \~russian Получить длину вектора //! \returns Square root of lengthSqr, unavailable for complex types Type length() const { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) return std::sqrt(lengthSqr()); // if (is_complex::value) return 1000.; // std::sqrt(lengthSqr()); } //! \~english Get Manhattan length (sum of absolute values) //! \~russian Получить манхэттенскую длину (сумма абсолютных значений) //! \returns Sum of absolute values of all elements, unavailable for complex types Type manhattanLength() const { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { Type tv(0); PIMV_FOR tv += piAbs(c[i]); return tv; } } //! \~english Get cosine of angle between two vectors //! \~russian Получить косинус угла между двумя векторами //! \param v The other vector //! \returns cos(angle), unavailable for complex types Type angleCos(const _CVector & v) const { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { Type tv = v.length() * length(); assert(piAbs(tv) > PIMATHVECTOR_ZERO_CMP); return dot(v) / tv; } } //! \~english Get sine of angle between two vectors //! \~russian Получить синус угла между двумя векторами //! \param v The other vector //! \returns sin(angle), unavailable for complex types Type angleSin(const _CVector & v) const { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { Type tv = angleCos(v); return std::sqrt(Type(1) - tv * tv); } } //! \~english Get angle in radians between two vectors //! \~russian Получить угол в радианах между двумя векторами //! \param v The other vector //! \returns Angle in radians, unavailable for complex types Type angleRad(const _CVector & v) const { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { return std::acos(angleCos(v)); } } //! \~english Get angle in degrees between two vectors //! \~russian Получить угол в градусах между двумя векторами //! \param v The other vector //! \returns Angle in degrees, unavailable for complex types Type angleDeg(const _CVector & v) const { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { return toDeg(angleRad(v)); } } //! \~english Get elevation angle //! \~russian Получить угол возвышения //! \param v The other vector //! \returns Elevation angle in degrees, unavailable for complex types Type angleElevation(const _CVector & v) const { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { return 90.0 - angleDeg(v - *this); } } //! \~english Get projection of this vector onto another vector //! \~russian Получить проекцию этого вектора на другой вектор //! \param v The vector to project onto //! \returns Projection vector, unavailable for complex types _CVector projection(const _CVector & v) { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { Type tv = v.length(); assert(piAbs(tv) > PIMATHVECTOR_ZERO_CMP); return v * (dot(v) / tv); } } //! \~english Normalize vector in place //! \~russian Нормализовать вектор на месте //! \returns Reference to this vector, unavailable for complex types _CVector & normalize() { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { Type tv = length(); assert(piAbs(tv) > PIMATHVECTOR_ZERO_CMP); if (tv == Type(1)) return *this; PIMV_FOR c[i] /= tv; return *this; } } //! \~english Get normalized copy of vector //! \~russian Получить нормализованную копию вектора //! \returns New normalized vector, unavailable for complex types _CVector normalized() { _CVector tv(*this); tv.normalize(); return tv; } //! \~english Check if vector is null (all elements zero) //! \~russian Проверить, является ли вектор нулевым (все элементы нули) //! \returns true if vector is null bool isNull() const { PIMV_FOR if (c[i] != Type{}) return false; return true; } //! \~english Check if vectors are orthogonal //! \~russian Проверить, перпендикулярны ли векторы //! \param v The other vector //! \returns true if vectors are orthogonal bool isOrtho(const _CVector & v) const { return ((*this) ^ v) == Type{}; } //! \~english Get element at index (non-const) //! \~russian Получить элемент по индексу (non-const) //! \param index Element index //! \returns Reference to element Type & operator[](uint index) { return c[index]; } //! \~english Get element at index (const) //! \~russian Получить элемент по индексу (const) //! \param index Element index //! \returns Copy of element const Type & operator[](uint index) const { return c[index]; } //! \~english Get element at index (const version) //! \~russian Получить элемент по индексу (версия const) //! \param index Element index //! \returns Copy of element Type at(uint index) const { return c[index]; } //! \~english Get element at index (non-const, alternative) //! \~russian Получить элемент по индексу (non-const, альтернативный метод) //! \param index Element index //! \returns Reference to element inline Type & element(uint index) { return c[index]; } //! \~english Get element at index (const, alternative) //! \~russian Получить элемент по индексу (const, альтернативный метод) //! \param index Element index //! \returns Copy of element inline const Type & element(uint index) const { return c[index]; } //! \~english Assign value to all elements //! \~russian Присвоить значение всем элементам //! \param v The value to assign //! \returns Reference to this vector _CVector & operator=(const Type & v) { PIMV_FOR c[i] = v; return *this; } //! \~english Check equality with another vector //! \~russian Проверить равенство с другим вектором //! \param v The vector to compare with //! \returns true if all elements are equal bool operator==(const _CVector & v) const { PIMV_FOR if (c[i] != v[i]) return false; return true; } //! \~english Check inequality with another vector //! \~russian Проверить неравенство с другим вектором //! \param v The vector to compare with //! \returns true if any element differs bool operator!=(const _CVector & v) const { return !(*this == c); } //! \~english Add vector to this vector //! \~russian Прибавить вектор к этому вектору //! \param v The vector to add void operator+=(const _CVector & v) { PIMV_FOR c[i] += v[i]; } //! \~english Subtract vector from this vector //! \~russian Вычесть вектор из этого вектора //! \param v The vector to subtract void operator-=(const _CVector & v) { PIMV_FOR c[i] -= v[i]; } //! \~english Multiply all elements by scalar //! \~russian Умножить все элементы на скаляр //! \param v The scalar to multiply by void operator*=(const Type & v) { PIMV_FOR c[i] *= v; } //! \~english Divide all elements by scalar //! \~russian Разделить все элементы на скаляр //! \param v The scalar to divide by void operator/=(const Type & v) { assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP); PIMV_FOR c[i] /= v; } //! \~english Unary minus operator //! \~russian Унарный оператор минус //! \returns New vector with negated elements _CVector operator-() const { _CVector tv; PIMV_FOR tv[i] = -c[i]; return tv; } //! \~english Add two vectors //! \~russian Сложить два вектора //! \param v The vector to add //! \returns New vector with sum of elements _CVector operator+(const _CVector & v) const { _CVector tv(*this); PIMV_FOR tv[i] += v[i]; return tv; } //! \~english Subtract two vectors //! \~russian Вычесть два вектора //! \param v The vector to subtract //! \returns New vector with difference of elements _CVector operator-(const _CVector & v) const { _CVector tv(*this); PIMV_FOR tv[i] -= v[i]; return tv; } //! \~english Multiply vector by scalar //! \~russian Умножить вектор на скаляр //! \param v The scalar to multiply by //! \returns New vector with scaled elements _CVector operator*(const Type & v) const { _CVector tv(*this); PIMV_FOR tv[i] *= v; return tv; } //! \~english Divide vector by scalar //! \~russian Разделить вектор на скаляр //! \param v The scalar to divide by //! \returns New vector with scaled elements _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 Compute cross product with another vector (3D only) //! \~russian Вычислить векторное произведение с другим вектором (только 3D) //! \param v The other vector //! \returns Cross product vector _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 Compute dot product with another vector //! \~russian Вычислить скалярное произведение с другим вектором //! \param v The other vector //! \returns Dot product (sum of element-wise products) Type dot(const _CVector & v) const { Type tv{}; PIMV_FOR tv += c[i] * v[i]; return tv; } //! \~english Element-wise multiplication with another vector //! \~russian Покомпонентное умножение с другим вектором //! \param v The other vector //! \returns New vector with element-wise products _CVector mul(const _CVector & v) const { _CVector tv(*this); PIMV_FOR tv[i] *= v[i]; return tv; } //! \~english Element-wise multiplication with scalar //! \~russian Покомпонентное умножение на скаляр //! \param v The scalar to multiply by //! \returns New vector with scaled elements _CVector mul(const Type & v) const { return (*this) * v; } //! \~english Element-wise division by another vector //! \~russian Покомпонентное деление на другой вектор //! \param v The vector to divide by //! \returns New vector with element-wise quotients _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 Element-wise division by scalar //! \~russian Покомпонентное деление на скаляр //! \param v The scalar to divide by //! \returns New vector with scaled elements _CVector div(const Type & v) const { return (*this) / v; } //! \~english Transpose vector to 1xN matrix //! \~russian Транспонировать вектор в матрицу 1xN //! \returns 1xN matrix representation of this vector PIMathMatrixT<1, Size, Type> transposed() const { PIMathMatrixT<1, Size, Type> ret; PIMV_FOR ret[0][i] = c[i]; return ret; } //! \~english Get distance from this point to line defined by two points //! \~russian Получить расстояние от этой точки до линии, заданной двумя точками //! \param lp0 First point on the line //! \param lp1 Second point on the line //! \returns Distance from point to line, unavailable for complex types Type distToLine(const _CVector & lp0, const _CVector & lp1) { static_assert(std::is_arithmetic::value, "Unavailable for complex"); if (std::is_arithmetic::value) { _CVector a(lp0, lp1); Type tv = a.length(); assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP); _CVector b(lp0, *this); return piAbs(a[0] * b[1] - a[1] * b[0]) / tv; } } //! \~english Convert vector to another size and type //! \~russian Преобразовать вектор в другой размер и тип //! \tparam Size1 New vector size //! \tparam Type1 New element type //! \returns Vector with new size and type template /// vector {Size, Type} to vector {Size1, Type1} PIMathVectorT turnTo() const { PIMathVectorT tv; uint sz = piMin(Size, Size1); for (uint i = 0; i < sz; ++i) tv[i] = c[i]; return tv; } //! \~english Returns this vector with another element type //! \~russian Возвращает этот вектор с другим типом элементов //! \tparam T New element type //! \returns Vector with new element type template PIMathVectorT toType() const { PIMathVectorT ret; PIMV_FOR ret[i] = element(i); return ret; } //! \~english Returns the subvector with size SubSize. Elements are taken from coordinates "offset" //! \~russian Возвращает подвектор с размерами SubSize. Элементы берутся с координат "offset" //! \tparam SubSize Size of the subvector //! \param offset Starting coordinate (can be negative) //! \details Coordinates can be negative. The returned subvector can be of any size. If original elements are out of bounds, zeros will //! be used //! \~russian Координаты могут быть отрицательными. Возвращаемый подвектор может быть любого размера. Если исходные элементы выходят за //! границы исходного подвектора, то в подвекторе будут нули \returns Subvector of specified size //! \~english Returns the subvector with size SubSize. Elements are taken from coordinates "offset" //! \~russian Возвращает подвектор с размерами SubSize. Элементы берутся с координат "offset" //! \tparam SubSize Size of the subvector //! \param offset Starting coordinate (can be negative) //! \details Coordinates can be negative. The returned subvector can be of any size. If original elements are out of bounds, zeros will //! be used //! \~russian Координаты могут быть отрицательными. Возвращаемый подвектор может быть любого размера. Если исходные элементы выходят за //! границы исходного подвектора, то в подвекторе будут нули \returns Subvector of specified size template PIMathVectorT subvector(int offset = 0) const { PIMathVectorT 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 Set the subvector "v" at coordinates "index" //! \~russian Устанавливает подвектор "v" в координаты "index" //! \tparam SubSize Size of the subvector //! \param index Starting coordinate (can be negative) //! \param v The subvector to set //! \details Assigns values from vector "v" to the area of current vector bounded by "v"'s size and vector boundaries, based on the //! installation coordinates. Coordinates can be negative. Vector "v" can be of any size. Returns reference to this vector. //! \~russian Присваивает значения из вектора "v" в область текущего вектора, ограниченную размерами "v", самого вектор и границами, //! исходя из координат установки. Координаты могут быть отрицательными. Вектор "v" может быть любого размера. Возвращает ссылку на этот //! вектор. \returns Reference to this vector template PIMathVectorT & setSubvector(int index, const PIMathVectorT & 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 Static cross product of two vectors //! \~russian Статическое векторное произведение двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns Cross product vector static _CVector cross(const _CVector & v1, const _CVector & v2) { return v1.cross(v2); } //! \~english Static dot product of two vectors //! \~russian Статическое скалярное произведение двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns Dot product static Type dot(const _CVector & v1, const _CVector & v2) { return v1.dot(v2); } //! \~english Static element-wise multiplication of two vectors //! \~russian Статическое покомпонентное умножение двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns New vector with element-wise products static _CVector mul(const _CVector & v1, const _CVector & v2) { return v1.mul(v2); } //! \~english Static scalar multiplication (scalar * vector) //! \~russian Статическое скалярное умножение (скаляр * вектор) //! \param v1 Scalar //! \param v2 Vector //! \returns Scaled vector static _CVector mul(const Type & v1, const _CVector & v2) { return v2 * v1; } //! \~english Static scalar multiplication (vector * scalar) //! \~russian Статическое скалярное умножение (вектор * скаляр) //! \param v1 Vector //! \param v2 Scalar //! \returns Scaled vector static _CVector mul(const _CVector & v1, const Type & v2) { return v1 * v2; } //! \~english Static element-wise division of two vectors //! \~russian Статическое покомпонентное деление двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns New vector with element-wise quotients static _CVector div(const _CVector & v1, const _CVector & v2) { return v1.div(v2); } //! \~english Static scalar division (vector / scalar) //! \~russian Статическое скалярное деление (вектор / скаляр) //! \param v1 Vector //! \param v2 Scalar //! \returns Scaled vector static _CVector div(const _CVector & v1, const Type & v2) { return v1 / v2; } private: Type c[Size]; }; //! \~english Scalar multiplication (scalar * vector) //! \~russian Скалярное умножение (скаляр * вектор) //! \param x Scalar //! \param v Vector //! \returns Scaled vector template inline PIMathVectorT operator*(const Type & x, const PIMathVectorT & v) { return v * x; } //! \~english Output vector to PIP stream //! \~russian Вывести вектор в поток PIP //! \param s The PIP output stream //! \param v The vector to output //! \returns Reference to the stream template inline PICout operator<<(PICout s, const PIMathVectorT & v) { s.space(); s.saveAndSetControls(0); s << "Vector{"; PIMV_FOR { s << v[i]; if (i < Size - 1) s << ", "; } s << "}"; s.restoreControls(); return s; } //! \~english 2D integer vector //! \~russian 2D целочисленный вектор typedef PIMathVectorT<2u, int> PIMathVectorT2i; //! \~english 3D integer vector //! \~russian 3D целочисленный вектор typedef PIMathVectorT<3u, int> PIMathVectorT3i; //! \~english 4D integer vector //! \~russian 4D целочисленный вектор typedef PIMathVectorT<4u, int> PIMathVectorT4i; //! \~english 2D double vector //! \~russian 2D вектор с числами двойной точности typedef PIMathVectorT<2u, double> PIMathVectorT2d; //! \~english 3D double vector //! \~russian 3D вектор с числами двойной точности typedef PIMathVectorT<3u, double> PIMathVectorT3d; //! \~english 4D double vector //! \~russian 4D вектор с числами двойной точности typedef PIMathVectorT<4u, double> PIMathVectorT4d; #undef PIMV_FOR /// Vector #define PIMV_FOR for (uint i = 0; i < c.size(); ++i) //! \~english Template class for dynamic-size mathematical vector //! \~russian Шаблонный класс для математического вектора динамического размера //! \brief Dynamic-size mathematical vector with runtime size //! \~english Dynamic-size mathematical vector with runtime size //! \~russian Вектор математический динамического размера с размером во время выполнения //! \details 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 class PIP_EXPORT PIMathVector { typedef PIMathVector _CVector; template friend PIBinaryStream

& operator<<(PIBinaryStream

& s, const PIMathVector & v); template friend PIBinaryStream

& operator>>(PIBinaryStream

& s, PIMathVector & v); public: //! \~english Constructor with size and initial value //! \~russian Конструктор с размером и начальным значением //! \param size The initial size of the vector //! \param new_value The initial value for all elements PIMathVector(const uint size = 0, const Type & new_value = Type()) { c.resize(size, new_value); } //! \~english Constructor from PIVector //! \~russian Конструктор из PIVector //! \param val The PIVector to copy from PIMathVector(const PIVector & val) { c = val; } //! \~english Constructor from move PIVector //! \~russian Конструктор из move PIVector //! \param val The PIVector to move from PIMathVector(PIVector && val): c(std::move(val)) {} //! \~english Constructor from initializer list //! \~russian Конструктор из списка инициализации //! \param init_list The initializer list to copy from PIMathVector(std::initializer_list init_list) { c = PIVector(init_list); } //! \~english Constructor from fixed-size vector //! \~russian Конструктор из фиксированного вектора //! \param val The fixed-size vector to copy from template PIMathVector(const PIMathVectorT & val) { c.resize(Size); PIMV_FOR c[i] = val[i]; } //! \~english Create vector from two points (st -> fn) //! \~russian Создать вектор из двух точек (st -> fn) //! \param st The start point //! \param fn The finish point //! \returns Vector from st to 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 Create zero vector of specified size //! \~russian Создать нулевой вектор указанного размера //! \param size The size of the vector //! \returns Zero vector static PIMathVector zeros(const uint size) { return PIMathVector(size, Type()); } //! \~english Create vector with all elements set to 1 //! \~russian Создать вектор со всеми элементами, равными 1 //! \param size The size of the vector //! \returns Vector filled with ones static PIMathVector ones(const uint size) { return PIMathVector(size, Type(1)); } //! \~english Create vector with values in arithmetic progression //! \~russian Создать вектор со значениями в арифметической прогрессии //! \param start The start value //! \param stop The stop value (exclusive) //! \param step The step between values //! \returns Vector with arithmetic progression static PIMathVector arange(const Type start, const Type stop, const Type step = Type(1)) { PIVector v; for (Type i = start; i < stop; i += step) v << i; return PIMathVector(std::move(v)); } //! \~english Get vector size //! \~russian Получить размер вектора //! \returns The dynamic size of the vector uint size() const { return c.size(); } //! \~english Resize the vector //! \~russian Изменить размер вектора //! \param size The new size //! \param new_value The value for new elements //! \returns Reference to this vector _CVector & resize(uint size, const Type & new_value = Type()) { c.resize(size, new_value); return *this; } //! \~english Get resized copy of the vector //! \~russian Получить копию вектора с измененным размером //! \param size The new size //! \param new_value The value for new elements //! \returns New vector with new size _CVector resized(uint size, const Type & new_value = Type()) { _CVector tv = _CVector(*this); tv.resize(size, new_value); return tv; } //! \~english Fill vector with a single value //! \~russian Заполнить вектор одним значением //! \param v The value to fill //! \returns Reference to this vector _CVector & fill(const Type & v) { c.fill(v); return *this; } //! \~english Add value to all elements //! \~russian Прибавить значение ко всем элементам //! \param v The value to add //! \returns Reference to this vector _CVector & move(const Type & v) { PIMV_FOR c[i] += v; return *this; } //! \~english Add vector to this vector //! \~russian Прибавить вектор к этому вектору //! \param v The vector to add //! \returns Reference to this vector _CVector & move(const _CVector & v) { assert(c.size() == v.size()); PIMV_FOR c[i] += v[i]; return *this; } //! \~english Swap two elements //! \~russian Поменять два элемента местами //! \param f First element index //! \param s Second element index //! \returns Reference to this vector _CVector & swapElements(uint f, uint s) { piSwap(c[f], c[s]); return *this; } //! \~english Get squared length of vector //! \~russian Получить квадрат длины вектора //! \returns Sum of squares of all elements Type lengthSqr() const { Type tv(0); PIMV_FOR tv += c[i] * c[i]; return tv; } //! \~english Get length of vector //! \~russian Получить длину вектора //! \returns Square root of lengthSqr Type length() const { return std::sqrt(lengthSqr()); } //! \~english Get Manhattan length (sum of absolute values) //! \~russian Получить манхэттенскую длину (сумма абсолютных значений) //! \returns Sum of absolute values of all elements Type manhattanLength() const { Type tv(0); PIMV_FOR tv += piAbs(c[i]); return tv; } //! \~english Get cosine of angle between two vectors //! \~russian Получить косинус угла между двумя векторами //! \param v The other vector //! \returns cos(angle) 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 Get sine of angle between two vectors //! \~russian Получить синус угла между двумя векторами //! \param v The other vector //! \returns sin(angle) Type angleSin(const _CVector & v) const { assert(c.size() == v.size()); Type tv = angleCos(v); return std::sqrt(Type(1) - tv * tv); } //! \~english Get angle in radians between two vectors //! \~russian Получить угол в радианах между двумя векторами //! \param v The other vector //! \returns Angle in radians Type angleRad(const _CVector & v) const { return std::acos(angleCos(v)); } //! \~english Get angle in degrees between two vectors //! \~russian Получить угол в градусах между двумя векторами //! \param v The other vector //! \returns Angle in degrees Type angleDeg(const _CVector & v) const { return toDeg(angleRad(v)); } //! \~english Get projection of this vector onto another vector //! \~russian Получить проекцию этого вектора на другой вектор //! \param v The vector to project onto //! \returns Projection vector _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 Normalize vector in place //! \~russian Нормализовать вектор на месте //! \returns Reference to this vector _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 Get normalized copy of vector //! \~russian Получить нормализованную копию вектора //! \returns New normalized vector _CVector normalized() { _CVector tv(*this); tv.normalize(); return tv; } //! \~english Check if vector is null (all elements zero) //! \~russian Проверить, является ли вектор нулевым (все элементы нули) //! \returns true if vector is null bool isNull() const { PIMV_FOR if (c[i] != Type(0)) return false; return true; } //! \~english Check if vector is valid (non-empty) //! \~russian Проверить, валиден ли вектор (не пустой) //! \returns true if vector is valid bool isValid() const { return !c.isEmpty(); } //! \~english Check if vectors are orthogonal //! \~russian Проверить, перпендикулярны ли векторы //! \param v The other vector //! \returns true if vectors are orthogonal bool isOrtho(const _CVector & v) const { return dot(v) == Type(0); } //! \~english Get element at index (non-const) //! \~russian Получить элемент по индексу (non-const) //! \param index Element index //! \returns Reference to element Type & operator[](uint index) { return c[index]; } //! \~english Get element at index (const) //! \~russian Получить элемент по индексу (const) //! \param index Element index //! \returns Copy of element const Type & operator[](uint index) const { return c[index]; } //! \~english Get element at index (const version) //! \~russian Получить элемент по индексу (версия const) //! \param index Element index //! \returns Copy of element Type at(uint index) const { return c[index]; } //! \~english Assign value to all elements //! \~russian Присвоить значение всем элементам //! \param v The value to assign //! \returns Reference to this vector _CVector & operator=(const Type & v) { PIMV_FOR c[i] = v; return *this; } //! \~english Check equality with another vector //! \~russian Проверить равенство с другим вектором //! \param v The vector to compare with //! \returns true if all elements are equal bool operator==(const _CVector & v) const { return c == v.c; } //! \~english Check inequality with another vector //! \~russian Проверить неравенство с другим вектором //! \param v The vector to compare with //! \returns true if any element differs bool operator!=(const _CVector & v) const { return c != v.c; } //! \~english Add vector to this vector //! \~russian Прибавить вектор к этому вектору //! \param v The vector to add void operator+=(const _CVector & v) { assert(c.size() == v.size()); PIMV_FOR c[i] += v[i]; } //! \~english Subtract vector from this vector //! \~russian Вычесть вектор из этого вектора //! \param v The vector to subtract void operator-=(const _CVector & v) { assert(c.size() == v.size()); PIMV_FOR c[i] -= v[i]; } //! \~english Multiply all elements by scalar //! \~russian Умножить все элементы на скаляр //! \param v The scalar to multiply by void operator*=(const Type & v) { PIMV_FOR c[i] *= v; } //! \~english Divide all elements by scalar //! \~russian Разделить все элементы на скаляр //! \param v The scalar to divide by void operator/=(const Type & v) { assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP); PIMV_FOR c[i] /= v; } //! \~english Unary minus operator //! \~russian Унарный оператор минус //! \returns New vector with negated elements _CVector operator-() const { _CVector tv(c.size()); PIMV_FOR tv[i] = -c[i]; return tv; } //! \~english Add two vectors //! \~russian Сложить два вектора //! \param v The vector to add //! \returns New vector with sum of elements _CVector operator+(const _CVector & v) const { assert(c.size() == v.size()); _CVector tv(*this); PIMV_FOR tv[i] += v[i]; return tv; } //! \~english Subtract two vectors //! \~russian Вычесть два вектора //! \param v The vector to subtract //! \returns New vector with difference of elements _CVector operator-(const _CVector & v) const { assert(c.size() == v.size()); _CVector tv(*this); PIMV_FOR tv[i] -= v[i]; return tv; } //! \~english Multiply vector by scalar //! \~russian Умножить вектор на скаляр //! \param v The scalar to multiply by //! \returns New vector with scaled elements _CVector operator*(const Type & v) const { _CVector tv(*this); PIMV_FOR tv[i] *= v; return tv; } //! \~english Divide vector by scalar //! \~russian Разделить вектор на скаляр //! \param v The scalar to divide by //! \returns New vector with scaled elements _CVector operator/(const Type & v) const { assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP); _CVector tv(*this); PIMV_FOR tv[i] /= v; return tv; } //! \~english Compute cross product with another vector (3D only) //! \~russian Вычислить векторное произведение с другим вектором (только 3D) //! \param v The other vector //! \returns Cross product vector _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 Compute dot product with another vector //! \~russian Вычислить скалярное произведение с другим вектором //! \param v The other vector //! \returns Dot product (sum of element-wise products) Type dot(const _CVector & v) const { assert(c.size() == v.size()); Type tv(0); PIMV_FOR tv += c[i] * v[i]; return tv; } //! \~english Element-wise multiplication with another vector //! \~russian Покомпонентное умножение с другим вектором //! \param v The other vector //! \returns New vector with element-wise products _CVector mul(const _CVector & v) const { assert(c.size() == v.size()); _CVector tv(*this); PIMV_FOR tv[i] *= v[i]; return tv; } //! \~english Element-wise multiplication with scalar //! \~russian Покомпонентное умножение на скаляр //! \param v The scalar to multiply by //! \returns New vector with scaled elements _CVector mul(const Type & v) const { return (*this) * v; } //! \~english Element-wise division by another vector //! \~russian Покомпонентное деление на другой вектор //! \param v The vector to divide by //! \returns New vector with element-wise quotients _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 Element-wise division by scalar //! \~russian Покомпонентное деление на скаляр //! \param v The scalar to divide by //! \returns New vector with scaled elements _CVector div(const Type & v) const { return (*this) / v; } //! \~english Get distance from this point to line defined by two points //! \~russian Получить расстояние от этой точки до линии, заданной двумя точками //! \param lp0 First point on the line //! \param lp1 Second point on the line //! \returns Distance from point to line 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(a[0] * b[1] - a[1] * b[0]) / tv; } //! \~english Convert to PIVector //! \~russian Преобразовать в PIVector //! \returns PIVector with same elements PIVector toVector() const { return c; } //! \~english Apply function to each element (const) //! \~russian Применить функцию к каждому элементу (const) //! \param f The function to apply void forEach(std::function f) const { c.forEach(f); } //! \~english Apply function to each element //! \~russian Применить функцию к каждому элементу //! \param f The function to apply //! \returns Reference to this vector _CVector & forEach(std::function f) { c.forEach(f); return *this; } //! \~english Get pointer to underlying data //! \~russian Получить указатель на внутренние данные //! \returns Pointer to first element inline Type * data() { return c.data(); } //! \~english Get pointer to underlying data (const) //! \~russian Получить указатель на внутренние данные (const) //! \returns Pointer to first element inline const Type * data() const { return c.data(); } //! \~english Static cross product of two vectors //! \~russian Статическое векторное произведение двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns Cross product vector static _CVector cross(const _CVector & v1, const _CVector & v2) { return v1.cross(v2); } //! \~english Static dot product of two vectors //! \~russian Статическое скалярное произведение двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns Dot product static Type dot(const _CVector & v1, const _CVector & v2) { return v1.dot(v2); } //! \~english Static element-wise multiplication of two vectors //! \~russian Статическое покомпонентное умножение двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns New vector with element-wise products static _CVector mul(const _CVector & v1, const _CVector & v2) { return v1.mul(v2); } //! \~english Static scalar multiplication (scalar * vector) //! \~russian Статическое скалярное умножение (скаляр * вектор) //! \param v1 Scalar //! \param v2 Vector //! \returns Scaled vector static _CVector mul(const Type & v1, const _CVector & v2) { return v2 * v1; } //! \~english Static scalar multiplication (vector * scalar) //! \~russian Статическое скалярное умножение (вектор * скаляр) //! \param v1 Vector //! \param v2 Scalar //! \returns Scaled vector static _CVector mul(const _CVector & v1, const Type & v2) { return v1 * v2; } //! \~english Static element-wise division of two vectors //! \~russian Статическое покомпонентное деление двух векторов //! \param v1 First vector //! \param v2 Second vector //! \returns New vector with element-wise quotients static _CVector div(const _CVector & v1, const _CVector & v2) { return v1.div(v2); } //! \~english Static scalar division (vector / scalar) //! \~russian Статическое скалярное деление (вектор / скаляр) //! \param v1 Vector //! \param v2 Scalar //! \returns Scaled vector static _CVector div(const _CVector & v1, const Type & v2) { return v1 / v2; } private: PIVector c; }; template inline PIMathVector operator*(const Type & x, const PIMathVector & v) { return v * x; } #undef PIMV_FOR #ifdef PIP_STD_IOSTREAM //! \~english Output vector to stream //! \~russian Вывести вектор в поток //! \param s The output stream //! \param v The vector to output //! \returns Reference to the stream template inline std::ostream & operator<<(std::ostream & s, const PIMathVector & v) { s << "{"; for (uint i = 0; i < v.size(); ++i) { s << v[i]; if (i < v.size() - 1) s << ", "; } s << "}"; return s; } #endif //! \~english Output vector to PIP stream //! \~russian Вывести вектор в поток PIP //! \param s The PIP output stream //! \param v The vector to output //! \returns Reference to the stream template inline PICout operator<<(PICout s, const PIMathVector & 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 Serialize vector to binary stream //! \~russian Сериализовать вектор в бинарный поток //! \param s The binary stream //! \param v The vector to serialize //! \returns Reference to the stream template inline PIBinaryStream

& operator<<(PIBinaryStream

& s, const PIMathVector & v) { s << v.c; return s; } //! \~english Deserialize vector from binary stream //! \~russian Десериализовать вектор из бинарного потока //! \param s The binary stream //! \param v The vector to deserialize //! \returns Reference to the stream template inline PIBinaryStream

& operator>>(PIBinaryStream

& s, PIMathVector & v) { s >> v.c; return s; } //! \~english 32-bit integer dynamic vector //! \~russian Динамический вектор с 32-битными целыми числами typedef PIMathVector PIMathVectori; //! \~english Double precision dynamic vector //! \~russian Динамический вектор с числами двойной точности typedef PIMathVector PIMathVectord; #endif // PIMATHVECTOR_H