お仕事でROSのRVizを使い、点群地図を表示させる事があります。
RVizのマウス操作に慣れてくると、 表示アングル調整が素早く出来るようになり 「うまく出来てるなぁ〜」と感心させられます。
まぁそれも、お仕事で使わせてもらえる「パワフルなマシン」の恩恵も多々あるのかと。
CPUはIntel Core i7。 GPUはNVIDIA GeForce GTX 1070。
非力なマシンでは、ROSを入れてRVizを動かす事自体の敷居が高いです。
とは言え、膨大なデータ量の点群地図を扱わなければ、、、 簡単なデータならば、非力なマシンでもこの操作感を再現できるのでは?
という事で、 RVizの右側のTypeがXYOrbit(rviz)の時のマウスドラッグの動作を、 wxPythonを使って試してみました。
グラフィックの表示は、負荷の軽いワイヤーフレームで。
レイトレーシング 2018春 の まずはワイヤーフレームから で使ってた部品 (ut, mt, v, line, vecs, ax, fcx, lstx) を流用してみました。
これらの部品を使ってワイヤーフレーム用のエンジンwfrm.pyを作り、 wxPythonのアプリ本体p3d.pyから呼び出してます。
index.yaml (JIS) / body.yaml (JIS)
以前に python3対応のメモ でも、 レイトレーシング 2018春 の えらいこっちゃ で、自宅のpython環境のデフォルトがpython2からpython3に上がってしまった事を書いてましたが、、、
wxPythonはpython2に入れたままで、python3には入れてませんでした。
さて'wxPython mac install'などとググってみると、、、 なにやら、python3でなかなかうまくいかない気配?
wxPythonのサイトのDwonloadを見てみると、macやwindowsは'pip install -U wxPython'とだけ書いてる感じです。
ならばとpip3で試してみると、とりあえず入ってくれました(^_^v
$ pip3 install -U wxPython : $ python Python 3.6.5 (default, Mar 30 2018, 06:41:49) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import wx >>> wx.VERSION (4, 0, 3, '') >>>
$ tar xzf p3d_v1.tgz $ cd p3d
$ ./p3d.py -fn xxx.yaml ( -fn xxx.yaml を省略すると cube.yaml )
視点が目標点の回りを回転します。
視点からの目線の表示なので、表示されてる対象が回転してるように見えます。
マウスを動かすと、視点が目標点に向かって接近したり遠ざかったりします。
ズーム的な表示の変化になります。
(今時はマウスのホイール押下か左右同時押しかな?)
ドラッグの移動量に応じて、目標点が移動します。
目標点の移動は、視点を中心とした回転移動にしてみました。 (RVizの動きとはちょっと違うかも...)
RVizではGUIのZeroボタンによるアングルのリセットがありますが、 左ボタンによるダブルクリックで、そのようにしてみました。
ワイヤーフレームのデータは、yamlファイルに書いてロードします。
p3d.py の起動時に -fn xxx.yaml で指定します。 省略するとデフォルトはとりあえず cube.yaml
yamlファイルのデータ形式は、ベタな感じで次の通り。
$ cat cube.yaml ps: - [-1,-1,-1] - [ 1,-1,-1] - [ 1, 1,-1] - [-1, 1,-1] - [-1,-1, 1] - [ 1,-1, 1] - [ 1, 1, 1] - [-1, 1, 1] idxs: - [0,1,2,3,0,4,5,6,7,4,1,5,0] - [2,6] - [3,7] eye_p: [0,-20,0] eye_t: [0,0,0]
RVizのでもそうなのですが、 ビューのタイプがXYOrbitのときの中ボタンドラッグでの調整が難しいです。
上から見降ろしたビューのタイプ、TopDownOrthoを追加してみました。
ビュー切替えは、右ボタンのダブルクリックで行ないます。
RVizのようにポップアップメニューにしても良かったのですが、、、 リセットを左ボタンのダブルクリックにしてたので、その習わしで。
$ cat v2.patch | patch -p1
ビューをTopDownOrthoに切替えたり、XYOrbitに戻したりするとき、 内部で保持してる視点の位置は変化させてません。
描画時の座標に変換の直前で、 視点座標系とグローバル座標系の変換行列に細工して、 真上からの視点になるように変更してます。
なので、中ボタンドラッグ以外の、左ボタンドラッグと右ボタンドラッグでは、 ビューのタイプに関わらず同じ処理です。
TopDownOrthoで中ボタンドラッグすると、 視点と目標点ともにXY平面に沿って平行移動します。
本当に上からのアングルになっているのか確認するため、 cube.yamlの立方体の上面に斜線を1つ追加しました。
上からのビューで中ボタンドラッグで移動させてみると、 視点の近く側にある面の方が少しだけ大きく表示されるので、 斜線のある面が上にきてる事が判ります。;-p)
YAMLファイル名の指定 -fn xxx.yaml で、 ファイル名'-'を指定すると標準入力からロードするようにしてみました。
合わせて「いわゆる伝統的な図」のYAMLデータを出力するsinc.pyを追加しました。
$ chmod +x sinc.py $ ./sinc.py | ./p3d.py -fn -
などと実行すると、生成したデータをファイルに落すことなく表示を試せます。
sinc.pyの図を表示すると、処理が重く反応が鈍いです。
レイトレーシング 2018春 の方式そのままに、C言語で実装したサーバにしてみました。
$ rm -rf p3d $ tar xzf v3.tgz $ cd p3d $ make
これまでのバージョンの構成は一旦捨てて、v3.tgz でまとめなおしてます。 流用するソースはmakeでサイトから引っ張ってきます。
(argmnt/ は 中の opt.py しか使ってません ;-p)
Makefile | メイクファイル |
---|---|
p3d.py | 本体 |
wfrm.py | ワイヤーフレーム処理とpython版のサーバ |
wfrm.c | ワイヤーフレーム処理とC言語版のサーバ |
dl_rt.sh | レイトレーシング 2018春 からダウンロードして rt/ を生成するスクリプト |
dl_ezyaml.sh | 簡易なYAMLパーサ 2018夏 からダウンロードして ezyaml/ を生成するスクリプト |
dl_argmnt.sh | テキスト配置ツール からダウンロードして argmnt/ を生成するスクリプト |
import.sh | 自前のpythonパッケージ内の暗黙の相対パスimportを明示的な相対パスimportに書き換えるスクリプト |
librt.patch | ダウンロードした rt/ に変更を加えるためのパッチ |
cube.yaml | 立方体のサンプルデータ |
sinc.py | 伝統の図のデータを生成するプログラム |
レイトレーシング 2018春 からの rt/ には librt.patch をあてて修正するようになってます。
rt/Makeile がライブラリを作るようになってなかったのと、 rt/vecs.c に地雷のようにバグが残ってたので修正。
(春の間、よくこの地雷を踏まずにCGをレンダリングしてたものだ...)
$ ./p3d.py -fn cube.yaml $ ./sinc.py | ./p3d.py -fn -
-srv オプションを付けます
$ ./p3d.py -fn cube.yaml -srv -ka $ ./sinc.py | ./p3d.py -fn - -srv -ka
-srv c オプションを付けます
$ cat cube.yaml | ezyaml/blk.py | ./p3d.py -fn - -srv c -ka $ ./sinc.py | ./p3d.py -fn - -srv c -ka
C言語のサーバからYAMLデータのロードでは、 簡易なYAMLパーサ 2018夏 のライブラリを使っているので、YAMLのブロックスタイルしかロードできません。
YAMLデータを ezyaml/blk.py を使ってブロックスタイルに変換してからロードします。
-ka オプションを追加すると、クローズボックスをクリックして終了するときに、 rt/val.py の値サーバも含めて、起動した全てのサーバを終了させます。
-ka オプションを指定しない場合は、終了時にwfrmサーバだけ終了させます。
手持ちのMacの環境では、 sinc.pyの図の表示がキビキビと動いてくれるようになりました。v^_^)
これまでpython2で普通に自前のモジュールをインポートしてました。 いわゆる「暗黙の相対パスのインポート」です。
$ ls foo.py bar.py $ cat foo.py import bar :
カレントディレクトリで実行する分にはええのですが、 例えば今回のように、過去のソース流用するためにパッケージディレクトリを作って置いた場合...
$ find . -type f ./pkg1/foo.py ./pkg1/bar.py ./pkg1/__init__.py ./hoge.py $ cat hoge.py from pkg1 import foo : $ cat pkg1/foo.py import bar : $ python2 hoge.py : $
python2ではこれでOK。
これがpython3では
$ python3 hoge.py Traceback (most recent call last): File "hoge.py", line 1, in <module> from pkg1 import foo File "pkg1/foo.py", line 1, in <module> import bar
python3では、明示的に相対パスのimportにせねばならんとな。
$ cat pkg1/foo.py from . import bar : $ python3 hoge.py : $ $ python2 hoge.py : $
などと pkg1/foo.py を書き換えると、python3でもOK。
import.sh を作って rt/ の下の自前モジュールの import を書き換えるようにしてみました。
しかしながら、この明示的な相対パスのimportを使ってしまうと、 pkg1/foo.py が "__main__" をもってて実行したい場合...
$ cat pk1/foo.py from . import bar : if __name__ == "__main__": print('foo') # EOF $ python2 pkg1/foo.py Traceback (most recent call last): File "pkg1/foo.py", line 1, in <module> from . import bar ValueError: Attempted relative import in non-package $ python3 pkg1/foo.py Traceback (most recent call last): File "pkg1/foo.py", line 1, in <module> from . import bar SystemError: Parent module '' not loaded, cannot perform relative import
python2 でも python3 でもエラー。
pythonコマンドの -m オプションでモジュールを指定して実行すればOK。
$ python2 -m pkg1.foo foo $ python3 -m pkg1.foo foo
rt/srvs.py から val.py サーバを起動して、他のサーバの起動コマンドを登録したりしとります。
wfrm.py の 関数 new()から srvs.py の infs[] を変更、追加して対応してみました。
(pythonは何でもpublicなので可能ですね ;-p)
$ make clean $ cat v4.patch | patch -p1 $ make
TODOの項目対策、対応してみました。
単純なバグでした。 Viewによる中ボタンdragの動作が、pythonのときとは逆になってました。
import.shの中で org/ ディレクトリの有無で実施済が判定するようにしてみました。
rt/lst.[ch] への lstx_opt() 追加を、librt.patch に含めてみました。 さほど速度の効果がないかも知れませんが、 wfrm.c の get_lst() から lstx_opt() を呼び出すようにしてみました。
背景色のデフォルトを黒くしました。 p3d.py の起動オプション -bg xxx で変更可能です。
$ ./p3d.py -bg wx.WHITE $ ./p3d.py -bg '(0,128,128)'
などと指定できます。 (括弧の中の数値は r, g, b 順です)
cube.yaml のキー'idxs'の箇所に指定を追加してみました。
$ cat cube.yaml ps: - [-1,-1,-1] - [ 1,-1,-1] - [ 1, 1,-1] - [-1, 1,-1] - [-1,-1, 1] - [ 1,-1, 1] - [ 1, 1, 1] - [-1, 1, 1] idxs: - [0,1,2,3,0,4,5,6,7,4,1,5,0] - col: [200,0,0] - [2,6] - [3,7] - col: [50,200,0] - [4,6] eye_p: [0,-20,0] eye_t: [0,0,0]
idxs のリストの要素として、 キー'col'で、値が [r, g, b] の順のリストを指定します。 (残念ながら 'wx.BLACK' などの文字列は指定できません)
以降、その指定色で線が描画されます。
初めのデフォルト色は白です。
初めのデフォルト色は p3d.py の起動オプション -fg xxx で変更可能です。
$ ./p3d.py -fg wx.RED $ ./p3d.py -fg '(0,128,128)'
などと指定できます。 (括弧の中の数値は r, g, b 順です)
sinc.pyも無意味に色つきデータを出力するよう変更してみました。;-p)