1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
|
#pragma once
/* greebo: This file contains the templated class definition of the two-component vector
*
* BasicVector2: A vector with two components of type <Element>
*
* The BasicVector2 is equipped with the most important operators like *, *= and so on.
*
* Note: The most commonly used Vector2 is a BasicVector2<double>, this is also defined in this file
*
* Note: that the multiplication of a Vector2 with another one (Vector2*Vector2) does NOT
* result in an inner product but in a component-wise scaling. Use the .dot() method to
* execute an inner product of two vectors.
*/
#include "lrint.h"
#include <sstream>
#include <cmath>
#include <fmt/format.h>
template <typename Element>
class BasicVector2 {
// This is where the components of the vector are stored.
Element _v[2];
public:
// Public typedef to read the type of our elements
typedef Element ElementType;
// Constructor with no arguments
BasicVector2() {
_v[0] = 0;
_v[1] = 0;
}
// Templated copy constructor
template<typename OtherElement>
BasicVector2(const BasicVector2<OtherElement>& other) {
x() = static_cast<Element>(other.x());
y() = static_cast<Element>(other.y());
}
/** Construct a BasicVector2 with the 2 provided components.
*/
BasicVector2(const Element& x_, const Element& y_) {
_v[0] = x_;
_v[1] = y_;
}
/** Construct a BasicVector2 from a 2-element array. The array must be
* valid as no bounds checking is done.
*/
BasicVector2(const Element* array) {
for (int i = 0; i < 2; ++i)
_v[i] = array[i];
}
/** Construct a BasicVector2 by parsing the supplied string. The string
* must contain 2 numeric values separated by whitespace.
*
* @param str
* The string from which component values are extracted.
*/
BasicVector2(const std::string& str) {
// Initialise the vector with 0, in case the string parse fails
_v[0] = _v[1] = 0;
// Use a stringstream to parse the string
std::stringstream strm(str);
strm << std::skipws;
strm >> x();
strm >> y();
}
/** Construct a BasicVector2 out of 2 elements of type OtherType
*/
template <typename OtherType>
BasicVector2(OtherType x, OtherType y) {
_v[0] = static_cast<Element>(x);
_v[1] = static_cast<Element>(y);
}
// Return NON-CONSTANT references to the vector components
Element& x() {
return _v[0];
}
Element& y() {
return _v[1];
}
// Return CONSTANT references to the vector components
const Element& x() const {
return _v[0];
}
const Element& y() const {
return _v[1];
}
/**
* Operator cast to Element*. Also provides operator[] due to the inbuilt
* operation on a pointer type.
*/
operator Element* () {
return _v;
}
/**
* Operator cast to const Element*.
*/
operator const Element* () const {
return _v;
}
Element* data() {
return _v;
}
const Element* data() const {
return _v;
}
/** Compare this BasicVector2 against another for equality.
*/
bool operator== (const BasicVector2& other) const {
return (other.x() == x() && other.y() == y());
}
/** Compare this BasicVector2 against another for inequality.
*/
bool operator!= (const BasicVector2& other) const {
return !(*this == other);
}
/* Define the negation operator -
* All the vector's components are negated
*/
BasicVector2<Element> operator- () const {
return BasicVector2<Element>(
-_v[0],
-_v[1]
);
}
/* Define the addition operators + and += with any other BasicVector2 of type OtherElement
* The vectors are added to each other element-wise
*/
template<typename OtherElement>
BasicVector2<Element> operator+ (const BasicVector2<OtherElement>& other) const {
return BasicVector2<Element>(
_v[0] + static_cast<Element>(other.x()),
_v[1] + static_cast<Element>(other.y())
);
}
template<typename OtherElement>
BasicVector2<Element>& operator+= (const BasicVector2<OtherElement>& other) {
_v[0] += static_cast<Element>(other.x());
_v[1] += static_cast<Element>(other.y());
return *this;
}
/* Define the substraction operators - and -= with any other BasicVector2 of type OtherElement
* The vectors are substracted from each other element-wise
*/
template<typename OtherElement>
BasicVector2<Element> operator- (const BasicVector2<OtherElement>& other) const {
return BasicVector2<Element>(
_v[0] - static_cast<Element>(other.x()),
_v[1] - static_cast<Element>(other.y())
);
}
template<typename OtherElement>
BasicVector2<Element>& operator-= (const BasicVector2<OtherElement>& other) {
_v[0] -= static_cast<Element>(other.x());
_v[1] -= static_cast<Element>(other.y());
return *this;
}
/* Define the multiplication operators * and *= with another Vector2 of type OtherElement
*
* The vectors are multiplied element-wise
*
* greebo: This is mathematically kind of senseless, as this is a mixture of
* a dot product and scalar multiplication. It can be used to scale each
* vector component by a different factor, so maybe this comes in handy.
*/
template<typename OtherElement>
BasicVector2<Element> operator* (const BasicVector2<OtherElement>& other) const {
return BasicVector2<Element>(
_v[0] * static_cast<Element>(other.x()),
_v[1] * static_cast<Element>(other.y())
);
}
template<typename OtherElement>
BasicVector2<Element>& operator*= (const BasicVector2<OtherElement>& other) {
_v[0] *= static_cast<Element>(other.x());
_v[1] *= static_cast<Element>(other.y());
return *this;
}
/* Define the multiplications * and *= with a scalar
*/
template<typename OtherElement>
BasicVector2<Element> operator* (const OtherElement& other) const {
Element factor = static_cast<Element>(other);
return BasicVector2<Element>(
_v[0] * factor,
_v[1] * factor
);
}
template<typename OtherElement>
BasicVector2<Element>& operator*= (const OtherElement& other) {
Element factor = static_cast<Element>(other);
_v[0] *= factor;
_v[1] *= factor;
return *this;
}
/* Define the division operators / and /= with another Vector2 of type OtherElement
* The vectors are divided element-wise
*/
template<typename OtherElement>
BasicVector2<Element> operator/ (const BasicVector2<OtherElement>& other) const {
return BasicVector2<Element>(
_v[0] / static_cast<Element>(other.x()),
_v[1] / static_cast<Element>(other.y())
);
}
template<typename OtherElement>
BasicVector2<Element>& operator/= (const BasicVector2<OtherElement>& other) {
_v[0] /= static_cast<Element>(other.x());
_v[1] /= static_cast<Element>(other.y());
return *this;
}
/* Define the scalar divisions / and /=
*/
template<typename OtherElement>
BasicVector2<Element> operator/ (const OtherElement& other) const {
Element divisor = static_cast<Element>(other);
return BasicVector2<Element>(
_v[0] / divisor,
_v[1] / divisor
);
}
template<typename OtherElement>
BasicVector2<Element>& operator/= (const OtherElement& other) {
Element divisor = static_cast<Element>(other);
_v[0] /= divisor;
_v[1] /= divisor;
return *this;
}
/** Cast to std::string
*/
operator std::string() const
{
return fmt::format("{0:f} {1:f}", _v[0], _v[1]);
}
/** Return the length of this vector.
*
* @returns
* The Pythagorean length of this vector.
*/
double getLength() const {
double lenSquared = _v[0]*_v[0] +
_v[1]*_v[1];
return sqrt(lenSquared);
}
/** Return the squared length of this vector.
*/
double getLengthSquared() const {
double lenSquared = _v[0]*_v[0] +
_v[1]*_v[1];
return lenSquared;
}
/**
* \brief Normalise this vector in-place by scaling by the inverse of its
* size.
* \return The length of the vector before normalisation.
*/
double normalise()
{
auto length = getLength();
_v[0] /= length;
_v[1] /= length;
return length;
}
/// Return the result of normalising this vector
BasicVector2<Element> getNormalised() const
{
auto length = getLength();
return { _v[0] / length, _v[1] / length };
}
/* Scalar product this vector with another Vector2,
* returning the projection of <self> onto <other>
*
* @param other
* The Vector2 to dot-product with this Vector2.
*
* @returns
* The inner product (a scalar): a[0]*b[0] + a[1]*b[1]
*/
template<typename OtherT>
Element dot(const BasicVector2<OtherT>& other) const {
return Element(_v[0] * other.x() +
_v[1] * other.y());
}
/* Cross-product this vector with another Vector2, returning the scalar result
*
* @param other
* The Vector2 to cross-product with this Vector2.
*
* @returns
* The cross-product of the two vectors, a scalar: a[0]*b[1] - b[0]*a[1]
*/
template<typename OtherT>
Element crossProduct(const BasicVector2<OtherT>& other) const {
return Element(_v[0] * other.y() - _v[1] * other.x());
}
// Returns the mid-point of this vector and the other one
BasicVector2<Element> mid(const BasicVector2<Element>& other) const
{
return (*this + other) * 0.5f;
}
};
// ==========================================================================================
/// A 2-element vector stored in double-precision floating-point.
using Vector2 = BasicVector2<double>;
// A 2-element vector stored in single-precision floating point format
using Vector2f = BasicVector2<float>;
/// 2-element vector of signed integer
using Vector2i = BasicVector2<int>;
// Stream insertion operator for a BasicVector2
template<typename T>
std::ostream& operator<<(std::ostream& st, BasicVector2<T> vec) {
st << "<" << vec.x() << ", " << vec.y() << ">";
return st;
}
namespace math
{
template<typename T>
inline bool isNear(const BasicVector2<T>& v1, const BasicVector2<T>& v2, double epsilon)
{
BasicVector2<T> diff = v1 - v2;
return std::abs(diff.x()) < epsilon && std::abs(diff.y()) < epsilon;
}
}
|