DATAKIT SDK  V2026.4
Bill Of Material

This sample demonstrates how to use the API to extract the Bill of Materials (BOM) from a CAD document.
It shows the sequence of API calls required to access the document structure, traverse the assembly hierarchy, retrieve component availability, and generate a structured BOM.

Enable readers and start Dtk_API

//*************************************************************************************
// StartAPI.cpp
// Initialises the Datakit API, enables readers, opens the input file, and
// drives the Bill of Materials extraction.
//*************************************************************************************
#include "datakit.h"
#ifdef Linux
#include <unistd.h>
#endif
// Forward declarations (see EnableReaders.cpp and ActivateApiOptions.cpp).
extern void EnableReaders();
// ---------------------------------------------------------------------------
// ProcessFile
// Opens a single CAD file and prints its Bill of Materials.
// ---------------------------------------------------------------------------
static Dtk_ErrorStatus ProcessFile(const Dtk_string &inFilePath)
{
std::cout << "Processing: " << inFilePath.c_str() << std::endl;
// Retrieve and display the file version (format-specific version string).
Dtk_string fileVersion;
Dtk_ErrorStatus err = myApi->GetFileVersion(inFilePath, fileVersion);
if( fileVersion.is_not_NULL() )
{
// Display the file version.
std::cout << "File version: " << fileVersion.c_str() << std::endl;
}
if( err != dtkNoError )
{
// Report error if unable to get file version.
std::cout << "Unable to get file version (error code: " << dtkTypeError( err ).c_str() << ")" << std::endl;
return err;
}
// Set a log file for reader diagnostics (missing sub-files, etc.).
Dtk_string logFilePath = inFilePath.filename() + Dtk_string("-bom.log");
myApi->SetLogFile(logFilePath);
// Open the document and obtain the root component.
err = myApi->OpenDocument(inFilePath, doc);
if (err != dtkNoError || doc.IsNULL())
{
std::cout << "Error: unable to open document (code: "
<< dtkTypeError(err).c_str() << ")\n";
return (err != dtkNoError) ? err : dtkErrorNullPointer;
}
// Collect the BOM entries by traversing the assembly tree.
Dtk_tab<BomEntry> bomEntries;
CreateBomForMainDoc(doc, bomEntries);
// Print the hierarchical BOM tree.
PrintBom(bomEntries);
// Print a summary of unique parts and their occurrence counts.
PrintBomSummary(bomEntries);
myApi->EndDocument( doc );
return dtkNoError;
}
// ---------------------------------------------------------------------------
// LaunchBillOfMaterialSample
// Entry point called from main(). Starts the Datakit API, processes each
// file supplied on the command line, then stops the API.
// ---------------------------------------------------------------------------
int LaunchBillOfMaterialSample(int argc, char **argv)
{
// Retrieve the current working directory (used as Datakit's working dir).
#ifndef Linux
wchar_t workingDirectory[1024];
_wgetcwd(workingDirectory, 1024);
#else
char workingDirectory[1024];
getcwd(workingDirectory, 1024);
#endif
std::cout << "Starting DATAKIT API..." << std::endl;
// Enable all required readers before starting the API.
// Start the Datakit API.
Dtk_ErrorStatus errorStatus = dtkNoError;
Dtk_API *myApi = Dtk_API::StartAPI(workingDirectory, errorStatus);
if (myApi == NULL)
{
std::cout << "Error: cannot start DATAKIT API (code: " << errorStatus << ")" << std::endl;
return errorStatus;
}
std::cout << "DATAKIT API started successfully." << std::endl;
// Process each input file provided on the command line.
int returnCode = 0;
for (int i = 1; i < argc; ++i)
{
Dtk_string inputFile(argv[i]);
Dtk_ErrorStatus fileErr = ProcessFile(inputFile);
if (fileErr != dtkNoError)
returnCode = static_cast<int>(fileErr);
}
// Stop the Datakit API and release all resources.
Dtk_API::StopAPI( myApi );
std::cout << std::endl << "DATAKIT API stopped." << std::endl;
return returnCode;
}

Traverse main document and dump Bill of Materials

