|
@@ -0,0 +1,289 @@
|
|
|
+/****************************************
|
|
|
+* Class: 2D vector class
|
|
|
+* Purpose: A single header file handling 2D vector computations.
|
|
|
+* Author: Zhao Liang
|
|
|
+* Last Updated: 2021/01/20
|
|
|
+*****************************************
|
|
|
+*
|
|
|
+* Note: Need to add error handling procedures in divisions.
|
|
|
+*
|
|
|
+*/
|
|
|
+
|
|
|
+#ifndef VEC2_H
|
|
|
+#define VEC2_H
|
|
|
+
|
|
|
+#pragma once
|
|
|
+
|
|
|
+#include <cmath>
|
|
|
+#include <iostream>
|
|
|
+
|
|
|
+namespace iv {
|
|
|
+namespace math {
|
|
|
+
|
|
|
+constexpr double _EPSILON = 1e-12;
|
|
|
+
|
|
|
+class Vec2
|
|
|
+{
|
|
|
+public:
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Constructors.
|
|
|
+ */
|
|
|
+
|
|
|
+ Vec2() : x_(0), y_(0) {}
|
|
|
+
|
|
|
+ explicit Vec2(double a) : x_(a), y_(a) {}
|
|
|
+
|
|
|
+ Vec2(double a, double b) : x_(a), y_(b) {}
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ // Compare to another vector
|
|
|
+ bool operator == (const Vec2 &v) const
|
|
|
+ {
|
|
|
+ return (std::abs(x_ - v.x()) < _EPSILON &&
|
|
|
+ std::abs(y_ - v.y()) < _EPSILON);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Return the unit vector Vec2(cos(angle), sin(angle)),
|
|
|
+ * The param 'angle' should be in radians.
|
|
|
+ */
|
|
|
+ static Vec2 unitVec2(const double angle)
|
|
|
+ {
|
|
|
+ return Vec2(cos(angle), sin(angle));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Access x and y components
|
|
|
+ */
|
|
|
+ double x() const { return x_; }
|
|
|
+ double y() const { return y_; }
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Set x and y components
|
|
|
+ */
|
|
|
+ void set_x(const double x) { x_ = x; }
|
|
|
+ void set_y(const double y) { y_ = y; }
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Operations with other scalars,
|
|
|
+ * vec2 is the left operand, scalar is the right operand.
|
|
|
+ */
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ // add a scalar
|
|
|
+ Vec2 operator + (double c) const { return Vec2(x() + c, y() + c); }
|
|
|
+ // subtract a scalar
|
|
|
+ Vec2 operator - (double c) const { return Vec2(x() - c, y() - c); }
|
|
|
+ // multiply a scalar
|
|
|
+ Vec2 operator * (double c) const { return Vec2(x() * c, y() * c); }
|
|
|
+ // divide by a scalar
|
|
|
+ Vec2 operator / (double c) const { return Vec2(x() / c, y() / c); }
|
|
|
+ // in-place add a scalar
|
|
|
+ Vec2 operator += (double c) { x_ += c; y_ += c; return (*this); }
|
|
|
+ // in-place subtract a scalar
|
|
|
+ Vec2 operator -= (double c) { x_ -= c; y_ -= c; return (*this); }
|
|
|
+ // in-place multiply a scalar
|
|
|
+ Vec2 operator *= (double c) { x_ *= c; y_ *= c; return (*this); }
|
|
|
+ // in-place divide by a scalar
|
|
|
+ Vec2 operator /= (double c) { x_ /= c; y_ /= c; return (*this); }
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Operations with other vec2
|
|
|
+ */
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ // add two vectors
|
|
|
+ Vec2 operator + (const Vec2 &v) const { return Vec2(x() + v.x(), y() + v.y()); }
|
|
|
+ // subtract another vector
|
|
|
+ Vec2 operator - (const Vec2 &v) const { return Vec2(x() - v.x(), y() - v.y()); }
|
|
|
+ // multiply two vectors as complex numbers
|
|
|
+ Vec2 operator * (const Vec2 &v) const
|
|
|
+ {
|
|
|
+ double x1 = x() * v.x() - y() * v.y();
|
|
|
+ double y1 = x() * v.y() + y() * v.x();
|
|
|
+ return Vec2(x1, y1);
|
|
|
+ }
|
|
|
+ // division as complex numbers
|
|
|
+ Vec2 operator / (const Vec2 &v) const
|
|
|
+ {
|
|
|
+ double snorm = v.squared_norm();
|
|
|
+ return Vec2(this->dot(v) / snorm, -this->cross(v) / snorm);
|
|
|
+ }
|
|
|
+ // in-place vector addition
|
|
|
+ Vec2 operator += (const Vec2 &v) { x_ += v.x(); y_ += v.y(); return (*this); }
|
|
|
+ // in-place vector subtraction
|
|
|
+ Vec2 operator -= (const Vec2 &v) { x_ -= v.x(); y_ -= v.y(); return (*this); }
|
|
|
+ // in-place vector multiplication as complex numbers
|
|
|
+ Vec2 operator *= (const Vec2 &v)
|
|
|
+ {
|
|
|
+ double x1 = x() * v.x() - y() * v.y();
|
|
|
+ double y1 = x() * v.y() + y() * v.x();
|
|
|
+ x_ = x1;
|
|
|
+ y_ = y1;
|
|
|
+ return (*this);
|
|
|
+ }
|
|
|
+ // in-place vector division as complex numbers
|
|
|
+ Vec2 operator /= (const Vec2 &v)
|
|
|
+ {
|
|
|
+ double snorm = v.squared_norm();
|
|
|
+ double x1 = this->dot(v) / snorm;
|
|
|
+ double y1 = -this->cross(v) / snorm;
|
|
|
+ x_ = x1;
|
|
|
+ y_ = y1;
|
|
|
+ return (*this);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Vector util functions
|
|
|
+ */
|
|
|
+
|
|
|
+ // ----------------------------------------
|
|
|
+
|
|
|
+ // Return squared norm
|
|
|
+ double squared_norm() const { return x() * x() + y() * y(); }
|
|
|
+
|
|
|
+ // Return the usual Euclidean norm
|
|
|
+ double norm() const { return sqrt(x() * x() + y() * y()); }
|
|
|
+
|
|
|
+ // Inner product of two vectors
|
|
|
+ double dot(const Vec2 &v) const { return x() * v.x() + y() * v.y(); }
|
|
|
+
|
|
|
+ // Angle with the positive x-axis in radians
|
|
|
+ double angle() const { return atan2(y(), x()); }
|
|
|
+
|
|
|
+ // Angle between two vectors
|
|
|
+ double angle(const Vec2 &v) const
|
|
|
+ {
|
|
|
+ return acos(this->dot(v) / (norm() * v.norm()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Distance between two vectors
|
|
|
+ double dist(const Vec2 &v) const { return (*this - v).norm(); }
|
|
|
+
|
|
|
+ // Squared distance between two vectors
|
|
|
+ double squared_dist(const Vec2 &v) const { return (*this - v).squared_norm(); }
|
|
|
+
|
|
|
+ // Cross product of two vectors
|
|
|
+ double cross(const Vec2 &v) const { return x() * v.y() - y() * v.x(); }
|
|
|
+
|
|
|
+ // Return a normalized version of this vector
|
|
|
+ Vec2 normalize() const
|
|
|
+ {
|
|
|
+ double s = norm();
|
|
|
+ return (*this) / s;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Translate a vector
|
|
|
+ Vec2 translate(double tx, double ty) const { return Vec2(x() + tx, y() + ty); }
|
|
|
+
|
|
|
+ // Rotate a vector by angle
|
|
|
+ Vec2 rotate(const double theta) const
|
|
|
+ {
|
|
|
+ double ct = cos(theta), st = sin(theta);
|
|
|
+ double x1 = x() * ct - y() * st;
|
|
|
+ double y1 = x() * ct + y() * st;
|
|
|
+ return Vec2(x1, y1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // return a perpendicular vector to this one
|
|
|
+ Vec2 perp() const { return Vec2(-y(), x()); }
|
|
|
+
|
|
|
+private:
|
|
|
+ double x_;
|
|
|
+ double y_;
|
|
|
+};
|
|
|
+
|
|
|
+// ----------------------------------------
|
|
|
+
|
|
|
+/*
|
|
|
+ * Vec2 operations as right operand
|
|
|
+*/
|
|
|
+
|
|
|
+// ----------------------------------------
|
|
|
+
|
|
|
+// print formatting
|
|
|
+std::ostream & operator << (std::ostream &out, const Vec2 &v)
|
|
|
+{
|
|
|
+ out << "Vec2(" << v.x() << ", " << v.y() << ")";
|
|
|
+ return out;
|
|
|
+}
|
|
|
+
|
|
|
+// add another scalar
|
|
|
+Vec2 operator + (double c, const Vec2 &v) { return Vec2(v.x() + c, v.y() + c); }
|
|
|
+// subtract another scalar
|
|
|
+Vec2 operator - (double c, const Vec2 &v) { return Vec2(c - v.x(), c - v.y()); }
|
|
|
+// multiply another scalar
|
|
|
+Vec2 operator * (double c, const Vec2 &v) { return Vec2(v.x() * c, v.y() * c); }
|
|
|
+// divide another scalar
|
|
|
+Vec2 operator / (double c, const Vec2 &v)
|
|
|
+{
|
|
|
+ double snorm = v.squared_norm();
|
|
|
+ return Vec2(v.x() * c / snorm, -v.y() * c / snorm);
|
|
|
+}
|
|
|
+
|
|
|
+// ----------------------------------------
|
|
|
+
|
|
|
+/*
|
|
|
+ * Vector util functions
|
|
|
+*/
|
|
|
+
|
|
|
+// ----------------------------------------
|
|
|
+
|
|
|
+// Inner product
|
|
|
+double vdot(const Vec2 &v1, const Vec2 &v2) { return v1.dot(v2); }
|
|
|
+
|
|
|
+// Cross
|
|
|
+double vcross(const Vec2 &v1, const Vec2 &v2) { return v1.cross(v2); }
|
|
|
+
|
|
|
+// Vector length
|
|
|
+double vlength(const Vec2 &v) { return v.norm(); }
|
|
|
+
|
|
|
+// Angle with positive x-axis
|
|
|
+double vangle(const Vec2 &v) { return v.angle(); }
|
|
|
+
|
|
|
+// Angle between two vectors
|
|
|
+double vangle(const Vec2 &v1, const Vec2 &v2) { return v1.angle(v2); }
|
|
|
+
|
|
|
+// distance between two vectors
|
|
|
+double vdist(const Vec2 &v1, const Vec2 &v2) { return v1.dist(v2); }
|
|
|
+
|
|
|
+// squared distance between two vectors
|
|
|
+double vsquared_dist(const Vec2 &v1, const Vec2 &v2) { return v1.squared_dist(v2); }
|
|
|
+
|
|
|
+// normalize a vector
|
|
|
+Vec2 vnormalize(const Vec2 &v) { return v.normalize(); }
|
|
|
+
|
|
|
+// return a perpendicular one
|
|
|
+Vec2 vperp(const Vec2 &v) { return v.perp(); }
|
|
|
+
|
|
|
+// rotate a vector
|
|
|
+Vec2 vrotate(const Vec2 &v, double theta) { return v.rotate(theta); }
|
|
|
+
|
|
|
+// return a unit vector of given direction
|
|
|
+Vec2 vdir(const double angle) { return Vec2::unitVec2(angle); }
|
|
|
+
|
|
|
+// return a linear combination of two vectors
|
|
|
+Vec2 vinterp(const Vec2 &v1, const Vec2 &v2, double t) { return v1 * (1 - t) + v2 * t; }
|
|
|
+
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+#endif // VEC2_H
|