Shape integer attribute using ocaf

All I want to be able to do is identify each shape (the ones you'd get using maps on the whole compound that makes up your model) with a permanent ID with this in mind.

now how do you do this with OCAF ? I've given up on the idea of doing it without OCAF because i need those IDs to be saved alongside the shapes when dumping onto disk.

i know you can save the compound as a .brep file but how do you save the shapes and the attributes stuff together. How do you actually do the attributes stuff (it looks i need to use TNaming_UsedShapes but after that, i am lost). Can i just generate maps of my solids, faces, edges, etc and assign the IDs and then be able to access the shapes directly from the IDs ?

Is there an example somewhere ? Has somebody done it and is willing to share ?

Again, i don't need anything fancy, just ONE unique integer ID per shape. I mean a shape with forward orient should have same id as shape with reverse sine it's the same physical shape.

I am about to give up on this. it's so damn difficult to do anything with OCC (it's a shame since it looks real powerful but it's about as user friendly as the registry of motor vehicles ... just kidding).

Could someone be kind enough to point me in the right direction ?

Forum supervisor's picture

Hello Ugo,

If you like to learn more about Open CASCADE Application Framework, naming of shapes and tracking history of their evolution please consider our on-site training courses such as Fundamentals course and course on Application Framework, or a complete remote training / e-learning course. You may find more information about our training offer at http://www.opencascade.org/support/training/ .

Best regards,
Forum Supervisor

Pawel's picture

Hi Ugo,

you could try something like this:

for(TopoDS_Iterator iter(Shape); iter.More(); iter.Next())
{
AssignID() //use a map/sequence whatsoever to store the shapes
//iterate recursively on iter.Value()
}

In the finction AssignID you can use a map - then you will get the id automatically as the key when you insert a shape. If you want to assign custom ids you can use something like this:

typedef NCollection_DataMap ProcessedShapesMap;
ProcessedShapesMap processedShapes;
processedShapes.Bind(component_id, iter.Value);

To store the ids and then shapes in OCAF you would probably have to do it one by one (just a guess). If you use XDE maybe XCAFDoc_ShapeMapTool would work (another guess). Again, if you use XDE you could create subshapes for shape and associate an id with each single subshape-label.

Those were some ideas I think you might want to check. However, I haven't implemented any of them in 100%.

At the moment I implement something similar using XDE and subshapes but I don't have to identify all subshapes building a shape - only some of them.

Hope this helps
Pawel

Dennis G.'s picture

Hello Ugo,

you need to prepare your programme in order to benefit from OCAF. First steps see here:
http://opencascade.blogspot.com/2008/12/adding-colors-and-names-to-your....

Did you read the "xde.pdf" in the doc folder? It might help, too.

Dennis

Ugo Capeto's picture

nobody has actual code to do it with just ocaf (no xde)?
i've read the blog post by Roman but there's gotta to be something simpler, right ?

say i have a compound, all i want is go through each solid, face, edge, vertex and give each entity a unique ID that's non transient. Of course, if 2 shapes are the same, they should have same ID (case of an edge shared by 2 faces in a solid or a face share by 2 solids).

i need a way to save to file the IDs and the .brep for the compound. I assume that's what happens when you save the document.

when i load back the document, i should have all my shapes and the IDs I defined before.

i am not good enough at ocaf and c++ to figure it out, but i am sure it's been done before.

Roman Lygin's picture

Never had to do this myself but this is what I'd do.
1. Create an indexed map of sub-shapes.
TopTools_MapOfShape aMap;
TopExp::MapShapes (aShape, aMap);
This fills out aMap in a pre-defined order (i.e. doing the same on aShape will fill out aMap the same way).

2. Assign integer ID's in whatever way is needed during run-time (e.g. using NCollection_DataMap)

For store/retrieve use OCAF:
Approach 1 - more explicit and heavy-weight.
- Create OCAF sub-tree of labels and populate with sub-shapes and attach attributes TNaming_NamedShape and TDataStd_Integer
The downside is larger file size.

Approach 2 - more compact
- Create one label and attach entire aShape (via TNaming_NamedShape) and TDataStd_IntegerArray. The latter must be populated from aMap filled out above.
- During retrieval fill out similar aMap and then NCollection_DataMap preserving order of sub-shapes and index in TDataStd_IntegerArray.

If you only need to store a map between sub-shapes and ID's the latter should work. If you may need sub-shapes for some other associations perhaps approach 1 can be used (however beware of file size overhead).

Hope this helps.
Roman

P.S. I deem decent knowledge of C++ is definitively an advantage (if not prerequisite) to work with OCC ;-).

---
opencascade.blogspot.com - the Open CASCADE blog
www.cadexchanger.com - CAD Exchanger, your 3D data translator

Ugo Capeto's picture

no kidding.
i browsed through the forum and people make reference to some sample code called sampleocaf. Where can you get it ?
Also, in the documentation, it says you have to define a class derived from TDocStd_Application and implement 2 methods : Formats() and ResourcesName() .. how on earth do you figure out what those methods should look like ?
you've gotta admit it's not too clear, right ?

Roman Lygin's picture

Sample OCAF - %CASROOT%\..\samples\standard\tutorial\mfc\10_Ocaf

Documentation:
- OCAF User's Guide (%CASROOT%\..\doc\overview\ocaf.pdf), par 4.3.3. Methods Formats() and ResourcesNames() are pure virtual and are declared in TDocStd_Application.hxx header.
Standard_EXPORT virtual Standard_CString ResourcesName() = 0;
Standard_EXPORT virtual void Formats(TColStd_SequenceOfExtendedString& Formats) = 0;

