AcmCLeaderNodeIterator
provides functionality for interacting
with the internal structure of a leader. Each leader can contain many nodes
(or no nodes). These nodes are connected to each other and provide a tree-like
structure. In most cases, the connection between nodes is simple and looks
like an array of points along which lines are successively drawn. But there
may be complicated cases when every main point has branches, which can look
like a tree branch with leaves. AcmCLeaderNodeIterator
was
created to interact with each node separately regardless of the complexity of
the tree. The iterator allows you to add new nodes, delete current nodes,
search for a parent branch, get the coordinates of a node, find the number of
branches, and so on.
To use AcmCLeaderNodeIterator
functionality, include the
following file:
#include "AcmCLeaderNodeIterator.h"
To get an iterator from a mechanical symbol, you also need to include the following files:
#include "AcmCLeader.h"
#include "AcmSurfaceTexture.h" // In your case it can be any other mechanical symbol
Below is sample code for creating and obtaining an iterator from a mechanical
symbol AcmSurfaceTexture
(the code is similar for other
mechanical symbols).
Note: PartList
,
PartRef
, HoleChart
and SectionSym
objects do not have leader support.
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);
As a result, a simple AcmSurfaceTexture
entity is created:
To move to the next node, use the iterator method step()
. This
method also allows you to step back if the iterator has previous nodes. To go
one node back, set the incoming parameter for the step()
method
as true.
If you need to get the coordinates of the current node, call the
vertex()
method. If you want to set a new position for the
current node, use the setVertex()
method.
Note: The counting of nodes starts in the
logical order of distance from the symbol, not in the order that the points
were added to the array when calling the addLeader()
method from
the AcmSymbol
-derived class. Below is a picture of vertex
numbering (also considered a node) and vertex coordinates.
To move to different nodes and change the coordinates for the second node, see the following code, which also gets the coordinates of all nodes and finds out how many branches belong to the current node.
// 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)
After these manipulations, the symbol leader looks like:
To create a new leader segment (set of nodes) associated with the current
node, use the iterator method addLeader()
.
Note: After adding a new segment, the iterator
is not moved to the last-added node and remains at the current position. After
adding a new segment, the number of branches departing from the current node
increases. This can be checked using the numOfBranches()
method.
// 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
After adding a new segment, the symbol leader looks like:
To create a new leader iterator for iterating the leader segment connected to
this node, use the newNodeIterator()
method. As an input
parameter, specify the index of the segment you want to walk through. Select a
newly created segment as an example; its index is 1. This is because a new
branch is added to the end of the array and previously there was already one
branch in the array.
You can also use the isLeafNode()
method to find out if this
node is the last one and a leaf. This method can be called not only from the
iterator for the new segment but also from the main iterator.
// 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
You can move to the next node and check whether it is a leaf. You can also
change the coordinates of the vertex using the transformBy()
method.
pNewSegIt->step();
isLeaf = pNewSegIt->isLeafNode(); // result: true
OdGeMatrix3d mtrx;
mtrx.setToScaling(1.2);
pNewSegIt->transformBy(mtrx);
After these manipulations, the symbol leader looks like:
To return the iterator to the previous node, in addition to the
step()
method you can also use the parent()
method.
The parent()
method is more relevant because if you initialize an
iterator with only leaf elements, the step back sets the iterator to the
previous node in the iterator nodes array instead of the parent element, which
may not be in the array at all. If the iterator moves successfully to the
parent node, true
is returned as the result.
// Set iterator to the parent node
pNewSegIt->parent(); // result: true
To add a new node before the current one, use the insertBefore()
method. As an input parameter, pass the point with coordinates in which the
new node is created. If the current node has no parent or the iterator is not
initialized, Acm::eBad
is returned as the result.
// 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
After inserting a new node, the symbol leader looks like:
To remove one of the nodes, use the remove()
method. For
example, assume the current node is named the node to which the iterator
points. Therefore, the remove()
method merges the next node after
the current one with the previous node from the current one and removes the
current node. It will look as if the current node is thrown out of the chain,
but the chain does not break and is rebuilt.
// Remove the node to which the iterator is pointing now
pNewSegIt->remove();
After deleting one of the nodes, the leader symbol looks like:
Instead of removing only one node, you can call the trim()
method to completely cut off all branches including the current node to which
the iterator points. In this case the iterator moves to the previous node and
all other nodes disappear. This method performs the same actions as the
removeLeader()
method.
After performing several actions with the iterators, update the data in the
main iterator by initializing it again so you can reach the node you need. To
make the deletion more visual, first add one more node, and then call the
trim()
method.
// 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
The figures below show how the leader looks after adding a new node (left) and after trimming (right):
To find a leader node, use one of the three iterator methods:
virtual Acm::ErrorStatus find(const OdGePoint3d& pt, bool fromTipPoint = true) = 0;
fromTipPoint
as true
(by default), the search is performed from the first node, regardless of
where the iterator currently points. If you specify
fromTipPoint
as false
, the search is carried out
on the nodes that remain in the iterator array starting from the current
node.
virtual Acm::ErrorStatus findClosest(const OdGePoint3d& pt) = 0;
virtual Acm::ErrorStatus findByGrip(int indice) = 0;
For all three methods, a result different from Acm::eOk
is
returned in the case of failure.
AcmCLeaderNodeIterator
has the following methods for working
with geometry:
virtual Acm::ErrorStatus attachGeomRef(const void* pGeometry, const OdDbObjectId& viewId, OdGePoint3d& prevLocation, bool hasReactor = false) = 0;
attachGeomRef()
method for the heirs of the
AcmSymbol
class (for details see the Mechanical Examples
located in the <INSTALL_DIR>/Mechanical/Examples
directory, where <INSTALL_DIR>
is a directory where you
unpacked the Mechanical SDK archive).
virtual Acm::ErrorStatus detachGeomRef() = 0;
virtual void releaseGeomRef() = 0;
There are also three methods used to get information about the status of current attachments:
virtual OdDbObjectId viewId() const = 0;
virtual bool isAttachedNoView() const = 0;
virtual bool isAttachedToView(OdDbObjectId& viewId) const = 0;
Copyright © 2002 – 2022. Open Design Alliance. All rights reserved.
|