物体を表示するためにはベクトルや行列の演算は必須です.KVSでは,2〜4次元の行列/ベクトルクラスが独自に定義されており,各クラスで用意されている四則演算メソッドを使って行列/ベクトルの演算を容易に行うことができます.
ベクトルクラスについて
ベクトルクラスを使用する際には,使用する次数 N ( N = 2, 3, 4 ) に応じてヘッダをインクルードします.
ベクトルのクラスのためのヘッダ |
#include <kvs/VectorN> |
また,変数を宣言する場合には型T ( T = i, ui, f, d ) に応じて
ベクトル型変数 x | kvs::VectorNT x; |
で宣言します.
ここで上述の省略形が許されているのは,
i | int 型 | |
ui | unsigned int 型 | |
f | float 型 | |
d | double 型 |
のみです.
また,以上の省略型以外に,int型,float型,unsigned int型に対して,次の省略形が使用できます.
VecN | float 型 | |
VecNi | int 型 | |
VecNui | unsigned int 型 |
KVS内でtypdef によって省略形が定義されていますが,基本的にはテンプレートクラスとして定義されています.そのため,
kvs::Vector3f a;
kvs::Vec3 a;
は
kvs::Vector3<float > a;
と書いても同じことを意味します.
従って,それ以外の型を宣言したい場合は,
kvs::Matrix33<unsigned char> b;
のように記述すれば良い.
n次元ベクトルの生成
KVSでは2,3,4次元の固定長なベクトルクラスの他に一般的なn 次元のベクトルクラスのオブジェクトの生成可能でです.
ヘッダ #include <kvs/Vector>
をインクルードし,例えばfloat型の10次元ベクトルを定義したい場合は
kvs::Vector<float> a( 10 );
のようにすればよい.
ベクトルクラスのもつメソッド
ベクトルクラスに用意されているメソッドは値の取得や代入,正規化などベクトルの演算に必要なメソッドが用意されています.
実際には,
(KVSのソースをダウンロードしたディレクトリ) kvs-src/Source/Core/Matrix/Vector3.h
を見てみて下さい.ここでは,各メソッドについて使い方を説明します.
コンストラクタ
int型のベクトルkvs::Vector3i を作成する方法としては以下のように4種類用意されています.
※初期値を指定しないでオブジェクトを生成した場合には,全成分の初期値は 0 になります.
// 1.初期値を指定しない
kvs::Vector3i a;
// 2.x, y, z 成分を1つ1つ記述する
kvs::Vector3i a( 1, 2, 0 );
// 3.2次元のベクトルクラス(kvs::Vector2)で定義されたオブジェクとz成分を指定する
kvs::Vector2i t( 1, 1 ); // 2次元のint型ベクトルクラスのオブジェクトを生成
kvs::Vector3i a( t, 3 );
// 4.3次元配列を代入する
int element[3] = { 1, 2, 3 };
kvs::Vector3i a( element );
値の代入: 演算子 [ ], set( )
配列と同様に演算子[ ] を使えるほか,値を代入するメソッド set( ) があります.
また,set( ) は引数の渡し方によってオーバーロードされており,コンストラクタと同様に「x, y, z 成分を1つ1つ記述する」,「2次元のベクトルとz成分を指定する」,「3次元配列を代入する」の3種類があります.
kvs::Vector3i b;
// 演算子 [ ] で値を代入する
b[0] = 1; b[1] = 10; b[2] =5;
// x, y, z 成分を1つ1つ指定する
b.set( 1, 2, 2 );
// 2次元のベクトルと z 成分を指定する
kvs::Vector2i t( 1, 1 );
b.set( t, 5 );
// 3次元配列を代入する
int element[3] = { 1, 2, 3 };
b.set( element );
値の取得: 演算子[ ], x( ), y( ), z( )
代入と同様に演算子 [ ] が使えるほか,ベクトルの x, y, z 成分を取得するメソッド x( ), y( ), z( ) があります.
// 演算子 [ ] をつかう
int x0, y0, z0;
x0 = a[0]; y0 = a[1]; z0 = a[2];
// 成分を指定して表示する
std::cout << a.x( ) << ", " << a.y( ) << ", " << a.z( ) << std::endl;
全成分のクリア:setZero(), setOnes, setUnitX(), setConstant(), setRandom()
値を直接代入する他に,成分を固定の値にするメソッドがあります.
setZero():全成分を 0 にする
setOnes():全成分を 1 にする
setUnitX(), setUnitY(), setUnitZ():それぞれx, y, z 軸方向の単位ベクトルに設定する
setConstant():全成分を引数に渡した値にする
setRandom():全成分に乱数を設定する
kvs::Vector3f c(10.0, 10.0, 10.0);
c.setZero(); // 全成分を 0 にする
c.setOnes(); // 全成分を 1 にする
c.setUnitX(); // x軸方向たの単位ベクトルに設定する(dの成分は (0, 1, 1)となる)
c.setConstant(5.0); // 全成分を 5 に設定
// 全成分に乱数を設定する
c.setRandom(); // 引数がない場合は[0, 1]の一様乱数を設定
c.setRandom( 1000 ); // 引数をシードとして[0, 1]の一様乱数を設定
c.setRandom( -1.0, 1.0 ); // [-1, 1]の範囲で乱数を設定
c.setRandom( -1.0, 1.0, 1000 ); // [-1, 1]の範囲でシードを1000 として乱数を設定
ベクトルを返す静的メンバ関数: Zero(), Ones(), UnityX(), Constant(), Random()
インスタンス化なしに使える静的なメンバ関数として,全成分をクリアする関数と同種の機能が用意されており,関数名が以下のようになります:
Zero():全成分が 0 のオブジェクトを返す
Ones():全成分が 1 のオブジェクトを返す
UnitX(), setUnitY(), setUnitZ():それぞれx, y, z 軸方向の単位ベクトルを返す
Constant():全成分を引数で渡した値にしたたオブジェクトを返す
Random():全成分に乱数を設定したオブジェクトを返す
kvs::Vector3f d;
d = kvs::Vector3f::Zero( ); // 全成分が 0 のベクトルを代入
d = kvs::Vector3f::Ones( ); // 全成分が 1 のベクトルを代入
d = kvs::Vector3f::UnitX( ); // x軸方向たの単位ベクトルを代入する
d ≡ kvs::Vector3f::Constant(3.0): // 全成分が 3 のベクトルを代入
正規化: normalize( ),normalized( )
ベクトルを正規化するメソッドには,次の2種類あります.
normalize( ) は自身を上書きして正規化しますが,
normalized( )はVector3 型の値を戻り値にし,自身を変更しません.
// 自身を正規化
kvs::Vector3d e( 1.0, 2.0, 3.0 );
e.normalize( );
// 正規化した値を返す(自身を変更しない)
kvs::Vector3d f( 1.0, 2.0, 3.0 );
kvs::Vector3d g = f.normalized( );
長さ: length( ), length2( )
ベクトルの長さ,長さの2乗を返すメソッド length( ), squaredLength( ) があります.
また,これらはdouble型の値を戻り値にします.
kvs::Vector3d h( 1.0, 2.0, 3.0 );
// ベクトルの長さを返す
double v = h.length( );
// ベクトルの長さの2乗を返す
double w = h.squaredLength( );
内積: dot( ), 外積: cross( ) , 交換: swap( )
内積は演算子 * ではなくメソッド dot( ) を使い,外積はメソッド cross( ) を使います.
また,ベクトルの値を交換するメソッド swap( ) があります.
// 内積
int dot = a.dot( b );
// 外積
c = a.cross( b );
// 入れ替え
a.swap( b );
オーバーロードされた演算子
標準出力: 演算子<<
ベクトルの成分を並べて:
1 2 3
のように標準出力させることができるように,出力ストリームをオーバーロードした演算子<< があります.
std::cout << a << std::endl;
ostream の参照を返すので演算子<< は組み合わせて使用できます.
四則演算子: +, -, *, /
演算子 + (+=) はベクトルの成分同士の足し算を行います.
演算子 - ( -= ) も同様です.また,オブジェクトに - をつけると各成分に - をつけたベクトルになります.
a.set( 1, 1, 1 );
b.set( 3, 4, 5 );
c = a + b;
a+=c;
a -= b;
std::cout << -a << std::endl;
演算子 * ( *= ) はベクトルの成分同士または,スカラーとベクトルの各成分のかけ算の2種類があります.
変数とベクトルのかけ算では,複合演算子 *= を用いる場合にはスカラーとベクトルの順番に注意して下さい.
// ベクトルの成分同士のかけ算
a*=b;
// 変数とベクトルのかけ算
int i = 10;
c = i*b;
c = b*i; // 同じ値になります
c *= i; // 計算可能です
i *= c; // !!! エラーになります !!!
演算子 / (/= ) は各成分同士または,スカラーとベクトルの成分の割り算の2種類があります.
かけ算の時と同様に,割り算の場合には,変数とベクトルの順番に注意して下さい.
d = c/i;
c /= i;
d = i/c; // !!! エラーになります !!!
i/=c; // !!! エラーになります !!!
関係演算子: ==, !=
ベクトル同士が等しいか(各成分の値がすべて一致するか)どうかを判定する関係演算子があります.
戻り値は bool型です.
// ベクトルが一致するかどうか
if( a == b ) {
std::cout << "a == b" << std::endl;
} else if( a != b ) {
std::cout << "a != b" << std::endl;
}
例 3次元ベクトルの演算
2つの3次元ベクトル:
x = [1, 0, 0]T, y = [2, 1, 1]T
を用いて和,差,内積,外積を計算するプログラムを作成します.
C言語的に書くと: Vector_C.tgz
#include <iostream>
int main( void )
{
double x[3] = { 1.0, 0.0, 0.0 };
double y[3] = { 2.0, 1.0, 1.0 };
// 和
double sum[3];
sum[0] = x[0] + y[0];
sum[1] = x[1] + y[1];
sum[2] = x[2] + y[2];
std::cout << "x + y = ( " << sum[0] << " " << sum[1] << " " << sum[2] << " )" << std::endl;
// 差
double dif[3];
dif[0] = x[0] - y[0];
dif[1] = x[1] - y[1];
dif[2] = x[2] - y[2];
std::cout << "x - y = ( " << dif[0] << " " << dif[1] << " " << dif[2] << " )" << std::endl;
// 内積
double prd = x[0]*y[0] + x[1]*y[1] + x[2]*y[2];
std::cout << "x dot y = " << prd << std::endl;
// 外積
double crs[3];
crs[0] = x[1]*y[2] - x[2]*y[1];
crs[1] = x[2]*y[0] - x[0]*y[2];
crs[2] = x[0]*y[1] - x[1]*y[0];
std::cout << "x cross y = ( " << crs[0] << " " << crs[1] << " " << crs[2] << " )" << std::endl;
return ( 0 );
}
のようになります.
このプログラムをKVSクラスを使って書き換えてみましょう.
1. 作業ディレクトリの作成
作業ディレクトリに「Vector」というディレクトリを作成して,移動して下さい.
$ mkdir Vector
$ cd Vector
2. main.ccp の作成
「main.cpp」というファイルを作成して下さい.
ここでは,3次元ベクトルを使用するために<kvs/Vector3>をインクルードします.
#include <kvs/Vector3>
int main( void )
{
return ( 0 );
}
3. kvs::Vectorクラス
xを3次元double型のベクトルとして宣言します.
クラス名はkvs::Vector3d となり,ここで,3は次元数,d はdouble型を表しています.
kvs::Vector3d x;
定義した変数に値を代入します.kvs::VectorクラスではC言語の配列と同様に添字演算子[]を用いて値を代入することができます.
x[0] = 1.0; x[1] = 0.0; x[2] = 0.0;
kvs::Vectorクラスではコンストラクタを用いて変数宣言と同時に値を代入することができます.
kvs::Vector3d y( 2.0, 1.0, 1.0 );
4. 和,差,内積,外積の計算
kvs::Vectorクラスにメソッドとして定義してあるため,それらを利用して簡単に計算することができます.
// 和
kvs::Vector3d sum = x + y;
// 差
kvs::Vector3d dif = x - y;
// 内積
double prd = x.dot( y );
// 外積
kvs::Vector3d crs = x.cross( y );
5. ベクトルの出力
ベクトルの出力をするための演算子<< も定義されています.
std::cout << x << std::endl;
6. まとめ
以上をまとめたプログラムはこちら: Vector.tgz
7. コンパイルと実行
作成したプログラムをコンパイル,実行してみましょう.
KVSプログラムをコンパイルするためにはkvsmakeコマンドを用いてMakefileを作成すると簡単にコンパイルを行うことができます.
$ kvsmake -G <-- Makefile の作成
$ kvsmake <-- コンパイル
エラーなくコンパイルできたら,実行してみましょう.
以下のような実行結果が得られると思います.
$ ./Vector <-- Windows環境ではVector.exe となります
x + y = ( 3 1 1 )
x - y = ( -1 -1 -1 )
x dot y = 2
x cross y = ( 0 -1 1 )
以上のように,KVSではベクトルを扱うことができます.
問題 ベクトルの直交性
2つのdouble型の3次元ベクトルを生成する.
1つは,標準入力から3成分を入力し,もう1つは[0, 1]の一様乱数で成分を与えるものとする.
この2つのベクトルを標準出力した後,直交しているか否か結果を出力するプログラムを作成しなさい.
Modefied at June 25, 2014
at April 17, 2017
at May 10, 2021
at June 11, 2021