Vector class
class Vector {
 static const num Epsilon = 0.0000001;
 static const num EpsilonSqr = Epsilon * Epsilon;
 final num _x;
 final num _y;
 Vector(num x, num y) : _x = x.toDouble(), _y = y.toDouble();
 Vector.zero() : _x = 0.0, _y = 0.0;
 Vector.polar(num len, num angle) : _x = (len * cos(angle)).toDouble(), _y = (len * sin(angle)).toDouble();
 Vector clone() => new Vector(_x, _y);
 num get x => _x;
 num get y => _y;
 String toString() => "Vector [x=${_x}, y=${_y}]";
 //-----------------------------------------------------------------------------------------------
 // Operators
 Vector operator +(Vector other) => new Vector(_x + other._x, _y + other._y);
 Vector operator -(Vector other) => new Vector(_x - other._x, _y - other._y);
 Vector operator *(Vector other) => new Vector(_x * other._x, _y * other._y);
 Vector operator /(Vector other) => new Vector(_x / other._x, _y / other._y);
 Vector operator -() => new Vector(-_x, -_y);
 bool operator ==(Vector other) => _x == other._x && _y == other._y;
 // ToDo: https://dartbug.com/11617
 int get hashCode => _x.hashCode + _y.hashCode * 7;
 bool equalsXY(num x, num y) => _x == x && _y == y;
 //-----------------------------------------------------------------------------------------------
 // Queries
 bool get isNormalized => ((_x * _x + _y * _y) - 1).abs() < EpsilonSqr;
 bool get isZero => (_x == 0 && _y == 0);
 bool get isValid => (_x.isNaN || _y.isNaN || _x.isInfinite || _y.isInfinite) == false;
 bool isNear(Vector other) => distanceSqr(other) < EpsilonSqr;
 bool isNearXY(num x, num y) => distanceXYSqr(x, y) < EpsilonSqr;
 bool isWithin(Vector other, num epsilon) => distanceSqr(other) < epsilon * epsilon;
 bool isWithinXY(num x, num y, num epsilon) => distanceXYSqr(x, y) < epsilon * epsilon;
 num get degrees => atan2(_y, _x) * 180 / PI;
 num get rads => atan2(_y, _x);
 //-----------------------------------------------------------------------------------------------
 // Scale
 Vector scale(num scale) {
   return new Vector(_x * scale, _y * scale);
 }
 Vector scaleLength(num value) {
   var scale = value / length;
   return new Vector(_x * scale, _y * scale);
 }
 Vector normalize() {
   num nf = 1 / length;
   return new Vector(_x * nf, _y * nf);
 }
 //-----------------------------------------------------------------------------------------------
 // Distance
 num get length => sqrt(_x * _x + _y * _y);
 num get lengthSqr => _x * _x + _y * _y;
 num distance(Vector vec) {
   num xd = _x - vec._x;
   num yd = _y - vec._y;
   return sqrt(xd * xd + yd * yd);
 }
 num distanceXY(num x, num y) {
   num xd = _x - x;
   num yd = _y - y;
   return sqrt(xd * xd + yd * yd);
 }
 num distanceSqr(Vector vec) {
   num xd = _x - vec._x;
   num yd = _y - vec._y;
   return xd * xd + yd * yd;
 }
 num distanceXYSqr(num x, num y) {
   num xd = _x - x;
   num yd = _y - y;
   return xd * xd + yd * yd;
 }
 //-----------------------------------------------------------------------------------------------
 // Dot product
 num dot(Vector vec) => _x * vec._x + _y * vec._y;
 num dotXY(num x, num y) => _x * x + _y * y;
 //-----------------------------------------------------------------------------------------------
 // Cross determinant
 num crossDet(Vector vec) => _x * vec._y - _y * vec._x;
 num crossDetXY(num x, num y) => _x * y - _y * x;
 //-----------------------------------------------------------------------------------------------
 // Rotate
 Vector rotate(num rads) {
   num s = sin(rads);
   num c = cos(rads);
   return new Vector(_x * c - _y * s, _x * s + _y * c);
 }
 Vector normalRight() {
   return new Vector(-_y, _x);
 }
 Vector normalLeft() {
   return new Vector(_y, -_x);
 }
 Vector negate() {
   return new Vector(-_x, -_y);
 }
 //-----------------------------------------------------------------------------------------------
 // Spinor rotation
 Vector rotateSpinor(Vector vec) {
   return new Vector(_x * vec._x - _y * vec._y, _x * vec._y + _y * vec._x);
 }
 Vector spinorBetween(Vector vec) {
   num d = this.lengthSqr;
   num r = (vec._x * _x + vec._y * _y) / d;
   num i = (vec._y * _x - vec._x * _y) / d;
   return new Vector(r, i);
 }
 //-----------------------------------------------------------------------------------------------
 // Lerp / slerp
 Vector lerp(Vector to, num t) {
   return new Vector(_x + t * (to._x - _x), _y + t * (to._y - _y));
 }
 Vector slerp(Vector vec, num t) {
   num cosTheta = this.dot(vec);
   num theta = acos(cosTheta);
   num sinTheta = sin(theta);
   if (sinTheta <= Epsilon)
     return vec.clone();
   num w1 = sin((1 - t) * theta) / sinTheta;
   num w2 = sin(t * theta) / sinTheta;
   return this.scale(w1) + vec.scale(w2);
 }
 //-----------------------------------------------------------------------------------------------
 // Reflect
 Vector reflect(Vector normal) {
   num d = 2 * (_x * normal._x + _y * normal._y);
   return new Vector(_x - d * normal._x, _y - d * normal._y);
 }
}
Static Properties
Constructors
new Vector.polar(num len, num angle) #
Vector.polar(num len, num angle) : _x = (len * cos(angle)).toDouble(), _y = (len * sin(angle)).toDouble();
new Vector.zero() #
Vector.zero() : _x = 0.0, _y = 0.0;
Properties
final int hashCode #
Get a hash code for this object.
All objects have hash codes. Hash codes are guaranteed to be the
same for objects that are equal when compared using the equality
operator ==. Other than that there are no guarantees about
the hash codes. They will not be consistent between runs and
there are no distribution guarantees.
If a subclass overrides hashCode it should override the equality operator as well to maintain consistency.
int get hashCode => _x.hashCode + _y.hashCode * 7;
Operators
Vector operator +(Vector other) #
Vector operator +(Vector other) => new Vector(_x + other._x, _y + other._y);
Vector operator -(Vector other) #
Vector operator -(Vector other) => new Vector(_x - other._x, _y - other._y);
Vector operator *(Vector other) #
Vector operator *(Vector other) => new Vector(_x * other._x, _y * other._y);
Vector operator /(Vector other) #
Vector operator /(Vector other) => new Vector(_x / other._x, _y / other._y);
bool operator ==(Vector other) #
The equality operator.
The default behavior for all Objects is to return true if and
only if this and 
other are the same object.
Override this method to specify a different equality relation on a class. The overriding method must still be an equivalence relation. That is, it must be:
- 
Total: It must return a boolean for all arguments. It should never throw or return null.
- 
Reflexive: For all objects o,o == omust be true.
- 
Symmetric: For all objects o1ando2,o1 == o2ando2 == o1must either both be true, or both be false.
- 
Transitive: For all objects o1,o2, ando3, ifo1 == o2ando2 == o3are true, theno1 == o3must be true.
The method should also be consistent over time, so equality of two objects should not change over time, or at least only change if one of the objects was modified.
If a subclass overrides the equality operator it should override the hashCode method as well to maintain consistency.
bool operator ==(Vector other) => _x == other._x && _y == other._y;
Methods
num distance(Vector vec) #
num distance(Vector vec) {
 num xd = _x - vec._x;
 num yd = _y - vec._y;
 return sqrt(xd * xd + yd * yd);
}
num distanceSqr(Vector vec) #
num distanceSqr(Vector vec) {
 num xd = _x - vec._x;
 num yd = _y - vec._y;
 return xd * xd + yd * yd;
}
num distanceXY(num x, num y) #
num distanceXY(num x, num y) {
 num xd = _x - x;
 num yd = _y - y;
 return sqrt(xd * xd + yd * yd);
}
num distanceXYSqr(num x, num y) #
num distanceXYSqr(num x, num y) {
 num xd = _x - x;
 num yd = _y - y;
 return xd * xd + yd * yd;
}
bool isWithin(Vector other, num epsilon) #
bool isWithin(Vector other, num epsilon) => distanceSqr(other) < epsilon * epsilon;
bool isWithinXY(num x, num y, num epsilon) #
bool isWithinXY(num x, num y, num epsilon) => distanceXYSqr(x, y) < epsilon * epsilon;
Vector lerp(Vector to, num t) #
Vector lerp(Vector to, num t) {
 return new Vector(_x + t * (to._x - _x), _y + t * (to._y - _y));
}
Vector normalize() #
Vector normalize() {
 num nf = 1 / length;
 return new Vector(_x * nf, _y * nf);
}
Vector reflect(Vector normal) #
Vector reflect(Vector normal) {
 num d = 2 * (_x * normal._x + _y * normal._y);
 return new Vector(_x - d * normal._x, _y - d * normal._y);
}
Vector rotate(num rads) #
Vector rotate(num rads) {
 num s = sin(rads);
 num c = cos(rads);
 return new Vector(_x * c - _y * s, _x * s + _y * c);
}
Vector rotateSpinor(Vector vec) #
Vector rotateSpinor(Vector vec) {
 return new Vector(_x * vec._x - _y * vec._y, _x * vec._y + _y * vec._x);
}
Vector scaleLength(num value) #
Vector scaleLength(num value) {
 var scale = value / length;
 return new Vector(_x * scale, _y * scale);
}
Vector slerp(Vector vec, num t) #
Vector slerp(Vector vec, num t) {
 num cosTheta = this.dot(vec);
 num theta = acos(cosTheta);
 num sinTheta = sin(theta);
 if (sinTheta <= Epsilon)
   return vec.clone();
 num w1 = sin((1 - t) * theta) / sinTheta;
 num w2 = sin(t * theta) / sinTheta;
 return this.scale(w1) + vec.scale(w2);
}