
Tue, 04/15/2025 - 11:57
A bit of context
I am trying to do a common operation between a solid that I constructed from a list of triangles and a box. The solid represents a staircase. It is generated in another app, meaning I only have access to its list of triangles. The following c++ code generates the staircase as an OCCT solid from its list of triangles :
const CsgNodeMsg_CsgPrimitiveMsg_CsgMeshMsg &meshMsg = csgNodeTypeData.mesh();
const GeometryMsg &geometry = meshMsg.geometry();
auto convertPointFromMessage = [](const Vector3fMsg &v) -> gp_Pnt { return gp_Pnt(v.x(), v.y(), v.z()); };
auto convertVectorFromMessage = [](const Vector3fMsg &v) -> gp_Vec { return gp_Vec(v.x(), v.y(), v.z()); };
// Checks if the face (triangle) defined by the vertices p1, p2, p3 is reversed given its normal
auto isReverse = [](const gp_Vec &normal, const gp_Pnt &p1, const gp_Pnt &p2, const gp_Pnt &p3) -> bool
{
return gp_Vec(p1, p2).Crossed(gp_Vec(p1, p3)).Dot(normal) < 0;
};
constexpr BRep_Builder shellBuilder;
TopoDS_Shell shell;
shellBuilder.MakeShell(shell);
for (const Face3Msg &triangle: geometry.triangles())
{
// Create edges for the triangle
gp_Pnt p1 = convertPointFromMessage(geometry.vertices(triangle.a()));
gp_Pnt p2 = convertPointFromMessage(geometry.vertices(triangle.b()));
gp_Pnt p3 = convertPointFromMessage(geometry.vertices(triangle.c()));
// If face is reversed, swap vertices
if (isReverse(convertVectorFromMessage(triangle.normal()), p1, p2, p3)) std::swap(p1, p3);
// Create a polygon with the vertices and create a face from it
TopoDS_Face face = BRepBuilderAPI_MakeFace(BRepBuilderAPI_MakePolygon(p1, p2, p3, Standard_True), Standard_True);
shellBuilder.Add(shell, face);
}
outShape = BRepBuilderAPI_MakeSolid(shell).Shape();
ApplyTransform(outShape, transformMsg);
I am suspecting the construction of the solid to be erroneous somehow. This is why I uploaded it.
The box is created with a classic BRepPrimAPI_MakeBox()
. It is exactly the size of the staircase. The goal is then to to a common operation (using the BRepAlgoAPI_Common()
) to trim the staircase, making it perfectly straight on the sides. The common operation is implemented as such:
// left is the staircase and right is the box
BRepAlgoAPI_Common commonFunction = BRepAlgoAPI_Common(left, right);
commonFunction.SetFuzzyValue(0.0005);
commonFunction.Build();
outShape = commonFunction.Shape();
The expected result
Using another rendering engine, I am able to get the expected result, where the staircase is trimmed perfectly. It does not used OCCT at all in this case. See the 'expected_staircase.png' image.
The actual result
The returned staircase is missing a lot of triangles. It's like the faces cut during the common operation weren't replaced after the operation. See the 'actual_staircase.png' image. I also tried to translate the box for the sake of the tests, it actually makes it worse. See the 'actual_staircase_translation.png'.
This post mentioned the fuzzy value parameter, I tried using it in the code shown above but it doesn't affect the result at all. Maybe I am using it wrong?
Feel free to ask questions if something is missing
Edit
I tried to use the BRepCheck_Analyzer()
object on the generated solid from the list of triangles. The IsValid()
methods returns false. The documentation specifies what the method checks, but I don't see any way to see which check failed.