Loading files
3d097a032This file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 1998-08-12
// Created by: Galina KULIKOVA
// Copyright (c) 1998-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// pdn 17.12.98 ie_exhaust-A.stp
#include <Bnd_Box.hxx>
#include <NCollection_Array1.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepBndLib.hxx>
#include <Message_Msg.hxx>
#include <Message_ProgressScope.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_IndexedMap.hxx>
#include <ShapeAnalysis_Shell.hxx>
#include <ShapeBuild_ReShape.hxx>
#include <ShapeFix_Face.hxx>
#include <ShapeFix_Shell.hxx>
#include <Standard_Type.hxx>
#include <Standard_Integer.hxx>
#include <NCollection_List.hxx>
#include <NCollection_Map.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Shell.hxx>
#include <TopTools_ShapeMapHasher.hxx>
#include <NCollection_IndexedDataMap.hxx>
#include <NCollection_Sequence.hxx>
#include <stack>
#include <algorithm>
IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Shell, ShapeFix_Root)
namespace
{
// Type aliases for DataMaps with shape hasher
using FaceEdgesMap = NCollection_IndexedDataMap<TopoDS_Face, NCollection_Array1<TopoDS_Edge>>;
using EdgeFacesMap =
NCollection_DataMap<TopoDS_Edge, NCollection_DynamicArray<TopoDS_Face>, TopTools_ShapeMapHasher>;
// Default increment for dynamic array of faces per edge
constexpr int DEFAULT_EDGE_FACES_INCREMENT = 5;
} // namespace
//=================================================================================================
ShapeFix_Shell::ShapeFix_Shell()
{
myStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);
myFixFaceMode = -1;
myFixOrientationMode = -1;
myFixFace = new ShapeFix_Face;
myNbShells = 0;
myNonManifold = false;
}
//=================================================================================================
ShapeFix_Shell::ShapeFix_Shell(const TopoDS_Shell& shape)
{
myStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);
myFixFaceMode = -1;
myFixOrientationMode = -1;
myFixFace = new ShapeFix_Face;
Init(shape);
myNonManifold = false;
}
//=================================================================================================
void ShapeFix_Shell::Init(const TopoDS_Shell& shell)
{
myShape = shell;
myShell = shell;
myNbShells = 0;
}
//=================================================================================================
bool ShapeFix_Shell::Perform(const Message_ProgressRange& theProgress)
{
bool status = false;
if (Context().IsNull())
{
SetContext(new ShapeBuild_ReShape);
}
myFixFace->SetContext(Context());
if (NeedFix(myFixFaceMode))
{
TopoDS_Shape S = Context()->Apply(myShell);
// Get the number of faces for progress indication
int aNbFaces = S.NbChildren();
// Start progress scope (no need to check if progress exists -- it is safe)
Message_ProgressScope aPS(theProgress, "Fixing face", aNbFaces);
for (TopoDS_Iterator iter(S); iter.More() && aPS.More(); iter.Next(), aPS.Next())
{
TopoDS_Shape sh = iter.Value();
TopoDS_Face tmpFace = TopoDS::Face(sh);
myFixFace->Init(tmpFace);
if (myFixFace->Perform())
{
status = true;
myStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE1);
}
}
// Halt algorithm in case of user's abort
if (!aPS.More())
{
return false;
}
}
TopoDS_Shape newsh = Context()->Apply(myShell);
if (NeedFix(myFixOrientationMode))
{
FixFaceOrientation(TopoDS::Shell(newsh), true, myNonManifold);
}
TopoDS_Shape aNewsh = Context()->Apply(newsh);
ShapeAnalysis_Shell aSas;
for (TopExp_Explorer aShellExp(aNewsh, TopAbs_SHELL); aShellExp.More(); aShellExp.Next())
{
TopoDS_Shell aCurShell = TopoDS::Shell(aShellExp.Current());
if (aCurShell.Closed())
{
aSas.LoadShells(aCurShell);
aSas.CheckOrientedShells(aCurShell, true);
if (aSas.HasFreeEdges())
{
aCurShell.Closed(false);
// clang-format off
SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed
// clang-format on
}
aSas.Clear();
}
}
if (status)
{
myStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE1);
}
if (Status(ShapeExtend_DONE2))
{
status = true;
}
return status;
}
//=================================================================================================
static bool GetFreeEdges(const TopoDS_Shape& aShape,
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>& MapEdges)
{
for (TopExp_Explorer aExpF(aShape, TopAbs_FACE); aExpF.More(); aExpF.Next())
{
for (TopExp_Explorer aExpE(aExpF.Current(), TopAbs_EDGE); aExpE.More(); aExpE.Next())
{
TopoDS_Edge edge = TopoDS::Edge(aExpE.Current());
if (!MapEdges.Contains(edge))
{
MapEdges.Add(edge);
}
else
{
MapEdges.Remove(edge);
}
}
}
return !MapEdges.IsEmpty();
}
/// Groups connected faces into separate sequences using existing connectivity data.
/// Uses depth-first search to find connected components through shared edges.
/// Each face appears in exactly one group, ensuring no duplicates across groups.
/// Groups are sorted by size with the largest group first.
/// @param theFaceEdges Map from faces to their constituent edges
/// @param theEdgeFaces Map from edges to faces that contain them
/// @return List of face sequences, each representing one connected component
static NCollection_List<NCollection_Sequence<TopoDS_Shape>> GetConnectedFaceGroups(
const FaceEdgesMap& theFaceEdges,
const EdgeFacesMap& theEdgeFaces)
{
NCollection_List<NCollection_Sequence<TopoDS_Shape>> aConnectedGroups;
if (theFaceEdges.IsEmpty())
{
return aConnectedGroups;
}
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aVisitedFaces(
static_cast<int>(theFaceEdges.Size()));
for (auto aFaceIter = theFaceEdges.begin(); aFaceIter != theFaceEdges.end(); ++aFaceIter)
{
const TopoDS_Face& aStartFace = aFaceIter.ChangeIterator().Key();
if (aVisitedFaces.Contains(aStartFace))
{
continue;
}
// Start new connected group
NCollection_Sequence<TopoDS_Shape> aConnectedGroup;
// DFS traversal using STL stack with NCollection_Allocator
using StackAllocator = NCollection_Allocator<TopoDS_Face>;
std::stack<TopoDS_Face, std::deque<TopoDS_Face, StackAllocator>> aStack;
aStack.push(aStartFace);
aVisitedFaces.Add(aStartFace);
while (!aStack.empty())
{
const TopoDS_Face aCurrentFace = aStack.top();
aStack.pop();
aConnectedGroup.Append(aCurrentFace);
// Find connected faces through shared edges
auto aFaceEdgesIter = theFaceEdges.Seek(aCurrentFace);
if (aFaceEdgesIter)
{
const NCollection_Array1<TopoDS_Edge>& aFaceEdgesArray = *aFaceEdgesIter;
for (int anEdgeIdx = aFaceEdgesArray.Lower(); anEdgeIdx <= aFaceEdgesArray.Upper();
++anEdgeIdx)
{
const TopoDS_Edge& anEdge = aFaceEdgesArray.Value(anEdgeIdx);
auto anEdgeFacesPtr = theEdgeFaces.Seek(anEdge);
if (anEdgeFacesPtr)
{
const NCollection_DynamicArray<TopoDS_Face>& aConnectedFaces = *anEdgeFacesPtr;
for (int aFaceIdx = 0; aFaceIdx < aConnectedFaces.Length(); ++aFaceIdx)
{
const TopoDS_Face& aNeighborFace = aConnectedFaces.Value(aFaceIdx);
if (!aVisitedFaces.Contains(aNeighborFace))
{
aVisitedFaces.Add(aNeighborFace);
aStack.push(aNeighborFace);
}
}
}
}
}
}
// Insert in sorted order (largest groups first)
bool anIsInserted = false;
for (NCollection_List<NCollection_Sequence<TopoDS_Shape>>::Iterator anIter(aConnectedGroups);
anIter.More();
anIter.Next())
{
if (aConnectedGroup.Length() > anIter.Value().Length())
{
aConnectedGroups.InsertBefore(aConnectedGroup, anIter);
anIsInserted = true;
break;
}
}
if (!anIsInserted)
{
aConnectedGroups.Append(aConnectedGroup);
}
}
return aConnectedGroups;
}
/// Creates shells from connected face groups using connectivity analysis.
/// Processes only the largest connected group for shell construction, improving efficiency
/// by focusing on faces that are actually topologically connected.
/// @param theLfaces Input sequence of faces to process; returns unprocessed faces
/// @param theMapMultiConnectEdges Map of edges shared by more than 2 faces (multiconnectivity mode)
/// @param theSeqShells Output sequence of created shells
/// @param theMapFaceShells Output map linking faces to their containing shells
/// @param theErrFaces Output sequence of faces that could not be processed (e.g., Mobius-like)
/// @return true if shell construction was successful, false otherwise
static bool GetShells(
NCollection_Sequence<TopoDS_Shape>& theLfaces,
const NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>& theMapMultiConnectEdges,
NCollection_Sequence<TopoDS_Shape>& theSeqShells,
NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& theMapFaceShells,
NCollection_Sequence<TopoDS_Shape>& theErrFaces)
{
bool aDone = false;
if (!theLfaces.Length())
{
return false;
}
TopoDS_Shell nshell;
BRep_Builder B;
B.MakeShell(nshell);
bool anIsMultiConnex = !theMapMultiConnectEdges.IsEmpty();
int aFaceIdx = 1, aFacesInShellCount = 1;
NCollection_Sequence<TopoDS_Shape> aSeqUnconnectFaces;
// Using STL containers because number of faces or edges can be too high
// to keep them on flat basket OCCT map
using EdgeOrientedMap =
NCollection_DataMap<TopoDS_Edge, std::pair<bool, bool>, TopTools_ShapeMapHasher>;
using TempProcessedEdges =
NCollection_DataMap<TopoDS_Edge, std::pair<bool, bool>, TopTools_ShapeMapHasher>;
FaceEdgesMap aFaceEdges;
aFaceEdges.ReSize(theLfaces.Length());
size_t aNumberOfEdges = 0;
NCollection_DynamicArray<TopoDS_Edge> aTempEdges;
for (NCollection_Sequence<TopoDS_Shape>::Iterator anFaceIter(theLfaces); anFaceIter.More();
anFaceIter.Next())
{
aTempEdges.Clear();
TopoDS_Face aFace = TopoDS::Face(anFaceIter.Value());
for (TopExp_Explorer anEdgeExp(aFace, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next())
{
aTempEdges.Append(TopoDS::Edge(anEdgeExp.Current()));
aNumberOfEdges++;
}
NCollection_Array1<TopoDS_Edge> aFaceEdgesArray(1, static_cast<int>(aTempEdges.Length()));
for (int idx = 0; idx < aTempEdges.Length(); ++idx)
{
aFaceEdgesArray.SetValue(idx + 1, aTempEdges.Value(idx));
}
aFaceEdges.Add(aFace, std::move(aFaceEdgesArray));
}
EdgeFacesMap aEdgeFaces(static_cast<int>(aNumberOfEdges));
for (int aFaceInd = 1; aFaceInd <= aFaceEdges.Length(); ++aFaceInd)
{
const TopoDS_Face& aFace = aFaceEdges.FindKey(aFaceInd);
const NCollection_Array1<TopoDS_Edge>& aFaceEdgesArray = aFaceEdges.FindFromIndex(aFaceInd);
for (int anEdgeInd = aFaceEdgesArray.Lower(); anEdgeInd <= aFaceEdgesArray.Upper(); ++anEdgeInd)
{
const TopoDS_Edge& anEdge = aFaceEdgesArray.Value(anEdgeInd);
NCollection_DynamicArray<TopoDS_Face>& aFacesArray =
aEdgeFaces.TryBound(anEdge, NCollection_DynamicArray<TopoDS_Face>());
// Check if face already exists in the array
bool aFaceExists = false;
for (int aFaceCheckIdx = 0; aFaceCheckIdx < aFacesArray.Length(); ++aFaceCheckIdx)
{
if (aFacesArray.Value(aFaceCheckIdx).IsSame(aFace))
{
aFaceExists = true;
break;
}
}
if (aFacesArray.IsEmpty())
{
aFacesArray.SetIncrement(DEFAULT_EDGE_FACES_INCREMENT);
}
if (!aFaceExists)
{
aFacesArray.Append(aFace);
}
}
}
// Get connected groups of faces using existing connectivity data
NCollection_List<NCollection_Sequence<TopoDS_Shape>> aConnectedGroups =
GetConnectedFaceGroups(aFaceEdges, aEdgeFaces);
// Process only the largest connected group for shell construction
if (aConnectedGroups.IsEmpty())
{
return false;
}
// Some assumption that each edge can be in two orientations
aNumberOfEdges = static_cast<size_t>((aNumberOfEdges / 2) + 1);
EdgeOrientedMap aProcessedEdges(static_cast<int>(aNumberOfEdges));
NCollection_Sequence<TopoDS_Shape> aProcessingFaces = std::move(aConnectedGroups.First());
TempProcessedEdges aTempProcessedEdges(static_cast<int>(aNumberOfEdges));
for (; aFaceIdx <= aProcessingFaces.Length(); aFaceIdx++)
{
aTempProcessedEdges.Clear();
int aBadOrientationCount = 0, aGoodOrientationCount = 0;
TopoDS_Face F1 = TopoDS::Face(aProcessingFaces.Value(aFaceIdx));
// Get edges of the face
const NCollection_Array1<TopoDS_Edge>& aFaceEdgesArray = aFaceEdges.FindFromKey(F1);
for (int anEdgeInd = aFaceEdgesArray.Lower(); anEdgeInd <= aFaceEdgesArray.Upper(); ++anEdgeInd)
{
const TopoDS_Edge& edge = aFaceEdgesArray.Value(anEdgeInd);
// if multiconnexity mode is equal to true faces contains
// the same multiconnexity edges are not added to one shell.
if (anIsMultiConnex && theMapMultiConnectEdges.Contains(edge))
{
continue;
}
std::pair<bool, bool>* aProcessedEdgeIt = aProcessedEdges.ChangeSeek(edge);
if (!aProcessedEdgeIt)
{
std::pair<bool, bool>* aTempProcessedEdgeIt = aTempProcessedEdges.ChangeSeek(edge);
if (!aTempProcessedEdgeIt)
{
std::pair<bool, bool> anEdgeOrientationPair{(edge.Orientation() == TopAbs_FORWARD),
(edge.Orientation() == TopAbs_REVERSED)};
aTempProcessedEdges.Bind(edge, anEdgeOrientationPair);
}
else
{
aTempProcessedEdgeIt->first =
aTempProcessedEdgeIt->first || (edge.Orientation() == TopAbs_FORWARD);
aTempProcessedEdgeIt->second =
aTempProcessedEdgeIt->second || (edge.Orientation() == TopAbs_REVERSED);
}
continue;
}
std::pair<bool, bool>& aPair = *aProcessedEdgeIt;
const bool isDirect = aPair.first;
const bool isReversed = aPair.second;
if ((edge.Orientation() == TopAbs_FORWARD && isDirect)
|| (edge.Orientation() == TopAbs_REVERSED && isReversed))
{
aBadOrientationCount++;
}
else if ((edge.Orientation() == TopAbs_FORWARD && isReversed)
|| (edge.Orientation() == TopAbs_REVERSED && isDirect))
{
aGoodOrientationCount++;
}
if (isDirect)
{
aPair.first = false;
}
else if (isReversed)
{
aPair.second = false;
}
if (!aPair.first && !aPair.second)
{
// if edge is processed in this face it is removed from map of processed edges
aProcessedEdges.UnBind(edge);
}
}
if (!aBadOrientationCount && !aGoodOrientationCount && aTempProcessedEdges.IsEmpty())
{
continue;
}
// if face can not be added to shell it added to sequence of error faces.
if (aGoodOrientationCount != 0 && aBadOrientationCount != 0)
{
theErrFaces.Append(F1);
aProcessingFaces.Remove(aFaceIdx);
aFacesInShellCount++;
continue;
}
// Addition of face to shell. In the dependance of orientation faces in the shell
// added face can be reversed.
if ((aGoodOrientationCount != 0 || aBadOrientationCount != 0) || aFacesInShellCount == 1)
{
if (aBadOrientationCount != 0)
{
F1.Reverse();
for (TempProcessedEdges::Iterator aTempEdgeIter(aTempProcessedEdges); aTempEdgeIter.More();
aTempEdgeIter.Next())
{
const TopoDS_Edge& edge = aTempEdgeIter.Key();
const auto& anEdgeOrientationPair = aTempEdgeIter.Value();
std::pair<bool, bool> aRevertedPair{!anEdgeOrientationPair.first,
!anEdgeOrientationPair.second};
std::pair<bool, bool>* aProcessedEdgePtr = aProcessedEdges.ChangeSeek(edge);
if (!aProcessedEdgePtr)
{
aProcessedEdges.Bind(edge, aRevertedPair);
}
else
{
*aProcessedEdgePtr = aRevertedPair;
}
}
aDone = true;
}
else
{
for (TempProcessedEdges::Iterator aTempEdgeIter(aTempProcessedEdges); aTempEdgeIter.More();
aTempEdgeIter.Next())
{
const TopoDS_Edge& edge = aTempEdgeIter.Key();
const auto& anEdgeOrientationPair = aTempEdgeIter.Value();
std::pair<bool, bool>* aProcessedEdgePtr = aProcessedEdges.ChangeSeek(edge);
if (!aProcessedEdgePtr)
{
aProcessedEdges.Bind(edge, anEdgeOrientationPair);
}
else
{
aProcessedEdgePtr->first = anEdgeOrientationPair.first;
aProcessedEdgePtr->second = anEdgeOrientationPair.second;
}
}
}
aFacesInShellCount++;
B.Add(nshell, F1);
theMapFaceShells.Bind(F1, nshell);
aProcessingFaces.Remove(aFaceIdx);
// check if closed shell is obtained in multi connex mode and add to sequence of
// shells and new shell begin to construct.
// (check is n*2)
if (anIsMultiConnex && BRep_Tool::IsClosed(nshell))
{
nshell.Closed(true);
theSeqShells.Append(nshell);
TopoDS_Shell nshellnext;
B.MakeShell(nshellnext);
nshell = nshellnext;
aFacesInShellCount = 1;
}
aFaceIdx = 0;
}
// if shell contains of one face. This face is added to sequence of faces.
// This shell is removed.
if (aProcessingFaces.Length() && aFaceIdx == aProcessingFaces.Length()
&& aFacesInShellCount <= 2)
{
TopoDS_Iterator aItf(nshell, false);
if (aItf.More())
{
aSeqUnconnectFaces.Append(aItf.Value());
theMapFaceShells.UnBind(aItf.Value());
}
TopoDS_Shell nshellnext;
B.MakeShell(nshellnext);
nshell = nshellnext;
aFaceIdx = 0;
aFacesInShellCount = 1;
}
}
bool isContains = false;
for (int k = 1; k <= theSeqShells.Length() && !isContains; k++)
{
isContains = nshell.IsSame(theSeqShells.Value(k));
}
if (!isContains)
{
int numFace = 0;
TopoDS_Shape aFace;
for (TopoDS_Iterator aItf(nshell, false); aItf.More(); aItf.Next())
{
aFace = aItf.Value();
numFace++;
}
if (numFace > 1)
{
// close all closed shells in no multi connex mode
if (!anIsMultiConnex)
{
nshell.Closed(BRep_Tool::IsClosed(nshell));
}
theSeqShells.Append(nshell);
}
else if (numFace == 1)
{
if (theMapFaceShells.IsBound(aFace))
{
theMapFaceShells.UnBind(aFace);
}
aProcessingFaces.Append(aFace);
}
}
// Add all unprocessed connected groups (second group and after) to unconnected faces
int aGroupIndex = 1;
for (NCollection_List<NCollection_Sequence<TopoDS_Shape>>::Iterator aGroupIter(aConnectedGroups);
aGroupIter.More();
aGroupIter.Next(), ++aGroupIndex)
{
if (aGroupIndex == 1)
{
continue; // Skip first group (already processed)
}
const NCollection_Sequence<TopoDS_Shape>& aUnprocessedGroup = aGroupIter.Value();
for (int anUnprocFaceIdx = 1; anUnprocFaceIdx <= aUnprocessedGroup.Length(); ++anUnprocFaceIdx)
{
aSeqUnconnectFaces.Append(aUnprocessedGroup.Value(anUnprocFaceIdx));
}
}
theLfaces = std::move(aProcessingFaces);
// Add unconnected faces from the largest group that couldn't be added to shells
for (int j1 = 1; j1 <= aSeqUnconnectFaces.Length(); j1++)
{
theLfaces.Append(aSeqUnconnectFaces.Value(j1));
}
return aDone;
}
//=======================================================================
// function : AddMultiConexityFaces
// purpose : In this function faces have only of multiconnexity boundary
// are added to shells having free boundary contains the same
// multiconnexity edges as faces.
//=======================================================================
static bool AddMultiConexityFaces(
NCollection_Sequence<TopoDS_Shape>& Lface,
const NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>& aMapMultiConnectEdges,
NCollection_Sequence<TopoDS_Shape>& SeqShells,
const NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& aMapFaceShells,
const NCollection_IndexedDataMap<TopoDS_Shape,
NCollection_List<TopoDS_Shape>,
TopTools_ShapeMapHasher>& aMapEdgeFaces,
NCollection_Sequence<TopoDS_Shape>& ErrFaces,
const bool NonManifold)
{
bool done = false;
// BRep_Builder aB;
NCollection_Sequence<TopoDS_Shape> llPosibleShells;
NCollection_Sequence<TopoDS_Shape> AddShapes;
for (int i1 = 1; i1 <= Lface.Length(); i1++)
{
const TopoDS_Shape& aShape = Lface.Value(i1);
int aNbMultEdges = 0;
// Finds faces having only multiconnexity boundary.
for (TopoDS_Iterator aItWires(aShape, false); aItWires.More(); aItWires.Next())
{
int aNbEdges = 0;
for (TopoDS_Iterator aItEdges(aItWires.Value(), false); aItEdges.More();
aItEdges.Next(), aNbEdges++)
{
const TopoDS_Shape& edge = aItEdges.Value();
if (!aMapMultiConnectEdges.Contains(edge))
{
continue;
}
aNbMultEdges++;
}
if (!aNbMultEdges)
{
continue;
}
if (aNbMultEdges == aNbEdges)
{
AddShapes.Append(aShape);
}
else
{
llPosibleShells.Append(aShape);
}
}
}
// Attempt to create shell from unconnected which have not only multiconnexity boundary.
NCollection_Sequence<TopoDS_Shape> aTmpShells;
if (!llPosibleShells.IsEmpty())
{
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aMap;
NCollection_Sequence<TopoDS_Shape> aTmp;
NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> aTmpFaceShell;
if (GetShells(llPosibleShells, aMap, aTmpShells, aTmpFaceShell, aTmp))
{
for (int kk = 1; kk <= aTmpShells.Length(); kk++)
{
const TopoDS_Shape& aSh = aTmpShells.Value(kk);
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapEdges;
if (GetFreeEdges(aSh, mapEdges))
{
int nbedge = 0;
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator amapIter(mapEdges);
amapIter.More();
amapIter.Next())
{
if (aMapMultiConnectEdges.Contains(amapIter.Key()))
{
nbedge++;
}
}
if (nbedge && nbedge == mapEdges.Extent())
{
AddShapes.Append(aSh);
}
}
}
}
}
// Add chosen faces to shells.
for (int k1 = 1; k1 <= AddShapes.Length(); k1++)
{
NCollection_DataMap<TopoDS_Shape, int, TopTools_ShapeMapHasher> MapOtherShells;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> dire, reve;
const TopoDS_Shape& aSh = AddShapes.Value(k1);
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapEdges;
if (!GetFreeEdges(aSh, mapEdges))
{
continue;
}
NCollection_List<TopoDS_Shape> lfaces;
// Fill MapOtherShells which will contain shells with orientation in which selected shape aSh
// will be add.
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator amapIter(mapEdges);
amapIter.More();
amapIter.Next())
{
if (!aMapMultiConnectEdges.Contains(amapIter.Key()))
{
continue;
}
TopoDS_Edge edge = TopoDS::Edge(amapIter.Key());
if (edge.Orientation() == TopAbs_FORWARD)
{
dire.Add(edge);
}
else
{
reve.Add(edge);
}
NCollection_List<TopoDS_Shape> lf;
lf = aMapEdgeFaces.FindFromKey(edge);
lfaces.Append(lf);
}
for (NCollection_List<TopoDS_Shape>::Iterator aItl(lfaces); aItl.More(); aItl.Next())
{
TopoDS_Shape aF = aItl.Value();
if (!aMapFaceShells.IsBound(aF))
{
continue;
}
TopoDS_Shape aOthershell;
aOthershell = aMapFaceShells.Find(aF);
if (MapOtherShells.IsBound(aOthershell))
{
continue;
}
if (!NonManifold && BRep_Tool::IsClosed(aOthershell))
{
continue;
}
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapShellEdges;
GetFreeEdges(aOthershell, mapShellEdges);
bool isAdd = true;
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator amapIter1(mapEdges);
amapIter1.More() && isAdd;
amapIter1.Next())
{
isAdd = mapShellEdges.Contains(amapIter1.Key());
}
if (!isAdd)
{
continue;
}
int nbdir = 0, nbrev = 0;
// add only free face whome all edges contains in the shell as open boundary.
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator aIte(mapShellEdges);
aIte.More();
aIte.Next())
{
TopoDS_Edge edgeS = TopoDS::Edge(aIte.Key());
if (!aMapMultiConnectEdges.Contains(edgeS))
{
continue;
}
if ((edgeS.Orientation() == TopAbs_FORWARD && dire.Contains(edgeS))
|| (edgeS.Orientation() == TopAbs_REVERSED && reve.Contains(edgeS)))
{
nbrev++;
}
else if ((edgeS.Orientation() == TopAbs_FORWARD && reve.Contains(edgeS))
|| (edgeS.Orientation() == TopAbs_REVERSED && dire.Contains(edgeS)))
{
nbdir++;
}
}
if (nbdir && nbrev)
{
ErrFaces.Append(aSh);
continue;
}
if (nbdir || nbrev)
{
int isReverse = (nbrev ? 1 : 0);
MapOtherShells.Bind(aOthershell, isReverse);
}
}
if (MapOtherShells.IsEmpty())
{
// i1++;
continue;
}
// Adds face to open shells containing the same multishared edges.
// For nonmanifold mode creation ine shell from face and shells containing the same multishared
// edges.
// If one face can be added to a few shells (case of compsolid) face will be added to each
// shell.
done = true;
int FirstRev = 0, FirstInd = 0;
int ind = 0;
for (int l = 1; l <= SeqShells.Length(); l++)
{
if (!MapOtherShells.IsBound(SeqShells.Value(l)))
{
continue;
}
ind++;
int isRev = MapOtherShells.Find(SeqShells.Value(l));
TopoDS_Shape anewShape = (isRev ? aSh.Reversed() : aSh);
BRep_Builder aB1;
TopoDS_Shape aShell = SeqShells.Value(l);
if (ind == 1 || !NonManifold)
{
if (ind == 1)
{
FirstRev = isRev;
FirstInd = l;
}
for (TopExp_Explorer aE(anewShape, TopAbs_FACE); aE.More(); aE.Next())
{
aB1.Add(aShell, aE.Current());
}
SeqShells.ChangeValue(l) = aShell;
}
else if (NonManifold)
{
bool isReversed = ((isRev) || FirstRev) && (!(isRev) || !FirstRev);
aShell = SeqShells.Value(FirstInd);
for (TopoDS_Iterator aItF(SeqShells.Value(l), false); aItF.More(); aItF.Next())
{
TopoDS_Shape nF = (isReversed ? aItF.Value().Reversed() : aItF.Value());
aB1.Add(aShell, nF);
}
SeqShells.ChangeValue(FirstInd) = aShell;
SeqShells.Remove(l--);
}
}
dire.Clear();
reve.Clear();
for (TopExp_Explorer aEt(aSh, TopAbs_FACE); aEt.More(); aEt.Next())
{
for (int kk = 1; kk <= Lface.Length(); kk++)
{
if (aEt.Current().IsSame(Lface.Value(kk)))
{
Lface.Remove(kk--);
}
}
}
}
return done;
}
//=======================================================================
// function : BoxIn
// purpose : Check if one face contains inside other.
//=======================================================================
static int BoxIn(const Bnd_Box& theBox1, const Bnd_Box& theBox2)
{
int aNumIn = 0;
double aXmin1, aYmin1, aXmax1, aYmax1, aXmin2, aYmin2, aXmax2, aYmax2, aZmin1, aZmax1, aZmin2,
aZmax2;
theBox1.Get(aXmin1, aYmin1, aZmin1, aXmax1, aYmax1, aZmax1);
theBox2.Get(aXmin2, aYmin2, aZmin2, aXmax2, aYmax2, aZmax2);
if (aXmin1 == aXmin2 && aXmax1 == aXmax2 && aYmin1 == aYmin2 && aYmax1 == aYmax2
&& aZmin1 == aZmin2 && aZmax1 == aZmax2)
{
aNumIn = 0;
}
else if (aXmin1 >= aXmin2 && aXmax1 <= aXmax2 && aYmin1 >= aYmin2 && aYmax1 <= aYmax2
&& aZmin1 >= aZmin2 && aZmax1 <= aZmax2)
{
aNumIn = 1;
}
else if (aXmin1 <= aXmin2 && aXmax1 >= aXmax2 && aYmin1 <= aYmin2 && aYmax1 >= aYmax2
&& aZmin1 <= aZmin2 && aZmax1 >= aZmax2)
{
aNumIn = 2;
}
return aNumIn;
}
//=======================================================================
// function : GetClosedShells
// purpose : Check if one shell is a part from other shell.
// For case of compsolid when a few shells are created from
// the same set of faces.
//=======================================================================
static void GetClosedShells(NCollection_Sequence<TopoDS_Shape>& Shells,
NCollection_Sequence<TopoDS_Shape>& aRemainShells)
{
NCollection_Array1<Bnd_Box> aBoxes(1, Shells.Length());
for (int i = 1; i <= Shells.Length(); i++)
{
Bnd_Box Box;
BRepBndLib::AddClose(Shells.Value(i), Box);
aBoxes.SetValue(i, Box);
}
NCollection_Map<int> aMapNum;
for (int j = 1; j <= aBoxes.Length(); j++)
{
for (int k = j + 1; k <= aBoxes.Length(); k++)
{
int NumIn = BoxIn(aBoxes.Value(j), aBoxes.Value(k));
switch (NumIn)
{
case 1:
aMapNum.Add(k);
break;
case 2:
aMapNum.Add(j);
break;
default:
break;
}
}
}
for (int i1 = 1; i1 <= Shells.Length(); i1++)
{
if (!aMapNum.Contains(i1))
{
aRemainShells.Append(Shells.Value(i1));
}
}
}
//=======================================================================
// function : GlueClosedCandidate
// purpose : First, attempt to create closed shells from sequence of open shells.
//=======================================================================
static void GlueClosedCandidate(
NCollection_Sequence<TopoDS_Shape>& OpenShells,
const NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>& aMapMultiConnectEdges,
NCollection_Sequence<TopoDS_Shape>& aSeqNewShells)
{
// Creating new shells if some open shells contain the same free boundary.
for (int i = 1; i < OpenShells.Length(); i++)
{
TopoDS_Shape aShell = OpenShells.Value(i);
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapEdges1;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> dire, reve;
if (!GetFreeEdges(aShell, mapEdges1))
{
continue;
}
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator aIte(mapEdges1);
aIte.More();
aIte.Next())
{
TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
if (!aMapMultiConnectEdges.Contains(edge1))
{
break;
}
if (edge1.Orientation() == TopAbs_FORWARD)
{
dire.Add(edge1);
}
else if (edge1.Orientation() == TopAbs_REVERSED)
{
reve.Add(edge1);
}
}
if (mapEdges1.Extent() > (dire.Extent() + reve.Extent()))
{
continue;
}
// Filling map MapOtherShells which contains candidate to creation of closed shell
// with aShell.
NCollection_DataMap<TopoDS_Shape, bool, TopTools_ShapeMapHasher> MapOtherShells;
for (int j = i + 1; j <= OpenShells.Length(); j++)
{
bool isAddShell = true;
bool isReversed = false;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapEdges2;
const TopoDS_Shape& aShell2 = OpenShells.Value(j);
if (!GetFreeEdges(aShell2, mapEdges2))
{
continue;
}
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator aIte2(mapEdges2);
aIte2.More() && isAddShell;
aIte2.Next())
{
TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
if (!aMapMultiConnectEdges.Contains(edge2))
{
isAddShell = false;
break;
// continue;
}
isAddShell = (dire.Contains(edge2) || reve.Contains(edge2));
if ((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
|| (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
{
isReversed = true;
}
}
if (!isAddShell)
{
continue;
}
MapOtherShells.Bind(OpenShells.Value(j), isReversed);
}
if (MapOtherShells.IsEmpty())
{
continue;
}
if (!MapOtherShells.IsEmpty())
{
// Case of compsolid when more than two shells have the same free boundary.
NCollection_Sequence<TopoDS_Shape> aSeqCandidate;
aSeqCandidate.Append(OpenShells.Value(i));
for (NCollection_DataMap<TopoDS_Shape, bool, TopTools_ShapeMapHasher>::Iterator aIt(
MapOtherShells);
aIt.More();
aIt.Next())
{
aSeqCandidate.Append(aIt.Key());
}
// Creation of all possible shells from chosen candidate.
// And the addition of them to temporary sequence.
NCollection_Sequence<TopoDS_Shape> aTmpSeq;
for (int k = 1; k <= aSeqCandidate.Length(); k++)
{
for (int l = k + 1; l <= aSeqCandidate.Length(); l++)
{
TopoDS_Shell aNewSh;
BRep_Builder aB;
aB.MakeShell(aNewSh);
for (TopoDS_Iterator aIt1(aSeqCandidate.Value(k), false); aIt1.More(); aIt1.Next())
{
aB.Add(aNewSh, aIt1.Value());
}
bool isRev = MapOtherShells.Find(aSeqCandidate.Value(l));
if (k != 1)
{
isRev = (isRev == MapOtherShells.Find(aSeqCandidate.Value(k)));
}
for (TopExp_Explorer aExp(aSeqCandidate.Value(l), TopAbs_FACE); aExp.More(); aExp.Next())
{
TopoDS_Shape aFace = (isRev ? aExp.Current().Reversed() : aExp.Current());
aB.Add(aNewSh, aFace);
}
aTmpSeq.Append(aNewSh);
}
}
// Choice from temporary sequence shells contains different set of faces (case of compsolid)
NCollection_Sequence<TopoDS_Shape> aRemainShells;
GetClosedShells(aTmpSeq, aRemainShells);
aSeqNewShells.Append(aRemainShells);
for (int j1 = i + 1; j1 <= OpenShells.Length(); j1++)
{
if (!MapOtherShells.IsBound(OpenShells.Value(j1)))
{
continue;
}
OpenShells.Remove(j1--);
}
}
else
{
BRep_Builder aB;
TopoDS_Shape aNewShell = aShell;
TopoDS_Shape addShell;
bool isReversed = false;
for (int j1 = i + 1; j1 <= OpenShells.Length(); j1++)
{
if (!MapOtherShells.Find(OpenShells.Value(j1), isReversed))
{
continue;
}
addShell = OpenShells.Value(j1);
OpenShells.Remove(j1);
break;
}
for (TopExp_Explorer aExpF(addShell, TopAbs_FACE); aExpF.More(); aExpF.Next())
{
TopoDS_Shape aFace = aExpF.Current();
if (isReversed)
{
aFace.Reverse();
}
aB.Add(aNewShell, aFace);
}
aSeqNewShells.Append(aNewShell);
}
// OpenShells.ChangeValue(i) = aShell;
OpenShells.Remove(i--);
}
}
//=======================================================================
// function : CreateNonManifoldShells
// purpose : Attempt to create max possible shells from open shells.
//=======================================================================
static void CreateNonManifoldShells(
NCollection_Sequence<TopoDS_Shape>& SeqShells,
const NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>& aMapMultiConnectEdges)
{
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
aMap;
for (int i = 1; i <= SeqShells.Length(); i++)
{
const TopoDS_Shape& aShell = SeqShells.Value(i);
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> medeg;
TopExp::MapShapes(aShell, TopAbs_EDGE, medeg);
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator mit(
aMapMultiConnectEdges);
mit.More();
mit.Next())
{
// for(TopExp_Explorer aExp(aShell,TopAbs_EDGE); aExp.More(); aExp.Next(),nbe++) {
// TopoDS_Shape ae = aExp.Current();
const TopoDS_Shape& ae = mit.Key();
// if( aMapMultiConnectEdges.Contains(aExp.Current())) {
if (medeg.Contains(ae))
{
if (aMap.Contains(ae))
{
aMap.ChangeFromKey(ae).Append(aShell);
}
else
{
NCollection_List<TopoDS_Shape> al;
al.Append(aShell);
aMap.Add(ae, al);
}
}
}
}
NCollection_IndexedDataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> aMapShells;
for (int j = 1; j <= aMap.Extent(); j++)
{
const NCollection_List<TopoDS_Shape>& LShells = aMap.FindFromIndex(j);
TopoDS_Shell aNewShell;
BRep_Builder aB;
aB.MakeShell(aNewShell);
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapmerge;
bool ismerged = false;
int num = 1;
for (NCollection_List<TopoDS_Shape>::Iterator alit(LShells); alit.More(); alit.Next(), num++)
{
if (!aMapShells.Contains(alit.Value()))
{
for (TopExp_Explorer aEf(alit.Value(), TopAbs_FACE); aEf.More(); aEf.Next())
{
aB.Add(aNewShell, aEf.Current());
}
ismerged = true;
mapmerge.Add(alit.Value());
}
else if (ismerged)
{
TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
while (aMapShells.Contains(arshell))
{
const TopoDS_Shape& ss = aMapShells.FindFromKey(arshell);
if (ss.IsSame(arshell))
{
break;
}
arshell = ss;
}
if (!mapmerge.Contains(arshell))
{
for (TopExp_Explorer aEf(arshell, TopAbs_FACE); aEf.More(); aEf.Next())
{
aB.Add(aNewShell, aEf.Current());
}
mapmerge.Add(arshell);
}
}
else
{
TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
while (aMapShells.Contains(arshell))
{
const TopoDS_Shape& ss = aMapShells.FindFromKey(arshell);
if (ss.IsSame(arshell))
{
break;
}
arshell = ss;
}
if (num == 1)
{
for (TopExp_Explorer aEf(arshell, TopAbs_FACE); aEf.More(); aEf.Next())
{
aB.Add(aNewShell, aEf.Current());
}
mapmerge.Add(arshell);
}
else if (!mapmerge.Contains(arshell))
{
for (TopExp_Explorer aEf(arshell, TopAbs_FACE); aEf.More(); aEf.Next())
{
aB.Add(aNewShell, aEf.Current());
}
mapmerge.Add(arshell);
}
}
}
if (mapmerge.Extent() > 1 || ismerged)
{
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator alit1(mapmerge);
alit1.More();
alit1.Next())
{
const TopoDS_Shape& oldShell = alit1.Key();
// while(aMapShells.Contains(oldShell)) {
// TopoDS_Shape ss = aMapShells.FindFromKey(oldShell);
// if(ss.IsSame(oldShell)) break;
// oldShell = ss;
// }
aMapShells.Add(oldShell, aNewShell);
}
}
}
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> MapNewShells;
for (int nn = 1; nn <= SeqShells.Length(); nn++)
{
if (aMapShells.Contains(SeqShells.Value(nn)))
{
TopoDS_Shape aNewShell = aMapShells.FindFromKey(SeqShells.Value(nn));
while (aMapShells.Contains(aNewShell))
{
const TopoDS_Shape& ss = aMapShells.FindFromKey(aNewShell);
if (ss.IsSame(aNewShell))
{
break;
}
aNewShell = ss;
}
MapNewShells.Add(aNewShell);
SeqShells.Remove(nn--);
}
}
for (int ii = 1; ii <= MapNewShells.Extent(); ii++)
{
SeqShells.Append(MapNewShells.FindKey(ii));
}
}
//=======================================================================
// function : CreateClosedShell
// purpose : Attempt to create max possible shells from open shells.
//=======================================================================
static void CreateClosedShell(
NCollection_Sequence<TopoDS_Shape>& OpenShells,
const NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>& aMapMultiConnectEdges)
{
NCollection_Sequence<TopoDS_Shape> aNewShells;
// First, attempt to create closed shells.
GlueClosedCandidate(OpenShells, aMapMultiConnectEdges, aNewShells);
// Creating new shells if some open shells contain the multishared same edges.
for (int i = 1; i < OpenShells.Length(); i++)
{
bool isAddShell = false;
TopoDS_Shape aShell = OpenShells.Value(i);
bool isReversed = false;
for (int j = i + 1; j <= OpenShells.Length(); j++)
{
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapEdges1;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> dire, reve;
if (!GetFreeEdges(aShell, mapEdges1))
{
break;
}
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator aIte(mapEdges1);
aIte.More();
aIte.Next())
{
TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
if (!aMapMultiConnectEdges.Contains(edge1))
{
continue;
}
if (edge1.Orientation() == TopAbs_FORWARD)
{
dire.Add(edge1);
}
else if (edge1.Orientation() == TopAbs_REVERSED)
{
reve.Add(edge1);
}
}
if (dire.IsEmpty() && reve.IsEmpty())
{
break;
}
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> mapEdges2;
TopoDS_Shape aShell2 = OpenShells.Value(j);
if (!GetFreeEdges(aShell2, mapEdges2))
{
continue;
}
for (NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator aIte2(mapEdges2);
aIte2.More();
aIte2.Next())
{
TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
if (!aMapMultiConnectEdges.Contains(edge2))
{
continue;
}
if (!dire.Contains(edge2) && !reve.Contains(edge2))
{
continue;
}
isAddShell = true;
if ((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
|| (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
{
isReversed = true;
}
}
if (!isAddShell)
{
continue;
}
BRep_Builder aB;
for (TopExp_Explorer aExpF21(OpenShells.Value(j), TopAbs_FACE); aExpF21.More();
aExpF21.Next())
{
TopoDS_Shape aFace = aExpF21.Current();
if (isReversed)
{
aFace.Reverse();
}
aB.Add(aShell, aFace);
}
OpenShells.ChangeValue(i) = aShell;
OpenShells.Remove(j--);
}
}
OpenShells.Append(aNewShells);
}
//=================================================================================================
bool ShapeFix_Shell::FixFaceOrientation(const TopoDS_Shell& shell,
const bool isAccountMultiConex,
const bool NonManifold)
{
// myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
bool done = false;
NCollection_Sequence<TopoDS_Shape> aSeqShells;
NCollection_Sequence<TopoDS_Shape> aErrFaces; // Compound of faces like to Mebiuce leaf.
NCollection_Sequence<TopoDS_Shape> Lface;
NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> aMapFaceShells;
myShell = shell;
myShape = shell;
int aNumMultShell = 0;
int nbF = 0;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aMapAdded;
for (TopoDS_Iterator iter(shell); iter.More(); iter.Next(), nbF++)
{
if (aMapAdded.Add(iter.Value()))
{
Lface.Append(iter.Value());
}
}
if (Lface.Length() < nbF)
{
done = true;
}
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
aMapEdgeFaces;
TopExp::MapShapesAndAncestors(myShell, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aMapMultiConnectEdges;
bool isFreeBoundaries = false;
for (int k = 1; k <= aMapEdgeFaces.Extent(); k++)
{
const int aFaceCount = aMapEdgeFaces.FindFromIndex(k).Extent();
if (!isFreeBoundaries && aFaceCount == 1)
{
TopoDS_Edge E = TopoDS::Edge(aMapEdgeFaces.FindKey(k));
if (!BRep_Tool::Degenerated(E))
{
isFreeBoundaries = true;
}
}
// Finds multishared edges
else if (isAccountMultiConex && aFaceCount > 2)
{
aMapMultiConnectEdges.Add(aMapEdgeFaces.FindKey(k));
}
}
if (BRep_Tool::IsClosed(myShell) ? isFreeBoundaries : !isFreeBoundaries)
{
myShell.Closed(!isFreeBoundaries);
// clang-format off
SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed
// clang-format on
}
bool isGetShells = true;
// Gets possible shells with taking in account of multiconnexity.
while (isGetShells && Lface.Length())
{
NCollection_Sequence<TopoDS_Shape> aTmpSeqShells;
if (GetShells(Lface, aMapMultiConnectEdges, aTmpSeqShells, aMapFaceShells, aErrFaces))
{
done = true;
}
isGetShells = !aTmpSeqShells.IsEmpty();
if (isGetShells)
{
aSeqShells.Append(aTmpSeqShells);
}
}
if (!done)
{
done = (aSeqShells.Length() > 1);
}
bool aIsDone = false;
if (Lface.Length() > 0 && aSeqShells.Length())
{
for (int jj = 1; jj <= Lface.Length(); jj++)
{
if (aMapFaceShells.IsBound(Lface.Value(jj)))
{
aMapFaceShells.UnBind(Lface.Value(jj));
}
}
// Addition of faces having only multiconnexity boundary to shells having holes
// containing only the multiconnexity edges
aIsDone = AddMultiConexityFaces(Lface,
aMapMultiConnectEdges,
aSeqShells,
aMapFaceShells,
aMapEdgeFaces,
aErrFaces,
NonManifold);
}
aNumMultShell = aSeqShells.Length();
if (!aErrFaces.IsEmpty())
{
// if Shell contains of Mebius faces one shell will be created from each those face.
BRep_Builder B;
B.MakeCompound(myErrFaces);
TopoDS_Compound aCompShells;
B.MakeCompound(aCompShells);
for (int n = 1; n <= aErrFaces.Length(); n++)
{
B.Add(myErrFaces, aErrFaces.Value(n));
}
if (aNumMultShell)
{
if (aNumMultShell == 1)
{
B.Add(aCompShells, aSeqShells.Value(1));
for (int n1 = 1; n1 <= aErrFaces.Length(); n1++)
{
TopoDS_Shell aSh;
B.MakeShell(aSh);
B.Add(aSh, aErrFaces.Value(n1));
B.Add(aCompShells, aSh);
}
myShape = aCompShells;
}
else
{
for (int i = 1; i <= aSeqShells.Length(); i++)
{
B.Add(aCompShells, aSeqShells.Value(i));
}
for (int n1 = 1; n1 <= aErrFaces.Length(); n1++)
{
TopoDS_Shell aSh;
B.MakeShell(aSh);
B.Add(aSh, aErrFaces.Value(n1));
B.Add(aCompShells, aSh);
}
myShape = aCompShells;
}
}
done = true;
myStatus = ShapeExtend::EncodeStatus(ShapeExtend_FAIL);
// clang-format off
SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG20" ) );// Impossible to orient faces in shell, several shells created
// clang-format on
return true;
}
if (aNumMultShell > 1)
{
NCollection_Sequence<TopoDS_Shape> OpenShells;
for (int i1 = 1; i1 <= aSeqShells.Length(); i1++)
{
TopoDS_Shape aShell = aSeqShells.Value(i1);
if (!BRep_Tool::IsClosed(aShell))
{
OpenShells.Append(aShell);
aSeqShells.Remove(i1--);
}
}
if (OpenShells.Length() > 1)
{
// Attempt of creation closed shell from open shells with taking into account multiconnexity.
CreateClosedShell(OpenShells, aMapMultiConnectEdges);
}
aSeqShells.Append(OpenShells);
}
// In the case if NonManifold is equal to true one non-manifold shell will be created.
// Else compound from shells will be created if length of sequence of shape >1.
if (Lface.Length())
{
for (int i = 1; i <= Lface.Length(); i++)
{
BRep_Builder aB;
TopoDS_Shell OneShell;
aB.MakeShell(OneShell);
aB.Add(OneShell, Lface.Value(i));
aSeqShells.Append(OneShell);
}
}
if (NonManifold && aSeqShells.Length() > 1)
{
CreateNonManifoldShells(aSeqShells, aMapMultiConnectEdges);
}
if (!done)
{
done = (aSeqShells.Length() > 1 || aIsDone);
}
if (aSeqShells.Length() == 1)
{
myShell = TopoDS::Shell(aSeqShells.Value(1));
myShape = myShell;
myNbShells = 1;
}
else
{
BRep_Builder B;
TopoDS_Compound aCompShells;
B.MakeCompound(aCompShells);
for (int i = 1; i <= aSeqShells.Length(); i++)
{
B.Add(aCompShells, aSeqShells.Value(i));
}
myShape = aCompShells;
myNbShells = aSeqShells.Length();
}
if (done)
{
myStatus = ShapeExtend::EncodeStatus(ShapeExtend_DONE2);
if (!Context().IsNull())
{
Context()->Replace(shell, myShape);
}
if (myNbShells == 1)
{
// clang-format off
SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG0" ) );// Faces were incorrectly oriented in the shell, corrected
} else {
SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG30" ) );// Improperly connected shell split into parts
}
// clang-format on
return true;
}
else
{
return false;
}
}
//=================================================================================================
bool ShapeFix_Shell::Status(const ShapeExtend_Status status) const
{
return ShapeExtend::DecodeStatus(myStatus, status);
}
//=================================================================================================
TopoDS_Shell ShapeFix_Shell::Shell()
{
return myShell;
}
//=================================================================================================
TopoDS_Shape ShapeFix_Shell::Shape()
{
return myShape;
}
//=================================================================================================
TopoDS_Compound ShapeFix_Shell::ErrorFaces() const
{
return myErrFaces;
}
//=================================================================================================
void ShapeFix_Shell::SetMsgRegistrator(const occ::handle<ShapeExtend_BasicMsgRegistrator>& msgreg)
{
ShapeFix_Root::SetMsgRegistrator(msgreg);
myFixFace->SetMsgRegistrator(msgreg);
}
//=================================================================================================
void ShapeFix_Shell::SetPrecision(const double preci)
{
ShapeFix_Root::SetPrecision(preci);
myFixFace->SetPrecision(preci);
}
//=================================================================================================
void ShapeFix_Shell::SetMinTolerance(const double mintol)
{
ShapeFix_Root::SetMinTolerance(mintol);
myFixFace->SetMinTolerance(mintol);
}
//=================================================================================================
void ShapeFix_Shell::SetMaxTolerance(const double maxtol)
{
ShapeFix_Root::SetMaxTolerance(maxtol);
myFixFace->SetMaxTolerance(maxtol);
}
//=================================================================================================
int ShapeFix_Shell::NbShells() const
{
return myNbShells;
}
//=================================================================================================
void ShapeFix_Shell::SetNonManifoldFlag(const bool isNonManifold)
{
myNonManifold = isNonManifold;
}