Engineering / Computers / Part 6 of 9
Traversing Assemblies & Feature Trees
Traversal is the backbone of every auditing tool worth building. Once a program can walk every component of an assembly and every feature of every component, it can answer questions that no engineer has time to answer by hand — and it can answer them the same way every time.
- Part 6 · Applied
- Recursion pattern
- Suppression states
- Audit reporting
KL-ENG-COMP-1506 · KEVOS® Knowledge Library · Australian English
Two structures matter: the component tree, which describes what an assembly is made of, and the feature tree, which describes how each piece was built. Both are walked by the same technique — obtain a starting node, process it, and hand each child back to the same routine.
01Why traversal comes before everything else
Automation that modifies models is where the visible value is. Automation that only looks is where the safe value is, and it is almost always the better first project.
It cannot break anything
A read-only tool has no failure mode that damages data. It can be run on production assemblies on the first day without a change-control conversation.
It produces evidence
"Sixty-one of four hundred parts have no material assigned" is an argument. "Our data is a bit inconsistent" is not.
It is reusable
The traversal you write for an audit is the same traversal a corrective tool will need. Building it first means the risky tool starts from proven code.
Which components carry no part number. Which are suppressed in the configuration being released. Which use a material not on the approved list. How many unique parts sit under how many instances. Which features are suppressed and in which configurations. Every one of these is a report, and every report is a candidate for a rule.
02Configuration first
You cannot ask an assembly directly for its components. You ask a configuration, because what an assembly contains depends on which configuration is active — components may be suppressed in one and resolved in another.
IConfiguration swConf = (IConfiguration)swModel.GetActiveConfiguration();
IComponent2 swRoot = (IComponent2)swConf.GetRootComponent();
if (swRoot == null) { /* not an assembly, or nothing resolved */ return; }
Walk(swRoot, 0);The root component represents the assembly itself. It is not something the user sees as a component, but it is the node whose children are the top-level components, and every traversal starts there.
An audit run against the active configuration reports on whatever the last user happened to leave selected. For a release check, iterate the configuration names deliberately and report per configuration. Stating which configuration a result belongs to is part of the result.
03The recursion pattern
One routine, calling itself. The depth argument is not required by the API — it exists so that the output can be indented, which turns a flat list into something a human recognises.
void Walk(IComponent2 component, int depth)
{
Record(component, depth); // your own reporting
object[] children = (object[])component.GetChildren();
if (children == null) return; // a leaf: a part, or nothing resolved
foreach (object child in children)
Walk((IComponent2)child, depth + 1);
}Three details make the difference between a traversal that works and one that works on real assemblies:
- Test the children for null. A part has no children, and the call returns nothing rather than an empty array. Iterating without the test fails on the first part reached.
- The same part appears many times. Traversal visits instances, not unique documents. Counting parts means collecting distinct paths; counting instances means counting visits. Decide which question you are answering.
- Suppressed branches stop. A suppressed component reports no children, so an audit that ignores suppression silently under-reports. Record the state alongside the name.
04Walking features
The feature tree is a chain rather than a nested structure: each feature knows the next one. Sub-features hang off individual features as a second chain.
IFeature feat = (IFeature)component.FirstFeature();
while (feat != null)
{
Record(feat.Name, feat.GetTypeName2());
IFeature sub = (IFeature)feat.GetFirstSubFeature();
while (sub != null)
{
Record(" " + sub.Name, sub.GetTypeName2());
sub = (IFeature)sub.GetNextSubFeature();
}
feat = (IFeature)feat.GetNextFeature();
}The same chain is walked from a document rather than a component when you are working inside a single part — the document exposes its own first feature, and the loop is otherwise identical.
A feature has a name, which the user can change and often has, and a type name, which identifies what kind of feature it is and does not change. Never make a decision on the user-visible name; a part renamed for clarity would silently change your tool's behaviour. Branch on the type name.
05Filtering what you report
A raw feature dump is unreadable. Every useful traversal filters, and the type name is how you filter.
| Goal | Filter on | Why |
|---|---|---|
| A tree a user recognises | Exclude reference geometry and origins | Planes and origins exist in every part and carry no information for the reader |
| Manufacturing review | Include material-removal and sheet-metal feature types | These are the features that determine how the part is made |
| Standards compliance | Include features whose parameters your standard constrains | Hole types, thread callouts, fillet radii |
| Rebuild health | Include anything reporting an error or warning state | Finds problems before a release rather than after |
| Library detection | Compare against known library feature type names | Distinguishes standard content from bespoke modelling |
Run an unfiltered traversal over a representative part and record every type name it produces. That list is the vocabulary your filters will use, and it is far more reliable than guessing at names. Keep it beside the tool; it also documents what the tool can and cannot see.
06Suppression states
Suppression is the most common thing an audit needs to read and the most common thing an engineer wants to change in bulk. Components and features handle it differently.
Components
A component reports a suppression state that distinguishes suppressed, resolved and lightweight. Setting the state changes it for the current configuration scope. Reading before writing lets you build a toggle rather than a one-way switch.
Features
A feature reports suppression per configuration, so the answer arrives as an array rather than a single value. Setting takes an explicit configuration scope argument — this configuration, all configurations, or a named list.
A lightweight component is loaded but not fully evaluated, and many members return incomplete information for one. An audit that treats lightweight as resolved will report missing data that is not missing at all. Either resolve components before reading them, or record the state alongside every result so the reader knows what was actually inspected.
Any tool that suppresses in bulk should first record what it found. A tool that can restore the previous state is a tool people will use; one that cannot is one they will run once and never again.
07Reporting and performance
Traversal produces data. What you do with it determines whether the tool gets used twice.
Indent to show structure
Depth is already in your recursion. Using it to indent turns a list into a tree the reader can navigate.
Export, do not just display
A results window is read once. A file — comma-separated at minimum — gets sorted, filtered and circulated.
Summarise first
Lead with counts and exceptions. The full listing belongs underneath, for the reader who disputes the summary.
Large assemblies
Traversal is fast until it is not. Four measures keep it usable:
- Read once, use many times. Collect what you need into your own structures during a single pass, rather than making repeated calls across the interop boundary for the same information.
- Do not resolve what you do not need. Resolving lightweight components to read a name is expensive. Resolve only where the data you require demands it.
- Report progress. A traversal of a large assembly takes long enough that silence will be interpreted as a hang.
- Guard the depth. A depth limit costs nothing and protects against pathological structures that would otherwise exhaust the stack.
