// 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.dart';

/// 3D column vector.
class Vector3 implements Vector {
  final Float64List _v3storage;

  /// The components of the vector.
  @override
  Float64List get storage => _v3storage;

  /// Set the values of [result] to the minimum of [a] and [b] for each line.
  static void min(Vector3 a, Vector3 b, Vector3 result) {
    result
      ..x = math.min(a.x, b.x)
      ..y = math.min(a.y, b.y)
      ..z = math.min(a.z, b.z);
  }

  /// Set the values of [result] to the maximum of [a] and [b] for each line.
  static void max(Vector3 a, Vector3 b, Vector3 result) {
    result
      ..x = math.max(a.x, b.x)
      ..y = math.max(a.y, b.y)
      ..z = math.max(a.z, b.z);
  }

  /// Interpolate between [min] and [max] with the amount of [a] using a linear
  /// interpolation and store the values in [result].
  static void mix(Vector3 min, Vector3 max, double a, Vector3 result) {
    result
      ..x = min.x + a * (max.x - min.x)
      ..y = min.y + a * (max.y - min.y)
      ..z = min.z + a * (max.z - min.z);
  }

  /// Construct a new vector with the specified values.
  factory Vector3(double x, double y, double z) =>
      Vector3.zero()..setValues(x, y, z);

  /// Initialized with values from [array] starting at [offset].
  factory Vector3.array(List<double> array, [int offset = 0]) =>
      Vector3.zero()..copyFromArray(array, offset);

  /// Zero vector.
  Vector3.zero() : _v3storage = Float64List(3);

  /// Splat [value] into all lanes of the vector.
  factory Vector3.all(double value) => Vector3.zero()..splat(value);

  /// Copy of [other].
  factory Vector3.copy(Vector3 other) => Vector3.zero()..setFrom(other);

  /// Constructs Vector3 with given Float64List as [storage].
  Vector3.fromFloat64List(this._v3storage);

  /// Constructs Vector3 with a [storage] that views given [buffer] starting at
  /// [offset]. [offset] has to be multiple of [Float64List.bytesPerElement].
  Vector3.fromBuffer(ByteBuffer buffer, int offset)
      : _v3storage = Float64List.view(buffer, offset, 3);

