
AVS Technical Report -Volume4,Number3 Novenber,1997-
AVS/Express Vizを使っていると、これは使いづらいなぁ、と思う機能が幾つかあります。
なかでも悪名高いのがdatamapの編集です。任意の設定は可能なのですが、幾つかのパラメーターを数値入力する必要があるため操作性が悪いのです。
特にAVS5からAVS/Expressに移行された方は、AVS5のgenerate colormapモジュールに慣れてしまっているため尚更不便に感じるようです。
そこで、今回はdatamapを任意に編集できるモジュールを作成します。
datamapは文字通りデータ値とカラーマップの対応を定義するオブジェクトです。AVS/Express Vizでは以下のようにデータ値とカラー値を対応させています。

図1 デフォルトのdatamap
図1で縦軸はカラー(HSV)の値、横軸はデータ値です。
デフォルトの設定ではデータの最小値と最大値の2点のみカラー情報が与えられています。レンダリングを行う時にはノード(セル)が持つデータ値がdatamapの最小値と最大値のどの位置にあるのかを計算して、その値でのカラー値を線形補間で求め、オブジェクトの色として反映します。
AVS/Express Vizでdatamapを編集する場合にはデータの最大、最小値間に複数の点を設けます。
そこにカラー情報を与えることにより、任意のdatamapを作成することが可能です。

図2 編集後のdatamap
図2では、[1]~[5]が新しく作成されたdatamapの制御点です。
通常datamapの編集作業は、AVS/ExpressのSingle-window DataViewer,Multi-window DataViewerの Datamap Editer から行います。

図3 Datamap Editer
しかし、datamapを編集するにはadd rangeボタンを押し制御点を増やしてから編集ポイントをスライダーで指定し、さらにHSVの値をスライダーor数値入力して...という作業を行わなければならず、直感的に作業できるエディタとは言えません。
この操作を必要とせずdatamapを編集できるようにするため、マウス操作により編集ポイントの指定と値を指定できるようなエディタを作成することにします。
参考にしたのはAVS5にあるgenerate colormapモジュールのエディタです。
制御点は始めから256点用意しておきます。エディタのパネル上にマウスポインタを置き、クリックされるとマウスポインタのX,Y座標より制御点とカラー値を計算します。変更されたカラー値はリアルタイムにエディタへ反映します。
構成としては、エディタを表示するViewer部分とマウスポインタのX,Y座標を取得するモジュール、マウスの座標情報をもとにカラーマップデータを作成するエディタモジュールを用意します。

図4 モジュールの構成
マウスポインタの情報を受け取り、色相(Hue)についてカラーマップデータを編集します(彩度、明度については今回は見送ります)。
また、編集後の色相を表示するためのmeshデータを出力します。
作成するmeshデータについて注意することがあります。今回はViewer内で移動しないオブジェクトを作成するため座標の指定方法に注意が必要です。
Viewerの中心が座標の原点(0,0)になり、Viewer左下が(-1,-1)、右上が(1,1)となります。エディタモジュールから出力するmeshデータはこの座標に合うように作成します。また、作成するmeshデータは色相の値に応じてY軸方向の座標を変えます。このmeshデータを表示したViewerのイメージとしては図5のようになります。

