#ifndef VECTOR_BASE_H #define VECTOR_BASE_H #include #include #include #include #define VECTOR_CHECK_INDEX(idx) \ do \ { \ unsigned int i((idx)); \ checkIndexInRange(i, __FUNCTION__); \ } \ while (0) \ template class VectorBase { public: VectorBase(); VectorBase(const T values[N]); VectorBase(const VectorBase& vector); ~VectorBase(); T getValue(const unsigned int index) const; void setValue(const unsigned int index, const T& value); unsigned int getDimensions() const; float getLengthSquared() const; float getLength() const; VectorBase normalize(); VectorBase normalized() const; template void assign(const VectorBase& other); template VectorBase& add(const VectorBase& other); template VectorBase& subtract(const VectorBase& other); template VectorBase& scalarMultiplication(const U& scalar); template T dotProduct(const VectorBase& other); // Checks whether all values are the same. template bool isEqual(const VectorBase& other) const; // Checks whether it really is the same object (at one and the same memory address). template bool isSame(const VectorBase& other) const; bool isSame(const VectorBase& other) const; T operator[](const unsigned int index); template VectorBase& operator=(const VectorBase& other); template VectorBase operator+(const VectorBase& other) const; template VectorBase operator-(const VectorBase& other) const; template VectorBase operator*(const U& scalar) const; /*template T operator*(const VectorBase& other) const;*/ template VectorBase operator/(const U& scalar) const; template VectorBase& operator+=(const VectorBase& other); template VectorBase& operator-=(const VectorBase& other); template VectorBase& operator*=(const U& scalar); template VectorBase& operator/=(const U& scalar); // Checks whether all values are the same. template bool operator==(const VectorBase& other) const; // Checks whether at least one value is different. template bool operator!=(const VectorBase& other) const; std::string toString() const; std::wstring toWString() const; protected: T m_values[N]; private: inline void checkIndexInRange(unsigned int index, const std::string& function) const { if (index >= N) { std::stringstream message; message << function << ": index " << index << " is out of range, maximum is " << N - 1; throw std::range_error(message.str()); } } inline void setValues(const T values[N]) { for (unsigned int i = 0; i < N; i++) { m_values[i] = values[i]; } } }; template VectorBase::VectorBase() {} template VectorBase::VectorBase(const T values[N]) { setValues(values); } template VectorBase::VectorBase(const VectorBase& vector) { setValues(vector.m_values); } template VectorBase::~VectorBase() { } template T VectorBase::getValue(const unsigned int index) const { VECTOR_CHECK_INDEX(index); return m_values[index]; } template void VectorBase::setValue(const unsigned int index, const T& value) { VECTOR_CHECK_INDEX(index); m_values[index] = value; } template unsigned int VectorBase::getDimensions() const { return N; } template float VectorBase::getLengthSquared() const { float result = 0.0f; for (unsigned int i = 0; i < N; i++) { result += float(m_values[i] * m_values[i]); } return result; } template float VectorBase::getLength() const { return std::sqrt(getLengthSquared()); } template VectorBase VectorBase::normalize() { float length = getLength(); if (length > 0.0f) { T tmpValues[N]; for (unsigned int i = 0; i < N; i++) { tmpValues[i] = m_values[i] / length; } // The values of *this won't be changed until all are in a valid state. setValues(tmpValues); } return *this; } template VectorBase VectorBase::normalized() const { float length = getLength(); T tmpValues[N]; if (length > 0.0f) { for (unsigned int i = 0; i < N; i++) { tmpValues[i] = m_values[i] / length; } } else { for (unsigned int i = 0; i < N; i++) { tmpValues[i] = 0; } } return VectorBase(tmpValues); } template template void VectorBase::assign(const VectorBase& other) { if (isSame(other)) { return; } if (isEqual(other)) { return; } T values[N]; for(unsigned int i = 0; i < N; i++) { values[i] = other.getValue(i); } setValues(values); } template template VectorBase& VectorBase::add(const VectorBase& other) { T tmpValues[N]; for (unsigned int i = 0; i < N; i++) { tmpValues[i] = m_values[i] + other.m_values[i]; } // The values of *this won't be changed until all are in a valid state. setValues(tmpValues); return *this; } template template VectorBase& VectorBase::subtract(const VectorBase& other) { T tmpValues[N]; for (unsigned int i = 0; i < N; i++) { tmpValues[i] = m_values[i] - other.m_values[i]; } // The values of *this won't be changed until all are in a valid state. setValues(tmpValues); return *this; } template template VectorBase& VectorBase::scalarMultiplication(const U& scalar) { T tmpValues[N]; for (unsigned int i = 0; i < N; i++) { tmpValues[i] = m_values[i] * scalar; } // The values of *this won't be changed until all are in a valid state. setValues(tmpValues); return *this; } template template T VectorBase::dotProduct(const VectorBase& other) { T result = 0.0f; for (unsigned int i = 0; i < N; i++) { result += (m_values[i] * other.m_values[i]); } return result; } template template bool VectorBase::isEqual(const VectorBase& other) const { for (unsigned int i = 0; i < N; i++) { if (m_values[i] != other.getValue(i)) { return false; } } return true; } template bool VectorBase::isSame(const VectorBase& other) const { return &other == this; } template template bool VectorBase::isSame(const VectorBase& other) const { return false; } template T VectorBase::operator[](const unsigned int index) { VECTOR_CHECK_INDEX(index); return m_values[index]; } template template VectorBase& VectorBase::operator=(const VectorBase& other) { assign(other); return *this; } template template VectorBase VectorBase::operator+(const VectorBase& other) const { VectorBase result(*this); return result.add(other); } template template VectorBase VectorBase::operator-(const VectorBase& other) const { VectorBase result(*this); return result.subtract(other); } template template VectorBase VectorBase::operator*(const U& scalar) const { VectorBase result(*this); return result.scalarMultiplication(scalar); } //template //template //T VectorBase::operator*(const VectorBase& other) const //{ // return dotProduct(other); //} template template VectorBase VectorBase::operator/(const U& scalar) const { VectorBase result(*this); return result.scalarMultiplication(1.0f / scalar); } template template VectorBase& VectorBase::operator+=(const VectorBase& other) { return add(other); } template template VectorBase& VectorBase::operator-=(const VectorBase& other) { return subtract(other); } template template VectorBase& VectorBase::operator*=(const U& scalar) { return scalarMultiplication(scalar); } template template VectorBase& VectorBase::operator/=(const U& scalar) { return scalarMultiplication(1.0f / scalar); } template template bool VectorBase::operator==(const VectorBase& other) const { return isEqual(other); } template template bool VectorBase::operator!=(const VectorBase& other) const { return !isEqual(other); } template std::string VectorBase::toString() const { std::stringstream result; result << "["; for (unsigned int i = 0; i < N - 1; i++) { result << m_values[i] << ", "; } result << m_values[N - 1] << "]"; return result.str(); } template std::wstring VectorBase::toWString() const { std::wstringstream result; result << L"["; for (unsigned int i = 0; i < N - 1; i++) { result << m_values[i] << L", "; } result << m_values[N - 1] << L"]"; return result.str(); } template std::ostream& operator<<(std::ostream& ostream, const VectorBase& vector) { ostream << vector.toString(); return ostream; } #endif // VECTOR_BASE_H