例 等値面の可視化

例 構造型ボリュームデータの作成」で作成した構造型ボリュームデータを改良して等値面を描画するプログラムを作成します.

 

1. 作業ディレクトリの作成

作業ディレクトリに「IsoSurface」というディレクトリを作成して,移動して下さい.

$ mkdir  IsoSurface
$ cd IsoSurface

 

2. main.cpp の作成

例 構造型ボリュームデータの作成」で作成したmain.cpp をコピーして,ファイルへエクスポートするところから下を削除して下さい.

#include <kvs/Vector3>
#include <kvs/StructuredVolumeObject>
#include <kvs/StructuredVolumeExporter>
#include <kvs/AVSField>  inline float func( float x, float y, float z ) { return ( 3.0 - x*x - y*y - 4.0*z*z ); } int main( int argc, char** argv ) { // グリッドサイズ kvs::UInt32 gridNum = 64; const kvs::Vector3ui resol( gridNum, gridNum, gridNum ); // ボリュームデータの値を格納するためのメモリの割り当て kvs::ValueArray<float> data( gridNum * gridNum * gridNum ); // dataにを操作するためのポインタ変数 float* pdata = data.data( ); float min = -2.0, max = 2.0; float dt = (float)(max - min)/(float)(gridNum-1); kvs::UInt64 index = 0; for(int k=0; k<gridNum; k++) { for(int j = 0; j<gridNum; j++) { for(int i=0; i< gridNum; i++) { float x = (float)min + (float)i*dt; float y = (float)min + (float)j*dt; float z = (float)min + (float)k*dt; // 関数値を評価してdataへ格納 pdata[ index++ ] = func(x, y, z) ; } } } size_t veclen = 1.0; // 構造型ボリュームオブジェクトの作成 kvs::StructuredVolumeObject *volume = new kvs::StructuredVolumeObject(); volume->setGridType( kvs::StructuredVolumeObject::Uniform ); volume->setResolution( resol ); volume->setVeclen( veclen ); volume->setValues( data );

 

3. ボリュームデータの最小値と最大値を計算する

kvs::StructuredVolumeObject が最小値・最大値をもっているかどうかは,

kvs::StructuredVolumeObject クラスのメソッド hasMinMaxValues()の値がtrueか falseかで知ることができます.

もっていなかった場合は,ボリュームデータのもつ密度値 (values) の最小値・最大値を計算するメソッド

updateMinMaxValues()

を実行して,最小値・最大値を計算します.

// ボリュームデータが最大値・最小値をもっているかチェック
if ( !volume->hasMinMaxValues() ) 
   volume->updateMinMaxValues();	// もっていなければ計算する

 

4. 表示したい等値面の値をキーボードから入力する

キーボードから等値面の値を入力し,入力された値がボリュームデータのもつ最小値・最大値の範囲を超えていないかチェックする.

// 等値面の値をキーボードから入力する
double input_iso, iso;
// ボリュームデータの最小値
double value_min = static_cast<double>( volume->minValue() );
// ボリュームデータの最大値 
double value_max = static_cast<double>( volume->maxValue() );

std::cout << "Input Isolevel [ " << value_min << " - " << value_max << "] : ";

// キーボードから入力した値を取得する
std::cin >> input_iso; // 最大値と最小値を超えていないかチェック if ( input_iso < value_min ) iso = value_min; else if( input_iso > value_max ) iso = value_max; else iso = input_iso;

 

5. 等値面を作成する

KVSには,kvs::StructuredVolumeObject からマーチングキューブ法を使って等値面を生成し,

kvs::PolygonObject を作成するクラス kvs::Isosurface があります.

これまでと同様にkvs::Isosurfacce のコンストラクタを用いて変数宣言と同時に値を代入します.

コンストラクタの要求する引数は

です.

法線の種類はポリゴンオブジェクトを作成したときと同様にenum型 {VertexNormal,PolygonNormal} で指定します.

kvs::PolygonObject* object =
   new kvs::Isosurface( volume,
                        iso,
                        kvs::PolygonObject::VertexNormal );	// 法線の種類

 

6. ポリゴンオブジェクトが作成できたかチェックする

ポリゴンオブジェクトが正しく作成できたかのチェックを行う.

また,正しく作成できていた場合には,ボリュームデータは不要になるため,削除する.

// ポリゴンオブジェクトが正しく作成できたか?
if ( !object )
{
    kvsMessageError( "Cannot create a polygon object." );
    delete volume;
    return( false );
}
// 不要になったボリュームデータを削除する
delete volume;

 

7. 描画

可視化処理を行います.

registerObjectには,kvs::Isosurfaceクラスを使って作成したobject を登録します.

// Screenクラスの生成と設定
kvs::Screen screen( &app );
screen.registerObject( object );
screen.setGeometry( 0, 0, 512, 512 );
screen.setTitle( "Isosurface");
screen.show();
// イベント待ち
return( app.run() );

 

8. ヘッダファイル

例3以外に使用したKVSクラスを追加してインクルードします.

ここでは,新たに

を追加しました.

#include <kvs/PolygonObject>
#include <kvs/Isosurface>
#include <kvs/Application>
#include <kvs/Screen>

 

9. まとめ

以上をまとめたプログラムはこちら: Isosurface.tgz

 

10. コンパイルと実行

作成したプログラムをコンパイル,実行してみましょう.

KVSプログラムをコンパイルするためにはkvsmakeコマンドを用いてMakefileを作成すると簡単にコンパイルを行うことができます.

$ kvsmake -G          <-- Makefile の作成

$ kvsmake            <-- コンパイル

エラーなくコンパイルできたら,実行してみましょう.

実行すると,最小値・最大値が出力され,描画したい等値面の値を入力するように促されるので,

とりあえず,『0.0』を入力して零等値面を描画して下さい.

$ ./Isosurface              

Input Isolevel [ -21  - 2.99395] : 0.0

 

例3と同様の等値面が描画できることが確認できると思います.

Isosurface

問題 複数等値面の描画

上述の例で,等値面を作成する際に指定した法線の種類を面法線( PolygonNormal )に変更してみよう.

変更した結果どのように絵が変わるのかを確認してみましょう.

さらに,等値面をもう1つ作成(新たな PolygonObject を作成)し,不透明度の違う2つの等値面を描画してみよう.

 

(ヒント)

もう1つの等値面は

kvs::PolygonObject* object2

として1つめの等値面と同様にして(等値面の値を変更して)作成します.

不透明度はPolygonObject クラスのもつメソッドを利用します.

object->setOpacity( 10 );
object2->setOpacity( 100 );

setOpasity 関数の引数の型は kvs::UInt8 です.

それぞれのオブジェクトに不透明度を設定することができます.

また,2つのオブジェクトをそれぞれスクリーンに登録することができます.

screen.registerObject( object );
screen.registerObject( object2 );

 

 

 

 

Modefied at June 16, 2013

at April 27, 2017

at May 28, 2021

 

TOP