Skip to content

AdvancedReadMe‐Japanese

NAS6mixfoolv edited this page Nov 7, 2025 · 6 revisions

NAS6LIB の高度なドキュメント

このドキュメントでは、NAS6LIB のアーキテクチャ、高度な機能、詳細な技術仕様について詳しく説明します。


目次

NAS6LIBリポジトリに戻る
NAS6LIB Wikiに戻る


モジュールとクラスの概要

NAS6LIB は以下の JavaScript モジュールで構成されており、それぞれに特定のクラスと機能が含まれています。

  • common.js: 基本的なファイルのダウンロードと一般的なユーティリティ関数を提供します。
  • hsv.js: HSV (色相、彩度、明度) と RGB (赤、緑、青) カラーモデル間の相互変換を処理します。
    • クラス: N6LHsv: AHSV と ARGB の変換クラス
  • keyboard.js: 対話型アプリケーションの キーボード入力 を管理します。
    • クラス: N6LKeyBoard: カスタムキーボード管理クラス
  • masspoint.js: 主に物理シミュレーション用の質点に関連する機能を実装します。
    • クラス: N6LMassPoint: MassPoint
  • matrix.js: 安定性とパフォーマンスを重視して設計されたコア行列演算が含まれています。
    • クラス: N6LMatrix: N次元行列
      • 同次座標に関する注意: このライブラリは、同次座標を独自に処理します。
        一般的なxyzwとは異なり、可変長の均一性を保つために、wパラメータをベクトル(wxyz、wxy)の先頭に配置します。
        同次座標が有効になっている場合(bHomo が true)、計算中はすべての要素が w で除算され、
        算術演算は w 以外の要素に対して実行されます。例えば、Matrix × ZeroVector([1,0,0,0],bHomo=true) は、
        行列の並進成分を返します。
  • planet.js: 軌道力学や天体シミュレーションに役立つ、ケプラー方程式 の関数が含まれています。
    • クラス: N6LPlanet: ケプラー方程式による惑星軌道
  • prime.js: 素数関連の計算 のためのユーティリティが含まれています。素数テスト
  • quaternion.js: 回転を管理するための堅牢な クォータニオン演算 を提供し、
    ジンバルロックなどの問題を回避するように設計されています。
  • クラス: N6LQuaternion: クォータニオン
  • クラス: N6LLnQuaternion: 補間をより便利にする対数クォータニオン。
  • rngkt.js: 常微分方程式を解くための強力な数値解析手法である ルンゲ・クッタ法 を実装します。
    物理シミュレーションでよく使用されます。
  • クラス: N6LRngKt: ルンゲ・クッタ法を用いた相対性理論
  • timer.js: スローダウンを引き起こすことなくメインループを効率的に実行するように設計された タイマーマネージャ。
    • クラス: N6LTimer: 時間通知
    • クラス: N6LTimerMan: 時間通知マネージャ。シングルタスクの JavaScript でマルチスレッドを実装するためのフレームワークです。
  • vector.js: 2次元、3次元、およびN次元計算のための基本的なベクトル演算を定義します。
    • クラス: N6LVector: N次元ベクトルまたは同次ベクトル

クラスメソッドの概要

目次に戻る

◆◆◆ClassMethod◆◆◆


相対論的物理学と高度な数学コア

このgifは、一般相対論が示唆する花びら軌道のシミュレーションです。相対論的補正項は極値に設定されています。

花びら軌道のgif

Google Geminiで強調されているように:
「NAS6ライブラリは、単純な3Dグラフィック描画ツールの枠を超えた、高度な物理シミュレーションフレームワークです。
特に、特殊相対性理論と一般相対性理論の主要な効果を
tに組み込んでいます。 効率的かつ実用的な近似手法を用いたシミュレーション。
これは数学、物理学、そして工学実装技術の高度な融合の結晶であり、その開発には計り知れない情熱と努力が注ぎ込まれてきました。

さらに、NAS6ライブラリは単なる物理シミュレーションにとどまらず、学術的精度と実用実装の両面において非常に高いレベルに達しています。
特に、開発者が導出した方程式とルンゲ・クッタ法を用いて水星近日点などの相対論的効果を再現し、
その精度を数値的および視覚的に検証している点は他に類を見ません。これは、開発者の並外れた探究心とエンジニアリング精神を凝縮した、
他に類を見ないライブラリです。効率性を重視しつつ真の物理的現実を追求する姿勢が光ります。

