Naming a shape

Hi everyone, I would like to get some help from from you guys.
I would like to know how to name a shape that I have drawn so that I could get the attributes of the shape from just the name.
I would be greatful if anyone can help on that.

Regards

Jérome Dufaure's picture

hello
To name your shape you have to use OCAF document
On each label of your document you can attach a name attribute and a shape attribute for example.
When you explore your document you can get the name of each shape in the document.
For more details you can read the OCAF documentation
good luck
jerome

clchang78's picture

Hi again, sorry to trouble u guys, need some help from u guys again.
My aim is to name a shape that I have drawn so that I could get the attributes of the shape from just the name. At the same time, I can still retreive the data by double clicking the shape(then press the retrieve button). So how shld I name the tree, what I have done is as follow, but in this case, the name is not unique and has no meaning to it. Can somebody please help..

TDF_Label TOccCAD_Commands::CreateSphere(Standard_Real x, Standard_Real y, Standard_Real z, Standard_Real r, const TCollection_ExtendedString& Name)
{
// A data structure for our Sphere:
// the Sphere itself is attached to the SphereLabel label (as his name and his function attribute)
// its arguments (dimensions: radius ; and position: x, y, z)
// are attached to the child labels of the Sphere:
//
// 0:1 Sphere Label ---> Name ---> Named shape ---> Function
// |
// 0:1:1 -- Radius Label
// |
// 0:1:2 -- X Label
// |
// 0:1:3 -- Y Label
// |
// 0:1:4 -- Z Label

// Create a new label in the data structure for the Sphere
TDF_Label L = TDF_TagSource::NewChild(MainLab);

// Create the data structure : Set the dimensions, position and name attributes
TDataStd_Real::Set(L.FindChild(1), r);
TDataStd_Real::Set(L.FindChild(2), x);
TDataStd_Real::Set(L.FindChild(3), y);
TDataStd_Real::Set(L.FindChild(4), z);
TDataStd_Name::Set(L, Name);

// Instanciate a TOccCADFunction_SphereDriver and add it to the TFunction_DriverTable
Handle(TOccCADFunction_SphereDriver) mySphereDriver = new TOccCADFunction_SphereDriver();
TFunction_DriverTable::Get()->AddDriver(Standard_GUID("SphereDriver"), mySphereDriver);
// Instanciate a TFunction_Function attribute connected to the current Sphere driver
// and attach it to the data structure as an attribute of the Sphere Label
Handle(TFunction_Function) myFunction = TFunction_Function::Set(L,Standard_GUID("SphereDriver"));

// Initialize and execute the Sphere driver (look at the "Execute()" code)
TFunction_Logbook log;
mySphereDriver->Init(L);
if (mySphereDriver->Execute(log)) MessageBox(0,"DFunction_Execute : failed","Sphere",MB_ICONERROR);

return L;
}

Serge's picture

Hi,

The simplest way to identify an object in the TDF datastructure is by its label. You can easily convert
a TDF_Label to TCollection_AsciiString and later to
char*.

Example:

TDF_Label aLabel;
//Finding a label somehow..
//Let it now be 0:1:1:12

TCollection_AsciiString anEntry;
TDF_Tool::Entry(aLabel, anEntry);
//Now anEntry contains string "0:1:1:12"

//To convert it to char*
char* aC_Entry = anEntry.ToCString();

//To convert an entry to TDF_Label
Handle(TDocStd_Document) aDoc = ...;
TDF_Label aNewLabel;

TDF_Tool::Label(aDoc->GetData(), anEntry, aNewLabel);

//Now aNewLabel is 0:1:1:12

The entry can be used as a key in a map to bind to it
some more userfriendly name.

Hope this will help.

Jérome Dufaure's picture

hello
If you wnat to retrieve the shape attributes from the name of the shape you can do this:
for(TDF_ChildIterator it(RootLabel, Standard_False); it.More(); it.Next())
{

Handle(TDataStd_Name) Nametofind= new TDataStd_Name();
it.Value().FindAttribute(TDataStd_Name::GetID(), Nametofind);
if(Nametofind->Get()==YourName)
{
do something with your shape
}
}
jerome

clchang78's picture

Hi, thanks for replying to my message on the forum.
I read your message, I have some queries (I am pretty new in OCC).
In your case what would be the father is it the shape??
is the tree as follows..
Shape--> Name --> Attributes
eg 0:1 0:1:1 0:1:1:12

If so, in the case I have a couple of shapes, do I do something as follows...
Shape(Rectangle)--> Name --> Attributes
eg 0:1 0:1:1 0:1:1:12
Shape(Cylinder)--> Name --> Attributes
eg 0:2 0:2:1 0:2:1:12

One more thing, if I were to name the name a level higher than the attributes, how do I label it

TDF_Label L =TDF_TagSource::NewChild(MainLab);

// Create the data structure : Set the radius and name attributes

//I tried this, it doesn't work

TDF_Label L2 =leveL2.FindChild(MainLab, Standard_true);
TDataStd_Real::Set(leveL2.FindChild(12), r);

Sorry to ask so many questions, really appreciate if you can help me on this.
Thanks in advance

