Work with assemblies

Hello,

Which is the best way to deal with assemblies? I would need to import an assembly from a STEP file and then be able to choose which part or parts I want to work with. As an example, imagine that I want to show an assembly sequence. First, I would like to display only the main element of the assembly and then make visible the rest of pieces, one by one, whenever the assembly is being carried out.

Any idea about how to do that?

Thanks in advance.

Regards,

Adriana

Qr Qr's picture

Hello Adriana,

The conventional way in OpenCascade to deal with assemblies is to use OCAF. More precisely, it is XDE (eXtended Data Framework) component which is based on OCAF. You should start with importing a STEP file to this XDE metastructure using the following code:

bool xde_STEP::Read(const TCollection_AsciiString& filename,
                    Handle(TDocStd_Document)&      result_document)
{
  STEPCAFControl_Reader Reader;
  Handle(XSControl_WorkSession) WS = Reader.Reader().WS();
 
  // Read CAD and associated data from file
  try
  {
    if ( !Reader.ReadFile( filename.ToCString() ) )
    {
      std::cout << "Cannot read STEP file" << std::endl;
      return false;
    }
    
    // Translate model into document
    if ( !Reader.Transfer(result_document) )
    {
      std::cout << "Cannot transfer CAD data from STEP file to XDE" << std::endl;
      return false;
    }
  }
  catch ( ... )
  {
    std::cout << "Exception on reading STEP file" << std::endl;
    return false;
  }
  return true;
}

Once you have this TDocStd_Document, you can start working with it using the tools from XCAFDoc package. Some additional information on XCAFDoc can be found at this link: https://dev.opencascade.org/doc/overview/html/occt_user_guides__xde.html

Be aware that XDE API is probably not very clear. We will be glad to hear about your experience with XDE. Any remarks and ideas how to make it better are welcome.

Adriana Costas's picture

Hello,

Thanks for the information. Another question: is there any relation between labels (or tags) of the TDocStd_Document and the name of the entities in the STEP file?

Qr Qr's picture

Yes. In OCAF, a name is specified by means of TDataStd_Name attribute which sits under the label of the corresponding assembly node. This mechanism does not make distinction between parts and instances coming from STEP file. In STEP, such distinction does exists. The names in STEP can be found in "product" and "next_assembly_usage_occurrence" entities. You may check the structure of OCAF populated from STEP using DFBrowse command in Draw console of OpenCascade.

Adriana Costas's picture

I don't know how to use Draw console... Now, I'm trying to represent the assembly (attached) and each part of the assembly separately but I've not even been able to show the complete assembly. This is my code:

        Handle(TDocStd_Document) doc;
        Handle(XCAFApp_Application) anApp = XCAFApp_Application::GetApplication();
        anApp->NewDocument("MDTV-XCAF", doc);
        bool success = read("/assembly.step", doc);

        Handle(XCAFDoc_ShapeTool) myAssembly = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
        TDF_Label aLabel = myAssembly->NewShape();
        Standard_Integer a = aLabel.Tag();

        Handle(TDataStd_Name) N;
        if (!aLabel.FindAttribute(TDataStd_Name::GetID(), N)) {
            cout << "no name is attached" << endl;
        }else{
            TCollection_ExtendedString name = N->Get();
        }
        
        TopoDS_Shape aShape;
        aShape = myAssembly->GetShape(aLabel);
        
         if (myAssembly->IsComponent(aLabel)) {
             cout << "component" << endl;
         }
        
         if ( myAssembly->IsAssembly(aLabel) ) {
             cout << "assembly" << endl;
         }

If I represent aShape I get nothing (black image). Moreover, the object myAssembly is neither detected as component nor as an assembly. Why? What am I doing wrong?

Thanks!

Attachments: 
Qr Qr's picture

Hi Adriana,

You may want to checkout branch CR29032 of OpenCascade from GitWeb (you may download the snapshot). The corresponding ticket is https://tracker.dev.opencascade.org/view.php?id=29032. In this branch, you can find new tool: XCAFDoc_AssemblyGraph. This tool is designed to ease your life and give you an explicit representation of assembly structure.

You initialize it like this:

Handle(TDocStd_Document) doc = ...; // Your XDE document

// Prepare assembly graph
Handle(XCAFDoc_AssemblyGraph) asmGraph = new XCAFDoc_AssemblyGraph(doc, true);

It gives you the assembly graph explicitly. You can then iterate nodes and arcs ("part-of" relations) like this:

// Iterate nodes
const NCollection_IndexedMap<XCAFDoc_ObjectId>& nodes = asmGraph->GetNodes();
//
for ( int n = 1; n <= nodes.Extent(); ++n )
{
  // Get type of a graph node
  const int nodeType = asmGraph->GetNodeType(n);

  ...

}

// Iterate arcs (adjacency matrix)
const XCAFDoc_AssemblyGraph::t_adjacency& arcs = asmGraph->GetArcs();
//
for ( XCAFDoc_AssemblyGraph::t_adjacency::Iterator it(arcs); it.More(); it.Next() )
{
  const int                         parentId = it.Key();
  const TColStd_PackedMapOfInteger& children = it.Value();

  // Loop over the children
  for ( TColStd_MapIteratorOfPackedMapOfInteger cit(children); cit.More(); cit.Next() )
  {
    const int childId = cit.Key();

    std::cout << "(parent, child) = "
              << "("
              << parentId
              << ", "
              << childId
              << ")"
              << std::endl;
  }
}

If you want to build a scene graph from your assembly (like in the picture attached), you may iterate the graph recursively together with populating your GUI view:

void IterateGraph(const Handle(XCAFDoc_AssemblyGraph)& asmGraph)
{
  // Loop over the roots
  const TColStd_PackedMapOfInteger& roots = asmGraph->GetRoots();
  //
  for ( TColStd_MapIteratorOfPackedMapOfInteger rit(roots); rit.More(); rit.Next() )
  {
    const int rootId = rit.Key();

    // Populate UI here

    // Loop over the children recursively
    IterateChildren(rootId, asmGraph);
  }
}

void IterateChildren(const int                            rootId,
                     const Handle(XCAFDoc_AssemblyGraph)& asmGraph)
{
  if ( !asmGraph->HasChildren(rootId) )
    return;

  // Iterate children
  const TColStd_PackedMapOfInteger& children = asmGraph->GetChildren(rootId);
  //
  for ( TColStd_MapIteratorOfPackedMapOfInteger cit(children); cit.More(); cit.Next() )
  {
    const int childId = cit.Key();

    // Populate UI here

    // Repeat recursively
    IterateChildren(childId, asmGraph);
  }
}

GetPersistentId() method of XCAFDoc_AssemblyGraph returns string ID for the OCAF label corresponding to the given assembly element. This entry can be used to access the data with XCAFDoc_ShapeTool (unless we do not have more higher-level interfaces to XDE). This way geometry is separated from assembly (conceptual) structure.

I shall be glad to hear about your experience with this interface for assemblies. The branch is under development, so any remarks are welcome.

Attachments: 
Adriana Costas's picture

Hi,

This new tool could be pretty useful, let's see if I can handle it. Another simple question: Is it possible to retrieve a component  as TodoDS_Shape or TDF_Label of the assembly looking for by the name? Reading the documentation I would say that it is not possible.

Qr Qr's picture

Adriana,

Unfortunately, XDE does not offer interfaces for filtering your data. Some popular services like searching parts by name do not exist, so you will have to write a piece of C++ code for that. It is a question of time to implement all such services. Feel free to contribute ;)

Adriana Costas's picture

Then, maybe XDE is not the tool that I need. Now I was reading again the documentation about STEP processor and I think that it may be enough for my case. In the end I only need to be able to load each component of an assembly separately. However I have tried to retrieve single entities and I haven't got it. If I use reader.GiveList() I get a list of length 1 so it seems that the processor is only loading the assembly but not its components. How can I access to these parts?

On the other hand, in the documentation is said: "You can select an entity either by its rank or by its handle (an entity’s handle can be obtained by invoking the StepData_StepModel::Entity function)" but I don't understand how to use these tools. What is the rank? Which type of entity I need to specify to produce a shape? Could you explain a bit more this point?

Your help is much appreciated.

Regards.

Qr Qr's picture

Then, maybe XDE is not the tool that I need.

I believe, it is. At least, it allows for working at a certain level of abstraction. For pure STEP reader, personally, I cannot help: I have never digged into it. Still, you may want to check STEPCAFControl_Reader which expands all these STEP entities to OCAF.

Adriana Costas's picture

Hello,

Now I'm working with an STEP file with the following structure:

  • assembly
    • sub-assembly
      • component
      • component
    • component

First, I get the assembly(root) by GetFreeShapes method and then I access to its parts by the method GetComponents. However, this method returns the sub-assembly as a component not as an assembly in such a way that afterwards I cannot access to its children. How can I retrieve the sub-assembly as an assembly? 

Kadir Canik's picture

Hello Adriana,

Can you read the assembly at the moment.

Best regards.