相対論的近日点歳差運動の検証(水星)

目次に戻る

NAS6LIB による相対論的効果の実装は、水星の軌道歳差運動のシミュレーションによって検証されています。
VB で開発された以前のバージョンを使用して、長期間(415 周回、100 年に相当)にわたる周回ごとの平均近日点歳差運動を計算しました。
注目すべきは、この大規模な長期シミュレーションを従来の PC で完了させるのに約 2~3 日かかったことです。
当時としては驚異的なこの効率性は、数値積分における 可変時間ステップ (dt) の使用によって大きく促進され、
これにより計算の最適化が可能になりました。軌道の重要な位相において精度を犠牲にしています。
この事実は、このライブラリの開発に込められた細心の注意の表れです。

計算値は観測値/理論値とほぼ一致しています。

  • 近日点歳差運動の理論値/観測値(太陽-水星):1周あたり 5.0178215994836975336556109594048e-7 rad
  • 近日点歳差運動の計算値(NAS6LIBシミュレーション):1周あたり 4.9767173587098088220555036489103e-7 rad

この結果は、加速合成において実際的な近似値(例えば、完全な相対論的ベクトル合成ではなくスカラー振幅調整を使用)
を用いているにもかかわらず、 NAS6LIBは、長期間のシミュレーション期間にわたって高い数値安定性と精度を保ちながら、
中核的な相対論的現象を効果的に捉えます。このアプローチは計算効率と安定性を重視しており、
水星の近日点移動のような重要な相対論的効果をモデル化するのに十分な性能を備えています。

軌道制約保存則

目次に戻る

このライブラリは、相対論的補正係数$dφ$を含む以下の軌道制約保存則を組み込んでいます。

$$dφ = (3)\left(\frac{v}{c}\right)^2$$

$dφ$を含む様々な軌道パラメータ間の基本的な関係は、以下の式で表されます。

記号集

軌道制約保存則で使用される記号のクイックリファレンスを以下に示します。

以下の式は、様々な方法を示しています。 $r_s c^2 = 2GM$ の値を導出せよ。ここで、$r_s$ はシュワルツシルト半径、$G$ は重力定数、$M$ は中心天体の質量である。
すべての式は次元的に $[m^3s^{-2}]$ と等価である。

$$r_s c^2 = 2GM = 2aV^2(1+d\phi) = 2a^3\omega^2(1+d\phi)$$ $$= ac^2(1-e^2)d\phi(2/3) = \frac{8\pi^2a^3}{T^2}(1+d\phi)$$ $$= \frac{2aV_p^2(1-e)}{1+e}(1+d\phi) = \frac{2aV_a^2(1+e)}{1-e}(1+d\phi)$$ $$= \frac{2h^2}{a(1-e^2)}(1+d\phi) = -4aE(1+d\phi)$$

これらの式(上記)は、$r_s c^2$を決定するために使用されます。

ただし、以下の式は、**$r_s$(シュワルツシルト半径)**を共通の物理量としてより明示的に表し、すべての項にわたって次元の一貫性を確保します。
これらの項はすべて長さ$[m]$に相当します。

$$r_s = \frac{2GM}{c^2} = 2a\left(\frac{V}{c}\right)^2(1+d\phi) = 2a^3\left(\frac{\omega}{c}\right)^2(1+d\phi)$$ $$= a(1-e^2)d\phi(2/3) = \frac{8\pi^2a^3}{c^2T^2}(1+d\phi)$$ $$= \frac{2aV_p^2(1-e)}{c^2(1+e)}(1+d\phi) = \frac{2aV_a^2(1+e)}{c^2(1-e)}(1+d\phi)$$ $$= \frac{2h^2}{c^2a(1-e^2)}(1+d\phi) = -\frac{4aE}{c^2}(1+d\phi)$$

  • G: 重力定数
  • M: 中心天体の質量
  • c: 光速
  • a: 軌道長半径
  • e: 軌道離心率
  • V: 平均軌道速度(一般的な文脈では瞬間速度)
  • dφ: 相対論的近点シフト(この文脈での定義による)
  • rs: 中心天体のシュワルツシルト半径
  • T: 軌道周期
  • ω: 平均角速度
  • Vp: 近点(近心)における速度
  • Va: 遠点(遠心)における速度
  • h: 比角運動量(単位質量あたりの角運動量)
  • E: 比軌道エネルギー(単位質量あたりのエネルギー)

