Getting data from IGES files

Hello,

I need to implement the following approach in my application - load IGES file, get tessellation and some other data for every element:
- vertices and faces,
- object name;
- object color.

Could you please give me some hints how to get it.

I load IGES files in this way:

     IGESControl_Controller::Init();
     IGESControl_Reader aReader;
     if (aReader.ReadFile((const Standard_CString)FileName) == IFSelect_RetDone)
     {
          aReader.SetReadVisible(Standard_True);
          aReader.PrintCheckLoad(Standard_True,IFSelect_GeneralInfo);

          aReader.ClearShapes();
          aReader.TransferRoots();
     }

Qr Qr's picture

Hello Vladimir,

With the code you posted you can read only the geometry. To have names and colors, you can use XDE (https://dev.opencascade.org/doc/overview/html/occt_user_guides__xde.html). Check out IGESCAFControl_Reader utility which reads IGES files with all metadata to an XDE document.

To produce a tessellation, you can use BRepMesh_IncrementalMesh. Notice that tessellation will be built after IGES loading, so it is not somewhat stored in the file initially. Then, to get sub-shapes like vertices or faces, you may use TopExp package.

Regards,
Qr.

Benjamin Bihler's picture

Here is some code snippet you might want to look at:

bool ImporterExporter::getIGESShapeColor(
        const Handle(IGESData_IGESEntity)& shapeEntity,
        const Handle(Interface_InterfaceModel)& model, Quantity_NameOfColor& color)
{
    int colorRank = shapeEntity->RankColor();
    if (colorRank >= 0)
    {
        IGESSelect_SignColor entityRedColorSigner(4);
        std::string red = entityRedColorSigner.Value(shapeEntity, model);
        if (red.empty())
        {
            return false;
        }
        IGESSelect_SignColor entityGreenColorSigner(5);
        std::string green = entityGreenColorSigner.Value(shapeEntity, model);
        if (green.empty())
        {
            return false;
        }
        IGESSelect_SignColor entityBlueColorSigner(6);
        std::string blue = entityBlueColorSigner.Value(shapeEntity, model);
        if (blue.empty())
        {
            return false;
        }
        double redValue = std::stod(red) / 100.0;
        double greenValue = std::stod(green) / 100.0;
        double blueValue = std::stod(blue) / 100.0;
        Quantity_Color shapeColor(redValue, greenValue, blueValue,
                Quantity_TOC_RGB);
        color = shapeColor.Name();
        return true;
    }
    else
    {
        const Handle(IGESData_ColorEntity)& colorEntity = shapeEntity->Color();
        if (colorEntity.IsNull())
        {
            return false;
        }
        else
        {
            Handle(IGESGraph_Color) colorGraph = Handle(IGESGraph_Color)::DownCast(
                    colorEntity);
            if (colorGraph.IsNull())
            {
                return false;
            }
            else
            {
                double red;
                double green;
                double blue;
                colorGraph->RGBIntensity(red, green, blue);
                red = red / 100.00;
                green = green / 100.00;
                blue = blue / 100.00;
                Quantity_Color shapeQuantityColor(red, green, blue, Quantity_TOC_RGB);
                color = shapeQuantityColor.Name();
                return true;
            }
        }
    }
    return false;
}

std::string ImporterExporter::getIGESShapeName(const IGESControl_Reader& reader,
        const TopoDS_Shape& shape, Handle(IGESData_IGESEntity)& shapeEntity)
{
    const Handle(XSControl_WorkSession)& workSession = reader.WS();
    const Handle(XSControl_TransferReader)& transferReader =
            workSession->TransferReader();
    const Handle(Transfer_TransientProcess)& readerTransientProcess =
            transferReader->TransientProcess();
    shapeEntity = Handle(IGESData_IGESEntity)::DownCast(
            transferReader->EntityFromShapeResult(shape, -1));
    
    if (shapeEntity.IsNull())
    {
        return getDefaultShapeName(shape);
    }
    if (shapeEntity->HasName())
    {
        return shapeEntity->NameValue()->String().ToCString();
    }
    else
    {
        return getDefaultShapeName(shape);
    }
}

Vladimir Yampoltsev's picture

Thank you all for the tips. I found examples of the use of the BRepMesh_IncrementalMesh:

https://www.opencascade.com/content/cannot-loadsave-stl-file
https://www.opencascade.com/content/import-step-export-mesh-wrong-placem...

However, an linking error(error LNK2019) occurs when i use the header file (BRepMesh_IncrementalMesh.hxx)

Project Settings and errors attached to the post.

Qr Qr's picture

It seems you're missing TKMesh.lib in your linker's input.

Vladimir Yampoltsev's picture

Thank you very much. It helped a lot. Now I understand how to get tessellation:

     BRepMesh_IncrementalMesh(shape, 0.001);
     for (TopExp_Explorer ex(shape, TopAbs_FACE); ex.More(); ex.Next())
     {    
          TopoDS_Face F = TopoDS::Face(ex.Current());
          TopLoc_Location L = TopLoc_Location();
          Handle(Poly_Triangulation) facing = BRep_Tool::Triangulation(F, L);
          int nbtris = facing->NbTriangles();
            
          gPointsList.clear();
          gVertexList.clear();
          gIndexesList.clear();

          const Poly_Array1OfTriangle & triangles = facing->Triangles();
          const TColgp_Array1OfPnt & nodes = facing->Nodes();
          for (int i = facing->NbTriangles(); i >= 1; i--)
          {
                Poly_Triangle triangle = triangles(i);
                Standard_Integer node1, node2, node3;
        
                triangle.Get(node1, node2, node3);
            
                AddPoint(gPointsList, nodes(node1));
                AddPoint(gPointsList, nodes(node2));
                AddPoint(gPointsList, nodes(node3));
           }
            
          GenerateGeometryData(gPointsList, &gVertexList, &gIndexesList);

     }

Could you please give me a hint how to scan all elements (sub-assemblies and parts) of an assembly and get their name and color?
I created an IGES file of the following structure:
-assembly1
---part1_asm1
---part2_asm1
---assembly2
------part1_asm2

I tried to get data in the following way:

     IGESCAFControl_Reader aReader;
     aReader.SetColorMode(true);
     aReader.SetNameMode(true);
     aReader.SetLayerMode(true);

     if (aReader.ReadFile("C:\\TEST\\Sborka2.igs") == IFSelect_RetDone)
     {
            Handle(TDocStd_Document) aDoc = new TDocStd_Document("IgesReader");
            aReader.SetReadVisible(Standard_True);
            aReader.PrintCheckLoad(Standard_True, IFSelect_GeneralInfo);
    
            if (aReader.Transfer(aDoc))
            {
                 aReader.PrintCheckTransfer(Standard_True, IFSelect_GeneralInfo);
                 Handle(XCAFDoc_ShapeTool) myAssembly = XCAFDoc_DocumentTool::ShapeTool(aDoc->Main());
                 Handle(XCAFDoc_ColorTool) myColors = XCAFDoc_DocumentTool::ColorTool(aDoc->Main());
                
                TDF_LabelSequence frshapes;
                myAssembly->GetShapes(frshapes);
                for (Standard_Integer i = 1; i <= frshapes.Length(); i++) 
                {

                     const TDF_Label& label = frshapes.Value(i);
                     Handle(TDataStd_Name) name;
                     TCollection_AsciiString ascii_name;
            
                     if (label.FindAttribute(TDataStd_Name::GetID(), name))
                     {
                          TCollection_ExtendedString extstr = name->Get();
                          ascii_name = name->Get();
                          fout1 << "Name: "<<ascii_name.ToCString()<<"\n";
                     }

                    XCAFDoc_ColorType ctype = XCAFDoc_ColorGen;
                    Quantity_Color col;
        
                    //This metod not found    
                    if (myColors->GetColor(label, ctype, col)) 
                    {
                    }

               }

          }

     }

However I got name of parts only:
=>[0:1:1:2]
part1_asm1
=>[0:1:1:4]
part2_amsm1
=>[0:1:1:6]
part1_asm2)
How can I get names of two assemblies (assembly1 и assembly2)?

