+//==================================================================================================
+GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
+ const Bnd_Box& theBaseShapeBB)
+{
+ GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
+ if (!aPlane)
+ return theOriginalShape;
+
+ gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
+ gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
+ double aSize = aCornerMin.SquareDistance(aCornerMax);
+
+ gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
+
+ gp_Pnt aCurPnt;
+ for (int x = 0; x < 2; ++x) {
+ aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
+ for (int y = 0; y < 2; ++y) {
+ aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
+ for (int z = 0; z < 2; ++z) {
+ aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
+ double aDist = aCurPnt.SquareDistance(aLocation);
+ if (aDist > aSize)
+ aSize = aDist;
+ }
+ }
+ }
+
+ aSize = Sqrt(aSize);
+ return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
+}
+
+//==================================================================================================
+GeomShapePtr buildOffset(const GeomShapePtr& theShape,
+ const double theOffset,
+ const GeomDirPtr theDirection,
+ GeomAlgoAPI_MakeShapeList& theMakeShapeList)
+{
+ if (Abs(theOffset) < Precision::Confusion())
+ return theShape; // no need zero offset
+
+ GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
+ if (!anAlgo->isDone()) {
+ // offset not done, perform translation
+ std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
+ anAxis->setDir(theDirection);
+ anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
+ }
+
+ GeomShapePtr aResult = theShape;
+ if (anAlgo->isDone()) {
+ theMakeShapeList.appendAlgo(anAlgo);
+ aResult = anAlgo->shape();
+ }
+ return aResult;
+}
+
+//==================================================================================================
+void collectPrismBases(const TopoDS_Shape& theBaseShape,
+ BRepPrimAPI_MakePrism& thePrismAlgo,
+ ListOfShape& theBoundaries,
+ const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+ for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
+ anExp.More(); anExp.Next()) {
+ theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
+ theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
+ }
+}
+
+//==================================================================================================
+typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
+
+bool isShapeApplicable(const GeomShapePtr& theSolid,
+ const std::list<ListOfShape>& theShapesToExist,
+ const SetOfShape& theShapesToExclude,
+ const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+ SetOfShape aFaces;
+ for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
+ aFExp.more(); aFExp.next()) {
+ GeomShapePtr aCurrent = aFExp.current();
+ if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
+ return false;
+ aFaces.insert(aCurrent);
+ }
+
+ // check all faces are in solid
+ bool isApplicable = true;
+ for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
+ it1 != theShapesToExist.end() && isApplicable; ++it1) {
+ ListOfShape::const_iterator it2 = it1->begin();
+ for (; it2 != it1->end(); ++it2)
+ if (aFaces.find(*it2) != aFaces.end())
+ break;
+ isApplicable = it2 != it1->end();
+ }
+ return isApplicable;
+}
+
+void collectModified(const GeomMakeShapePtr& theOperation,
+ const ListOfShape& theShapes,
+ std::list<ListOfShape>& theModified)
+{
+ for (ListOfShape::const_iterator anIt = theShapes.begin();
+ anIt != theShapes.end(); ++anIt) {
+ theModified.push_back(ListOfShape());
+ theOperation->modified(*anIt, theModified.back());
+ theOperation->generated(*anIt, theModified.back());
+ theModified.back().push_back(*anIt);
+ }
+}
+
+GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
+ const ListOfShape& theBoundaries,
+ const ListOfShape& theShapesToExclude,
+ const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+ ListOfShape aResults;
+
+ // collect modified shapes
+ std::list<ListOfShape> aModifiedBoundaries;
+ collectModified(theOperation, theBoundaries, aModifiedBoundaries);
+
+ std::list<ListOfShape> aModifiedExclude;
+ collectModified(theOperation, theShapesToExclude, aModifiedExclude);
+ SetOfShape aTabooShapes;
+ for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
+ anIt != aModifiedExclude.end(); ++anIt)
+ aTabooShapes.insert(anIt->begin(), anIt->end());
+
+ // type of sub-shapes to explode
+ GeomAPI_Shape::ShapeType aSubshapeType;
+ switch (theTypeToExp) {
+ case GeomAPI_Shape::VERTEX:
+ aSubshapeType = GeomAPI_Shape::EDGE;
+ break;
+ case GeomAPI_Shape::EDGE:
+ aSubshapeType = GeomAPI_Shape::FACE;
+ break;
+ case GeomAPI_Shape::FACE:
+ aSubshapeType = GeomAPI_Shape::SOLID;
+ break;
+ default:
+ aSubshapeType = GeomAPI_Shape::COMPOUND;
+ }
+
+ // search applicable solids
+ GeomShapePtr anOperationResult = theOperation->shape();
+ for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
+ anExp.more(); anExp.next()) {
+ if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
+ aResults.push_back(anExp.current());
+ }
+
+ GeomShapePtr aResult;
+ if (aResults.size() == 1)
+ aResult = aResults.front();
+ else if (!aResults.empty())
+ aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
+ return aResult;
+}
+