From 5defca41ffcec0263990d9f192132a5f8d9cb2c3 Mon Sep 17 00:00:00 2001 From: emv Date: Fri, 22 Sep 2017 14:09:25 +0300 Subject: [PATCH] Improve the algorithm of computation of the exposed area. The algorithm OCCTools_ComputeExposedArea has been improved by switching to working with compounds of Faces instead of Solids in the Gluing mode. In the Gluing mode there is no need to work with solids, as the arguments are expected to be touching only and should not have any common volume. Working with faces helps to avoid errors while constructing the solids. In this mode the result of the operation will be just the compound of faces. --- src/OCCTools/OCCTools_ComputeExposedArea.cxx | 137 ++++++++++++++++--- src/OCCTools/OCCTools_ComputeExposedArea.hxx | 10 ++ 2 files changed, 126 insertions(+), 21 deletions(-) diff --git a/src/OCCTools/OCCTools_ComputeExposedArea.cxx b/src/OCCTools/OCCTools_ComputeExposedArea.cxx index 5754abcc5f..536da21521 100644 --- a/src/OCCTools/OCCTools_ComputeExposedArea.cxx +++ b/src/OCCTools/OCCTools_ComputeExposedArea.cxx @@ -3,11 +3,16 @@ // Author: Mikhail Sazonov #include "OCCTools_ComputeExposedArea.hxx" + +#include +#include #include #include #include -#include #include +#include +#include +#include #pragma comment(lib,"TKernel") #pragma comment(lib,"TKMath") @@ -16,6 +21,11 @@ #pragma comment(lib,"TKTopAlgo") #pragma comment(lib,"TKBO") +static + void MakeCompound(const TopoDS_Shape& theShape, + TopoDS_Shape& theComp, + const TopAbs_ShapeEnum theType = TopAbs_FACE); + //======================================================================= //function : Constructor //purpose : @@ -46,8 +56,8 @@ OCCTools_ComputeExposedArea::OCCTools_ComputeExposedArea(const TopTools_ListOfSh } //======================================================================= -//function : Constructor -//purpose : +//function : AddShape +//purpose : //======================================================================= Standard_Boolean OCCTools_ComputeExposedArea::AddShape(const TopoDS_Shape& theShape) { @@ -101,31 +111,100 @@ Standard_Integer OCCTools_ComputeExposedArea::Perform(const Handle(Message_Progr } else { - // create fuse algorithm - BRepAlgoAPI_Fuse aBOP; - aBOP.SetProgressIndicator(theProgress); - aBOP.SetRunParallel(Standard_True); - aBOP.SetFuzzyValue(myFuzzyValue); - //aBOP.SetNonDestructive(Standard_True); - if (myIsGluing) - aBOP.SetGlue(BOPAlgo_GlueShift); + // For the case of gluing there is no need to perform operation on + // the solids, it is enough to fuse only the faces, and remove all + // coinciding splits from the result. + // Without gluing we need to perform real Boolean Fuse operation + // to avoid common part in the result - // prepare arguments for fusion - TopTools_ListOfShape anArgs, aTools; - anArgs = myShapes; - anArgs.RemoveFirst(); - aTools.Append(myShapes.First()); - aBOP.SetArguments(anArgs); - aBOP.SetTools(aTools); + BRepAlgoAPI_BuilderAlgo *pBuilder = myIsGluing ? + new BRepAlgoAPI_BuilderAlgo() : new BRepAlgoAPI_Fuse(); + pBuilder->SetProgressIndicator(theProgress); + pBuilder->SetRunParallel(Standard_True); + pBuilder->SetFuzzyValue(myFuzzyValue); + if (myIsGluing) + { + pBuilder->SetGlue(BOPAlgo_GlueShift); + // prepare arguments - remove solids and make compound of faces + TopTools_ListOfShape aLFaces; + TopTools_ListIteratorOfListOfShape aItLS(myShapes); + for (; aItLS.More(); aItLS.Next()) + { + TopoDS_Shape aFaces; + MakeCompound(aItLS.Value(), aFaces); + aLFaces.Append(aFaces); + } + pBuilder->SetArguments(aLFaces); + } + else + { + // For the fuse one of the shapes should be an object + // and other the tools + TopTools_ListOfShape anObjects, aTools; + anObjects = myShapes; + anObjects.RemoveFirst(); + aTools.Append(myShapes.First()); + pBuilder->SetArguments(anObjects); + ((BRepAlgoAPI_Fuse*)pBuilder)->SetTools(aTools); + } // perform fusion - aBOP.Build(); - if (!aBOP.IsDone()) + pBuilder->Build(); + if (!pBuilder->IsDone()) { return Status_FuseError; } - myFusedShape = aBOP.Shape(); + myFusedShape = pBuilder->Shape(); + + if (myIsGluing) + { + // Analyze the result of fuse - the fused result should contain only unique faces + + // Result compound + TopoDS_Compound aResult; + BRep_Builder().MakeCompound(aResult); + + // Make a map from the result faces to original ones + BOPCol_IndexedDataMapOfShapeListOfShape aFaceLOrigins; + + TopTools_ListIteratorOfListOfShape aItLS(myShapes); + for (; aItLS.More(); aItLS.Next()) + { + const TopoDS_Shape& aS = aItLS.Value(); + TopExp_Explorer anExp(aS, TopAbs_FACE); + for (; anExp.More(); anExp.Next()) + { + const TopoDS_Shape& aF = anExp.Current(); + const TopTools_ListOfShape& aLFIm = pBuilder->Modified(aF); + if (aLFIm.IsEmpty()) + { + // the face has not been even touched + BRep_Builder().Add(aResult, aF); + continue; + } + + TopTools_ListIteratorOfListOfShape aItLFIm(aLFIm); + for (; aItLFIm.More(); aItLFIm.Next()) + { + const TopoDS_Shape& aFIm = aItLFIm.Value(); + TopTools_ListOfShape *pLOrigins = aFaceLOrigins.ChangeSeek(aFIm); + if (!pLOrigins) + pLOrigins = &aFaceLOrigins(aFaceLOrigins.Add(aFIm, TopTools_ListOfShape())); + pLOrigins->Append(aF); + } + } + } + + Standard_Integer i, aNb = aFaceLOrigins.Extent(); + for (i = 1; i <= aNb; ++i) + { + if (aFaceLOrigins(i).Extent() == 1) + BRep_Builder().Add(aResult, aFaceLOrigins.FindKey(i)); + } + + myFusedShape = aResult; + } } // compute area of fused shape @@ -134,3 +213,19 @@ Standard_Integer OCCTools_ComputeExposedArea::Perform(const Handle(Message_Progr myArea = aProps.Mass(); return Status_OK; } + +//======================================================================= +//function : MakeCompound +//purpose : +//======================================================================= +void MakeCompound(const TopoDS_Shape& theShape, + TopoDS_Shape& theComp, + const TopAbs_ShapeEnum theType) +{ + TopoDS_Compound aComp; + BRep_Builder().MakeCompound(aComp); + TopExp_Explorer anExp(theShape, theType); + for (; anExp.More(); anExp.Next()) + BRep_Builder().Add(aComp, anExp.Current()); + theComp = aComp; +} diff --git a/src/OCCTools/OCCTools_ComputeExposedArea.hxx b/src/OCCTools/OCCTools_ComputeExposedArea.hxx index 301f155b82..0e15077d4c 100644 --- a/src/OCCTools/OCCTools_ComputeExposedArea.hxx +++ b/src/OCCTools/OCCTools_ComputeExposedArea.hxx @@ -14,6 +14,15 @@ class Message_ProgressIndicator; //! and calculates the area of the result (exposed area). //! It looks only for solid shapes in input arguments. If there are no solids //! it looks for faces and tries to create closed shells and then solids of them. +//! The class has the following options: +//! - *Gluing mode* - allows speeding up the calculation on the touching arguments; +//! In this mode the area computation will be performed on the faces, +//! forming the closed shells, not on the solids. It will help to avoid +//! extra computations and, most importantly, possible errors while +//! constructing the solids; +//! - *Fuzzy mode* - additional tolerance for the operation to make the arguments +//! interfere when its appropriate. +//! class OCCTools_ComputeExposedArea { public: @@ -85,6 +94,7 @@ public: } private: + TopTools_ListOfShape myShapes; TopoDS_Shape myFusedShape; Standard_Real myFuzzyValue; -- 2.39.5