//*************************************************************************************
// BillOfMaterial.cpp
// Implements Bill of Materials traversal of a Datakit assembly tree.
//
// The traversal walks the component tree depth-first:
// - InstanceComponentType : records the instance and recurses into its prototype.
// - PrototypeComponentType : records the part and recurses into its children.
// - CatalogComponentType : only the activated children are traversed; if none
// are activated the default child is used instead.
// - VirtualComponentType : transparent container – all children are traversed.
//*************************************************************************************
#include "datakit.h"
#include <iostream>
#include <map>
#include <string>
// ---------------------------------------------------------------------------
// CreateBomForMainDoc
// Creates a Bill of Materials for the given Dtk_MainDoc.
// ---------------------------------------------------------------------------
void CreateBomForMainDoc( Dtk_MainDocPtr inMainDoc, Dtk_tab<BomEntry> &outBomEntries )
{
Dtk_ComponentPtr rootComponent = inMainDoc->RootComponent();
if( rootComponent.IsNULL() )
{
std::cout << "Warning: document has no root component." << std::endl;
}
else
{
TraverseBom( rootComponent, outBomEntries, 0 );
}
}
// ---------------------------------------------------------------------------
// TraverseBom
// Recursively walks the Datakit component tree and appends a BomEntry for
// every instance/prototype pair encountered.
// ---------------------------------------------------------------------------
void TraverseBom(Dtk_ComponentPtr inComponent, Dtk_tab<BomEntry> &outBomEntries, Dtk_Int32 inDepth)
{
if (inComponent.IsNULL())
return;
Dtk_Component::ComponentTypeEnum type = inComponent->ComponentType();
{
// An instance holds a placement (transformation) and references a prototype.
Dtk_string instanceName = inComponent->InstanceName();
// The prototype is the first (and only) child of an instance.
if (inComponent->GetNumChildren() > 0)
{
Dtk_ComponentPtr prototype = inComponent->GetChild(0);
if (prototype.IsNotNULL())
{
BomEntry entry;
entry.partName = prototype->Name();
entry.instanceName = instanceName;
entry.depth = inDepth;
entry.occurrenceCount = 1;
entry.isMissing = prototype->IsAvailabilityFlaggedAs(Dtk_Component::ComponentMissing) == DTK_TRUE;
outBomEntries.push_back(entry);
// Only recurse into the prototype's children if it is not missing.
if (!entry.isMissing)
TraverseBom(prototype, outBomEntries, inDepth + 1);
}
}
}
{
// A prototype may have sub-components (instances of sub-parts).
Dtk_Size_t numChildren = inComponent->GetNumChildren();
for (Dtk_Size_t i = 0; i < numChildren; ++i)
{
TraverseBom(inComponent->GetChild(i), outBomEntries, inDepth);
}
}
{
// A catalog holds multiple alternative configurations.
// Only the activated children contribute to the BOM; if none are activated
// the default child is used.
Dtk_Size_t numChildren = inComponent->GetNumChildren();
if (numChildren > 0)
{
Dtk_tab<Dtk_Int32> activatedIndices = inComponent->GetActivatedChildrenInCatalog();
if (activatedIndices.size() > 0)
{
for (Dtk_Size_t i = 0; i < activatedIndices.size(); ++i)
{
TraverseBom(inComponent->GetChild(activatedIndices[i]), outBomEntries, inDepth);
}
}
else
{
// Fall back to the default child.
Dtk_Int32 defaultIndex = inComponent->GetDefaultChildInCatalog();
if (defaultIndex >= 0 && static_cast<Dtk_Size_t>(defaultIndex) < numChildren)
{
TraverseBom(inComponent->GetChild(defaultIndex), outBomEntries, inDepth);
}
}
}
}
{
// A virtual component is a transparent grouping node with no geometry of
// its own. Traverse all its children without adding a BOM entry.
Dtk_Size_t numChildren = inComponent->GetNumChildren();
for (Dtk_Size_t i = 0; i < numChildren; ++i)
{
TraverseBom(inComponent->GetChild(i), outBomEntries, inDepth);
}
}
}
// ---------------------------------------------------------------------------
// PrintBom
// Prints the BOM as an ASCII tree, e.g.:
//
// Assembly
// |-- SubAssembly
// | |-- PartA
// | |-- PartB
// |-- PartC
// ---------------------------------------------------------------------------
void PrintBom(const Dtk_tab<BomEntry> &inBomEntries)
{
std::cout << std::endl;
std::cout << "Bill of Materials" << std::endl;
std::cout << "-----------------" << std::endl;
if (inBomEntries.size() == 0)
{
std::cout << " (no components found)" << std::endl;
return;
}
for (Dtk_Size_t i = 0; i < inBomEntries.size(); ++i)
{
const BomEntry &entry = inBomEntries[i];
const Dtk_Int32 depth = entry.depth;
// Build the prefix: one "| " per ancestor level, then "|-- " for the branch.
std::string prefix;
for (Dtk_Int32 d = 0; d < depth - 1; ++d)
prefix += "| ";
if (depth > 0)
prefix += "|-- ";
std::cout << prefix;
// Print instance name if available.
if (entry.instanceName.is_not_NULL() && entry.instanceName.len() > 0)
std::cout << "[" << entry.instanceName.c_str() << "] -> ";
std::cout << entry.partName.c_str();
// Append availability tags.
if (entry.isMissing)
std::cout << " [MISSING]";
std::cout << std::endl;
}
}
// ---------------------------------------------------------------------------
// PrintBomSummary
// Counts how many times each unique part name appears in the BOM and prints
// a summary table sorted by part name.
// ---------------------------------------------------------------------------
void PrintBomSummary(const Dtk_tab<BomEntry> &inBomEntries)
{
std::cout << std::endl;
std::cout << "Summary (flattened occurrence count)" << std::endl;
std::cout << "------------------------------------" << std::endl;
if (inBomEntries.size() == 0)
{
std::cout << " (no components found)" << std::endl;
return;
}
// Accumulate per part name: occurrence count and availability flags.
std::map<std::string, int> countMap;
std::map<std::string, bool> missingMap;
for (Dtk_Size_t i = 0; i < inBomEntries.size(); ++i)
{
const BomEntry &entry = inBomEntries[i];
std::string key = entry.partName.is_not_NULL() ? entry.partName.c_str() : "(unnamed)";
countMap[key]++;
if (entry.isMissing)
missingMap[key] = true;
}
// Print the table header.
std::cout << " Part Name | Count | Status" << std::endl;
std::cout << " ---------------------------------- | ----- | --------------------" << std::endl;
for (std::map<std::string, int>::const_iterator it = countMap.begin();
it != countMap.end(); ++it)
{
const std::string &key = it->first;
// Left-align the part name in a 34-character field.
std::string name = key;
if (name.size() > 34)
name = name.substr(0, 31) + "...";
std::cout << " ";
std::cout << name;
for (size_t pad = name.size(); pad < 34; ++pad)
std::cout << ' ';
// Count column (5 chars wide).
std::cout << " | ";
std::string countStr = std::to_string(it->second);
for (size_t pad = countStr.size(); pad < 5; ++pad)
std::cout << ' ';
std::cout << countStr;
// Status column.
std::cout << " | ";
bool hasMissing = missingMap.count(key) > 0;
if (hasMissing )
std::cout << " [MISSING]";
std::cout << std::endl;
}
std::cout << std::endl;
}
Dtk_API::EndDocument
Dtk_ErrorStatus EndDocument(Dtk_MainDocPtr &inoutDocument)
Close a Document.
TraverseBom
void TraverseBom(Dtk_ComponentPtr inComponent, Dtk_tab< BomEntry > &outBomEntries, Dtk_Int32 inDepth)
Definition: BillOfMaterial.cpp:43
Dtk_Component::CatalogComponentType
@ CatalogComponentType
Definition: dtk_maindoc.hpp:575
BomEntry::depth
Dtk_Int32 depth
Definition: BillOfMaterial.hpp:15
Dtk_SmartPtr::IsNotNULL
Dtk_bool IsNotNULL() const
Definition: util_ptr_dtk.hpp:119
DTK_TRUE
#define DTK_TRUE
Definition: define.h:726
Dtk_API::StartAPI
static Dtk_API * StartAPI(const Dtk_string &inTemporyDirectory, Dtk_ErrorStatus &outErrorCode, const Dtk_string &inCustomerID=Dtk_string())
Start DATAKIT API.
Dtk_string
This is a high level string class.
Definition: dtk_string.hpp:53
Dtk_Size_t
size_t Dtk_Size_t
Definition: define.h:711
BomEntry::isMissing
bool isMissing
Definition: BillOfMaterial.hpp:17
Dtk_API::OpenDocument
Dtk_ErrorStatus OpenDocument(const Dtk_string &inInputFile, Dtk_MainDocPtr &outDocument)
Open a Document (call EndDocument to close it)
ProcessFile
static Dtk_ErrorStatus ProcessFile(const Dtk_string &inFilePath)
Definition: BomStartAPI.cpp:21
Dtk_Component::VirtualComponentType
@ VirtualComponentType
Definition: dtk_maindoc.hpp:576
BillOfMaterial.hpp
Dtk_Component::InstanceComponentType
@ InstanceComponentType
Definition: dtk_maindoc.hpp:573
Dtk_string::is_not_NULL
Dtk_bool is_not_NULL() const
Dtk_API::GetAPI
static Dtk_API * GetAPI()
Get DATAKIT API.
Dtk_string::filename
Dtk_string filename() const
File Utility : Retrieves the filename in Dtk_string form.
Dtk_Int32
int32_t Dtk_Int32
Definition: define.h:686
BomEntry::occurrenceCount
Dtk_Int32 occurrenceCount
Definition: BillOfMaterial.hpp:16
Dtk_Component::ComponentTypeEnum
ComponentTypeEnum
Definition: dtk_maindoc.hpp:572
Dtk_ErrorStatus
Dtk_ErrorStatus
Definition: error_dtk.hpp:6
Dtk_SmartPtr::IsNULL
Dtk_bool IsNULL() const
Definition: util_ptr_dtk.hpp:118
Dtk_SmartPtr
Definition: util_ptr_dtk.hpp:37
dtkTypeError
Dtk_string dtkTypeError(Dtk_Int32 errNumero)
LaunchBillOfMaterialSample
int LaunchBillOfMaterialSample(int argc, char **argv)
Definition: BomStartAPI.cpp:77
Dtk_string::c_str
const char * c_str() const
Retrieve the ASCII conversion string.
PrintBomSummary
void PrintBomSummary(const Dtk_tab< BomEntry > &inBomEntries)
Definition: BillOfMaterial.cpp:178
EnableReaders
void EnableReaders()
Definition: LibReadersSample/RunThroughAPI/GetStarted/EnableReaders.cpp:12
datakit.h
Dtk_tab
This is a high level array class.
Definition: util_stl_dtk.hpp:84
Dtk_tab::size
Dtk_Size_t size() const
Returns the size of the array.
Definition: util_stl_dtk.hpp:503
Dtk_API::StopAPI
static void StopAPI(Dtk_API *&inAPI, Dtk_bool inWriteTimeInLog=1)
Stop DATAKIT API.
BomEntry
Definition: BillOfMaterial.hpp:12
BomEntry::partName
Dtk_string partName
Definition: BillOfMaterial.hpp:13
Dtk_Component::PrototypeComponentType
@ PrototypeComponentType
Definition: dtk_maindoc.hpp:574
Dtk_Component::ComponentMissing
@ ComponentMissing
Definition: dtk_maindoc.hpp:562
Dtk_string::len
int len() const
Retrieve the length of the Dtk_string.
Dtk_API::GetFileVersion
Dtk_ErrorStatus GetFileVersion(const Dtk_string &inInputFile, Dtk_string &outVersion)
Independant method to get version of inInputFile.
dtkNoError
@ dtkNoError
Definition: error_dtk.hpp:151
Dtk_tab::push_back
void push_back(const T &x)
Inserts an element at the end of the array.
Definition: util_stl_dtk.hpp:416
CreateBomForMainDoc
void CreateBomForMainDoc(Dtk_MainDocPtr inMainDoc, Dtk_tab< BomEntry > &outBomEntries)
Definition: BillOfMaterial.cpp:24
Dtk_API::SetLogFile
Dtk_ErrorStatus SetLogFile(const Dtk_string &inLogFile)
Set Log File.
BomEntry::instanceName
Dtk_string instanceName
Definition: BillOfMaterial.hpp:14
dtkErrorNullPointer
@ dtkErrorNullPointer
Definition: error_dtk.hpp:23
PrintBom
void PrintBom(const Dtk_tab< BomEntry > &inBomEntries)
Definition: BillOfMaterial.cpp:133
Dtk_API
Definition: dtk_api.hpp:75