3D rotation test with ThreeJS






左ドラッグ&テンキー
28:ピッチ
46:ヨー
13:ロール

left drag & numeric keypad
28: Pitch
46: Yaw
13: Roll
W,X,Y,Zの順番です
等価な見なし値になります(異常条件、別値同意値等があるため)

The order is W, X, Y, Z
These are considered to be equivalent values(due to abnormal conditions, different agreed values, etc.)
Camera World 

RotVec

EulerAngle-X-Y-Z-(deg)

Quaternion

Matrix






RotVec


EulerAngle-X-Y-Z-(deg)


Quaternion


Matrix







一人でねちねち試行錯誤するよりもGeminiさんとの対話のおかげで
左ドラッグを素早く実装することができましたありがとうGeminiさん

./javascripts/nas6/rottest3js.js

var chk = false;
var TMan = new N6LTimerMan();  //timer manager//タイマーマネージャー
var TimerID = -1;

var fr = 1000;

var A = new N6LMatrix(4).UnitMat();  //mat view // Three.jsのビュー行列に変換する前の、純粋な回転行列を保持 (主にUI表示用)
var B = new N6LMatrix(4).UnitMat();  //mat view // カメラのワールド変換行列(位置と回転を含む)。継続的に更新され、Three.jsカメラに適用される。
var la = new N6LVector(4, true).UnitVec(3);  // lookAtベクトル (カメラの向いている方向)
var up = new N6LVector(4, true).UnitVec(2);  // upベクトル (カメラの上方向)
var cr = new N6LVector(4, true).UnitVec(1);  // rightベクトル (カメラの右方向)
var tr = new N6LVector(4, true).UnitVec(0);  // translationベクトル (カメラの位置)
var pos = new N6LVector(4, true).UnitVec(0); // カメラの現在位置を保存するためのベクトル(主に復元処理で使用)
var pyr = new N6LVector([1, 0, 0, 0], true); // ピッチ(x), ヨー(y), ロール(z)の累積角(キーボード操作用)

//DOMのロード終了でinitを叩く
window.addEventListener("DOMContentLoaded", init);

var renderer;
var camera;
var scene;