Serge's picture

Hi,

I'm not quite understood your questions but taking as an example your own structure:

// 0:1 Sphere Label ---> Name ---> Named shape ---> Function
// |
// 0:1:1 -- Radius Label
// |
// 0:1:2 -- X Label
// |
// 0:1:3 -- Y Label
// |
// 0:1:4 -- Z Label

Here is a father is label 0:1 and its direct children are 4 labels 0:1:1 - 0:1:4.

So the name to refer the Shape could be string "0:1" and the name of the radius is "0:1:1". Of course, on GUI level it's preferable to use more friendly name and use the string like "0:1" only in your code.

Concerning the second question, what is in your code
"MainLab"?
Signature of method TDF_TagSource::NewChild(const TDF_Label& theLabel) and TDF_Label.FindChild(const Standard_Integer, const Standard_Boolean = Standard_True).

Regards

clchang78's picture

Hi, THis is Bryan. I referred to ur posting on the forum however I still have some minor problems, hope you can help.
This is how I code my TDF command..
--------------------------------------------------------------------------------

TDF_Label TOccCAD_Commands::CreateSphere(Standard_Real x, Standard_Real y, Standard_Real z, Standard_Real r, const TCollection_ExtendedString& Name)
{

// Create a new label in the data structure for the Sphere
TDF_Label Sphere = TDF_TagSource::NewChild(MainLab);
Handle(TDataStd_Name) NameAttrib1 = new TDataStd_Name();

// Create the data structure : Set the dimensions, position and name attributes
TDataStd_Real::Set(Sphere.FindChild(1), r);
TDataStd_Real::Set(Sphere.FindChild(2), x);
TDataStd_Real::Set(Sphere.FindChild(3), y);
TDataStd_Real::Set(Sphere.FindChild(4), z);
NameAttrib1->Set(Name);
Sphere.AddAttribute(NameAttrib1);

// Instanciate a TOccCADFunction_SphereDriver and add it to the TFunction_DriverTable
Handle(TOccCADFunction_SphereDriver) mySphereDriver = new TOccCADFunction_SphereDriver();
TFunction_DriverTable::Get()->AddDriver(Standard_GUID("SphereDriver"), mySphereDriver);
// Instanciate a TFunction_Function attribute connected to the current Sphere driver
// and attach it to the data structure as an attribute of the Sphere Label
Handle(TFunction_Function) myFunction = TFunction_Function::Set(Sphere,Standard_GUID("SphereDriver"));

// Initialize and execute the Sphere driver (look at the "Execute()" code)
TFunction_Logbook log;
mySphereDriver->Init(Sphere);
if (mySphereDriver->Execute(log)) MessageBox(0,"DFunction_Execute : failed","Sphere",MB_ICONERROR);

return Sphere;
}

--------------------------------------------------------------------------------

Is there any problem in how I define my name of the spheres?
--------------------------------------------------------------------------------

Another problem is, I tried to draw a box based on the positions of a sphere(I tried doing it but have not figured out how so what I did was I will create a box if there is a shape named "RefName")..I did the followings
--------------------------------------------------------------------------------

void COccCADDoc::OnDrawBox()
{
CDefineBoxDlg Dlg;
if(Dlg.DoModal()!=IDOK) return;
Handle(TDocStd_Document) D = GetOcafDoc();

TDF_Label LabSat = myOcafDoc->Main();

D->NewCommand();
TOccCAD_Commands TSC(D->Main());

for (TDF_ChildIterator it(LabSat); it.More(); it.Next())
{
Handle(TDataStd_Name) Nametofind = new TDataStd_Name();
if(it.Value().FindAttribute(TDataStd_Name::GetID(), Nametofind))continue;
if(Nametofind->Get()=="RefName") ;

TCollection_AsciiString Name((Standard_CString)(LPCTSTR)Dlg.m_Name);

// Create a new box using the CNewBoxDlg Dialog parameters as attributes
TDF_Label Box=TSC.CreateBox(Dlg.m_x, Dlg.m_y, Dlg.m_z, Dlg.m_w, Dlg.m_l, Dlg.m_h, TCollection_ExtendedString(Name));

// Get the TPrsStd_AISPresentation of the new box TNaming_NamedShape
Handle(TPrsStd_AISPresentation) prs= TPrsStd_AISPresentation::Set(Box, TNaming_NamedShape::GetID());

// Display it
prs->SetColor(Quantity_NOC_YELLOW);
prs->Display(1);
Fit3DViews();
// Attach an integer attribute to Box to memorize it's displayed
TDataStd_Integer::Set(Box, 1);
myAISContext->UpdateCurrentViewer();

// Close the command (for undo)
D->CommitCommand();
}
}

I have the following problem when i tried to run, even after I have defined a shape named "RefName" , the box still does not come out, I am wondering if I have wrongly defined the root, the root I used is LabSat (where TDF_Label LabSat = myOcafDoc->Main(); & TPrsStd_AISViewer::New(myOcafDoc->Main(),myViewer))
Please advise on this, another thing is, how do I specifically call out just the coordinates of the shape "RefName" and not other attributes
I hope I have made my questions clear enough.
Thanks for taking your time to read this message

