Empty Sectioning Result with BOPAlgo_Section on XCAFPrs_AISObject

Hi, I want to use the sectioning algorithm provided by BOPAlgo_Section to section an XCAFPrs_AISObject and a face. The XCAFPrs_AISObject is an OBJ model loaded using RWObj_CafReader. However, when the input parameters have overlapping regions, the result of the sectioning algorithm is always empty. I've attached my test code and the OBJ model. The OBJ was created using Blender as a box, and the cutting face is a horizontal plane, both located at the origin. So, there should be a result when performing the sectioning on them. I also tested section a horizontal face and a box created with BRepPrimAPI_MakeBox, and the sectioning result was correct. The Opencascade version is 7.7.0.

#include <RWObj_CafReader.hxx>
#include <XCAFApp_Application.hxx>
#include <Message_ProgressRange.hxx>
#include <XCAFDoc_ShapeTool.hxx>
#include <XCAFDoc_ColorTool.hxx>
#include <TDF_LabelSequence.hxx>
#include <XCAFPrs_AISObject.hxx>
#include <XCAFDoc_DocumentTool.hxx>
#include <BRep_Tool.hxx>
#include <TopoDS.hxx>
#include <iostream>
#include <BinXCAFDrivers.hxx>
#include <AIS_InteractiveContext.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BOPAlgo_Section.hxx>
#include <TopoDS_Shape.hxx>
#include <TopExp_Explorer.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <stdexcept>
#include <vector>
#include <array>
#include <BRepBndLib.hxx>



int main() {
    TopoDS_Face tool_face;
    TDF_LabelSequence FreeShape;
    BOPAlgo_Section sectioner;

    TopoDS_Shape shp_result; // Variable to store the result of the sectioning operation.

    // Set the path to the .obj file to be loaded.
    const char* theObjFileName = "D:/2.obj";

    // Initialize the application and define the XCAF format.
    Handle(TDocStd_Application) anApp = new TDocStd_Application();
    BinXCAFDrivers::DefineFormat(anApp);

    // Create a new XCAF document.
    Handle(TDocStd_Document) anXCAFDoc;
    anApp->NewDocument("MDTV-XCAF", anXCAFDoc);

    // Set up the reader for the .obj file and perform the reading operation.
    RWObj_CafReader aReader;
    aReader.SetDocument(anXCAFDoc);
    aReader.Perform(theObjFileName, Message_ProgressRange());

    // Get the main label of the XCAF document and retrieve the shape tool.
    TDF_Label mainLabel = anXCAFDoc->Main();
    Handle(XCAFDoc_ShapeTool) myShapeTool = XCAFDoc_DocumentTool::ShapeTool(mainLabel);

    // Get all free shapes in the document.
    myShapeTool->GetShapes(FreeShape);

    // Output the number of free shapes.
    std::cout << "FreeShape.Length() = " << FreeShape.Length() << std::endl;

    // Define a plane to be used for creating a tool face.
    gp_Pnt P(0, 0, 0);
    gp_Dir D(gp_Vec(0, 0, 1));
    gp_Pln testPln(P, D);

    // Create a tool face on the defined plane within specified bounds.
    tool_face = BRepBuilderAPI_MakeFace(testPln, -9, 9, -9, 9).Face();

    // Add the tool face as an argument to the sectioning algorithm.
    sectioner.AddArgument(tool_face);

    // Loop through all free shapes and add them to the sectioning algorithm.
    for (int i = 1; i <= FreeShape.Length(); i++) {
        TDF_Label label = FreeShape.Value(i);
        Handle(XCAFPrs_AISObject) displayedShape = new XCAFPrs_AISObject(label);

        sectioner.AddArgument(displayedShape->Shape());
    }

    sectioner.Perform();

    shp_result = sectioner.Shape();

    // Check if the result is null and output the corresponding message.
    Handle(AIS_Shape) anAisShape = new AIS_Shape(shp_result);
    if (shp_result.IsNull()) {
        std::cout << "shp_result is null" << std::endl;
    }
    else {
        std::cout << "shp_result is not null" << std::endl;
    }

    // Clear the sectioner and set new arguments for another operation.
    {
        sectioner.Clear();
        TopoDS_Shape S1 = BRepPrimAPI_MakeBox(10, 20, 30).Shape(); // Create a box shape.
        sectioner.AddArgument(S1);
        sectioner.AddArgument(tool_face);
        sectioner.Perform();
        shp_result = sectioner.Shape();
        Handle(AIS_Shape) anAisShape = new AIS_Shape(shp_result);

        // Check if the result is null and output the corresponding message.
        if (shp_result.IsNull()) {
            std::cout << "shp_result is null" << std::endl;
        }
        else {
            std::cout << "shp_result is not null" << std::endl;
        }
    }

    return 0;
}
Attachments: 
Xposeder's picture

I have added some debugging code:

   if (sectioner.HasErrors()) {
        const Handle(Message_Report) report = sectioner.GetReport();
        Standard_OStream& theOS = std::cout;
        sectioner.DumpErrors(theOS);
        theOS << "cutError:"  << &theOS <<std::endl;
        sectioner.DumpWarnings(theOS);
        theOS << "cutWarning:" << &theOS << std::endl;;
    }

There is an output line of BOPAlgo_AlertNullInputShapes, which seems to be the cause. I thought it might be that the shape of the OBJ model is considered null, so I tested it:

// Loop through all free shapes and add them to the sectioning algorithm.
for (int i = 1; i <= FreeShape.Length(); i++) {
    TDF_Label label = FreeShape.Value(i);
    Handle(XCAFPrs_AISObject) displayedShape = new XCAFPrs_AISObject(label);
    if (displayedShape->Shape().IsNull()) {
        std::cout << "displayedShape->Shape().IsNull()" << std::endl;
    }
    sectioner.AddArgument(displayedShape->Shape());
}

it output displayedShape->Shape().IsNull(), so why the shape of the OBJ model is considered null? I visualized the OBJ model with some other code, and it is indeed visible.

gkv311 n's picture

OBJ format defines only tessellated model representation, which is enough for displaying, but not that good for modeling. Boolean algorithms in OCCT currently operate only on analythical surfaces like B-Splines, spheres, cylinders, etc. within valid B-Rep.

For performing Boolean operations on polygonal models (from OBJ) you will need either reconstructing analytical surfaces and proper B-Rep (this task is not well handled by automatic algorithms like SSP and usually requires manual steps) or to use other libraries specifically designed for intersecting triangulations (like OMF).

sOup x's picture

Can you elaborate on the terms SSP & OMF?

gkv311 n's picture

Can you elaborate on the terms SSP & OMF?

These are commercial extensions to OCCT (Surface from Scattered Points and Opencascade Mesh Framework).

Dmitrii Pasukhin's picture

Hello, 

SSP - surface from scattered points. Reconstruction geometry tool.

OMF - OpenCascade mesh framework. Helps with different operating on mesh.

Both of them are commercial components, more details:

https://occt3d.com/components/mesh-framework-component/

https://occt3d.com/components/surface-from-scattered-points-component-sdk/

Best regards, Dmitrii.

 

Xposeder's picture

Hi, thank you for your earnest response. I see, I will consider using other methods to solve this problem.