blob: d878fd10b88352a39a57bd545848368e6e9e3354 [file] [log] [blame]
 // Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details. // All rights reserved. Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. part of vector_math_64; /// 2D column vector. class Vector2 implements Vector { final Float64List _v2storage; /// The components of the vector. @override Float64List get storage => _v2storage; /// Set the values of [result] to the minimum of [a] and [b] for each line. static void min(Vector2 a, Vector2 b, Vector2 result) { result ..x = math.min(a.x, b.x) ..y = math.min(a.y, b.y); } /// Set the values of [result] to the maximum of [a] and [b] for each line. static void max(Vector2 a, Vector2 b, Vector2 result) { result ..x = math.max(a.x, b.x) ..y = math.max(a.y, b.y); } /// Interpolate between [min] and [max] with the amount of [a] using a linear /// interpolation and store the values in [result]. static void mix(Vector2 min, Vector2 max, double a, Vector2 result) { result ..x = min.x + a * (max.x - min.x) ..y = min.y + a * (max.y - min.y); } /// Construct a new vector with the specified values. factory Vector2(double x, double y) => Vector2.zero()..setValues(x, y); /// Initialized with values from [array] starting at [offset]. factory Vector2.array(List array, [int offset = 0]) => Vector2.zero()..copyFromArray(array, offset); /// Zero vector. Vector2.zero() : _v2storage = Float64List(2); /// Splat [value] into all lanes of the vector. factory Vector2.all(double value) => Vector2.zero()..splat(value); /// Copy of [other]. factory Vector2.copy(Vector2 other) => Vector2.zero()..setFrom(other); /// Constructs Vector2 with a given [Float64List] as [storage]. Vector2.fromFloat64List(this._v2storage); /// Constructs Vector2 with a [storage] that views given [buffer] starting at /// [offset]. [offset] has to be multiple of [Float64List.bytesPerElement]. Vector2.fromBuffer(ByteBuffer buffer, int offset) : _v2storage = Float64List.view(buffer, offset, 2); /// Generate random vector in the range (0, 0) to (1, 1). You can /// optionally pass your own random number generator. factory Vector2.random([math.Random? rng]) { rng ??= math.Random(); return Vector2(rng.nextDouble(), rng.nextDouble()); } /// Set the values of the vector. void setValues(double x_, double y_) { _v2storage[0] = x_; _v2storage[1] = y_; } /// Zero the vector. void setZero() { _v2storage[0] = 0.0; _v2storage[1] = 0.0; } /// Set the values by copying them from [other]. void setFrom(Vector2 other) { final otherStorage = other._v2storage; _v2storage[1] = otherStorage[1]; _v2storage[0] = otherStorage[0]; } /// Splat [arg] into all lanes of the vector. void splat(double arg) { _v2storage[0] = arg; _v2storage[1] = arg; } /// Returns a printable string @override String toString() => '[\${_v2storage[0]},\${_v2storage[1]}]'; /// Check if two vectors are the same. @override bool operator ==(Object? other) => (other is Vector2) && (_v2storage[0] == other._v2storage[0]) && (_v2storage[1] == other._v2storage[1]); @override int get hashCode => Object.hashAll(_v2storage); /// Negate. Vector2 operator -() => clone()..negate(); /// Subtract two vectors. Vector2 operator -(Vector2 other) => clone()..sub(other); /// Add two vectors. Vector2 operator +(Vector2 other) => clone()..add(other); /// Scale. Vector2 operator /(double scale) => clone()..scale(1.0 / scale); /// Scale. Vector2 operator *(double scale) => clone()..scale(scale); /// Access the component of the vector at the index [i]. double operator [](int i) => _v2storage[i]; /// Set the component of the vector at the index [i]. void operator []=(int i, double v) { _v2storage[i] = v; } /// Set the length of the vector. A negative [value] will change the vectors /// orientation and a [value] of zero will set the vector to zero. set length(double value) { if (value == 0.0) { setZero(); } else { var l = length; if (l == 0.0) { return; } l = value / l; _v2storage[0] *= l; _v2storage[1] *= l; } } /// Length. double get length => math.sqrt(length2); /// Length squared. double get length2 { double sum; sum = _v2storage[0] * _v2storage[0]; sum += _v2storage[1] * _v2storage[1]; return sum; } /// Normalize this. double normalize() { final l = length; if (l == 0.0) { return 0.0; } final d = 1.0 / l; _v2storage[0] *= d; _v2storage[1] *= d; return l; } /// Normalize this. Returns length of vector before normalization. /// DEPRECATED: Use [normalize]. @Deprecated('Use normalize() insteaed.') double normalizeLength() => normalize(); /// Normalized copy of this. Vector2 normalized() => clone()..normalize(); /// Normalize vector into [out]. Vector2 normalizeInto(Vector2 out) { out ..setFrom(this) ..normalize(); return out; } /// Distance from this to [arg] double distanceTo(Vector2 arg) => math.sqrt(distanceToSquared(arg)); /// Squared distance from this to [arg] double distanceToSquared(Vector2 arg) { final dx = x - arg.x; final dy = y - arg.y; return dx * dx + dy * dy; } /// Returns the angle between this vector and [other] in radians. double angleTo(Vector2 other) { final otherStorage = other._v2storage; if (_v2storage[0] == otherStorage[0] && _v2storage[1] == otherStorage[1]) { return 0.0; } final d = dot(other) / (length * other.length); return math.acos(d.clamp(-1.0, 1.0)); } /// Returns the signed angle between this and [other] in radians. double angleToSigned(Vector2 other) { final otherStorage = other._v2storage; if (_v2storage[0] == otherStorage[0] && _v2storage[1] == otherStorage[1]) { return 0.0; } final s = cross(other); final c = dot(other); return math.atan2(s, c); } /// Inner product. double dot(Vector2 other) { final otherStorage = other._v2storage; double sum; sum = _v2storage[0] * otherStorage[0]; sum += _v2storage[1] * otherStorage[1]; return sum; } /// /// Transforms this into the product of this as a row vector, /// postmultiplied by matrix, [arg]. /// If [arg] is a rotation matrix, this is a computational shortcut for applying, /// the inverse of the transformation. /// void postmultiply(Matrix2 arg) { final argStorage = arg.storage; final v0 = _v2storage[0]; final v1 = _v2storage[1]; _v2storage[0] = v0 * argStorage[0] + v1 * argStorage[1]; _v2storage[1] = v0 * argStorage[2] + v1 * argStorage[3]; } /// Cross product. double cross(Vector2 other) { final otherStorage = other._v2storage; return _v2storage[0] * otherStorage[1] - _v2storage[1] * otherStorage[0]; } /// Rotate this by 90 degrees then scale it. Store result in [out]. Return [out]. Vector2 scaleOrthogonalInto(double scale, Vector2 out) { out.setValues(-scale * _v2storage[1], scale * _v2storage[0]); return out; } /// Reflect this. void reflect(Vector2 normal) { sub(normal.scaled(2.0 * normal.dot(this))); } /// Reflected copy of this. Vector2 reflected(Vector2 normal) => clone()..reflect(normal); /// Relative error between this and [correct] double relativeError(Vector2 correct) { final correct_norm = correct.length; final diff_norm = (this - correct).length; return diff_norm / correct_norm; } /// Absolute error between this and [correct] double absoluteError(Vector2 correct) => (this - correct).length; /// True if any component is infinite. bool get isInfinite { var is_infinite = false; is_infinite = is_infinite || _v2storage[0].isInfinite; is_infinite = is_infinite || _v2storage[1].isInfinite; return is_infinite; } /// True if any component is NaN. bool get isNaN { var is_nan = false; is_nan = is_nan || _v2storage[0].isNaN; is_nan = is_nan || _v2storage[1].isNaN; return is_nan; } /// Add [arg] to this. void add(Vector2 arg) { final argStorage = arg._v2storage; _v2storage[0] = _v2storage[0] + argStorage[0]; _v2storage[1] = _v2storage[1] + argStorage[1]; } /// Add [arg] scaled by [factor] to this. void addScaled(Vector2 arg, double factor) { final argStorage = arg._v2storage; _v2storage[0] = _v2storage[0] + argStorage[0] * factor; _v2storage[1] = _v2storage[1] + argStorage[1] * factor; } /// Subtract [arg] from this. void sub(Vector2 arg) { final argStorage = arg._v2storage; _v2storage[0] = _v2storage[0] - argStorage[0]; _v2storage[1] = _v2storage[1] - argStorage[1]; } /// Multiply entries in this with entries in [arg]. void multiply(Vector2 arg) { final argStorage = arg._v2storage; _v2storage[0] = _v2storage[0] * argStorage[0]; _v2storage[1] = _v2storage[1] * argStorage[1]; } /// Divide entries in this with entries in [arg]. void divide(Vector2 arg) { final argStorage = arg._v2storage; _v2storage[0] = _v2storage[0] / argStorage[0]; _v2storage[1] = _v2storage[1] / argStorage[1]; } /// Scale this by [arg]. void scale(double arg) { _v2storage[1] = _v2storage[1] * arg; _v2storage[0] = _v2storage[0] * arg; } /// Return a copy of this scaled by [arg]. Vector2 scaled(double arg) => clone()..scale(arg); /// Negate. void negate() { _v2storage[1] = -_v2storage[1]; _v2storage[0] = -_v2storage[0]; } /// Absolute value. void absolute() { _v2storage[1] = _v2storage[1].abs(); _v2storage[0] = _v2storage[0].abs(); } /// Clamp each entry n in this in the range [min[n]]-[max[n]]. void clamp(Vector2 min, Vector2 max) { final minStorage = min.storage; final maxStorage = max.storage; _v2storage[0] = _v2storage[0].clamp(minStorage[0], maxStorage[0]).toDouble(); _v2storage[1] = _v2storage[1].clamp(minStorage[1], maxStorage[1]).toDouble(); } /// Clamp entries this in the range [min]-[max]. void clampScalar(double min, double max) { _v2storage[0] = _v2storage[0].clamp(min, max).toDouble(); _v2storage[1] = _v2storage[1].clamp(min, max).toDouble(); } /// Floor entries in this. void floor() { _v2storage[0] = _v2storage[0].floorToDouble(); _v2storage[1] = _v2storage[1].floorToDouble(); } /// Ceil entries in this. void ceil() { _v2storage[0] = _v2storage[0].ceilToDouble(); _v2storage[1] = _v2storage[1].ceilToDouble(); } /// Round entries in this. void round() { _v2storage[0] = _v2storage[0].roundToDouble(); _v2storage[1] = _v2storage[1].roundToDouble(); } /// Round entries in this towards zero. void roundToZero() { _v2storage[0] = _v2storage[0] < 0.0 ? _v2storage[0].ceilToDouble() : _v2storage[0].floorToDouble(); _v2storage[1] = _v2storage[1] < 0.0 ? _v2storage[1].ceilToDouble() : _v2storage[1].floorToDouble(); } /// Clone of this. Vector2 clone() => Vector2.copy(this); /// Copy this into [arg]. Returns [arg]. Vector2 copyInto(Vector2 arg) { final argStorage = arg._v2storage; argStorage[1] = _v2storage[1]; argStorage[0] = _v2storage[0]; return arg; } /// Copies this into [array] starting at [offset]. void copyIntoArray(List array, [int offset = 0]) { array[offset + 1] = _v2storage[1]; array[offset + 0] = _v2storage[0]; } /// Copies elements from [array] into this starting at [offset]. void copyFromArray(List array, [int offset = 0]) { _v2storage[1] = array[offset + 1]; _v2storage[0] = array[offset + 0]; } set xy(Vector2 arg) { final argStorage = arg._v2storage; _v2storage[0] = argStorage[0]; _v2storage[1] = argStorage[1]; } set yx(Vector2 arg) { final argStorage = arg._v2storage; _v2storage[1] = argStorage[0]; _v2storage[0] = argStorage[1]; } set r(double arg) => x = arg; set g(double arg) => y = arg; set s(double arg) => x = arg; set t(double arg) => y = arg; set x(double arg) => _v2storage[0] = arg; set y(double arg) => _v2storage[1] = arg; set rg(Vector2 arg) => xy = arg; set gr(Vector2 arg) => yx = arg; set st(Vector2 arg) => xy = arg; set ts(Vector2 arg) => yx = arg; Vector2 get xx => Vector2(_v2storage[0], _v2storage[0]); Vector2 get xy => Vector2(_v2storage[0], _v2storage[1]); Vector2 get yx => Vector2(_v2storage[1], _v2storage[0]); Vector2 get yy => Vector2(_v2storage[1], _v2storage[1]); Vector3 get xxx => Vector3(_v2storage[0], _v2storage[0], _v2storage[0]); Vector3 get xxy => Vector3(_v2storage[0], _v2storage[0], _v2storage[1]); Vector3 get xyx => Vector3(_v2storage[0], _v2storage[1], _v2storage[0]); Vector3 get xyy => Vector3(_v2storage[0], _v2storage[1], _v2storage[1]); Vector3 get yxx => Vector3(_v2storage[1], _v2storage[0], _v2storage[0]); Vector3 get yxy => Vector3(_v2storage[1], _v2storage[0], _v2storage[1]); Vector3 get yyx => Vector3(_v2storage[1], _v2storage[1], _v2storage[0]); Vector3 get yyy => Vector3(_v2storage[1], _v2storage[1], _v2storage[1]); Vector4 get xxxx => Vector4(_v2storage[0], _v2storage[0], _v2storage[0], _v2storage[0]); Vector4 get xxxy => Vector4(_v2storage[0], _v2storage[0], _v2storage[0], _v2storage[1]); Vector4 get xxyx => Vector4(_v2storage[0], _v2storage[0], _v2storage[1], _v2storage[0]); Vector4 get xxyy => Vector4(_v2storage[0], _v2storage[0], _v2storage[1], _v2storage[1]); Vector4 get xyxx => Vector4(_v2storage[0], _v2storage[1], _v2storage[0], _v2storage[0]); Vector4 get xyxy => Vector4(_v2storage[0], _v2storage[1], _v2storage[0], _v2storage[1]); Vector4 get xyyx => Vector4(_v2storage[0], _v2storage[1], _v2storage[1], _v2storage[0]); Vector4 get xyyy => Vector4(_v2storage[0], _v2storage[1], _v2storage[1], _v2storage[1]); Vector4 get yxxx => Vector4(_v2storage[1], _v2storage[0], _v2storage[0], _v2storage[0]); Vector4 get yxxy => Vector4(_v2storage[1], _v2storage[0], _v2storage[0], _v2storage[1]); Vector4 get yxyx => Vector4(_v2storage[1], _v2storage[0], _v2storage[1], _v2storage[0]); Vector4 get yxyy => Vector4(_v2storage[1], _v2storage[0], _v2storage[1], _v2storage[1]); Vector4 get yyxx => Vector4(_v2storage[1], _v2storage[1], _v2storage[0], _v2storage[0]); Vector4 get yyxy => Vector4(_v2storage[1], _v2storage[1], _v2storage[0], _v2storage[1]); Vector4 get yyyx => Vector4(_v2storage[1], _v2storage[1], _v2storage[1], _v2storage[0]); Vector4 get yyyy => Vector4(_v2storage[1], _v2storage[1], _v2storage[1], _v2storage[1]); double get r => x; double get g => y; double get s => x; double get t => y; double get x => _v2storage[0]; double get y => _v2storage[1]; Vector2 get rr => xx; Vector2 get rg => xy; Vector2 get gr => yx; Vector2 get gg => yy; Vector3 get rrr => xxx; Vector3 get rrg => xxy; Vector3 get rgr => xyx; Vector3 get rgg => xyy; Vector3 get grr => yxx; Vector3 get grg => yxy; Vector3 get ggr => yyx; Vector3 get ggg => yyy; Vector4 get rrrr => xxxx; Vector4 get rrrg => xxxy; Vector4 get rrgr => xxyx; Vector4 get rrgg => xxyy; Vector4 get rgrr => xyxx; Vector4 get rgrg => xyxy; Vector4 get rggr => xyyx; Vector4 get rggg => xyyy; Vector4 get grrr => yxxx; Vector4 get grrg => yxxy; Vector4 get grgr => yxyx; Vector4 get grgg => yxyy; Vector4 get ggrr => yyxx; Vector4 get ggrg => yyxy; Vector4 get gggr => yyyx; Vector4 get gggg => yyyy; Vector2 get ss => xx; Vector2 get st => xy; Vector2 get ts => yx; Vector2 get tt => yy; Vector3 get sss => xxx; Vector3 get sst => xxy; Vector3 get sts => xyx; Vector3 get stt => xyy; Vector3 get tss => yxx; Vector3 get tst => yxy; Vector3 get tts => yyx; Vector3 get ttt => yyy; Vector4 get ssss => xxxx; Vector4 get ssst => xxxy; Vector4 get ssts => xxyx; Vector4 get sstt => xxyy; Vector4 get stss => xyxx; Vector4 get stst => xyxy; Vector4 get stts => xyyx; Vector4 get sttt => xyyy; Vector4 get tsss => yxxx; Vector4 get tsst => yxxy; Vector4 get tsts => yxyx; Vector4 get tstt => yxyy; Vector4 get ttss => yyxx; Vector4 get ttst => yyxy; Vector4 get ttts => yyyx; Vector4 get tttt => yyyy; }