Qr Qr's picture

First, I would recommend you to start using Draw for visualization of XDE structure. In Draw you can do the following:

> ReadIges [filename] doc # read IGES with all metadata to OCAF document
> XShow doc # show assembly in 3D viewer
> DFBrowse doc # show OCAF structure

You have to understand the XDE structure in order to learn how to iterate an assembly. Here is a sample code how you can do that. To understand better what is "free shape", "reference", "component", etc., there is no any better way than checking out the OpenCascade's sources.

// This function iterates XDE starting from the root items (empty "rootEntry").
void IterateBranch(const TCollection_AsciiString& rootEntry,
                   const TCollection_AsciiString& parentItem)
{
  Handle(TDocStd_Document)  Doc       = ...;
  Handle(XCAFDoc_ShapeTool) ShapeTool = ...;
  //
  TDF_LabelSequence Labels;
  if ( rootEntry.IsEmpty() )
  {
    // Get list of roots
    ShapeTool->GetFreeShapes(Labels);
  }
  else
  {
    // Access label by its ID
    TDF_Label RootLabel;
    TDF_Tool::Label(Doc->Main().Data(), rootEntry, RootLabel);

    // Access all components of an assembly
    if ( ShapeTool->IsAssembly(RootLabel) )
      ShapeTool->GetComponents(RootLabel, Labels);
  }

  // Iterate over the root entities
  for ( int lit = 1; lit <= Labels.Length(); ++lit )
  {
    TDF_Label L = Labels.Value(lit);
    //
    TCollection_AsciiString RefName, EntryId, RefEntryId, Name;
    Handle(TDataStd_Name) NodeName;

    TDF_Tool::Entry(L, EntryId);
    if ( ShapeTool->IsReference(L) ) // It is a reference to a part with location
    {
      // NAME OF THE REFERENCE
      if ( L.FindAttribute(TDataStd_Name::GetID(), NodeName) )
        RefName = TCollection_AsciiString( NodeName->Get() );

      TDF_Label RefLabel;
      if ( ShapeTool->GetReferredShape(L, RefLabel) ) // Get the real underlying part
      {
        L = RefLabel;
        TDF_Tool::Entry(RefLabel, RefEntryId);
      }
    }

    // NAME OF THE PART
    if ( L.FindAttribute(TDataStd_Name::GetID(), NodeName) )
    {
      Name = TCollection_AsciiString( NodeName->Get() );

      // Trim spaces
      RefName.RightAdjust();
      RefName.LeftAdjust();

      if ( !RefName.IsEmpty()           &&
            RefName.Search("=>[0:") != 1 &&
           !IsEqual(RefName, Name)  )
      {
        Name += TCollection_AsciiString (" [") + RefName + "]";
      }
    }

    if ( RefEntryId.IsEmpty() )
      RefEntryId = EntryId;

    // Build path to entry in the assembly tree
    if ( !parentItem.IsEmpty() )
    {
      EntryId.Prepend("/");
      EntryId.Prepend(parentItem);
    }

    // Continue iteration recursively
    IterateBranch(RefEntryId, EntryId);
  }
}

