Part: Fix orientation of internal shells of a solid (#26717)

* Part: Fix orientation of internal shells of a solid

If a solid consists of multiple shells then it can happen that the
internal shells have incorrect orientation that leads to a broken solid.

This fixes issue https://github.com/FreeCAD/FreeCAD/issues/24994

* Part: Add method Feature::fixSolids

This method explicitly checks for solids with the error
'BRepCheck_EnclosedRegion' that means that internal shells of a solid
are wrong.

Using ShapeFix_Solid fixes the solid.

---------

Co-authored-by: wwmayer <wmayer@freecad.org>
This commit is contained in:
Max Wilfinger
2026-01-08 17:35:26 +01:00
committed by GitHub
parent 8010b04656
commit c6ede8614f
5 changed files with 61 additions and 0 deletions

View File

@@ -150,6 +150,7 @@
#include <BRepCheck_Analyzer.hxx>
#include <BRepCheck_ListIteratorOfListOfStatus.hxx>
#include <BRepCheck_Result.hxx>
#include <BRepCheck_Solid.hxx>
#include <BRepClass_FaceClassifier.hxx>
#include <BRepClass3d.hxx>
#include <BRepClass3d_SolidClassifier.hxx>

View File

@@ -1292,6 +1292,13 @@ bool FaceUniter::process()
return true;
}
void FaceUniter::fixOrientation(const TopoDS_Shell& shell)
{
if (shell.Orientation() != workShell.Orientation()) {
workShell.Reverse();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// BRepBuilderAPI_RefineModel implement a way to log all modifications on the faces
@@ -1358,11 +1365,16 @@ void Part::BRepBuilderAPI_RefineModel::Build()
const TopoDS_Solid& solid = TopoDS::Solid(xp.Current());
BRepTools_ReShape reshape;
TopExp_Explorer it;
int countShells = 0;
for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) {
countShells++;
const TopoDS_Shell& currentShell = TopoDS::Shell(it.Current());
ModelRefine::FaceUniter uniter(currentShell);
if (uniter.process()) {
if (uniter.isModified()) {
if (countShells > 1) {
uniter.fixOrientation(currentShell);
}
const TopoDS_Shell& newShell = uniter.getShell();
reshape.Replace(currentShell, newShell);
LogModifications(uniter);

View File

@@ -198,6 +198,7 @@ public:
{
return workShell;
}
void fixOrientation(const TopoDS_Shell& shell);
bool isModified()
{
return modifiedSignal;

View File

@@ -23,11 +23,15 @@
#include <BRep_Tool.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepCheck_Solid.hxx>
#include <BRepCheck_Status.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <ShapeFix_Solid.hxx>
#include <Standard_Failure.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Builder.hxx>
#include "App/Datums.h"
@@ -241,6 +245,44 @@ int Feature::countSolids(const TopoDS_Shape& shape, TopAbs_ShapeEnum type)
return result;
}
TopoShape Feature::fixSolids(const TopoShape& solids)
{
if (solids.isNull()) {
return solids;
}
std::vector<TopoDS_Solid> fixSolids;
TopExp_Explorer xp;
xp.Init(solids.getShape(), TopAbs_SOLID);
for (; xp.More(); xp.Next()) {
TopoDS_Solid solid = TopoDS::Solid(xp.Current());
BRepCheck_Solid bs(solid);
if (bs.IsStatusOnShape(solid)) {
const auto& listOfStatus = bs.StatusOnShape(solid);
if (listOfStatus.Contains(BRepCheck_EnclosedRegion)) {
fixSolids.emplace_back(solid);
}
}
}
if (fixSolids.empty()) {
return solids;
}
TopoDS_Compound comp;
TopoDS_Builder bb;
bb.MakeCompound(comp);
for (const TopoDS_Solid& it : fixSolids) {
ShapeFix_Solid fix(it);
fix.Perform();
bb.Add(comp, fix.Solid());
}
TopoShape fixShape(comp);
return fixShape;
}
bool Feature::isSingleSolidRuleSatisfied(const TopoDS_Shape& shape, TopAbs_ShapeEnum type)
{
if (singleSolidRuleMode() == Feature::SingleSolidRuleMode::Disabled) {

View File

@@ -127,6 +127,11 @@ protected:
TopoShape getSolid(const TopoShape&) const;
static int countSolids(const TopoDS_Shape&, TopAbs_ShapeEnum type = TopAbs_SOLID);
/**
* Fix solids
*/
TopoShape fixSolids(const TopoShape&);
/**
* Checks if the single-solid body rule is fulfilled.
*/