mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-26 22:00:33 +05:00
2169 lines
68 KiB
C++
2169 lines
68 KiB
C++
#ifdef OCCGEOMETRY
|
|
|
|
// GEOM PARTITION : partition algorithm
|
|
//
|
|
// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
|
|
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2.1 of the License.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
// See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
|
|
//
|
|
//
|
|
//
|
|
// File : Partition_Spliter.cxx
|
|
// Author : Benedicte MARTIN
|
|
// Module : GEOM
|
|
// $Header: /cvs/netgen/netgen/libsrc/occ/Partition_Spliter.cxx,v 1.7 2008/03/31 14:20:28 wabro Exp $
|
|
|
|
//using namespace std;
|
|
#include <climits>
|
|
#include "Partition_Inter2d.hxx"
|
|
#include "Partition_Inter3d.hxx"
|
|
#include "Partition_Loop2d.hxx"
|
|
#include "Partition_Loop3d.hxx"
|
|
#include "Partition_Spliter.ixx"
|
|
|
|
#include "utilities.h"
|
|
|
|
#include <Precision.hxx>
|
|
#include <TopAbs_Orientation.hxx>
|
|
#include <TopExp.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
|
|
#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
|
|
#include <TopTools_DataMapOfShapeListOfShape.hxx>
|
|
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
|
#include <TopTools_IndexedMapOfShape.hxx>
|
|
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
|
#include <TopTools_ListOfShape.hxx>
|
|
#include <TopTools_MapIteratorOfMapOfShape.hxx>
|
|
#include <TopTools_SequenceOfShape.hxx>
|
|
|
|
#include <Geom2d_Curve.hxx>
|
|
#include <Geom_Curve.hxx>
|
|
#include <Geom_Surface.hxx>
|
|
#include <Geom_TrimmedCurve.hxx>
|
|
#include <gp_Pnt.hxx>
|
|
#include <gp_Pnt2d.hxx>
|
|
#include <gp_Vec.hxx>
|
|
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Compound.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <TopoDS_Face.hxx>
|
|
#include <TopoDS_Iterator.hxx>
|
|
#include <TopoDS_Shell.hxx>
|
|
#include <TopoDS_Solid.hxx>
|
|
#include <TopoDS_Vertex.hxx>
|
|
#include <TopoDS_Wire.hxx>
|
|
|
|
#include <BRepBndLib.hxx>
|
|
#include <BRepClass3d_SolidClassifier.hxx>
|
|
#include <BRepLib.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
|
|
#include <Extrema_ExtPC.hxx>
|
|
#include <GeomAdaptor_Curve.hxx>
|
|
#include <TopOpeBRepTool_CurveTool.hxx>
|
|
|
|
#ifdef DEB
|
|
//# define PART_PERF
|
|
#endif
|
|
|
|
#ifdef PART_PERF
|
|
# include <OSD_Chronometer.hxx>
|
|
#endif
|
|
|
|
//=======================================================================
|
|
//function : isClosed
|
|
//purpose : check id a shape is closed, ie is a solid or a closed shell
|
|
//=======================================================================
|
|
|
|
static Standard_Boolean isClosed(const TopoDS_Shape& theShape)
|
|
{
|
|
Standard_Boolean isClosed = (theShape.ShapeType() == TopAbs_SOLID);
|
|
|
|
if (!isClosed && theShape.ShapeType() == TopAbs_SHELL) {
|
|
TopTools_IndexedDataMapOfShapeListOfShape MEF;
|
|
TopExp::MapShapesAndAncestors(theShape, TopAbs_EDGE, TopAbs_FACE, MEF);
|
|
for (Standard_Integer i=1; isClosed && i<=MEF.Extent(); ++i)
|
|
isClosed = ( MEF(i).Extent() != 1 );
|
|
}
|
|
|
|
return isClosed;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Partition_Spliter
|
|
//purpose : constructor
|
|
//=======================================================================
|
|
|
|
Partition_Spliter::Partition_Spliter()
|
|
{
|
|
myAsDes = new BRepAlgo_AsDes;
|
|
Clear();
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : AddTool
|
|
//purpose : add cutting tool that will _NOT_ be in result
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::AddTool(const TopoDS_Shape& S)
|
|
{
|
|
if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
|
|
TopoDS_Iterator it (S);
|
|
for (; it.More(); it.Next())
|
|
{
|
|
AddTool( it.Value());
|
|
myFaceShapeMap.Bind( it.Value(), S ); // to know compound by shape
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (TopExp_Explorer exp(S,TopAbs_FACE); exp.More(); exp.Next())
|
|
{
|
|
myMapTools.Add(exp.Current());
|
|
myFaceShapeMap.Bind( exp.Current(), S );
|
|
}
|
|
if (isClosed( S ))
|
|
myClosedShapes.Add( S );
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : AddShape
|
|
//purpose : add object Shape to be splited
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::AddShape(const TopoDS_Shape& S)
|
|
{
|
|
if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
|
|
TopoDS_Iterator it (S);
|
|
for (; it.More(); it.Next())
|
|
{
|
|
AddShape( it.Value());
|
|
myFaceShapeMap.Bind( it.Value(), S ); // to know compound by shape
|
|
}
|
|
return;
|
|
}
|
|
|
|
TopExp_Explorer exp(S,TopAbs_FACE);
|
|
if (!exp.More()) { // do not split edges and vertices
|
|
//myBuilder.Add( myShape, S );
|
|
return;
|
|
}
|
|
|
|
Standard_Integer nbFacesBefore = myMapFaces.Extent(); // not to add twice the same S
|
|
for (; exp.More(); exp.Next()) {
|
|
const TopoDS_Shape & aFace = exp.Current();
|
|
if ( ! myFaceShapeMap.IsBound( aFace )) // keep shape of tool face added as object
|
|
myFaceShapeMap.Bind( aFace, S );
|
|
if (myMapFaces.Add( aFace ))
|
|
myImagesFaces.SetRoot( aFace );
|
|
}
|
|
|
|
if (nbFacesBefore == myMapFaces.Extent())
|
|
return;
|
|
|
|
// solids must be processed before all
|
|
if (S.ShapeType() == TopAbs_SOLID)
|
|
myListShapes.Prepend(S);
|
|
else
|
|
myListShapes.Append(S);
|
|
|
|
if (isClosed( S ))
|
|
myClosedShapes.Add( S );
|
|
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Shape
|
|
//purpose : return resulting compound
|
|
//=======================================================================
|
|
|
|
TopoDS_Shape Partition_Spliter::Shape() const
|
|
{
|
|
return myShape;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Clear
|
|
//purpose : clear fields
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::Clear()
|
|
{
|
|
myDoneStep = TopAbs_SHAPE;
|
|
|
|
myListShapes.Clear();
|
|
myMapFaces.Clear();
|
|
myMapTools.Clear();
|
|
myEqualEdges.Clear();
|
|
myNewSection.Clear();
|
|
myClosedShapes.Clear();
|
|
mySharedFaces.Clear();
|
|
myWrappingSolid.Clear();
|
|
myFaceShapeMap.Clear();
|
|
|
|
myInternalFaces.Clear();
|
|
myIntNotClFaces.Clear();
|
|
|
|
myAsDes->Clear();
|
|
myImagesFaces.Clear();
|
|
myImagesEdges.Clear();
|
|
myImageShape.Clear();
|
|
|
|
// myInter3d = Partition_Inter3d(myAsDes);
|
|
Partition_Inter3d hinter3d (myAsDes);
|
|
myInter3d = hinter3d;
|
|
|
|
myAddedFacesMap.Clear();
|
|
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Compute
|
|
//purpose : produce a result
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::Compute(const TopAbs_ShapeEnum Limit)
|
|
{
|
|
if ((Limit != TopAbs_SHAPE && myDoneStep == Limit) ||
|
|
(Limit == TopAbs_SHAPE && myDoneStep == TopAbs_SOLID))
|
|
return;
|
|
|
|
myBuilder.MakeCompound( myShape );
|
|
|
|
TopTools_MapIteratorOfMapOfShape it;
|
|
TopTools_ListIteratorOfListOfShape itl;
|
|
TopExp_Explorer exp;
|
|
|
|
#ifdef PART_PERF
|
|
OSD_Chronometer aCron;
|
|
#endif
|
|
|
|
if (myDoneStep > TopAbs_VERTEX) {
|
|
|
|
TopTools_ListOfShape aListFaces;
|
|
aListFaces = myImagesFaces.Roots();
|
|
for (it.Initialize(myMapTools); it.More(); it.Next())
|
|
aListFaces.Append(it.Key());
|
|
|
|
#ifdef PART_PERF
|
|
aCron.Start();
|
|
#endif
|
|
|
|
//-----------------------------------------------
|
|
// Intersection between faces
|
|
//-----------------------------------------------
|
|
// result is in myAsDes as a map Face - list of new edges;
|
|
// special care is done for section edges, same domain faces and vertices:
|
|
// data about them is inside myInter3d
|
|
myInter3d.CompletPart3d(aListFaces, myFaceShapeMap);
|
|
|
|
#ifdef PART_PERF
|
|
MESSAGE("+++ CompletPart3d()");
|
|
aCron.Show( cout );
|
|
aCron.Reset();
|
|
aCron.Start();
|
|
#endif
|
|
//-----------------------------------------------
|
|
// Intersection of edges
|
|
//-----------------------------------------------
|
|
|
|
// add tool faces which must be reconstructed to myMapFaces too
|
|
FindToolsToReconstruct();
|
|
|
|
#ifdef PART_PERF
|
|
MESSAGE("+++ FindToolsToReconstruct()");
|
|
aCron.Show( cout );
|
|
aCron.Reset();
|
|
aCron.Start();
|
|
#endif
|
|
|
|
// add existing vertices to edges of object faces in myAsDes
|
|
TopTools_MapOfShape DoneEM;
|
|
for ( it.Initialize(myMapFaces); it.More(); it.Next()) {
|
|
const TopoDS_Shape& F = it.Key();
|
|
TopoDS_Face FForward = TopoDS::Face(F.Oriented(TopAbs_FORWARD));
|
|
for (exp.Init(FForward,TopAbs_EDGE); exp.More(); exp.Next()) {
|
|
const TopoDS_Edge& E = TopoDS::Edge( exp.Current() );
|
|
myAsDes->Add(FForward,E);
|
|
if (DoneEM.Add(E)) {
|
|
TopoDS_Iterator itV(E);
|
|
for (; itV.More(); itV.Next()) {
|
|
const TopoDS_Vertex& V = TopoDS::Vertex( itV.Value());
|
|
myAsDes->Add(E, myInter3d.ReplaceSameDomainV( V, E ));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// intersect edges that are descendants of a face in myAsDes
|
|
TopTools_MapOfShape& Modif = myInter3d.TouchedFaces();
|
|
for ( it.Initialize(Modif); it.More(); it.Next()) {
|
|
const TopoDS_Face& F = TopoDS::Face(it.Key());
|
|
Partition_Inter2d::CompletPart2d (myAsDes, F, myInter3d.NewEdges());
|
|
}
|
|
// now myAsDes contains also new vertices made at edge intersection as
|
|
// descendant of edges both new and old
|
|
|
|
myDoneStep = TopAbs_VERTEX;
|
|
|
|
#ifdef PART_PERF
|
|
MESSAGE("+++ CompletPart2d()");
|
|
aCron.Show( cout );
|
|
aCron.Reset();
|
|
aCron.Start();
|
|
#endif
|
|
} // if (myDoneStep > TopAbs_VERTEX)
|
|
|
|
if (Limit == TopAbs_VERTEX) {
|
|
// add new vertices to myShape
|
|
for ( it.Initialize( myInter3d.NewEdges() ); it.More(); it.Next()) {
|
|
if (! myAsDes->HasDescendant( it.Key() ))
|
|
continue;
|
|
itl.Initialize( myAsDes->Descendant( it.Key() ));
|
|
for (; itl.More(); itl.Next())
|
|
myBuilder.Add ( myShape, itl.Value() );
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
if (myDoneStep > TopAbs_EDGE) {
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
// ------- Reconstruction of all the edges.------
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
|
|
// ==============
|
|
// cut new edges
|
|
// ==============
|
|
TopTools_ListOfShape LSE; // all edge splits
|
|
for ( it.Initialize(myInter3d.NewEdges()); it.More(); it.Next()) {
|
|
|
|
TopoDS_Vertex V1,V2;
|
|
TopoDS_Edge EE = TopoDS::Edge(it.Key());
|
|
|
|
TopTools_ListOfShape aListV, aListF;
|
|
aListV = myAsDes->Descendant(EE); // intersection vertices
|
|
aListF = myAsDes->Ascendant(EE); // intersected faces
|
|
|
|
if (aListV.IsEmpty())
|
|
continue; // new edge does not intersect any other edge
|
|
|
|
// Add end vertices to new edges only if
|
|
// one face is Tool and the other is Shape
|
|
Standard_Boolean isTool1 = ! myMapFaces.Contains( aListF.First() );
|
|
Standard_Boolean isTool2 = ! myMapFaces.Contains( aListF.Last() );
|
|
if (isTool1 || isTool2)
|
|
{
|
|
TopExp::Vertices(EE,V1,V2);
|
|
Standard_Real Tol = Max (BRep_Tool::Tolerance( V1 ),
|
|
BRep_Tool::Tolerance( V2 ));
|
|
|
|
gp_Pnt P1 = BRep_Tool::Pnt(V1);
|
|
gp_Pnt P2 = BRep_Tool::Pnt(V2);
|
|
Standard_Boolean AddV1 = Standard_True;
|
|
Standard_Boolean AddV2 = Standard_True;
|
|
|
|
// add only if there is no intersection at end vertex
|
|
for (itl.Initialize(aListV); itl.More(); itl.Next()) {
|
|
const TopoDS_Vertex& Ve = TopoDS::Vertex(itl.Value()) ;
|
|
Standard_Real Tol2 = Max ( Tol, BRep_Tool::Tolerance( Ve ));
|
|
Tol2 *= Tol2;
|
|
gp_Pnt P = BRep_Tool::Pnt(Ve);
|
|
if (AddV1 && P.SquareDistance(P1) <= Tol2)
|
|
AddV1 = Standard_False;
|
|
|
|
if (AddV2 && P.SquareDistance(P2) <= Tol2)
|
|
AddV2 = Standard_False;
|
|
}
|
|
|
|
if (AddV1) {
|
|
aListV.Append(V1);
|
|
myAsDes->Add(EE,V1);
|
|
}
|
|
|
|
if (AddV2) {
|
|
aListV.Append(V2);
|
|
myAsDes->Add(EE,V2);
|
|
}
|
|
}
|
|
|
|
// cut new edges
|
|
Standard_Integer NbV=aListV.Extent() ;
|
|
if (NbV>1 || (NbV==1 && V1.IsSame(V2)) ) {
|
|
TopTools_ListOfShape LNE;
|
|
MakeEdges (EE,aListV, LNE);
|
|
myImagesEdges.Bind(EE,LNE);
|
|
LSE.Append( LNE );
|
|
}
|
|
}
|
|
|
|
// ==============
|
|
// cut old edges
|
|
// ==============
|
|
for ( it.Initialize(myMapFaces); it.More(); it.Next()) {
|
|
for (exp.Init( it.Key(), TopAbs_EDGE); exp.More(); exp.Next()) {
|
|
const TopoDS_Edge& EE = TopoDS::Edge( exp.Current() );
|
|
if ( myImagesEdges.HasImage( EE ))
|
|
continue;
|
|
TopTools_ListOfShape LNE;
|
|
const TopTools_ListOfShape& aListVV = myAsDes->Descendant(EE);
|
|
MakeEdges (EE, aListVV, LNE);
|
|
myImagesEdges.Bind(EE,LNE);
|
|
LSE.Append( LNE );
|
|
}
|
|
}
|
|
#ifdef PART_PERF
|
|
MESSAGE("+++ Cut Edges");
|
|
aCron.Show( cout );
|
|
aCron.Reset();
|
|
aCron.Start();
|
|
#endif
|
|
|
|
// process same domain section edges
|
|
MergeEqualEdges( LSE );
|
|
|
|
myDoneStep = TopAbs_EDGE;
|
|
|
|
#ifdef PART_PERF
|
|
MESSAGE("+++ MergeEqualEdges()");
|
|
aCron.Show( cout );
|
|
aCron.Reset();
|
|
aCron.Start();
|
|
#endif
|
|
} // if (myDoneStep > TopAbs_EDGE)
|
|
|
|
if (Limit == TopAbs_EDGE) {
|
|
// add splits of old edges
|
|
TopTools_ListIteratorOfListOfShape itNE;
|
|
for (itl.Initialize( myListShapes );itl.More();itl.Next()) {
|
|
if (myMapTools.Contains( itl.Value() ))
|
|
continue; // skip tool faces
|
|
for ( exp.Init( itl.Value(), TopAbs_EDGE ); exp.More(); exp.Next()) {
|
|
itNE.Initialize( myImagesEdges.Image( exp.Current() ));
|
|
for ( ; itNE.More(); itNE.Next())
|
|
myBuilder.Add ( myShape, itNE.Value() );
|
|
}
|
|
}
|
|
// add splits of new edges
|
|
for ( it.Initialize( myInter3d.NewEdges() ); it.More(); it.Next()) {
|
|
itNE.Initialize( myImagesEdges.Image( it.Key() ));
|
|
for (; itNE.More(); itNE.Next())
|
|
myBuilder.Add ( myShape, itNE.Value() );
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// split faces
|
|
//-----------------------------------------------
|
|
|
|
if (myDoneStep > TopAbs_FACE) {
|
|
|
|
for (itl.Initialize(myListShapes);itl.More();itl.Next()) {
|
|
TopoDS_Shape FacesComp = MakeFaces ( itl.Value());
|
|
// there is a cunning here: myImagesFaces keeps faces made by Loop2d
|
|
// but some of them may be replaced with splits of same domain face
|
|
// and myImageShape keeps ultimate result
|
|
myImageShape.Bind( itl.Value(), FacesComp );
|
|
}
|
|
|
|
myDoneStep = TopAbs_FACE;
|
|
#ifdef PART_PERF
|
|
MESSAGE("+++ MakeFaces()");
|
|
aCron.Show( cout );
|
|
aCron.Reset();
|
|
aCron.Start();
|
|
#endif
|
|
}
|
|
|
|
if (Limit == TopAbs_WIRE ||
|
|
Limit == TopAbs_FACE) {
|
|
for (itl.Initialize(myListShapes);itl.More();itl.Next()) {
|
|
if ( myMapTools.Contains( itl.Value() ))
|
|
continue; // no result needed for a tool face
|
|
const TopoDS_Shape& FacesComp = myImageShape.Image( itl.Value() ).First();
|
|
for ( exp.Init( FacesComp, Limit); exp.More(); exp.Next())
|
|
myBuilder.Add ( myShape, exp.Current());
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// split and add solids and shells
|
|
//-----------------------------------------------
|
|
|
|
Standard_Boolean makeSolids = (Limit == TopAbs_SHAPE ||
|
|
Limit < TopAbs_SHELL);
|
|
for (itl.Initialize(myListShapes);itl.More();itl.Next())
|
|
{
|
|
const TopoDS_Shape & S = itl.Value();
|
|
if (S.ShapeType() > TopAbs_SHELL)
|
|
continue;
|
|
|
|
TopTools_ListOfShape NSL; // new shape list
|
|
MakeShells (S , NSL);
|
|
if (makeSolids && S.ShapeType() == TopAbs_SOLID )
|
|
MakeSolids( S, NSL );
|
|
|
|
// store new shells or solids
|
|
TopTools_ListIteratorOfListOfShape itNSL (NSL);
|
|
for ( ; itNSL.More(); itNSL.Next())
|
|
myBuilder.Add (myShape, itNSL.Value());
|
|
}
|
|
#ifdef PART_PERF
|
|
MESSAGE("+++ MakeShells()");
|
|
aCron.Show( cout );
|
|
#endif
|
|
|
|
//-----------------------------------------------
|
|
// add split faces
|
|
//-----------------------------------------------
|
|
|
|
for (itl.Initialize(myListShapes);itl.More();itl.Next())
|
|
{
|
|
const TopoDS_Shape & S = itl.Value();
|
|
if (S.ShapeType() != TopAbs_FACE ||
|
|
myMapTools.Contains( S ))
|
|
continue;
|
|
TopoDS_Iterator itS( myImageShape.Image(S).First() );
|
|
for (; itS.More(); itS.Next())
|
|
if (! myAddedFacesMap.Contains( itS.Value() ))
|
|
myBuilder.Add (myShape, itS.Value());
|
|
}
|
|
|
|
myDoneStep = makeSolids ? TopAbs_SOLID : TopAbs_SHELL;
|
|
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MakeSolids
|
|
//purpose : make solids out of Shells
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::MakeSolids(const TopoDS_Shape & theSolid,
|
|
TopTools_ListOfShape & theShellList)
|
|
{
|
|
// for a solid wrapping other shells or solids without intersection,
|
|
// it is necessary to find shells making holes in it
|
|
|
|
TopTools_ListOfShape aNewSolids; // result
|
|
TopTools_ListOfShape aHoleShells;
|
|
TopoDS_Shape anInfinitePointShape;
|
|
|
|
Standard_Boolean isWrapping = myWrappingSolid.Contains( theSolid );
|
|
if (!isWrapping && !theShellList.IsEmpty())
|
|
{
|
|
// check if theSolid initially has internal shells
|
|
TopoDS_Iterator aShellExp (theSolid);
|
|
aShellExp.Next();
|
|
isWrapping = aShellExp.More();
|
|
}
|
|
|
|
TopTools_ListIteratorOfListOfShape aShellIt(theShellList);
|
|
for ( ; aShellIt.More(); aShellIt.Next())
|
|
{
|
|
const TopoDS_Shape & aShell = aShellIt.Value();
|
|
|
|
// check if a shell is a hole
|
|
if (isWrapping && IsInside (anInfinitePointShape, aShell))
|
|
aHoleShells.Append( aShell );
|
|
else
|
|
{
|
|
// make a solid from a shell
|
|
TopoDS_Solid Solid;
|
|
myBuilder.MakeSolid( Solid );
|
|
myBuilder.Add (Solid, aShell);
|
|
|
|
aNewSolids.Append (Solid);
|
|
}
|
|
}
|
|
|
|
// find an outer shell most close to each hole shell
|
|
TopTools_DataMapOfShapeShape aInOutMap;
|
|
for (aShellIt.Initialize( aHoleShells ); aShellIt.More(); aShellIt.Next())
|
|
{
|
|
const TopoDS_Shape & aHole = aShellIt.Value();
|
|
TopTools_ListIteratorOfListOfShape aSolisIt (aNewSolids);
|
|
for ( ; aSolisIt.More(); aSolisIt.Next())
|
|
{
|
|
const TopoDS_Shape & aSolid = aSolisIt.Value();
|
|
if (! IsInside( aHole, aSolid ))
|
|
continue;
|
|
|
|
if ( aInOutMap.IsBound (aHole))
|
|
{
|
|
const TopoDS_Shape & aSolid2 = aInOutMap( aHole );
|
|
if ( IsInside( aSolid, aSolid2 ))
|
|
{
|
|
aInOutMap.UnBind( aHole );
|
|
aInOutMap.Bind ( aHole, aSolid );
|
|
}
|
|
}
|
|
else
|
|
aInOutMap.Bind ( aHole, aSolid );
|
|
}
|
|
|
|
// add aHole to a solid
|
|
if (aInOutMap.IsBound( aHole ))
|
|
myBuilder.Add ( aInOutMap( aHole ), aHole );
|
|
}
|
|
|
|
theShellList.Clear();
|
|
theShellList.Append( aNewSolids );
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : FindFacesInside
|
|
//purpose : return compound of faces of other shapes that are
|
|
// inside <theShape>.
|
|
// <theShape> is an object shape.
|
|
// <CheckClosed> makes avoid faces that do not form a
|
|
// closed shell
|
|
// <All> makes return already added faces
|
|
//=======================================================================
|
|
|
|
TopoDS_Shape Partition_Spliter::FindFacesInside(const TopoDS_Shape& theShape,
|
|
const Standard_Boolean CheckClosed,
|
|
const Standard_Boolean All)
|
|
{
|
|
// ================================================
|
|
// check if internal faces have been already found
|
|
// ================================================
|
|
TopExp_Explorer expl;
|
|
if (myInternalFaces.IsBound( theShape ))
|
|
{
|
|
TopoDS_Shape aIntFComp = myInternalFaces.Find ( theShape );
|
|
TopoDS_Shape aIntRemFComp = myIntNotClFaces.Find ( theShape );
|
|
|
|
expl.Init( aIntRemFComp, TopAbs_FACE);
|
|
if (CheckClosed || !expl.More())
|
|
return aIntFComp;
|
|
|
|
TopoDS_Compound C;
|
|
myBuilder.MakeCompound( C );
|
|
// add removed faces
|
|
for (; expl.More(); expl.Next())
|
|
myBuilder.Add( C, expl.Current() );
|
|
// add good internal faces
|
|
for (expl.Init( aIntFComp, TopAbs_FACE); expl.More(); expl.Next())
|
|
myBuilder.Add( C, expl.Current() );
|
|
return C;
|
|
}
|
|
|
|
// ===================================
|
|
// get data for internal faces search
|
|
// ===================================
|
|
|
|
// compound of split faces of theShape
|
|
const TopoDS_Shape& CSF = myImageShape.Image(theShape).First();
|
|
|
|
TopTools_MapOfShape MSE, MFP;
|
|
TopTools_DataMapOfShapeListOfShape DMSEFP;
|
|
TopTools_MapIteratorOfMapOfShape itm;
|
|
TopTools_ListOfShape EmptyL;
|
|
|
|
// MSE filling: map of new section edges of CSF
|
|
for (expl.Init(CSF,TopAbs_EDGE); expl.More(); expl.Next()) {
|
|
const TopoDS_Shape & resE = expl.Current() ;
|
|
if (myNewSection.Contains( resE )) // only new edges
|
|
MSE.Add(resE);
|
|
}
|
|
|
|
// DMEF: map edge of CSF - faces of CSF
|
|
TopTools_IndexedDataMapOfShapeListOfShape DMEF;
|
|
TopExp::MapShapesAndAncestors(CSF, TopAbs_EDGE, TopAbs_FACE, DMEF);
|
|
|
|
// Fill
|
|
// 1. MFP - a map of faces to process: map of resulting faces except
|
|
// those of theShape; we`ll add to C those of them which are inside CSF
|
|
// 2. DMSEFP - edge of MSE => faces of MFP
|
|
TopTools_ListIteratorOfListOfShape itl;
|
|
for (itl.Initialize(myListShapes);itl.More();itl.Next()) {
|
|
const TopoDS_Shape& aShape = itl.Value();
|
|
if ( theShape.IsSame( aShape )) continue;
|
|
// fill maps
|
|
// iterate on split faces of aShape
|
|
TopoDS_Iterator itF ( myImageShape.Image(aShape).First() );
|
|
for ( ; itF.More(); itF.Next()) {
|
|
const TopoDS_Shape& sf = itF.Value();
|
|
MFP.Add(sf);
|
|
// iterate on edges of split faces of aShape,
|
|
// add to DMSEFP edges that are new
|
|
for (expl.Init( sf, TopAbs_EDGE ); expl.More(); expl.Next()) {
|
|
TopoDS_Shape se = expl.Current();
|
|
if ( MSE.Contains(se)) {// section edge
|
|
if (!DMSEFP.IsBound(se))
|
|
DMSEFP.Bind(se,EmptyL);
|
|
DMSEFP(se).Append(sf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// add tool faces having section edges on faces of theShape to MFP and DMSEFP;
|
|
// such tool faces need not to be reconstructed and so they are not in myListShapes
|
|
for (itm.Initialize(myMapTools); itm.More(); itm.Next())
|
|
{
|
|
const TopoDS_Shape & aToolFace = itm.Key();
|
|
if (myMapFaces.Contains( aToolFace ))
|
|
continue;
|
|
MFP.Add(aToolFace);
|
|
for (expl.Init( aToolFace, TopAbs_EDGE ); expl.More(); expl.Next()) {
|
|
TopoDS_Shape se = expl.Current();
|
|
if ( MSE.Contains( se )) {// section edge
|
|
if (!DMSEFP.IsBound( se ))
|
|
DMSEFP.Bind( se, EmptyL );
|
|
DMSEFP( se ).Append( aToolFace );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ===========================
|
|
// find faces inside theShape
|
|
// ===========================
|
|
|
|
Standard_Boolean skipAlreadyAdded = Standard_False;
|
|
Standard_Boolean GoodOri, inside;
|
|
Standard_Real dot;
|
|
TopTools_ListOfShape KeepFaces;
|
|
TopTools_DataMapIteratorOfDataMapOfShapeListOfShape Mapit;
|
|
|
|
// iterate on section edges, check faces of other shapes
|
|
// sharing section edges and put internal faces to KeepFaces
|
|
for (Mapit.Initialize(DMSEFP); Mapit.More() ; Mapit.Next() ) {
|
|
// a new edge of theShape
|
|
const TopoDS_Edge& E = TopoDS::Edge (Mapit.Key());
|
|
// an original edge of which E is a split
|
|
const TopoDS_Edge& OrigE = TopoDS::Edge ( myImagesEdges.Root( E ));
|
|
// does OrigE itself splits a face
|
|
Standard_Boolean isSectionE = myInter3d.IsSectionEdge ( OrigE );
|
|
|
|
// split faces of other shapes sharing E
|
|
TopTools_ListOfShape& LSF = DMSEFP.ChangeFind(E);
|
|
itl.Initialize( LSF );
|
|
while (itl.More()) {
|
|
// a split faces of other shape
|
|
TopoDS_Face aFace1 = TopoDS::Face(itl.Value());
|
|
// remove aFace1 form DMSEFP and MFP
|
|
LSF.Remove( itl ); // == itl.Next();
|
|
if (!MFP.Remove( aFace1 ))
|
|
continue; // was not is MFP ( i.e already checked)
|
|
// check if aFace1 was already added to 2 shells
|
|
if (!All &&
|
|
myAddedFacesMap.Contains( aFace1 ) &&
|
|
myAddedFacesMap.Contains( aFace1.Reversed() )) {
|
|
skipAlreadyAdded = Standard_True;
|
|
continue;
|
|
}
|
|
|
|
// find another face which originates from the same face as aFace1:
|
|
// usually aFace2 is internal if aFace1 is not and vice versa
|
|
|
|
TopoDS_Shape anOrigFace = aFace1;
|
|
if (myImagesFaces.IsImage(aFace1))
|
|
anOrigFace = myImagesFaces.Root(aFace1);
|
|
TopoDS_Shape aFace2;
|
|
if ( !isSectionE ) {
|
|
while (itl.More()) {
|
|
aFace2 = itl.Value();
|
|
if (!MFP.Contains( aFace2 )) {
|
|
LSF.Remove( itl );
|
|
continue;
|
|
}
|
|
if (anOrigFace.IsSame( myImagesFaces.Root( aFace2 )))
|
|
break;
|
|
itl.Next();
|
|
}
|
|
if (itl.More()) { // aFace2 found, remove it from maps
|
|
LSF.Remove( itl );
|
|
MFP.Remove(aFace2);
|
|
}
|
|
else
|
|
aFace2.Nullify();
|
|
itl.Initialize( LSF );
|
|
}
|
|
|
|
// check that anOrigFace is not same domain with CSF faces it intersects
|
|
|
|
const TopTools_ListOfShape& FL = DMEF.FindFromKey(E); //faces of CSF sharing E
|
|
const TopoDS_Shape& origF1 = myImagesFaces.Root(FL.First());
|
|
const TopoDS_Shape& origF2 = myImagesFaces.Root(FL.Last());
|
|
Standard_Boolean sameDom1 = anOrigFace.IsSame( origF1 );
|
|
Standard_Boolean sameDom2 = anOrigFace.IsSame( origF2 );
|
|
if (!(sameDom1 || sameDom2) && myInter3d.HasSameDomainF( anOrigFace )) {
|
|
sameDom1 = myInter3d.IsSameDomainF( anOrigFace, origF1);
|
|
if (origF1 == origF2)
|
|
sameDom2 = sameDom1;
|
|
else
|
|
myInter3d.IsSameDomainF( anOrigFace, origF2);
|
|
}
|
|
if (sameDom1 && sameDom2)
|
|
continue;
|
|
if ((sameDom1 || sameDom2)) {
|
|
inside = Partition_Loop3d::IsInside (E,
|
|
TopoDS::Face(FL.First()),
|
|
TopoDS::Face(FL.Last()),
|
|
1, dot, GoodOri);
|
|
if (inside || (dot + Precision::Angular() >= 1.0))
|
|
continue; // E is convex between origF1 and origF2 or they are tangent
|
|
}
|
|
|
|
|
|
// keep one of found faces
|
|
|
|
//face of CSF sharing E
|
|
const TopoDS_Shape& aShapeFace = sameDom1 ? FL.Last() : FL.First();
|
|
// analyse aFace1 state
|
|
inside = Partition_Loop3d::IsInside (E, TopoDS::Face(aShapeFace), aFace1,
|
|
1, dot, GoodOri);
|
|
if (inside && isSectionE)
|
|
{
|
|
// aFace1 must be tested with both adjacent faces of CSF
|
|
const TopoDS_Shape& aShapeFace2 = sameDom1 ? FL.First() : FL.Last();
|
|
if (aShapeFace2 != aShapeFace)
|
|
inside = Partition_Loop3d::IsInside (E, TopoDS::Face(aShapeFace2), aFace1,
|
|
1, dot, GoodOri);
|
|
}
|
|
|
|
// store internal face
|
|
if (inside)
|
|
KeepFaces.Append(aFace1);
|
|
|
|
else if (!aFace2.IsNull())
|
|
{
|
|
if (dot + Precision::Angular() >= 1.0)
|
|
{
|
|
// aFace2 state is not clear, it will be analysed alone,
|
|
// put it back to the maps
|
|
MFP.Add( aFace2 );
|
|
LSF.Append( aFace2 );
|
|
}
|
|
else
|
|
KeepFaces.Append(aFace2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===================================================
|
|
// add not distributed faces connected with KeepFaces
|
|
// ===================================================
|
|
|
|
// ultimate list of internal faces
|
|
TopTools_ListOfShape KeptFaces;
|
|
|
|
// add to MFP unsplit tool faces as well, they may be connected with
|
|
// tool faces interfering with theShape
|
|
for ( itm.Initialize(myMapTools); itm.More(); itm.Next() ) {
|
|
const TopoDS_Shape& aToolFace = itm.Key();
|
|
if (!myImageShape.HasImage(aToolFace))
|
|
MFP.Add (aToolFace);
|
|
}
|
|
|
|
if (MFP.IsEmpty())
|
|
KeptFaces.Append (KeepFaces);
|
|
|
|
while (!KeepFaces.IsEmpty())
|
|
{
|
|
// KeepEdges : map of edges of faces kept last time
|
|
TopTools_IndexedMapOfShape KeepEdges;
|
|
for ( itl.Initialize(KeepFaces); itl.More(); itl.Next() ) {
|
|
TopExp::MapShapes( itl.Value(), TopAbs_EDGE, KeepEdges);
|
|
KeptFaces.Append( itl.Value() );
|
|
}
|
|
|
|
KeepFaces.Clear();
|
|
|
|
// keep faces connected with already kept faces by KeepEdges
|
|
for ( itm.Initialize(MFP); itm.More(); itm.Next() ) {
|
|
const TopoDS_Shape& FP = itm.Key();
|
|
for (expl.Init(FP,TopAbs_EDGE); expl.More(); expl.Next()) {
|
|
const TopoDS_Shape& se = expl.Current();
|
|
if (!MSE.Contains(se) && KeepEdges.Contains(se) ) {
|
|
KeepFaces.Append(FP);
|
|
MFP.Remove(FP);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===============================================================
|
|
// here MFP contains faces outer of theShape and those of shapes
|
|
// which do not interfere with theShape at all and between which
|
|
// there may be those wrapped by theShape and whose faces may be
|
|
// needed to be returned as well
|
|
// ===============================================================
|
|
|
|
Standard_Boolean isSolid = (theShape.ShapeType() == TopAbs_SOLID);
|
|
if (All || isSolid) // All is for sub-result removal
|
|
{
|
|
// loop on not used faces; checked faces will be removed from MFP
|
|
// during the loop
|
|
for ( itm.Initialize( MFP ); itm.More(); itm.Next() ) {
|
|
const TopoDS_Shape & aFace = itm.Key();
|
|
|
|
// a shape which aFace originates from
|
|
TopoDS_Shape anOrigShape = GetOriginalShape( aFace );
|
|
|
|
// find out if all split faces of anOrigShape are not in MFP
|
|
// and by the way remove them from MFP
|
|
Standard_Boolean isAllOut = Standard_True;
|
|
TopoDS_Shape aSplitFaces = anOrigShape;
|
|
if (myImageShape.HasImage(anOrigShape))
|
|
aSplitFaces = myImageShape.Image(anOrigShape).First();
|
|
|
|
TopTools_ListOfShape aSplitFaceL; // faces candidate to be kept
|
|
for (expl.Init( aSplitFaces, TopAbs_FACE ); expl.More(); expl.Next())
|
|
{
|
|
const TopoDS_Shape & aSpFace = expl.Current();
|
|
// a tool face which became object has image but the whole tool shape has not
|
|
if (myImageShape.HasImage( aSpFace ))
|
|
{
|
|
TopExp_Explorer exF (myImageShape.Image( aSpFace ).First(), TopAbs_FACE );
|
|
for ( ; exF.More(); exF.Next() )
|
|
{
|
|
aSplitFaceL.Append( exF.Current() );
|
|
if ( ! MFP.Remove( exF.Current() ) && isAllOut )
|
|
// a shared face might be removed from MFP during a prev loop
|
|
isAllOut = mySharedFaces.Contains( exF.Current() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aSplitFaceL.Append( aSpFace );
|
|
if ( ! MFP.Remove( aSpFace ) && isAllOut)
|
|
// a shared face might be removed from MFP during a prev loop
|
|
isAllOut = mySharedFaces.Contains( aSpFace );
|
|
}
|
|
}
|
|
itm.Initialize( MFP ); // iterate remaining faces
|
|
if ( !isAllOut )
|
|
continue;
|
|
|
|
// classify anOrigShape against theShape
|
|
if (IsInside (anOrigShape, theShape))
|
|
{
|
|
if (isSolid && myClosedShapes.Contains( anOrigShape ))
|
|
// to make a special care at solid reconstruction
|
|
myWrappingSolid.Add ( theShape );
|
|
|
|
// keep faces of an internal shape anOrigShape
|
|
KeptFaces.Append( aSplitFaceL );
|
|
}
|
|
}
|
|
}
|
|
|
|
// ====================================================
|
|
// check if kept faces form a shell without free edges
|
|
// ====================================================
|
|
|
|
DMEF.Clear(); // edge - kept faces
|
|
MFP.Clear(); // reuse it for wrong faces
|
|
if (CheckClosed) {
|
|
for (itl.Initialize(KeptFaces); itl.More(); itl.Next() )
|
|
TopExp::MapShapesAndAncestors(itl.Value(), TopAbs_EDGE, TopAbs_FACE, DMEF);
|
|
|
|
Standard_Integer i, nb = DMEF.Extent();
|
|
Standard_Boolean isClosed = Standard_False;
|
|
while (!isClosed) {
|
|
isClosed = Standard_True;
|
|
for (i=1; isClosed && i<=nb; ++i) {
|
|
const TopoDS_Shape& E = DMEF.FindKey( i );
|
|
if (! BRep_Tool::Degenerated( TopoDS::Edge( E )) &&
|
|
! MSE.Contains( E ))
|
|
isClosed = ( DMEF(i).Extent() != 1 );
|
|
}
|
|
if (!isClosed) {
|
|
const TopoDS_Shape& F = DMEF.FindFromIndex( i-1 ).First(); // bad face
|
|
MFP.Add( F );
|
|
// remove bad face from DMEF
|
|
for (expl.Init( F, TopAbs_EDGE); expl.More(); expl.Next()) {
|
|
const TopoDS_Shape& E = expl.Current();
|
|
TopTools_ListOfShape& FL = DMEF.ChangeFromKey( E );
|
|
for (itl.Initialize( FL ); itl.More(); itl.Next() ) {
|
|
if ( F.IsSame( itl.Value() )) {
|
|
FL.Remove( itl );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ==============
|
|
// make a result
|
|
// ==============
|
|
|
|
TopoDS_Compound C;
|
|
// compound of removed internal faces
|
|
TopoDS_Compound CNotCl;
|
|
|
|
myBuilder.MakeCompound(C);
|
|
myBuilder.MakeCompound(CNotCl);
|
|
|
|
// add to compounds
|
|
for (itl.Initialize(KeptFaces); itl.More(); itl.Next() )
|
|
{
|
|
TopoDS_Shape & aIntFace = itl.Value();
|
|
if (! MFP.Contains( aIntFace ))
|
|
myBuilder.Add( C, aIntFace);
|
|
else
|
|
myBuilder.Add( CNotCl, aIntFace);
|
|
}
|
|
|
|
if (!skipAlreadyAdded && CheckClosed)
|
|
{
|
|
myInternalFaces.Bind( theShape, C );
|
|
myIntNotClFaces.Bind( theShape, CNotCl );
|
|
}
|
|
|
|
return C;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MakeShell
|
|
//purpose : split S into compound of shells
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::MakeShells(const TopoDS_Shape& S,
|
|
TopTools_ListOfShape& NS)
|
|
{
|
|
Partition_Loop3d ShellMaker;
|
|
// get compound of split faces of S
|
|
const TopoDS_Shape& FacesComp = myImageShape.Image(S).First();
|
|
ShellMaker.AddConstFaces( FacesComp );
|
|
// add split faces inside S
|
|
if (myClosedShapes.Contains( S )) {
|
|
TopoDS_Shape InternalFacesComp = FindFacesInside(S, Standard_True);
|
|
ShellMaker.AddSectionFaces( InternalFacesComp );
|
|
}
|
|
|
|
NS = ShellMaker.MakeShells( myAddedFacesMap );
|
|
|
|
// Add faces added to new shell to myAddedFacesMap:
|
|
// avoid rebuilding twice common part of 2 solids.
|
|
TopTools_ListIteratorOfListOfShape itS(NS);
|
|
while ( itS.More()) {
|
|
TopExp_Explorer expF (itS.Value(), TopAbs_FACE);
|
|
for (; expF.More(); expF.Next())
|
|
myAddedFacesMap.Add (expF.Current());
|
|
|
|
itS.Next();
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : findEqual
|
|
//purpose : compare edges of EL1 against edges of EL2,
|
|
// Result is in EMM binding EL1 edges to list of equal edges.
|
|
// Edges are considered equal only if they have same vertices.
|
|
// <addSame>==True makes consider same edges as equal
|
|
// Put in <AllEqMap> all equal edges
|
|
//=======================================================================
|
|
|
|
static void findEqual (const TopTools_ListOfShape& EL1,
|
|
const TopTools_ListOfShape& EL2,
|
|
const Standard_Boolean addSame,
|
|
TopTools_DataMapOfShapeListOfShape& EEM,
|
|
TopTools_MapOfShape& AllEqMap)
|
|
{
|
|
// map vertices to edges for EL2
|
|
TopTools_DataMapOfShapeListOfShape VEM;
|
|
TopTools_ListIteratorOfListOfShape itE1, itE2(EL2);
|
|
TopoDS_Iterator itV;
|
|
TopTools_ListOfShape emptyL;
|
|
for (; itE2.More(); itE2.Next()) {
|
|
for (itV.Initialize( itE2.Value() ); itV.More(); itV.Next()) {
|
|
const TopoDS_Shape& V = itV.Value();
|
|
if (! VEM.IsBound( V ) )
|
|
VEM.Bind( V, emptyL);
|
|
VEM( V ).Append( itE2.Value());
|
|
}
|
|
}
|
|
|
|
gp_Vec D1, D2;
|
|
gp_Pnt P;
|
|
Standard_Real f,l,u,tol;
|
|
Handle(Geom_Curve) C1, C2;
|
|
Extrema_ExtPC Extrema;
|
|
TopoDS_Vertex V1, V2, V3, V4;
|
|
|
|
AllEqMap.Clear();
|
|
|
|
for (itE1.Initialize(EL1); itE1.More(); itE1.Next()) {
|
|
const TopoDS_Edge& E1 = TopoDS::Edge( itE1.Value());
|
|
if (BRep_Tool::Degenerated( E1 ) || AllEqMap.Contains (E1))
|
|
continue;
|
|
TopExp::Vertices( E1, V1, V2 );
|
|
|
|
if (VEM.IsBound(V1))
|
|
itE2.Initialize( VEM(V1) );
|
|
for (; itE2.More(); itE2.Next()) {
|
|
const TopoDS_Edge& E2 = TopoDS::Edge( itE2.Value());
|
|
if (BRep_Tool::Degenerated( E2 ) || AllEqMap.Contains (E2))
|
|
continue;
|
|
|
|
if (E1.IsSame(E2)) {
|
|
if (!addSame)
|
|
continue;
|
|
}
|
|
else {
|
|
TopExp::Vertices( E2, V3, V4);
|
|
if (!V2.IsSame(V4) && !V2.IsSame(V3))
|
|
continue;
|
|
// E1 and E2 have same vertices
|
|
// check D1 at end points.
|
|
C2 = BRep_Tool::Curve( E2, f,l);
|
|
C1 = BRep_Tool::Curve( E1, f,l);
|
|
u = BRep_Tool::Parameter(V1,E1);
|
|
C1->D1(u, P, D1);
|
|
u = BRep_Tool::Parameter(V1.IsSame(V3) ? V3 : V4, E2);
|
|
C2->D1(u, P, D2);
|
|
D1.Normalize(); D2.Normalize();
|
|
if (Abs(D1*D2) + Precision::Angular() < 1.0)
|
|
continue;
|
|
if (! V1.IsSame(V2)) {
|
|
u = BRep_Tool::Parameter(V2,E1);
|
|
C1->D1(u, P, D1);
|
|
u = BRep_Tool::Parameter(V2.IsSame(V3) ? V3 : V4, E2);
|
|
C2->D1(u, P, D2);
|
|
D1.Normalize(); D2.Normalize();
|
|
if (Abs(D1*D2) + Precision::Angular() < 1.0)
|
|
continue;
|
|
}
|
|
// check distance at a couple of internal points
|
|
tol = Max(BRep_Tool::Tolerance(E1),
|
|
BRep_Tool::Tolerance(E2));
|
|
GeomAdaptor_Curve AC1(C1);
|
|
Extrema.Initialize(AC1,f,l);
|
|
Standard_Boolean ok = Standard_True, hasMin = Standard_False;
|
|
BRep_Tool::Range( E2, f, l);
|
|
Standard_Integer i=1, nbi=3;
|
|
for (; i<nbi && ok; ++i) {
|
|
Extrema.Perform( C2->Value( f+(l-f)*i/nbi ));
|
|
Standard_Integer j=1, nbj=Extrema.NbExt();
|
|
for (; j<=nbj && ok; ++j) {
|
|
if (Extrema.IsMin(j)) {
|
|
hasMin = Standard_True;
|
|
// ok = Extrema.Value(j) <= tol; // V6.3
|
|
ok = Extrema.SquareDistance(j) <= tol; // V6.5
|
|
}
|
|
}
|
|
}
|
|
if ( !hasMin || !ok)
|
|
continue;
|
|
}
|
|
// bind E2 to E1 in EEM
|
|
if (!EEM.IsBound(E1)) {
|
|
EEM.Bind (E1, emptyL);
|
|
AllEqMap.Add (E1);
|
|
}
|
|
EEM(E1).Append(E2);
|
|
AllEqMap.Add (E2);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MakeFaces
|
|
//purpose : split faces of S, return compound of new faces
|
|
//=======================================================================
|
|
|
|
TopoDS_Shape Partition_Spliter::MakeFaces (const TopoDS_Shape& S)
|
|
{
|
|
TopoDS_Compound C;
|
|
myBuilder.MakeCompound(C);
|
|
|
|
TopTools_ListIteratorOfListOfShape itl, itNE;
|
|
|
|
TopExp_Explorer exp(S,TopAbs_FACE);
|
|
for (; exp.More(); exp.Next()) {
|
|
|
|
const TopoDS_Face& F = TopoDS::Face(exp.Current());
|
|
|
|
TopTools_ListOfShape LNF;
|
|
|
|
if (myImagesFaces.HasImage( F )) {
|
|
myImagesFaces.LastImage( F, LNF );
|
|
TopAbs_Orientation oriF = F.Orientation();
|
|
for ( itl.Initialize( LNF ); itl.More(); itl.Next())
|
|
itl.Value().Orientation( oriF );
|
|
}
|
|
else {
|
|
|
|
Partition_Loop2d loops;
|
|
loops.Init(F);
|
|
|
|
TopTools_IndexedMapOfShape EM;
|
|
TopExp::MapShapes( F, TopAbs_EDGE, EM);
|
|
|
|
TopTools_MapOfShape AddedEqualM, EqualSeamM;
|
|
Standard_Boolean needRebuild = Standard_False;
|
|
|
|
// add splits to loops
|
|
|
|
// LE: old edges + new unsplit edges
|
|
const TopTools_ListOfShape& LE = myAsDes->Descendant(F);
|
|
for (itl.Initialize(LE); itl.More(); itl.Next()) {
|
|
const TopoDS_Edge& E = TopoDS::Edge( itl.Value() );
|
|
|
|
Standard_Boolean isSectionE = myInter3d.IsSectionEdge(E);
|
|
Standard_Boolean isNewE = !EM.Contains( E );
|
|
|
|
// LSE: list of split edges
|
|
TopTools_ListOfShape LSE;
|
|
myImagesEdges.LastImage(E,LSE); // splits of E or E itself
|
|
|
|
for (itNE.Initialize(LSE); itNE.More(); itNE.Next()) {
|
|
|
|
TopoDS_Edge NE = TopoDS::Edge( itNE.Value() );
|
|
Standard_Boolean isSameE = NE.IsSame ( E );
|
|
|
|
if ( isNewE || isSectionE || !isSameE) {
|
|
if (AddedEqualM.Contains( NE )) {
|
|
// a seam must be twice in a loop
|
|
if (!BRep_Tool::IsClosed( E, F ) || !EqualSeamM.Add( NE ))
|
|
continue;
|
|
}
|
|
|
|
if (isNewE) {
|
|
if (isSectionE) {
|
|
if ( ! myInter3d.IsSplitOn( NE, E, F) )
|
|
continue;
|
|
}
|
|
else {
|
|
TopoDS_Vertex V1,V2;
|
|
TopExp::Vertices(NE,V1,V2);
|
|
const TopTools_ListOfShape& EL1 = myAsDes->Ascendant(V1);
|
|
const TopTools_ListOfShape& EL2 = myAsDes->Ascendant(V2);
|
|
if ( EL1.Extent() < 2 && EL2.Extent() < 2 )
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
NE.Orientation( E.Orientation());
|
|
if (!isSameE) {
|
|
// orient NE because it may be a split of other edge
|
|
Standard_Real f,l,u;
|
|
Handle(Geom_Curve) C3d = BRep_Tool::Curve( E,f,l );
|
|
Handle(Geom_Curve) NC3d = BRep_Tool::Curve( NE,f,l);
|
|
if ( C3d != NC3d) {
|
|
gp_Vec D1, ND1; gp_Pnt P;
|
|
TopoDS_Vertex V = TopExp::FirstVertex(NE);
|
|
u = BRep_Tool::Parameter(V,NE);
|
|
NC3d->D1 (u, P, ND1);
|
|
u = BRep_Tool::Parameter(V,E);
|
|
C3d ->D1 (u, P, D1);
|
|
if (ND1.Dot(D1) < 0)
|
|
NE.Reverse();
|
|
}
|
|
}
|
|
}
|
|
if (myEqualEdges.Contains( NE ))
|
|
AddedEqualM.Add( NE );
|
|
|
|
needRebuild = Standard_True;
|
|
}
|
|
|
|
if (isNewE || isSectionE)
|
|
myNewSection.Add( NE );
|
|
|
|
if (isNewE)
|
|
loops.AddSectionEdge(NE);
|
|
else
|
|
loops.AddConstEdge(NE);
|
|
}
|
|
}
|
|
|
|
//-------------------
|
|
// Build the faces.
|
|
//-------------------
|
|
|
|
if (needRebuild) {
|
|
|
|
loops.Perform();
|
|
loops.WiresToFaces(myImagesEdges);
|
|
|
|
LNF = loops.NewFaces();
|
|
|
|
myImagesFaces.Bind(F,LNF);
|
|
|
|
// replace the result faces that have already been built
|
|
// during same domain faces reconstruction done earlier
|
|
if (myInter3d.HasSameDomainF( F ))
|
|
{
|
|
// build map edge to same domain faces: EFM
|
|
TopTools_IndexedDataMapOfShapeListOfShape EFM;
|
|
TopTools_MapOfShape SDFM; // avoid doubling
|
|
itl.Initialize( myInter3d.SameDomain( F ));
|
|
for (; itl.More(); itl.Next()) {
|
|
if ( !myImagesFaces.HasImage( itl.Value() ))
|
|
continue;
|
|
// loop on splits of a SD face
|
|
TopTools_ListIteratorOfListOfShape itNF;
|
|
itNF.Initialize (myImagesFaces.Image( itl.Value() ));
|
|
for ( ; itNF.More(); itNF.Next()) {
|
|
TopoDS_Shape SDF = itNF.Value();
|
|
if (myImagesFaces.HasImage( SDF )) // already replaced
|
|
SDF = myImagesFaces.Image( SDF ).First();
|
|
if (SDFM.Add (SDF))
|
|
TopExp::MapShapesAndAncestors(SDF, TopAbs_EDGE, TopAbs_FACE, EFM);
|
|
}
|
|
}
|
|
// do replace faces in the LNF
|
|
TopTools_ListOfShape LOF;
|
|
if ( !EFM.IsEmpty() )
|
|
itl.Initialize( LNF );
|
|
while (itl.More()) {
|
|
const TopoDS_Shape& NF = itl.Value();
|
|
TopExp_Explorer expE ( NF, TopAbs_EDGE );
|
|
const TopoDS_Edge& E = TopoDS::Edge (expE.Current());
|
|
if (EFM.Contains( E )) {
|
|
const TopTools_ListOfShape& SDFL = EFM.FindFromKey( E );
|
|
TopoDS_Shape SDF = SDFL.First();
|
|
Standard_Boolean GoodOri;
|
|
Standard_Real dot;
|
|
Partition_Loop3d::IsInside (E, TopoDS::Face(NF), TopoDS::Face(SDF),
|
|
1, dot, GoodOri);
|
|
if (dot < 0)
|
|
{
|
|
// NF and SDF are on different side of E
|
|
if (SDFL.Extent() == 1) {
|
|
itl.Next();
|
|
continue;
|
|
}
|
|
else
|
|
SDF = SDFL.Last(); // next face must be on the same side
|
|
}
|
|
gp_Vec V1 = Partition_Loop3d::Normal( E, TopoDS::Face( NF ));
|
|
gp_Vec V2 = Partition_Loop3d::Normal( E, TopoDS::Face( SDF ));
|
|
if (V1*V2 < 0)
|
|
SDF.Reverse();
|
|
|
|
if (!myImagesFaces.HasImage( NF ))
|
|
myImagesFaces.Bind( NF, SDF );
|
|
|
|
// mySharedFaces is used in FindFacesInside()
|
|
mySharedFaces.Add( SDF );
|
|
|
|
LOF.Prepend ( SDF );
|
|
LNF.Remove (itl);
|
|
}
|
|
else
|
|
itl.Next();
|
|
}
|
|
|
|
LNF.Append (LOF);
|
|
}
|
|
} // if (needRebuild)
|
|
|
|
else {
|
|
LNF.Append( F );
|
|
myImagesFaces.Bind(F,LNF);
|
|
}
|
|
} // if (myImagesFaces.HasImage( F ))
|
|
|
|
// fill the resulting compound
|
|
for (itl.Initialize(LNF); itl.More(); itl.Next())
|
|
myBuilder.Add ( C, itl.Value());
|
|
|
|
} // loop on faces of S
|
|
|
|
return C;
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : Tri
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
static void Tri(const TopoDS_Edge& E,
|
|
TopTools_SequenceOfShape& Seq,
|
|
const Partition_Inter3d & theInter3d)
|
|
{
|
|
Standard_Boolean Invert = Standard_True;
|
|
Standard_Real U1,U2;
|
|
TopoDS_Vertex V1,V2;
|
|
|
|
while (Invert) {
|
|
Invert = Standard_False;
|
|
for ( Standard_Integer i = 1; i < Seq.Length(); i++) {
|
|
|
|
V1 = TopoDS::Vertex(Seq.Value(i));
|
|
V2 = TopoDS::Vertex(Seq.Value(i+1));
|
|
|
|
V1.Orientation(TopAbs_INTERNAL);
|
|
V2.Orientation(TopAbs_INTERNAL);
|
|
|
|
U1 = BRep_Tool::Parameter(V1,E);
|
|
U2 = BRep_Tool::Parameter(V2,E);
|
|
|
|
if (IsEqual(U1,U2)) {
|
|
if (theInter3d.ReplaceSameDomainV( V1, E ).IsSame( V1 ))
|
|
Seq.Remove(i+1); // remove V2
|
|
else
|
|
Seq.Remove(i);
|
|
i--;
|
|
continue;
|
|
}
|
|
if (U2 < U1) {
|
|
Seq.Exchange(i,i+1);
|
|
Invert = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MakeEdges
|
|
//purpose : cut E by vertices VOnE, return list of new edges NE
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::MakeEdges (const TopoDS_Edge& E,
|
|
const TopTools_ListOfShape& VOnE,
|
|
TopTools_ListOfShape& NE ) const
|
|
{
|
|
TopoDS_Edge WE = E;
|
|
WE.Orientation(TopAbs_FORWARD);
|
|
|
|
Standard_Real U1,U2, f, l;
|
|
TopoDS_Vertex V1,V2,VF,VL;
|
|
|
|
BRep_Tool::Range(WE,f,l);
|
|
TopExp::Vertices(WE,VF,VL);
|
|
|
|
if (VOnE.Extent() < 3) { // do not rebuild not cut edge
|
|
if (( VF.IsSame( VOnE.First() ) && VL.IsSame( VOnE.Last() )) ||
|
|
(VL.IsSame( VOnE.First() ) && VF.IsSame( VOnE.Last() )) ) {
|
|
NE.Append( E );
|
|
return;
|
|
}
|
|
}
|
|
|
|
TopTools_SequenceOfShape SV;
|
|
TopTools_ListIteratorOfListOfShape itv(VOnE);
|
|
TopTools_MapOfOrientedShape VM( VOnE.Extent() );
|
|
for (; itv.More(); itv.Next())
|
|
if ( VM.Add( itv.Value() ))
|
|
SV.Append(itv.Value());
|
|
|
|
Tri( WE, SV, myInter3d );
|
|
|
|
if (SV.Length() < 3) { // do not rebuild not cut edge
|
|
if (( VF.IsSame( SV.First() ) && VL.IsSame( SV.Last() )) ||
|
|
( VL.IsSame( SV.First() ) && VF.IsSame( SV.Last() )) ) {
|
|
NE.Append( E );
|
|
return;
|
|
}
|
|
}
|
|
|
|
Standard_Integer iVer, NbVer = SV.Length();
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Construction of the new edges.
|
|
//----------------------------------------------------------------
|
|
|
|
if (VF.IsSame(VL)) { // closed edge
|
|
if (NbVer==1)
|
|
SV.Append( SV.First() );
|
|
else if (!SV.First().IsSame(SV.Last())) {
|
|
Standard_Boolean isFirst=0;
|
|
Standard_Real minDU = 1.e10;
|
|
TopoDS_Vertex endV = Partition_Inter2d::FindEndVertex(VOnE, f,l, E, isFirst,minDU);
|
|
if (endV.IsSame(SV.First()))
|
|
SV.Append(endV);
|
|
else if (endV.IsSame(SV.Last()))
|
|
SV.Prepend(endV);
|
|
else
|
|
MESSAGE ("END VERTEX IS IN SEQUENCE MIDDLE");
|
|
}
|
|
NbVer = SV.Length();
|
|
}
|
|
|
|
for (iVer=1; iVer < NbVer; iVer++) {
|
|
V1 = TopoDS::Vertex(SV(iVer));
|
|
V2 = TopoDS::Vertex(SV(iVer+1));
|
|
|
|
TopoDS_Shape NewEdge = WE.EmptyCopied();
|
|
V1.Orientation(TopAbs_FORWARD);
|
|
myBuilder.Add (NewEdge,V1);
|
|
V2.Orientation(TopAbs_REVERSED);
|
|
myBuilder.Add (NewEdge,V2);
|
|
|
|
if (iVer==1)
|
|
U1 = f;
|
|
else {
|
|
V1.Orientation(TopAbs_INTERNAL);
|
|
U1=BRep_Tool::Parameter(V1,WE);
|
|
}
|
|
if (iVer+1 == NbVer)
|
|
U2 = l;
|
|
else {
|
|
V2.Orientation(TopAbs_INTERNAL);
|
|
U2=BRep_Tool::Parameter(V2,WE);
|
|
}
|
|
if (Abs(U1-U2) <= Precision::PConfusion()) {
|
|
MESSAGE( "MakeEdges(), EQUAL PARAMETERS OF DIFFERENT VERTICES");
|
|
continue;
|
|
}
|
|
TopoDS_Edge EE=TopoDS::Edge(NewEdge);
|
|
myBuilder.Range (EE,U1,U2);
|
|
|
|
TopoDS_Edge NEdge = TopoDS::Edge(NewEdge);
|
|
myBuilder.SameParameter(NEdge,Standard_False);
|
|
|
|
Standard_Real tol = 1.0e-2;
|
|
Standard_Boolean flag = BRep_Tool::SameParameter(NEdge);
|
|
if (!flag) {
|
|
BRepLib::SameParameter(NEdge,tol);
|
|
}
|
|
NE.Append(NEdge.Oriented(E.Orientation()));
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MergeEqualEdges
|
|
//purpose : find equal edges, choose ones to keep and make
|
|
// them have pcurves on all faces they are shared by
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::MergeEqualEdges (const TopTools_ListOfShape& LSE)
|
|
{
|
|
// find equal edges
|
|
// map: edge - equal edges
|
|
TopTools_DataMapOfShapeListOfShape EEM( LSE.Extent() );
|
|
findEqual (LSE, LSE, 0, EEM, myEqualEdges);
|
|
|
|
TopTools_ListOfShape EEL; // list of equal edges
|
|
TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itM (EEM);
|
|
for ( ; itM.More(); itM.Next()) {
|
|
EEL = itM.Value();
|
|
EEL.Append( itM.Key() );
|
|
|
|
// choose an edge to keep, section edges have priority
|
|
TopoDS_Edge EKeep;
|
|
TopTools_ListIteratorOfListOfShape itEE (EEL);
|
|
for (; itEE.More(); itEE.Next()) {
|
|
EKeep = TopoDS::Edge( itEE.Value() );
|
|
const TopoDS_Edge& EKeepOrig = TopoDS::Edge( myImagesEdges.Root( EKeep ));
|
|
if (myInter3d.IsSectionEdge( EKeepOrig ))
|
|
break;
|
|
}
|
|
|
|
// update edge images and build pcurves
|
|
Standard_Real f,l, tol;
|
|
for (itEE.Initialize (EEL); itEE.More(); itEE.Next()) {
|
|
const TopoDS_Edge& E = TopoDS::Edge( itEE.Value() );
|
|
if ( E.IsSame( EKeep ))
|
|
continue;
|
|
|
|
// 1. build pcurves of the kept edge on faces where replaced edges exist
|
|
const TopoDS_Edge& EReplOrig = TopoDS::Edge( myImagesEdges.Root( E ));
|
|
TopTools_ListOfShape FL;
|
|
FL = myAsDes->Ascendant( EReplOrig );
|
|
Standard_Integer iFace, iFirstSectionFace = FL.Extent() + 1;
|
|
// add faces where the replaced edge is a section edge
|
|
if (myInter3d.IsSectionEdge( EReplOrig )) {
|
|
TopTools_ListIteratorOfListOfShape seIt;
|
|
seIt.Initialize( myInter3d.SectionEdgeFaces ( EReplOrig ));
|
|
for ( ; seIt.More(); seIt.Next())
|
|
FL.Append( seIt.Value() );
|
|
}
|
|
// loop on faces
|
|
TopTools_ListIteratorOfListOfShape itF (FL);
|
|
for ( iFace = 1 ; itF.More(); itF.Next(), ++iFace ) {
|
|
const TopoDS_Face& F = TopoDS::Face( itF.Value());
|
|
|
|
Handle(Geom2d_Curve) pc = BRep_Tool::CurveOnSurface( EKeep, F, f,l);
|
|
if (pc.IsNull()) {
|
|
Handle(Geom_Curve) C3d = BRep_Tool::Curve( EKeep, f, l);
|
|
C3d = new Geom_TrimmedCurve( C3d, f,l);
|
|
pc = TopOpeBRepTool_CurveTool::MakePCurveOnFace (F,C3d,tol);
|
|
if (pc.IsNull()) {
|
|
MESSAGE (" CANNOT BUILD PCURVE ");
|
|
}
|
|
myBuilder.UpdateEdge( EKeep, pc, F, tol);
|
|
}
|
|
|
|
if (iFace >= iFirstSectionFace ||
|
|
!BRep_Tool::IsClosed( EReplOrig, F ))
|
|
continue;
|
|
|
|
// build the second pcurve for a seam
|
|
TopoDS_Vertex V = TopExp::FirstVertex( EKeep );
|
|
Standard_Real Ukeep = BRep_Tool::Parameter( V, EKeep );
|
|
Standard_Real Urepl = BRep_Tool::Parameter( V, E );
|
|
|
|
TopoDS_Edge EReplRev = E;
|
|
EReplRev.Reverse();
|
|
Handle(Geom2d_Curve) pcRepl1 = BRep_Tool::CurveOnSurface( E, F, f,l);
|
|
Handle(Geom2d_Curve) pcRepl2 = BRep_Tool::CurveOnSurface( EReplRev, F, f,l);
|
|
|
|
gp_Pnt2d p1r, p2r, pk;
|
|
p1r = pcRepl1->Value( Urepl );
|
|
p2r = pcRepl2->Value( Urepl );
|
|
pk = pc->Value( Ukeep );
|
|
|
|
// suppose that pk is equal to either p1r or p2r
|
|
Standard_Boolean isUPeriod =
|
|
( Abs( p1r.X() - p2r.X() ) > Abs( p1r.Y() - p2r.Y() ));
|
|
Standard_Boolean is1Equal;
|
|
if (isUPeriod)
|
|
is1Equal = ( Abs( p1r.X() - pk.X() ) < Abs( p2r.X() - pk.X() ));
|
|
else
|
|
is1Equal = ( Abs( p1r.Y() - pk.Y() ) < Abs( p2r.Y() - pk.Y() ));
|
|
|
|
Handle(Geom2d_Curve) pc2 = Handle(Geom2d_Curve)::DownCast
|
|
( pc->Translated( pk, is1Equal ? p2r : p1r ) );
|
|
|
|
if (E.Orientation() == TopAbs_REVERSED)
|
|
is1Equal = !is1Equal;
|
|
|
|
if (is1Equal)
|
|
myBuilder.UpdateEdge( EKeep, pc, pc2, F, tol);
|
|
else
|
|
myBuilder.UpdateEdge( EKeep, pc2, pc, F, tol);
|
|
|
|
} // loop on a Faces where a replaced edge exists
|
|
|
|
|
|
// 2. update edge images according to replacement
|
|
if (myImagesEdges.HasImage( E ))
|
|
myImagesEdges.Remove( E );
|
|
myImagesEdges.Bind( E, EKeep );
|
|
|
|
} // loop on a list of equal edges EEL
|
|
} // loop on a map of equal edges EEM
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : KeepShapesInside
|
|
//purpose : remove shapes that are outside of S from result
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::KeepShapesInside (const TopoDS_Shape& S)
|
|
{
|
|
TopoDS_Iterator it;
|
|
if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
|
|
for (it.Initialize( S ); it.More(); it.Next())
|
|
KeepShapesInside( it.Value());
|
|
return;
|
|
}
|
|
|
|
Standard_Boolean isTool = Standard_False;
|
|
if (!myImageShape.HasImage( S )) {
|
|
isTool = CheckTool( S );
|
|
if (!isTool) return;
|
|
}
|
|
|
|
// build map of internal faces
|
|
TopTools_IndexedMapOfShape MIF;
|
|
TopoDS_Shape IntFacesComp = FindFacesInside( S, Standard_False, Standard_True);
|
|
TopExp::MapShapes( IntFacesComp, TopAbs_FACE, MIF );
|
|
|
|
TopoDS_Compound C;
|
|
myBuilder.MakeCompound(C);
|
|
|
|
TopAbs_ShapeEnum anInternalShapeType = TopAbs_SHAPE;
|
|
if (!MIF.IsEmpty())
|
|
{
|
|
// leave in the result only those shapes having a face in MIF
|
|
for (it.Initialize( myShape ); it.More(); it.Next()) {
|
|
const TopoDS_Shape & aResShape = it.Value();
|
|
TopExp_Explorer expResF( aResShape, TopAbs_FACE );
|
|
for (; expResF.More(); expResF.Next()) {
|
|
if ( MIF.Contains( expResF.Current())) {
|
|
myBuilder.Add( C, aResShape );
|
|
if (aResShape.ShapeType() < anInternalShapeType)
|
|
anInternalShapeType = aResShape.ShapeType();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// may be S was not split by internal faces then it is missing
|
|
// in myShape, add it
|
|
if (!isTool &&
|
|
(anInternalShapeType > TopAbs_SOLID || S.ShapeType() > TopAbs_SOLID))
|
|
{
|
|
TopTools_IndexedMapOfShape MSF; // map of split faces of S
|
|
TopExp::MapShapes( myImageShape.Image(S).First(), TopAbs_FACE, MSF);
|
|
|
|
// find a shape having all faces in MSF
|
|
for (it.Initialize( myShape ); it.More(); it.Next()) {
|
|
TopExp_Explorer expResF( it.Value(), TopAbs_FACE );
|
|
for (; expResF.More(); expResF.Next()) {
|
|
if (! MSF.Contains( expResF.Current()))
|
|
break;
|
|
}
|
|
if (! expResF.More()) {
|
|
myBuilder.Add( C, it.Value() );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
myShape = C;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : RemoveShapesInside
|
|
//purpose : remove shapes that are inside S from result
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::RemoveShapesInside (const TopoDS_Shape& S)
|
|
{
|
|
TopoDS_Iterator it;
|
|
if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
|
|
for (it.Initialize( S ); it.More(); it.Next())
|
|
RemoveShapesInside( it.Value());
|
|
return;
|
|
}
|
|
Standard_Boolean isTool = Standard_False;
|
|
if (!myImageShape.HasImage( S )) {
|
|
isTool = CheckTool( S );
|
|
if (!isTool) return;
|
|
}
|
|
|
|
TopoDS_Shape IntFacesComp = FindFacesInside( S, Standard_False, Standard_True);
|
|
TopTools_IndexedMapOfShape MIF; // map of internal faces
|
|
TopExp::MapShapes( IntFacesComp, TopAbs_FACE, MIF);
|
|
|
|
if (MIF.IsEmpty()) return;
|
|
|
|
// add to MIF split faces of S
|
|
if (myImageShape.HasImage(S))
|
|
TopExp::MapShapes( myImageShape.Image(S).First(), TopAbs_FACE, MIF);
|
|
|
|
// leave in the result only those shapes not having all face in MIF
|
|
|
|
TopoDS_Compound C;
|
|
myBuilder.MakeCompound(C);
|
|
|
|
// RMF : faces of removed shapes that encounter once
|
|
TopTools_MapOfShape RFM;
|
|
|
|
for (it.Initialize( myShape ); it.More(); it.Next()) {
|
|
|
|
TopExp_Explorer expResF( it.Value(), TopAbs_FACE );
|
|
for (; expResF.More(); expResF.Next())
|
|
if (!MIF.Contains( expResF.Current()))
|
|
break;
|
|
|
|
if (expResF.More())
|
|
// add shape to result
|
|
myBuilder.Add( C, it.Value() );
|
|
else
|
|
// add faces of a removed shape to RFM
|
|
for (expResF.ReInit(); expResF.More(); expResF.Next()) {
|
|
const TopoDS_Shape& F = expResF.Current();
|
|
if ( ! RFM.Remove ( F ))
|
|
RFM.Add( F );
|
|
}
|
|
}
|
|
|
|
if (!isTool) {
|
|
|
|
// rebuild S, it must remain in the result
|
|
|
|
Standard_Boolean isClosed = Standard_False;
|
|
switch (S.ShapeType()) {
|
|
case TopAbs_SOLID :
|
|
isClosed = Standard_True; break;
|
|
case TopAbs_SHELL: {
|
|
TopTools_IndexedDataMapOfShapeListOfShape MEF;
|
|
TopExp::MapShapesAndAncestors(S, TopAbs_EDGE, TopAbs_FACE, MEF);
|
|
Standard_Integer i;
|
|
for (i=1; isClosed && i<=MEF.Extent(); ++i)
|
|
isClosed = ( MEF(i).Extent() != 1 );
|
|
break;
|
|
}
|
|
default:
|
|
isClosed = Standard_False;
|
|
}
|
|
if (isClosed) {
|
|
|
|
// add to a new shape external faces of removed shapes, ie those in RFM
|
|
|
|
TopoDS_Shell Shell;
|
|
myBuilder.MakeShell( Shell );
|
|
|
|
// exclude redundant internal face with edges encountered only once
|
|
TopTools_IndexedDataMapOfShapeListOfShape MEF;
|
|
TopTools_MapIteratorOfMapOfShape itF (RFM);
|
|
for ( ; itF.More(); itF.Next())
|
|
TopExp::MapShapesAndAncestors(itF.Key(), TopAbs_EDGE, TopAbs_FACE, MEF);
|
|
|
|
// add only faces forming a closed shell
|
|
for (itF.Reset() ; itF.More(); itF.Next())
|
|
{
|
|
TopExp_Explorer expE (itF.Key(), TopAbs_EDGE);
|
|
for (; expE.More(); expE.Next())
|
|
if (MEF.FindFromKey(expE.Current()).Extent() == 1)
|
|
break;
|
|
if (!expE.More())
|
|
myBuilder.Add( Shell, itF.Key());
|
|
}
|
|
|
|
if (S.ShapeType() == TopAbs_SOLID) {
|
|
TopoDS_Solid Solid;
|
|
myBuilder.MakeSolid( Solid );
|
|
myBuilder.Add (Solid, Shell);
|
|
myBuilder.Add (C, Solid);
|
|
}
|
|
else
|
|
myBuilder.Add (C, Shell);
|
|
}
|
|
else {
|
|
if (myImageShape.HasImage( S )) {
|
|
for (it.Initialize( myImageShape.Image(S).First()); it.More(); it.Next())
|
|
myBuilder.Add (C, it.Value());
|
|
}
|
|
}
|
|
}
|
|
|
|
myShape = C;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : CheckTool
|
|
//purpose : Return True if <S> is a tool shape. Prepare tool
|
|
// faces of <S> for the search of internal faces.
|
|
//=======================================================================
|
|
|
|
Standard_Boolean Partition_Spliter::CheckTool(const TopoDS_Shape& S)
|
|
{
|
|
// suppose S has not an image
|
|
|
|
Standard_Boolean isTool = Standard_False;
|
|
TopoDS_Compound C;
|
|
myBuilder.MakeCompound( C );
|
|
|
|
TopExp_Explorer expF( S, TopAbs_FACE);
|
|
for (; expF.More(); expF.Next()) {
|
|
|
|
const TopoDS_Face& F = TopoDS::Face( expF.Current() );
|
|
if (myMapTools.Contains( F ))
|
|
isTool = Standard_True;
|
|
else
|
|
continue;
|
|
|
|
if (myImagesFaces.HasImage( F )) {
|
|
// F has been reconstructed
|
|
TopAbs_Orientation Fori = F.Orientation();
|
|
TopTools_ListOfShape LNF;
|
|
myImagesFaces.LastImage( F, LNF);
|
|
TopTools_ListIteratorOfListOfShape itF (LNF);
|
|
for ( ; itF.More(); itF.Next())
|
|
myBuilder.Add( C, itF.Value().Oriented(Fori) );
|
|
continue;
|
|
}
|
|
|
|
Standard_Boolean hasSectionE = myInter3d.HasSectionEdge( F );
|
|
Standard_Boolean hasNewE = myAsDes->HasDescendant( F );
|
|
if (!hasSectionE && !hasNewE)
|
|
{
|
|
// F intersects nothing
|
|
myBuilder.Add( C, F );
|
|
continue;
|
|
}
|
|
|
|
// make an image for F
|
|
|
|
TopoDS_Face NF = F;
|
|
NF.Orientation(TopAbs_FORWARD);
|
|
NF = TopoDS::Face( NF.EmptyCopied() ); // make a copy
|
|
TopoDS_Wire NW;
|
|
myBuilder.MakeWire( NW );
|
|
|
|
// add edges, as less as possible
|
|
TopTools_ListOfShape NEL;
|
|
TopTools_ListIteratorOfListOfShape itNE;
|
|
if (hasSectionE) {
|
|
// add section edges
|
|
TopExp_Explorer expE;
|
|
for ( ; expE.More(); expE.Next()) {
|
|
if (! myImagesEdges.HasImage( expE.Current() ))
|
|
continue;
|
|
myImagesEdges.LastImage( expE.Current(), NEL );
|
|
for ( itNE.Initialize( NEL ); itNE.More(); itNE.Next())
|
|
myBuilder.Add ( NW, itNE.Value());
|
|
}
|
|
}
|
|
if (hasNewE) {
|
|
// add new edges
|
|
NEL = myAsDes->Descendant( F );
|
|
for ( itNE.Initialize( NEL ); itNE.More(); itNE.Next()) {
|
|
TopTools_ListOfShape SEL; // splits
|
|
myImagesEdges.LastImage( itNE.Value(), SEL );
|
|
TopTools_ListIteratorOfListOfShape itSE (SEL);
|
|
for ( ; itSE.More(); itSE.Next())
|
|
myBuilder.Add ( NW, itSE.Value());
|
|
}
|
|
}
|
|
myBuilder.Add( NF, NW );
|
|
myBuilder.Add (C, NF);
|
|
|
|
NF.Orientation( F.Orientation() ); // NF is most probably invalid
|
|
myImagesFaces.Bind (F, NF);
|
|
}
|
|
if (isTool)
|
|
myImageShape.Bind (S, C);
|
|
|
|
return isTool;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : IsInside
|
|
//purpose : Return True if the first vertex of S1 inside S2.
|
|
// If S1.IsNull(), check infinite point against S2.
|
|
//=======================================================================
|
|
|
|
Standard_Boolean Partition_Spliter::IsInside (const TopoDS_Shape& theS1,
|
|
const TopoDS_Shape& theS2)
|
|
{
|
|
BRepClass3d_SolidClassifier aClassifier( theS2 );
|
|
|
|
TopExp_Explorer expl( theS1, TopAbs_VERTEX );
|
|
if (!expl.More())
|
|
aClassifier.PerformInfinitePoint( ::RealSmall());
|
|
else
|
|
{
|
|
const TopoDS_Vertex & aVertex = TopoDS::Vertex( expl.Current() );
|
|
aClassifier.Perform (BRep_Tool::Pnt( aVertex ),
|
|
BRep_Tool::Tolerance( aVertex ));
|
|
}
|
|
|
|
return ( aClassifier.State() == TopAbs_IN );
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetOriginalShape
|
|
//purpose : Return the shape aShape originates from. aShape
|
|
// should be a face or more complex result shape
|
|
//=======================================================================
|
|
|
|
TopoDS_Shape Partition_Spliter::GetOriginalShape(const TopoDS_Shape& theShape) const
|
|
{
|
|
TopoDS_Shape anOrigShape;
|
|
|
|
TopExp_Explorer expl( theShape, TopAbs_FACE);
|
|
if (expl.More())
|
|
{
|
|
|
|
TopoDS_Shape aFace = expl.Current();
|
|
if (myImagesFaces.IsImage( aFace ))
|
|
aFace = myImagesFaces.Root( aFace );
|
|
anOrigShape = myFaceShapeMap.Find( aFace );
|
|
}
|
|
return anOrigShape;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : FindToolsToReconstruct
|
|
//purpose : find and store as objects tools which interfere
|
|
// with solids or are inside solids without
|
|
// an interference
|
|
//=======================================================================
|
|
|
|
void Partition_Spliter::FindToolsToReconstruct()
|
|
{
|
|
if (myMapTools.IsEmpty())
|
|
return;
|
|
|
|
Standard_Integer nbFoundTools = 0;
|
|
|
|
// build edge - face map in order to detect interference with section edges
|
|
TopTools_IndexedDataMapOfShapeListOfShape EFM;
|
|
TopTools_MapIteratorOfMapOfShape aMapIt;
|
|
for (aMapIt.Initialize(myMapTools); aMapIt.More(); aMapIt.Next())
|
|
TopExp::MapShapesAndAncestors( aMapIt.Key(), TopAbs_EDGE, TopAbs_FACE, EFM);
|
|
for (aMapIt.Initialize(myMapFaces); aMapIt.More(); aMapIt.Next())
|
|
TopExp::MapShapesAndAncestors( aMapIt.Key(), TopAbs_EDGE, TopAbs_FACE, EFM);
|
|
|
|
TopTools_MapOfShape aCurrentSolids, aCheckedShapes;
|
|
|
|
// faces cut by new edges
|
|
TopTools_MapOfShape & aSectionFaces = myInter3d.TouchedFaces();
|
|
|
|
// keep solids interfering with each other in aCurrentSolids map
|
|
// and add tool faces intersecting solids as object shapes
|
|
|
|
TopTools_ListIteratorOfListOfShape itS, itF, itCF, itE;
|
|
for (itS.Initialize( myListShapes ); itS.More(); itS.Next()) {
|
|
TopExp_Explorer expSo (itS.Value(), TopAbs_SOLID);
|
|
for (; expSo.More(); expSo.Next()) {
|
|
|
|
// check if a solid has been already processed
|
|
const TopoDS_Shape & aSo = expSo.Current();
|
|
if (!aCheckedShapes.Add( aSo ))
|
|
continue;
|
|
aCurrentSolids.Add( aSo );
|
|
|
|
// faces to check
|
|
TopTools_ListOfShape aFacesToCheck;
|
|
TopExp_Explorer exp( aSo, TopAbs_FACE );
|
|
for ( ; exp.More(); exp.Next())
|
|
aFacesToCheck.Append ( exp.Current());
|
|
|
|
// add other shapes interefering with a solid.
|
|
// iterate faces to check while appending new ones
|
|
for (itCF.Initialize (aFacesToCheck) ; itCF.More(); itCF.Next())
|
|
{
|
|
const TopoDS_Shape& aCheckFace = itCF.Value();
|
|
// if (!aCheckedShapes.Add( aCheckFace ))
|
|
// continue;
|
|
|
|
// find faces interfering with aCheckFace
|
|
TopTools_ListOfShape anIntFaces;
|
|
|
|
// ** 1. faces intersecting aCheckFace with creation of new edges on it
|
|
if ( myAsDes->HasDescendant( aCheckFace ))
|
|
{
|
|
// new edges on aCheckFace
|
|
const TopTools_ListOfShape& NEL = myAsDes->Descendant( aCheckFace );
|
|
for (itE.Initialize( NEL); itE.More(); itE.Next())
|
|
{
|
|
const TopoDS_Shape & aNewEdge = itE.Value();
|
|
if (!aCheckedShapes.Add( aNewEdge ))
|
|
continue;
|
|
|
|
// faces interfering by aNewEdge
|
|
itF.Initialize (myAsDes->Ascendant( aNewEdge ));
|
|
for (; itF.More(); itF.Next())
|
|
if (aCheckFace != itF.Value())
|
|
anIntFaces.Append( itF.Value() );
|
|
|
|
// ** 2. faces having section edge aNewEdge on aFacesToCheck
|
|
if (EFM.Contains( aNewEdge))
|
|
{
|
|
itF.Initialize ( EFM.FindFromKey (itE.Value()));
|
|
for (; itF.More(); itF.Next())
|
|
if (aCheckFace != itF.Value())
|
|
anIntFaces.Append( itF.Value() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// ** 3. faces cut by edges of aCheckFace
|
|
TopExp_Explorer expE (aCheckFace, TopAbs_EDGE);
|
|
for ( ; expE.More(); expE.Next())
|
|
{
|
|
const TopoDS_Shape & aCheckEdge = expE.Current();
|
|
if (aCheckedShapes.Add( aCheckEdge ) &&
|
|
myInter3d.IsSectionEdge( TopoDS::Edge( aCheckEdge )))
|
|
{
|
|
itF.Initialize( myInter3d.SectionEdgeFaces( TopoDS::Edge( aCheckEdge )));
|
|
for (; itF.More(); itF.Next())
|
|
if (aCheckFace != itF.Value())
|
|
anIntFaces.Append( itF.Value() );
|
|
}
|
|
}
|
|
|
|
// process faces interfering with aCheckFace and shapes they
|
|
// belong to
|
|
for (itF.Initialize (anIntFaces); itF.More(); itF.Next())
|
|
{
|
|
const TopoDS_Shape & F = itF.Value();
|
|
if (! aCheckedShapes.Add( F ))
|
|
continue;
|
|
|
|
Standard_Boolean isTool = myMapTools.Contains( F );
|
|
if (isTool &&
|
|
myFaceShapeMap( aCheckFace ).ShapeType() == TopAbs_SOLID )
|
|
{
|
|
// a tool interfering with a solid
|
|
if (aSectionFaces.Contains( F ))
|
|
AddShape( F );
|
|
++ nbFoundTools;
|
|
if (nbFoundTools == myMapTools.Extent())
|
|
return;
|
|
}
|
|
|
|
const TopoDS_Shape & S = myFaceShapeMap( F );
|
|
if (aCheckedShapes.Add( S ))
|
|
{
|
|
// a new shape interefering with aCurrentSolids is found
|
|
if (!isTool && S.ShapeType() == TopAbs_SOLID)
|
|
aCurrentSolids.Add ( S );
|
|
// add faces to aFacesToCheck list
|
|
for ( exp.Init( S, TopAbs_FACE ); exp.More(); exp.Next())
|
|
aFacesToCheck.Append ( exp.Current() );
|
|
}
|
|
}
|
|
} // loop on aFacesToCheck
|
|
|
|
// Here aCurrentSolids contains all solids interfering with each other.
|
|
// aCheckedShapes contains all faces belonging to shapes included
|
|
// in or interfering with aCurrentSolids or previously checked solids.
|
|
// Test if tool faces that do not interefere with other shapes are
|
|
// wrapped by any of aCurrentSolids
|
|
|
|
TopTools_MapIteratorOfMapOfShape aSolidIt (aCurrentSolids);
|
|
for ( ; aSolidIt.More(); aSolidIt.Next())
|
|
{
|
|
const TopoDS_Shape & aSolid = aSolidIt.Key();
|
|
TopTools_MapOfShape aCheckedTools( myMapTools.Extent() );
|
|
|
|
TopTools_MapIteratorOfMapOfShape aToolIt (myMapTools);
|
|
for ( ; aToolIt.More(); aToolIt.Next())
|
|
{
|
|
const TopoDS_Shape & aToolFace = aToolIt.Key();
|
|
if (aCheckedShapes.Contains( aToolFace ) || // already found
|
|
aCheckedTools.Contains( aToolFace )) // checked against aSolid
|
|
continue;
|
|
|
|
const TopoDS_Shape & aToolShape = myFaceShapeMap( aToolFace );
|
|
TopExp_Explorer aToolFaceIt( aToolShape, TopAbs_FACE );
|
|
|
|
Standard_Boolean isInside = IsInside( aToolShape, aSolid );
|
|
for ( ; aToolFaceIt.More(); aToolFaceIt.Next() )
|
|
{
|
|
const TopoDS_Shape & aTool = aToolFaceIt.Current();
|
|
aCheckedTools.Add( aTool );
|
|
if (isInside)
|
|
{
|
|
if (aSectionFaces.Contains( aTool ))
|
|
AddShape( aTool );
|
|
++ nbFoundTools;
|
|
if (nbFoundTools == myMapTools.Extent())
|
|
return;
|
|
aCheckedShapes.Add( aTool );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // loop on solid shapes
|
|
}
|
|
}
|
|
|
|
#endif
|