Finding Bottom Point of STL & Give It to BRepAlgoAPI_Section Constructor as a Parameter

Dear OCCT Community,

I'm trying to split an .STL file with BRepAlgoAPI_Section class and I've implement below code blocks for creating a planar splitter:

BRepAlgoAPI_Section OCCTShapeHealer::createSplitterWithGivenHeight(TopoDS_Shape shape, float height)
{
    BRepAlgoAPI_Section splitter_section (shape, gp_Pln(gp_Pnt(0.0, 0.0, height), gp::DZ()), Standard_False);
    splitter_section.ComputePCurveOn1(Standard_True);
    splitter_section.Approximation(Standard_True);
    splitter_section.Build();
    return splitter_section;
}

If the Z-coordinate of the origin point of my STL is not at 0, the splitting does not take place where I expected because it accepts Z as 0 during the cutting process. I will give a few examples below so I can explain better with images:

STL File Name Preview Full STL File on Free CAD Application Original Height of STL File (as milimeter) Given Height for Splitting (as milimeter) After Splitting, Preview of Top Component After Splitting, Preview of Bottom Component
  57 mm

Bottom point is:

(0,0,-57)

   17.0 did not split because it has a Z- value less than 0 did not split because it has a Z- value less than 0. As a consequence, shape is same:

  57 mm

Bottom point is:

(0,0, 0)

 17.0

As a result, what I would like to ask is that: If I know the value of bottom (for example, let it be -37), how do I give this value to the splitter? Which method should I use for this?

Thank you in advance,

Best regards.

Eugene Zaliznyak's picture

Hello Nezihe!
If I understand your question correctly, you should take bottom position of part and + height.
But It is so simple and I am not sure I have understood you. In other way, please describe the problem more transparently)

With respect, Eugene.

Nezihe Sözen's picture

Hello Eugene, Thank you for your reply. Actually, you're right about finding bottom/corner point and translate/relocate the TopoDS_Shape is so simple:

gp_XYZ OCCTShapeHealer::getMinimumCornerCoordinateFromShape(TopoDS_Shape being_bounded_shape)
{
    Bnd_Box bounding_box;
    gp_Pnt corner_min;
    BRepBndLib::Add(being_bounded_shape, bounding_box);
    corner_min = bounding_box.CornerMin();
    return corner_min.XYZ();
}
TopoDS_Shape OCCTShapeHealer::getShapeLocatedIntoZeroPoint(TopoDS_Shape being_relocated_shape, gp_XYZ relocation_value)
{
    gp_Trsf XYZTransformation;
    TopoDS_Shape relocated_shape;

    if (relocation_value.X() != 0){
        XYZTransformation.SetValues(1, 0, 0, -(relocation_value.X()), 0, 1, 0, 0, 0, 0, 1, 0);
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape= transformXYZ.Shape();
    }
    if (relocation_value.Y() != 0){
        XYZTransformation.SetValues(1, 0, 0, 0, 0, 1, 0, -(relocation_value.Y()), 0, 0, 1, 0);
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape = transformXYZ.Shape();
    }
    if (relocation_value.Z() != 0){
        XYZTransformation.SetValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -(relocation_value.Z()));
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape = transformXYZ.Shape();
    }

    return relocated_shape;
}

However; if I invoke the splitter method without implementing the above methods, the splitting does not work correctly.

I would like to share my implementation better intelligibility:

How I can import an STL file?


bool OCCTStlFileImporter::readCADFileTemplateMethod(const std::string &cad_file_path, std::vector<OCCTMeshModel> &solid_meshes)
{
    if (!isImportedCADFile(cad_file_path) || !isFilledMeshModels(solid_meshes)){
        return false;
    }
    return true;
}

bool OCCTStlFileImporter::isImportedCADFile(const std::string &stl_file_path)
{
    triangulated_mesh_ = RWStl::ReadFile(stl_file_path.c_str());
    return !triangulated_mesh_.IsNull();
}

