前回までの記事では、OpenCASCADE の Draw Test Harness を利用し、独自コマンドを組み込むところまでを紹介しました。今回は、実例を用いながらコーディングしていきたいと思います。
目的
任意の半径を持つ球体を 1/8 にした形状を作成し、その容積を印字したいと思います。
想定しているコマンドの書式は次のとおり。
[bash]
sphere1p8 result_name radius_of_sphere
[/bash]
アプローチとしては、まず原点(0, 0, 0)に半径 r の sphere を作り、同じ位置に大きさ(r, r, r) の box を作成し、二つをコモン演算します。その結果に対して容積を取得しようと思います。
ソースコード
まず、前回のサンプルコードをベースに、プリミティブ、ソリッド、プロパティを扱うためのヘッダを追加してあげます。次に、hello() 関数を sphere1p8() 関数に書き換え、コマンド定義も変更してやります。
[cpp]
include <iostream>
include "/opt/occ660/ros/config.h"
include <Draw.hxx>
include <Draw_Interpretor.hxx>
include <DBRep.hxx>
/* コマンドで利用するヘッダ */
include <TopoDS_Solid.hxx>
include <BRepPrimAPI_MakeBox.hxx>
include <BRepPrimAPI_MakeSphere.hxx>
include <BRepAlgoAPI_Common.hxx>
include <BRepGProp.hxx>
include <GProp_GProps.hxx>
include <Standard_PrimitiveTypes.hxx>
/* 1/8球を作成し、ボリュームを印字する */
static int sphere1p8(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
{
if (argc != 3)
return 1;
// 半径
double r = atof(argv[2]);
// 球と箱を作る
BRepPrimAPI_MakeSphere sphere(gp_Pnt(0, 0, 0), r);
BRepPrimAPI_MakeBox box(gp_Pnt(0, 0, 0), r, r, r);
// ブール演算
BRepAlgoAPI_Common bo(box.Solid(), sphere.Solid());
bo.SetOperation(BOPAlgo_COMMON); // 6.6.0 から BOP_* が BOPAlgo_* になってる
bo.Build();
if (bo.ErrorStatus())
return bo.ErrorStatus();
// 結果を取り出して、登録
TopoDS_Shape shape = bo.Shape();
DBRep::Set(argv[1], shape);
// 容積を印字
GProp_GProps gpr;
BRepGProp::VolumeProperties(shape, gpr);
std::cout << std::endl << "Volume: " << gpr.Mass() << std::endl;
return 0;
}
void Draw_InitAppli(Draw_Interpretor& di)
{
Draw::Commands(di);
di.Add("sphere1p8", "sphere1p8 result r", FILE, sphere1p8);
}
include <Draw_Main.hxx>
DRAW_MAIN
[/cpp]
sphere1p8() 内の処理は、コメントを参考にすれば説明は不要だと思います。1点だけ、補足をしておきますと、40行目の DBRep::Set() 関数で DBRep という Draw の幾何オブジェクト管理構造にオブジェクトを登録しています。この DBRep に登録する事により、AXO ビューアにオブジェクトが表示されることになります。また、Draw インタプリタ上からオブジェクトの名前をキーにして扱うことも出来るようになります。
Draw 内だけで使われるもので、有用な関数を次に示します。
- Draw_Interpretor::Eval … 関数内から Draw コマンドを実行する
例)di.Eval("pload ALL; axo");
- Draw_Interpretor::EvalFile … 関数内からファイルパスを指定し、Tcl スクリプトファイルを実行する
例)di.EvalFile("script.tcl");
- DBRep::Set … オブジェクト名をキーにして、オブジェクトを管理構造に追加する
例)DBRep::Set(objname, myObject);
- DBRep::Get … オブジェクト名をキーにして、オブジェクトを管理構造から取得する
例)TopoDS_Shape myObject = DBRep::Get(objname);
上記の例のように Eval() の文字列はコマンド単位ではなく、一連のスクリプトの内容として食わせることが可能です。(コマンドはセミコロン区切りで1行に連結できます。)
また、DBRep はオブジェクトを静的に管理しているようなので、static 呼び出しで使います。 コマンドの引数として指定されたオブジェクト名で、オブジェクトを取得・設定する際に利用します。
これだけ知っていれば充分ですが、さらに詳しい情報は、Draw_Interpretor と DBRep のリファレンスを参考にしてください。
ビルドと実行
前回のサンプルファイルの時から、利用しているライブラリファイルが増えましたので、ビルドコマンドライン、とりわけ Makefile も書き換える必要があります。
[cpp]
g++ -I/usr/local/inc -lTKernel -lTKDraw -lTKMath -lTKBRep -lTKTopAlgo -lTKPrim -lTKBO -lTKG2d drawtest.cpp
[/cpp]
沢山増えましたね。リンカエラーで「クラス○○の参照が見つかりません!」と怒られた場合は、クラスのリファレンスマニュアルを参照すると、ライブラリ名を特定することができます。例えば、Draw_interpretor クラスの参照エラーとなった場合、リファレンスページの画面上部に「Open CASCADE Technology > Module Draw > Toolkit TKDraw > Package Draw」と表示されています。この Toolkit の部分がライブラリ名になるので、この場合ですと「TKDraw」というライブラリをリンクしてあげればいい事になります。
OpenCASCADE ライブラリは、ほとんどに接頭辞 TK が付いていますが、Toolkit の略です。Tcl/Tk の Tk とおんなじですね。
ビルドが成功したら、実行バイナリを起動して、pload ALL、axo の順にタイプします。その後、追加したコマンド sphere1p8 obj 10.2、 fit コマンドを実行すると、次のようになりました。
あとは、コンパイラに -g して GDB などに投げて、ガリガリとトライ&エラーが楽しめます。