これらの関係から、以下の主要な軌道パラメータが導出されます。

  • シュワルツシルト半径: $r_s = \frac{2GM}{c^2}$
  • 軌道速度: $V = \sqrt{\frac{GM}{a(1+dφ)}} = \frac{aω}{\sqrt{1+dφ}}$
  • 重力パラメータ: $GM = a^3ω^2(1+dφ)$
  • 軌道周期: $T = \sqrt{\frac{4π^2a^3}{GM}(1+dφ)}$
  • 比角運動量: $h = \sqrt{\frac{GMa(1-e^2)}{1+dφ}}$
  • 比軌道エネルギー: $E = -\frac{GM}{2a(1+dφ)}$

$dφ$ に関する注意: $dφ =上記の関係から \frac{3GM}{ac^2(1-e^2)}$ を導くことができますが、
$dφ$ のこの特定の形式は、軌道角の ラジアンあたり で表されていることに注意することが重要です。
これは、$2π$ 係数(通常は軌道あたりの歳差運動の総和に関連付けられます)が存在しないためです。
この $dφ$ の定義は、このライブラリの計算の文脈において一貫しています。

このプロジェクトにおける $d\phi$ 計算とそれが軌道力学に与える影響の文脈において、
中心天体の シュワルツシルト半径 を理解することが極めて重要になります。
これは、その重力と惑星の 軌道 に大きな影響を与える 重要な物理量 です。
したがって、関連する物理現象の記述 と 計算モデル に大きな影響を与えます。
この概念はまた、ここで直接扱われる範囲を超えて、多様な理論的アプローチと解釈 の可能性を秘めています。

計算表

目次に戻る

太陽のシュワルツシルト半径 $r_s = 2953,[m]$
光速 $c = 299792458,[m/s]$
相対論的歳差項は $2\pi d\phi = 2\pi \cdot \frac{3.0}{(1-e^2)}\left(\frac{v}{c}\right)^2$

太陽系の惑星に定数を代入し、$r_s c^2 = ac^2(1-e^2)\frac{d\phi}{3\pi}$ と $r_s c^2 = 2aV^2$ の関係を検証します。

| 惑星名 | 長半径 a[m] | 平均軌道速度 V[m/s] | 離心率 e | (1-e^2) | 3.0/(1-e^2) | (v/c)^2 | 2πdφ | $rs=a(1-e^2)\frac{2πdφ}{3π}$[m] | $rs=2a(\frac{V}{c})^2$[m] |
| :---------- | :------------------- | :---------------------------- | :-------------- | :------------------ | :-------------------------- | :-------------------------- | :------------------ | :-------------------------- |
| 水星 | 57909656770 | 47872.5 | 0.2056 | 0.95772864 | 3.1324112851 | 2.5499449799789e-8 | 5.018679455692e-7 | 2953.328771 | 2953.328771 |
| 金星 | 108208930000 | 35021.4 | 0.0068 | 0.99995376 | 3.0001387264147 | 1.36466357799887e-8 | 2.57244919280835553e-7 | 2953.3757117 | 2953.37571 |
| 地球 | 149597870700 | 29780 | 0.0167 | 0.99972111 | 3.0008369 | 9.86751921971e-9 | 1.86050242679988148e-7 | 2952.31972537 | 2952.31972872 |
| 火星 | 227936640000 | 24130.9 | 0.0934 | 0.99127644 | 3.02640099 | 6.4789650016638728e-9 | 1.232003588093984e-7 | 2953.5870257 | 2953.5870263 |
| 木星 | 778412010000 | 13069.7 | 0.0485 | 0.99764775 | 3.007073388 | 1.900596092587527e-9 | 3.5909861298224e-8 | 2958.893648887 | 2958.893649 |
| 土星 | 1426725400000 | 9672.4 | 0.0555 | 0.99691975 | 3.0092693 | 1.040943340003783e-9 | 1.9681944998115e-8 | 2970.28060454459 | 2970.2806 |
| 天王星 | 2870990000000 | 6800 | 0.0463 | 0.99785631 | 3.0064448858 | 5.14489385919193163e-10 | 9.7187303959641e-9 | 2954.1877641236 | 2954.18776416 |
| 海王星 | 4495060000000 | 5500 | 0.009 | 0.999919 | 3.00024301968 | 3.36576641956219576e-10 | 6.3448341659952e-9 | 3025.8644 | 3025.8644 |


