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.