  /// Generate random vector in the range (0, 0, 0) to (1, 1, 1). You can
  /// optionally pass your own random number generator.
  factory Vector3.random([math.Random? rng]) {
    rng ??= math.Random();
    return Vector3(rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
  }

  /// Set the values of the vector.
  void setValues(double x, double y, double z) {
    _v3storage[2] = z;
    _v3storage[1] = y;
    _v3storage[0] = x;
  }

  /// Zero vector.
  void setZero() {
    _v3storage[2] = 0.0;
    _v3storage[1] = 0.0;
    _v3storage[0] = 0.0;
  }

  /// Set the values by copying them from [other].
  void setFrom(Vector3 other) {
    final otherStorage = other._v3storage;
    _v3storage[2] = otherStorage[2];
    _v3storage[1] = otherStorage[1];
    _v3storage[0] = otherStorage[0];
  }

  /// Splat [arg] into all lanes of the vector.
  void splat(double arg) {
    _v3storage[2] = arg;
    _v3storage[1] = arg;
    _v3storage[0] = arg;
  }

  /// Returns a printable string
  @override
  String toString() => '[${storage[0]},${storage[1]},${storage[2]}]';

  /// Check if two vectors are the same.
  @override
  bool operator ==(Object other) =>
      (other is Vector3) &&
      (_v3storage[2] == other._v3storage[2]) &&
      (_v3storage[1] == other._v3storage[1]) &&
      (_v3storage[0] == other._v3storage[0]);

  @override
  int get hashCode => Object.hashAll(_v3storage);

  /// Negate
  Vector3 operator -() => clone()..negate();

  /// Subtract two vectors.
  Vector3 operator -(Vector3 other) => clone()..sub(other);

  /// Add two vectors.
  Vector3 operator +(Vector3 other) => clone()..add(other);

  /// Scale.
  Vector3 operator /(double scale) => scaled(1.0 / scale);

  /// Scale by [scale].
  Vector3 operator *(double scale) => scaled(scale);

  /// Access the component of the vector at the index [i].
  double operator [](int i) => _v3storage[i];

  /// Set the component of the vector at the index [i].
  void operator []=(int i, double v) {
    _v3storage[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;
      _v3storage[0] *= l;
      _v3storage[1] *= l;
      _v3storage[2] *= l;
    }
  }

  /// The length of the vector.
  double get length => math.sqrt(length2);

  /// The squared length of the vector.
  double get length2 {
    double sum;
    sum = _v3storage[2] * _v3storage[2];
    sum += _v3storage[1] * _v3storage[1];
    sum += _v3storage[0] * _v3storage[0];
    return sum;
  }

  /// Normalizes this.
  double normalize() {
    final l = length;
    if (l == 0.0) {
      return 0.0;
    }
    final d = 1.0 / l;
    _v3storage[2] *= d;
    _v3storage[1] *= d;
    _v3storage[0] *= d;
    return l;
  }

  /// Normalize this. Returns length of vector before normalization.
  @Deprecated('Use normalize() instead.')
  double normalizeLength() => normalize();

  /// Normalizes copy of this.
  Vector3 normalized() => Vector3.copy(this)..normalize();

  /// Normalize vector into [out].
  Vector3 normalizeInto(Vector3 out) {
    out
      ..setFrom(this)
      ..normalize();
    return out;
  }

  /// Distance from this to [arg]
  double distanceTo(Vector3 arg) => math.sqrt(distanceToSquared(arg));

  /// Squared distance from this to [arg]
  double distanceToSquared(Vector3 arg) {
    final argStorage = arg._v3storage;
    final dz = _v3storage[2] - argStorage[2];
    final dy = _v3storage[1] - argStorage[1];
    final dx = _v3storage[0] - argStorage[0];

    return dx * dx + dy * dy + dz * dz;
  }

  /// Returns the angle between this vector and [other] in radians.
  double angleTo(Vector3 other) {
    final otherStorage = other._v3storage;
    if (_v3storage[2] == otherStorage[2] &&
        _v3storage[1] == otherStorage[1] &&
        _v3storage[0] == otherStorage[0]) {
      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] around [normal]
  /// in radians.
  double angleToSigned(Vector3 other, Vector3 normal) {
    final angle = angleTo(other);
    final c = cross(other);
    final d = c.dot(normal);

    return d < 0.0 ? -angle : angle;
  }

  /// Inner product.
  double dot(Vector3 other) {
    final otherStorage = other._v3storage;
    return _v3storage[2] * otherStorage[2] +
        _v3storage[1] * otherStorage[1] +
        _v3storage[0] * otherStorage[0];
  }

  /// 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(Matrix3 arg) {
    final argStorage = arg._m3storage;
    final v2 = _v3storage[2];
    final v1 = _v3storage[1];
    final v0 = _v3storage[0];

    _v3storage[2] =
        v0 * argStorage[6] + v1 * argStorage[7] + v2 * argStorage[8];
    _v3storage[1] =
        v0 * argStorage[3] + v1 * argStorage[4] + v2 * argStorage[5];
    _v3storage[0] =
        v0 * argStorage[0] + v1 * argStorage[1] + v2 * argStorage[2];
  }

  /// Cross product.
  Vector3 cross(Vector3 other) {
    final z = _v3storage[2];
    final y = _v3storage[1];
    final x = _v3storage[0];
    final otherStorage = other._v3storage;
    final oz = otherStorage[2];
    final oy = otherStorage[1];
    final ox = otherStorage[0];
    return Vector3(y * oz - z * oy, z * ox - x * oz, x * oy - y * ox);
  }

  /// Cross product. Stores result in [out].
  Vector3 crossInto(Vector3 other, Vector3 out) {
    final z = _v3storage[2];
    final y = _v3storage[1];
    final x = _v3storage[0];
    final otherStorage = other._v3storage;
    final oz = otherStorage[2];
    final oy = otherStorage[1];
    final ox = otherStorage[0];
    final outStorage = out._v3storage;
    outStorage[2] = x * oy - y * ox;
    outStorage[1] = z * ox - x * oz;
    outStorage[0] = y * oz - z * oy;
    return out;
  }

  /// Reflect this.
  void reflect(Vector3 normal) {
    final dotProduct = 2.0 * normal.dot(this);
    _v3storage[2] -= normal._v3storage[2] * dotProduct;
    _v3storage[1] -= normal._v3storage[1] * dotProduct;
    _v3storage[0] -= normal._v3storage[0] * dotProduct;
  }

  /// Reflected copy of this.
  Vector3 reflected(Vector3 normal) => clone()..reflect(normal);

  /// Projects this using the projection matrix [arg]
  void applyProjection(Matrix4 arg) {
    final argStorage = arg._m4storage;
    final z = _v3storage[2];
    final y = _v3storage[1];
    final x = _v3storage[0];
    final d = 1.0 /
        (argStorage[15] +
            argStorage[11] * z +
            argStorage[7] * y +
            argStorage[3] * x);
    _v3storage[0] = (argStorage[12] +
            argStorage[8] * z +
            argStorage[4] * y +
            argStorage[0] * x) *
        d;
    _v3storage[1] = (argStorage[13] +
            argStorage[9] * z +
            argStorage[5] * y +
            argStorage[1] * x) *
        d;
    _v3storage[2] = (argStorage[14] +
            argStorage[10] * z +
            argStorage[6] * y +
            argStorage[2] * x) *
        d;
  }

  /// Applies a rotation specified by [axis] and [angle].
  void applyAxisAngle(Vector3 axis, double angle) {
    applyQuaternion(Quaternion.axisAngle(axis, angle));
  }

  /// Applies a quaternion transform.
  void applyQuaternion(Quaternion arg) {
    final argStorage = arg._qStorage;
    final v2 = _v3storage[2];
    final v1 = _v3storage[1];
    final v0 = _v3storage[0];
    final qw = argStorage[3];
    final qz = argStorage[2];
    final qy = argStorage[1];
    final qx = argStorage[0];
    final ix = qw * v0 + qy * v2 - qz * v1;
    final iy = qw * v1 + qz * v0 - qx * v2;
    final iz = qw * v2 + qx * v1 - qy * v0;
    final iw = -qx * v0 - qy * v1 - qz * v2;
    _v3storage[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
    _v3storage[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
    _v3storage[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  }

  /// Multiplies this by [arg].
  void applyMatrix3(Matrix3 arg) {
    final argStorage = arg._m3storage;
    final v2 = _v3storage[2];
    final v1 = _v3storage[1];
    final v0 = _v3storage[0];
    _v3storage[2] =
        argStorage[2] * v0 + argStorage[5] * v1 + argStorage[8] * v2;
    _v3storage[1] =
        argStorage[1] * v0 + argStorage[4] * v1 + argStorage[7] * v2;
    _v3storage[0] =
        argStorage[0] * v0 + argStorage[3] * v1 + argStorage[6] * v2;
  }

  /// Multiplies this by a 4x3 subset of [arg]. Expects [arg] to be an affine
  /// transformation matrix.
  void applyMatrix4(Matrix4 arg) {
    final argStorage = arg._m4storage;
    final v2 = _v3storage[2];
    final v1 = _v3storage[1];
    final v0 = _v3storage[0];
    _v3storage[2] = argStorage[2] * v0 +
        argStorage[6] * v1 +
        argStorage[10] * v2 +
        argStorage[14];
    _v3storage[1] = argStorage[1] * v0 +
        argStorage[5] * v1 +
        argStorage[9] * v2 +
        argStorage[13];
    _v3storage[0] = argStorage[0] * v0 +
        argStorage[4] * v1 +
        argStorage[8] * v2 +
        argStorage[12];
  }

  /// Relative error between this and [correct]
  double relativeError(Vector3 correct) =>
      absoluteError(correct) / correct.length;

  /// Absolute error between this and [correct]
  double absoluteError(Vector3 correct) {
    final zDiff = _v3storage[2] - correct._v3storage[2];
    final yDiff = _v3storage[1] - correct._v3storage[1];
    final xDiff = _v3storage[0] - correct._v3storage[0];
    return math.sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff);
  }

  /// True if any component is infinite.
  bool get isInfinite =>
      _v3storage[2].isInfinite ||
      _v3storage[1].isInfinite ||
      _v3storage[0].isInfinite;

  /// True if any component is NaN.
  bool get isNaN =>
      _v3storage[2].isNaN || _v3storage[1].isNaN || _v3storage[0].isNaN;

  /// Add [arg] to this.
  void add(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] += argStorage[2];
    _v3storage[1] += argStorage[1];
    _v3storage[0] += argStorage[0];
  }

  /// Add [arg] scaled by [factor] to this.
  void addScaled(Vector3 arg, double factor) {
    final argStorage = arg._v3storage;
    _v3storage[2] += argStorage[2] * factor;
    _v3storage[1] += argStorage[1] * factor;
    _v3storage[0] += argStorage[0] * factor;
  }

  /// Subtract [arg] from this.
  void sub(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] -= argStorage[2];
    _v3storage[1] -= argStorage[1];
    _v3storage[0] -= argStorage[0];
  }

  /// Multiply entries in this with entries in [arg].
  void multiply(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] *= argStorage[2];
    _v3storage[1] *= argStorage[1];
    _v3storage[0] *= argStorage[0];
  }