相対性理論に関するさらなる議論と考察のためのリンク

◆◆◆Deep Relativity Discussion◆◆◆


同次座標と N6LMatrix/N6LVector の bHomo フラグ

目次に戻る

注:
これは、w、x、y、z、… の順序で定義される同次座標の説明です。順序は異なりますが、機能は同じです…
NAS6LIB はレンダラーではないため、右手系や左手系はなく、主にレンダラーの座標系に従います。
ただし、ベクトルの外積は右手系で定義されており、レンダラーの座標系に従っている限り、大きな問題は発生しません。

このセクションでは、w N6L は同次座標と bHomo フラグの意味を処理します。これらはライブラリ内で特別な動作を指示します。

  • 座標系の想定
    N6L は基本的に DirectX の規約に基づいているため、行優先の左手座標系を想定しています。

右手座標系を採用している他のライブラリや API とやり取りする場合は、入出力時に転置や Z 軸反転(-1 による乗算)
などの変換が必要になる場合があることに注意することが重要です。

ただし、N6L 内でのみ計算を実行している限り、内部規約を一貫して遵守していれば、これらの外部変換は厳密には必要ありません。

  • N6L の行列レイアウト

同次変換行列は通常、次のように表現されます。

$$M = \begin{pmatrix} ROT & T \\\ 0 & 1 \end{pmatrix}$$

ここで、ROT は回転成分、T は平行移動成分です。N6L は内部表現として、機能的には同等ですが、若干異なる行優先レイアウトを採用しています。
この配置によって計算上の問題は発生しません。

N6L の期待される行列レイアウト(行優先):

$$M = \begin{pmatrix} 1 & 0 & 0 & 0 \\\ T_0 & ROT_{00} & ROT_{01} & ROT_{02} \\\ T_1 & ROT_{10} & ROT_{11} & ROT_{12} \\\ T_2 & ROT_{20} & ROT_{21} & ROT_{22} \end{pmatrix}$$

Mij は回転変換成分です。
Tk は並進成分です。
行 N0 は w 成分の行です。
行 N1 は回転行列の x 軸成分の行です(ローカル座標系)。
行 N2 は回転行列の y 軸成分の行です(ローカル座標系)。
N3行目は、回転行列(ローカル座標系)のZ軸成分の行です。

注:
ベクトル×行列の計算は列優先の計算です。
行列×ベクトルの計算は行優先の計算です。
NAS6LIBで使用される行優先の計算形式の利点は、
ローカル回転変換の各軸を行として直接抽出できることです。
この場合、移動成分は列に配置されますが、
それらを同次ゼロベクトルで乗算することで、
同様に直接抽出できます。
この場合、式の行優先表記は主にN6LMatrix.Mul(N6LVector)ですが、
状況に応じて列優先表記のN6LVector.Mul(N6LMatrix)として記述することもできます。

同次座標系の主な利点
同次座標系と4x4行列を使用することで、様々な3Dグラフィックス変換を統一された
線形代数演算として扱うことができます。その利点は計り知れません。

  • 統一された変換表現:

  • 平行移動、回転、拡大縮小、せん断、さらには透視投影といった多様な変換を、
    単一の4x4行列の乗算で表現できます。これにより、複雑な変換チェーン
    (例: オブジェクトの回転 → 平行移動 → カメラビューの変換)が単純な行列積に簡素化され、
    コードが大幅に効率化されます。同次座標系がなければ、
    異なる変換タイプごとに異なる計算方法が必要になり、コードがはるかに複雑になります。

  • 効率的な逆行列計算(特に回転):
    4x4同次行列から3x3の回転部分を抽出し、その直交行列の特性を利用して、転置するだけで逆行列を求めることができます。
    この最適化により、計算コストの高い一般的な逆行列計算(ガウス消去法など)が回避され、
    リアルタイムグラフィックスのパフォーマンスが大幅に向上します。

  • 透視投影表現:
    同次座標のw成分は、透視投影(奥行き知覚)を表現するために不可欠です。

物体の距離が変化するとw成分も変化し、最終的な3Dから2Dへの投影において正しい透視投影を実現します。

  • 点とベクトルの区別(変換特性):
    同次座標では、点(位置)は通常 (x, y, z, 1) として表現され、方向ベクトルは (x, y, z, 0) として表現されます。
    この区別により、変換行列が適用された場合の挙動が自動的に決定されます。

  • 点は平行移動の影響を受けます。
    方向ベクトルは平行移動の影響を受けません(回転と拡大縮小のみの影響を受けます)。
    この特性も、単一の行列演算によって自動的に実現されます。

  • bHomoフラグ:N6Lの魔法のスイッチ

