eulerInto method

void eulerInto(
  1. Vector3 out, {
  2. Vector3? hint,
})

Write this rotation's Euler angles (radians, see the class docs) into out.

Every rotation has two Euler triples (plus multiples of 2π). Without a hint the one with x in -π/2, π/2 and y, z in (-π, π] is returned. With a hint — typically the angles the rotation was last set from — the triple closest to it is returned, each angle unwrapped towards the hint; and when setEuler(hint) already gives this rotation, out is exactly the hint. That is what lets an inspector show 370° or (180°, 0, 180°) and get the same numbers back.

Safe when out == hint.

Implementation

void eulerInto(Vector3 out, {Vector3? hint}) {
  if (hint != null && _reproduces(hint.x, hint.y, hint.z)) {
    out.setValues(hint.x, hint.y, hint.z);
    return;
  }
  final xx = x * x, yy = y * y, zz = z * z;
  final m12 = 2.0 * (y * z - x * w);
  final m02 = 2.0 * (x * z + y * w);
  final m22 = 1.0 - 2.0 * (xx + yy);
  final m10 = 2.0 * (x * y + z * w);
  final m11 = 1.0 - 2.0 * (xx + zz);
  final sx = -m12;
  // cos x from a whole row: unlike asin(sx), it stays exact near ±90°.
  final cx = math.sqrt(m10 * m10 + m11 * m11);
  double ex, ey, ez;
  if (cx > 1e-8) {
    ex = math.atan2(sx, cx);
    ey = math.atan2(m02, m22);
    ez = math.atan2(m10, m11);
  } else {
    // Gimbal lock (x = ±90°): only y ∓ z is defined. Keep the hint's z
    // (0 without one) and solve y from it. Below this cos x, rounding in
    // the matrix moves y and z more than snapping x to ±90° does.
    final m00 = 1.0 - 2.0 * (yy + zz);
    final m20 = 2.0 * (x * z - y * w);
    final s = sx > 0 ? 1.0 : -1.0;
    ex = s * math.pi / 2;
    ez = hint?.z ?? 0.0;
    ey = math.atan2(-m20, m00) + s * ez;
    if (hint == null) ey = _wrapPi(ey);
  }
  if (hint == null) {
    out.setValues(ex, ey, ez);
    return;
  }
  // The other triple for the same rotation: (π - x, y + π, z + π).
  final ax1 = _near(ex, hint.x), ay1 = _near(ey, hint.y);
  final az1 = _near(ez, hint.z);
  final ax2 = _near(math.pi - ex, hint.x);
  final ay2 = _near(ey + math.pi, hint.y);
  final az2 = _near(ez + math.pi, hint.z);
  final d1 = _sq(ax1 - hint.x) + _sq(ay1 - hint.y) + _sq(az1 - hint.z);
  final d2 = _sq(ax2 - hint.x) + _sq(ay2 - hint.y) + _sq(az2 - hint.z);
  if (d2 < d1) {
    out.setValues(ax2, ay2, az2);
  } else {
    out.setValues(ax1, ay1, az1);
  }
}