1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-05 18:16:23 +03:00
occt/src/ShapeFix/ShapeFix_Shell.cxx
abv 42cf5bc1ca 0024002: Overall code and build procedure refactoring -- automatic
Automatic upgrade of OCCT code by command "occt_upgrade . -nocdl":
- WOK-generated header files from inc and sources from drv are moved to src
- CDL files removed
- All packages are converted to nocdlpack
2015-07-12 07:42:38 +03:00

1104 lines
41 KiB
C++

// 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_Array1OfBox.hxx>
#include <Bnd_Box.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepBndLib.hxx>
#include <Message_Msg.hxx>
#include <Message_ProgressIndicator.hxx>
#include <Message_ProgressSentry.hxx>
#include <Precision.hxx>
#include <ShapeAnalysis_Shell.hxx>
#include <ShapeBuild_ReShape.hxx>
#include <ShapeExtend.hxx>
#include <ShapeExtend_BasicMsgRegistrator.hxx>
#include <ShapeFix_Face.hxx>
#include <ShapeFix_Shell.hxx>
#include <Standard_Type.hxx>
#include <TColStd_DataMapOfIntegerListOfInteger.hxx>
#include <TColStd_MapOfInteger.hxx>
#include <TColStd_SequenceOfInteger.hxx>
#include <TopAbs.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_DataMapIteratorOfDataMapOfShapeInteger.hxx>
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_DataMapOfShapeShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeShape.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_MapIteratorOfMapOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_SequenceOfShape.hxx>
//=======================================================================
//function : ShapeFix_Shell
//purpose :
//=======================================================================
ShapeFix_Shell::ShapeFix_Shell()
{
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
myFixFaceMode = -1;
myFixOrientationMode = -1;
myFixFace = new ShapeFix_Face;
myNbShells =0;
}
//=======================================================================
//function : ShapeFix_Shell
//purpose :
//=======================================================================
ShapeFix_Shell::ShapeFix_Shell(const TopoDS_Shell& shape)
{
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
myFixFaceMode = -1;
myFixOrientationMode = -1;
myFixFace = new ShapeFix_Face;
Init(shape);
}
//=======================================================================
//function : Init
//purpose :
//=======================================================================
void ShapeFix_Shell::Init(const TopoDS_Shell& shell)
{
myShape = shell;
myShell = shell;
myNbShells =0;
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
Standard_Boolean ShapeFix_Shell::Perform(const Handle(Message_ProgressIndicator)& theProgress)
{
Standard_Boolean status = Standard_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
Standard_Integer aNbFaces = 0;
for ( TopExp_Explorer aFaceExp(S, TopAbs_FACE); aFaceExp.More(); aFaceExp.Next() )
++aNbFaces;
// Start progress scope (no need to check if progress exists -- it is safe)
Message_ProgressSentry aPSentry(theProgress, "Fixing face", 0, aNbFaces, 1);
for( TopoDS_Iterator iter(S); iter.More() && aPSentry.More(); iter.Next(), aPSentry.Next() )
{
TopoDS_Shape sh = iter.Value();
TopoDS_Face tmpFace = TopoDS::Face(sh);
myFixFace->Init(tmpFace);
if ( myFixFace->Perform() )
{
status = Standard_True;
myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
}
}
// Halt algorithm in case of user's abort
if ( !aPSentry.More() )
return Standard_False;
}
TopoDS_Shape newsh = Context()->Apply(myShell);
if ( NeedFix ( myFixOrientationMode) )
FixFaceOrientation(TopoDS::Shell(newsh));
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, Standard_True);
if (aSas.HasFreeEdges())
{
aCurShell.Closed (Standard_False);
SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed
}
aSas.Clear();
}
}
if ( status )
myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
if(Status(ShapeExtend_DONE2))
status = Standard_True;
return status;
}
//=======================================================================
// function : GetFreeEdges
// purpose :
//=======================================================================
static Standard_Boolean GetFreeEdges(const TopoDS_Shape& aShape,TopTools_MapOfShape& 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.Extent());
}
//=======================================================================
// function : GetShells
// purpose : If mode isMultiConnex = Standard_True gets max possible shell for
// exception of multiconnexity parts.
// Else if this mode is equal to Standard_False maximum possible
// shell will be created without taking account of multiconnexity.
// In this function map face - shell and sequence of mebius faces is formed.
//=======================================================================
static Standard_Boolean GetShells(TopTools_SequenceOfShape& Lface,
const TopTools_MapOfShape& aMapMultiConnectEdges,
TopTools_SequenceOfShape& aSeqShells,
TopTools_DataMapOfShapeShape& aMapFaceShells,
TopTools_SequenceOfShape& ErrFaces)
{
Standard_Boolean done = Standard_False;
if(!Lface.Length()) return Standard_False;
TopoDS_Shell nshell;
TopTools_MapOfShape dire, reve;
BRep_Builder B;
B.MakeShell(nshell);
Standard_Boolean isMultiConnex = !aMapMultiConnectEdges.IsEmpty();
Standard_Integer i=1, j=1;
TopTools_SequenceOfShape aSeqUnconnectFaces;
for( ; i<=Lface.Length(); i++) {
TopTools_MapOfShape dtemp, rtemp;
Standard_Integer nbbe=0, nbe = 0;
TopoDS_Face F1 = TopoDS::Face(Lface.Value(i));
for(TopExp_Explorer expe(F1, TopAbs_EDGE); expe.More(); expe.Next()) {
TopoDS_Edge edge = TopoDS::Edge(expe.Current());
// if multiconnexity mode is equal to Standard_True faces contains
// the same multiconnexity edges are not added to one shell.
if(isMultiConnex && aMapMultiConnectEdges.Contains(edge))
continue;
if((edge.Orientation() == TopAbs_FORWARD && dire.Contains(edge))
|| (edge.Orientation() == TopAbs_REVERSED && reve.Contains(edge)))
nbbe++;
else if((edge.Orientation() == TopAbs_FORWARD && reve.Contains(edge))
|| (edge.Orientation() == TopAbs_REVERSED && dire.Contains(edge)))
nbe++;
if(dire.Contains(edge)) dire.Remove(edge);
else
if(reve.Contains(edge)) reve.Remove(edge);
else {
if(edge.Orientation() == TopAbs_FORWARD) dtemp.Add(edge);
if(edge.Orientation() == TopAbs_REVERSED) rtemp.Add(edge);
}
}
if(!nbbe && !nbe && dtemp.IsEmpty() && rtemp.IsEmpty())
continue;
// if face can not be added to shell it added to sequence of error faces.
if( nbe != 0 && nbbe != 0) {
ErrFaces.Append(F1);
Lface.Remove(i);
j++;
continue;
}
// Addition of face to shell. In the dependance of orientation faces in the shell
// added face can be reversed.
if((nbe != 0 || nbbe != 0) || j == 1) {
if(nbbe != 0) {
F1.Reverse();
for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next())
reve.Add(ite.Key());
for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
dire.Add(ite1.Key());
done = Standard_True;
}
else {
for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next())
dire.Add(ite.Key());
for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
reve.Add(ite1.Key());
}
j++;
B.Add(nshell,F1);
aMapFaceShells.Bind(F1,nshell);
Lface.Remove(i);
// check if closed shell is obtained in multy connex mode and add to sequence of
// shells and new shell begin to construct.
// (check is n*2)
if(isMultiConnex && BRep_Tool::IsClosed (nshell)) {
nshell.Closed (Standard_True);
aSeqShells.Append(nshell);
TopoDS_Shell nshellnext;
B.MakeShell(nshellnext);
nshell = nshellnext;
j=1;
}
i=0;
}
//if shell contains of one face. This face is added to sequence of faces.
// This shell is removed.
if(Lface.Length() && i == Lface.Length() && j <=2) {
TopoDS_Iterator aItf(nshell,Standard_False);
if(aItf.More()) {
aSeqUnconnectFaces.Append(aItf.Value());
aMapFaceShells.UnBind(aItf.Value());
}
TopoDS_Shell nshellnext;
B.MakeShell(nshellnext);
nshell = nshellnext;
i=0;
j=1;
}
}
Standard_Boolean isContains = Standard_False;
for(Standard_Integer k =1 ; k <= aSeqShells.Length() && !isContains; k++)
isContains = nshell.IsSame(aSeqShells.Value(k));
if(!isContains) {
Standard_Integer numFace =0;
TopoDS_Shape aFace;
for(TopoDS_Iterator aItf(nshell,Standard_False) ; aItf.More(); aItf.Next()) {
aFace = aItf.Value();
numFace++;
}
if(numFace >1) {
// close all closed shells in no multy connex mode
if(!isMultiConnex)
nshell.Closed (BRep_Tool::IsClosed (nshell));
aSeqShells.Append(nshell);
}
else if(numFace == 1) {
if(aMapFaceShells.IsBound(aFace))
aMapFaceShells.UnBind(aFace);
Lface.Append(aFace);
}
}
//Sequence of faces Lface contains faces which can not be added to obtained shells.
for(Standard_Integer j1 =1; j1 <= aSeqUnconnectFaces.Length(); j1++) {
Lface.Append(aSeqUnconnectFaces);
}
return done;
}
//=======================================================================
// 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 Standard_Boolean AddMultiConexityFaces(TopTools_SequenceOfShape& Lface,
const TopTools_MapOfShape& aMapMultiConnectEdges,
TopTools_SequenceOfShape& SeqShells,
const TopTools_DataMapOfShapeShape& aMapFaceShells,
const TopTools_IndexedDataMapOfShapeListOfShape& aMapEdgeFaces,
TopTools_SequenceOfShape& ErrFaces,
const Standard_Boolean NonManifold)
{
Standard_Boolean done = Standard_False;
// BRep_Builder aB;
TopTools_SequenceOfShape llPosibleShells;
TopTools_SequenceOfShape AddShapes;
for(Standard_Integer i1 = 1 ; i1<=Lface.Length();i1++ ) {
TopoDS_Shape aShape = Lface.Value(i1);
Standard_Integer aNbMultEdges =0;
//Finds faces having only multiconnexity boundary.
for(TopoDS_Iterator aItWires(aShape,Standard_False); aItWires.More(); aItWires.Next()) {
Standard_Integer aNbEdges =0;
for(TopoDS_Iterator aItEdges(aItWires.Value(),Standard_False); aItEdges.More(); aItEdges.Next(),aNbEdges++) {
TopoDS_Shape edge = aItEdges.Value();
if(!aMapMultiConnectEdges.Contains(edge)) continue;
aNbMultEdges++;
}
if(!aNbMultEdges) continue;
if(aNbMultEdges == aNbEdges)
AddShapes.Append(aShape);
else llPosibleShells.Append(aShape);
}
}
// Attemp to create shell from unconnected which have not only multiconnexity boundary.
TopTools_SequenceOfShape aTmpShells;
if(!llPosibleShells.IsEmpty()) {
TopTools_MapOfShape aMap;
TopTools_SequenceOfShape aTmp;
TopTools_DataMapOfShapeShape aTmpFaceShell;
if(GetShells(llPosibleShells,aMap,aTmpShells,aTmpFaceShell,aTmp)) {
for(Standard_Integer kk =1; kk <= aTmpShells.Length(); kk++) {
TopoDS_Shape aSh = aTmpShells.Value(kk);
TopTools_MapOfShape mapEdges;
if(GetFreeEdges(aSh,mapEdges)) {
Standard_Integer nbedge =0;
for(TopTools_MapIteratorOfMapOfShape amapIter(mapEdges);amapIter.More(); amapIter.Next()) {
if( aMapMultiConnectEdges.Contains(amapIter.Key()))
nbedge++;
}
if(nbedge && nbedge == mapEdges.Extent())
AddShapes.Append(aSh);
}
}
}
}
//Add choosen faces to shells.
for(Standard_Integer k1 =1; k1 <= AddShapes.Length(); k1++) {
TopTools_DataMapOfShapeInteger MapOtherShells;
TopTools_MapOfShape dire,reve;
TopoDS_Shape aSh = AddShapes.Value(k1);
TopTools_MapOfShape mapEdges;
if(!GetFreeEdges(aSh,mapEdges)) continue;
TopTools_ListOfShape lfaces;
//Fill MapOtherShells which will contain shells with orientation in which selected shape aSh will be add.
for(TopTools_MapIteratorOfMapOfShape 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);
TopTools_ListOfShape lf;
lf = aMapEdgeFaces.FindFromKey(edge);
lfaces.Append(lf);
}
for(TopTools_ListIteratorOfListOfShape 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;
TopTools_MapOfShape mapShellEdges;
GetFreeEdges(aOthershell,mapShellEdges);
Standard_Boolean isAdd = Standard_True;
for(TopTools_MapIteratorOfMapOfShape amapIter1(mapEdges);amapIter1.More() && isAdd ; amapIter1.Next())
isAdd = mapShellEdges.Contains(amapIter1.Key());
if(!isAdd) continue;
Standard_Integer nbdir =0, nbrev=0;
//add only free face whome all edges contains in the shell as open boundary.
for(TopTools_MapIteratorOfMapOfShape 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) {
Standard_Integer isReverse =(nbrev ? 1: 0);
MapOtherShells.Bind(aOthershell,isReverse);
}
}
if(MapOtherShells.IsEmpty()) {
// i1++;
continue;
}
//Adds face to open shells containg 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 = Standard_True;
Standard_Integer FirstRev = 0,FirstInd =0;
Standard_Integer ind =0;
for(Standard_Integer l =1; l <= SeqShells.Length(); l++) {
if(!MapOtherShells.IsBound(SeqShells.Value(l))) continue;
ind++;
Standard_Integer 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) {
Standard_Boolean isReversed = !((!(isRev) && !FirstRev) || ((isRev) && FirstRev));
aShell = SeqShells.Value(FirstInd);
for(TopoDS_Iterator aItF(SeqShells.Value(l),Standard_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(Standard_Integer 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 Standard_Integer BoxIn(const Bnd_Box& theBox1,const Bnd_Box& theBox2)
{
Standard_Integer aNumIn = 0;
Standard_Real 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 afew shells are created from
// the same set of faces.
//=======================================================================
static void GetClosedShells(TopTools_SequenceOfShape& Shells, TopTools_SequenceOfShape& aRemainShells)
{
Bnd_Array1OfBox aBoxes(1,Shells.Length());
for(Standard_Integer i =1; i <= Shells.Length(); i++) {
Bnd_Box Box;
BRepBndLib::AddClose(Shells.Value(i),Box);
aBoxes.SetValue(i,Box);
}
TColStd_MapOfInteger aMapNum;
for(Standard_Integer j = 1; j <= aBoxes.Length(); j++) {
for(Standard_Integer k = j+1; k <= aBoxes.Length(); k++) {
Standard_Integer 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(Standard_Integer i1 =1; i1 <= Shells.Length(); i1++) {
if(!aMapNum.Contains(i1))
aRemainShells.Append(Shells.Value(i1));
}
}
//=======================================================================
// function : GlueClosedCandidate
// purpose :Attemt firstly to create closed shells from sequence of open shells.
//=======================================================================
static void GlueClosedCandidate(TopTools_SequenceOfShape& OpenShells,
const TopTools_MapOfShape& aMapMultiConnectEdges,
TopTools_SequenceOfShape& aSeqNewShells)
{
// Creating new shells if some open shells contain the same free boundary.
for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ ) {
TopoDS_Shape aShell = OpenShells.Value(i);
TopTools_MapOfShape mapEdges1;
TopTools_MapOfShape dire,reve;
if(!GetFreeEdges(aShell,mapEdges1)) continue;
for(TopTools_MapIteratorOfMapOfShape 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.
TopTools_DataMapOfShapeInteger MapOtherShells;
for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ ) {
Standard_Boolean isAddShell = Standard_True;
Standard_Boolean isReversed = Standard_False;
Standard_Integer nbedge =0;
TopTools_MapOfShape mapEdges2;
TopoDS_Shape aShell2 = OpenShells.Value(j);
if(!GetFreeEdges(aShell2,mapEdges2)) continue;
for(TopTools_MapIteratorOfMapOfShape aIte2( mapEdges2);aIte2.More() && isAddShell;aIte2.Next()) {
TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
if(!aMapMultiConnectEdges.Contains(edge2)) {
isAddShell = Standard_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 = Standard_True;
nbedge++;
}
if(!isAddShell) continue;
MapOtherShells.Bind(OpenShells.Value(j),isReversed);
}
if(!MapOtherShells.Extent()) continue;
if(MapOtherShells.Extent() >1) {
// Case of compsolid when more than two shells have the same free boundary.
TopTools_SequenceOfShape aSeqCandidate;
aSeqCandidate.Append(OpenShells.Value(i));
for(TopTools_DataMapIteratorOfDataMapOfShapeInteger aIt(MapOtherShells); aIt.More(); aIt.Next())
aSeqCandidate.Append(aIt.Key());
//Creation all possibly shells from choosen candidate.And
// addition of them to temporary sequence.
TopTools_SequenceOfShape aTmpSeq;
for(Standard_Integer k =1; k <= aSeqCandidate.Length(); k++) {
for(Standard_Integer l = k+1; l <= aSeqCandidate.Length(); l++) {
TopoDS_Shell aNewSh;
BRep_Builder aB;
aB.MakeShell(aNewSh);
for(TopoDS_Iterator aIt1(aSeqCandidate.Value(k),Standard_False); aIt1.More(); aIt1.Next())
aB.Add(aNewSh,aIt1.Value());
Standard_Integer isRev = MapOtherShells.Find(aSeqCandidate.Value(l));
if(k !=1) {
isRev = ((isRev == MapOtherShells.Find(aSeqCandidate.Value(k))) ? 1 : 0);
}
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)
TopTools_SequenceOfShape aRemainShells;
GetClosedShells(aTmpSeq,aRemainShells);
aSeqNewShells.Append(aRemainShells);
for(Standard_Integer 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;
Standard_Boolean isReversed = Standard_False;
for(Standard_Integer j1 = i+1 ; j1 <= OpenShells.Length();j1++ ) {
if(!MapOtherShells.IsBound(OpenShells.Value(j1))) continue;
addShell = OpenShells.Value(j1);
isReversed = MapOtherShells.Find(addShell);
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(TopTools_SequenceOfShape& SeqShells,
const TopTools_MapOfShape& aMapMultiConnectEdges)
{
TopTools_IndexedDataMapOfShapeListOfShape aMap;
for(Standard_Integer i =1 ; i <= SeqShells.Length(); i++) {
TopoDS_Shape aShell = SeqShells.Value(i);
TopTools_IndexedMapOfShape medeg;
TopExp::MapShapes(aShell,TopAbs_EDGE,medeg);
for(TopTools_MapIteratorOfMapOfShape mit(aMapMultiConnectEdges); mit.More(); mit.Next()) {
//for(TopExp_Explorer aExp(aShell,TopAbs_EDGE); aExp.More(); aExp.Next(),nbe++) {
//TopoDS_Shape ae = aExp.Current();
TopoDS_Shape ae =mit.Key();
//if( aMapMultiConnectEdges.Contains(aExp.Current())) {
if(medeg.Contains(ae)) {
if(aMap.Contains(ae))
aMap.ChangeFromKey(ae).Append(aShell);
else {
TopTools_ListOfShape al;
al.Append(aShell);
aMap.Add(ae,al);
}
}
}
}
TopTools_IndexedDataMapOfShapeShape aMapShells;
for(Standard_Integer j =1; j <= aMap.Extent(); j++) {
const TopTools_ListOfShape& LShells = aMap.FindFromIndex(j);
TopoDS_Shell aNewShell;
BRep_Builder aB;
aB.MakeShell(aNewShell);
TopTools_MapOfShape mapmerge;
Standard_Boolean ismerged = Standard_False;
Standard_Integer num = 1;
for(TopTools_ListIteratorOfListOfShape 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 = Standard_True;
mapmerge.Add(alit.Value());
}
else if(ismerged) {
TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
while(aMapShells.Contains(arshell)){
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)) {
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(TopTools_MapIteratorOfMapOfShape alit1(mapmerge); alit1.More();alit1.Next()) {
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);
}
}
}
TopTools_IndexedMapOfShape MapNewShells;
for(Standard_Integer nn = 1;nn <= SeqShells.Length(); nn++) {
if(aMapShells.Contains(SeqShells.Value(nn))) {
TopoDS_Shape aNewShell = aMapShells.FindFromKey(SeqShells.Value(nn));
while(aMapShells.Contains(aNewShell)) {
TopoDS_Shape ss = aMapShells.FindFromKey(aNewShell);
if(ss.IsSame(aNewShell)) break;
aNewShell = ss;
}
MapNewShells.Add(aNewShell);
SeqShells.Remove(nn--);
}
}
for(Standard_Integer 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(TopTools_SequenceOfShape& OpenShells,
const TopTools_MapOfShape& aMapMultiConnectEdges)
{
TopTools_SequenceOfShape aNewShells;
//Attemt firstly to create closed shells.
GlueClosedCandidate(OpenShells,aMapMultiConnectEdges,aNewShells);
// Creating new shells if some open shells contain the multishared same edges.
for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ ) {
Standard_Boolean isAddShell = Standard_False;
TopoDS_Shape aShell = OpenShells.Value(i);
Standard_Boolean isReversed = Standard_False;
for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ ) {
TopTools_MapOfShape mapEdges1;
TopTools_MapOfShape dire,reve;
if(!GetFreeEdges(aShell,mapEdges1)) break;
for(TopTools_MapIteratorOfMapOfShape 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;
TopTools_MapOfShape mapEdges2;
TopoDS_Shape aShell2 = OpenShells.Value(j);
if(!GetFreeEdges(aShell2,mapEdges2)) continue;
for(TopTools_MapIteratorOfMapOfShape 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 = Standard_True;
if((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
|| (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
isReversed = Standard_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);
}
//=======================================================================
// function : FixFaceOrientation
// purpose :
//=======================================================================
Standard_Boolean ShapeFix_Shell::FixFaceOrientation(const TopoDS_Shell& shell,const Standard_Boolean isAccountMultiConex,const Standard_Boolean NonManifold)
{
//myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
Standard_Boolean done = Standard_False;
TopTools_SequenceOfShape aSeqShells;
TopTools_SequenceOfShape aErrFaces; // Compound of faces like to Mebiuce leaf.
TopTools_SequenceOfShape Lface;
TopTools_DataMapOfShapeShape aMapFaceShells;
myShell = shell;
myShape = shell;
Standard_Integer aNumMultShell =0;
for (TopoDS_Iterator iter(shell); iter.More(); iter.Next())
Lface.Append(iter.Value());
TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
TopExp::MapShapesAndAncestors(myShell,TopAbs_EDGE,TopAbs_FACE,aMapEdgeFaces);
TopTools_MapOfShape aMapMultiConnectEdges;
Standard_Boolean isFreeBoundaries = Standard_False;
for(Standard_Integer k = 1; k <= aMapEdgeFaces.Extent(); k++) {
const Standard_Integer aFaceCount = aMapEdgeFaces.FindFromIndex(k).Extent();
if (!isFreeBoundaries && aFaceCount == 1) {
TopoDS_Edge E = TopoDS::Edge(aMapEdgeFaces.FindKey(k));
if (!BRep_Tool::Degenerated(E))
isFreeBoundaries = Standard_True;
}
//Finds multishared edges
else if (isAccountMultiConex && aFaceCount > 2)
aMapMultiConnectEdges.Add(aMapEdgeFaces.FindKey(k));
}
if (BRep_Tool::IsClosed(myShell)? isFreeBoundaries : !isFreeBoundaries)
{
myShell.Closed (!isFreeBoundaries);
SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed
}
Standard_Boolean isGetShells = Standard_True;
//Gets possible shells with taking in account of multiconnexity.
while(isGetShells && Lface.Length()) {
TopTools_SequenceOfShape aTmpSeqShells;
if(GetShells(Lface, aMapMultiConnectEdges, aTmpSeqShells,aMapFaceShells,aErrFaces)) {
done = Standard_True;
}
isGetShells = !aTmpSeqShells.IsEmpty();
if(isGetShells)
aSeqShells.Append(aTmpSeqShells);
}
if(!done)
done = (aSeqShells.Length() >1);
Standard_Boolean aIsDone = Standard_False;
if(Lface.Length() > 0 && aSeqShells.Length()) {
for(Standard_Integer 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(Standard_Integer n =1; n <= aErrFaces.Length(); n++)
B.Add(myErrFaces,aErrFaces.Value(n));
if(aNumMultShell) {
if(aNumMultShell == 1) {
B.Add(aCompShells,aSeqShells.Value(1));
for(Standard_Integer 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(Standard_Integer i =1; i <= aSeqShells.Length(); i++)
B.Add(aCompShells,aSeqShells.Value(i));
for(Standard_Integer 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 = Standard_True;
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL);
SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG20" ) );// Impossible to orient faces in shell, several shells created
return Standard_True;
}
if(aNumMultShell >1) {
TopTools_SequenceOfShape OpenShells;
for(Standard_Integer 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 Standard_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(Standard_Integer 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(Standard_Integer 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 )
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
return Standard_True;
}
else return Standard_False;
}
//=======================================================================
//function : Status
//purpose :
//=======================================================================
Standard_Boolean ShapeFix_Shell::Status(const ShapeExtend_Status status) const
{
return ShapeExtend::DecodeStatus (myStatus, status);
}
//=======================================================================
//function : Shell
//purpose :
//=======================================================================
TopoDS_Shell ShapeFix_Shell::Shell()
{
return myShell;
}
//=======================================================================
//function : Shell
//purpose :
//=======================================================================
TopoDS_Shape ShapeFix_Shell::Shape()
{
return myShape;
}
//=======================================================================
//function : ErrorFaces
//purpose :
//=======================================================================
TopoDS_Compound ShapeFix_Shell::ErrorFaces() const
{
return myErrFaces;
}
//=======================================================================
//function : SetMsgRegistrator
//purpose :
//=======================================================================
void ShapeFix_Shell::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
{
ShapeFix_Root::SetMsgRegistrator ( msgreg );
myFixFace->SetMsgRegistrator ( msgreg );
}
//=======================================================================
//function : SetPrecision
//purpose :
//=======================================================================
void ShapeFix_Shell::SetPrecision (const Standard_Real preci)
{
ShapeFix_Root::SetPrecision ( preci );
myFixFace->SetPrecision ( preci );
}
//=======================================================================
//function : SetMinTolerance
//purpose :
//=======================================================================
void ShapeFix_Shell::SetMinTolerance (const Standard_Real mintol)
{
ShapeFix_Root::SetMinTolerance ( mintol );
myFixFace->SetMinTolerance ( mintol );
}
//=======================================================================
//function : SetMaxTolerance
//purpose :
//=======================================================================
void ShapeFix_Shell::SetMaxTolerance (const Standard_Real maxtol)
{
ShapeFix_Root::SetMaxTolerance ( maxtol );
myFixFace->SetMaxTolerance ( maxtol );
}
//=======================================================================
//function : NbShells
//purpose :
//=======================================================================
Standard_Integer ShapeFix_Shell::NbShells() const
{
return myNbShells;
}