bHomoフラグはN6L内で特別なスイッチとして機能し、trueに設定すると独自の動作が可能になります。

bHomoがtrueの場合、N6Lは特定の演算を実行します。
算術演算、転置、その他の変換の場合、N6Lは3x3 ROT成分(w成分は省略)を抽出し、
この3x3部分行列に対して演算を実行し、その後w成分を再結合します。
この動作は、同次座標計算の本質的な特性を活用し、より直感的で合理的な変換記述方法を可能にします。

重要: 変換チェーンの最後で bHomo フラグを false にしなければならない場合があります
(例: 特定の操作のために非同次 3D 座標に戻す場合)。
bHomo フラグを適切に切り替えたり管理したりし忘れると、予期しない表示エラーやバグが発生する可能性があります。
bHomo が true または false に設定されていることを、行列の想定される使用例に応じて常に確認してください。
N6LXXX.SetHomo(rh) // bHomo フラグの設定、N6LXXX.ToHomo() // w 要素の追加、N6LXXX.ToNormal() // w 要素の削除などを行うことで、
bHomo フラグを比較的安全に操作できます。

  • N6L における bHomo フラグの動作

bHomo フラグの動作は複雑ですが、導入された理由を説明すると
例えば、N6LVector.Abs() の実装は次のようになります。

//絶対平方
SquareAbs() {
  var sum = 0.0;
  var i = 0;
  var l = new N6LVector(this);
  if(l.bHomo) {
    i = 1;
    l = l.Homogeneous();
  }
  for(; i < l.x.length; i++) sum += l.x[i] * l.x[i];
  return sum;
};

//絶対値
Abs() {
  return Math.sqrt(this.SquareAbs());
};

つまり、bHomoフラグはw要素をスキップするかどうかを決定し、この条件が存在する場合、同じN6LVectorを同次ベクトルと非同次ベクトルの
どちらとして扱い、同次ベクトルの場合はw要素を絶対値に含めず、自動的に判定できるという利点があります。
しかし、この方法にもいくつか問題点があります。N6LMatrixでは、データはN6LMatrix.x要素にN6LVector配列として格納されますが、
このデータ格納には、N6LVector配列のベクトル要素のbHomoがデフォルトでfalseである必要があります(通常の行列計算における動作)。
そのため、行列の行を取得するには、次の2つの方法があります。

var m = new N6LMatrix(4).UnitMat();
var v1 = m.x[1]; // ローカル x 軸を取得 bHomo=false
var v2 = m.GetRow(1); // ローカル x 軸を取得 bHomo=true

取得した N6LVector の bHomo フラグが実装要件で期待されているとおりに設定されていない場合、
w 要素の処理時にバグが発生する可能性があります。
私の経験では、m.x[1] を直接取得する癖があり、
bHomo=false によって意図せず誤動作が発生するケースがありました。
このようなケースの解決策は、行列からベクトルを取得した後、明示的に SetHomo(true または false) を呼び出すことです。


カスタムキーボード管理クラス (keyboard.js)

目次に戻る

N6LKeyBoard クラスは、エイリアス管理や同時キー押下のサポートなど、高度なキーボード入力管理を提供します。

主な機能

  • エイリアス管理: 実際のキーIDを、より便利なカスタムエイリアスにマッピングします。
  • 統合エイリアス: 複数のキーをグループ化して、1つの「統合」キーとして機能します。
  • 同時押下検出: 複数のキーが同時に押されたかどうかを簡単に確認できます。

メインメソッド

  • KeyB.ToReal(str): エイリアスID文字列を実際のキーIDに変換します。
  • KeyB.ToAlias(str, ary): 実際のキーID文字列をエイリアスIDに変換し、エイリアスのリストをary配列に返します。
  • if(KeyB.keystate[KeyB.indexof(KeyB.ToReal(str))]): 特定のキーが現在押されているかどうかを確認します。
  • KeyB.addAlias([original IDstr, alternative IDstr]): キーに新しいエイリアスを追加・定義します。
  • KeyB.delAlias(str): 既存のエイリアスリンクを削除します。
  • KeyB.addUnityAlias([unified IDstr, alternative IDstr, ...]): キーのグループに「unified alias」を追加・定義します。
  • KeyB.delUnityAlias(str): unified aliasを削除します。
  • KeyB.UnityAlias(aliasID): エイリアスを統合します。
  • KeyB.isPressUnityAlias(aliasID): unified aliasの押下情報を取得します。

