AMCAX Kernel 1.0.0.0
Loading...
Searching...
No Matches
A STEP File Reading And Writing Example

Overview

This tutorial introduces the basic usage of AMCAX STEP Reader and AMCAX STEP Writer.

Prerequisites

Developers should have the following background knowledge:

  • Modern C++ programming (C++17 or later)
  • 3D geometric modeling
  • B-Rep topology structure

The AMCAX kernel and STEPReader / STEPWriter are developed in C++17, making extensive use of STL containers and algorithms.

Import Section

Include headers

Represents a product in the STEP standard with geometry and style information.
Class for translating STEP files into TopoShape objects, with support for styles.

Currently, the STEP module provides 3 types of Reader variants:

  • STEPReader: basic version, only supports translating a STEP file into TopoShape.
  • STEPStyledReader: supports reading more complete data (recommended).
  • STEPLabelReader: supports additional annotation information.

This tutorial will use STEPStyledReader for demonstration.

Create a Reader object

Reader does not provide static functions; all operations are performed through class instances. You can pass a std::istream, such as cin, ifstream, etc. The Reader does not manage its lifecycle.

std::ifstream ifs("/path/to/input.STEP", std::ios::binary);
if (!ifs.is_open()) {
return 1;
}
Class for translating STEP files into TopoShape objects, with support for styles.
Definition STEPStyledReader.hpp:34

You can also pass a file path directly:

AMCAX::STEP::STEPStyledReader reader("/path/to/input.STEP");

(Optional) Set units

Since the kernel has no concept of units, units in imported data need to be handled via Reader by applying scaling. By default, 1 millimeter is assumed. You can disable scaling or change units with:

reader.SetTargetUnit(AMCAX::STEP::STEPLengthUnit::Presets::NOSCALE);

After parsing, you can obtain the original file’s unit via STEPStyledReader::GetUnit() or STEPStyledProduct::Factors().

(Optional) Set progress reporting

A callback function can be used to receive progress updates:

reader.SetProgressCallback(
std::cout << " State: " << int(state) << std::endl;
if (c2.type == AMCAX::STEP::STEPProgressMessage::U64_TYPE && c2.payload.u64) {
std::cout << " Message1: " << c1.payload.u64 << std::endl;
std::cout << " Message2: " << c2.payload.u64 << std::endl;
}
});
Encapsulates a specific state value in the STEP process (reader or writer).
Definition STEPProgress.hpp:56
Message object used to report progress values in the STEP process.
Definition STEPProgress.hpp:18
@ U64_TYPE
Payload contains uint64_t.
Definition STEPProgress.hpp:30

Message1 indicates the processed shape index, Message2 indicates the total shape count. In multithreaded scenarios, Message1 may not be sequential.

Read file

Although the Reader object opens the file upon construction, reading and translation actually begin only when reader::Read() is called.

bool topo_success = reader.Read();

Read() is blocking until parsing finishes, returning false on failure. When initialized with std::istream, the stream must remain valid during parsing.

(Optional) Event callback

You can provide a STEPDataCallback to receive intermediate results during parsing:

bool topo_success = reader.Read([&reader](AMCAX::STEP::DataEvent e,
const std::shared_ptr<AMCAX::STEP::STEPStyledProduct>& p,
size_t rep_idx) {
switch (e) {
case AMCAX::STEP::DataEvent::ProductReady:
// This event means the Product tree is assembled.
// You can access nodes via reader.GetProducts().
// ProductName, Description, Location, Target, Children, and related APIs are usable.
// Product nodes containing shapes will be initialized with placeholder data here.
// After this event, reader only accesses nodes via pointers,
// so it is also safe to std::move(reader.GetProducts()) here.
break;
case AMCAX::STEP::DataEvent::ShapeReady:
// A shape has been prepared.
// Access via p->ShapeAt(rep_idx), properties via p->PropertyAt(rep_idx).
// p->FactorAt(rep_idx) and p->ShapeRepresentationAt(rep_idx) are also available.
// You need to manually traverse reader.GetProducts() (including subtrees)
// to compute final Location.
break;
case AMCAX::STEP::DataEvent::LabelReady:
// Only triggered by STEPLabelReader.
// Indicates a shape and property data (AMCAXAF Label format) are ready.
// Use p->LabelAt(rep_idx) to access.
// For the same TopoShape, LabelReady follows ShapeReady,
// with matching p and rep_idx parameters.
break;
default:;
}
// IMPORTANT! STEP allows reuse of Products.
// In this module, it’s represented by "Shadow" nodes.
// Shadow nodes contain only Location, no shape/label data,
// so ShapeReady / LabelReady events are not triggered for them.
// After Read() returns, traverse all IsShadow() nodes in reader.GetProducts() (including subtrees).
});

