/*
* PROJECT: NyARToolkit(Extension)
* --------------------------------------------------------------------------------
* The NyARToolkit is Java edition ARToolKit class library.
* Copyright (C)2008-2009 Ryo Iizuka
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* For further information please contact.
* http://nyatla.jp/nyatoolkit/
* <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
*
*/
package jp.nyatla.nyartoolkit.core.param;
import jp.nyatla.nyartoolkit.core.types.NyARDoublePoint2d;
import jp.nyatla.nyartoolkit.core.types.NyARDoublePoint3d;
import jp.nyatla.nyartoolkit.core.types.NyARIntSize;
import jp.nyatla.nyartoolkit.core.types.matrix.NyARDoubleMatrix44;
/**
* このクラスは、視錐台と、これを使った演算関数を定義します。
* クラスのメンバには、視錐台行列、その逆行列があります。
* 提供する機能は、視錐台を使った演算です。
*/
public class NyARFrustum
{
/** frustum行列*/
protected NyARDoubleMatrix44 _frustum_rh=new NyARDoubleMatrix44();
/** frustum逆行列*/
protected NyARDoubleMatrix44 _inv_frustum_rh=new NyARDoubleMatrix44();
/** 撮像画面のサイズ*/
protected NyARIntSize _screen_size=new NyARIntSize();
/**
* コンストラクタです。
* ARToolkitの射影変換行列から、インスタンスを作ります。
* @param i_projection
* @param i_width
* スクリーンサイズです。
* @param i_height
* スクリーンサイズです。
* @param i_near
* 近平面までの距離です。単位はmm
* @param i_far
* 遠平面までの距離です。単位はmm
*/
public NyARFrustum(NyARPerspectiveProjectionMatrix i_projection,int i_width,int i_height,double i_near,double i_far)
{
this.setValue(i_projection, i_width, i_height, i_near, i_far);
}
/**
* この関数は、ARToolKitスタイルの射影変換行列から視錐台を作成してセットします。
* @param i_projection
* ARToolKitスタイルの射影変換行列
* @param i_width
* スクリーンサイズです。
* @param i_height
* スクリーンサイズです。
* @param i_near
* nearポイントをmm単位で指定します。
* @param i_far
* farポイントをmm単位で指定します。
*/
public void setValue(NyARPerspectiveProjectionMatrix i_projection,int i_width,int i_height,double i_near,double i_far)
{
i_projection.makeCameraFrustumRH(i_width, i_height, i_near, i_far,this._frustum_rh);
this._inv_frustum_rh.inverse(this._frustum_rh);
this._screen_size.setValue(i_width,i_height);
}
/**
* このスクリーン座標を、撮像点座標に変換します。
* 撮像点の座標系は、カメラ座標系になります。
* <p>公式 -
* この関数は、gluUnprojectのビューポートとモデルビュー行列を固定したものです。
* 公式は、以下の物使用しました。
* http://www.opengl.org/sdk/docs/man/xhtml/gluUnProject.xml
* ARToolKitの座標系に合せて計算するため、OpenGLのunProjectとはix,iyの与え方が違います。画面上の座標をそのまま与えてください。
* </p>
* @param ix
* スクリーン上の座標
* @param iy
* 画像上の座標
* @param o_point_on_screen
* 撮像点座標
*/
public final void unProject(double ix,double iy,NyARDoublePoint3d o_point_on_screen)
{
double n=(this._frustum_rh.m23/(this._frustum_rh.m22-1));
NyARDoubleMatrix44 m44=this._inv_frustum_rh;
double v1=(this._screen_size.w-ix-1)*2/this._screen_size.w-1.0;//ARToolKitのFrustramに合せてる。
double v2=(this._screen_size.h-iy-1)*2/this._screen_size.h-1.0;
double v3=2*n-1.0;
double b=1/(m44.m30*v1+m44.m31*v2+m44.m32*v3+m44.m33);
o_point_on_screen.x=(m44.m00*v1+m44.m01*v2+m44.m02*v3+m44.m03)*b;
o_point_on_screen.y=(m44.m10*v1+m44.m11*v2+m44.m12*v3+m44.m13)*b;
o_point_on_screen.z=(m44.m20*v1+m44.m21*v2+m44.m22*v3+m44.m23)*b;
return;
}
/**
* この関数は、スクリーン上の点と原点を結ぶ直線と、任意姿勢の平面の交差点を、カメラの座標系で取得します。
* この座標は、カメラ座標系です。
* @param ix
* スクリーン上の座標
* @param iy
* スクリーン上の座標
* @param i_mat
* 平面の姿勢行列です。
* @param o_pos
* 結果を受け取るオブジェクトです。
*/
public final void unProjectOnCamera(double ix,double iy,NyARDoubleMatrix44 i_mat,NyARDoublePoint3d o_pos)
{
//画面→撮像点
this.unProject(ix,iy,o_pos);
//撮像点→カメラ座標系
double nx=i_mat.m02;
double ny=i_mat.m12;
double nz=i_mat.m22;
double mx=i_mat.m03;
double my=i_mat.m13;
double mz=i_mat.m23;
double t=(nx*mx+ny*my+nz*mz)/(nx*o_pos.x+ny*o_pos.y+nz*o_pos.z);
o_pos.x=t*o_pos.x;
o_pos.y=t*o_pos.y;
o_pos.z=t*o_pos.z;
}
/**
* 画面上の点と原点を結ぶ直線と任意姿勢の平面の交差点を、平面の座標系で取得します。
* ARToolKitの本P175周辺の実装と同じです。
* <p>
* このAPIは繰り返し使用には最適化されていません。同一なi_matに繰り返しアクセスするときは、展開してください。
* </p>
* @param ix
* スクリーン上の座標
* @param iy
* スクリーン上の座標
* @param i_mat
* 平面の姿勢行列です。
* @param o_pos
* 結果を受け取るオブジェクトです。
* @return
* 計算に成功すると、trueを返します。
*/
public final boolean unProjectOnMatrix(double ix,double iy,NyARDoubleMatrix44 i_mat,NyARDoublePoint3d o_pos)
{
//交点をカメラ座標系で計算
unProjectOnCamera(ix,iy,i_mat,o_pos);
//座標系の変換
NyARDoubleMatrix44 m=new NyARDoubleMatrix44();
if(!m.inverse(i_mat)){
return false;
}
m.transform3d(o_pos, o_pos);
return true;
}
/**
* カメラ座標系の点を、スクリーン座標の点へ変換します。
* @param i_x
* カメラ座標系の点
* @param i_y
* カメラ座標系の点
* @param i_z
* カメラ座標系の点
* @param o_pos2d
* 結果を受け取るオブジェクトです。
*/
public final void project(double i_x,double i_y,double i_z,NyARDoublePoint2d o_pos2d)
{
NyARDoubleMatrix44 m=this._frustum_rh;
double v3_1=1/i_z*m.m32;
double w=this._screen_size.w;
double h=this._screen_size.h;
o_pos2d.x=w-(1+(i_x*m.m00+i_z*m.m02)*v3_1)*w/2;
o_pos2d.y=h-(1+(i_y*m.m11+i_z*m.m12)*v3_1)*h/2;
return;
}
/**
* 透視変換行列の参照値を返します。
* この値は読出し専用です。変更しないでください。
* @return
* [read only]透視変換行列を格納したオブジェクト
*/
public final NyARDoubleMatrix44 refMatrix()
{
return this._frustum_rh;
}
/**
* 透視変換行列の逆行列を返します。
* この値は読出し専用です。変更しないでください。
* @return
* [read only]透視変換行列の逆行列を格納したオブジェクト
*/
public final NyARDoubleMatrix44 refInvMatrix()
{
return this._inv_frustum_rh;
}
}