bool OCCTStlFileImporter::isFilledMeshModels(std::vector<OCCTMeshModel> &solid_meshes)
{
    TopoDS_Shape theShape;
    OCCTMeshModel model;

    TopoDS_Vertex aTriVertexes[3];
    TopoDS_Face aFace;
    TopoDS_Wire aWire;
    BRepBuilderAPI_Sewing aSewingTool;
    aSewingTool.Init (1.0e-06, Standard_True);

    TopoDS_Compound aComp;
    BRep_Builder BuildTool;
    BuildTool.MakeCompound (aComp);

    for (Standard_Integer aTriIdx  = 1; aTriIdx <= triangulated_mesh_->NbTriangles(); ++aTriIdx)
    {
        const Poly_Triangle aTriangle = triangulated_mesh_->Triangle (aTriIdx);

        Standard_Integer anId[3];
        aTriangle.Get(anId[0], anId[1], anId[2]);

        const gp_Pnt aPnt1 = triangulated_mesh_->Node (anId[0]);
        const gp_Pnt aPnt2 = triangulated_mesh_->Node (anId[1]);
        const gp_Pnt aPnt3 = triangulated_mesh_->Node (anId[2]);
        if (!(aPnt1.IsEqual (aPnt2, 0.0))
                && !(aPnt1.IsEqual (aPnt3, 0.0)))
        {
            aTriVertexes[0] = BRepBuilderAPI_MakeVertex (aPnt1);
            aTriVertexes[1] = BRepBuilderAPI_MakeVertex (aPnt2);
            aTriVertexes[2] = BRepBuilderAPI_MakeVertex (aPnt3);

            aWire = BRepBuilderAPI_MakePolygon (aTriVertexes[0], aTriVertexes[1], aTriVertexes[2], Standard_True);
            if (!aWire.IsNull())
            {
                aFace = BRepBuilderAPI_MakeFace (aWire);
                if (!aFace.IsNull())
                {
                    BuildTool.Add (aComp, aFace);
                }
            }
        }
    }

    aSewingTool.Load (aComp);
    aSewingTool.Perform();
    theShape = aSewingTool.SewedShape();
    if (theShape.IsNull())
    {
        theShape = aComp;
    }


    model.setMeshModelId(1);
    model.setMeshModelName("stlmodel");
    model.setMeshShape(theShape);

    solid_meshes.push_back(model);

    return true;
}

How I can split the TopoDS_Shape (imported from an STL file) ?

std::vector<TopoDS_Shape> OCCTShapeHealer::getSplittedMeshesAsTwoPart(TopoDS_Shape being_splitted_mesh, float height)
{
    std::vector<TopoDS_Shape> splitted_meshes;

    auto bottom_point_of_the_shape = this->getMinimumXYZCoordinateFromShape(being_splitted_mesh);

    if(bottom_point_of_the_shape.Z() != 0){
        being_splitted_mesh = this->getShapeLocatedIntoZeroPoint(being_splitted_mesh, bottom_point_of_the_shape);
    }

    // Split the shape.
    BRepFeat_SplitShape shape_splitter(being_splitted_mesh);
    BRepAlgoAPI_Section section = this->createSplitterWithGivenHeight(being_splitted_mesh, height);

    for (TopExp_Explorer iter(section.Shape(), TopAbs_EDGE); iter.More(); iter.Next())
    {
        TopoDS_Shape shape_of_edge = iter.Current();
        TopoDS_Shape shape_of_face;

        if (section.HasAncestorFaceOn1(shape_of_edge, shape_of_face))
        {
            TopoDS_Edge edge = TopoDS::Edge(shape_of_edge);
            TopoDS_Face face = TopoDS::Face(shape_of_face);

            shape_splitter.Add(edge, face);
        }
    }

    shape_splitter.Build();

    // Rebuild top and bottom shape.
    BRep_Builder brep_builder;
    TopoDS_Compound top_compound;
    TopoDS_Compound bottom_compound;

    brep_builder.MakeCompound(top_compound);
    brep_builder.MakeCompound(bottom_compound);

    // Top shape.
    TopTools_MapOfShape map_of_top_shape;
    const TopTools_ListOfShape& list_of_top_shapes = shape_splitter.Left();
    for (auto i = list_of_top_shapes.cbegin(); i != list_of_top_shapes.cend(); i++)
    {
        map_of_top_shape.Add(*i);
        brep_builder.Add(top_compound, *i);
    }

    // Bottom shape.
    TopTools_IndexedMapOfShape indexed_map_of_bottom_shape;
    TopExp::MapShapes(shape_splitter.Shape(), TopAbs_FACE, indexed_map_of_bottom_shape);

    for (auto i = indexed_map_of_bottom_shape.cbegin(); i != indexed_map_of_bottom_shape.cend(); i++)
    {
        if (!map_of_top_shape.Contains(*i))
        {
            brep_builder.Add(bottom_compound, *i);
        }
    }

    splitted_meshes.push_back(getShapeAsInitialLocation(top_compound, bottom_point_of_the_shape));
    splitted_meshes.push_back(getShapeAsInitialLocation(bottom_compound, bottom_point_of_the_shape));

    return splitted_meshes;
}