Note: The callback runs in the parser thread; heavy logic may reduce performance.

Prepare result container

std::vector<std::shared_ptr<AMCAX::STEP::STEPStyledProduct>> products;

For the simpler STEPReader or STEPLabelReader (with AMCAXAF::Label), there are corresponding STEPProduct or STEPLabelProduct types.

Retrieve results

products = std::move(reader.GetProducts());

products contains multiple STEPStyledProduct, each corresponding to a Product entity in the STEP file.

Shadow nodes

Shadow nodes only contain translation/rotation information, checkable with IsShadow():

using ProductPtr = std::shared_ptr<STEPStyledProduct>;
void ConvertToNormal(ProductPtr& root) {
if (root->IsShadow()) {
root->MarkNormal();
}
for (size_t i = 0; i < root->ChildrenSize(); ++i) {
ConvertToNormal(root->ChildAt(i));
}
}

(Optional) Flatten tree structure

If only the position of each Topology Shape matters and assembly hierarchy is irrelevant, STEPTool provides functions to flatten the hierarchy into a 1-D array.

// or
auto flat = AMCAX::STEP::STEPTool::Flatten(products);
Utility class for operations on STEP shape data structures.
static AMCAX_API std::vector< std::shared_ptr< STEPProduct > > Flatten(const std::vector< std::shared_ptr< STEPProduct > > &shapes, bool unrolling=true)
Create a flattened, one-dimensional copy of a STEPProduct tree.
static AMCAX_API std::vector< std::shared_ptr< STEPProduct > > & FlattenInplace(std::vector< std::shared_ptr< STEPProduct > > &shapes, bool unrolling=true)
Flatten a STEPProduct tree into a one-dimensional array, in place.

Get sub-shape properties

auto treeroot = products[0];
AMCAX::TopoShape compound = treeroot->ShapeAt(0);
const auto& props = treeroot->PropertyAt(0);
for (AMCAX::TopoExplorer exp(compound, AMCAX::ShapeType::Solid);
exp.More(); exp.Next())
{
auto solid = exp.Current();
auto it = props.find(solid);
if (it != props.end()) {
const AMCAX::STEP::ShapeProperty& property = it->second;
const ShapeRGBA& color = property.GetColor();
if (color) {
/* Use color information */
}
}
}
Represents a property attached to a STEP entity (e.g., name, style, visibility).
Definition ShapeProperty.hpp:27
Class of a tool for exploring the B-Rep structure.
Definition TopoExplorer.hpp:14
AMCAX_API bool More() const noexcept
Does the explorer have more shapes.
Base class of shape, containing an underlying shape with a location and an orientation.
Definition TopoShape.hpp:15

Extract overall TopoShape

Use OneShape() or STEPTool::MakeCompound() to obtain a complete TopoShape:

for (auto node : reader.GetProducts()) {
// A Compound of all shapes in node->Shapes().
// If ShapesSize() == 1, returns the single shape directly.
TopoShape s1 = node->OneShape(false);
// Same as above, but also includes shapes in node->Children().
TopoShape s2 = node->OneShape(true);
}
// A STEP file may contain multiple Product trees.
// This merges them into one Compound.
TopoShape all = AMCAX::STEP::STEPTool::MakeCompound(reader.GetProducts());
static AMCAX_API AMCAX::TopoShape MakeCompound(const std::shared_ptr< STEPProduct > &root)
Create a TopoShape by combining all shapes in a STEPProduct tree.

Export Section

Include header

Class for exporting TopoShape objects and related data to STEP files.

Unlike Reader, the Writer is not split into variants; all types of Products can be written directly.

Create Writer object

AMCAX::STEP::STEPWriter writer("/path/to/output.STEP");
Class for exporting TopoShape objects and related data to STEP files.
Definition STEPWriter.hpp:34

Or using an output stream:

std::ofstream ofs("/path/to/output.STEP");

