From 71f5fd648ada796d6b620b25cb16a6b4fa990b3f Mon Sep 17 00:00:00 2001 From: emv Date: Fri, 17 Nov 2017 16:27:36 +0300 Subject: [PATCH] 0029333: Boolean Operations - Prevent modification of the input shapes in case their sub-shapes have not been modified Prevent modification of the input shapes in destructive mode in case their sub-shapes have not been modified: 1. Prevent edge splitting for the pave blocks with old vertices if it is possible to use the existing edge (*BOPAlgo_PaveFiller::MakeSplitEdges*); 2. Prevent creation of the new containers (WIRES/SHELLS/COMPSOLIDS) if non of its parts have been modified (*BOPAlgo_Builder::FillImagesContainer*); 3. Prevent creation of the new face if non of its wires have been modified (*BOPAlgo_Builder::FillImagesFaces*); 4. If possible, use the original face to be the representative for the group of SD faces (*BOPAlgo_Builder::FillSameDomainFaces*). Cosmetic changes: 1. Documentation of the *BOPAlgo_Builder* class. 2. Making simple methods of the *BOPAlgo_Builder* class inline. 3. Getting rid of the *BOPAlgo_Builder::mySplits* field as it is excessive. *BOPAlgo_Builder::myImages* can be used instead. 3. Moving the Check Inverted option from *BOPAlgo_Options* to *BOPAlgo_Builder*. Test cases for the issue. Adjustment of the test case to their current behavior. Test case *blend/complex/H2* has been deleted as duplicate of the test case *blend/simple/Z1*. --- dox/dev_guides/upgrade/upgrade.md | 5 + src/BOPAlgo/BOPAlgo_BOP.cxx | 75 +---- src/BOPAlgo/BOPAlgo_BOP.hxx | 2 - src/BOPAlgo/BOPAlgo_Builder.cxx | 98 +----- src/BOPAlgo/BOPAlgo_Builder.hxx | 333 ++++++++++++++------ src/BOPAlgo/BOPAlgo_Builder_1.cxx | 124 ++++---- src/BOPAlgo/BOPAlgo_Builder_2.cxx | 241 ++++++++------ src/BOPAlgo/BOPAlgo_Builder_3.cxx | 13 +- src/BOPAlgo/BOPAlgo_Options.cxx | 2 - src/BOPAlgo/BOPAlgo_Options.hxx | 21 -- src/BOPAlgo/BOPAlgo_PaveFiller_7.cxx | 147 +++++---- src/BOPDS/BOPDS_CommonBlock.cxx | 17 + src/BOPDS/BOPDS_CommonBlock.hxx | 16 +- src/BRepAlgoAPI/BRepAlgoAPI_Algo.hxx | 1 - src/BRepAlgoAPI/BRepAlgoAPI_BuilderAlgo.cxx | 6 +- src/BRepAlgoAPI/BRepAlgoAPI_BuilderAlgo.hxx | 37 ++- src/BRepFeat/BRepFeat_Builder.cxx | 2 - src/BRepOffset/BRepOffset_MakeOffset_1.cxx | 56 +++- tests/blend/complex/G9 | 2 +- tests/blend/complex/H2 | 16 - tests/blend/simple/Q4 | 2 +- tests/blend/simple/Z1 | 4 +- tests/bugs/modalg_7/bug27711 | 15 +- tests/bugs/modalg_7/bug29333_1 | 65 ++++ tests/bugs/modalg_7/bug29333_2 | 62 ++++ tests/caf/named_shape/F8 | 40 +-- tests/caf/named_shape/F9 | 38 +-- tests/perf/modalg/bug29237_1 | 4 +- tests/perf/modalg/bug29237_3 | 4 +- 29 files changed, 810 insertions(+), 638 deletions(-) delete mode 100644 tests/blend/complex/H2 create mode 100644 tests/bugs/modalg_7/bug29333_1 create mode 100644 tests/bugs/modalg_7/bug29333_2 diff --git a/dox/dev_guides/upgrade/upgrade.md b/dox/dev_guides/upgrade/upgrade.md index cee4fc82f2..b4bbcbae53 100644 --- a/dox/dev_guides/upgrade/upgrade.md +++ b/dox/dev_guides/upgrade/upgrade.md @@ -1453,3 +1453,8 @@ The following public method has been removed: The methods BuildPCurveForEdgeOnPlane and BuildPCurveForEdgesOnPlane have been moved from the class BOPTools_AlgoTools2D to the more lower level class BRepLib. + +@subsection upgrade_721_removed Removed features + +The following obsolete features have been removed: +* The method *BOPAlgo_Builder::Splits()* has been removed as excessive. The method *BOPAlgo_Builder::Images()* can be used instead. \ No newline at end of file diff --git a/src/BOPAlgo/BOPAlgo_BOP.cxx b/src/BOPAlgo/BOPAlgo_BOP.cxx index ed85aa1007..8889480015 100644 --- a/src/BOPAlgo/BOPAlgo_BOP.cxx +++ b/src/BOPAlgo/BOPAlgo_BOP.cxx @@ -1035,38 +1035,17 @@ void BOPAlgo_BOP::BuildSolid() } // BOPCol_IndexedDataMapOfShapeListOfShape aMEF; - // Split faces will be added in the end - // to avoid errors in BuilderSolid algorithm - BOPCol_ListOfShape aLF, aLFx; + // Fill the list of faces to build the result solids + BOPCol_ListOfShape aSFS; aNb = aMFS.Extent(); for (i = 1; i <= aNb; ++i) { const BOPCol_ListOfShape& aLSx = aMFS(i); if (aLSx.Extent() == 1) { const TopoDS_Shape& aFx = aMFS.FindKey(i); BOPTools::MapShapesAndAncestors(aFx, TopAbs_EDGE, TopAbs_FACE, aMEF); - if (IsBoundSplits(aFx, aMEF)){ - aLFx.Append(aFx); - continue; - } - aLF.Append(aFx); + aSFS.Append(aFx); } } - // - // Faces to build result solids - BOPCol_ListOfShape aSFS; - aItLS.Initialize(aLF); - for(; aItLS.More(); aItLS.Next()) { - const TopoDS_Shape& aFx = aItLS.Value(); - aSFS.Append(aFx); - } - // - // Split faces - aItLS.Initialize(aLFx); - for (; aItLS.More(); aItLS.Next()) { - const TopoDS_Shape& aFx = aItLS.Value(); - aSFS.Append(aFx); - } - // // Internal faces aNb = aMFI.Extent(); for (i = 1; i <= aNb; ++i) { @@ -1198,54 +1177,6 @@ void BOPAlgo_BOP::BuildSolid() myShape = aResult; } //======================================================================= -//function : IsBoundSplits -//purpose : -//======================================================================= -Standard_Boolean BOPAlgo_BOP::IsBoundSplits - (const TopoDS_Shape& aS, - BOPCol_IndexedDataMapOfShapeListOfShape& aMEF) -{ - Standard_Boolean bRet = Standard_False; - if (mySplits.IsBound(aS) || myOrigins.IsBound(aS)) { - return !bRet; - } - - BOPCol_ListIteratorOfListOfShape aIt; - Standard_Integer aNbLS; - TopAbs_Orientation anOr; - // - //check face aF may be connected to face from mySplits - TopExp_Explorer aExp(aS, TopAbs_EDGE); - for (; aExp.More(); aExp.Next()) { - const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current())); - // - anOr = aE.Orientation(); - if (anOr==TopAbs_INTERNAL) { - continue; - } - // - if (BRep_Tool::Degenerated(aE)) { - continue; - } - // - const BOPCol_ListOfShape& aLS=aMEF.FindFromKey(aE); - aNbLS = aLS.Extent(); - if (!aNbLS) { - continue; - } - // - aIt.Initialize(aLS); - for (; aIt.More(); aIt.Next()) { - const TopoDS_Shape& aSx = aIt.Value(); - if (mySplits.IsBound(aSx) || myOrigins.IsBound(aS)) { - return !bRet; - } - } - } - // - return bRet; -} -//======================================================================= //function : TypeToExplore //purpose : //======================================================================= diff --git a/src/BOPAlgo/BOPAlgo_BOP.hxx b/src/BOPAlgo/BOPAlgo_BOP.hxx index 6555c3f8e7..21915e1a53 100644 --- a/src/BOPAlgo/BOPAlgo_BOP.hxx +++ b/src/BOPAlgo/BOPAlgo_BOP.hxx @@ -109,8 +109,6 @@ protected: Standard_EXPORT void BuildSolid(); - Standard_EXPORT Standard_Boolean IsBoundSplits (const TopoDS_Shape& theS, BOPCol_IndexedDataMapOfShapeListOfShape& theMEF); - //! Treatment of the cases with empty shapes.
//! It returns TRUE if there is nothing to do, i.e. //! all shapes in one of the groups are empty shapes. diff --git a/src/BOPAlgo/BOPAlgo_Builder.cxx b/src/BOPAlgo/BOPAlgo_Builder.cxx index 20f74f4362..3de5ee8ab8 100644 --- a/src/BOPAlgo/BOPAlgo_Builder.cxx +++ b/src/BOPAlgo/BOPAlgo_Builder.cxx @@ -50,10 +50,10 @@ BOPAlgo_Builder::BOPAlgo_Builder() myEntryPoint(0), myImages(100, myAllocator), myShapesSD(100, myAllocator), - mySplits(100, myAllocator), myOrigins(100, myAllocator), myNonDestructive(Standard_False), - myGlue(BOPAlgo_GlueOff) + myGlue(BOPAlgo_GlueOff), + myCheckInverted(Standard_True) { } //======================================================================= @@ -71,10 +71,10 @@ BOPAlgo_Builder::BOPAlgo_Builder myEntryPoint(0), myImages(100, myAllocator), myShapesSD(100, myAllocator), - mySplits(100, myAllocator), myOrigins(100, myAllocator), myNonDestructive(Standard_False), - myGlue(BOPAlgo_GlueOff) + myGlue(BOPAlgo_GlueOff), + myCheckInverted(Standard_True) { } //======================================================================= @@ -101,7 +101,6 @@ void BOPAlgo_Builder::Clear() myMapFence.Clear(); myImages.Clear(); myShapesSD.Clear(); - mySplits.Clear(); myOrigins.Clear(); } //======================================================================= @@ -131,95 +130,6 @@ void BOPAlgo_Builder::SetArguments(const BOPCol_ListOfShape& theShapes) } } //======================================================================= -//function : Arguments -//purpose : -//======================================================================= -const BOPCol_ListOfShape& BOPAlgo_Builder::Arguments()const -{ - return myArguments; -} -//======================================================================= -//function : Images -//purpose : -//======================================================================= -const BOPCol_DataMapOfShapeListOfShape& BOPAlgo_Builder::Images()const -{ - return myImages; -} -//======================================================================= -//function : Origins -//purpose : -//======================================================================= -const BOPCol_DataMapOfShapeListOfShape& BOPAlgo_Builder::Origins()const -{ - return myOrigins; -} - -//======================================================================= -//function : ShapesSd -//purpose : -//======================================================================= -const BOPCol_DataMapOfShapeShape& BOPAlgo_Builder::ShapesSD()const -{ - return myShapesSD; -} -//======================================================================= -//function : Splits -//purpose : -//======================================================================= -const BOPCol_DataMapOfShapeListOfShape& BOPAlgo_Builder::Splits()const -{ - return mySplits; -} -//======================================================================= -//function : PPaveFiller -//purpose : -//======================================================================= -BOPAlgo_PPaveFiller BOPAlgo_Builder::PPaveFiller() -{ - return myPaveFiller; -} -//======================================================================= -//function : PDS -//purpose : -//======================================================================= -BOPDS_PDS BOPAlgo_Builder::PDS() -{ - return myDS; -} -//======================================================================= -//function : SetNonDestructive -//purpose : -//======================================================================= -void BOPAlgo_Builder::SetNonDestructive(const Standard_Boolean theFlag) -{ - myNonDestructive = theFlag; -} -//======================================================================= -//function : NonDestructive -//purpose : -//======================================================================= -Standard_Boolean BOPAlgo_Builder::NonDestructive() const -{ - return myNonDestructive; -} -//======================================================================= -//function : SetGlue -//purpose : -//======================================================================= -void BOPAlgo_Builder::SetGlue(const BOPAlgo_GlueEnum theGlue) -{ - myGlue=theGlue; -} -//======================================================================= -//function : Glue -//purpose : -//======================================================================= -BOPAlgo_GlueEnum BOPAlgo_Builder::Glue() const -{ - return myGlue; -} -//======================================================================= // function: CheckData // purpose: //======================================================================= diff --git a/src/BOPAlgo/BOPAlgo_Builder.hxx b/src/BOPAlgo/BOPAlgo_Builder.hxx index b61e5f28fc..011b22a75e 100644 --- a/src/BOPAlgo/BOPAlgo_Builder.hxx +++ b/src/BOPAlgo/BOPAlgo_Builder.hxx @@ -54,6 +54,10 @@ class BOPAlgo_PaveFiller; //! shapes during the operation (by default it is off);
//! - *Gluing options* - allows to speed up the calculation of the intersections //! on the special cases, in which some sub-shapes are coinciding.
+//! - *Disabling the check for inverted solids* - Disables/Enables the check of the input solids +//! for inverted status (holes in the space). The default value is TRUE, +//! i.e. the check is performed. Setting this flag to FALSE for inverted solids, +//! most likely will lead to incorrect results. //! //! The algorithm returns the following Error statuses: //! - *BOPAlgo_AlertTooFewArguments* - in case there are no enough arguments to perform the operation; @@ -67,139 +71,282 @@ public: DEFINE_STANDARD_ALLOC - + //! Empty constructor. Standard_EXPORT BOPAlgo_Builder(); -Standard_EXPORT virtual ~BOPAlgo_Builder(); - - Standard_EXPORT BOPAlgo_Builder(const BOPCol_BaseAllocator& theAllocator); - + Standard_EXPORT virtual ~BOPAlgo_Builder(); + + Standard_EXPORT BOPAlgo_Builder(const Handle(NCollection_BaseAllocator)& theAllocator); + + //! Clears the content of the algorithm. Standard_EXPORT virtual void Clear() Standard_OVERRIDE; - - Standard_EXPORT BOPAlgo_PPaveFiller PPaveFiller(); - - Standard_EXPORT BOPDS_PDS PDS(); - + + //! Returns the PaveFiller, algorithm for sub-shapes intersection. + BOPAlgo_PPaveFiller PPaveFiller() + { + return myPaveFiller; + } + + //! Returns the Data Structure, holder of intersection information. + BOPDS_PDS PDS() + { + return myDS; + } + + //! Returns the Context, tool for cashing heavy algorithms. + Handle(IntTools_Context) Context() const + { + return myContext; + } + + +public: //! @name Arguments + + //! Adds the argument to the operation. Standard_EXPORT virtual void AddArgument (const TopoDS_Shape& theShape); - + + //! Sets the list of arguments for the operation. Standard_EXPORT virtual void SetArguments (const BOPCol_ListOfShape& theLS); - - Standard_EXPORT const BOPCol_ListOfShape& Arguments() const; - Standard_EXPORT virtual void Perform() Standard_OVERRIDE; - - Standard_EXPORT virtual void PerformWithFiller (const BOPAlgo_PaveFiller& theFiller); - - //! Returns the list of shapes generated from the - //! shape theS. - Standard_EXPORT virtual const TopTools_ListOfShape& Generated (const TopoDS_Shape& theS) Standard_OVERRIDE; - - //! Returns the list of shapes modified from the shape - //! theS. - Standard_EXPORT virtual const TopTools_ListOfShape& Modified (const TopoDS_Shape& theS) Standard_OVERRIDE; - - //! Returns true if the shape theS has been deleted. - Standard_EXPORT virtual Standard_Boolean IsDeleted (const TopoDS_Shape& theS) Standard_OVERRIDE; - - Standard_EXPORT const BOPCol_DataMapOfShapeListOfShape& Images() const; - - Standard_EXPORT Standard_Boolean IsInterferred (const TopoDS_Shape& theS) const; - - //! Returns myOrigins. - Standard_EXPORT const BOPCol_DataMapOfShapeListOfShape& Origins() const; - - //! Returns myShapesSD. - Standard_EXPORT const BOPCol_DataMapOfShapeShape& ShapesSD() const; - - //! Returns mySplits. - Standard_EXPORT const BOPCol_DataMapOfShapeListOfShape& Splits() const; - - + //! Returns the list of arguments. + const BOPCol_ListOfShape& Arguments() const + { + return myArguments; + } + +public: //! @name Options + //! Sets the flag that defines the mode of treatment. //! In non-destructive mode the argument shapes are not modified. Instead //! a copy of a sub-shape is created in the result if it is needed to be updated. //! This flag is taken into account if internal PaveFiller is used only. //! In the case of calling PerformWithFiller the corresponding flag of that PaveFiller //! is in force. - Standard_EXPORT void SetNonDestructive(const Standard_Boolean theFlag); + void SetNonDestructive(const Standard_Boolean theFlag) + { + myNonDestructive = theFlag; + } //! Returns the flag that defines the mode of treatment. //! In non-destructive mode the argument shapes are not modified. Instead //! a copy of a sub-shape is created in the result if it is needed to be updated. - Standard_EXPORT Standard_Boolean NonDestructive() const; + Standard_Boolean NonDestructive() const + { + return myNonDestructive; + } //! Sets the glue option for the algorithm - Standard_EXPORT void SetGlue(const BOPAlgo_GlueEnum theGlue); - + void SetGlue(const BOPAlgo_GlueEnum theGlue) + { + myGlue = theGlue; + } + //! Returns the glue option of the algorithm - Standard_EXPORT BOPAlgo_GlueEnum Glue() const; + BOPAlgo_GlueEnum Glue() const + { + return myGlue; + } -protected: + //! Enables/Disables the check of the input solids for inverted status + void SetCheckInverted(const Standard_Boolean theCheck) + { + myCheckInverted = theCheck; + } - //! Prepare information for history support - Standard_EXPORT virtual void PrepareHistory() Standard_OVERRIDE; - + //! Returns the flag defining whether the check for input solids on inverted status + //! should be performed or not. + Standard_Boolean CheckInverted() const + { + return myCheckInverted; + } + + +public: //! @name Performing the operation + + //! Performs the operation. + //! The intersection will be performed also. + Standard_EXPORT virtual void Perform() Standard_OVERRIDE; + + //! Performs the operation with the prepared filler. + //! The intersection will not be performed in this case. + Standard_EXPORT virtual void PerformWithFiller (const BOPAlgo_PaveFiller& theFiller); + + +public: //! @name History methods + + //! Returns the list of shapes generated from the + //! shape theS. + Standard_EXPORT virtual const TopTools_ListOfShape& Generated (const TopoDS_Shape& theS) Standard_OVERRIDE; + + //! Returns the list of shapes modified from the shape + //! theS. + Standard_EXPORT virtual const TopTools_ListOfShape& Modified (const TopoDS_Shape& theS) Standard_OVERRIDE; + + //! Returns true if the shape theS has been deleted. + Standard_EXPORT virtual Standard_Boolean IsDeleted (const TopoDS_Shape& theS) Standard_OVERRIDE; + + +public: //! @name Images/Origins + + //! Returns the map of images. + const BOPCol_DataMapOfShapeListOfShape& Images() const + { + return myImages; + } + + //! Returns the map of origins. + const BOPCol_DataMapOfShapeListOfShape& Origins() const + { + return myOrigins; + } + + //! Returns the map of Same Domain (SD) shapes - coinciding shapes + //! from different arguments. + const BOPCol_DataMapOfShapeShape& ShapesSD() const + { + return myShapesSD; + } + + +protected: //! @name Methods for building the result + + //! Performs the building of the result. + //! The method calls the PerfromInternal1() method surrounded by a try-catch block. Standard_EXPORT virtual void PerformInternal (const BOPAlgo_PaveFiller& thePF); - + + //! Performs the building of the result. + //! To build the result of any other operation + //! it will be necessary to override this method. Standard_EXPORT virtual void PerformInternal1 (const BOPAlgo_PaveFiller& thePF); - + + //! Prepare information for history support. + Standard_EXPORT virtual void PrepareHistory() Standard_OVERRIDE; + + //! Builds the result of operation. + //! The method is called for each of the arguments type and + //! adds into the result the splits of the arguments of that type. + Standard_EXPORT virtual void BuildResult (const TopAbs_ShapeEnum theType); + + +protected: //! @name Checking input arguments + + //! Checks the input data. Standard_EXPORT virtual void CheckData() Standard_OVERRIDE; - //! Checks if the intersection algorithm has Errors/Warnings + //! Checks if the intersection algorithm has Errors/Warnings. Standard_EXPORT void CheckFiller(); - + + //! Prepares the result shape by making it empty compound. Standard_EXPORT virtual void Prepare(); - + + +protected: //! @name Fill Images of VERTICES + + //! Fills the images of vertices. Standard_EXPORT void FillImagesVertices(); - + + +protected: //! @name Fill Images of EDGES + + //! Fills the images of edges. Standard_EXPORT void FillImagesEdges(); - - Standard_EXPORT virtual void BuildResult (const TopAbs_ShapeEnum theType); - + + +protected: //! @name Fill Images of CONTAINERS + + //! Fills the images of containers (WIRES/SHELLS/COMPSOLID). Standard_EXPORT void FillImagesContainers (const TopAbs_ShapeEnum theType); - - Standard_EXPORT void FillImagesCompounds(); - + + //! Builds the image of the given container using the splits + //! of its sub-shapes. Standard_EXPORT void FillImagesContainer (const TopoDS_Shape& theS, const TopAbs_ShapeEnum theType); - - Standard_EXPORT void FillImagesCompound (const TopoDS_Shape& theS, BOPCol_MapOfShape& theMF); - + + +protected: //! @name Fill Images of FACES + + //! Fills the images of faces. + //! The method consists of three steps: + //! 1. Build the splits of faces; + //! 2. Find SD faces; + //! 3. Add internal vertices (if any) to faces. Standard_EXPORT void FillImagesFaces(); - + + //! Builds the splits of faces using the information from the + //! intersection stage stored in Data Structure. Standard_EXPORT virtual void BuildSplitFaces(); - + + //! Looks for the same domain faces among the splits of the faces. + //! Updates the map of images with SD faces. Standard_EXPORT void FillSameDomainFaces(); - - Standard_EXPORT void FillImagesFaces1(); - + + //! Classifies the alone vertices on faces relatively its splits + //! and adds them as INTERNAL into the splits. + Standard_EXPORT void FillInternalVertices(); + + +protected: //! @name Fill Images of SOLIDS + + //! Fills the images of solids. + //! The method consists of four steps: + //! 1. Build the draft solid - just rebuild the solid using the splits of faces; + //! 2. Find faces from other arguments located inside the solids; + //! 3. Build splits of solid using the inside faces; + //! 4. Fill internal shapes for the splits (Wires and vertices). Standard_EXPORT void FillImagesSolids(); - - Standard_EXPORT void BuildDraftSolid (const TopoDS_Shape& theSolid, TopoDS_Shape& theDraftSolid, BOPCol_ListOfShape& theLIF); - - Standard_EXPORT virtual void FillIn3DParts (BOPCol_DataMapOfShapeListOfShape& theInParts, BOPCol_DataMapOfShapeShape& theDraftSolids, const BOPCol_BaseAllocator& theAllocator); - - Standard_EXPORT void BuildSplitSolids (BOPCol_DataMapOfShapeListOfShape& theInParts, BOPCol_DataMapOfShapeShape& theDraftSolids, const BOPCol_BaseAllocator& theAllocator); - + + //! Builds the draft solid by rebuilding the shells of the solid + //! with the splits of faces. + Standard_EXPORT void BuildDraftSolid (const TopoDS_Shape& theSolid, + TopoDS_Shape& theDraftSolid, + BOPCol_ListOfShape& theLIF); + + //! Finds faces located inside each solid. + Standard_EXPORT virtual void FillIn3DParts (BOPCol_DataMapOfShapeListOfShape& theInParts, + BOPCol_DataMapOfShapeShape& theDraftSolids, + const Handle(NCollection_BaseAllocator)& theAllocator); + + //! Builds the splits of the solids using their draft versions + //! and faces located inside. + Standard_EXPORT void BuildSplitSolids (BOPCol_DataMapOfShapeListOfShape& theInParts, + BOPCol_DataMapOfShapeShape& theDraftSolids, + const Handle(NCollection_BaseAllocator)& theAllocator); + + //! Classifies the vertices and edges from the arguments relatively + //! splits of solids and makes them INTERNAL for solids. Standard_EXPORT void FillInternalShapes(); - + + +protected: //! @name Fill Images of COMPOUNDS + + //! Fills the images of compounds. + Standard_EXPORT void FillImagesCompounds(); + + //! Builds the image of the given compound. + Standard_EXPORT void FillImagesCompound (const TopoDS_Shape& theS, + BOPCol_MapOfShape& theMF); + +protected: //! @name Post treatment + + //! Post treatment of the result of the operation. + //! The method checks validity of the sub-shapes of the result + //! and updates the tolerances to make them valid. Standard_EXPORT virtual void PostTreat(); - BOPCol_ListOfShape myArguments; - BOPCol_MapOfShape myMapFence; - BOPAlgo_PPaveFiller myPaveFiller; - BOPDS_PDS myDS; - Handle(IntTools_Context) myContext; - Standard_Integer myEntryPoint; - BOPCol_DataMapOfShapeListOfShape myImages; - BOPCol_DataMapOfShapeShape myShapesSD; - BOPCol_DataMapOfShapeListOfShape mySplits; - BOPCol_DataMapOfShapeListOfShape myOrigins; - Standard_Boolean myNonDestructive; - BOPAlgo_GlueEnum myGlue; +protected: //! @name Fields -private: + BOPCol_ListOfShape myArguments; //!< Arguments of the operation + BOPCol_MapOfShape myMapFence; //!< Fence map providing the uniqueness of the shapes in the list of arguments + BOPAlgo_PPaveFiller myPaveFiller; //!< Pave Filler - algorithm for sub-shapes intersection + BOPDS_PDS myDS; //!< Data Structure - holder of intersection information + Handle(IntTools_Context) myContext; //!< Context - tool for cashing heavy algorithms such as Projectors and Classifiers + Standard_Integer myEntryPoint; //!< EntryPoint - controls the deletion of the PaveFiller, which could live longer than the Builder + BOPCol_DataMapOfShapeListOfShape myImages; //!< Images - map of Images of the sub-shapes of arguments + BOPCol_DataMapOfShapeShape myShapesSD; //!< ShapesSD - map of SD Shapes + BOPCol_DataMapOfShapeListOfShape myOrigins; //!< Origins - map of Origins, back map of Images + Standard_Boolean myNonDestructive; //!< Safe processing option allows avoiding modification of the input shapes + BOPAlgo_GlueEnum myGlue; //!< Gluing option allows speeding up the intersection of the input shapes + Standard_Boolean myCheckInverted; //!< Check inverted option allows disabling the check of input solids on inverted status }; - #endif // _BOPAlgo_Builder_HeaderFile diff --git a/src/BOPAlgo/BOPAlgo_Builder_1.cxx b/src/BOPAlgo/BOPAlgo_Builder_1.cxx index f18fd3bcdb..23d1d811e9 100644 --- a/src/BOPAlgo/BOPAlgo_Builder_1.cxx +++ b/src/BOPAlgo/BOPAlgo_Builder_1.cxx @@ -40,28 +40,22 @@ //======================================================================= void BOPAlgo_Builder::FillImagesVertices() { - Standard_Integer nV, nVSD; - BOPCol_DataMapIteratorOfDataMapOfIntegerInteger aIt; - // - const BOPCol_DataMapOfIntegerInteger& aMSDV=myDS->ShapesSD(); - aIt.Initialize(aMSDV); - for (; aIt.More(); aIt.Next()) { - nV=aIt.Key(); - nVSD=aIt.Value(); - const TopoDS_Shape& aV=myDS->Shape(nV); - const TopoDS_Shape& aVSD=myDS->Shape(nVSD); - // - BOPCol_ListOfShape aLVSD(myAllocator); - // - aLVSD.Append(aVSD); - myImages.Bind(aV, aLVSD); - // + BOPCol_DataMapIteratorOfDataMapOfIntegerInteger aIt(myDS->ShapesSD()); + for (; aIt.More(); aIt.Next()) + { + Standard_Integer nV = aIt.Key(); + Standard_Integer nVSD = aIt.Value(); + + const TopoDS_Shape& aV = myDS->Shape(nV); + const TopoDS_Shape& aVSD = myDS->Shape(nVSD); + // Add to Images map + myImages.Bound(aV, BOPCol_ListOfShape(myAllocator))->Append(aVSD); + // Add to SD map myShapesSD.Bind(aV, aVSD); - // + // Add to Origins map BOPCol_ListOfShape* pLOr = myOrigins.ChangeSeek(aVSD); - if (!pLOr) { + if (!pLOr) pLOr = myOrigins.Bound(aVSD, BOPCol_ListOfShape()); - } pLOr->Append(aV); } } @@ -115,26 +109,6 @@ void BOPAlgo_Builder::FillImagesVertices() } } //======================================================================= -// function: IsInterferred -// purpose: -//======================================================================= - Standard_Boolean BOPAlgo_Builder::IsInterferred(const TopoDS_Shape& theS)const -{ - Standard_Boolean bInterferred; - TopoDS_Iterator aIt; - // - bInterferred=Standard_False; - aIt.Initialize(theS); - for (; aIt.More(); aIt.Next()) { - const TopoDS_Shape& aSx=aIt.Value(); - if (myImages.IsBound(aSx)) { - bInterferred=!bInterferred; - break; - } - } - return bInterferred; -} -//======================================================================= //function : BuildResult //purpose : //======================================================================= @@ -211,45 +185,57 @@ void BOPAlgo_Builder::FillImagesVertices() void BOPAlgo_Builder::FillImagesContainer(const TopoDS_Shape& theS, const TopAbs_ShapeEnum theType) { - Standard_Boolean bInterferred, bToReverse; - TopoDS_Iterator aIt; - BRep_Builder aBB; - BOPCol_ListIteratorOfListOfShape aItIm; - // - bInterferred=IsInterferred(theS); - if (!bInterferred){ + // Check if any of the sub-shapes of the container have been modified + TopoDS_Iterator aIt(theS); + for (; aIt.More(); aIt.Next()) + { + const TopoDS_Shape& aSS = aIt.Value(); + const BOPCol_ListOfShape* pLFIm = myImages.Seek(aSS); + if (pLFIm && ((pLFIm->Extent() != 1) || !pLFIm->First().IsSame(aSS))) + break; + } + + if (!aIt.More()) + { + // Non of the sub-shapes have been modified. + // No need to create the new container. return; } - // + + BRep_Builder aBB; + // Make the new container of the splits of its sub-shapes TopoDS_Shape aCIm; BOPTools_AlgoTools::MakeContainer(theType, aCIm); - // + aIt.Initialize(theS); - for (; aIt.More(); aIt.Next()) { - const TopoDS_Shape& aSx=aIt.Value(); - if (myImages.IsBound(aSx)) { - const BOPCol_ListOfShape& aLFIm=myImages.Find(aSx); - aItIm.Initialize(aLFIm); - for (; aItIm.More(); aItIm.Next()) { - TopoDS_Shape aSxIm=aItIm.Value(); - // - bToReverse=BOPTools_AlgoTools::IsSplitToReverse(aSxIm, aSx, myContext); - if (bToReverse) { - aSxIm.Reverse(); - } - aBB.Add(aCIm, aSxIm); - } + for (; aIt.More(); aIt.Next()) + { + const TopoDS_Shape& aSS = aIt.Value(); + const BOPCol_ListOfShape* pLSSIm = myImages.Seek(aSS); + + if (!pLSSIm) + { + // No splits, add the sub-shape itself + aBB.Add(aCIm, aSS); + continue; } - else { - aBB.Add(aCIm, aSx); + + // Add the splits + BOPCol_ListIteratorOfListOfShape aItIm(*pLSSIm); + for (; aItIm.More(); aItIm.Next()) + { + TopoDS_Shape aSSIm = aItIm.Value(); + if (!aSSIm.IsEqual(aSS) && + BOPTools_AlgoTools::IsSplitToReverse(aSSIm, aSS, myContext)) + { + aSSIm.Reverse(); + } + aBB.Add(aCIm, aSSIm); } } - // + aCIm.Closed(BRep_Tool::IsClosed(aCIm)); - // - BOPCol_ListOfShape aLSIm(myAllocator); - aLSIm.Append(aCIm); - myImages.Bind(theS, aLSIm); + myImages.Bound(theS, BOPCol_ListOfShape(myAllocator))->Append(aCIm); } //======================================================================= //function : FillImagesCompound diff --git a/src/BOPAlgo/BOPAlgo_Builder_2.cxx b/src/BOPAlgo/BOPAlgo_Builder_2.cxx index 9de1c35c52..5855705ab0 100644 --- a/src/BOPAlgo/BOPAlgo_Builder_2.cxx +++ b/src/BOPAlgo/BOPAlgo_Builder_2.cxx @@ -157,7 +157,7 @@ class BOPAlgo_VFI : public BOPAlgo_Algo { BOPAlgo_VFI() : BOPAlgo_Algo(), - myFlag(-1) { + myIsInternal(Standard_False) { } // virtual ~BOPAlgo_VFI(){ @@ -179,8 +179,8 @@ class BOPAlgo_VFI : public BOPAlgo_Algo { return myF; } // - Standard_Integer Flag()const { - return myFlag; + Standard_Boolean IsInternal()const { + return myIsInternal; } // void SetContext(const Handle(IntTools_Context)& aContext) { @@ -195,11 +195,13 @@ class BOPAlgo_VFI : public BOPAlgo_Algo { Standard_Real aT1, aT2, dummy; // BOPAlgo_Algo::UserBreak(); - myFlag = myContext->ComputeVF(myV, myF, aT1, aT2, dummy, myFuzzyValue); + Standard_Integer iFlag = + myContext->ComputeVF(myV, myF, aT1, aT2, dummy, myFuzzyValue); + myIsInternal = (iFlag == 0); } // protected: - Standard_Integer myFlag; + Standard_Boolean myIsInternal; TopoDS_Vertex myV; TopoDS_Face myF; Handle(IntTools_Context) myContext; @@ -226,7 +228,7 @@ void BOPAlgo_Builder::FillImagesFaces() { BuildSplitFaces(); FillSameDomainFaces(); - FillImagesFaces1(); + FillInternalVertices(); } //======================================================================= //function : BuildSplitFaces @@ -293,6 +295,20 @@ void BOPAlgo_Builder::BuildSplitFaces() if (!aNbPBIn && !aNbPBSc) { + if (!aNbAV) + { + // Check if any wires of the face have been modified. + // If not, there is no need to create the new face. + TopoDS_Iterator aItW(aF); + for (; aItW.More(); aItW.Next()) + { + if (myImages.IsBound(aItW.Value())) + break; + } + if (!aItW.More()) + continue; + } + // No internal parts for the face, so just build the draft face // and keep it to pass directly into result. // If the original face has any internal edges, the draft face @@ -457,7 +473,7 @@ void BOPAlgo_Builder::BuildSplitFaces() anOriF = aF.Orientation(); const BOPCol_ListOfShape& aLFR = aFacesIm(k); // - BOPCol_ListOfShape* pLFIm = mySplits.Bound(aF, BOPCol_ListOfShape()); + BOPCol_ListOfShape* pLFIm = myImages.Bound(aF, BOPCol_ListOfShape()); aIt.Initialize(aLFR); for (; aIt.More(); aIt.Next()) { TopoDS_Shape& aFR=aIt.ChangeValue(); @@ -567,7 +583,7 @@ void BOPAlgo_Builder::FillSameDomainFaces() } } - const BOPCol_ListOfShape* pLFSp = mySplits.Seek(aF); + const BOPCol_ListOfShape* pLFSp = myImages.Seek(aF); if (pLFSp) { BOPCol_ListIteratorOfListOfShape aItLF(*pLFSp); @@ -652,18 +668,83 @@ void BOPAlgo_Builder::FillSameDomainFaces() for (; aItB.More(); aItB.Next()) { const BOPCol_ListOfShape& aLSD = aItB.Value(); - // First face will be SD face for all faces in the group - const TopoDS_Shape& aFSD1 = aLSD.First(); + // If the group contains some original faces, the one with minimal + // index in the DS will be chosen as the SD for the whole group. + // If there are no original faces in the group, the first face from + // the group will be used as the SD face. + // Such SD face will be representative of the whole group in the result. + TopoDS_Face* pFSD = NULL; + Standard_Integer nFMin = ::IntegerLast(); BOPCol_ListIteratorOfListOfShape aItLF(aLSD); for (; aItLF.More(); aItLF.Next()) { - const TopoDS_Shape& aFSD = aItLF.Value(); - myShapesSD.Bind(aFSD, aFSD1); - // If the face has no splits but have an SD face, it is considered as being split - if (myDS->Index(aFSD) >= 0) - mySplits.Bound(aFSD, BOPCol_ListOfShape())->Append(aFSD); + const TopoDS_Shape& aF = aItLF.Value(); + // Check the index of the face in DS + const Standard_Integer nF = myDS->Index(aF); + if (nF >= 0) + { + // The fact that the face is found in the DS, means that + // the face has not been change, and thus it is original one. + // + // Such face does not have any splits, but have an SD face. + // Consider it being split. + myImages.Bound(aF, BOPCol_ListOfShape())->Append(aF); + + // For the SD face chose the one with minimal index + if (nF < nFMin) + { + nFMin = nF; + pFSD = (TopoDS_Face*)&aF; + } + } + } + + if (!pFSD) + { + // No original faces in the group, take the first one + pFSD = (TopoDS_Face*)&aLSD.First(); + } + + // Save all SD connections + aItLF.Initialize(aLSD); + for (; aItLF.More(); aItLF.Next()) + { + const TopoDS_Shape& aF = aItLF.Value(); + myShapesSD.Bind(aF, *pFSD); } } + + // Update the map of images with SD faces and + // fill the map of origins. + Standard_Integer aNbS = myDS->NbSourceShapes(); + for (Standard_Integer i = 0; i < aNbS; ++i) + { + const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i); + if (aSI.ShapeType() != TopAbs_FACE) + continue; + + const TopoDS_Shape& aF = aSI.Shape(); + BOPCol_ListOfShape* pLFIm = myImages.ChangeSeek(aF); + if (!pLFIm) + continue; + + BOPCol_ListIteratorOfListOfShape aItLFIm(*pLFIm); + for (; aItLFIm.More(); aItLFIm.Next()) + { + TopoDS_Shape& aFIm = aItLFIm.ChangeValue(); + const TopoDS_Shape* pFSD = myShapesSD.Seek(aFIm); + if (pFSD) + // Update image with SD face + aFIm = *pFSD; + + // Fill the map of origins + BOPCol_ListOfShape* pLFOr = myOrigins.ChangeSeek(aFIm); + if (!pLFOr) + pLFOr = myOrigins.Bound(aFIm, BOPCol_ListOfShape()); + pLFOr->Append(aF); + } + } + aMBlocks.Clear(); aDMSLS.Clear(); } @@ -671,103 +752,63 @@ void BOPAlgo_Builder::FillSameDomainFaces() // function: FillImagesFaces1 // purpose: //======================================================================= -void BOPAlgo_Builder::FillImagesFaces1() +void BOPAlgo_Builder::FillInternalVertices() { - Standard_Integer i, aNbS, iSense, nVx, aNbVFI, iFlag; - TopoDS_Face aFSD; - TopoDS_Vertex aVx; - BRep_Builder aBB; - BOPCol_ListOfInteger aLIAV; - BOPCol_ListOfShape aLFIm; - BOPCol_ListIteratorOfListOfInteger aItV; - BOPCol_ListIteratorOfListOfShape aItLS, aItF; + // Vector of pairs of Vertex/Face for classification of the vertices + // relatively faces, and adding them as internal into the faces BOPAlgo_VectorOfVFI aVVFI; - // - aNbS=myDS->NbSourceShapes(); - for (i=0; iShapeInfo(i); - if (aSI.ShapeType()!=TopAbs_FACE) { + + Standard_Integer aNbS = myDS->NbSourceShapes(); + for (Standard_Integer i = 0; i < aNbS; ++i) + { + const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i); + if (aSI.ShapeType() != TopAbs_FACE) continue; - } - // - const TopoDS_Face& aF=(*(TopoDS_Face*)(&aSI.Shape())); - // - if (!mySplits.IsBound(aF)) { + + const TopoDS_Shape& aF = aSI.Shape(); + const BOPCol_ListOfShape* pLFIm = myImages.Seek(aF); + if (!pLFIm) continue; - } - // - // 1. - aLIAV.Clear(); + + // Find vertices to add as internal into the splits + BOPCol_ListOfInteger aLIAV; myDS->AloneVertices(i, aLIAV); - aLFIm.Clear(); - // - const BOPCol_ListOfShape& aLSp=mySplits.Find(aF); - aItLS.Initialize(aLSp); - for (; aItLS.More(); aItLS.Next()) { - const TopoDS_Face& aFSp=(*(TopoDS_Face*)(&aItLS.Value())); - if (!myShapesSD.IsBound(aFSp)) { - aLFIm.Append(aFSp); - } - else { - aFSD=(*(TopoDS_Face*)(&myShapesSD.Find(aFSp))); - iSense=BOPTools_AlgoTools::Sense(aFSp, aFSD, myContext); - if (iSense<0) { - aFSD.Reverse(); - } - aLFIm.Append(aFSD); - } - } - // - //FillInternalVertices(aLFIm, aLIAV); - // - myImages.Bind(aF, aLFIm); - // - // 2. fill myOrigins - aItLS.Initialize(aLFIm); - for (; aItLS.More(); aItLS.Next()) { - const TopoDS_Face& aFSp=(*(TopoDS_Face*)(&aItLS.Value())); - // - BOPCol_ListOfShape* pLOr = myOrigins.ChangeSeek(aFSp); - if (!pLOr) { - pLOr = myOrigins.Bound(aFSp, BOPCol_ListOfShape()); - } - pLOr->Append(aF); - } - // - // 3. - aItV.Initialize(aLIAV); - for (; aItV.More(); aItV.Next()) { - nVx=aItV.Value(); - aVx=(*(TopoDS_Vertex*)(&myDS->Shape(nVx))); - aVx.Orientation(TopAbs_INTERNAL); - // - aItF.Initialize(aLFIm); - for (; aItF.More(); aItF.Next()) { - TopoDS_Face& aFy=(*(TopoDS_Face*)(&aItF.Value())); - // - BOPAlgo_VFI& aVFI=aVVFI.Append1(); - aVFI.SetVertex(aVx); - aVFI.SetFace(aFy); + + // Add vertices and faces for classification + BOPCol_ListIteratorOfListOfInteger aItLV(aLIAV); + for (; aItLV.More(); aItLV.Next()) + { + TopoDS_Vertex aV = TopoDS::Vertex(myDS->Shape(aItLV.Value())); + aV.Orientation(TopAbs_INTERNAL); + + BOPCol_ListIteratorOfListOfShape aItLFIm(*pLFIm); + for (; aItLFIm.More(); aItLFIm.Next()) + { + const TopoDS_Face& aFIm = TopoDS::Face(aItLFIm.Value()); + // Make the pair + BOPAlgo_VFI& aVFI = aVVFI.Append1(); + aVFI.SetVertex(aV); + aVFI.SetFace(aFIm); aVFI.SetFuzzyValue(myFuzzyValue); aVFI.SetProgressIndicator(myProgressIndicator); } } - }// for (i=0; i #include #include +#include #include #include #include @@ -414,12 +415,11 @@ void BOPAlgo_PaveFiller::MakeSplitEdges() return; } // - Standard_Boolean bCB, bV1, bV2; - Standard_Integer i, nE, nV1, nV2, nSp, aNbPB, aNbVBSE, k; + Standard_Integer i, nE, nV1, nV2, nSp, aNbVBSE, k; Standard_Real aT1, aT2; BOPDS_ListIteratorOfListOfPaveBlock aItPB; Handle(BOPDS_PaveBlock) aPB; - BOPDS_MapOfPaveBlock aMPB(100); + BOPDS_MapOfCommonBlock aMCB(100); TopoDS_Vertex aV1, aV2; TopoDS_Edge aE; BOPAlgo_VectorOfSplitEdge aVBSE; @@ -429,77 +429,96 @@ void BOPAlgo_PaveFiller::MakeSplitEdges() // aNbPBP=aPBP.Extent(); // - for (i=0; iOriginalEdge(); + const BOPDS_ShapeInfo& aSIE = myDS->ShapeInfo(nE); + if (aSIE.HasFlag()) + { + // Skip degenerated edges + continue; + } + + const Handle(BOPDS_CommonBlock)& aCB = myDS->CommonBlock(aPB); + Standard_Boolean bCB = !aCB.IsNull(); + if (bCB && !aMCB.Add(aCB)) + continue; + aPB->Indices(nV1, nV2); - bV1=myDS->IsNewShape(nV1); - bV2=myDS->IsNewShape(nV2); - bCB=myDS->IsCommonBlock(aPB); - // - if (!(bV1 || bV2)) { // no new vertices here - if (!myNonDestructive || !bCB) { - if (bCB) { - if (!aPB->HasEdge()) { - const Handle(BOPDS_CommonBlock)& aCB = myDS->CommonBlock(aPB); - nE = aCB->PaveBlock1()->OriginalEdge(); - aCB->SetEdge(nE); - // Compute tolerance of the common block and update the edge - Standard_Real aTol = BOPAlgo_Tools::ComputeToleranceOfCB(aCB, myDS, myContext); - myDS->UpdateEdgeTolerance(nE, aTol); + // Check if it is necessary to make the split of the edge + { + Standard_Boolean bV1 = myDS->IsNewShape(nV1); + Standard_Boolean bV2 = myDS->IsNewShape(nV2); + + Standard_Boolean bToSplit = Standard_True; + if (!bV1 && !bV2) // no new vertices here + { + if (!myNonDestructive || !bCB) + { + if (bCB) + { + // Find the edge with these vertices + BOPDS_ListIteratorOfListOfPaveBlock it(aCB->PaveBlocks()); + for (; it.More(); it.Next()) + { + nE = it.Value()->OriginalEdge(); + if (myDS->PaveBlocks(nE).Extent() == 1) + break; + } + if (it.More()) + { + // The pave block is found + bToSplit = Standard_False; + aCB->SetRealPaveBlock(it.Value()); + aCB->SetEdge(nE); + // Compute tolerance of the common block and update the edge + Standard_Real aTol = BOPAlgo_Tools::ComputeToleranceOfCB(aCB, myDS, myContext); + myDS->UpdateEdgeTolerance(nE, aTol); + } } + else if (aLPB.Extent() == 1) + { + bToSplit = Standard_False; + aPB->SetEdge(nE); + } + if (!bToSplit) + continue; } - else { - nE = aPB->OriginalEdge(); - aPB->SetEdge(nE); - } - continue; } } - } - // - aItPB.Initialize(aLPB); - for (; aItPB.More(); aItPB.Next()) { - aPB=aItPB.Value(); - nE=aPB->OriginalEdge(); - const BOPDS_ShapeInfo& aSIE=myDS->ShapeInfo(nE); - if (aSIE.HasFlag()){ - continue; + + // Split the edge + if (bCB) + { + aPB = aCB->PaveBlock1(); + nE = aPB->OriginalEdge(); + aPB->Indices(nV1, nV2); } + aPB->Range(aT1, aT2); // - const Handle(BOPDS_CommonBlock)& aCB=myDS->CommonBlock(aPB); - bCB=!aCB.IsNull(); - if (bCB) { - aPB=aCB->PaveBlock1(); - } + aE = (*(TopoDS_Edge *)(&myDS->Shape(nE))); + aE.Orientation(TopAbs_FORWARD); // - if (aMPB.Add(aPB)) { - nE=aPB->OriginalEdge(); - aPB->Indices(nV1, nV2); - aPB->Range(aT1, aT2); - // - aE=(*(TopoDS_Edge *)(&myDS->Shape(nE))); - aE.Orientation(TopAbs_FORWARD); - // - aV1=(*(TopoDS_Vertex *)(&myDS->Shape(nV1))); - aV1.Orientation(TopAbs_FORWARD); - // - aV2=(*(TopoDS_Vertex *)(&myDS->Shape(nV2))); - aV2.Orientation(TopAbs_REVERSED); - // - BOPAlgo_SplitEdge& aBSE=aVBSE.Append1(); - // - aBSE.SetData(aE, aV1, aT1, aV2, aT2); - aBSE.SetPaveBlock(aPB); - if (bCB) { - aBSE.SetCommonBlock(aCB); - } - aBSE.SetDS(myDS); - aBSE.SetProgressIndicator(myProgressIndicator); + aV1 = (*(TopoDS_Vertex *)(&myDS->Shape(nV1))); + aV1.Orientation(TopAbs_FORWARD); + // + aV2 = (*(TopoDS_Vertex *)(&myDS->Shape(nV2))); + aV2.Orientation(TopAbs_REVERSED); + // + BOPAlgo_SplitEdge& aBSE = aVBSE.Append1(); + // + aBSE.SetData(aE, aV1, aT1, aV2, aT2); + aBSE.SetPaveBlock(aPB); + if (bCB) { + aBSE.SetCommonBlock(aCB); } + aBSE.SetDS(myDS); + aBSE.SetProgressIndicator(myProgressIndicator); } // for (; aItPB.More(); aItPB.Next()) { } // for (i=0; i //! +//! Additionally to the options defined in the base class, the algorithm has +//! the following options:
+//! - *Safe processing mode* - allows to avoid modification of the input +//! shapes during the operation (by default it is off); +//! - *Gluing options* - allows to speed up the calculation of the intersections +//! on the special cases, in which some sub-shapes are coinciding. +//! - *Disabling the check for inverted solids* - Disables/Enables the check of the input solids +//! for inverted status (holes in the space). The default value is TRUE, +//! i.e. the check is performed. Setting this flag to FALSE for inverted solids, +//! most likely will lead to incorrect results. +//! //! It returns the following Error statuses:
//! - 0 - in case of success;
//! - *BOPAlgo_AlertTooFewArguments* - in case there are no enough arguments to perform the operation;
@@ -72,6 +82,19 @@ Standard_EXPORT virtual ~BRepAlgoAPI_BuilderAlgo(); //! Returns the glue option of the algorithm Standard_EXPORT BOPAlgo_GlueEnum Glue() const; + //! Enables/Disables the check of the input solids for inverted status + void SetCheckInverted(const Standard_Boolean theCheck) + { + myCheckInverted = theCheck; + } + + //! Returns the flag defining whether the check for input solids on inverted status + //! should be performed or not. + Standard_Boolean CheckInverted() const + { + return myCheckInverted; + } + //! Sets the arguments Standard_EXPORT void SetArguments (const TopTools_ListOfShape& theLS); @@ -130,20 +153,10 @@ protected: Standard_Boolean myNonDestructive; TopTools_ListOfShape myArguments; BOPAlgo_GlueEnum myGlue; - + Standard_Boolean myCheckInverted; private: - - - - }; - - - - - - #endif // _BRepAlgoAPI_BuilderAlgo_HeaderFile diff --git a/src/BRepFeat/BRepFeat_Builder.cxx b/src/BRepFeat/BRepFeat_Builder.cxx index 59b2440889..e601dedf2b 100644 --- a/src/BRepFeat/BRepFeat_Builder.cxx +++ b/src/BRepFeat/BRepFeat_Builder.cxx @@ -503,9 +503,7 @@ } } // - mySplits.Bind(aF, aLFIm); if (aLFIm.Extent() == 0) { - mySplits.UnBind(aF); myImages.UnBind(aF); } } diff --git a/src/BRepOffset/BRepOffset_MakeOffset_1.cxx b/src/BRepOffset/BRepOffset_MakeOffset_1.cxx index 86d84ad899..a22b7729e8 100644 --- a/src/BRepOffset/BRepOffset_MakeOffset_1.cxx +++ b/src/BRepOffset/BRepOffset_MakeOffset_1.cxx @@ -5633,14 +5633,8 @@ void UpdateValidEdges(const TopTools_IndexedDataMapOfShapeListOfShape& theFImage GetBoundsToUpdate(aLF, theOEImages, theOEOrigins, aMEB, aLABounds, aLAValid, aBounds, theAsDes); // - // intersect valid splits with bounds and update both + // Intersect valid splits with bounds and update both BOPAlgo_Builder aGF; - // The order is important here, because we need to keep the - // unmodified edges from the Bounds in the resulting maps. - // In case of total coincidence of the edges with the same vertices - // the edges in the common block will not be split and no new - // edges will be created and the first pave block - // will be used as a real pave block. aGF.AddArgument(aBounds); aGF.AddArgument(aSplits); aGF.Perform(); @@ -5668,18 +5662,56 @@ void UpdateValidEdges(const TopTools_IndexedDataMapOfShapeListOfShape& theFImage } } // + // Rebuild the map of edges to avoid, using the intersection results + TopTools_IndexedMapOfShape aMEAvoid; + // GF's data structure + const BOPDS_PDS& pDS = aGF.PDS(); + aNbE = theEdgesToAvoid.Extent(); - for (i = 1; i <= aNbE; ++i) { + for (i = 1; i <= aNbE; ++i) + { const TopoDS_Shape& aE = theEdgesToAvoid(i); const TopTools_ListOfShape& aLEIm = aGF.Modified(aE); + + // Only untouched and fully coinciding edges should be kept in the avoid map + Standard_Boolean bKeep = aLEIm.IsEmpty(); + if (aLEIm.Extent() == 1 && aE.IsSame(aLEIm.First())) + { + const BOPDS_ListOfPaveBlock& aLPB = pDS->PaveBlocks(pDS->Index(aE)); + if (aLPB.Extent() == 1) + { + const Handle(BOPDS_PaveBlock)& aPB = aLPB.First(); + const Handle(BOPDS_CommonBlock)& aCB = pDS->CommonBlock(aPB); + if (!aCB.IsNull()) + { + const BOPDS_ListOfPaveBlock& aLPBCB = aCB->PaveBlocks(); + BOPDS_ListIteratorOfListOfPaveBlock aItLPB(aLPBCB); + for (; aItLPB.More(); aItLPB.Next()) + { + if (pDS->PaveBlocks(aItLPB.Value()->OriginalEdge()).Extent() > 1) + break; + } + bKeep = !aItLPB.More(); + } + } + } + + if (bKeep) + { + // keep the original edge + aMEAvoid.Add(aE); + continue; + } + TopTools_ListIteratorOfListOfShape aItLEIm(aLEIm); - for (; aItLEIm.More(); aItLEIm.Next()) { + for (; aItLEIm.More(); aItLEIm.Next()) + { const TopoDS_Shape& aEIm = aItLEIm.Value(); - if (!aNewEdges.Contains(aEIm)) { - theEdgesToAvoid.Add(aEIm); - } + if (!aNewEdges.Contains(aEIm)) + aMEAvoid.Add(aEIm); } } + theEdgesToAvoid = aMEAvoid; } //======================================================================= diff --git a/tests/blend/complex/G9 b/tests/blend/complex/G9 index ff4881becc..340187c593 100644 --- a/tests/blend/complex/G9 +++ b/tests/blend/complex/G9 @@ -8,6 +8,6 @@ pcylinder c2 5 20 ttranslate c2 4.9 0 10 bfuse f c1b c2 explode f E -blend result f 4.9 f_5 +blend result f 4.9 f_4 checkprops result -s 2104.35 diff --git a/tests/blend/complex/H2 b/tests/blend/complex/H2 deleted file mode 100644 index cc8343d537..0000000000 --- a/tests/blend/complex/H2 +++ /dev/null @@ -1,16 +0,0 @@ -# ==================================== -## Grid : CFI900 -## Test : N1 -## Comment : from USA60109 -## ==================================== - -pcylinder c1 10 20 -pcylinder c2 5 20 -ttranslate c2 5 0 20 -bfuse f c1 c2 -explode f E -blend result f 1 f_1 -explode result sh -renamevar result_1 result - -checkprops result -s 2485.86 diff --git a/tests/blend/simple/Q4 b/tests/blend/simple/Q4 index e47e8603c6..cb6ec86dda 100644 --- a/tests/blend/simple/Q4 +++ b/tests/blend/simple/Q4 @@ -5,6 +5,6 @@ pcylinder c 1 10 ttranslate c 2.5 2.5 2.5 bfuse s c b explode s E -blend result s 1 s_3 +blend result s 1 s_2 checkprops result -s 192.343 diff --git a/tests/blend/simple/Z1 b/tests/blend/simple/Z1 index 1afc065575..ec3e6b9920 100644 --- a/tests/blend/simple/Z1 +++ b/tests/blend/simple/Z1 @@ -7,8 +7,8 @@ ttranslate c2 5 0 20 bfuse f c1 c2 -explode f E +explode c1 e -blend result f 1 f_1 +blend result f 1 c1_3 checkprops result -s 2485.86 diff --git a/tests/bugs/modalg_7/bug27711 b/tests/bugs/modalg_7/bug27711 index 8105c11ba3..6ec342352a 100644 --- a/tests/bugs/modalg_7/bug27711 +++ b/tests/bugs/modalg_7/bug27711 @@ -11,20 +11,15 @@ puts "" smallview -box a -1.5 -1.5 0 3 3 3 -box b -3 -3 -3 6 6 3 -bfuse result a b -set bug_info [string trim [checkshape result]] -if {$bug_info != "This shape seems to be valid"} { - puts "ERROR: Problem of test case functionality. Should be additionally investigated." -} +restore [locate_data_file bug27711.brep] s + clear -display result +display s fit xwd $imagedir/${casename}_step_0.png -explode result e -blend result result 0.5 result_12 0.5 result_11 +explode s e +blend result s 0.5 s_12 0.5 s_11 set bug_info [string trim [checkshape result]] if {$bug_info != "This shape seems to be valid"} { puts "ERROR: Problem of test case functionality. Should be additionally investigated." diff --git a/tests/bugs/modalg_7/bug29333_1 b/tests/bugs/modalg_7/bug29333_1 new file mode 100644 index 0000000000..fa77f316f9 --- /dev/null +++ b/tests/bugs/modalg_7/bug29333_1 @@ -0,0 +1,65 @@ +puts "========" +puts "OCC29333" +puts "========" +puts "" +################################################# +# Boolean Operations - Prevent modification of the input shapes in case their sub-shapes have not been modified +################################################# + +# create two touching faces +plane p 0 0 0 0 0 1 +mkface f1 p -10 10 -10 10 + +copy f1 f2 +ttranslate f2 20 0 0 + +# fuse these faces +bfuse s f1 f2 + +# split one of these faces +explode s f + +line l 0 0 0 1 0 0 +mkedge e l +bclearobjects +bcleartools +baddobjects s_1 +baddtools e +bfillds +bsplit s1_sp + + +# fuse again +bclearobjects +bcleartools +baddobjects s1_sp +baddtools s_2 +bfillds +bbuild result + +checkshape result +checkprops result -s 800 +checknbshapes result -vertex 8 -edge 10 -wire 3 -face 3 + + +# check that non of the shapes from s1_sp is modified +compound result s1_sp c +checknbshapes c -vertex 8 -edge 10 -wire 3 -face 3 + + +# fuse with different order +bclearobjects +bcleartools +baddobjects s_2 +baddtools s1_sp +bfillds +bbuild result + +checkshape result +checkprops result -s 800 +checknbshapes result -vertex 8 -edge 10 -wire 3 -face 3 + + +# check that non of the shapes from s1_sp is modified +compound result s1_sp c +checknbshapes c -vertex 8 -edge 10 -wire 3 -face 3 diff --git a/tests/bugs/modalg_7/bug29333_2 b/tests/bugs/modalg_7/bug29333_2 new file mode 100644 index 0000000000..ccb0760745 --- /dev/null +++ b/tests/bugs/modalg_7/bug29333_2 @@ -0,0 +1,62 @@ +puts "========" +puts "OCC29333" +puts "========" +puts "" +################################################# +# Boolean Operations - Prevent modification of the input shapes in case their sub-shapes have not been modified +################################################# + +# create two touching boxes +box b1 10 10 10 +box b2 10 0 0 10 10 10 + +# make them share the common face +mkvolume s b1 b2 + +# split one of these solids +explode s so + +plane p 0 0 5 0 0 1 +mkface f p +bclearobjects +bcleartools +baddobjects s_1 +baddtools f +bfillds +bsplit s1_sp + + +# fuse again +bclearobjects +bcleartools +baddobjects s1_sp +baddtools s_2 +bfillds +bbuild result + +checkshape result +checkprops result -s 1400 -v 2000 +checknbshapes result -vertex 16 -edge 28 -wire 16 -face 16 -shell 3 -solid 3 + + +# check that non of the shapes from s1_sp is modified +compound result s1_sp c +checknbshapes c -vertex 16 -edge 28 -wire 16 -face 16 -shell 3 -solid 3 + + +# fuse with different order +bclearobjects +bcleartools +baddobjects s_2 +baddtools s1_sp +bfillds +bbuild result + +checkshape result +checkprops result -s 1400 -v 2000 +checknbshapes result -vertex 16 -edge 28 -wire 16 -face 16 -shell 3 -solid 3 + + +# check that non of the shapes from s1_sp is modified +compound result s1_sp c +checknbshapes c -vertex 16 -edge 28 -wire 16 -face 16 -shell 3 -solid 3 diff --git a/tests/caf/named_shape/F8 b/tests/caf/named_shape/F8 index 36389003db..4147563580 100755 --- a/tests/caf/named_shape/F8 +++ b/tests/caf/named_shape/F8 @@ -9,7 +9,7 @@ # 1. Create 3 boxes $B1, $B2, $B3 # 2. $FS1 = Fuse ($B1, $B2) # 3. $FS2 = Fuse ($B1, $B3) -# 4. Make selections of the face 'fuse2_23' +# 4. Make selections of the face 'fuse2_19' # 5. Modify B2 # 6. Recompute # =============================================== @@ -37,12 +37,12 @@ GetShape $doc $FS2:2 fuse2 explode fuse2 f -#4. select fuse2_23 (using SelectShape) -set Sel1 0:2:23 -SelectShape $doc $Sel1 fuse2_23 fuse2 -GetShape $doc $Sel1 f23before -#f23before is face -set info1 [whatis f23before] +#4. select fuse2_19 (using SelectShape) +set Sel1 0:2:19 +SelectShape $doc $Sel1 fuse2_19 fuse2 +GetShape $doc $Sel1 f19before +#f19before is face +set info1 [whatis f19before] #5. Modify @@ -53,40 +53,40 @@ ComputeFun $doc $B2:1 ComputeFun $doc $FS1 ComputeFun $doc $FS2 SolveSelection $doc $Sel1 -GetShape $doc $Sel1 f23after -#f23after is face -set info2 [whatis f23after] +GetShape $doc $Sel1 f19after +#f19after is face +set info2 [whatis f19after] if { [regexp "shape" $info1] != 1 } { - puts "Error : There is not word shape in f23after" + puts "Error : There is not word shape in f19after" } if { [regexp "FACE" $info1] != 1 } { - puts "Error : There is not word FACE in f23after" + puts "Error : There is not word FACE in f19after" } if { [regexp "REVERSED" $info1] != 1 } { - puts "Error : There is not word REVERSED in f23after" + puts "Error : There is not word REVERSED in f19after" } if { [regexp "Modified" $info1] != 1 } { - puts "Error : There is not word Modified in f23after" + puts "Error : There is not word Modified in f19after" } if { [regexp "Orientable" $info1] != 1 } { - puts "Error : There is not word Orientable in f23after" + puts "Error : There is not word Orientable in f19after" } if { [regexp "shape" $info2] != 1 } { - puts "Error : There is not word shape in f23before" + puts "Error : There is not word shape in f19before" } if { [regexp "FACE" $info2] != 1 } { - puts "Error : There is not word FACE in f23before" + puts "Error : There is not word FACE in f19before" } if { [regexp "REVERSED" $info2] != 1 } { - puts "Error : There is not word REVERSED in f23before" + puts "Error : There is not word REVERSED in f19before" } if { [regexp "Modified" $info2] != 1 } { - puts "Error : There is not word Modified in f23before" + puts "Error : There is not word Modified in f19before" } if { [regexp "Orientable" $info2] != 1 } { - puts "Error : There is not word Orientable in f23before" + puts "Error : There is not word Orientable in f19before" } diff --git a/tests/caf/named_shape/F9 b/tests/caf/named_shape/F9 index c3612a5515..4489ec0916 100755 --- a/tests/caf/named_shape/F9 +++ b/tests/caf/named_shape/F9 @@ -9,7 +9,7 @@ # 1. Create 3 boxes $B1, $B2, $B3 # 2. $FS1 = Fuse ($B1, $B2) # 3. $FS2 = Fuse ($B1, $B3) -# 4. Make selections of the face 'fuse2_23' +# 4. Make selections of the face 'fuse2_19' # 5. Modify B2 # 6. Recompute # =============================================== @@ -38,11 +38,11 @@ explode fuse2 f -#4. Select fuse2_23 using Attach -set Sel2 [AttachShape $doc fuse2_23 $B1] -GetShape $doc $Sel2:1:2 nf23before -#nf23before is face -set info1 [whatis nf23before] +#4. Select fuse2_19 using Attach +set Sel2 [AttachShape $doc fuse2_19 $B1] +GetShape $doc $Sel2:1:2 nf19before +#nf19before is face +set info1 [whatis nf19before] #5. Modify @@ -56,38 +56,38 @@ ComputeFun $doc $B3:1 ComputeFun $doc $FS1 ComputeFun $doc $FS2 ComputeFun $doc $Sel2:1 -GetShape $doc $Sel2:1:2 nf23after -#nf23after is face -set info2 [whatis nf23after] +GetShape $doc $Sel2:1:2 nf19after +#nf19after is face +set info2 [whatis nf19after] if { [regexp "shape" $info1] != 1 } { - puts "Error : There is not word shape in nf23after" + puts "Error : There is not word shape in nf19after" } if { [regexp "FACE" $info1] != 1 } { - puts "Error : There is not word FACE in nf23after" + puts "Error : There is not word FACE in nf19after" } if { [regexp "REVERSED" $info1] != 1 } { - puts "Error : There is not word REVERSED in nf23after" + puts "Error : There is not word REVERSED in nf19after" } if { [regexp "Modified" $info1] != 1 } { - puts "Error : There is not word Modified in nf23after" + puts "Error : There is not word Modified in nf19after" } if { [regexp "Orientable" $info1] != 1 } { - puts "Error : There is not word Orientable in nf23after" + puts "Error : There is not word Orientable in nf19after" } if { [regexp "shape" $info2] != 1 } { - puts "Error : There is not word shape in nf23before" + puts "Error : There is not word shape in nf19before" } if { [regexp "FACE" $info2] != 1 } { - puts "Error : There is not word FACE in nf23before" + puts "Error : There is not word FACE in nf19before" } if { [regexp "REVERSED" $info2] != 1 } { - puts "Error : There is not word REVERSED in nf23before" + puts "Error : There is not word REVERSED in nf19before" } if { [regexp "Modified" $info2] != 1 } { - puts "Error : There is not word Modified in nf23before" + puts "Error : There is not word Modified in nf19before" } if { [regexp "Orientable" $info2] != 1 } { - puts "Error : There is not word Orientable in nf23before" + puts "Error : There is not word Orientable in nf19before" } \ No newline at end of file diff --git a/tests/perf/modalg/bug29237_1 b/tests/perf/modalg/bug29237_1 index 37ff7bfaf4..548e87b24c 100644 --- a/tests/perf/modalg/bug29237_1 +++ b/tests/perf/modalg/bug29237_1 @@ -37,10 +37,10 @@ dchrono cpu stop counter OCC29237 # check the result of CUT checkshape rcut -checknbshapes rcut -vertex 640 -edge 1760 -wire 842 -face 842 -shell 1 -solid 1 +checknbshapes rcut -vertex 1200 -edge 2040 -wire 842 -face 842 -shell 1 -solid 1 -t -m "CUT" checkprops rcut -s 3.4136e+006 -v 2.9712e+007 # check the result of COMMON checkshape rcommon -checknbshapes rcommon -vertex 616 -edge 1484 -wire 882 -face 882 -shell 147 -solid 147 +checknbshapes rcommon -vertex 1176 -edge 1764 -wire 882 -face 882 -shell 147 -solid 147 -t -m "COMMON" checkprops rcommon -s 2.13392e+006 -v 1.6448e+007 diff --git a/tests/perf/modalg/bug29237_3 b/tests/perf/modalg/bug29237_3 index 8b4064c932..0255485554 100644 --- a/tests/perf/modalg/bug29237_3 +++ b/tests/perf/modalg/bug29237_3 @@ -38,10 +38,10 @@ dchrono cpu stop counter OCC29237 # check the result of CUT checkshape rcut -checknbshapes rcut -vertex 1294 -edge 3074 -wire 1842 -face 1842 -shell 301 -solid 301 +checknbshapes rcut -vertex 2488 -edge 3732 -wire 1846 -face 1846 -shell 301 -solid 301 -t -m "CUT" checkprops rcut -s 2.59678e+006 -v 1.5346e+007 # check the result of COMMON checkshape rcommon -checknbshapes rcommon -vertex 0 -edge 0 -wire 0 -face 0 -shell 0 -solid 0 +checknbshapes rcommon -vertex 0 -edge 0 -wire 0 -face 0 -shell 0 -solid 0 -t -m "COMMON" checkprops rcommon -s empty -v empty -- 2.39.5