Vladimir Yampoltsev's picture

Thank you very much for your help! I read and analyze samples with using XDE structure. Your code provides me the following information without names of assemblies:

=>[0:1:1:2]
part1_asm1
=>[0:1:1:4]
part2_amsm1
=>[0:1:1:6]
part1_asm2

Condition [  if (ShapeTool->IsAssembly(RootLabel))  ] is never true.
And I never some to the following sections (if this code is commented then part names are available):

    if (!RefName.IsEmpty() && RefName.Search("=>[0:") != 1 &&    !IsEqual(RefName, Name))

Maybe I use wrong parameters in your code? Could you please check it?

Handle(TDocStd_Document) gDoc;

void IterateBranch(const TCollection_AsciiString& rootEntry, const TCollection_AsciiString& parentItem)
{
    Handle(TDocStd_Document)  Doc = gDoc;
    Handle(XCAFDoc_ShapeTool) ShapeTool = XCAFDoc_DocumentTool::ShapeTool(Doc->Main());

//////

}

int _tmain(int argc, _TCHAR* argv[])
{

     IGESCAFControl_Reader aReader;
     //aReader.SetColorMode(true);
     aReader.SetNameMode(true);
     //aReader.SetLayerMode(true);
     aReader.ReadFile("C:\\TEST\\sborka.igs");
     gDoc = new TDocStd_Document("IgesReader");
     //aReader.SetReadVisible(Standard_True);
     aReader.PrintCheckLoad(Standard_True, IFSelect_GeneralInfo);
     aReader.Transfer(gDoc);
     TCollection_AsciiString par1, par2;
     IterateBranch(par1, par2);

     return 0;

}

Qr Qr's picture

Vladimir, could you share your IGES file? It will be easier to profile on the reference data.