より詳細なAPIドキュメントと具体的なメソッドシグネチャについては、keyboard.js 内のソースコードコメントを参照してください。
キーボード同時入力テスト

行列の有効な数値の維持

目次に戻る

行列の数値の有効性を確保し、3Dグラフィックスでよくある問題を防ぐために、N6LMatrixライブラリでは以下のメソッドを採用しています。

メソッドの説明:

N6LMatrix.Repair(eps)

説明: 指定された誤差範囲内で、行列要素を0.0、1.0、または-1.0付近の値に修復します。
これは、丸め誤差による精度の回復に役立ちます。
引数: eps: 許容誤差範囲(実数) 戻り値: this (修正後の行列)

N6LMatrix.Max()

説明: 行列のすべての要素の中で最大の絶対値を返します(元の符号は保持されます)。
引数: なし。
戻り値: 要素の絶対値の最大値(実数)。

N6LMatrix.DivMax()

説明: 行列のすべての要素を除算します。
行列内の最大絶対値で除算します。
引数: なし。
戻り値: 要素を最大絶対値で除算した新しい N6LMatrix。
注: このメソッドは、誤差の蓄積により要素の絶対値が ±1.0 を超える致命的なエラーを防ぐために不可欠です。
このエラーが発生すると、各要素の値が予想よりも大幅に大きくなったり小さくなったりする可能性があります。

N6LMatrix.NormalMat()

説明: 行列を正規化します。具体的には、回転行列の場合、回転部分内の各軸ベクトルの直交性と単位長さ (1.0) を確保します。
引数: なし。
戻り値: 正規化された新しい N6LMatrix。

N6LMatrix.Homogeneous()

説明: 同次スケーリングを適用します。このメソッドは、x、y、z 成分を w 成分で除算し、
w を 1 に設定することで、各要素に同次スケーリングを適用します。
引数: なし。
戻り値: 同次スケーリングを適用した新しい N6LMatrix。

N6LMatrix.ToHomo()

説明: 行列を同次行列に変換します。
引数: なし。
戻り値: 同次形式の新しい N6LMatrix。

N6LMatrix.ToNormal()

説明: 行列を正規行列に変換します。
引数: なし。
戻り値: 正規化された形式の新しい N6LMatrix。

N6LMatrix の重要な用途
一般的な数値計算の問題に対処するために、特に N6LMatrix.Repair(eps)、N6LMatrix.NormalMat()、および N6LMatrix.Homogeneous() を使用します。

N6LMatrix.Repair(eps) は、浮動小数点演算中に蓄積される丸め誤差を修復するために使用されます。

この関数がないと、小さな誤差が積み重なり、視覚的なアーティファクトが発生する可能性があります。
N6LMatrix.NormalMat() は、行列の回転部分における軸ベクトルの直交性と単位長さを保証します。
時間の経過とともに、変換を繰り返すと、数値的不安定性により回転行列の直交性が失われ、視覚的な歪みや回転の誤りが生じる可能性があります。
N6LMatrix.Homogeneous() は、同次座標の正規化を処理します。
x、y、z 成分を w 成分で割り、w を 1 に設定し、この同次スケールを各要素に適用します。
この手順は、正しい透視投影と、w が 0 に近づく際の数値的な問題を回避するために重要です。

さまざまな行列変換中にこれらの演算を適用しないと、オブジェクトが消えたり、誤った形状が表示されたりするなど、
予期しない視覚的なバグが発生する可能性があります。これらの問題は、多くの場合、微小な浮動小数点エラーの蓄積に起因しており、
明示的な数値メンテナンス手順がなければデバッグが非常に困難になる可能性があります。

N6LMatrix.RotAxis() の実装例

目次に戻る

RotAxis() メソッドを分解し、数値安定性に関する前回の説明と一致する重要な手順を重点的に見ていきましょう。

RotAxis(axis, theta) メソッドの分析

このメソッドは、指定された軸を中心とした回転行列を theta 度(通常はラジアン)で計算します。

入力検証:

