Friday, March 13, 2009

OCAF Code is gone. Did It Worth?

How does an OpenCascade application using OCAF work? OCAF applications are MVC applications applications, where there is a storage layer (the Model) that stores the data needed to keep the entire scene. There is an OpenCascade view that displays a list of AIS_InteractiveObjects which are built directly from the OCAF data. And in between there is a NaroCad (or any other application code) code (Contoller).

We’ve decided to get rid of OCAF code.

Why?
- OCAF code is C++ code, and makes it almost impossible to debug it using the Visual Studio debugger (we debug it by displaying it visually, but we don't have other ways)
- OCAF structure forces us to work with GUIDs and makes it also very hard from C# level to extend it easily
- OCAF has no attribute for colors, or other .NET types. We stored till now as an IntegerArray attribute to the interesting nodes.
- TFunction (shape generators that make the parametric modeling working) code is really clumsy and we need to iterate over entire OCAF Tree and do a lot of things manually
- last but not least: there is no obvious way to get notified when data was changed (or its dependencies)

OCAF have nevertheless some good design decisions that we wanted to keep, as the labels (the OCAF tree nodes) are indexed by integers. This makes locating a tree path pretty fast and with minimal code. Another one is that the attributes are stored unique per node. So there cannot exist two integers under the same label.

What does the implementation bring as being C# only?
- A cleaner API:
Every node has a Children property exposed, which is a SortedDictionary (where Node is the TDF_Label replacement). This makes it clear to the user that it can iterate over the nodes.


The new code to iterate children is the following:
foreach(Node child in label.Children.Values)
{
//code using the current child node
}
- we use Generics to access the node attributes:
If we want to modify an integer value to a tree node, the code is the following
L.UpdateInterpreter().Value = (int)OcafObjectVisibility.ToBeDisplayed;
Another custom attribute that is the base of parametric modeling functions:
FunctionInterpreter function = L.UpdateInterpreter();
function.Name = "Extrude";

function.SetNode(L);
if (function.Execute() != 0)
{
// Handle the error
}

An easy way to add a custom attribute:

public class IntegerInterpreter: AttributeInterpreterBase
{
public IntegerInterpreter() : base("Integer") {}

public int Value { get ; set; }
}

And before using it, you should call AttributeDataFactory.Instance.RegisterInterpreter();
The attributes may get more complex, but this is the whole idea!

Code implications:
- in 90% the code is shorter, but in 100% the code is cleaner
- code completion and debugging works over the place
- refactor that implies 70 files
- potential problems for 2-3 days in NaroCad codebase

Note: we did replicate not only the OCAF tree storage, but also (as it was needed) the OCAF Document functionality, so if someone will want to use NaroCAD storage model, will have the entire support for doing this. This may make NaroCAD a very C# friendly CAD development platform, and for sure one step beyond the past.

No comments: