1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-05-21 10:55:33 +03:00
occt/src/BRepCheck/BRepCheck_Shell.cxx
abv ab860031bd 0025202: Incorrect value of IsClosed flag in shapes produced by some algorithms
Method BRep_Tool::IsClosed() extended to analyze closure of wires in addition to shells and solids.
External and Internal edges and vertices are ignored in this check.
Analysis of compounds is disabled.

Update of flag Closed according to actual state is added in most places where new shells are constructed.

Draw-command and test case for issue CR25202
2014-10-10 16:28:36 +04:00

936 lines
24 KiB
C++

// Created on: 1995-12-12
// Created by: Jacques GOUSSARD
// Copyright (c) 1995-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.
#include <BRepCheck_Shell.ixx>
#include <BRepCheck_ListOfStatus.hxx>
#include <BRepCheck_ListIteratorOfListOfStatus.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_MapIteratorOfMapOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <BRep_Tool.hxx>
#include <BRep_Builder.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepCheck.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
#include <TopTools_DataMapOfShapeInteger.hxx>
//=======================================================================
//function : Propagate
//purpose :
//=======================================================================
static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape& mapEF,
const TopoDS_Shape& fac,
TopTools_MapOfShape& mapF)
{
if (mapF.Contains(fac))
{
return;
}
mapF.Add(fac); // attention, if oriented == Standard_True, fac should
// be FORWARD or REVERSED. It is not checked.
TopTools_MapIteratorOfMapOfShape itf(mapF);
while(itf.More())
{
Standard_Boolean hasBeenAdded = Standard_False;
const TopoDS_Shape& fac = itf.Key();
TopExp_Explorer ex;
for (ex.Init(fac,TopAbs_EDGE); ex.More(); ex.Next())
{
const TopoDS_Edge& edg = TopoDS::Edge(ex.Current());
// test if the edge is in the map (only orienteed edges are present)
if (mapEF.Contains(edg))
{
for (TopTools_ListIteratorOfListOfShape itl(mapEF.FindFromKey(edg)); itl.More(); itl.Next())
{
if (!itl.Value().IsSame(fac) && !mapF.Contains(itl.Value()))
{
mapF.Add(itl.Value());
hasBeenAdded = Standard_True;
}
}
}
}//for (ex.Init(fac,TopAbs_EDGE); ex.More();)
if(hasBeenAdded)
{
itf.Initialize(mapF);
}
else
{
itf.Next();
}
}
}
//=======================================================================
//function : BRepCheck_Trace
//purpose :
//=======================================================================
Standard_EXPORT Standard_Integer BRepCheck_Trace(const Standard_Integer phase) {
static int BRC_Trace = 0;
if (phase < 0) BRC_Trace =0;
else if (phase > 0) BRC_Trace=phase;
return BRC_Trace;
}
void PrintShape(const TopoDS_Shape& theShape, const Standard_Integer upper) {
if (!theShape.IsNull()) {
Standard_Integer code = theShape.HashCode(upper);
switch (theShape.ShapeType()) {
case TopAbs_COMPOUND :
cout << "COMPOUND";
break;
case TopAbs_COMPSOLID :
cout << "COMPSOLID";
break;
case TopAbs_SOLID :
cout << "SOLID";
break;
case TopAbs_SHELL :
cout << "SHELL";
break;
case TopAbs_FACE :
cout << "FACE";
break;
case TopAbs_WIRE :
cout << "WIRE";
break;
case TopAbs_EDGE :
cout << "EDGE";
break;
case TopAbs_VERTEX :
cout << "VERTEX";
break;
case TopAbs_SHAPE :
cout << "SHAPE";
break;
}
cout << " : " << code << " ";
switch (theShape.Orientation()) {
case TopAbs_FORWARD :
cout << "FORWARD";
break;
case TopAbs_REVERSED :
cout << "REVERSED";
break;
case TopAbs_INTERNAL :
cout << "INTERNAL";
break;
case TopAbs_EXTERNAL :
cout << "EXTERNAL";
break;
}
cout << endl;
}
}
//=======================================================================
//function : IsOriented
//purpose :
//=======================================================================
inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
{
return (S.Orientation() == TopAbs_FORWARD ||
S.Orientation() == TopAbs_REVERSED);
}
//=======================================================================
//function : BRepCheck_Shell
//purpose :
//=======================================================================
BRepCheck_Shell::BRepCheck_Shell(const TopoDS_Shell& S)
{
Init(S);
}
//=======================================================================
//function : Minimum
//purpose :
//=======================================================================
void BRepCheck_Shell::Minimum()
{
myCdone = Standard_False;
myOdone = Standard_False;
if (!myMin)
{
BRepCheck_ListOfStatus thelist;
myMap.Bind(myShape, thelist);
BRepCheck_ListOfStatus& lst = myMap(myShape);
// it is checked if the shell is "connected"
TopExp_Explorer exp(myShape,TopAbs_FACE);
Standard_Integer nbface = 0;
myMapEF.Clear();
for (; exp.More(); exp.Next())
{
nbface++;
TopExp_Explorer expe;
for (expe.Init(exp.Current(),TopAbs_EDGE);
expe.More(); expe.Next())
{
const TopoDS_Shape& edg = expe.Current();
Standard_Integer index = myMapEF.FindIndex(edg);
if (index == 0)
{
TopTools_ListOfShape thelist1;
index = myMapEF.Add(edg, thelist1);
}
myMapEF(index).Append(exp.Current());
}
}//for (; exp.More(); exp.Next())
if (nbface == 0)
{
BRepCheck::Add(lst,BRepCheck_EmptyShell);
}
else if (nbface >= 2)
{
TopTools_MapOfShape mapF;
exp.ReInit();
Propagate(myMapEF,exp.Current(),mapF);
if (mapF.Extent() != nbface)
{
BRepCheck::Add(lst,BRepCheck_NotConnected);
}
}//else if (nbface >= 2)
if (lst.IsEmpty())
{
lst.Append(BRepCheck_NoError);
}
myMapEF.Clear();
myMin = Standard_True;
}
}
//=======================================================================
//function : InContext
//purpose :
//=======================================================================
void BRepCheck_Shell::InContext(const TopoDS_Shape& S)
{
if (myMap.IsBound(S)) {
return;
}
BRepCheck_ListOfStatus thelist;
myMap.Bind(S, thelist);
BRepCheck_ListOfStatus& lst = myMap(S);
// for (TopExp_Explorer exp(S,TopAbs_SHELL); exp.More(); exp.Next()) {
TopExp_Explorer exp(S,TopAbs_SHELL) ;
for ( ; exp.More(); exp.Next()) {
if (exp.Current().IsSame(myShape)) {
break;
}
}
if (!exp.More()) {
BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
return;
}
TopAbs_ShapeEnum styp = S.ShapeType();
switch (styp) {
case TopAbs_SOLID:
{
BRepCheck_Status fst = Closed();
if ((fst == BRepCheck_NotClosed && S.Closed()) ||
(fst != BRepCheck_NoError)) {
BRepCheck::Add(lst,fst);
}
else if (!IsUnorientable()) {
fst = Orientation();
BRepCheck::Add(lst,fst);
}
}
break;
default:
break;
}
if (lst.IsEmpty()) {
lst.Append(BRepCheck_NoError);
}
}
//=======================================================================
//function : Blind
//purpose :
//=======================================================================
void BRepCheck_Shell::Blind()
{
if (!myBlind) {
// nothing more than in the minimum
myBlind = Standard_True;
}
}
//=======================================================================
//function : Closed
//purpose :
//=======================================================================
BRepCheck_Status BRepCheck_Shell::Closed(const Standard_Boolean Update)
{
if (myCdone)
{
if (Update)
{
BRepCheck::Add(myMap(myShape), myCstat);
}
return myCstat;
}
myCdone = Standard_True; // it will be done...
BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
if (itl.Value() != BRepCheck_NoError)
{
myCstat = itl.Value();
return myCstat; // already saved
}
myCstat = BRepCheck_NoError;
//
Standard_Integer index, aNbF;
TopExp_Explorer exp, ede;
TopTools_MapOfShape mapS, aMEToAvoid;
myMapEF.Clear();
// Checks if the oriented faces of the shell give a "closed" shell,
// i-e if each oriented edge on oriented faces is found 2 times.
//
//modified by NIZNHY-PKV Mon Jun 4 13:59:21 2007f
exp.Init(myShape,TopAbs_FACE);
for (; exp.More(); exp.Next())
{
const TopoDS_Shape& aF=exp.Current();
if (IsOriented(aF))
{
ede.Init(exp.Current(),TopAbs_EDGE);
for (; ede.More(); ede.Next())
{
const TopoDS_Shape& aE=ede.Current();
if (!IsOriented(aE))
{
aMEToAvoid.Add(aE);
}
}
}
}
//modified by NIZNHY-PKV Mon Jun 4 13:59:23 2007t
//
exp.Init(myShape,TopAbs_FACE);
for (; exp.More(); exp.Next())
{
const TopoDS_Shape& aF=exp.Current();
if (IsOriented(aF))
{
if (!mapS.Add(aF))
{
myCstat = BRepCheck_RedundantFace;
if (Update)
{
BRepCheck::Add(myMap(myShape),myCstat);
}
return myCstat;
}
//
ede.Init(exp.Current(),TopAbs_EDGE);
for (; ede.More(); ede.Next())
{
const TopoDS_Shape& aE=ede.Current();
//modified by NIZNHY-PKV Mon Jun 4 14:07:57 2007f
//if (IsOriented(aE)) {
if (!aMEToAvoid.Contains(aE))
{
//modified by NIZNHY-PKV Mon Jun 4 14:08:01 2007
index = myMapEF.FindIndex(aE);
if (!index)
{
TopTools_ListOfShape thelist;
index = myMapEF.Add(aE, thelist);
}
myMapEF(index).Append(aF);
}
}
}
}
//
myNbori = mapS.Extent();
if (myNbori >= 2)
{
mapS.Clear();
// Search for the first oriented face
TopoDS_Shape aF;
exp.Init(myShape, TopAbs_FACE);
for (;exp.More(); exp.Next())
{
aF=exp.Current();
if (IsOriented(aF))
{
break;
}
}
Propagate(myMapEF, aF, mapS);
}
//
//
aNbF=mapS.Extent();
if (myNbori != aNbF)
{
myCstat = BRepCheck_NotConnected;
if (Update)
{
BRepCheck::Add(myMap(myShape),myCstat);
}
return myCstat;
}
//
//
Standard_Integer i, Nbedges, nboc, nbSet;
//
Nbedges = myMapEF.Extent();
for (i = 1; i<=Nbedges; ++i)
{
nboc = myMapEF(i).Extent();
if (nboc == 0 || nboc >= 3)
{
TopTools_ListOfShape theSet;
nbSet=NbConnectedSet(theSet);
// If there is more than one closed cavity the shell is considered invalid
// this corresponds to the criteria of a solid (not those of a shell)
if (nbSet>1)
{
myCstat = BRepCheck_InvalidMultiConnexity;
if (Update)
{
BRepCheck::Add(myMap(myShape),myCstat);
}
return myCstat;
}
}
else if (nboc == 1)
{
if (!BRep_Tool::Degenerated(TopoDS::Edge(myMapEF.FindKey(i))))
{
myCstat=BRepCheck_NotClosed;
if (Update)
{
BRepCheck::Add(myMap(myShape),myCstat);
}
return myCstat;
}
}
}
if (Update) {
BRepCheck::Add(myMap(myShape),myCstat);
}
return myCstat;
}
//=======================================================================
//function : Orientation
//purpose :
//=======================================================================
BRepCheck_Status BRepCheck_Shell::Orientation(const Standard_Boolean Update)
{
if (myOdone) {
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
return myOstat;
}
myOdone = Standard_True;
myOstat = Closed();
if (myOstat != BRepCheck_NotClosed && myOstat != BRepCheck_NoError) {
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
return myOstat;
}
myOstat = BRepCheck_NoError;
// First the orientation of each face in relation to the shell is found.
// It is used to check BRepCheck_RedundantFace
TopTools_DataMapOfShapeInteger MapOfShapeOrientation;
TopExp_Explorer exp,ede;
for (exp.Init(myShape,TopAbs_FACE); exp.More(); exp.Next()) {
if (!MapOfShapeOrientation.Bind(exp.Current(), (Standard_Integer)(exp.Current().Orientation()))) {
myOstat = BRepCheck_RedundantFace;
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
else {
return myOstat;
}
}
}
#ifdef DEB
if (BRepCheck_Trace(0) > 1) {
TopTools_DataMapIteratorOfDataMapOfShapeInteger itt(MapOfShapeOrientation);
Standard_Integer upper = MapOfShapeOrientation.NbBuckets();
cout << "La map shape Orientation :" << endl;
for (; itt.More(); itt.Next()) {
PrintShape(itt.Key(), upper);
}
cout << endl;
}
#endif
// Then the orientation of faces by their connectivity is checked
// BRepCheck_BadOrientationOfSubshape and
// BRepCheck_SubshapeNotInShape are checked;
Standard_Integer Nbedges = myMapEF.Extent();
TopoDS_Face Fref;
TopAbs_Orientation orf;
for (Standard_Integer i = 1; i<= Nbedges; i++) {
const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(i));
if (BRep_Tool::Degenerated(edg)) continue;
TopTools_ListOfShape& lface = myMapEF(i);
TopTools_ListIteratorOfListOfShape lite(lface);
if (lface.Extent() <= 2)
{
lite.Initialize(lface);
Fref = TopoDS::Face(lite.Value());
if (!MapOfShapeOrientation.IsBound(Fref)) {
myOstat = BRepCheck_SubshapeNotInShape;
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
// quit because no workaround for the incoherence is possible
return myOstat;
}
lite.Next();
if (lite.More()) { // Edge of connectivity
//JR/Hp :
Standard_Integer iorf = MapOfShapeOrientation.Find(Fref);
orf = (TopAbs_Orientation) iorf;
//orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
Fref.Orientation(orf);
// edge is examined
if (!lite.Value().IsSame(Fref)) { // edge non "closed"
for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
if (ede.Current().IsSame(edg)) {
break;
}
}
TopAbs_Orientation orient = ede.Current().Orientation();
TopoDS_Face Fcur= TopoDS::Face(lite.Value());
if (!MapOfShapeOrientation.IsBound(Fcur)) {
myOstat = BRepCheck_SubshapeNotInShape;
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
// quit because no workaround for the incoherence is possible
return myOstat;
}
//JR/Hp :
Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
orf = (TopAbs_Orientation) iorf ;
// orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
Fcur.Orientation(orf);
for (ede.Init(Fcur, TopAbs_EDGE); ede.More(); ede.Next()) {
if (ede.Current().IsSame(edg)) {
break;
}
}
if (ede.Current().Orientation() == orient) {
// The loop is continued on the edges as many times
// as the same edge is present in the wire
// modified by NIZHNY-MKK Tue Sep 30 11:11:42 2003
Standard_Boolean bfound = Standard_False;
ede.Next();
for (; ede.More(); ede.Next()) {
if (ede.Current().IsSame(edg)) {
// modified by NIZHNY-MKK Tue Sep 30 11:12:03 2003
bfound = Standard_True;
break;
}
}
// if (ede.Current().Orientation() == orient) {
// modified by NIZHNY-MKK Thu Oct 2 17:56:47 2003
if (!bfound || (ede.Current().Orientation() == orient)) {
myOstat = BRepCheck_BadOrientationOfSubshape;
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
break;
}
return myOstat;
}
}
}
}
}
else //more than two faces
{
Standard_Integer numF = 0, numR = 0;
TopTools_MapOfShape Fmap;
for (lite.Initialize(lface); lite.More(); lite.Next())
{
TopoDS_Face Fcur= TopoDS::Face(lite.Value());
if (!MapOfShapeOrientation.IsBound(Fcur))
{
myOstat = BRepCheck_SubshapeNotInShape;
if (Update)
BRepCheck::Add(myMap(myShape), myOstat);
// quit because no workaround for the incoherence is possible
return myOstat;
}
Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur);
orf = (TopAbs_Orientation) iorf;
//orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
Fcur.Orientation(orf);
for (ede.Init(Fcur,TopAbs_EDGE); ede.More(); ede.Next())
if (ede.Current().IsSame(edg))
break;
if (Fmap.Contains(Fcur)) //edge is "closed" on Fcur, we meet Fcur twice
{
ede.Next();
for (; ede.More(); ede.Next())
if (ede.Current().IsSame(edg))
break;
}
TopAbs_Orientation orient = ede.Current().Orientation();
if (orient == TopAbs_FORWARD)
numF++;
else
numR++;
Fmap.Add(Fcur);
}
if (numF != numR)
{
myOstat = BRepCheck_BadOrientationOfSubshape;
if (Update)
{
BRepCheck::Add(myMap(myShape), myOstat);
break;
}
return myOstat;
}
}
}
// If at least one incorrectly oriented face has been found, it is checked if the shell can be oriented.
// i.e. : if by modification of the orientation of a face it is possible to find
// a coherent orientation. (it is not possible on a Moebius band)
// BRepCheck_UnorientableShape is checked
if (myOstat == BRepCheck_BadOrientationOfSubshape) {
if (!Fref.IsNull()) {
if (Nbedges > 0) {
TopTools_MapOfShape alre;
TopTools_ListOfShape voisin;
voisin.Append(Fref);
alre.Clear();
while (!voisin.IsEmpty()) {
Fref=TopoDS::Face(voisin.First());
voisin.RemoveFirst();
if (!MapOfShapeOrientation.IsBound(Fref)) {
myOstat = BRepCheck_SubshapeNotInShape;
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
// quit because no workaround for the incoherence is possible
return myOstat;
}
//JR/Hp :
Standard_Integer iorf = MapOfShapeOrientation.Find(Fref) ;
orf = (TopAbs_Orientation) iorf ;
// orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
Fref.Orientation(orf);
#ifdef DEB
if (BRepCheck_Trace(0) > 3) {
cout << "Fref : " ;
PrintShape(Fref, MapOfShapeOrientation.NbBuckets());
}
#endif
TopExp_Explorer edFcur;
alre.Add(Fref);
for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
const TopoDS_Edge& edg = TopoDS::Edge(ede.Current());
TopAbs_Orientation orient = edg.Orientation();
TopTools_ListOfShape& lface = myMapEF.ChangeFromKey(edg);
TopTools_ListIteratorOfListOfShape lite(lface);
TopoDS_Face Fcur= TopoDS::Face(lite.Value());
if (Fcur.IsSame(Fref)) {
lite.Next();
if (lite.More()) {
Fcur=TopoDS::Face(lite.Value());
}
else {
// from the free border one goes to the next edge
continue;
}
}
if (!MapOfShapeOrientation.IsBound(Fcur)) {
myOstat = BRepCheck_SubshapeNotInShape;
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
// quit because no workaround for the incoherence is possible
return myOstat;
}
//JR/Hp :
Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
orf = (TopAbs_Orientation) iorf ;
// orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
Fcur.Orientation(orf);
#ifdef DEB
if (BRepCheck_Trace(0) > 3) {
cout << " Fcur : " ;
PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
}
#endif
for (edFcur.Init(Fcur, TopAbs_EDGE); edFcur.More(); edFcur.Next()) {
if (edFcur.Current().IsSame(edg)) {
break;
}
}
if (edFcur.Current().Orientation() == orient) {
if (alre.Contains(Fcur)) {
// It is necessary to return a face that has been already examined or returned
// if one gets nowhere, the shell cannot be oriented.
myOstat = BRepCheck_UnorientableShape;
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
// quit, otherwise there is a risk of taking too much time.
#ifdef DEB
if (BRepCheck_Trace(0) > 3) {
orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
Fcur.Orientation(orf);
cout << " Error : this face has been already examined " << endl;
cout << " Imposible to return it ";
PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
}
#endif
return myOstat;
}
orf = TopAbs::Reverse(orf);
MapOfShapeOrientation(Fcur)=orf;
#ifdef DEB
if (BRepCheck_Trace(0) > 3) {
orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
Fcur.Orientation(orf);
cout << " Resulting Fcur is returned : " ;
PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
}
#endif
}
if (alre.Add(Fcur)) {
voisin.Append(Fcur);
}
}
}
}
}
}
if (Update) {
BRepCheck::Add(myMap(myShape), myOstat);
}
return myOstat;
}
//=======================================================================
//function : SetUnorientable
//purpose :
//=======================================================================
void BRepCheck_Shell::SetUnorientable()
{
BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
}
//=======================================================================
//function : IsUnorientable
//purpose :
//=======================================================================
Standard_Boolean BRepCheck_Shell::IsUnorientable() const
{
if (myOdone) {
return (myOstat != BRepCheck_NoError);
}
for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
itl.More();
itl.Next()) {
if (itl.Value() == BRepCheck_UnorientableShape) {
return Standard_True;
}
}
return Standard_False;
}
//=======================================================================
//function : NbConnectedSet
//purpose :
//=======================================================================
Standard_Integer BRepCheck_Shell::NbConnectedSet(TopTools_ListOfShape& theSets)
{
// The connections are found
TopTools_IndexedDataMapOfShapeListOfShape parents;
TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, parents);
// All faces are taken
TopTools_MapOfShape theFaces;
TopExp_Explorer exsh(myShape, TopAbs_FACE);
for (; exsh.More(); exsh.Next()) theFaces.Add(exsh.Current());
// The edges that are not oriented or have more than 2 connections are missing
Standard_Integer iCur;
TopTools_MapOfShape theMultiEd;
TopTools_MapOfShape theUnOriEd;
for (iCur=1; iCur<=parents.Extent(); iCur++) {
const TopoDS_Edge& Ed = TopoDS::Edge(parents.FindKey(iCur));
if (parents(iCur).Extent()> 2) theMultiEd.Add(Ed);
if (Ed.Orientation()!=TopAbs_REVERSED &&
Ed.Orientation()!=TopAbs_FORWARD) theUnOriEd.Add(Ed);
}
// Starting from multiconnected edges propagation by simple connections
TopTools_ListIteratorOfListOfShape lconx1, lconx2;
TopTools_MapIteratorOfMapOfShape itmsh(theMultiEd);
TopoDS_Shell CurShell;
TopoDS_Shape adFac;
TopTools_ListOfShape lesCur;
BRep_Builder BRB;
Standard_Boolean newCur=Standard_True;
BRB.MakeShell(CurShell);
for (; itmsh.More(); itmsh.Next()) {
const TopoDS_Shape& Ed = itmsh.Key();
if (!theUnOriEd.Contains(Ed)) {
for (lconx1.Initialize(parents.FindFromKey(Ed)); lconx1.More(); lconx1.Next()) {
if (theFaces.Contains(lconx1.Value())) {
adFac=lconx1.Value();
BRB.Add(CurShell, adFac);
theFaces.Remove(adFac);
newCur=Standard_False;
if (theFaces.IsEmpty()) break;
lesCur.Append(adFac);
while (!lesCur.IsEmpty()) {
adFac=lesCur.First();
lesCur.RemoveFirst();
for (exsh.Init(adFac, TopAbs_EDGE); exsh.More(); exsh.Next()) {
const TopoDS_Shape& ced = exsh.Current();
if (!theMultiEd.Contains(ced)) {
for (lconx2.Initialize(parents.FindFromKey(ced)); lconx2.More(); lconx2.Next()) {
if (theFaces.Contains(lconx2.Value())) {
adFac=lconx2.Value();
BRB.Add(CurShell, adFac);
theFaces.Remove(adFac);
newCur=Standard_False;
if (theFaces.IsEmpty()) break;
lesCur.Append(adFac);
}
}
}
if (theFaces.IsEmpty()) break;
}
}
if (!newCur) {
CurShell.Closed (BRep_Tool::IsClosed (CurShell));
theSets.Append(CurShell);
CurShell.Nullify();
newCur=Standard_True;
BRB.MakeShell(CurShell);
}
}
if (theFaces.IsEmpty()) break;
}
}
if (theFaces.IsEmpty()) break;
}
return theSets.Extent();
}