最初の if ブロックは、無効な軸またはこの行列の次元を処理し、デバッグモードでは警告とともに単位行列を返します。

これは、堅牢なコードを実現するための良い方法です。

軸の正規化:

var vwk = new N6LVector(3);
var mwk = new N6LMatrix(this);
if(!this.bHomo) vwk = new N6LVector(axis);
else vwk = axis.ToNormal();
vwk = vwk.NormalVec();
vwk = axis.ToNormal(); または vwk = new N6LVector(axis); :
これにより、入力軸ベクトルが同次(w 成分を持つ)である場合、通常の 3D ベクトルに変換されます。
vwk = vwk.NormalVec(); : これは重要です!軸ベクトルを明示的に正規化します(長さを 1 にします)。
回転式が正しく機能するには、回転軸は単位ベクトルでなければなりません。
入力軸ベクトルに累積誤差があり、長さが正確に 1 でなかった場合、この手順で修正されます。
回転行列の計算(ロドリゲスの回転式):

var c = Math.cos(theta);
var s = Math.sin(theta);
var d = 新しい N6LMatrix([
[c+vwk.x[0]vwk.x[0](1.0-c)、vwk.x[0]vwk.x[1](1.0-c)-vwk.x[2]*s、vwk.x[0]vwk.x[2](1.0-c)+vwk.x[1]s],
[vwk.x[1]vwk.x[0](1.0-c)+vwk.x[2]
s, c+vwk.x[1]vwk.x[1](1.0-c), vwk.x[1]vwk.x[2](1.0-c)-vwk.x[0]*s],
[vwk.x[2]vwk.x[0](1.0-c)-vwk.x[1]*s, vwk.x[2]vwk.x[1](1.0-c)+vwk.x[0]*s, c+vwk.x[2]vwk.x[2](1.0-c) ]]);

これはロドリゲスの回転公式を直接実装し、正規化されたvwk軸とθ角に基づいて3x3回転行列dを作成します。

回転行列の正規化 (d = d.NormalMat();):

d = d.NormalMat();
ここで、新しく生成された回転行列dに対してN6LMatrix.NormalMat()が機能します。
ロドリゲスの公式は理論的には直交行列を生成するはずですが、計算中の浮動小数点精度誤差(特にcosとsinの値)により、
完全な直交性からわずかに逸脱する可能性があります。
ここでNormalMat()を呼び出すと、直交性が即座に修復されます。
回転行列の基底ベクトルの長さが単位であることを保証します。

これにより、新たな数値誤差が生じ、後続の計算で誤差が累積するのを防ぎます。

行列の乗算と修復 (return this.Mul(ret).Repair();):

if(!this.bHomo) return this.Mul(d); // 同次行列でない場合、おそらく3x3行列
var ret = d.ToHomo(); // 3x3回転行列を4x4同次行列に変換
return this.Mul(ret).Repair(); // 乗算を行い、最終結果を修復
この行列が同次行列 (bHomo が true) の場合、新しく作成された3x3回転行列 d は、まず4x4同次行列 (ret = d.ToHomo();) に変換されます。
次に、現在の行列 (this) と乗算 (this.Mul(ret)) されます。
最後に、そして最も重要なのは、乗算の結果に対して .Repair() が呼び出されることです。
これは非常に重要なステップです!行列の乗算、特に浮動小数点数を使った乗算を実行すると、
累積した丸め誤差によって要素が理想値からわずかにずれることがあります。
(例えば、完全な 0.0 が 0.000000001 になったり、1.0 が 0.999999999 になったりします。)

Repair() はこれらの値を意図した近傍の 0.0、1.0、または -1.0 に戻します。
これにより数値の安定性が維持され、微妙な視覚的な不具合やさらなる誤差の蓄積が防止されます。

  • N6LMatrix.Repair() を導入した理由

数値解析のデバッグ中に、丸め誤差のために、理論上は -1、0、または 1 になるはずなのに、実際にはこれらの値になっていないことに気付きました。
もしそうであれば、誤差がepsの範囲内であれば、値をその値に強制的に設定し、問題を解決しました。

  • これらの補正はカプセル化されています

これらの補正はRotAxis()などの変換メソッドに埋め込まれ、カプセル化されているため、ライブラリユーザーはこれらの変換メソッドを呼び出すだけで、
ほとんどの行列の数値的妥当性を確認できます。

目次に戻る

Clone this wiki locally