See XCAFDoc_Application.hxx and .cxx for example of their definition.

Additional doc:
- OCAF White Paper (ocaf_wp.pdf)
- OCAF Function Mechanism User's Guide/White Paper (ocaf_functionmechanism_wp.pdf)
- Distribution of data through OCAF tree White Papere (ocaf_tree_wp.pdf)

Ugo Capeto's picture

alright, i think i am finally getting it. You need a label to attach the shape and the attribute associated with the shape.

i am thinking of starting a blog to explain some of the finer points of ocaf for those that are deficient in C++. seriously.

Ugo Capeto's picture

Ok Roman,i am kinda using a combination of both approaches registering "higher-order" shapes, say, a bunch of aShape's.

Now, when I register the shape attribute for those shapes, what type of evolution should I use ? I mean i don't really care about shape history, i just want to register the shape so that it gets saved when saving the document. Do i use PRIMITIVE ?

Also, when you register the shape, i am assuming the shape and all the sub-shapes get saved at the same time as the document. Right ?

Ugo Capeto's picture

oh i see, you don't control of that registration thingy.

Is it possible to tell OCAF not to keep track of the old shape and the new shape?

Ugo Capeto's picture

yeah, the problem with registering shapes is that the document is gonna be creating labels of its own when the shapes are changed by the application (say a fuse between 2 solids).
i don't really want that, i don't want new labels to be created for every operation that involve the shapes i have registered.
again, i just want to register the shapes so that i can attach an ID to them and be able to dump them on file, so that, when i reload the model, the IDs and the shapes are there, "intact".
Can I register shapes and turn off the "evolution" mechanism that seems to go with it ?

Ugo Capeto's picture

oh boy, i keep replying to myself. sorry about that.

i think i understand now how it works. you have to create a label and tell ocaf the old shape and the new shape. it's not done automatically.

so if i have no intention of keeping track of incremental changes, is it ok to use:

TNaming_Builder builder(aLabel);

builder.Generated(aShape); to associate the shape with the label

and in case that shape gets deleted:

builder.Delete(aShape);

or replaced:

builder.Replaced(aShape,aNewShape);

that's basically all the book-keeping i need to do with ocaf.

Roman Lygin's picture

Hi Ugo,

OCAF does not update any shape history automatically for you. When you attach a shape to a label and do not update its history, OCAF will simply dump those original shape into the file regardless what you did with the shape in your application. (Of course, due to explicit sharing subshapes may experience some modifications - e.g. tolerance change - after modeling operations, but topology structure will remain).

Roman
---
opencascade.blogspot.com - the Open CASCADE blog
www.cadexchanger.com - CAD Exchanger, your 3D data translator

tmacedo29's picture

Hi Roman,

it's a great approuch! But if instead of use an integer ID, I'd like to use a string name. What could I use instead of TDataStd_IntegerArray?

Thank You in Advance
Regards,

Roman Lygin's picture

I think TDataStd_ExtStringArray can be used as an equivalent.
Roman

---
opencascade.blogspot.com - the Open CASCADE blog
www.cadexchanger.com - CAD Exchanger, your 3D data translator

tmacedo29's picture

Hi Roman,

thank you very much for your answer.

Thank you again!
Regards

Ugo Capeto's picture

alright, a few more questions:

i've created a child label below root and registered a shape like so:
TNaming_Builder builder(label);
builder.Generated(aShape);
then i save the ocaf file.

now, after i close the doc and reload it:
given the label above, how do i get back aShape?

was i supposed to create a named shape prior to saving the ocaf file ?

slightly confused.
again, i don't care about the evolution, i just want to retrieve the shape i registered.
thanks in advance.

Ugo Capeto's picture

ok, i am gonna answer my own question .. let me know if it's wrong:

Handle(TNaming_NamedShape) NS = new TNaming_NamedShape();
aLabel.FindAttribute(TNaming_NamedShape::GetID(),NS);
aShape = NS->Get();

Ugo Capeto's picture

while i am at it, might well ask how you retrieve an integer attribute.

given aLabel,
Handle(TDataStd_Integer) INT=new TDataStd_Integer();
aLabel.AddAttribute(INT);
INT->Set(aVal);

Given aLabel, how do you retrieve the integer aVal?

Ugo Capeto's picture

ok, i am gonna answer my own question .. let me know if it's wrong:

Handle(TDataStd_Integer) INT = new TDataStd_Integer();
aLabel.FindAttribute(TDataStd_Integer::GetID(),INT);
aValue = INT->Get();

Now, given aValue (integer), do i need to visit all the labels to get the proper one?

Roman Lygin's picture

Ugo,
Approach 1 (individual labels containing a shape and an integer) already supposes that you have a shape and integer GUI attached to the same label.
So:
Handle(TNaming_NamedShape) NS;
aLabel.FindAttribute(TNaming_NamedShape::GetID(),NS);
aShape = NS->Get();
Handle(TDataStd_Integer) INT;
aLabel.FindAttribute(TDataStd_Integer::GetID(),INT);
aValue = INT->Get();
aMap.Bind (aShape, aValue);

Note that you do not need to initialize a handle with new before calling FindAttribute(). The latter will return its value anyway.

Ugo Capeto's picture

ok cool, thanks a lot.
Now, say I want to "de-register" the shape currently associated with the label (and possibly register a new shape instead for that label),
do I use aLabel.Forget(TNaming_NamedShape::GetID()); ?