Question regarding proper iteration through TopoDS shapes

I was curious about how one should iterate through shape hierarchy to collect the polygon information and translations correctly. For example, say i have a STP file and when I read it in I get 3 top level shapes of type compound, compound, and shell. I've always assumed that compounds MUST have solids and when i get to a solid, i iterate through all faces owned by that solid. Can I simply iterate through all faces owned by a compound? can I combine all three shapes into a compound and iterate through all faces for that new compound? 

I'm asking because I currently have a file with those 3 high level shapes, and it seems when i go to collect the polygon data for the shell, I'm missing some faces. When i build meshes with the data from the 2 compounds they look correct.

I've uploaded the stp file I'm working with. An image of what it should look like can be found here https://grabcad.com/library/airflow-reducer-1 The geometry owned by the shell is the blue and green portions.

My code for how I collect geometry is as follows:

 

    //Create Document
    Handle(TDocStd_Document) doc;
    Handle(XCAFApp_Application) app = XCAFApp_Application::GetApplication();

    app->NewDocument("MDTV-XCAF", doc);

    STEPCAFControl_Reader reader;
    reader.SetColorMode(true);
    reader.SetNameMode(true);
    reader.SetLayerMode(true);

    IFSelect_ReturnStatus status = reader.ReadFile(file.fullInputName.c_str());
    reader.Transfer(doc);
   
    Handle(XCAFDoc_ColorTool) myColors = XCAFDoc_DocumentTool::ColorTool(doc->Main());
    Handle(XCAFDoc_ShapeTool) myAssembly = XCAFDoc_DocumentTool::ShapeTool(doc->Main());

    TDF_LabelSequence frshapes;
    TopoDS_Compound totalShape;
    BRep_Builder shapeBuilder;

    shapeBuilder.MakeCompound(totalShape);
    Standard_Integer length = frshapes.Length();
    for (Standard_Integer i(1); i <= length; ++i) {
        const TDF_Label& label = frshapes.Value(i);
        TopoDS_Shape shape;
        myAssembly->GetShape(label, shape);

        shapeBuilder.Add(totalShape, shape);
    }

BRepTools::Clean(totalShape);
BRepMesh_IncrementalMesh(totalShape, TOLERANCE, Standard_False, 0.5, Standard_True);

TopoDS_Iterator itor(totalShape);
while (itor.More()) {
    const TopoDS_Shape& shape = itor.Value();
    TopAbs_ShapeEnum type = shape.ShapeType();
    handler.pParentLabel = &(handler.pAssembly->get()->FindShape(shape, Standard_False));
    if (type == TopAbs_COMPOUND) {
        parseCompound(shape, model, handler);
    }
    else if (type == TopAbs_SOLID) {
        parseSolid(shape, model, handler);
    }
    else if (type == TopAbs_SHELL){
        parseSolid(shape, model, handler);
    }
    itor.Next();
}

parseCompound simply goes through each subshape of the compound until it gets to at least a solid, and inevitably calls parseSolid which is as follows:

TopExp_Explorer faceExplorer(shape, TopAbs_FACE);
while (faceExplorer.More()) {
    TopoDS_Face faceTopo = TopoDS::Face(faceExplorer.Current());
    TopLoc_Location location = faceTopo.Location();

    //various color data things

    Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(faceTopo, location);
    gp_Trsf transform = location; 
    if (tri.IsNull() == Standard_False) {
         const TColgp_Array1OfPnt& nodes = tri->Nodes();

        gp_Pnt transformedPoint;
        for (auto point : nodes) {
            transformedPoint = point.Transformed(transform);
            mesh.Vertices.push_back(Point3D(transformedPoint.X(), transformedPoint.Y(), transformedPoint.Z()));
        }

...so on and so forth collecting normals and indices
faceExplorer.Next();

at first I used to just get all faces from the compound but then I had an issue where the vertices were not being positioned correctly. When I went down to at least the Solid level, and getting the solids transform, everything worked well. but now the shell is giving me issues where I'm missing portions of the green geometry. The yellow and orange bits are the 2 compounds, and appear correctly.

Thanks,
Aaron

 

Attachments: 
Patrik Mueller's picture

Hi Aaron,

check the main shapes first :

        TDF_LabelSequence rootShapes;
        myAssembly ->GetShapes(rootShapes);
        for(Standard_Integer i=1; i<=rootShapes.Length(); i++)
        {
            if (myAssembly ->IsFree(rootShapes.Value(i)))
                theSequence.Append(rootShapes.Value(i));
        }

After that iterate through the labels and not the pure Topology (see "occt_xde.pdf"). Some shapes could be instanced with another location and the colors could be on the shapes you don't traverse (e.g. Assemblies). For example a root label could set a color for the whole assembly and the faces have no color attributes!

XCAFPrs_AISObject class has an implementation of traversing such structures.

Best regards,

Patrik

Aaron McDonald's picture

Ah, I suspected something like that when I first started trying to get the color data. Thanks for the advice!