図5 Viewerイメージ
マウスポインタの情報取得については、DrawCursor2Dモジュールを利用します。このモジュールはViewer上でマウス右ボタンをクリックをするとその位置にCrossとDrawCursor2DモジュールのコントロールパネルにマウスのXY座標が表示されます。
AVS/Express Vizでは、DrawCursor2Dモジュール内でXY座標を持つオブジェクトまで階層をたどることができませんので、Consoleウインドウで探さなければなりません。
調べてみると、
マウスのX座標は
DrawCursor2D.draw_cursor.GDdraw2d_cursor.out_mesh.coordinates.values[0][0]
Y座標は
DrawCursor2D.draw_cursor.GDdraw2d_cursor.out_mesh.coordinates.values[0][1]
マウスの状態は
DrawCursor2D.draw_cursor.GDdraw2d_cursor.state
を参照すれば得られることが分かります。
マウスの状態は
state = 1 右ボタンが押されたとき
state = 2 右ボタンが押されたまま移動したとき
state = 3 右ボタンが押されていないとき
です。
エディタで行われた操作をもとにdatamapオブジェクトの各値を更新するようなメソッドを作成することになるのだろうと思ったのですが、なかなか簡単には行きません。
AVS/Express Vizでは機能制限があるためにdatamapオブジェクトを開くことができません。
AVS/Express Consoleウインドウを使うか、AVS/Express Developerを利用すればdatamapオブジェクトの様子を見ることができます。
ところが、AVS/Express Developerを利用してdatamapオブジェクトを開いてもどこをどのように更新すればよいのか見当もつきません……。
そこで、ここではデータの更新方法としてもっと単純な方法を採用しました。
Datamap Editer には AVS5 のカラーマップデータファイルを読み込む機能があります。そこで、編集したdatamapデータをAVS5のカラーマップデータとしてファイル出力し、それを読み込んでdatamapをアップデートします。
AVS5のカラーマップデータのフォーマットは以下の通りです。
256
0.666667 0.343750 1.000000 0.000000
0.664052 0.350000 1.000000 0.000015
0.661438 0.356250 1.000000 0.000062
:
0.002614 0.387500 1.000000 0.992172
0.000000 0.231250 1.000000 1.000000
0.0 255.0
一行目 : カラーエントリー数
二行目以降 : hue(色相) saturation(彩度) brightness(明度) opacity(不透明度)
最終行 : カラーマップレンジの最小値 最大値
カラーマップファイル出力モジュールは、エディタモジュールから出力されるmeshデータを受け取り、AVS5カラーマップデータをファイル出力するように作成します。

図6 処理の流れ
エディタの概要、出力ファイルフォーマットが決まったので、実際にモジュールの作成を行います。
今回は、マウスのイベントを受け取りリアルタイムに処理しなければならないため、expressプロセスでモジュールを作成します。これは、userプロセスで作成するよりもモジュールの動作が早いからです。
これまでテクニカルレポートでモジュールの作成方法を紹介したときにはuserプロセスで動作するモジュールでした。userプロセスモジュールは作成したモジュールがexpress本体とは別のロードモジュールになります。作成したオブジェクトはExpressとは別プロセスになりExpressの管理下で動作します。
モジュールをexpressプロセスで作成すると、Expressを再構成し新たに作成したモジュールはExpressに組み込まれます。Expressと同じプロセスで動作するようになるのです。
まずは、プロジェクトを作成します。
プルダウンメニューより Project -> Save as... を選びディレクトリの指定をおこなって下さい。
図7のようなプリミティブを持つモジュールを作成します。

図7 colormap_editer,write_colormapモジュール
colormap_editerモジュールはマウスポインタのX,Y座標を受け取りカラーマップデータを出力します。stateはマウスの状態を受け取るオブジェクトです。
write_colormapモジュールはカラーマップ情報であるmeshデータを入力とし、指定されたファイルに出力します。doはファイル出力するためのトリガースイッチになります。
以下の内容のVファイルを作成し、Library WorkspacesのWorkspace 1を選択しRead Objectの機能でライブラリに読み込んで下さい。
editer.v
module colormap_editer<process="express",src_file="edit.c",build_dir="src"> {
omethod update(out_map+write,
X+read+notify,Y+read+notify,state+read+notify) = "edit";
Field_Struct out_map<NEportLevels={0,2}> {
dims => {258,2};
ndim = 2;
nspace = 2;
nnode_data = 1;
node_data = {
{
veclen=1,,,,,,,,
}};
};
double X<NEportLevels={2,0}>;
double Y<NEportLevels={2,0}>;
int state<NEportLevels={2,0}>;
};
write_color.v
module write_colormap<process="express",src_file="write_map.c",build_dir="src"> {
omethod+req update(
Do+read+notify,in_map+req,in_map+read,in_map+req,filename+read+req
) = "write_map";
int Do<NEportLevels={2,0}>;
Field_Struct &in_map<NEportLevels={2,0}>;
string filename<NEportLevels={2,0}>;
};
プルダウンメニューよりProject -> Saveを選び保存します。
作成したモジュールを利用するときには、このexpressを実行する必要があります(普通に可視化を行うときにも、このexpressを使用することができます)。
% <Express_install_dir>/bin/$MACHINE/base -project . -comp_proc express -exit
(注)コマンド実行時には環境変数MACHINEを設定して下さい。環境変数MACHINEに設定する文字列は<Express_install_dir>/bin/xp_machを実行すると得られます。
コンパイルが無事に終了すると、プロジェクト配下のbin/$MACHINEディレクトリにexpressロードモジュールが作成されます。
作成したモジュールを利用するときには、このexpressを実行する必要があります(普通に可視化を行うときにも、このexpressを使用することができます)。
% ./bin/$(MACHINE)/express -viz -project .
と実行して下さい。
Library WorkspacesのWorkspace 1にcolormap_editer,write_colormapの二つのモジュールが含まれたAVS/Express Vizが起動されます。
DrawCursor2Dモジュールからマウスポインタの情報を得るには、データを参照する外部のオブジェクト(float,int)にDrawCursor2Dの内部へのパスを記述しなければなりません。

