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);
}