  /// Divide entries in this with entries in [arg].
  void divide(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] /= argStorage[2];
    _v3storage[1] /= argStorage[1];
    _v3storage[0] /= argStorage[0];
  }

  /// Scale this.
  void scale(double arg) {
    _v3storage[2] *= arg;
    _v3storage[1] *= arg;
    _v3storage[0] *= arg;
  }

  /// Create a copy of this and scale it by [arg].
  Vector3 scaled(double arg) => clone()..scale(arg);

  /// Negate this.
  void negate() {
    _v3storage[2] = -_v3storage[2];
    _v3storage[1] = -_v3storage[1];
    _v3storage[0] = -_v3storage[0];
  }

  /// Absolute value.
  void absolute() {
    _v3storage[2] = _v3storage[2].abs();
    _v3storage[1] = _v3storage[1].abs();
    _v3storage[0] = _v3storage[0].abs();
  }

  /// Clamp each entry n in this in the range [min[n]]-[max[n]].
  void clamp(Vector3 min, Vector3 max) {
    final minStorage = min.storage;
    final maxStorage = max.storage;
    _v3storage[2] =
        _v3storage[2].clamp(minStorage[2], maxStorage[2]).toDouble();
    _v3storage[1] =
        _v3storage[1].clamp(minStorage[1], maxStorage[1]).toDouble();
    _v3storage[0] =
        _v3storage[0].clamp(minStorage[0], maxStorage[0]).toDouble();
  }

  /// Clamp entries in this in the range [min]-[max].
  void clampScalar(double min, double max) {
    _v3storage[2] = _v3storage[2].clamp(min, max).toDouble();
    _v3storage[1] = _v3storage[1].clamp(min, max).toDouble();
    _v3storage[0] = _v3storage[0].clamp(min, max).toDouble();
  }

  /// Floor entries in this.
  void floor() {
    _v3storage[2] = _v3storage[2].floorToDouble();
    _v3storage[1] = _v3storage[1].floorToDouble();
    _v3storage[0] = _v3storage[0].floorToDouble();
  }

  /// Ceil entries in this.
  void ceil() {
    _v3storage[2] = _v3storage[2].ceilToDouble();
    _v3storage[1] = _v3storage[1].ceilToDouble();
    _v3storage[0] = _v3storage[0].ceilToDouble();
  }

  /// Round entries in this.
  void round() {
    _v3storage[2] = _v3storage[2].roundToDouble();
    _v3storage[1] = _v3storage[1].roundToDouble();
    _v3storage[0] = _v3storage[0].roundToDouble();
  }

  /// Round entries in this towards zero.
  void roundToZero() {
    _v3storage[2] = _v3storage[2] < 0.0
        ? _v3storage[2].ceilToDouble()
        : _v3storage[2].floorToDouble();
    _v3storage[1] = _v3storage[1] < 0.0
        ? _v3storage[1].ceilToDouble()
        : _v3storage[1].floorToDouble();
    _v3storage[0] = _v3storage[0] < 0.0
        ? _v3storage[0].ceilToDouble()
        : _v3storage[0].floorToDouble();
  }

  /// Clone of this.
  Vector3 clone() => Vector3.copy(this);

  /// Copy this into [arg].
  Vector3 copyInto(Vector3 arg) {
    final argStorage = arg._v3storage;
    argStorage[2] = _v3storage[2];
    argStorage[1] = _v3storage[1];
    argStorage[0] = _v3storage[0];
    return arg;
  }

  /// Copies this into [array] starting at [offset].
  void copyIntoArray(List<double> array, [int offset = 0]) {
    array[offset + 2] = _v3storage[2];
    array[offset + 1] = _v3storage[1];
    array[offset + 0] = _v3storage[0];
  }

  /// Copies elements from [array] into this starting at [offset].
  void copyFromArray(List<double> array, [int offset = 0]) {
    _v3storage[2] = array[offset + 2];
    _v3storage[1] = array[offset + 1];
    _v3storage[0] = array[offset + 0];
  }

  set xy(Vector2 arg) {
    final argStorage = arg._v2storage;
    _v3storage[1] = argStorage[1];
    _v3storage[0] = argStorage[0];
  }

  set xz(Vector2 arg) {
    final argStorage = arg._v2storage;
    _v3storage[2] = argStorage[1];
    _v3storage[0] = argStorage[0];
  }

  set yx(Vector2 arg) {
    final argStorage = arg._v2storage;
    _v3storage[1] = argStorage[0];
    _v3storage[0] = argStorage[1];
  }

  set yz(Vector2 arg) {
    final argStorage = arg._v2storage;
    _v3storage[2] = argStorage[1];
    _v3storage[1] = argStorage[0];
  }

  set zx(Vector2 arg) {
    final argStorage = arg._v2storage;
    _v3storage[2] = argStorage[0];
    _v3storage[0] = argStorage[1];
  }

  set zy(Vector2 arg) {
    final argStorage = arg._v2storage;
    _v3storage[2] = argStorage[0];
    _v3storage[1] = argStorage[1];
  }

  set xyz(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] = argStorage[2];
    _v3storage[1] = argStorage[1];
    _v3storage[0] = argStorage[0];
  }

  set xzy(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[0] = argStorage[0];
    _v3storage[2] = argStorage[1];
    _v3storage[1] = argStorage[2];
  }

  set yxz(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] = argStorage[2];
    _v3storage[1] = argStorage[0];
    _v3storage[0] = argStorage[1];
  }

  set yzx(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] = argStorage[1];
    _v3storage[1] = argStorage[0];
    _v3storage[0] = argStorage[2];
  }

  set zxy(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] = argStorage[0];
    _v3storage[0] = argStorage[1];
    _v3storage[1] = argStorage[2];
  }

  set zyx(Vector3 arg) {
    final argStorage = arg._v3storage;
    _v3storage[2] = argStorage[0];
    _v3storage[1] = argStorage[1];
    _v3storage[0] = argStorage[2];
  }

  set r(double arg) => x = arg;
  set g(double arg) => y = arg;
  set b(double arg) => z = arg;
  set s(double arg) => x = arg;
  set t(double arg) => y = arg;
  set p(double arg) => z = arg;
  set x(double arg) => _v3storage[0] = arg;
  set y(double arg) => _v3storage[1] = arg;
  set z(double arg) => _v3storage[2] = arg;
  set rg(Vector2 arg) => xy = arg;
  set rb(Vector2 arg) => xz = arg;
  set gr(Vector2 arg) => yx = arg;
  set gb(Vector2 arg) => yz = arg;
  set br(Vector2 arg) => zx = arg;
  set bg(Vector2 arg) => zy = arg;
  set rgb(Vector3 arg) => xyz = arg;
  set rbg(Vector3 arg) => xzy = arg;
  set grb(Vector3 arg) => yxz = arg;
  set gbr(Vector3 arg) => yzx = arg;
  set brg(Vector3 arg) => zxy = arg;
  set bgr(Vector3 arg) => zyx = arg;
  set st(Vector2 arg) => xy = arg;
  set sp(Vector2 arg) => xz = arg;
  set ts(Vector2 arg) => yx = arg;
  set tp(Vector2 arg) => yz = arg;
  set ps(Vector2 arg) => zx = arg;
  set pt(Vector2 arg) => zy = arg;
  set stp(Vector3 arg) => xyz = arg;
  set spt(Vector3 arg) => xzy = arg;
  set tsp(Vector3 arg) => yxz = arg;
  set tps(Vector3 arg) => yzx = arg;
  set pst(Vector3 arg) => zxy = arg;
  set pts(Vector3 arg) => zyx = arg;
  Vector2 get xx => Vector2(_v3storage[0], _v3storage[0]);
  Vector2 get xy => Vector2(_v3storage[0], _v3storage[1]);
  Vector2 get xz => Vector2(_v3storage[0], _v3storage[2]);
  Vector2 get yx => Vector2(_v3storage[1], _v3storage[0]);
  Vector2 get yy => Vector2(_v3storage[1], _v3storage[1]);
  Vector2 get yz => Vector2(_v3storage[1], _v3storage[2]);
  Vector2 get zx => Vector2(_v3storage[2], _v3storage[0]);
  Vector2 get zy => Vector2(_v3storage[2], _v3storage[1]);
  Vector2 get zz => Vector2(_v3storage[2], _v3storage[2]);
  Vector3 get xxx => Vector3(_v3storage[0], _v3storage[0], _v3storage[0]);
  Vector3 get xxy => Vector3(_v3storage[0], _v3storage[0], _v3storage[1]);
  Vector3 get xxz => Vector3(_v3storage[0], _v3storage[0], _v3storage[2]);
  Vector3 get xyx => Vector3(_v3storage[0], _v3storage[1], _v3storage[0]);
  Vector3 get xyy => Vector3(_v3storage[0], _v3storage[1], _v3storage[1]);
  Vector3 get xyz => Vector3(_v3storage[0], _v3storage[1], _v3storage[2]);
  Vector3 get xzx => Vector3(_v3storage[0], _v3storage[2], _v3storage[0]);
  Vector3 get xzy => Vector3(_v3storage[0], _v3storage[2], _v3storage[1]);
  Vector3 get xzz => Vector3(_v3storage[0], _v3storage[2], _v3storage[2]);
  Vector3 get yxx => Vector3(_v3storage[1], _v3storage[0], _v3storage[0]);
  Vector3 get yxy => Vector3(_v3storage[1], _v3storage[0], _v3storage[1]);
  Vector3 get yxz => Vector3(_v3storage[1], _v3storage[0], _v3storage[2]);
  Vector3 get yyx => Vector3(_v3storage[1], _v3storage[1], _v3storage[0]);
  Vector3 get yyy => Vector3(_v3storage[1], _v3storage[1], _v3storage[1]);
  Vector3 get yyz => Vector3(_v3storage[1], _v3storage[1], _v3storage[2]);
  Vector3 get yzx => Vector3(_v3storage[1], _v3storage[2], _v3storage[0]);
  Vector3 get yzy => Vector3(_v3storage[1], _v3storage[2], _v3storage[1]);
  Vector3 get yzz => Vector3(_v3storage[1], _v3storage[2], _v3storage[2]);
  Vector3 get zxx => Vector3(_v3storage[2], _v3storage[0], _v3storage[0]);
  Vector3 get zxy => Vector3(_v3storage[2], _v3storage[0], _v3storage[1]);
  Vector3 get zxz => Vector3(_v3storage[2], _v3storage[0], _v3storage[2]);
  Vector3 get zyx => Vector3(_v3storage[2], _v3storage[1], _v3storage[0]);
  Vector3 get zyy => Vector3(_v3storage[2], _v3storage[1], _v3storage[1]);
  Vector3 get zyz => Vector3(_v3storage[2], _v3storage[1], _v3storage[2]);
  Vector3 get zzx => Vector3(_v3storage[2], _v3storage[2], _v3storage[0]);
  Vector3 get zzy => Vector3(_v3storage[2], _v3storage[2], _v3storage[1]);
  Vector3 get zzz => Vector3(_v3storage[2], _v3storage[2], _v3storage[2]);
  Vector4 get xxxx =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[0], _v3storage[0]);
  Vector4 get xxxy =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[0], _v3storage[1]);
  Vector4 get xxxz =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[0], _v3storage[2]);
  Vector4 get xxyx =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[1], _v3storage[0]);
  Vector4 get xxyy =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[1], _v3storage[1]);
  Vector4 get xxyz =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[1], _v3storage[2]);
  Vector4 get xxzx =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[2], _v3storage[0]);
  Vector4 get xxzy =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[2], _v3storage[1]);
  Vector4 get xxzz =>
      Vector4(_v3storage[0], _v3storage[0], _v3storage[2], _v3storage[2]);
  Vector4 get xyxx =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[0], _v3storage[0]);
  Vector4 get xyxy =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[0], _v3storage[1]);
  Vector4 get xyxz =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[0], _v3storage[2]);
  Vector4 get xyyx =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[1], _v3storage[0]);
  Vector4 get xyyy =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[1], _v3storage[1]);
  Vector4 get xyyz =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[1], _v3storage[2]);
  Vector4 get xyzx =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[2], _v3storage[0]);
  Vector4 get xyzy =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[2], _v3storage[1]);
  Vector4 get xyzz =>
      Vector4(_v3storage[0], _v3storage[1], _v3storage[2], _v3storage[2]);
  Vector4 get xzxx =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[0], _v3storage[0]);
  Vector4 get xzxy =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[0], _v3storage[1]);
  Vector4 get xzxz =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[0], _v3storage[2]);
  Vector4 get xzyx =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[1], _v3storage[0]);
  Vector4 get xzyy =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[1], _v3storage[1]);
  Vector4 get xzyz =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[1], _v3storage[2]);
  Vector4 get xzzx =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[2], _v3storage[0]);
  Vector4 get xzzy =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[2], _v3storage[1]);
  Vector4 get xzzz =>
      Vector4(_v3storage[0], _v3storage[2], _v3storage[2], _v3storage[2]);
  Vector4 get yxxx =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[0], _v3storage[0]);
  Vector4 get yxxy =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[0], _v3storage[1]);
  Vector4 get yxxz =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[0], _v3storage[2]);
  Vector4 get yxyx =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[1], _v3storage[0]);
  Vector4 get yxyy =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[1], _v3storage[1]);
  Vector4 get yxyz =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[1], _v3storage[2]);
  Vector4 get yxzx =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[2], _v3storage[0]);
  Vector4 get yxzy =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[2], _v3storage[1]);
  Vector4 get yxzz =>
      Vector4(_v3storage[1], _v3storage[0], _v3storage[2], _v3storage[2]);
  Vector4 get yyxx =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[0], _v3storage[0]);
  Vector4 get yyxy =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[0], _v3storage[1]);
  Vector4 get yyxz =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[0], _v3storage[2]);
  Vector4 get yyyx =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[1], _v3storage[0]);
  Vector4 get yyyy =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[1], _v3storage[1]);
  Vector4 get yyyz =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[1], _v3storage[2]);
  Vector4 get yyzx =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[2], _v3storage[0]);
  Vector4 get yyzy =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[2], _v3storage[1]);
  Vector4 get yyzz =>
      Vector4(_v3storage[1], _v3storage[1], _v3storage[2], _v3storage[2]);
  Vector4 get yzxx =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[0], _v3storage[0]);
  Vector4 get yzxy =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[0], _v3storage[1]);
  Vector4 get yzxz =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[0], _v3storage[2]);
  Vector4 get yzyx =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[1], _v3storage[0]);
  Vector4 get yzyy =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[1], _v3storage[1]);
  Vector4 get yzyz =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[1], _v3storage[2]);
  Vector4 get yzzx =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[2], _v3storage[0]);
  Vector4 get yzzy =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[2], _v3storage[1]);
  Vector4 get yzzz =>
      Vector4(_v3storage[1], _v3storage[2], _v3storage[2], _v3storage[2]);
  Vector4 get zxxx =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[0], _v3storage[0]);
  Vector4 get zxxy =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[0], _v3storage[1]);
  Vector4 get zxxz =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[0], _v3storage[2]);
  Vector4 get zxyx =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[1], _v3storage[0]);
  Vector4 get zxyy =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[1], _v3storage[1]);
  Vector4 get zxyz =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[1], _v3storage[2]);
  Vector4 get zxzx =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[2], _v3storage[0]);
  Vector4 get zxzy =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[2], _v3storage[1]);
  Vector4 get zxzz =>
      Vector4(_v3storage[2], _v3storage[0], _v3storage[2], _v3storage[2]);
  Vector4 get zyxx =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[0], _v3storage[0]);
  Vector4 get zyxy =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[0], _v3storage[1]);
  Vector4 get zyxz =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[0], _v3storage[2]);
  Vector4 get zyyx =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[1], _v3storage[0]);
  Vector4 get zyyy =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[1], _v3storage[1]);
  Vector4 get zyyz =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[1], _v3storage[2]);
  Vector4 get zyzx =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[2], _v3storage[0]);
  Vector4 get zyzy =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[2], _v3storage[1]);
  Vector4 get zyzz =>
      Vector4(_v3storage[2], _v3storage[1], _v3storage[2], _v3storage[2]);
  Vector4 get zzxx =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[0], _v3storage[0]);
  Vector4 get zzxy =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[0], _v3storage[1]);
  Vector4 get zzxz =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[0], _v3storage[2]);
  Vector4 get zzyx =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[1], _v3storage[0]);
  Vector4 get zzyy =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[1], _v3storage[1]);
  Vector4 get zzyz =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[1], _v3storage[2]);
  Vector4 get zzzx =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[2], _v3storage[0]);
  Vector4 get zzzy =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[2], _v3storage[1]);
  Vector4 get zzzz =>
      Vector4(_v3storage[2], _v3storage[2], _v3storage[2], _v3storage[2]);
  double get r => x;
  double get g => y;
  double get b => z;
  double get s => x;
  double get t => y;
  double get p => z;
  double get x => _v3storage[0];
  double get y => _v3storage[1];
  double get z => _v3storage[2];
  Vector2 get rr => xx;
  Vector2 get rg => xy;
  Vector2 get rb => xz;
  Vector2 get gr => yx;
  Vector2 get gg => yy;
  Vector2 get gb => yz;
  Vector2 get br => zx;
  Vector2 get bg => zy;
  Vector2 get bb => zz;
  Vector3 get rrr => xxx;
  Vector3 get rrg => xxy;
  Vector3 get rrb => xxz;
  Vector3 get rgr => xzx;
  Vector3 get rgg => xyy;
  Vector3 get rgb => xyz;
  Vector3 get rbr => xzx;
  Vector3 get rbg => xzy;
  Vector3 get rbb => xzz;
  Vector3 get grr => yxx;
  Vector3 get grg => yxy;
  Vector3 get grb => yxz;
  Vector3 get ggr => yyx;
  Vector3 get ggg => yyy;
  Vector3 get ggb => yyz;
  Vector3 get gbr => yxz;
  Vector3 get gbg => yzy;
  Vector3 get gbb => yzz;
  Vector3 get brr => zxx;
  Vector3 get brg => zxy;
  Vector3 get brb => zxz;
  Vector3 get bgr => zyx;
  Vector3 get bgg => zyy;
  Vector3 get bgb => zyz;
  Vector3 get bbr => zzx;
  Vector3 get bbg => zzy;
  Vector3 get bbb => zzz;
  Vector4 get rrrr => xxxx;
  Vector4 get rrrg => xxxy;
  Vector4 get rrrb => xxxz;
  Vector4 get rrgr => xxyx;
  Vector4 get rrgg => xxyy;
  Vector4 get rrgb => xxyz;
  Vector4 get rrbr => xxzx;
  Vector4 get rrbg => xxzy;
  Vector4 get rrbb => xxzz;
  Vector4 get rgrr => xyxx;
  Vector4 get rgrg => xyxy;
  Vector4 get rgrb => xyxz;
  Vector4 get rggr => xyyx;
  Vector4 get rggg => xyyy;
  Vector4 get rggb => xyyz;
  Vector4 get rgbr => xyzx;
  Vector4 get rgbg => xyzy;
  Vector4 get rgbb => xyzz;
  Vector4 get rbrr => xzxx;
  Vector4 get rbrg => xzxy;
  Vector4 get rbrb => xzxz;
  Vector4 get rbgr => xzyx;
  Vector4 get rbgg => xzyy;
  Vector4 get rbgb => xzyz;
  Vector4 get rbbr => xzzx;
  Vector4 get rbbg => xzzy;
  Vector4 get rbbb => xzzz;
  Vector4 get grrr => yxxx;
  Vector4 get grrg => yxxy;
  Vector4 get grrb => yxxz;
  Vector4 get grgr => yxyx;
  Vector4 get grgg => yxyy;
  Vector4 get grgb => yxyz;
  Vector4 get grbr => yxzx;
  Vector4 get grbg => yxzy;
  Vector4 get grbb => yxzz;
  Vector4 get ggrr => yyxx;
  Vector4 get ggrg => yyxy;
  Vector4 get ggrb => yyxz;
  Vector4 get gggr => yyyx;
  Vector4 get gggg => yyyy;
  Vector4 get gggb => yyyz;
  Vector4 get ggbr => yyzx;
  Vector4 get ggbg => yyzy;
  Vector4 get ggbb => yyzz;
  Vector4 get gbrr => yzxx;
  Vector4 get gbrg => yzxy;
  Vector4 get gbrb => yzxz;
  Vector4 get gbgr => yzyx;
  Vector4 get gbgg => yzyy;
  Vector4 get gbgb => yzyz;
  Vector4 get gbbr => yzzx;
  Vector4 get gbbg => yzzy;
  Vector4 get gbbb => yzzz;
  Vector4 get brrr => zxxx;
  Vector4 get brrg => zxxy;
  Vector4 get brrb => zxxz;
  Vector4 get brgr => zxyx;
  Vector4 get brgg => zxyy;
  Vector4 get brgb => zxyz;
  Vector4 get brbr => zxzx;
  Vector4 get brbg => zxzy;
  Vector4 get brbb => zxzz;
  Vector4 get bgrr => zyxx;
  Vector4 get bgrg => zyxy;
  Vector4 get bgrb => zyxz;
  Vector4 get bggr => zyyx;
  Vector4 get bggg => zyyy;
  Vector4 get bggb => zyyz;
  Vector4 get bgbr => zyzx;
  Vector4 get bgbg => zyzy;
  Vector4 get bgbb => zyzz;
  Vector4 get bbrr => zzxx;
  Vector4 get bbrg => zzxy;
  Vector4 get bbrb => zzxz;
  Vector4 get bbgr => zzyx;
  Vector4 get bbgg => zzyy;
  Vector4 get bbgb => zzyz;
  Vector4 get bbbr => zzzx;
  Vector4 get bbbg => zzzy;
  Vector4 get bbbb => zzzz;
  Vector2 get ss => xx;
  Vector2 get st => xy;
  Vector2 get sp => xz;
  Vector2 get ts => yx;
  Vector2 get tt => yy;
  Vector2 get tp => yz;
  Vector2 get ps => zx;
  Vector2 get pt => zy;
  Vector2 get pp => zz;
  Vector3 get sss => xxx;
  Vector3 get sst => xxy;
  Vector3 get ssp => xxz;
  Vector3 get sts => xyx;
  Vector3 get stt => xyy;
  Vector3 get stp => xyz;
  Vector3 get sps => xzx;
  Vector3 get spt => xzy;
  Vector3 get spp => xzz;
  Vector3 get tss => yxx;
  Vector3 get tst => yxy;
  Vector3 get tsp => yxz;
  Vector3 get tts => yyx;
  Vector3 get ttt => yyy;
  Vector3 get ttp => yyz;
  Vector3 get tps => yzx;
  Vector3 get tpt => yzy;
  Vector3 get tpp => yzz;
  Vector3 get pss => zxx;
  Vector3 get pst => zxy;
  Vector3 get psp => zxz;
  Vector3 get pts => zyx;
  Vector3 get ptt => zyy;
  Vector3 get ptp => zyz;
  Vector3 get pps => zzx;
  Vector3 get ppt => zzy;
  Vector3 get ppp => zzz;
  Vector4 get ssss => xxxx;
  Vector4 get ssst => xxxy;
  Vector4 get sssp => xxxz;
  Vector4 get ssts => xxyx;
  Vector4 get sstt => xxyy;
  Vector4 get sstp => xxyz;
  Vector4 get ssps => xxzx;
  Vector4 get sspt => xxzy;
  Vector4 get sspp => xxzz;
  Vector4 get stss => xyxx;
  Vector4 get stst => xyxy;
  Vector4 get stsp => xyxz;
  Vector4 get stts => xyyx;
  Vector4 get sttt => xyyy;
  Vector4 get sttp => xyyz;
  Vector4 get stps => xyzx;
  Vector4 get stpt => xyzy;
  Vector4 get stpp => xyzz;
  Vector4 get spss => xzxx;
  Vector4 get spst => xzxy;
  Vector4 get spsp => xzxz;
  Vector4 get spts => xzyx;
  Vector4 get sptt => xzyy;
  Vector4 get sptp => xzyz;
  Vector4 get spps => xzzx;
  Vector4 get sppt => xzzy;
  Vector4 get sppp => xzzz;
  Vector4 get tsss => yxxx;
  Vector4 get tsst => yxxy;
  Vector4 get tssp => yxxz;
  Vector4 get tsts => yxyx;
  Vector4 get tstt => yxyy;
  Vector4 get tstp => yxyz;
  Vector4 get tsps => yxzx;
  Vector4 get tspt => yxzy;
  Vector4 get tspp => yxzz;
  Vector4 get ttss => yyxx;
  Vector4 get ttst => yyxy;
  Vector4 get ttsp => yyxz;
  Vector4 get ttts => yyyx;
  Vector4 get tttt => yyyy;
  Vector4 get tttp => yyyz;
  Vector4 get ttps => yyzx;
  Vector4 get ttpt => yyzy;
  Vector4 get ttpp => yyzz;
  Vector4 get tpss => yzxx;
  Vector4 get tpst => yzxy;
  Vector4 get tpsp => yzxz;
  Vector4 get tpts => yzyx;
  Vector4 get tptt => yzyy;
  Vector4 get tptp => yzyz;
  Vector4 get tpps => yzzx;
  Vector4 get tppt => yzzy;
  Vector4 get tppp => yzzz;
  Vector4 get psss => zxxx;
  Vector4 get psst => zxxy;
  Vector4 get pssp => zxxz;
  Vector4 get psts => zxyx;
  Vector4 get pstt => zxyy;
  Vector4 get pstp => zxyz;
  Vector4 get psps => zxzx;
  Vector4 get pspt => zxzy;
  Vector4 get pspp => zxzz;
  Vector4 get ptss => zyxx;
  Vector4 get ptst => zyxy;
  Vector4 get ptsp => zyxz;
  Vector4 get ptts => zyyx;
  Vector4 get pttt => zyyy;
  Vector4 get pttp => zyyz;
  Vector4 get ptps => zyzx;
  Vector4 get ptpt => zyzy;
  Vector4 get ptpp => zyzz;
  Vector4 get ppss => zzxx;
  Vector4 get ppst => zzxy;
  Vector4 get ppsp => zzxz;
  Vector4 get ppts => zzyx;
  Vector4 get pptt => zzyy;
  Vector4 get pptp => zzyz;
  Vector4 get ppps => zzzx;
  Vector4 get pppt => zzzy;
  Vector4 get pppp => zzzz;
}