図8 DrawCursor2D内部への参照
DrawCursor2Dモジュールが配置される度にこの作業を行うのは大変面倒です。そこで、あらかじめマウスポインタの情報を参照しているオブジェクトを用意し、それとDrawCursor2Dモジュールをまとめてマクロモジュールを作成します。
以下その方法です。
X
=> DrawCursor2D.draw_cursor.GDdraw2d_cursor.out_mesh.coordinates.values[0][0]
Y
=> DrawCursor2D.draw_cursor.GDdraw2d_cursor.out_mesh.coordinates.values[0][1]
state
=> DrawCursor2D.draw_cursor.GDdraw2d_cursor.state

図9 mouse pointerへのマクロ化

図10 mouse pointerモジュール
これでWorkspace 1に登録できました。
プルダウンメニューよりProject -> Save を選択して登録内容を保存します。
以降このプロジェクトではViewerでのマウスポインターの位置を取得するときにこのmouse pointerモジュールを利用すれば簡単に情報を得ることができるようになりました。
colormap_editerモジュールから出力されるmeshデータはDataObjectに入力してオブジェクトとして出力します。このときDataObject内で移動しないオブジェクトの属性"Locked"を与える必要があります。
Dataobjectモジュール中で以下のように指定するとオブジェクトが移動しなくなります。
GDM.DataObject DataObject{
Obj{
xform_mode = "Locked";
};
};
ところがAVS/Express Vizではこの属性をModuleStackやScratch Pad上で与えることができず、ConsoleからVコマンドで指定するしか方法がありません。
しかし、colormap_editerモジュールを配置するごとにVコマンドで指定するのも煩わしいです。
回避する方法として、colormap_editerモジュールとDataObjectモジュールをマクロ化し、マクロを記述しているVファイルにオブジェクトLockedの属性を書き加えます。

図11 edit colormapへのマクロ化

図12 edit colormapモジュール
修正前
GDM.DataObject DataObject<NEx=176.,NEy=176.> {
in => <-.colormap_editer.out_map;
obj<NEportLevels={1,3}>;
};
修正後
GDM.DataObject DataObject<NEx=176.,NEy=176.> {
in => <-.colormap_editer.out_map;
obj<NEportLevels={1,3}>;
Obj {
xform_mode = "Locked";
};
};
図13のようにネットワークを組みます。

図13 ネットワーク図

図14 エディター画面
Viewerへマウスポインタを持って行き、右ボタンを押して移動させるとカラー値が変化します。グラフの高さとグラフの色が変ります。
write_colormapモジュールにファイルのパスを指定しDoに1を設定するとAVS5形式のカラーマップがファイルに出力されます。
可視化ネットワークを組み、datamapを変更したいオブジェクトを選択します。コントロールパネルよりDatamapを選択、Option より Input/Putput を選び ActionのリストよりRead AVS5 Colormapを選択します。保存したカラーマップデータを指定し読み込むとその情報がdatamapに反映されます。

図15 変更されたdatamap
可視化をする時にオブジェクトにつける色は、可視化結果を分かりやすく見せるための重要なファクターです。データの分布が片寄っている場合には、デフォルトのdatamapを修正しデータの分布にあったカラーマップを利用した方が分かりやすい表示が行えます。
今回はAVS/Express Vizへの機能追加のひとつとしてdatamapを編集するツールを作成してみました。作成したモジュールも機能的に足りないものですが、興味ある方は参考までに使ってみて下さい。標準のDatamap Editerよりも直感的な編集が可能になっていると思います。
理想としては、ファイルを経由することなく直接datamapオブジェクト内のデータを更新できるようにすることです。しかし、ここまで細かいカスタマイズをしようとするとAVS/Express Developerを使用しないと難しいものがあります。
AVS Support Center, fns-avssup@cs.jp.fujitsu.com