From: emv Date: Thu, 15 Mar 2018 14:02:46 +0000 (+0300) Subject: 0029580: Regression: invalid result of BOP Fuse X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=f3ba48646fe10ad9768082c6801230ec64158c61;p=occt-copy.git 0029580: Regression: invalid result of BOP Fuse Boolean Operation - avoid creation of INTERNAL solid from unclassified faces in Solid Builder algorithm. Instead warn the user that some of the faces have been unclassified and not used for solids creation. Adjustment of the test cases. Test cases for the issue. --- diff --git a/dox/dev_guides/upgrade/upgrade.md b/dox/dev_guides/upgrade/upgrade.md index 9199f96304..8e13457e24 100644 --- a/dox/dev_guides/upgrade/upgrade.md +++ b/dox/dev_guides/upgrade/upgrade.md @@ -1464,3 +1464,13 @@ The following obsolete features have been removed: @subsection upgrade_730_BOPAlgo_Section Changes in BOPAlgo_Section The public method *BuildSection()* in the class *BOPAlgo_Section* has became protected. The methods *Perform()* or *PerformWithFiller()* should be called for construction of the result of SECTION operation. + +@subsection upgrade_730_BuilderSolid Boolean Operations - Solid Builder algorithm + +Previously, the unclassified faces of *BOPAlgo_BuilderSolid* algorithm (the faces which have not been used for solids creation and located outside of all created solids) have been used to form an additional solid (not closed one) with INTERNAL orientation. +Since new version, these unclassified faces are no longer added into resulting solids. Instead, the @ref occt_algorithms_ers "warning" containing these faces appears. + +The following public methods of the *BOPAlgo_BuilderSolid* class have been removed as excessive: +* void SetSolid(const TopoDS_Solid& theSolid); +* const TopoDS_Solid& Solid() const; + diff --git a/src/BOPAlgo/BOPAlgo.msg b/src/BOPAlgo/BOPAlgo.msg index 673a39ec42..d89a53c332 100644 --- a/src/BOPAlgo/BOPAlgo.msg +++ b/src/BOPAlgo/BOPAlgo.msg @@ -76,3 +76,6 @@ Warning: Building 2D curve of edge on face has failed .BOPAlgo_AlertAcquiredSelfIntersection Warning: Some sub-shapes of some of the argument become connected through other shapes and the argument became self-interfered + +.BOPAlgo_AlertSolidBuilderUnusedFaces +Warning: Some of the faces passed to the Solid Builder algorithm have not been classified and not used for solids creation diff --git a/src/BOPAlgo/BOPAlgo_Alerts.hxx b/src/BOPAlgo/BOPAlgo_Alerts.hxx index 04ce9c7b4f..05fffbce8b 100644 --- a/src/BOPAlgo/BOPAlgo_Alerts.hxx +++ b/src/BOPAlgo/BOPAlgo_Alerts.hxx @@ -88,4 +88,8 @@ DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertBuildingPCurveFailed) //! other shapes and the argument became self-interfered DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertAcquiredSelfIntersection) +//! Some of the faces passed to the Solid Builder algorithm have not been classified +//! and not used for solids creation +DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertSolidBuilderUnusedFaces) + #endif // _BOPAlgo_Alerts_HeaderFile diff --git a/src/BOPAlgo/BOPAlgo_BOP.cxx b/src/BOPAlgo/BOPAlgo_BOP.cxx index 8889480015..13933957a3 100644 --- a/src/BOPAlgo/BOPAlgo_BOP.cxx +++ b/src/BOPAlgo/BOPAlgo_BOP.cxx @@ -1058,16 +1058,19 @@ void BOPAlgo_BOP::BuildSolid() BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC); if (aSFS.Extent()) { // Build solids from set of faces - BOPAlgo_BuilderSolid aSB; - aSB.SetContext(myContext); - aSB.SetShapes(aSFS); - aSB.Perform(); - if (aSB.HasErrors()) { + BOPAlgo_BuilderSolid aBS; + aBS.SetContext(myContext); + aBS.SetShapes(aSFS); + aBS.Perform(); + if (aBS.HasErrors()) { AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed return; } + + myReport->Merge(aBS.GetReport()); + // new solids - const BOPCol_ListOfShape& aLSR = aSB.Areas(); + const BOPCol_ListOfShape& aLSR = aBS.Areas(); // // add new solids to result aItLS.Initialize(aLSR); diff --git a/src/BOPAlgo/BOPAlgo_BOPAlgo_msg.pxx b/src/BOPAlgo/BOPAlgo_BOPAlgo_msg.pxx index feec778809..adb19e9e98 100644 --- a/src/BOPAlgo/BOPAlgo_BOPAlgo_msg.pxx +++ b/src/BOPAlgo/BOPAlgo_BOPAlgo_msg.pxx @@ -78,4 +78,7 @@ static const char BOPAlgo_BOPAlgo_msg[] = "Warning: Building 2D curve of edge on face has failed\n" "\n" ".BOPAlgo_AlertAcquiredSelfIntersection\n" - "Warning: Some sub-shapes of some of the argument become connected through other shapes and the argument became self-interfered\n"; + "Warning: Some sub-shapes of some of the argument become connected through other shapes and the argument became self-interfered\n" + "\n" + ".BOPAlgo_AlertSolidBuilderUnusedFaces\n" + "Warning: Some of the faces passed to the Solid Builder algorithm have not been classified and not used for solids creation\n"; diff --git a/src/BOPAlgo/BOPAlgo_BuilderSolid.cxx b/src/BOPAlgo/BOPAlgo_BuilderSolid.cxx index c56c6b9647..2d59eac595 100644 --- a/src/BOPAlgo/BOPAlgo_BuilderSolid.cxx +++ b/src/BOPAlgo/BOPAlgo_BuilderSolid.cxx @@ -106,22 +106,6 @@ BOPAlgo_BuilderSolid::~BOPAlgo_BuilderSolid() { } //======================================================================= -//function : SetSolid -//purpose : -//======================================================================= -void BOPAlgo_BuilderSolid::SetSolid(const TopoDS_Solid& aS) -{ - mySolid=aS; -} -//======================================================================= -//function : Solid -//purpose : -//======================================================================= -const TopoDS_Solid& BOPAlgo_BuilderSolid::Solid()const -{ - return mySolid; -} -//======================================================================= //function : Perform //purpose : //======================================================================= @@ -677,8 +661,10 @@ void BOPAlgo_BuilderSolid::PerformInternalShapes() } } - // Make solid from the unused faces (if any) + // Find all unclassified faces and warn the user about them. + // Do not put such faces into result as they will form not closed solid. BOPCol_IndexedMapOfShape aMFUnUsed; + for (i = 1; i <= aNbF; ++i) { const TopoDS_Shape& aF = aMFs(i); @@ -688,24 +674,21 @@ void BOPAlgo_BuilderSolid::PerformInternalShapes() if (aMFUnUsed.Extent()) { - TopoDS_Solid aSolid; - aBB.MakeSolid(aSolid); - // BOPCol_ListOfShape aLSI; MakeInternalShells(aMFUnUsed, aLSI); - // - aItLS.Initialize(aLSI); - for (; aItLS.More(); aItLS.Next()) - { - const TopoDS_Shape& aSI = aItLS.Value(); - aBB.Add (aSolid, aSI); - Bnd_Box aBox; - BRepBndLib::Add(aSolid, aBox); - myBoxes.Bind(aSolid, aBox); + TopoDS_Shape aWShape; + if (aLSI.Extent() == 1) + aWShape = aLSI.First(); + else + { + aBB.MakeCompound(TopoDS::Compound(aWShape)); + aItLS.Initialize(aLSI); + for (; aItLS.More(); aItLS.Next()) + aBB.Add(aWShape, aItLS.Value()); } - myAreas.Append(aSolid); - } + + AddWarning(new BOPAlgo_AlertSolidBuilderUnusedFaces(aWShape)); } } //======================================================================= //function : MakeInternalShells diff --git a/src/BOPAlgo/BOPAlgo_BuilderSolid.hxx b/src/BOPAlgo/BOPAlgo_BuilderSolid.hxx index 3bb4f440bb..bb583f2cac 100644 --- a/src/BOPAlgo/BOPAlgo_BuilderSolid.hxx +++ b/src/BOPAlgo/BOPAlgo_BuilderSolid.hxx @@ -22,64 +22,115 @@ #include #include -#include #include #include #include -class TopoDS_Solid; -//! The algorithm to build solids from set of faces +//! Solid Builder is the algorithm for building solids from set of faces. +//! The given faces should be non-intersecting, i.e. all coinciding parts +//! of the faces should be shared among them. +//! +//! The algorithm performs the following steps to build the solids: +//! 1. Find: +//! - faces orientated INTERNAL; +//! - alone faces given twice with different orientation; +//! 2. Build all possible closed shells from the rest of the faces +//! (*BOPAlgo_ShellSplitter* is used for that); +//! 3. Classify the obtained shells on the Holes and Growths; +//! 4. Build solids from the Growth shells, put Hole shells into closest Growth solids; +//! 5. Classify all unused faces relatively created solids and put them as internal +//! shells into the closest solids; +//! 6. Find all unclassified faces, i.e. faces outside of all created solids, +//! make internal shells from them and put these shells into a warning. +//! +//! It is possible to avoid all internal shells in the resulting solids. +//! For that it is necessary to use the method SetAvoidInternalShapes(true) +//! of the base class. In this case the steps 5 and 6 will not be performed at all. +//! +//! The algorithm may return the following warnings: +//! - *BOPAlgo_AlertShellSplitterFailed* in case the ShellSplitter algorithm has failed; +//! - *BOPAlgo_AlertSolidBuilderUnusedFaces* in case there are some faces outside of +//! created solids left. +//! +//! Example of usage of the algorithm: +//! ~~~~ +//! const TopTools_ListOfShape& aFaces = ...; // Faces to build the solids +//! Standard_Boolean isAvoidInternals = ...; // Flag which defines whether to create the internal shells or not +//! BOPAlgo_BuilderSolid aBS; // Solid Builder tool +//! aBS.SetShapes(aFaces); // Set the faces +//! aBS.SetAvoidInternalShapes(isAvoidInternals); // Set the AvoidInternalShapesFlag +//! aBS.Perform(); // Perform the operation +//! if (!aBS.IsDone()) // Check for the errors +//! { +//! // error treatment +//! Standard_SStream aSStream; +//! aBS.DumpErrors(aSStream); +//! return; +//! } +//! if (aBS.HasWarnings()) // Check for the warnings +//! { +//! // warnings treatment +//! Standard_SStream aSStream; +//! aBS.DumpWarnings(aSStream); +//! } +//! +//! const TopTools_ListOfShape& aSolids = aBS.Areas(); // Obtaining the result solids +//! ~~~~ +//! class BOPAlgo_BuilderSolid : public BOPAlgo_BuilderArea { public: DEFINE_STANDARD_ALLOC - +public: //! @name Constructors + + //! Empty constructor Standard_EXPORT BOPAlgo_BuilderSolid(); -Standard_EXPORT virtual ~BOPAlgo_BuilderSolid(); - + Standard_EXPORT virtual ~BOPAlgo_BuilderSolid(); + + //! Constructor with allocator Standard_EXPORT BOPAlgo_BuilderSolid(const BOPCol_BaseAllocator& theAllocator); - - //! Sets the source solid - Standard_EXPORT void SetSolid (const TopoDS_Solid& theSolid); - - //! Returns the source solid - Standard_EXPORT const TopoDS_Solid& Solid() const; - - //! Performs the algorithm + +public: //! @name Performing the operation + + //! Performs the construction of the solids from the given faces Standard_EXPORT virtual void Perform() Standard_OVERRIDE; - //! Returns the map of solid/box pairs +public: //! @name Getting the bounding boxes of the created solids + + //! For classification purposes the algorithm builds the bounding boxes + //! for all created solids. This method returns the data map of solid - box pairs. const BOPCol_DataMapOfShapeBox& GetBoxesMap() const { return myBoxes; } -protected: - - //! Collect the faces that - //! a) are internal - //! b) are the same and have different orientation +protected: //! @name Protected methods performing the operation + + //! Collect the faces: + //! - with INTERNAL orientation; + //! - that are alone but given twice with different orientation. + //! These faces will be put into the map *myShapesToAvoid* and will be + //! avoided in shells construction, but will be classified later on. Standard_EXPORT virtual void PerformShapesToAvoid() Standard_OVERRIDE; - - //! Build draft shells - //! a)myLoops - draft shells that consist of - //! boundary faces - //! b)myLoopsInternal - draft shells that contains - //! inner faces - Standard_EXPORT virtual void PerformLoops() Standard_OVERRIDE; - - //! Build draft solids that contains boundary faces - Standard_EXPORT virtual void PerformAreas() Standard_OVERRIDE; - - //! Build finalized solids with internal shells - Standard_EXPORT virtual void PerformInternalShapes() Standard_OVERRIDE; + //! Build all possible closed shells from the given faces. + //! The method fills the following maps: + //! - myLoops - Created closed shells; + //! - myLoopsInternal - The shells created from unused faces. + Standard_EXPORT virtual void PerformLoops() Standard_OVERRIDE; - TopoDS_Solid mySolid; + //! Classifies the created shells on the Holes and Growths. + //! Creates the solids from the Growths shells. + //! Puts the Hole shells into the closest Growths solids. + Standard_EXPORT virtual void PerformAreas() Standard_OVERRIDE; + //! Classifies the unused faces relatively the created solids. + //! Puts the classified faces into the closest solids as internal shells. + //! Warns the user about unclassified faces if any. + Standard_EXPORT virtual void PerformInternalShapes() Standard_OVERRIDE; private: diff --git a/src/BOPAlgo/BOPAlgo_Builder_3.cxx b/src/BOPAlgo/BOPAlgo_Builder_3.cxx index e03cf01778..05014c68b3 100644 --- a/src/BOPAlgo/BOPAlgo_Builder_3.cxx +++ b/src/BOPAlgo/BOPAlgo_Builder_3.cxx @@ -333,10 +333,28 @@ void BOPAlgo_Builder::BuildDraftSolid(const TopoDS_Shape& theSolid, } //======================================================================= + +//======================================================================= +//class : BOPAlgo_SplitSolid +//purpose : Auxiliary class to extend the BOPAlgo_BuilderSolid with the solid to split +//======================================================================= +class BOPAlgo_SplitSolid : public BOPAlgo_BuilderSolid +{ +public: + //! Sets the solid + void SetSolid(const TopoDS_Solid& theSolid) { mySolid = theSolid; } + + //! Returns the solid + const TopoDS_Solid& Solid() const { return mySolid; } + +private: + TopoDS_Solid mySolid; //!< Solid to split +}; + // Vector of Solid Builders -typedef BOPCol_NCVector BOPAlgo_VectorOfBuilderSolid; +typedef BOPCol_NCVector BOPAlgo_VectorOfBuilderSolid; // Functors to split solids -typedef BOPCol_Functor BOPAlgo_BuilderSolidFunctor; // typedef BOPCol_CntMerge(aBS.GetReport()); } // // Add new solids to images map diff --git a/src/BOPAlgo/BOPAlgo_CellsBuilder.cxx b/src/BOPAlgo/BOPAlgo_CellsBuilder.cxx index e36405224d..4eae759a7c 100644 --- a/src/BOPAlgo/BOPAlgo_CellsBuilder.cxx +++ b/src/BOPAlgo/BOPAlgo_CellsBuilder.cxx @@ -887,6 +887,8 @@ Standard_Boolean BOPAlgo_CellsBuilder::RemoveInternals(const BOPCol_ListOfShape& continue; } // + myReport->Merge(aBS.GetReport()); + // TopoDS_Solid& aSNew = *(TopoDS_Solid*)&aBS.Areas().First(); // // put all internal parts into new solid diff --git a/src/BOPAlgo/BOPAlgo_MakerVolume.cxx b/src/BOPAlgo/BOPAlgo_MakerVolume.cxx index da912808b3..d2eb985d0d 100644 --- a/src/BOPAlgo/BOPAlgo_MakerVolume.cxx +++ b/src/BOPAlgo/BOPAlgo_MakerVolume.cxx @@ -255,7 +255,6 @@ void BOPAlgo_MakerVolume::BuildSolids(BOPCol_ListOfShape& theLSR) // BOPAlgo_BuilderSolid aBS; // - aBS.SetSolid(mySBox); aBS.SetShapes(myFaces); aBS.SetRunParallel(myRunParallel); aBS.SetAvoidInternalShapes(myAvoidInternalShapes); @@ -266,6 +265,8 @@ void BOPAlgo_MakerVolume::BuildSolids(BOPCol_ListOfShape& theLSR) return; } // + myReport->Merge(aBS.GetReport()); + // theLSR = aBS.Areas(); } diff --git a/src/BOPAlgo/BOPAlgo_Tools.cxx b/src/BOPAlgo/BOPAlgo_Tools.cxx index b3fde89676..38de815795 100644 --- a/src/BOPAlgo/BOPAlgo_Tools.cxx +++ b/src/BOPAlgo/BOPAlgo_Tools.cxx @@ -1505,8 +1505,8 @@ void BOPAlgo_FillIn3DParts::MakeConnexityBlock(const TopoDS_Face& theFStart, myItW.Initialize(aW); for (; myItW.More(); myItW.Next()) { - const TopoDS_Shape& aE = myItW.Value(); - if (theMEAvoid.Contains(aE)) + const TopoDS_Edge& aE = TopoDS::Edge(myItW.Value()); + if (theMEAvoid.Contains(aE) || BRep_Tool::Degenerated(aE)) { if (theFaceToClassify.IsNull()) theFaceToClassify = TopoDS::Face(aF); diff --git a/tests/boolean/bcut_complex/F2 b/tests/boolean/bcut_complex/F2 index 5ca5836f25..7aa2f6f0b7 100644 --- a/tests/boolean/bcut_complex/F2 +++ b/tests/boolean/bcut_complex/F2 @@ -1,12 +1,10 @@ # Original bug : buc60127 # Date : 18mar98 -puts "TODO #22911 ALL: Faulty shapes in variables faulty_1 to faulty_" -puts "TODO #22911 ALL: Error : The area of result shape is" +puts "TODO #22911 ALL: Error : The command is not valid. The area is 0." restore [locate_data_file buc60127-part.rle] part restore [locate_data_file buc60127-tool.rle] tool bcut result part tool checkprops result -s 0 -checkview -display result -2d -s -otherwise { part tool } -path ${imagedir}/${test_image}.png diff --git a/tests/bugs/modalg_6/bug26789_1 b/tests/bugs/modalg_6/bug26789_1 index c5dddec066..c1bb6f2b38 100644 --- a/tests/bugs/modalg_6/bug26789_1 +++ b/tests/bugs/modalg_6/bug26789_1 @@ -1,8 +1,6 @@ puts "TODO 0026789 ALL: Error : The area of result shape is" puts "TODO 0026789 ALL: Error : The volume of result shape is" -puts "TODO 0026789 ALL: Error : is WRONG because number of SOLID entities in shape" -puts "TODO 0026789 ALL: Error : is WRONG because number of SHELL entities in shape" -puts "TODO 0026789 ALL: Faulty shapes in variables faulty_" +puts "TODO 0026789 ALL: Error : is WRONG because number of" puts "========" puts "OCC26789" diff --git a/tests/bugs/modalg_7/bug25983 b/tests/bugs/modalg_7/bug25983 deleted file mode 100644 index 9eb515cdb2..0000000000 --- a/tests/bugs/modalg_7/bug25983 +++ /dev/null @@ -1,24 +0,0 @@ -puts "TODO OCC25983 ALL: Faulty shapes in variables faulty_1 to faulty_" - -puts "========" -puts "OCC25983" -puts "========" -puts "" -########################################## -# Fusion of sweep and its mirror invalid -########################################## - -restore [locate_data_file bug25983_deform-fusion1-tcl-BSpline.brep] BSpline -wire Knurling-0-spine BSpline -mksweep Knurling-0-spine -setsweep -FR -polyline DWire 0 0 0 1 -0.9999999999999998 0 1.0000000000000002 0.9999999999999998 0 0 0 0 -trotate DWire 0 0 0 1 0 0 134.99999999999693 -ttranslate DWire 9 0 0 -addsweep DWire -buildsweep Knurling -C -S -copy Knurling Clone -tmirror Clone 0 0 0 1 0 0 -bfuse result Knurling Clone - -checkshape result diff --git a/tests/bugs/modalg_7/bug25983_1 b/tests/bugs/modalg_7/bug25983_1 new file mode 100644 index 0000000000..9d5204f1a7 --- /dev/null +++ b/tests/bugs/modalg_7/bug25983_1 @@ -0,0 +1,30 @@ +puts "TODO OCC25983 ALL: Error : is WRONG because number of" +puts "TODO OCC25983 ALL: Error : The area of result shape is" +puts "TODO OCC25983 ALL: Error : The volume of result shape is" + +puts "========" +puts "OCC25983" +puts "========" +puts "" +########################################## +# Fusion of sweep and its mirror invalid +########################################## + +restore [locate_data_file bug25983_deform-fusion1-tcl-BSpline.brep] BSpline +wire Knurling-0-spine BSpline +mksweep Knurling-0-spine +setsweep -FR +polyline DWire 0 0 0 1 -0.9999999999999998 0 1.0000000000000002 0.9999999999999998 0 0 0 0 +trotate DWire 0 0 0 1 0 0 134.99999999999693 +ttranslate DWire 9 0 0 +addsweep DWire +buildsweep Knurling -C -S +copy Knurling Clone +tmirror Clone 0 0 0 1 0 0 +bfuse result Knurling Clone + +checkshape result +checknbshapes result -wire 24 -face 24 -shell 1 -solid 1 +checkprops result -s 262.476 -v 54.0383 + +checkview -display result -2d -path ${imagedir}/${test_image}.png diff --git a/tests/bugs/modalg_7/bug25983_2 b/tests/bugs/modalg_7/bug25983_2 new file mode 100644 index 0000000000..23fad7968d --- /dev/null +++ b/tests/bugs/modalg_7/bug25983_2 @@ -0,0 +1,28 @@ +puts "========" +puts "OCC25983" +puts "========" +puts "" +########################################## +# Fusion of sweep and its mirror invalid +########################################## + +restore [locate_data_file bug25983_deform-fusion1-tcl-BSpline.brep] BSpline +wire Knurling-0-spine BSpline +mksweep Knurling-0-spine +setsweep -FR +polyline DWire 0 0 0 1 -0.9999999999999998 0 1.0000000000000002 0.9999999999999998 0 0 0 0 +trotate DWire 0 0 0 1 0 0 134.99999999999693 +ttranslate DWire 9 0 0 +addsweep DWire +buildsweep Knurling -C -S +copy Knurling Clone +tmirror Clone 0 0 0 1 0 0 + +bfuzzyvalue 1.e-3 +bfuse result Knurling Clone + +checkshape result +checknbshapes result -wire 24 -face 24 -shell 1 -solid 1 +checkprops result -s 262.476 -v 54.0383 + +checkview -display result -2d -path ${imagedir}/${test_image}.png diff --git a/tests/bugs/modalg_7/bug29580_1 b/tests/bugs/modalg_7/bug29580_1 new file mode 100644 index 0000000000..5592ec77f6 --- /dev/null +++ b/tests/bugs/modalg_7/bug29580_1 @@ -0,0 +1,18 @@ +puts "========" +puts "OCC29580" +puts "========" +puts "" +################################################# +# Regression: invalid result of BOP Fuse +################################################# + +restore [locate_data_file bug29580_Cylinder.brep] b1 +restore [locate_data_file bug29580_Solid.brep] b2 + +bfuse result b1 b2 + +checkshape result +checknbshapes result -wire 14 -face 13 -shell 1 -solid 1 +checkprops result -s 865.851 -v 1622.19 + +checkview -display result -2d -path ${imagedir}/${test_image}.png diff --git a/tests/bugs/modalg_7/bug29580_2 b/tests/bugs/modalg_7/bug29580_2 new file mode 100644 index 0000000000..2b60f9a310 --- /dev/null +++ b/tests/bugs/modalg_7/bug29580_2 @@ -0,0 +1,37 @@ +puts "========" +puts "OCC29580" +puts "========" +puts "" +################################################# +# Regression: invalid result of BOP Fuse +################################################# + + +circle c1 0 -5 0 1 0 0 10 +circle c2 0 5 0 1 0 0 10 +mkedge e1 c1 +mkedge e2 c2 +wire w1 e1 +wire w2 e2 +mkplane f1 w1 +mkplane f2 w2 +bcut f12 f1 f2 +revol b1 f12 0 0 0 0 0 1 180 +ttranslate b1 0 31.358955689999998 0 + +plane pln 0 0 0 0 0 1 1.1102230246251565e-016 -1 0 +psphere b2 pln 8.6602540399999999 180 +ttranslate b2 0 31.358955689999998 0 + +bclearobjects +bcleartools +baddobjects b1 +baddtools b2 +bfillds +bbuild result + +checkshape result +checknbshapes result -vertex 4 -edge 14 -wire 10 -face 10 -shell 3 -solid 3 -t +checkprops result -s 3879.55 -v 6295.15 + +checkview -display result -2d -path ${imagedir}/${test_image}.png