クオータニオンJavaScript で!!

コンピュータ・グラフィックを計算すときに、回転は付きものだ。
勉強しているうちに「クオータニオンで回転」が出てきた。
まず、それを学んだ結果を記録する

クオータニオンとは

  • それは「数」であり、「超複素数」である。数の世界は、自然数から負の数へ、有理数から無理数へ、実数から複素数へと拡大してきた。複数の成分をもつ「数」を「多元数」と呼ぶ。
その前に「複素数」とは
  • 複素数は2つの成分を持つ「数」で「二元数」である。

   (  \mathbb{C} は複素数、\mathbb{R}は実数、a_x, a_yは2つの成分、i \: は虚数単位を表す)

   
  \alpha = a_x + i\: a_y\\
  \color{#00f}{ \alpha = 1 \times {a_x} + i \times {a_y}; \;  ※理解しやすいように表記}\\
  \alpha \in \mathbb{C} \\
  a_x, a_y \in \mathbb{R} \\
  i^2 = -1

クオータニオン
  • 4つの成分をもった数(四元数)である。

     \color{blue}{ \tilde A = \pmb I A_x + \pmb J A_y + \pmb K A_z + 1 \cdot A_w}

   
  I \cdot J \cdot K =  I^2 = K^2 = J^2 = -1\\
  IJ = -JI = K\\
  JK = -KJ = I\\
  KI = -IK = J\\

その他の超複素数
  • その他に、「八元数」もある。しかし交換法則だけでなく、結合法則も不成立となる。実数までの普通の文字式計算の法則が、超複素数になると崩れる。
  • 「三元数」などは無い。(0と1を証明が出来、加減乗算の証明できない)
  • 恐れずに書くのであれば、複素数は2つの成分を持つ「数」なのだから、複素数の2つの成分に「複素数」を当てはめればクオータニオンクオータニオンもまた数なのだから、複素数の2つの成分に当てはめれば、オクトニオン(8成分)、2^nと続く。また成分が多くなれば「数」として制約も多くなり、扱えなくなる。どこまで増やせるかは理解不能

クオータニオンの演算について

クオータニオンの一般系

    \tilde A = \pmb I A_x + \pmb J A_y + \pmb K A_z + A_w

クオータニオンの和

    \tilde A = \tilde B + \tilde C

   
A_x = B_x + C_x \\
A_y = B_y + C_y \\
A_z = B_z + C_z \\
A_w = B_w + C_w
となる。

クオータニオンの積

    \tilde A = \tilde B \cdot \tilde C

   
A_x = B_w C_x + B_x C_w + B_y C_z - B_z C_y \\
A_y = B_w C_y - B_x C_z + B_y C_w + B_z C_x \\
A_z = B_w C_z + B_x C_y - B_y C_x + B_z C_w \\
A_w = B_w C_w - B_x C_x - B_y C_y - B_z C_z
となる。クオータニオンは積に関して非可換である。
   
  \tilde A \cdot \tilde B \neq \tilde B \cdot \tilde A \\
  \tilde A , \tilde B \in \mathbb{Q}

クオータニオンのノルム

    \lVert \tilde A \rVert = \sqrt{{A_x} ^2 + {A_y}^2 + {A_z}^2 + {A_w}^2}

クオータニオンの積の逆元

    {\tilde A}^{-1} = \displaystyle \frac {\tilde A*}{{\lVert \tilde A \rVert}^2}

class Quaternion {
  constructor (x = 0, y = 0, z = 0, w = 0) {
    this.x = x;
    this.y = y;
    this.z = z;
    this.w = w;
  }

  add ({x, y, z, w}) {
    this.x += x;
    this.y += y;
    this.z += z;
    this.w += w;
    return this;
  }

  multi ({x, y, z, w}) {
    let {x: x_, y: y_, z: z_, w: w_} = this;
    this.x = w_*x + x_*w + y_*z + z_*y;
    this.y = w_*y - x_*z + y_*w + z_*x;
    this.z = w_*z + x_*y - y_*x + z_*w;
    this.w = w_*w - x_*x - y_*y - z_*z; 
    return this;
  }

  norm () {
    return Math.sqrt (this.x**2 + this.y**2 + this.z**2 + this.z**2);
  }

  inverse () {
    let n = this.x**2 + this.y**2 + this.z**2 + this.z**2;
    return new Quaternion (this.x / -n, this.y / -n, this.z / -n, this.w / n);
  }

}