概要
AcmCLeaderNodeIteratorは、リーダーの内部構造と対話するための機能を提供します。各リーダーは多数のノード(またはノードなし)を含むことができます。これらのノードは互いに接続されており、ツリーのような構造を提供します。ほとんどの場合、ノード間の接続は単純で、線が連続して描画される点配列のように見えます。しかし、すべての主要な点に枝があり、葉を持つ木の枝のように見える複雑なケースもあります。AcmCLeaderNodeIteratorは、ツリーの複雑さに関係なく、各ノードと個別にやり取りするために作成されました。このイテレータを使用すると、新しいノードの追加、現在のノードの削除、親ブランチの検索、ノードの座標の取得、ブランチ数の検索などを行うことができます。
リーダーの作成
AcmCLeaderNodeIterator機能を使用するには、次のファイルを含めます。
#include "AcmCLeaderNodeIterator.h"
メカニカルシンボルからイテレータを取得するには、次のファイルもインクルードする必要があります。
#include "AcmCLeader.h"
#include "AcmSurfaceTexture.h" // In your case it can be any other mechanical symbol
以下は、メカニカルシンボルAcmSurfaceTextureからイテレータを作成および取得するためのサンプルコードです(他のメカニカルシンボルでも同様のコードです)。
注: PartList、PartRef、HoleChart、およびSectionSymオブジェクトはリーダーをサポートしていません。
OdDbDatabasePtr pDb = ... // get database
// Create and initialize symbol data. If something is wrong, such as a symbol or
// symbol standard is not supported by the current standard, a code other than
// Acm::eOk will be returned.
AcmSurfaceTexturePtr pSymb = AcmSurfaceTexture::createObject();
if (pSymb->setSymbolDefaults(pDb) != Acm::eOk)
return;
// Add points to array and call the addLeader() method for leader creation
OdGePoint3dArray points;
points.setLogicalLength(3);
points[0].set(10.0, 30.0, 0.0);
points[1].set(50.0, 60.0, 0.0);
points[2].set(70.0, 65.0, 0.0);
// Acm::eOk will be returned if the leader for the symbol was successfully created
if (pSymb->addLeader(points) != Acm::eOk)
return;
// Get leader. Since we have added only one leader, its index will be 0
AcmCLeader* pLeader = pSymb->getLeader(0);
if (!pLeader)
return;
// Get leader iterator
AcmCLeaderNodeIteratorPtr pIt = pLeader->newNodeIterator();
if (pIt.isNull())
return;
// Next step is iterator data initialization.
// This method will collect all nodes or only leafs of tree structure depending
// on how the input flag is set. By default, it collects all nodes.
pIt->start(false);
// To make sure that the iterator has been initialized correctly and the leader
// contains at least one node, call the done() iterator method. In the future,
// this method can be used to check if all nodes have been walked through.
if (pIt->done())
return;
// Get and open ModelSpace blockRecord
OdDbBlockTableRecordPtr pMSpace =
OdDbBlockTableRecord::cast(pDb->getModelSpaceId().openObject(OdDb::kForWrite));
if (pMSpace.isNull())
return;
// Now we can add AcmSurfaceTexture to the ModelSpace in order to look at the
// result of entity creation
pMSpace->appendOdDbEntity(pSymb);
その結果、シンプルなAcmSurfaceTextureエンティティが作成されます。
リーダーの変更
次のノードに移動するには、イテレータメソッド step() を使用します。このメソッドは、イテレータに前のノードがある場合、ステップバックすることもできます。1つ前のノードに戻るには、step() メソッドの入力パラメータを true に設定します。
現在のノードの座標を取得する必要がある場合は、vertex() メソッドを呼び出します。現在のノードの新しい位置を設定したい場合は、setVertex() メソッドを使用します。
注: ノードのカウントは、AcmSymbol 派生クラスから addLeader() メソッドを呼び出したときにポイントが配列に追加された順序ではなく、シンボルからの距離の論理的な順序で開始されます。以下は、頂点番号付け (ノードとも見なされます) と頂点座標の図です。
異なるノードに移動し、2番目のノードの座標を変更するには、以下のコードを参照してください。このコードは、すべてのノードの座標を取得し、現在のノードに属するブランチの数も調べます。
// Get the number of branches spun off from the current node
int branchesOfNode1 = pIt->numOfBranches(); // result: 1
// Get node coordinates
OdGePoint3d point1 = pIt->vertex(); // result: 70.0 65.0 0.0
// Step to the next node
pIt->step();
int branchesOfNode2 = pIt->numOfBranches(); // result: 1
OdGePoint3d point2 = pIt->vertex(); // result: 50.0 60.0 0.0
pIt->step();
int branchesOfNode3 = pIt->numOfBranches(); // result: 0 (because it's the last node)
OdGePoint3d point3 = pIt->vertex(); // result: 10.0 30.0 0.0
// Step backward and change vertex of second node
pIt->step(true);
pIt->setVertex(OdGePoint3d(40.0, 40.0, 0.0));
point2 = pIt->vertex(); // result: 40.0 40.0 0.0 (coordinates were updated)
これらの操作の後、シンボルリーダーは次のようになります。
リーダーセグメントの操作
現在のノードに関連付けられた新しいリーダーセグメント (ノードのセット) を作成するには、イテレータメソッド addLeader() を使用します。
注: 新しいセグメントを追加した後、イテレータは最後に追加されたノードに移動せず、現在の位置に留まります。新しいセグメントを追加した後、現在のノードから分岐するブランチの数が増加します。これは numOfBranches() メソッドを使用して確認できます。
// Add a new leader segment based on points from input array
OdGePoint3dArray pointsForNewNodes;
pointsForNewNodes.setLogicalLength(2);
pointsForNewNodes[0].set(25.0, 45.0, 0.0);
pointsForNewNodes[1].set(15.0, 45.0, 0.0);
pIt->addLeader(pointsForNewNodes);
// Get coordinates for the current node
OdGePoint3d currentVertex = pIt->vertex(); // result: 40.0 40.0 0.0
// Count of branches will increase after adding a new segment
int branchesCount = pIt->numOfBranches(); // result: 2
新しいセグメントを追加した後、シンボルリーダーは次のようになります。
このノードに接続されたリーダーセグメントを反復処理するための新しいリーダーイテレータを作成するには、newNodeIterator() メソッドを使用します。入力パラメータとして、走査したいセグメントのインデックスを指定します。例として新しく作成されたセグメントを選択します。そのインデックスは1です。これは、新しいブランチが配列の末尾に追加され、以前に配列内にすでに1つのブランチがあったためです。
isLeafNode() メソッドを使用して、このノードが最後のノードであり、リーフであるかどうかを調べることもできます。このメソッドは、新しいセグメントのイテレータからだけでなく、メインイテレータからも呼び出すことができます。
// Create a new iterator for the new leader segment
AcmCLeaderNodeIteratorPtr pNewSegIt = pIt->newNodeIterator(1);
if (pNewSegIt.isNull())
return;
// Initialize the new iterator and check if it contains data or not
pNewSegIt->start();
if (pNewSegIt->done())
return;
// Check if the current node is a leaf
bool isLeaf = pNewSegIt->isLeafNode(); // result: false
次のノードに移動して、それがリーフであるかどうかを確認できます。transformBy() メソッドを使用して、頂点の座標を変更することもできます。
pNewSegIt->step();
isLeaf = pNewSegIt->isLeafNode(); // result: true
OdGeMatrix3d mtrx;
mtrx.setToScaling(1.2);
pNewSegIt->transformBy(mtrx);
これらの操作の後、シンボルリーダーは次のようになります。
ノードの操作
イテレータを前のノードに戻すには、step() メソッドに加えて parent() メソッドも使用できます。parent() メソッドはより適切です。なぜなら、リーフ要素のみでイテレータを初期化した場合、ステップバックはイテレータをイテレータノード配列内の前のノードに設定し、配列に存在しない可能性のある親要素には設定しないためです。イテレータが親ノードに正常に移動した場合、結果として true が返されます。
// Set iterator to the parent node
pNewSegIt->parent(); // result: true
ノードの追加
現在のノードの前に新しいノードを追加するには、insertBefore() メソッドを使用します。入力パラメータとして、新しいノードが作成される座標を持つ点を渡します。現在のノードに親がない場合、またはイテレータが初期化されていない場合、結果として Acm::eBad が返されます。
// Insert a new node in front of the node that the iterator is currently pointing at
Acm::ErrorStatus es = pNewSegIt->insertBefore(OdGePoint3d(32.0, 48.0, 0.0)); // result: Acm::eOk
新しいノードを挿入した後、シンボルリーダーは次のようになります。
ノードの削除
ノードの1つを削除するには、remove() メソッドを使用します。たとえば、現在のノードがイテレータが指すノードであると仮定します。したがって、remove() メソッドは、現在のノードの次のノードを現在のノードの前のノードと結合し、現在のノードを削除します。現在のノードがチェーンから投げ出されたように見えますが、チェーンは切断されず、再構築されます。
// Remove the node to which the iterator is pointing now
pNewSegIt->remove();
ノードの1つを削除した後、リーダーシンボルは次のようになります。
1つのノードだけを削除する代わりに、trim() メソッドを呼び出して、イテレータが指す現在のノードを含むすべてのブランチを完全に切り離すことができます。この場合、イテレータは前のノードに移動し、他のすべてのノードは消滅します。このメソッドは removeLeader() メソッドと同じ動作を実行します。
イテレータでいくつかの操作を実行した後、必要なノードに到達できるように、メインイテレータのデータを再度初期化して更新します。削除をより視覚的にするために、まずノードをもう1つ追加し、次に trim() メソッドを呼び出します。
// Update data in the iterator after calls of different methods
pIt->start(); // set the iterator to the first node
pIt->step(); // move the iterator pointer to the second node where forking is present
pIt->insertBefore(OdGePoint3d(60.0, 62.5, 0.0)); // insert a new node
pIt->trim(); // cut off all next leader segments starting from the current
下の図は、新しいノードを追加した後(左)とトリミングした後(右)のリーダーの様子を示しています。
ノードを検索
リーダーノードを検索するには、次の3つのイテレータメソッドのいずれかを使用します。
- virtual Acm::ErrorStatus find(const OdGePoint3d& pt, bool fromTipPoint = true) = 0;
指定された点に基づいて検索し、検索を開始する場所を指定できます。fromTipPointをtrue(デフォルト)に指定すると、イテレータが現在指している場所に関係なく、最初のノードから検索が実行されます。fromTipPointをfalseに指定すると、現在のノードから始まるイテレータ配列に残っているノードに対して検索が実行されます。 - virtual Acm::ErrorStatus findClosest(const OdGePoint3d& pt) = 0;
最も近い点を検索します。検索は、現在のノードに依存するノードで実行されます。点が見つかった場合、イテレータポインタはその点に設定されます。 - virtual Acm::ErrorStatus findByGrip(int indice) = 0;
グリップインデックスを使用してノードを検索し、イテレータポインタを見つかったノードに設定します。
これら3つのメソッドすべてにおいて、失敗した場合はAcm::eOkとは異なる結果が返されます。
ノードジオメトリの操作
AcmCLeaderNodeIteratorには、ジオメトリを操作するための次のメソッドがあります。
- virtual Acm::ErrorStatus attachGeomRef(const void* pGeometry, const OdDbObjectId& viewId, OdGePoint3d& prevLocation, bool hasReactor = false) = 0;
ジオメトリをノードにアタッチします。このメソッドは、AcmSymbolクラスの子孫に対するattachGeomRef()メソッドと同じアプローチを必要とします(詳細については、/Mechanical/ExamplesディレクトリにあるMechanical Examplesを参照してください。ここで、<INSTALL_DIR>はMechanical SDKアーカイブを解凍したディレクトリです)。 - virtual Acm::ErrorStatus detachGeomRef() = 0;
ジオメトリが存在する場合、現在のノードからジオメトリをデタッチします。 - virtual void releaseGeomRef() = 0;
ジオメトリの解放を実行します。
アタッチメントのステータスを取得
現在のアタッチメントのステータスに関する情報を取得するために使用される3つのメソッドもあります。
- virtual OdDbObjectId viewId() const = 0;
ノードが関連付けられているビューのIDを取得します。 - virtual bool isAttachedNoView() const = 0;
ノードがビューに接続されていないかどうかを確認します。 - virtual bool isAttachedToView(OdDbObjectId& viewId) const = 0;
ノードがビューに接続されているかどうかを確認します。