BRepAlgoAPI_Section OCCTShapeHealer::createSplitterWithGivenHeight(TopoDS_Shape shape, float height)
{
    BRepAlgoAPI_Section splitter_section (shape, gp_Pln(gp_Pnt(0.0, 0.0, height), gp::DZ()), Standard_False);
    splitter_section.ComputePCurveOn1(Standard_True);
    splitter_section.Approximation(Standard_True);
    splitter_section.Build();
    return splitter_section;
}

gp_XYZ OCCTShapeHealer::getMinimumXYZCoordinateFromShape(TopoDS_Shape being_bounded_shape)
{
    Bnd_Box bounding_box;
    gp_Pnt corner_min;
    BRepBndLib::Add(being_bounded_shape, bounding_box);
    corner_min = bounding_box.CornerMin();
    return corner_min.XYZ();
}

TopoDS_Shape OCCTShapeHealer::getShapeLocatedIntoZeroPoint(TopoDS_Shape being_relocated_shape, gp_XYZ relocation_value)
{
    gp_Trsf XYZTransformation;
    TopoDS_Shape relocated_shape;

    if (relocation_value.X() != 0){
        XYZTransformation.SetValues(1, 0, 0, -(relocation_value.X()), 0, 1, 0, 0, 0, 0, 1, 0);
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape= transformXYZ.Shape();
    }
    if (relocation_value.Y() != 0){
        XYZTransformation.SetValues(1, 0, 0, 0, 0, 1, 0, -(relocation_value.Y()), 0, 0, 1, 0);
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape = transformXYZ.Shape();
    }
    if (relocation_value.Z() != 0){
        XYZTransformation.SetValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -(relocation_value.Z()));
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape = transformXYZ.Shape();
    }

    return relocated_shape;
}

TopoDS_Shape OCCTShapeHealer::getShapeAsInitialLocation(TopoDS_Shape being_relocated_shape, gp_XYZ relocation_value)
{
    Bnd_Box box;
    BRepBndLib::Add(being_relocated_shape, box);
    Standard_Real theXmin, theYmin, theZmin, theXmax, theYmax, theZmax;
    gp_Trsf XYZTransformation;
    TopoDS_Shape relocated_shape;

    if (relocation_value.X() != 0){
        XYZTransformation.SetValues(1, 0, 0, (relocation_value.X()), 0, 1, 0, 0, 0, 0, 1, 0);
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape= transformXYZ.Shape();
    }
    if (relocation_value.Y() != 0){
        XYZTransformation.SetValues(1, 0, 0, 0, 0, 1, 0, (relocation_value.Y()), 0, 0, 1, 0);
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape = transformXYZ.Shape();
    }
    if (relocation_value.Z() != 0){
        XYZTransformation.SetValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, (relocation_value.Z()));
        BRepBuilderAPI_Transform transformXYZ(XYZTransformation);
        transformXYZ.Perform(being_relocated_shape);
        relocated_shape = transformXYZ.Shape();
    }

    return relocated_shape;
}

One more last word, my expectation is that if my stl file's top point 0,0,0 and bottom point 0,0,-58 and if I give the height -37.0, method should split the shape as two part: (0,0,0 <-> 0,0,-37) and (0,0,-37 <-> 0,0,-58 ). I am not able to overcome this problem. 

Thank you!

Nezihe

Attachments: 
Eugene Zaliznyak's picture

No, transforming original shape cannot be a solution. Is it possible for you to put here only code, which trys to cut model by height position from very start call with height value.