Save to STEP with colored faces, edges or vertices

Quaoar

Administrator
Staff member
Yesterday I got the question of how to colorize part's faces and save the colored part to STEP. Here's how one can do this using XDE/OCAF framework of OpenCascade:

C++:
  TopoDS_Shape partShape = // Your shape

  /* Create application and document of the XDE format */

  Handle(TDocStd_Application) app = new TDocStd_Application;
  BinXCAFDrivers::DefineFormat(app);

  Handle(TDocStd_Document) doc;
  app->NewDocument("BinXCAF", doc);
  //
  if ( doc.IsNull() )
  {
    // Cannot create an OCAF document.
    return 1;
  }

  /* Populate XDE document */

  Handle(XCAFDoc_ShapeTool)
    stool = XCAFDoc_DocumentTool::ShapeTool( doc->Main() );

  TDF_Label rootLab = stool->AddShape(partShape);

  /* Set colors */

  TopTools_IndexedMapOfShape allFaces;
  TopExp::MapShapes(partShape, TopAbs_FACE, allFaces);

  // I use some random indices here for test.
  TDF_Label ssLab[3];
  ssLab[0] = stool->AddSubShape(rootLab, allFaces(1));
  ssLab[1] = stool->AddSubShape(rootLab, allFaces(2));
  ssLab[2] = stool->AddSubShape(rootLab, allFaces(3));

  Handle(XCAFDoc_ColorTool)
    ctool = XCAFDoc_DocumentTool::ColorTool( doc->Main() );

  ctool->SetColor(ssLab[0], Quantity_NOC_RED,   XCAFDoc_ColorSurf);
  ctool->SetColor(ssLab[1], Quantity_NOC_GREEN, XCAFDoc_ColorSurf);
  ctool->SetColor(ssLab[2], Quantity_NOC_BLUE1, XCAFDoc_ColorSurf);

  /* Write STEP file */

  STEPCAFControl_Writer writer;

  if ( !writer.Transfer(doc) )
  {
    // Cannot transfer data.
    return 1;
  }

  if ( writer.Write( filename.c_str() ) != IFSelect_RetDone )
  {
    // Cannot write file.
    return 1;
  }
 

Jonathan

New member
@Quaoar,

how would you go about reading the step files back and display the colors according to the step data?

I was able to load/display the models with

C++:
void CPathFinderDoc::LoadSavedModels()
{
    Handle(XCAFDoc_ColorTool) colorTool = XCAFDoc_DocumentTool::ColorTool(myDoc->Main());
    Handle(XCAFDoc_ShapeTool) shapeTool    = XCAFDoc_DocumentTool::ShapeTool(myDoc->Main());
    TDF_Label LabSat = myDoc->Main().FindChild(1);
        for (TDF_ChildIterator it(LabSat); it.More(); it.Next())
        {
            TDF_Label L = it.Value();
            Handle(TNaming_NamedShape) TNS;
            if (!L.FindAttribute(TNaming_NamedShape::GetID(), TNS)) continue;
            Handle(TPrsStd_AISPresentation) prs;
            if (!L.FindAttribute(TPrsStd_AISPresentation::GetID(), prs)) {
                prs = TPrsStd_AISPresentation::Set(L, TNaming_NamedShape::GetID());
            }
            Handle(TDataStd_Name) N;
            if (L.FindAttribute(TDataStd_Name::GetID(), N)) {
                TCollection_AsciiString name = N->Get();
            }

            prs->Display(1);
        }
    myAISContext->UpdateCurrentViewer();
}

but as far as the color goes i'm 100% lost

using the inspector it seems like it would be an attribute of the child of the label containing the shape but I'm not sure.. I'll keep digging..

Is the GUID am looking for XCAFDoc_ColorTool::GetID()?
 

Quaoar

Administrator
Staff member
@Jonathan, you might want to check the code base of Lesson 12 related to XDE and colors: https://gitlab.com/ssv/lessons/-/tree/master/Lesson12_XDE

In the DisplayScene class, the input XDE object is being iterated and all styles are grabbed into XCAFPrs_AISObject objects. The latter objects are kind of "originals" or "parts" and are never shown in the scene. What we actually display are rather the "connected interactive" objects that hold references to the original ones. This is a sort of instancing mechanism OpenCascade comes up with. It's pretty useful as it allows one to reproduce the instancing relations just like they are defined in the input STEP model. I attached one such model that we used at OCC a lot. It's a kinda "hello world" thingy for assemblies.

1626638642099.png

Another object (not an assembly) with some colored faces (ANC101_colored.stp):

1626639049408.png

To confess, it's really darn hard to come up with the code like this unless you're well familiar with the library. That's why I was thinking to cover this subject in one of the upcoming lessons.
 

Jonathan

New member
Thank you so much I will study Lesson 12, or perhaps I should start with lesson 1. :)

what I found out this weekend is that the color is linked using TDataStd_Tree node.. the same nodes are used to link shapes ( I think )

my code is not very good I will gladly read yours and hopefully be able to make my code a bit better :)

I want to say that the inspector really helped me make sense of all this .
 
Last edited:

Jonathan

New member
@Quaoar
Using the connectedinteractive make sense, instead of creating copies.

The issue I am having now, is if I pick a face, I can tell it's from what solid, but I am unable to match the face to a face of the solid..

C++:
TopoDS_Shape pSelectedShape = myAISContext->SelectedShape();
Handle(AIS_InteractiveObject) pAisObj = myAISContext->SelectedInteractive();

            if (pAisObj->IsKind(STANDARD_TYPE(AIS_ConnectedInteractive))) {        
                Handle(AIS_ConnectedInteractive) aisObjHandle = Handle(AIS_ConnectedInteractive)::DownCast(pAisObj);

                if (!aisObjHandle->HasConnection()) { return result; }
                
                Handle(AIS_InteractiveObject) connectedto = aisObjHandle->ConnectedTo();
                
                if (connectedto->IsKind(STANDARD_TYPE(XCAFPrs_AISObject))) {
                    Handle(XCAFPrs_AISObject) connectedToObj = Handle(XCAFPrs_AISObject)::DownCast(connectedto);
                
                    TDF_Label label = connectedToObj->GetLabel();    // give me the right label            
                    TopoDS_Shape theConnectedShape = connectedToObj->Shape();
        
                    TopExp_Explorer theExplorer(theConnectedShape, TopAbs_FACE);
                    while (theExplorer.More())
                    {
                        TopoDS_Shape aShape = theExplorer.Value();
                        if (aShape.IsEqual(pSelectedShape) || aShape.IsSame(pSelectedShape)) {
                            theApp.MsgDebugWnd(L"Found a shape like it.");
                        }
                        theExplorer.Next();
                    }

The explorer goes thru all the face but never finds any match.. Is it because the shape is located or transformed?

I hope I don't ask too many question. I did spend quite a bit of time trying to figure this out but it's not working.

basically what I am trying to achieve is find the face in the shape of the label so I can maintain the link in the ocaf document..
 

Quaoar

Administrator
Staff member
...

The explorer goes thru all the face but never finds any match.. Is it because the shape is located or transformed?
@Jonathan that's likely you're right about the fact that a shape is located. Have you tried IsPartner() method for comparison? Does it make any difference?
 
Top