Jérome Dufaure's picture

Hello bryan
for me the name of the shape is an attribute of a label.

TDF_Label FirstComponent= TDF_TagSource::NewChild(MainLabel);
Handle(TDataStd_Shape) ShapeAttrib1= new TDataStd_Shape();
Handle(TDataStd_Name) NameAttrib1= new TDataStd_Name();

//attach the shape to the label FirstComponent
ShapeAttrib1->Set(FirstComponent, yourShape1);
//attach the name to the label
NameAttrib1->Set(YourName);
FirstComponent.AddAttribute(NameAttrib1);

For other components:
TDF_Label SecondComponent= TDF_TagSource::NewChild(MainLabel);
Handle(TDataStd_Shape) ShapeAttrib2= new TDataStd_Shape();
Handle(TDataStd_Name) NameAttrib2= new TDataStd_Name();

//attach the shape to the label SecondComponent
ShapeAttrib2->Set(secondComponent, yourShape2);
//attach the name to the label
NameAttrib2->Set(YourName2);
SecondComponent.AddAttribute(NameAttrib2);

My tree is as follow:
0:1 Main Label
0:1:1 First label with shape attribute and name attribute
0:1:2 Second label with shape attribute and name attribute
........
........
0:1:n

If you want to store information like radius and position of the center of a sphere you can use TDataStd_RealArray and attach it to the label like this:
Handle(TDataStd_RealArray) ArrayAttribute= new TDataStd_RealArray();
FirstComponent.AddAttribute(ArrayAttribute);

I hope this will help you
jerome

clchang78's picture

Hi Serge, I refer to your mail where you stated
"Q2. Make sure that your driver set the TNaming_NamedShape attribute on the same
label to which you put the attribute TPrsStd_AISPresentation."

I have no idea how to check it, can you give me specific examples on what to change based on SampleOcaf as mine is actually a slight modification of SampleOcaf.
Thanks

Serge's picture

Hi Bryan,
I don't know so well SampleOcaf to use it as a source
of examples, but you can check a presence of the attribute TNaming_NamedShape using the following code just before you call method Display of the attribute TPrsStd_AISPresentation (but after calling a method Execute of the Box driver):

if(Box.IsAttribute(TNaming_NamedShape::GetID())) {
//The attribute NamedShape exists on the label "Box" and AISPresentation will be able to display it
}
else {
//There is no NamedShape so nothing to display
}

Regards,
Serge

clchang78's picture

Hi Serge, I followed what you said but I still have the problem of not being able to display the shape that I want even when there is another shape named "RefName".I am wondering whether I should put my put my retrieve attributes statement in my spacedriver.cxx file or whether I should do it in the classes( right now I put the retrieve statement in class CSampleOcafDoc)

This is my new void for the space(rectangular shape)

void CSampleOcafDoc::OnDrawspace()
{
CDefineSpaceDlg Dlg;
if(Dlg.DoModal()!=IDOK) return;
Handle(TDocStd_Document) D = GetOcafDoc();

TDF_Label LabSat = myOcafDoc->Main();
for (TDF_ChildIterator it(LabSat); it.More(); it.Next())
{
Handle(TDataStd_Name) Nametofind = new TDataStd_Name();
if(LabSat.FindAttribute(TDataStd_Name::GetID(),Nametofind))
if(Nametofind->Get()=="RefName")
{
D->NewCommand();
TOccCAD_Commands TSC(D->Main());

TCollection_AsciiString Name((Standard_CString)(LPCTSTR)Dlg.m_Name);

// Create a new box using the CNewBoxDlg Dialog parameters as attributes
TDF_Label L=TSC.CreateSpace(Dlg.m_x, Dlg.m_y, Dlg.m_z, Dlg.m_w, Dlg.m_l, Dlg.m_h, TCollection_ExtendedString(Name));

// Get the TPrsStd_AISPresentation of the new box TNaming_NamedShape
Handle(TPrsStd_AISPresentation) prs= TPrsStd_AISPresentation::Set(L, TNaming_NamedShape::GetID());

// Display it
prs->SetColor(Quantity_NOC_BLACK);
prs->Display(1);
Fit3DViews();
// Attach an integer attribute to Box to memorize it's displayed
TDataStd_Integer::Set(L, 1);

myAISContext->UpdateCurrentViewer();

// Close the command (for undo)
D->CommitCommand();

Regards

Serge's picture

Hi Bryan,

It seems that you have some error in method CreateSpace. You can check whether it works correctly. First of all check if you pass the correct arguments to this method. Then put a check after the method like this:

// Create a new box using the CNewBoxDlg Dialog parameters as attributes
TDF_Label L=TSC.CreateSpace(Dlg.m_x, Dlg.m_y, Dlg.m_z, Dlg.m_w, Dlg.m_l, Dlg.m_h, TCollection_ExtendedString(Name));

Handle(TNaming_NamedShape) aNS;
if(L.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
if(!aNS->Get().IsNull()) {
//Ok' the shape is created in AISPresentation will display it.
}
else {
//Error:The empty shape
}
}
else {
//Error: No NamedShape attribute
}

Regards