Table of Contents

Documents

OCAF (the Open CASCADE Application Framework) stores application data in a tree of labels carrying attributes, with undo, redo and files for free. XCAF is built on it.

flowchart TD
    app["TDocStd_Application<br/><i>formats, open documents</i>"] --> doc["TDocStd_Document<br/><i>undo, redo, file</i>"]
    doc --> root["0 root label"]
    root --> main["0:1 main label"]
    main --> l1["0:1:1"]
    main --> l2["0:1:2"]
    l1 --- a1(["TDataStd_Name: width"])
    l1 --- a2(["TDataStd_Real: 40.0"])
    l2 --- a3(["TDataStd_Name: part"])
    l2 --- a4(["TNaming_NamedShape: a box"])

A label is a place in the tree, named by its path of tags (its entry, 0:1:2). An attribute is data on a label, at most one per attribute class (per GUID).

Labels and attributes

// an application knows the formats; BinDrivers adds "BinOcaf", OCCT's binary format
var application = new TDocStd_Application();
BinDrivers.DefineFormat(application);

TDocStd_Document? document = null;
application.NewDocument("BinOcaf", ref document);
var main = document!.Main(); // the label 0:1

// labels form a tree of tags: FindChild(tag, true) makes the child if it's missing
var width = main.FindChild(1, true); // 0:1:1
TDataStd_Name.Set(width, "width");
TDataStd_Real.Set(width, 40.0);

var part = main.FindChild(2, true); // 0:1:2
TDataStd_Name.Set(part, "part");
new TNaming_Builder(part).Generated(new BRepPrimAPI_MakeBox(40, 20, 10).Shape());

// attributes are found by their class's GUID
TDF_Attribute? attribute = null;
var value = width.FindAttribute(TDataStd_Real.GetID(), ref attribute)
  ? TDataStd_Real.DownCast(attribute)!.Get()
  : 0;

TopoDS_Shape? shape = null;
if (part.FindAttribute(TNaming_NamedShape.GetID(), ref attribute))
{
  shape = TNaming_NamedShape.DownCast(attribute)!.Get();
}

// entries name labels as text
var entry = "";
TDF_Tool.Entry(part, ref entry); // "0:1:2"
var names = new List<string>();
for (var child = new TDF_ChildIterator(main); child.More(); child.Next())
{
  if (child.Value().FindAttribute(TDataStd_Name.GetID(), ref attribute))
  {
    names.Add(TDataStd_Name.DownCast(attribute)!.Get());
  }
}
Attribute Holds
TDataStd_Name a name
TDataStd_Integer, TDataStd_Real, TDataStd_AsciiString a value
TDataStd_IntegerArray, TDataStd_RealArray, TDataStd_ExtStringArray an array
TDataStd_TreeNode a link into a tree other than the labels'
TDataStd_UAttribute nothing: a marker, found by its GUID
TNaming_NamedShape a shape, with its history (TNaming_Builder: Generated, Modify, Delete)
TDF_Reference a link to another label

FindAttribute takes the class's GUID (TDataStd_Real.GetID()) and gives a TDF_Attribute: DownCast it. Set on a label with the attribute already there changes it.

Undo and redo

Changes between OpenCommand and CommitCommand form one undoable step:

sequenceDiagram
    participant App as your code
    participant Doc as TDocStd_Document
    App->>Doc: SetUndoLimit(10)
    App->>Doc: OpenCommand()
    App->>Doc: TDataStd_Real.Set(width, 55)
    Note over Doc: attributes back up<br/>their old values
    App->>Doc: CommitCommand()
    App->>Doc: Undo()
    Note over Doc: width is 40 again
    App->>Doc: Redo()
document.SetUndoLimit(10); // without a limit, commands record nothing

document.OpenCommand();
TDataStd_Real.Set(width, 55.0); // changes the attribute that's there
document.CommitCommand();

var before = document.GetAvailableUndos(); // 1
document.Undo();                           // width is 40 again
document.Redo();                           // and 55
document.Undo();

AbortCommand() drops the changes since OpenCommand(). With SetNestedTransactionMode(true), commands nest.

Files

var saved = application.SaveAs(document, "model.cbf"); // PCDM_SS_OK
application.Close(document); // Close, not just Dispose: OCCT keeps documents open

TDocStd_Document? opened = null;
var status = application.Open("model.cbf", ref opened); // PCDM_RS_OK
Format Drivers File
BinOcaf BinDrivers.DefineFormat(application) binary, .cbf
XmlOcaf XmlDrivers.DefineFormat(application) XML, .xml
BinXCAF BinXCAFDrivers.DefineFormat(application) binary XCAF, .xbf
XmlXCAF XmlXCAFDrivers.DefineFormat(application) XML XCAF, .xml

SaveAs and Open also take a System.IO.Stream.

Important

Close documents through their application, application.Close(document): the application holds a raw pointer to each document it opened, which only Close clears. Disposing the proxy isn't enough.