//エントリーポイント
function init() {
  const width = 500;
  const height = 500;

  renderer = new THREE.WebGLRenderer({
    canvas: document.querySelector("#cnv0")
  });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(width, height);
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(
    45,
    width / height,
    1,
    10000
  );
  camera.position.set(0, 0, 20);

  // camera.projectionMatrix はThree.jsの射影行列。NAS6LIB形式に変換しているが、このデモでは直接使用されていない。
  // 主にBをカメラのワールド変換行列として初期化する目的。
  // camera.position.set(0, 0, 20); と一致するようにBを初期化するのが理想的。
  // ここでのBの初期化は、純粋な単位行列にしておき、別途camera.positionを基にBを構築する方法も考えられる。
  var Proj = camera.projectionMatrix;
  B = B.From3JS(Proj); // Three.jsの行列をNAS6LIB形式に変換
//  B = B.SetHomo(true); // ホモジニアス座標のW成分を1に設定し、正規化

  const geometry = new THREE.BoxGeometry(5, 5, 5);
  const loader = new THREE.TextureLoader();

  path = "./img/skybox";
  format = '2.jpg';
  urls = [
    path + 'px' + format, path + 'nx' + format,
    path + 'py' + format, path + 'ny' + format,
    path + 'pz' + format, path + 'nz' + format
  ];

  tCube = new THREE.CubeTextureLoader().load( urls );
  scene.background = tCube;


  // 平行光源
  const light = new THREE.DirectionalLight(0xffffff);
  light.intensity = 2; // 光の強さを倍に
  light.position.set(1, 1, 1);
  // シーンに追加
  scene.add(light);
  const alight = new THREE.AmbientLight( '#808080' );
  scene.add( alight );




  // Three.jsのレンダラーを作成しているキャンバス要素を取得
  // 例: document.getElementById('myCanvas') や renderer.domElement
  const canvasMS = renderer.domElement;

  let mouseX = 0;
  let mouseY = 0;

  let isDragging = false;
  let previousMouseX = 0;
  let previousMouseY = 0;

  canvasMS.addEventListener('mousedown', (event) => {
    if (event.button === 0) { // 左クリック (button === 0)
      isDragging = true;
      const rect = canvasMS.getBoundingClientRect();
      previousMouseX = event.pageX - rect.left;
      previousMouseY = event.pageY - rect.top;
    }
  });

  canvasMS.addEventListener('mousemove', (event) => {
    if (isDragging) {
      const rect = canvasMS.getBoundingClientRect();
      const currentMouseX = event.pageX - rect.left;
      const currentMouseY = event.pageY - rect.top;

      // カメラのヨー・ピッチの感度調整用。1pxあたりのラジアン
      const rotationSpeed = 0.005;

      // マウスの水平移動量 deltaX はカメラのヨー(Y軸周り)回転に、
      // 垂直移動量 deltaY はカメラのピッチ(X軸周り)回転に対応。
      // 符号はThree.jsの座標系とマウス操作の方向に合わせて調整。
      // マウスのデルタ(移動量)
      const deltaX = currentMouseX - previousMouseX;
      const deltaY = currentMouseY - previousMouseY;

      // ヨーとピッチの角度を計算
      // Three.jsはY軸が上方向なので、マウスの上下移動とピッチの方向を合わせるためdeltaYの符号に注意
      const yawAngle = -deltaX * rotationSpeed; // 左右移動でY軸(上方向)周りに回転
      const pitchAngle = -deltaY * rotationSpeed; // 上下移動でX軸(横方向)周りに回転

      // カメラのワールド行列(B)を一時的にコピーし、
      // 必要に応じて逆行列を取ることでビュー行列(カメラ視点)またはワールド行列(オブジェクト視点)として扱う
      //カメラワールド行列
      var matWK = new N6LMatrix(B);
      var radioList = document.getElementsByName("INV"); // "INV"ラジオボタンの状態に応じて反転
      var dt = []; // InverseMat関数用のダミー変数(使用しないなら削除しても良い)
      if(radioList[0].checked) {
        ;// radioList[0]がチェックされている場合、matWKはカメラのワールド行列として扱う
      } else {
        // radioList[0]がチェックされていない場合、matWKをビュー行列(逆行列)に変換
        matWK = matWK.InverseMat(dt);
      }

      // カメラの現在のローカル軸(X, Y, Z)をmatWKから取得
      // これらの軸は、カメラの現在の向きに基づいているため、どんな姿勢でも正確な回転を可能にする
      // N6LMatrixのインデックスと軸の対応に注意(例: x[3]がZ軸、x[2]がY軸)
      // Three.jsは列優先行列 (mat.elements[0]はX軸のX成分)。
      // NAS6LIBのN6LMatrix.x[index]が列ベクトルを返す前提で軸を取得。
      // az = new N6LVector(matWK.x[2]); // カメラZ軸 (前方) - Three.jsのZ軸(col 2)
      // ay = new N6LVector(matWK.x[1]); // カメラY軸 (上方) - Three.jsのY軸(col 1)
      // ax = ay.Cross(az); // カメラX軸 (右方) - 右手系でY軸とZ軸の外積がX軸
      // 3JSとNAS6LIBでは↑↓のようにオーダーが違います
      var az = new N6LVector(matWK.x[3]); // カメラZ軸 (前方)
      az = az.SetHomo(true);
      var ay = new N6LVector(matWK.x[2]); // カメラY軸 (上方)
      ay = ay.SetHomo(true);
      var ax = az.Cross(ay); // カメラX軸 (右方)。右手系: (前方 x 上方) = 左方、(上方 x 前方) = 右方。NAS6LIBのCrossの実装と一致させる。
      ax = ax.SetHomo(true);

      // ヨー回転を適用 (Y軸周り)
      // matWKは内部でクォータニオンを使用しており、ジンバルロックの問題を回避する
      matWK = matWK.RotAxis(ay, yawAngle * 1.0);

      // ★重要: ヨー回転によりmatWKが更新されたため、ローカル軸も再計算する。
      // これにより、次のピッチ回転が現在のカメラの正確なX軸周りに行われる。
      // (微小な角度であれば不要だが、大きな角度や連続的な操作で不具合(ねじれ)を回避するため必須)
      az = new N6LVector(matWK.x[3]);
      az = az.SetHomo(true);
      ay = new N6LVector(matWK.x[2]);
      ay = ay.SetHomo(true);
      ax = az.Cross(ay);
      ax = ax.SetHomo(true);

      // ピッチ回転を適用 (X軸周り)
      matWK = matWK.RotAxis(ax, pitchAngle * -1.0);

      matWK = matWK.NormalMat(); // 行列の正規化(スケールやせん断の蓄積を防ぐため)

      //update
      if(radioList[0].checked) {
        ;
      }
      else {
        matWK = matWK.InverseMat(dt);
      }
      // matWK = matWK.SetCol(0,new N6LVector([1,1,1,1])); // この行は目的によっては不要になる可能性あり
       matWK = matWK.SetCol(0,new N6LVector([1,0,0,0])); // この行は目的によっては不要になる可能性あり
      // matWK = matWK.SetHomo(true); // W成分の正規化

      // 最終的なカメラのワールド行列をBに保存
      B = new N6LMatrix(matWK);

      previousMouseX = currentMouseX;
      previousMouseY = currentMouseY;
    }
  });

  canvasMS.addEventListener('mouseup', (event) => {
    if (event.button === 0) {
      isDragging = false;
    }
  });

  // キャンバス外でマウスを離した場合に備えて、windowにもmouseupイベントを追加するとより頑健
  window.addEventListener('mouseup', () => {
    isDragging = false;
  });





  TimerID = TMan.add();
  Loop(TimerID);

  //main loop//メインループ
  function Loop(id){

  //カメラワールド行列
  var matWK = new N6LMatrix(B);
  var radioList = document.getElementsByName("INV");
  var dt = [];
  if(radioList[0].checked) {
    ;
  }
  else {
    matWK = matWK.InverseMat(dt);
  }

  var az = new N6LVector(matWK.x[3]);     //カメラZ軸行
  az = az.SetHomo(true);
  var ay = new N6LVector(matWK.x[2]);     //カメラY軸行
  ay = ay.SetHomo(true);
  var ax = az.Cross(ay);                  //カメラX軸行
  ax = ax.SetHomo(true);


  // ... (mousemoveイベント内とほぼ同様の軸取得・回転処理) ...

  // ヨーピッチロール回転 (テキストボックスからの入力値による回転)
  // Loop関数はpyrの累積値を微小な角度として毎フレーム適用するため、
  // 各回転後の軸の再取得は省略しても(見た目上)問題になりにくい。
  // しかし、厳密にはmousemoveと同様に逐次軸を更新するのが最も正確。
  matWK = matWK.RotAxis(az, pyr.x[3] * -1.0); // ロール (Z軸周り)
  matWK = matWK.RotAxis(ay, pyr.x[2] * -1.0); // ヨー (Y軸周り)
  matWK = matWK.RotAxis(ax, pyr.x[1] * -1.0); // ピッチ (X軸周り)

  matWK = matWK.NormalMat();

  //update
  if(radioList[0].checked) {
    ;
  }
  else {
    matWK = matWK.InverseMat(dt);
  }
//  matWK = matWK.SetCol(0,new N6LVector([1,1,1,1]));
  matWK = matWK.SetCol(0,new N6LVector([1,0,0,0));
//  matWK = matWK.SetHomo(true);
  B = new N6LMatrix(matWK);
  tr = new N6LVector(matWK.x[0]);
  tr = tr.SetHomo(true);
  up = new N6LVector(matWK.x[2]);
  up = up.SetHomo(true);
  la = new N6LVector(matWK.x[3]);
  la = la.SetHomo(true);
  A = matWK.TransposedMat().TranslatedMat(tr.Mul(-1)).ScaleMat(new N6LVector([1,1,1,-1],true)).TransposedMat();
  //出力用テキストボックス更新のためのAなので同次要素w=1を入れたほうがいいかも
//  A = A.SetCol(0,new N6LVector([1,1,1,1]));
  A = A.SetCol(0,new N6LVector([1,0,0,0]));
//  A = A.SetHomo(true);

  var rot = matWK.Vector();
  //reset
  pyr = new N6LVector([1, 0, 0, 0], true); 


  //回転情報を取得してテキストボックスを更新
  var ea = A.EulerAngle(1,2,3);
  var elm = document.getElementById('rotEA');
  var str = String(Math.floor(ea.x[1]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[2]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[3]*(180.0/Math.PI)*fr)/fr);
  elm.value = str;

  rot = A.Vector();
  elm = document.getElementById('rot');
  str = 'true,4,'+String(Math.floor(rot.x[0]*fr)/fr)+','+String(Math.floor(rot.x[1]*fr)/fr)+','+String(Math.floor(rot.x[2]*fr)/fr)+','+String(Math.floor(rot.x[3]*fr)/fr);
  elm.value = str;

  var qt = A.Quaternion();
  elm = document.getElementById('rotQT');
  str = 'true,4,'+String(Math.floor(qt.q.x[0]*fr)/fr)+','+String(Math.floor(qt.q.x[1]*fr)/fr)+','+String(Math.floor(qt.q.x[2]*fr)/fr)+','+String(Math.floor(qt.q.x[3]*fr)/fr);
  elm.value = str;

  elm = document.getElementById('rotMT');
  str = 'true,4\ntrue,4,'+String(Math.floor(A.x[0].x[0]*fr)/fr)+','+String(Math.floor(A.x[0].x[1]*fr)/fr)+','+String(Math.floor(A.x[0].x[2]*fr)/fr)+','+String(Math.floor(A.x[0].x[3]*fr)/fr) +
        '\ntrue,4,'+String(Math.floor(A.x[1].x[0]*fr)/fr)+','+String(Math.floor(A.x[1].x[1]*fr)/fr)+','+String(Math.floor(A.x[1].x[2]*fr)/fr)+','+String(Math.floor(A.x[1].x[3]*fr)/fr) +  
        '\ntrue,4,'+String(Math.floor(A.x[2].x[0]*fr)/fr)+','+String(Math.floor(A.x[2].x[1]*fr)/fr)+','+String(Math.floor(A.x[2].x[2]*fr)/fr)+','+String(Math.floor(A.x[2].x[3]*fr)/fr) +  
        '\ntrue,4,'+String(Math.floor(A.x[3].x[0]*fr)/fr)+','+String(Math.floor(A.x[3].x[1]*fr)/fr)+','+String(Math.floor(A.x[3].x[2]*fr)/fr)+','+String(Math.floor(A.x[3].x[3]*fr)/fr);
  elm.innerText = str;
  elm.value = str;




  // AはUI表示用の純粋な回転行列として、B(位置情報含む)から回転部分のみを抽出
  // Three.jsのカメラに設定するため、NAS6LIBの行列からThree.jsが必要とする情報を抽出
  // (tr: 位置, up: 上方向ベクトル, la: 注視点(lookAt)ベクトル)
  camera.position.set(tr.x[1], tr.x[2], tr.x[3]); // NAS6LベクトルのW,X,Y,ZのオーダーなのでThree.jsのX,Y,Zにマッピング
  camera.up.set(up.x[1], up.x[2], up.x[3]); // NAS6LベクトルのW,X,Y,ZのオーダーなのでThree.jsのX,Y,Zにマッピング
  camera.lookAt(la.x[1], la.x[2], la.x[3]); // NAS6LベクトルのW,X,Y,ZのオーダーなのでThree.jsのX,Y,Zにマッピング


    // レンダリング
    renderer.render(scene, camera);

    TMan.timer[id].setalerm(function() { Loop(id); }, 50);  //メインループセット
  }
}



//以下回転の復元
function chgrotVec(){
  var elm = document.getElementById('rotin');
  var ro = String(elm.value);
  elm = document.getElementById('rot');
  elm.value = ro;
  var rot = new N6LVector().Parse(ro);
  var radioList = document.getElementsByName("INV");
  var dt = [];
  if(radioList[0].checked) {
    A = rot.Matrix();
//    A = A.SetCol(0,new N6LVector([1,1,1,1]));
    A = A.SetCol(0,new N6LVector([1,0,0,0]));
//    A = A.SetHomo(true);
  }
  else {
    A = rot.Matrix();
//    A = A.SetCol(0,new N6LVector([1,1,1,1]));
    A = A.SetCol(0,new N6LVector([1,0,0,0]));
//    A = A.SetHomo(true);
    A = A.InverseMat(dt);
  }
  B = new N6LMatrix([pos,A.x[1],A.x[2],A.x[3].Mul(-1)]);
  B.x[3].x[0] = 1.0;
  pos = new N6LVector(B.x[0]);

  elm = document.getElementById('rot');
  var ea = A.EulerAngle(1,2,3);
  elm = document.getElementById('rotEA');
  var str = String(Math.floor(ea.x[1]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[2]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[3]*(180.0/Math.PI)*fr)/fr);
  elm.value = str;
  var qt = A.Quaternion();
  elm = document.getElementById('rotQT');
  str = 'true,4,'+String(Math.floor(qt.q.x[0]*fr)/fr)+','+String(Math.floor(qt.q.x[1]*fr)/fr)+','+String(Math.floor(qt.q.x[2]*fr)/fr)+','+String(Math.floor(qt.q.x[3]*fr)/fr);
  elm.value = str;
  elm = document.getElementById('rotMT');
  str = 'true,4
true,4,'+String(Math.floor(A.x[0].x[0]*fr)/fr)+','+String(Math.floor(A.x[0].x[1]*fr)/fr)+','+String(Math.floor(A.x[0].x[2]*fr)/fr)+','+String(Math.floor(A.x[0].x[3]*fr)/fr) +
        '
true,4,'+String(Math.floor(A.x[1].x[0]*fr)/fr)+','+String(Math.floor(A.x[1].x[1]*fr)/fr)+','+String(Math.floor(A.x[1].x[2]*fr)/fr)+','+String(Math.floor(A.x[1].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[2].x[0]*fr)/fr)+','+String(Math.floor(A.x[2].x[1]*fr)/fr)+','+String(Math.floor(A.x[2].x[2]*fr)/fr)+','+String(Math.floor(A.x[2].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[3].x[0]*fr)/fr)+','+String(Math.floor(A.x[3].x[1]*fr)/fr)+','+String(Math.floor(A.x[3].x[2]*fr)/fr)+','+String(Math.floor(A.x[3].x[3]*fr)/fr);
  elm.value = str;
}

function chgrotEA(){
  var elm = document.getElementById('rotEAin');
  var roEA = String(elm.value);
  elm = document.getElementById('rotEA');
  elm.value = roEA;
  var tk = roEA.split(',');
  var ea = new N6LVector([1,Number(tk[0])*(Math.PI/180.0),Number(tk[1])*(Math.PI/180.0),Number(tk[2])*(Math.PI/180.0)],true);
  var ax = new N6LVector(4,true).UnitVec(1);
  var ay = new N6LVector(4,true).UnitVec(2);
  var az = new N6LVector(4,true).UnitVec(3);
  A = A.UnitMat().RotAxis(ax,ea.x[1]);
  ay = A.GetRow(2);
  A = A.RotAxis(ay,ea.x[2]);
  az = A.GetRow(3);
  A = A.RotAxis(az,ea.x[3]);
//  A = A.SetCol(0,new N6LVector([1,1,1,1]));
  A = A.SetCol(0,new N6LVector([1,0,0,0]));
//  A = A.SetHomo(true);
  var radioList = document.getElementsByName("INV");
  var dt = [];
  if(radioList[0].checked) {
    ;
  }
  else {
    A = A.InverseMat(dt);
  }
  B = new N6LMatrix([pos,A.x[1],A.x[2],A.x[3].Mul(-1)]);
  B.x[3].x[0] = 1.0;
  pos = new N6LVector(B.x[0]);

  elm = document.getElementById('rot');
  var rot = A.Vector();
  var str = 'true,4,'+String(Math.floor(rot.x[0]*fr)/fr)+','+String(Math.floor(rot.x[1]*fr)/fr)+','+String(Math.floor(rot.x[2]*fr)/fr)+','+String(Math.floor(rot.x[3]*fr)/fr);
  elm.value = str;
  var qt = A.Quaternion();
  elm = document.getElementById('rotQT');
  str = 'true,4,'+String(Math.floor(qt.q.x[0]*fr)/fr)+','+String(Math.floor(qt.q.x[1]*fr)/fr)+','+String(Math.floor(qt.q.x[2]*fr)/fr)+','+String(Math.floor(qt.q.x[3]*fr)/fr);
  elm.value = str;
  elm = document.getElementById('rotMT');
  str = 'true,4
true,4,'+String(Math.floor(A.x[0].x[0]*fr)/fr)+','+String(Math.floor(A.x[0].x[1]*fr)/fr)+','+String(Math.floor(A.x[0].x[2]*fr)/fr)+','+String(Math.floor(A.x[0].x[3]*fr)/fr) +
        '
true,4,'+String(Math.floor(A.x[1].x[0]*fr)/fr)+','+String(Math.floor(A.x[1].x[1]*fr)/fr)+','+String(Math.floor(A.x[1].x[2]*fr)/fr)+','+String(Math.floor(A.x[1].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[2].x[0]*fr)/fr)+','+String(Math.floor(A.x[2].x[1]*fr)/fr)+','+String(Math.floor(A.x[2].x[2]*fr)/fr)+','+String(Math.floor(A.x[2].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[3].x[0]*fr)/fr)+','+String(Math.floor(A.x[3].x[1]*fr)/fr)+','+String(Math.floor(A.x[3].x[2]*fr)/fr)+','+String(Math.floor(A.x[3].x[3]*fr)/fr);
  elm.value = str;
}

function chgrotQT(){
  var elm = document.getElementById('rotQTin');
  var ro = String(elm.value);
  elm = document.getElementById('rotQT');
  elm.value = ro;
  var qt = new N6LQuaternion().Parse(ro);
  var dt = [];
  A = qt.Matrix();
//  A = A.SetCol(0,new N6LVector([1,1,1,1]));
  A = A.SetCol(0,new N6LVector([1,0,0,0]));
//  A = A.SetHomo(true);
  var radioList = document.getElementsByName("INV");
  if(radioList[0].checked) {
    ;
  }
  else {
    A = A.InverseMat(dt);
  }
  B = new N6LMatrix([pos,A.x[1],A.x[2],A.x[3].Mul(-1)]);
  B.x[3].x[0] = 1.0;
  pos = new N6LVector(B.x[0]);

  elm = document.getElementById('rot');
  var rot = A.Vector();
  var str = 'true,4,'+String(Math.floor(rot.x[0]*fr)/fr)+','+String(Math.floor(rot.x[1]*fr)/fr)+','+String(Math.floor(rot.x[2]*fr)/fr)+','+String(Math.floor(rot.x[3]*fr)/fr);
  elm.value = str;
  var ea = A.EulerAngle(1,2,3);
  elm = document.getElementById('rotEA');
  str = String(Math.floor(ea.x[1]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[2]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[3]*(180.0/Math.PI)*fr)/fr);
  elm.value = str;
  elm = document.getElementById('rotQT');
  str = 'true,4,'+String(Math.floor(qt.q.x[0]*fr)/fr)+','+String(Math.floor(qt.q.x[1]*fr)/fr)+','+String(Math.floor(qt.q.x[2]*fr)/fr)+','+String(Math.floor(qt.q.x[3]*fr)/fr);
  elm.value = str;
  elm = document.getElementById('rotMT');
  str = 'true,4
true,4,'+String(Math.floor(A.x[0].x[0]*fr)/fr)+','+String(Math.floor(A.x[0].x[1]*fr)/fr)+','+String(Math.floor(A.x[0].x[2]*fr)/fr)+','+String(Math.floor(A.x[0].x[3]*fr)/fr) +
        '
true,4,'+String(Math.floor(A.x[1].x[0]*fr)/fr)+','+String(Math.floor(A.x[1].x[1]*fr)/fr)+','+String(Math.floor(A.x[1].x[2]*fr)/fr)+','+String(Math.floor(A.x[1].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[2].x[0]*fr)/fr)+','+String(Math.floor(A.x[2].x[1]*fr)/fr)+','+String(Math.floor(A.x[2].x[2]*fr)/fr)+','+String(Math.floor(A.x[2].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[3].x[0]*fr)/fr)+','+String(Math.floor(A.x[3].x[1]*fr)/fr)+','+String(Math.floor(A.x[3].x[2]*fr)/fr)+','+String(Math.floor(A.x[3].x[3]*fr)/fr);
  elm.value = str;
}

function chgrotMT(){
  var elm = document.getElementById('rotMTin');
  var ro = String(elm.value);
  elm = document.getElementById('rotMT');
  elm.value = ro;
  ro = ro.replace(/\n/g, " ");
  A = new N6LMatrix().Parse(ro);
//  A = A.SetCol(0,new N6LVector([1,1,1,1]));
  A = A.SetCol(0,new N6LVector([1,0,0,0]));
//  A = A.SetHomo(true);
  var radioList = document.getElementsByName("INV");
  var dt = [];
  if(radioList[0].checked) {
    ;
  }
  else {
    A = A.InverseMat(dt);
  }
  B = new N6LMatrix([pos,A.x[1],A.x[2],A.x[3].Mul(-1)]);
  B.x[3].x[0] = 1.0;
  pos = new N6LVector(B.x[0]);

  elm = document.getElementById('rot');
  var rot = A.Vector();
  var str = 'true,4,'+String(Math.floor(rot.x[0]*fr)/fr)+','+String(Math.floor(rot.x[1]*fr)/fr)+','+String(Math.floor(rot.x[2]*fr)/fr)+','+String(Math.floor(rot.x[3]*fr)/fr);
  elm.value = str;
  var ea = A.EulerAngle(1,2,3);
  elm = document.getElementById('rotEA');
  var str = String(Math.floor(ea.x[1]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[2]*(180.0/Math.PI)*fr)/fr)+','+String(Math.floor(ea.x[3]*(180.0/Math.PI)*fr)/fr);
  elm.value = str;
  var qt = A.Quaternion();
  elm = document.getElementById('rotQT');
  str = 'true,4,'+String(Math.floor(qt.q.x[0]*fr)/fr)+','+String(Math.floor(qt.q.x[1]*fr)/fr)+','+String(Math.floor(qt.q.x[2]*fr)/fr)+','+String(Math.floor(qt.q.x[3]*fr)/fr);
  elm.value = str;
  elm = document.getElementById('rotMT');
  str = 'true,4
true,4,'+String(Math.floor(A.x[0].x[0]*fr)/fr)+','+String(Math.floor(A.x[0].x[1]*fr)/fr)+','+String(Math.floor(A.x[0].x[2]*fr)/fr)+','+String(Math.floor(A.x[0].x[3]*fr)/fr) +
        '
true,4,'+String(Math.floor(A.x[1].x[0]*fr)/fr)+','+String(Math.floor(A.x[1].x[1]*fr)/fr)+','+String(Math.floor(A.x[1].x[2]*fr)/fr)+','+String(Math.floor(A.x[1].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[2].x[0]*fr)/fr)+','+String(Math.floor(A.x[2].x[1]*fr)/fr)+','+String(Math.floor(A.x[2].x[2]*fr)/fr)+','+String(Math.floor(A.x[2].x[3]*fr)/fr) +  
        '
true,4,'+String(Math.floor(A.x[3].x[0]*fr)/fr)+','+String(Math.floor(A.x[3].x[1]*fr)/fr)+','+String(Math.floor(A.x[3].x[2]*fr)/fr)+','+String(Math.floor(A.x[3].x[3]*fr)/fr);
  elm.value = str;
}

//出力用テキストボックスから入力用へ情報をコピー
function copy(){
  var elm = document.getElementById('rot');
  var str = String(elm.value);
  elm = document.getElementById('rotin');
  elm.value = str;
  elm = document.getElementById('rotEA');
  str = String(elm.value);
  elm = document.getElementById('rotEAin');
  elm.value = str;
  var elm = document.getElementById('rotQT');
  var str = String(elm.value);
  elm = document.getElementById('rotQTin');
  elm.value = str;
  var elm = document.getElementById('rotMT');
  var str = String(elm.value);
  elm = document.getElementById('rotMTin');
  elm.value = str;
  pos = new N6LVector(B.x[0]);
}

//入力状態遷移(カメラの移動の入力とテキストボックスへの入力の受付の振り分け)
var be = true;
function input(){
  var str;
  if(be) str = 'rgb(255,255,255)';
  else str = 'rgb(136,136,136)';
  var elm = document.getElementById('rotin');
  elm.style.backgroundColor = str;
  elm = document.getElementById('rotEAin');
  elm.style.backgroundColor = str;
  elm = document.getElementById('rotQTin');
  elm.style.backgroundColor = str;
  elm = document.getElementById('rotMTin');
  elm.style.backgroundColor = str;
  if(be) be = false;
  else be = true;
  KeyB.setenable(be);
}

//キー入力
function chkKeyBoard(){
  if(KeyB.keystate[KeyB.indexof(KeyB.ToReal('VK_N1'))]) {//N1Key
    pyr.x[3] -= 5 * (Math.PI / 180);
  }
  if(KeyB.keystate[KeyB.indexof(KeyB.ToReal('VK_N2'))]) {//N2Key
    pyr.x[1] += 5 * (Math.PI / 180);
  }
  if(KeyB.keystate[KeyB.indexof(KeyB.ToReal('VK_N3'))]) {//N3Key
    pyr.x[3] += 5 * (Math.PI / 180);
  }
  if(KeyB.keystate[KeyB.indexof(KeyB.ToReal('VK_N4'))]) {//N4Key
    pyr.x[2] += 5 * (Math.PI / 180);
  }
  if(KeyB.keystate[KeyB.indexof(KeyB.ToReal('VK_N6'))]) {//N6Key
    pyr.x[2] -= 5 * (Math.PI / 180);
  }
  if(KeyB.keystate[KeyB.indexof(KeyB.ToReal('VK_N8'))]) {//N8Key
    pyr.x[1] -= 5 * (Math.PI / 180);
  }
};






戻る