(Optional) Set units

Although STEPWriter does not rescale data, since the kernel has no unit concept, you must manually specify what units to write in the STEP file. Default is 1 millimeter.

writer.SetOutputUnit(AMCAX::STEP::STEPLengthUnit::Presets::CENTIMETRE);

(Optional) Set progress callback

Like Reader, Writer provides a two-parameter progress callback:

writer.SetProgressCallback(
{
std::cout << " State: " << int(state) << std::endl;
if (c2.type == AMCAX::STEP::STEPProgressMessage::U64_TYPE && c2.payload.u64) {
std::cout << " Message1: " << c1.payload.u64 << std::endl;
std::cout << " Message2: " << c2.payload.u64 << std::endl;
}
});

Export Product or TopoShape

Export individually:

for (auto& p : products) {
writer.WriteShape(p);
}
for (auto& s : std::vector{ TopoShape{} }) {
writer.WriteShape(s);
}

Or export an entire array at once:

writer.WriteShapes(products);

Since the Writer always favors maintaining the tree structure of Products, both ways produce the same output structure.

Export Label

STEP format allows attaching custom attributes to shapes. The kernel uses the Label format for property data.

// initialize root
writer.WriteShape(root);
The class of Label.
Definition Label.hpp:27

Finalize export

After exporting, it is recommended to call the following to append the STEP file footer and close the file:

writer.Done();

If the user does not explicitly call Done(), STEPWriter’s destructor ensures the same operation is performed.

Simplified interface

If you only need the final Topology Shape, you can use simplified methods in STEPTool:

AMCAX::STEP::STEPTool::Read(shape, "/path/to/input.STEP");
if (!shape.IsNull()) {
AMCAX::STEP::STEPTool::Write(shape, "/path/to/output.STEP");
}
static AMCAX_API bool Write(const AMCAX::TopoShape &s, std::ostream &os)
Write a TopoShape to a stream in STEP format.
static AMCAX_API bool Read(AMCAX::TopoShape &s, std::istream &is)
Read a TopoShape from a stream in STEP format.
AMCAX_API bool IsNull() const noexcept
Is the shape null.

Click here example01 to download the complete Reader source code as example01.

Appendix Example

#include <iostream>
void printProductName(const std::shared_ptr<AMCAX::STEP::STEPStyledProduct>& node, int indent = 0)
{
for (int i = 0; i < indent; ++i) {
std::cout << "| ";
if (node->IsShadow()) {
std::cout << "SHADOW: " << node->ProductName() << std::endl;
}
else {
std::cout << node->ProductName() << std::endl;
for (auto& child : node->Children()) {
printProductName(child, indent + 1);
}
}
}
}
void printSolidName(const std::shared_ptr<AMCAX::STEP::STEPStyledProduct>& node, int indent = 0)
{
for (size_t i = 0; i < node->ShapesSize(); ++i)
{
const auto& origShape = node->ShapeAt(i);
const auto& props = node->PropertyAt(i);
for (AMCAX::TopoExplorer SolidExp(origShape, AMCAX::ShapeType::Solid);
SolidExp.More(); SolidExp.Next())
{
const auto& solid = SolidExp.Current();
auto it = props.find(solid);
if (it != props.end() && it->second.NameHasValue())
{
std::string name = it->second.Name();
std::cout << '\"' << name << '\"' << std::endl;
}
}
}
for (auto& child : node->Children())
{
printSolidName(child, indent + 1);
}
}
int main()
{
std::vector<std::shared_ptr<AMCAX::STEP::STEPStyledProduct>> products;
AMCAX::STEP::STEPStyledReader reader("./data/bed214T.step");
reader.SetTargetUnit(AMCAX::STEP::STEPLengthUnit::Presets::METRE);
bool topo_success = reader.Read();
if (!topo_success) return -1;
products = reader.GetProducts();
for (auto root : products)
{
printProductName(root);
printSolidName(root);
}
// Extract overall shape
// Flatten tree into 1-D array
AMCAX::STEP::STEPWriter writer("./output.step");
writer.SetOutputUnit(AMCAX::STEP::STEPLengthUnit::Presets::METRE);
writer.WriteShapes(products);
writer.Done();
}
Class of a tool for exploring the B-Rep structure.
Class of iterator for B-Rep structure.