Get rid of requirement for the arguments of Boolean operations of type CUT and COMMON to be one-dimensional shape. For FUSE operation this requirement is kept.
@subsection upgrade_750_sensitiveEntity Select3D_SensitiveEntity interface change
The method Select3D_SensitiveEntity::NbSubElements() has been changed to be constant. Select3D_SensitiveEntity subclasses at application level should be updated accordingly.
+
+
+@subsection upgrade_750_Booleans Changes in Boolean operations algorithm
+
+* TreatCompound method has been moved from *BOPAlgo_Tools* to *BOPTools_AlgoTools*. Additionally, the map parameter became optional:
+~~~~
+void BOPTools_AlgoTools::TreatCompound (const TopoDS_Shape& theS,
+ TopTools_ListOfShape& theLS,
+ TopTools_MapOfShape* theMap = NULL);
+~~~~
return;
}
//
- Standard_Integer aDim1, aDim2;
- Standard_Boolean bBadTypes = Standard_False;
- //
- aDim1 = BOPTools_AlgoTools::Dimension(myShape1);
- aDim2 = BOPTools_AlgoTools::Dimension(myShape2);
- if (aDim1 < aDim2) {
- if (myOperation == BOPAlgo_FUSE ||
- myOperation == BOPAlgo_CUT21) {
- bBadTypes = Standard_True;
- }
- }
- else if (aDim1 > aDim2) {
- if (myOperation == BOPAlgo_FUSE ||
- myOperation == BOPAlgo_CUT) {
- bBadTypes = Standard_True;
+ if (myOperation != BOPAlgo_UNKNOWN &&
+ myOperation != BOPAlgo_COMMON)
+ {
+ Standard_Integer iDimMin[2], iDimMax[2];
+ BOPTools_AlgoTools::Dimensions(myShape1, iDimMin[0], iDimMax[0]);
+ BOPTools_AlgoTools::Dimensions(myShape2, iDimMin[1], iDimMax[1]);
+
+ Standard_Boolean bBadTypes =
+ ((myOperation == BOPAlgo_FUSE) &&
+ (iDimMin[0] != iDimMax[0] || iDimMin[1] != iDimMax[1] || iDimMin[0] != iDimMin[1])) ||
+ ((myOperation == BOPAlgo_CUT) && (iDimMax[0] > iDimMin[1])) ||
+ ((myOperation == BOPAlgo_CUT21) && (iDimMin[0] < iDimMax[1]));
+
+ if (bBadTypes) {
+ BOPAlgo_CheckResult aResult;
+ aResult.SetShape1(myShape1);
+ aResult.SetShape2(myShape2);
+ aResult.SetCheckStatus(BOPAlgo_BadType);
+ myResult.Append(aResult);
}
}
- if (bBadTypes) {
- BOPAlgo_CheckResult aResult;
- aResult.SetShape1(myShape1);
- aResult.SetShape2(myShape2);
- aResult.SetCheckStatus(BOPAlgo_BadType);
- myResult.Append(aResult);
- }
}
}
//=======================================================================
//=======================================================================
void BOPAlgo_BOP::CheckData()
{
- Standard_Integer i, j, iDim, aNbArgs, aNbTools;
+ Standard_Integer i, j, aNbArgs, aNbTools;
Standard_Boolean bFuse;
TopTools_ListIteratorOfListOfShape aItLS;
//
// or equal to the MAXIMAL dimension of the TOOLS;
// 4. COMMON: The arguments and tools could have any dimensions.
//
- Standard_Integer iDimMin[2] = { 0, 0 }, iDimMax[2] = { 0, 0 };
+ Standard_Integer iDimMin[2] = { 3, 3 },
+ iDimMax[2] = { 0, 0 };
Standard_Boolean bHasValid[2] = {Standard_False, Standard_False};
//
for (i=0; i<2; ++i) {
for (j=0; aItLS.More(); aItLS.Next(), ++j) {
const TopoDS_Shape& aS=aItLS.Value();
Standard_Boolean bIsEmpty = BOPTools_AlgoTools3D::IsEmptyShape(aS);
- if (bIsEmpty) {
+ if (bIsEmpty)
+ {
AddWarning(new BOPAlgo_AlertEmptyShape (aS));
continue;
}
- //
- iDim = BOPTools_AlgoTools::Dimension(aS);
- if (iDim < 0) {
+
+ Standard_Integer iDMin, iDMax;
+ BOPTools_AlgoTools::Dimensions(aS, iDMin, iDMax);
+
+ if (iDMin < iDimMin[i])
+ iDimMin[i] = iDMin;
+ if (iDMax > iDimMax[i])
+ iDimMax[i] = iDMax;
+
+ if (bFuse && (iDimMin[i] != iDimMax[i]))
+ {
// non-homogeneous argument
AddError (new BOPAlgo_AlertBOPNotAllowed);
return;
}
- //
bHasValid[i] = Standard_True;
- //
- if (!j) {
- iDimMin[i] = iDim;
- iDimMax[i] = iDim;
- continue;
- }
- //
- if (iDim < iDimMin[i]) {
- iDimMin[i] = iDim;
- }
- else if (iDim > iDimMax[i]) {
- iDimMax[i] = iDim;
- }
- //
- if (bFuse && (iDimMin[i] != iDimMax[i])) {
- // non-homogeneous argument
- AddError (new BOPAlgo_AlertBOPNotAllowed);
- return;
- }
}
}
//
if (bHasValid[0] || bHasValid[1])
{
// In case of all empty shapes in one of the groups
- // this group aquires the dimension of other group
+ // this group acquires the dimension of other group
myDims[0] = bHasValid[0] ? iDimMin[0] : iDimMin[1];
myDims[1] = bHasValid[1] ? iDimMin[1] : iDimMin[0];
}
aItLS.Initialize(aLS);
for (; aItLS.More(); aItLS.Next()) {
const TopoDS_Shape& aS = aItLS.Value();
- iDim = BOPTools_AlgoTools::Dimension(aS);
- if (iDim < 0) {
- continue;
+ TopTools_ListOfShape aList;
+ BOPTools_AlgoTools::TreatCompound (aS, aList);
+ for (TopTools_ListOfShape::Iterator itList (aList); itList.More(); itList.Next())
+ {
+ const TopoDS_Shape& aSS = itList.Value();
+ iDim = BOPTools_AlgoTools::Dimension (aSS);
+ if (iDim < 0)
+ continue;
+ aType = TypeToExplore (iDim);
+ TopExp::MapShapes (aSS, aType, aMS);
}
- aType = TypeToExplore(iDim);
- TopExp::MapShapes(aS, aType, aMS);
}
}
//
for (; aItLS.More(); aItLS.Next())
{
const TopoDS_Shape& aS = aItLS.Value();
- BOPAlgo_Tools::TreatCompound(aS, aMInpFence, aLSNonCont);
+ BOPTools_AlgoTools::TreatCompound(aS, aLSNonCont, &aMInpFence);
}
}
{
TopTools_ListOfShape aLS;
TopTools_MapOfShape aMFence;
- BOPAlgo_Tools::TreatCompound(aS, aMFence, aLS);
+ BOPTools_AlgoTools::TreatCompound(aS, aLS, &aMFence);
TopTools_ListOfShape::Iterator it(aLS);
for (; it.More(); it.Next())
aIt.Initialize(aArguments);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS=aIt.Value();
- BOPAlgo_Tools::TreatCompound(aS, aMFence, aLSC);
+ BOPTools_AlgoTools::TreatCompound(aS, aLSC, &aMFence);
}
aIt.Initialize(aLSC);
for (; aIt.More(); aIt.Next()) {
TopTools_ListIteratorOfListOfShape aIt(myArguments);
for (; aIt.More(); aIt.Next()) {
const TopoDS_Shape& aS = aIt.Value();
- //
- Standard_Integer iDim = BOPTools_AlgoTools::Dimension(aS);
- aMDims.Add(iDim);
- TopAbs_ShapeEnum aType = TypeToExplore(iDim);
- //
- TopExp_Explorer aExp(aS, aType);
- for (; aExp.More(); aExp.Next()) {
- const TopoDS_Shape& aST = aExp.Current();
- const TopTools_ListOfShape* pLSIm = myImages.Seek(aST);
- if (!pLSIm) {
- TopTools_ListOfShape* pLS = myIndex.ChangeSeek(aST);
- if (!pLS) {
- pLS = &myIndex(myIndex.Add(aST, TopTools_ListOfShape()));
- }
- pLS->Append(aS);
- //
- if (aMFence.Add(aST)) {
- aBB.Add(anAllParts, aST);
- }
- //
- continue;
- }
- //
- TopTools_ListIteratorOfListOfShape aItIm(*pLSIm);
- for (; aItIm.More(); aItIm.Next()) {
- const TopoDS_Shape& aSTIm = aItIm.Value();
- //
- TopTools_ListOfShape* pLS = myIndex.ChangeSeek(aSTIm);
- if (!pLS) {
- pLS = &myIndex(myIndex.Add(aSTIm, TopTools_ListOfShape()));
+
+ TopTools_ListOfShape aLSubS;
+ BOPTools_AlgoTools::TreatCompound (aS, aLSubS);
+ for (TopTools_ListOfShape::Iterator itSub (aLSubS); itSub.More(); itSub.Next())
+ {
+ const TopoDS_Shape& aSS = itSub.Value();
+ Standard_Integer iDim = BOPTools_AlgoTools::Dimension (aSS);
+ aMDims.Add(iDim);
+ TopAbs_ShapeEnum aType = TypeToExplore (iDim);
+ TopExp_Explorer aExp (aSS, aType);
+ for (; aExp.More(); aExp.Next())
+ {
+ const TopoDS_Shape& aST = aExp.Current();
+ const TopTools_ListOfShape* pLSIm = myImages.Seek(aST);
+ if (!pLSIm) {
+ TopTools_ListOfShape* pLS = myIndex.ChangeSeek(aST);
+ if (!pLS) {
+ pLS = &myIndex(myIndex.Add(aST, TopTools_ListOfShape()));
+ }
+ pLS->Append(aS);
+ //
+ if (aMFence.Add(aST)) {
+ aBB.Add(anAllParts, aST);
+ }
+ //
+ continue;
}
- pLS->Append(aS);
//
- if (aMFence.Add(aSTIm)) {
- aBB.Add(anAllParts, aSTIm);
- }
- } // for (; aItIm.More(); aItIm.Next()) {
- } // for (; aExp.More(); aExp.Next()) {
+ TopTools_ListIteratorOfListOfShape aItIm(*pLSIm);
+ for (; aItIm.More(); aItIm.Next()) {
+ const TopoDS_Shape& aSTIm = aItIm.Value();
+ //
+ TopTools_ListOfShape* pLS = myIndex.ChangeSeek(aSTIm);
+ if (!pLS) {
+ pLS = &myIndex(myIndex.Add(aSTIm, TopTools_ListOfShape()));
+ }
+ pLS->Append(aS);
+ //
+ if (aMFence.Add(aSTIm)) {
+ aBB.Add(anAllParts, aSTIm);
+ }
+ } // for (; aItIm.More(); aItIm.Next()) {
+ } // for (; aExp.More(); aExp.Next()) {
+ } // for (; itSub.More(); itSub.Next())
} // for (; aIt.More(); aIt.Next()) {
//
myAllParts = anAllParts;
TopTools_ListIteratorOfListOfShape itLA(myArguments);
for (; itLA.More(); itLA.Next())
- BOPAlgo_Tools::TreatCompound(itLA.Value(), aMFence, aLA);
+ BOPTools_AlgoTools::TreatCompound(itLA.Value(), aLA, &aMFence);
if (aLA.IsEmpty())
{
// Extract all non-compound shapes from the result
TopTools_ListOfShape aLShapes;
TopTools_MapOfShape aMFence;
- BOPAlgo_Tools::TreatCompound(myShape, aMFence, aLShapes);
+ BOPTools_AlgoTools::TreatCompound(myShape, aLShapes, &aMFence);
if (aLShapes.IsEmpty())
return;
TopTools_ListOfShape::Iterator itLA(myDS->Arguments());
for (; itLA.More(); itLA.Next())
- BOPAlgo_Tools::TreatCompound(itLA.Value(), aMFence, aLSC);
+ BOPTools_AlgoTools::TreatCompound(itLA.Value(), aLSC, &aMFence);
// Get only edges and vertices from arguments
TopTools_ListOfShape aLVE;
TopTools_ListOfShape aShapes;
TopTools_MapOfShape aMFence;
// Extract all shapes from the compound
- BOPAlgo_Tools::TreatCompound(myInputShape, aMFence, aShapes);
+ BOPTools_AlgoTools::TreatCompound(myInputShape, aShapes, &aMFence);
if (aShapes.IsEmpty())
{
// Add error of empty input shape
}
}
-//=======================================================================
-//function : TreatCompound
-//purpose :
-//=======================================================================
-void BOPAlgo_Tools::TreatCompound(const TopoDS_Shape& theS,
- TopTools_MapOfShape& aMFence,
- TopTools_ListOfShape& theLS)
-{
- TopAbs_ShapeEnum aType = theS.ShapeType();
- if (aType != TopAbs_COMPOUND)
- {
- if (aMFence.Add(theS))
- theLS.Append(theS);
- return;
- }
- TopoDS_Iterator aIt(theS);
- for (; aIt.More(); aIt.Next())
- {
- const TopoDS_Shape& aS = aIt.Value();
- TreatCompound(aS, aMFence, theLS);
- }
-}
-
//=======================================================================
// Classification of the faces relatively solids
//=======================================================================
const Standard_Real theFuzzyValue,
TopTools_ListOfListOfShape& theChains);
- //! Collect in the output list recursively all non-compound subshapes of the first level
- //! of the given shape theS. If a shape presents in the map theMFence it is skipped.
- //! All shapes put in the output are also added into theMFence.
- Standard_EXPORT static void TreatCompound(const TopoDS_Shape& theS,
- TopTools_MapOfShape& theMFence,
- TopTools_ListOfShape& theLS);
-
//! Classifies the faces <theFaces> relatively solids <theSolids>.
//! The IN faces for solids are stored into output data map <theInParts>.
//!
#include <TopAbs_ShapeEnum.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
+#include <TopTools_MapOfShape.hxx>
#include <TopTools_ListOfListOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <Precision.hxx>
const TopoDS_Edge& aE,
const Handle(IntTools_Context)& aContext);
- //! Retutns dimension of the shape <theS>.
+ //! Returns the min and max dimensions of the shape <theS>.
+ Standard_EXPORT static void Dimensions (const TopoDS_Shape& theS,
+ Standard_Integer& theDMin,
+ Standard_Integer& theDMax);
+
+ //! Returns dimension of the shape <theS>.
+ //! If the shape contains elements of different dimension, -1 is returned.
Standard_EXPORT static Standard_Integer Dimension(const TopoDS_Shape& theS);
+ //! Collects in the output list recursively all non-compound sub-shapes of the first level
+ //! of the given shape theS. The optional map theMap is used to avoid the duplicates in the
+ //! output list, so it will also contain all non-compound sub-shapes.
+ Standard_EXPORT static void TreatCompound (const TopoDS_Shape& theS,
+ TopTools_ListOfShape& theList,
+ TopTools_MapOfShape* theMap = NULL);
+
//! Returns true if the shell <theShell> is open
Standard_EXPORT static Standard_Boolean IsOpenShell(const TopoDS_Shell& theShell);
#include <TopoDS_Solid.hxx>
#include <TopoDS_Vertex.hxx>
-static
- void TreatCompound(const TopoDS_Shape& theC1,
- TopTools_ListOfShape& theLSX);
-
//=======================================================================
// function: UpdateVertex
// purpose:
}
}
}
+
+namespace
+{
+
//=======================================================================
-//function : Dimension
+//function : dimension
+//purpose : returns dimension of elementary shape
+//=======================================================================
+static Standard_Integer dimension (const TopoDS_Shape& theS)
+{
+ switch (theS.ShapeType())
+ {
+ case TopAbs_VERTEX:
+ return 0;
+ case TopAbs_EDGE:
+ case TopAbs_WIRE:
+ return 1;
+ case TopAbs_FACE:
+ case TopAbs_SHELL:
+ return 2;
+ case TopAbs_SOLID:
+ case TopAbs_COMPSOLID:
+ return 3;
+ default:
+ return -1;
+ }
+}
+
+}
+
+//=======================================================================
+//function : Dimensions
//purpose :
//=======================================================================
-Standard_Integer BOPTools_AlgoTools::Dimension(const TopoDS_Shape& theS)
+void BOPTools_AlgoTools::Dimensions (const TopoDS_Shape& theS,
+ Standard_Integer& theDMin,
+ Standard_Integer& theDMax)
{
- Standard_Integer i, iRet, iRx0 = 0, iRx = 0;
- TopAbs_ShapeEnum aTS;
+ theDMin = theDMax = dimension (theS);
+ if (theDMax >= 0)
+ return;
+
TopTools_ListOfShape aLS;
- TopTools_ListIteratorOfListOfShape aIt;
- //
- aTS=theS.ShapeType();
- if (aTS!=TopAbs_COMPOUND) {
- switch (aTS) {
- case TopAbs_EDGE:
- case TopAbs_WIRE:
- iRet=1;
- break;
- case TopAbs_FACE:
- case TopAbs_SHELL:
- iRet=2;
- break;
- case TopAbs_SOLID:
- case TopAbs_COMPSOLID:
- iRet=3;
- break;
- default:
- iRet=0;
- }
- return iRet;
- }
- //
- iRet=-1;
- TreatCompound(theS, aLS);
- if(aLS.IsEmpty()) {
- iRet = -2; //empty compound
- return iRet;
+ TopTools_MapOfShape aMFence;
+ TreatCompound (theS, aLS, &aMFence);
+ if (aLS.IsEmpty())
+ {
+ // empty shape
+ theDMin = theDMax = -1;
+ return;
}
- aIt.Initialize(aLS);
- for (i=0; aIt.More(); aIt.Next()) {
- const TopoDS_Shape& aSx=aIt.Value();
- iRx=Dimension(aSx);
- if (!i) {
- iRx0=iRx;
- i=1;
- continue;
- }
- if (iRx!=iRx0) {
- return iRet;// -1
- }
+
+ theDMin = 3;
+ theDMax = 0;
+ for (TopTools_ListOfShape::Iterator it (aLS); it.More(); it.Next())
+ {
+ Standard_Integer aDim = dimension (it.Value());
+ if (aDim < theDMin)
+ theDMin = aDim;
+ if (aDim > theDMax)
+ theDMax = aDim;
}
- return iRx;
+}
+
+//=======================================================================
+//function : Dimension
+//purpose :
+//=======================================================================
+Standard_Integer BOPTools_AlgoTools::Dimension(const TopoDS_Shape& theS)
+{
+ Standard_Integer aDMin, aDMax;
+ Dimensions (theS, aDMin, aDMax);
+ return (aDMin == aDMax) ? aDMin : -1;
}
//=======================================================================
//function : TreatCompound
//purpose :
//=======================================================================
-void TreatCompound(const TopoDS_Shape& theC1,
- TopTools_ListOfShape& theLSX)
+void BOPTools_AlgoTools::TreatCompound (const TopoDS_Shape& theS,
+ TopTools_ListOfShape& theLS,
+ TopTools_MapOfShape* theMFence)
{
- Standard_Integer aNbC1;
- TopAbs_ShapeEnum aType;
- TopTools_ListOfShape aLC, aLC1;
- TopTools_ListIteratorOfListOfShape aIt, aIt1;
- TopoDS_Iterator aItC;
- //
- aLC.Append (theC1);
- for(;;) {
- aLC1.Clear();
- aIt.Initialize(aLC);
- for (; aIt.More(); aIt.Next()) {
- const TopoDS_Shape& aC=aIt.Value(); //C is compound
- //
- aItC.Initialize(aC);
- for (; aItC.More(); aItC.Next()) {
- const TopoDS_Shape& aS=aItC.Value();
- aType=aS.ShapeType();
- if (aType==TopAbs_COMPOUND) {
- aLC1.Append(aS);
- }
- else {
- theLSX.Append(aS);
- }
- }
- }
- //
- aNbC1=aLC1.Extent();
- if (!aNbC1) {
- break;
- }
- //
- aLC.Clear();
- aIt.Initialize(aLC1);
- for (; aIt.More(); aIt.Next()) {
- const TopoDS_Shape& aSC=aIt.Value();
- aLC.Append(aSC);
+ TopAbs_ShapeEnum aType = theS.ShapeType();
+ if (aType != TopAbs_COMPOUND)
+ {
+ if (!theMFence || theMFence->Add (theS))
+ {
+ theLS.Append (theS);
}
- }// while(1)
+ return;
+ }
+
+ for (TopoDS_Iterator it (theS); it.More(); it.Next())
+ {
+ TreatCompound (it.Value(), theLS, theMFence);
+ }
}
--- /dev/null
+puts "======================================================="
+puts "0030386: Modeling Algorithms - Unable to perform Cut operation"
+puts "======================================================="
+puts ""
+
+restore [locate_data_file bug30386_shapes.brep] s
+explode s
+bclearobjects
+bcleartools
+baddobjects s_1
+baddtools s_2
+bfillds
+
+bbop r0 0
+bbop r2 2
+
+foreach r {r0 r2} {
+ checkshape $r
+ if {![regexp "OK" [bopcheck $r]]} {
+ puts "Error: the $r is a self-interfering shape"
+ }
+}
+
+checknbshapes r0 -wire 6 -face 6 -shell 0 -solid 0 -t
+checkprops r0 -s 1.0852
+
+checknbshapes r2 -wire 546 -face 533 -shell 12 -solid 12 -t
+checkprops r2 -s 223.275 -v 123.21
+
+checkview -display r2 -2d -path ${imagedir}/${test_image}.png
--- /dev/null
+puts "REQUIRED All: Error: Boolean operation of the given type is not allowed on the given inputs"
+
+puts "======================================================="
+puts "0030386: Modeling Algorithms - Unable to perform Cut operation"
+puts "======================================================="
+puts ""
+
+restore [locate_data_file bug30386_shapes.brep] s
+explode s
+# just to avoid intersection
+ttranslate s_2 10 0 0
+bclearobjects
+bcleartools
+baddobjects s_1
+baddtools s_2
+bfillds
+# try to perform fuse operation - error is expected
+bbop r1 1
--- /dev/null
+puts "REQUIRED All: Error: Boolean operation of the given type is not allowed on the given inputs"
+
+puts "======================================================="
+puts "0030386: Modeling Algorithms - Unable to perform Cut operation"
+puts "======================================================="
+puts ""
+
+restore [locate_data_file bug30386_shapes.brep] s
+explode s
+# just to avoid intersection
+ttranslate s_2 10 0 0
+bclearobjects
+bcleartools
+baddobjects s_1
+baddtools s_2
+bfillds
+# try to perform CUT21 operation - error is expected
+bbop r3 3
--- /dev/null
+puts "======================================================="
+puts "0030386: Modeling Algorithms - Unable to perform Cut operation"
+puts "======================================================="
+puts ""
+
+# prepare the first argument - compound of mutlti-dimensional shapes
+vertex v 0 0 2
+line l 5 5 0 0 0 1
+mkedge e l -10 10
+plane p 0 0 1 0 0 1
+mkface f p -15 15 -15 15
+box b 8 8 8 5 5 5
+bclearobjects
+bcleartools
+baddobjects v e f b
+bfillds
+bbuild s1
+
+# second argument - solid
+box s2 10 10 10
+
+bclearobjects
+bcleartools
+baddobjects s1
+baddtools s2
+bfillds
+
+# it is allowed to perform only CUT and COMMON operations
+bbop r0 0
+bbop r2 2
+
+
+foreach r {r0 r2} {
+ checkshape $r
+ if {![regexp "OK" [bopcheck $r]]} {
+ puts "Error: the $r is a self-interfering shape"
+ }
+}
+
+checknbshapes r0 -vertex 16 -edge 18 -wire 7 -face 7 -shell 1 -solid 1 -t
+checkprops r0 -s 124
+explode r0 so
+checkprops r0_1 -v 8
+
+checknbshapes r2 -vertex 24 -edge 30 -wire 11 -face 10 -shell 1 -solid 1 -t
+checkprops r2 -s 950
+explode r2 so
+checkprops r2_1 -v 117
+
+checkview -display r2 -2d -path ${imagedir}/${test_image}.png
--- /dev/null
+puts "REQUIRED All: Error: Boolean operation of the given type is not allowed on the given inputs"
+
+puts "======================================================="
+puts "0030386: Modeling Algorithms - Unable to perform Cut operation"
+puts "======================================================="
+puts ""
+
+# prepare the first argument - compound of mutlti-dimensional shapes
+vertex v 0 0 2
+line l 5 5 0 0 0 1
+mkedge e l -10 10
+plane p 0 0 1 0 0 1
+mkface f p -15 15 -15 15
+box b 8 8 8 5 5 5
+bclearobjects
+bcleartools
+baddobjects v e f b
+bfillds
+bbuild s1
+
+# second argument - compound of solid and face
+box b2 10 10 10
+bclearobjects
+bcleartools
+baddobjects f
+baddtools b2
+bfillds
+bbuild s2
+
+# only common operation should be allowed
+
+bclearobjects
+bcleartools
+baddobjects s1
+baddtools s2
+bfillds
+
+if {[regexp "Error: Boolean operation of the given type is not allowed on the given inputs" [bbop r 0]]} {
+ puts "Error: COMMON Operation must be allowed on any types of arguments"
+}
+
+foreach i {1 2 3} {
+ if {![regexp "Error: Boolean operation of the given type is not allowed on the given inputs" [bbop r $i]]} {
+ puts "Error: Operation must not be allowed"
+ }
+}