I'm wondering why don't use OCAF in NaroCAD
In the OCC forum (http://www.opencascade.org/org/forum/thread_16794/) you wrote: "The OCAF like layer is rewritten in C# for maintenance reasons as is pretty hard to work with two debuggers, one to debug C++ OpenCascade code and the other side the C#"
Could you be so kind to give me more details about you decision ?
NaroCAD as architecture it has two code parts: one that is OpenCascade/C++ code, and some managed code (namely the .NET/C# code).
The OCAF tree in OpenCascade is made like this: there is a defined integer-indexed tree structure (the integer usage is for strength reduction, meaning faster operations on trees like seaching, managing, etc.) and inside there is a list of GUID based attributes. In this way, by adding a new GUID "type" you can attach an extra attribute to a node that consist on extra data.
When you are in a .NET world, the wrapped OCAF stops from debugging point of view just as pointers to GUIDs, but not as internal data that the attribute express.
For example imagine that you add an extra attribute named Density, that will be attached to any volumetric shape. If you debug from Visual C++ code, as an OCAF attribute you may expand the pointer to the attribute and you will see if density was setup or not, if there is a specific bug that the density is always setup to 0.0 When I will do it in OCAF mode this pointer is meaningless and the GUIDs like identification does not help much.
How NaroCAD did it better by rewriting it?
- the attribute names are reflection/namespace based names. In internal logic of NaroCAD when you debug a tree node, you will see the Density like attribute
- it is generic based. If you defined your custom attribute you have to register it once (the registering is just to know how to save/restore from file) and you can write to any node somelike this: node.Set<DensityInterpreter>().Value = 30.0;
You should remark that node.Set<DensityInterpreter>() will return an instance of DensityInterpreter so the .Value have the meaning in the DensityInterpreter context. Is static typing but have somelike dynamic language feeling, to say so. The API is practically minimalist and makes sense using generics more than playing around with GUIDs. For example:
var interpreter = node.Get<DensityInterpreter>();
This code tests if node have attached Density values to the node, and later if the node have one, will offer it so you can use it as the right type. No GUIDs, or no reflection full name is needed. Everything is transparent for user.
- working with nodes is also easy, instead of writing somelike node.Find(newId, true), you can write directly node that creates automatically the node. This to be done, would need using another class just to wrap this behavior from C# point of view making hard to operate with
- the latest important feature is propagation. Propagation in OCAF (as much as I've understand it) is done by visiting the entire scene and mark gradually the values that were affected. The design in NaroCAD is much simpler, and is based on events/delegates. Every attribute that changes can call the OnModify method and propagation will make it automatically. On top of this the "Function" code just wrap it in a also generic way this features. In fact functions just simply creates nodes and connect to notify events of the child nodes. If you will take the NodeBuilder class, it will also wrap the Function's mechanisms to be also transparent to user
The implementation of both children of any node and attribute indexing is done by using the SortedDictionary generic class, meaning in short that the adding, remove or locating one node is O(log n) (it's somehow amortized if you balance right your tree: node for example is log(firstLevelOfTree)*log(secondLevelOfTree)). The visiting of all items is O(n) or O(1) for item. This will guarantee that will likely work enough fast for most propagation scenarios that affect a lot of shapes values without adding them. The performance for adding items is still good anyway, but adding 10.000 items at once may be slow(er) but it will be O(logn*n) for all items, so may be for an unbalanced tree, just some seconds.
So at the end the advantages of using a OCAF C# rewritten version adds clarity, speed guarantees, debugging, propagation, generics. At the end the whole Node class that I've was talking about have 375 lines, which is fairly tested code, which may be interesting to be used elsewhere. For this reason we used it for saving the options parameters or the "capabilities" code meaning to link sematic relations between items that NaroCAD store.
thank you vey much for your long & detailed reply.
Pls correct me if I'm wrong but a NaroCAD document couldn't be used with XDE, right ?
Inside the "General Definitions" of XDE I found this entry: "To read and write attributes such as names, colors, layers for IGES and STEP and validation properties and structure of assemblies for STEP, you can use an XDE document". Looking at your code inside ExportToStep I can see that you are exporting only Shapes but you don't export attributes such as names, colors, layers. Am I wrong ?
Yes. you're right. But some attributes as colors and layers are stored in NaroXML file. If you know how to extend the code to add the extra attributes in both ways (import and export) as they mostly exist (I'm not sure about layers part, but I'm sure that shape name and color, transparency are there), I'll be really happy to assist you how to write a patch or to make it to work just right.