3. Print Structure
This tutorial guides you through the basics of creating a console application with HOOPS Exchange. By the end of this tutorial, you will have a solid understanding of the technology, allowing you to seamlessly integrate HOOPS Exchange into your own applications.
The completed project will load a specified input file and print the assembly structure to stdout
.
Prerequisites
Refer to the Environment Setup Guide for detailed instructions.
To start development, make sure you have the following:
CMake: If not installed, download and install it from here.
Source Code: Access the complete source code for this project on GitHub. Download and unzip it to your preferred location.
Once you have CMake and the source code:
Run CMake.
Set the source directory to the path of the extracted folder.
Specify the binary directory path for project file generation.
Click the Generate button.
Your project is now configured and ready for compilation and execution.
After successfully building and compiling the project, run the generated application. The standard output should display something similar to the following:
Product1
HOUSING(HOUSING.1)
MechanicalTool.1
CYLINDER LINER(CYLINDER LINER.1)
MechanicalTool.1
HOUSING TOP(HOUSING TOP.1)
MechanicalTool.1
MOBILE PART(MOBILE PART.1)
PUSH ROD(PUSH ROD.1)
MechanicalTool.1
BEARING PR DW(BEARING PR DW.1)
MechanicalTool.1
BEARING PR UP(BEARING PR UP.1)
MechanicalTool.1
AXE(AXE.1)
MechanicalTool.1
PISTON(PISTON.1)
...
The sample is divided into two parts:
As the main point of this tutorial, we will start with the latter. Then we will load a model file and connect to our traversal function.
Traversing the Model File
The simplest way to navigate through our model file is to use the traversal API that abstracts away the complexity of a model file by using standard tree-structure terminology.
The entire traversal is done in a recursive function that is first called on the root node of our model tree:
void traverse_tree(A3DTree* const hnd_tree, A3DTreeNode* const hnd_node, size_t depth) {
// Display node's name...
// Recursively call traverse_tree on child nodes...
}
The depth
parameter is only used to provide the indentation while displaying each node name.
Display Nodes’ Name
To get the name of a node, use A3DTreeNodeGetName()
.
The function fills in a C-string that needs to be freed when the data isn’t used any longer:
The code for displaying the name looks like this:
std::cout << std::string(2 * depth, ' '); // Print indent
A3DUTF8Char* node_name = 0;
if (A3DTreeNodeGetName(hnd_node, &node_name) == A3D_SUCCESS && node_name != 0) {
std::cout << node_name << std::endl;
A3DTreeNodeGetName(0, &node_name);
}
Recursively Visit Child Nodes
Going deeper into the model tree is done by calling A3DTreeNodeGetChildren()
.
This function gets the child nodes of the currently visited one.
For there, we loop through the list of child nodes and call traverse_tree
on each of them:
// Recursively call traverse_tree on child nodes
A3DUns32 n_child_nodes = 0;
A3DTreeNode** child_nodes = 0;
if(A3DTreeNodeGetChildren(hnd_tree, hnd_node, &n_child_nodes, &child_nodes) == A3D_SUCCESS) {
for (A3DUns32 n = 0 ; n < n_child_nodes ; ++n) {
traverse_tree(hnd_tree, child_nodes[n], depth+1);
}
A3DTreeNodeGetChildren(0, 0, &n_child_nodes, &child_nodes);
}
Loading the Model File
Now that we know how to recursively traverse our model tree, let’s load a file and instantiate the root A3DTreeNode
on which we make our first call of traverse_tree()
.
In the main()
function, the model file is loaded through the A3DSDKHOOPSExchangeLoader
helper class.
At the end of the call, model_file
contains a valid handle to your loaded CAD file:
A3DSDKHOOPSExchangeLoader he_loader(HE_BINARY_DIRECTORY);
A3DImport he_import(HE_DATA_DIRECTORY INPUT_FILE);
he_loader.Import(he_import);
A3DAsmModelFile* model_file = he_loader.m_psModelFile;
Then, we use A3DTreeCompute()
to generate the tree structure out of model_file
, and A3DTreeGetRootNode()
to obtain the root node.
Finally, we call traverse_tree()
, that will start the traversal:
// Get the model tree
A3DTree* hnd_tree = 0;
A3DTreeCompute(model_file, &hnd_tree, 0);
// Get the root node
A3DTreeNode* hnd_root_node = 0;
A3DTreeGetRootNode(hnd_tree, &hnd_root_node);
// Run the traversal
traverse_tree(hnd_tree, hnd_root_node, 0);
// Release model tree memory
A3DTreeCompute(0, &hnd_tree, 0);
The Full Code
Here is a full working example of the Print Assembly Structure sample.
#define INITIALIZE_A3D_API
#include <A3DSDKIncludes.h>
#include <iostream>
#include <string>
#include <cassert>
//////////////////////////////////////////////////////////////////////
/// INPUT_FILE
/// Default CAD input file, relative to Exchange sample data folder.
/// To see how the value is used, check the `main()` function.
#define INPUT_FILE "/prc/_micro engine.prc"
void traverse_tree(A3DTree* const hnd_tree, A3DTreeNode* const hnd_node, size_t depth) {
// Display node's entity name
std::cout << std::string(2 * depth, ' '); // Print indent
A3DUTF8Char* node_name = 0;
if (A3DTreeNodeGetName(hnd_node, &node_name) == A3D_SUCCESS && node_name != 0) {
std::cout << node_name << std::endl;
A3DTreeNodeGetName(0, &node_name);
} else {
std::cout << "N/A" << std::endl;
}
// Recursively call traverse_tree on child nodes
A3DUns32 n_child_nodes = 0;
A3DTreeNode** child_nodes = 0;
if(A3DTreeNodeGetChildren(hnd_tree, hnd_node, &n_child_nodes, &child_nodes) == A3D_SUCCESS) {
for (A3DUns32 n = 0 ; n < n_child_nodes ; ++n) {
traverse_tree(hnd_tree, child_nodes[n], depth+1);
}
A3DTreeNodeGetChildren(0, 0, &n_child_nodes, &child_nodes);
}
}
int main(int argc, char* argv[]) {
///////////////////////////////////////////////////////////
// INITIALIZE HOOPS EXCHANGE AND LOAD THE MODEL FILE
A3DSDKHOOPSExchangeLoader he_loader(HE_BINARY_DIRECTORY);
assert(he_loader.m_eSDKStatus == A3D_SUCCESS);
A3DImport he_import(HE_DATA_DIRECTORY INPUT_FILE);
A3DStatus status = he_loader.Import(he_import);
assert(status == A3D_SUCCESS);
A3DAsmModelFile* model_file = he_loader.m_psModelFile;
////////////////////////////////////////////////////////////
// TRAVERSE THE MODEL TREE
A3DTree* hnd_tree = 0;
status = A3DTreeCompute(model_file, &hnd_tree, 0);
assert(status == A3D_SUCCESS);
A3DTreeNode* hnd_root_node = 0;
status = A3DTreeGetRootNode(hnd_tree, &hnd_root_node);
assert(status == A3D_SUCCESS);
traverse_tree(hnd_tree, hnd_root_node, 0);
A3DTreeCompute(0, &hnd_tree, 0);
/////////////////////////////////////////////////////////////
// Everything is loaded to GPU; Exchange can be released.
A3DAsmModelFileDelete(model_file);
A3DDllTerminate();
A3DSDKUnloadLibrary();
return EXIT_SUCCESS;
}
The code is also available on GitHub.
Now that you have learned how to traverse a model file using A3DTree
and A3DTreeNode
, you can dive into a more complete example: Write a CAD Viewer.