OpenCASCADE で点、線分、ポリラインを作成する。

OpenCASCADE関連の日本語情報がほとんどありませんので、Tipsというか、使い方というか、自分用のメモ的なものを小出しにしてまとめていこうと思います。

OCCで形状を作成する場合、特殊なものでなければ BRepBuilderAPI を用います。点、線分、ポリラインも例に漏れずこれを使います。

点を作る

OCCの点は、扱うレベルによっていくつか言い方が変わってきます。
ここではトポロジーレベル(TopoDS)の点(Vertex)を作成します。

gp_Pnt p(10, 20, 0);
TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(p);

簡単ですね!

上の例では、座標値 [10, 20, 0] の位置に存在する点を作成しました。
gp_Pnt は、これも点と言えば点なのですが、主に X, Y, Z の座標値を格納したり、引数に渡す時の入れ物としての「点」です。
一方、TopoDS_Vertex は、幾何として三次元空間上に存在する「点」です。

なんだか良く分からない説明ですが、gp_Pnt をその人のプロフィール、TopoDS_Vertex がその人自身、みたいな感じで見てもらったら結構です。(かえって分かりづらいかな…)

通常は上の例で問題がないんですが、もう少しだけ「ちゃんと」記述すると、次のようにも書けます。

gp_Pnt p(10, 20, 0);
BRepBuilderAPI_MakeVertex mv(p);
TopoDS_Vertex v = mv.Vertex(); // Vertex として受け取る場合
TopoDS_Shape  s = mv.Shape();  // Shape として受け取る場合

BRepBuilderAPI_Make~系のクラスは、作る目的の型に特殊化してくれるメソッドと、抽象的な TopoDS_Shape 型で返してくれる Shape() が大体備わっています。用途に応じて使い分けができます。

線分を作成する

OCCにおける線という概念も、点と同様に扱うレベルによって言い方が変わってきます。ここでも、まずはトポロジーレベルでの線分を作成してみましょう。

gp_Pnt start_point(0, 0, 0);
gp_Pnt terminal_point(10, 20, 0);
TopoDS_Edge e = BRepBuilderAPI_MakeEdge(start_point, terminal_point);

gp_Pnt 型で始終点を定義して、それを引数に BRepBuilderAPI_MakeEdge() で線分を作成しています。これも Vertex 同様に MakeEdge のオブジェクトを作り

gp_Pnt start_point(0, 0, 0);
gp_Pnt terminal_point(10, 20, 0);
BRepBuilderAPI_MakeEdge me(start_point, terminal_point);
if (me.IsDone()) {
    TopoDS_Edge e = me.Edge();   // Edge として受け取る場合
    TopoDS_Shape s = me.Shape(); // Shape として受け取る場合
}

という風に書く事もできます。Vertex と一つ違うのは、IsDone() メソッドで判定している点です。
Vertex の場合は、点の作成に失敗することがありませんが、線分の場合は例えば始終点が同一点であった場合など、線分として成立しない引数が渡される可能性があります。
そこで、作成が上手くいったかどうかを IsDone() で判定しているわけです。
MakeEdge に限らず、引数によっては成立しない形状を作成する際には、いきなり Shape() を取得するのではなく IsDone() でチェックすることを心掛けましょう。

ポリラインを作成する

ポリラインは BRepBuilderAPI_MakePolygon を使って作成します。トポロジーレベルでの幾何の型は TopoDS_Edge または TopoDS_Wire になります。
作成した形状によって Edge / Wire にいずれかになるわけではなく、次のように用途によって受け取ることができます。

BRepBuilderAPI_MakePolygon mp;

mp.Add(gp_Pnt(0, 0, 0));
mp.Add(gp_Pnt(10, 0, 0));
mp.Add(gp_Pnt(10, 10, 0));
mp.Add(gp_Pnt(20, 10, 0));

mp.Build();

if (mp.IsDone()) {
    TopoDS_Edge e = mp.Edge();    // Edge として
    TopoDS_Wire w = mp.Wire();    // Wire として
    TOpoDS_Shape e = mp.Shape();  // Shape として
}

ポリラインの通過点を順番に Add() していき、最後に Build() します。
点や線分や座標値を1つ、または2つ指定された瞬間にその形状が確定しますがポリラインの場合は複数の通過点によって構成されていますので、明示的に Build() を呼ばないといけません。

オマケ1: TopoDS_Shape からダウンキャストする

発生したシェイプは、とりあえず TopoDS_Shape で受け取っておいて、必要な時にダウンキャストして利用することがよくあります。

キャストと言えば、一般的にはポインタの型変換ですがOCCでは実体アドレスから特殊化する方法があります。(OCCにおけるポインタ隠蔽の仕組みについては別の機会に書きます)

TopoDS_Shape s = ...
TopAbs_ShapeEnum type = s.ShapeType()

if (type == TopAbs_Vertex) {
    TopoDS_Vertex v = TopoDS::Vertex(s);
    ...
}
else if (type == TopAbs_Edge) {
    TopoDS_Edge e = TopoDS::Edge(s);
    ...
}
else if (type == TopAbs_Wire) {
    TopoDS_Wire w = TopoDS::Wire(s);
    ...
}
...

何らかの処理によって発生した TopoDS_Shape 型の s を、その ShapeType を見てそれぞれの型に「ダウンキャスト」しています。
上の TopoDS::Vertex, Edge, Wire のほか、Face, Shell, Solid, CompSolid, Compound, Shape もそれぞれの型に対応して使うことができます。

また、これらの TopoDS_* 型は、すべて TopoDS_Shape の派生クラスになっているので、

TopoDS_Shape s = some_builder_instance.Edge();

と、親の型で受け取っても、必要に応じてダウンキャストできるので問題はありません。
これらの機能により、トポロジーレベルのオブジェクトは柔軟に扱うことができます。

オマケ2: ヘッダーファイルは?

OCCは大抵の場合、使いたいクラスの型名がそのままヘッダーファイル名になっています。
その為、「gp_Pnt」や「BRepBuilderAPI_MakeEdge」を使いたい場合は、

#include <gp_Pnt.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>

のように、拡張子「hxx」をつけて #include してあげればOKです。
もちろん、INCLUDE に OCC の inc ディレクトリが指定しておかなければなりません。

「OpenCASCADE で点、線分、ポリラインを作成する。」への2件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください