+
+//==================================================================================================
+ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& theShape)
+{
+ ListOfShape aSubShapes;
+
+ if (!theShape->isCompound() && !theShape->isCompSolid() &&
+ !theShape->isShell() && !theShape->isWire()) {
+ return aSubShapes;
+ }
+
+ for (GeomAPI_ShapeIterator anIt(theShape); anIt.more(); anIt.next()) {
+ GeomShapePtr aSubShape = anIt.current();
+ if (aSubShape->isVertex() || aSubShape->isEdge() ||
+ aSubShape->isFace() || aSubShape->isSolid()) {
+ aSubShapes.push_back(aSubShape);
+ } else {
+ aSubShapes.splice(aSubShapes.end(), getLowLevelSubShapes(aSubShape));
+ }
+ }
+
+ return aSubShapes;
+}
+
+//==================================================================================================
+static void getMinMaxPointsOnLine(const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
+ const gp_Dir theDir,
+ double& theMin, double& theMax)
+{
+ theMin = RealLast();
+ theMax = RealFirst();
+ // Project bounding points on theDir
+ for (std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator
+ aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) {
+ const gp_Pnt& aPnt = (*aPointsIt)->impl<gp_Pnt>();
+ gp_Dir aPntDir (aPnt.XYZ());
+ Standard_Real proj = (theDir*aPntDir) * aPnt.XYZ().Modulus();
+ if (proj < theMin) theMin = proj;
+ if (proj > theMax) theMax = proj;
+ }
+}
+
+//==================================================================================================
+void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects,
+ const ListOfShape& theBaseShapes,
+ const std::shared_ptr<GeomAPI_Dir> theDir,
+ double& theToSize, double& theFromSize)
+{
+ // Bounding box of objects
+ std::list<std::shared_ptr<GeomAPI_Pnt> > aBndObjs =
+ GeomAlgoAPI_ShapeTools::getBoundingBox(theObjects);
+ if (aBndObjs.size() != 8) {
+ return;
+ }
+
+ // the value to enlarge the bounding box of each object to make the extruded shape
+ // a little bit larger than overall objects to get the correct result of Boolean CUT operation
+ double anEnlargement = 0.1 * aBndObjs.front()->distance(aBndObjs.back());
+
+ // Prism direction
+ if (theDir.get()) {
+ // One direction for all prisms
+ gp_Dir aDir = theDir->impl<gp_Dir>();
+
+ // Bounding box of the base
+ std::list<std::shared_ptr<GeomAPI_Pnt> > aBndBases =
+ GeomAlgoAPI_ShapeTools::getBoundingBox(theBaseShapes);
+ if (aBndBases.size() != 8) {
+ return;
+ }
+
+ // Objects bounds
+ Standard_Real lowBnd, upperBnd;
+ getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd);
+
+ // Base bounds
+ Standard_Real lowBase, upperBase;
+ getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase);
+
+ // ----------.-----.---------.--------------.-----------> theDir
+ // lowBnd lowBase upperBase upperBnd
+
+ theToSize = upperBnd - lowBase;
+ theFromSize = upperBase - lowBnd;
+ } else {
+ // Direction is a normal to each base shape (different normals to bases)
+ // So we calculate own sizes for each base shape
+ theToSize = 0.0;
+ theFromSize = 0.0;
+
+ for (ListOfShape::const_iterator anIt = theBaseShapes.begin();
+ anIt != theBaseShapes.end(); ++anIt) {
+ const GeomShapePtr& aBaseShape_i = (*anIt);
+ ListOfShape aBaseShapes_i;
+ aBaseShapes_i.push_back(aBaseShape_i);
+
+ // Bounding box of the base
+ std::list<std::shared_ptr<GeomAPI_Pnt> > aBndBases =
+ GeomAlgoAPI_ShapeTools::getBoundingBox(aBaseShapes_i, anEnlargement);
+ if (aBndBases.size() != 8) {
+ return;
+ }
+
+ // Direction (normal to aBaseShapes_i)
+ // Code like in GeomAlgoAPI_Prism
+ gp_Dir aDir;
+ const TopoDS_Shape& aBaseShape = aBaseShape_i->impl<TopoDS_Shape>();
+ BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
+ if (aFindPlane.Found() == Standard_True) {
+ Handle(Geom_Plane) aPlane;
+ if (aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) {
+ TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
+ const TopoDS_Shape& aFace = anExp.Current();
+ Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace));
+ if (aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
+ Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
+ Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
+ aSurface = aTrimSurface->BasisSurface();
+ }
+ if (aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
+ return;
+ }
+ aPlane = Handle(Geom_Plane)::DownCast(aSurface);
+ } else {
+ aPlane = aFindPlane.Plane();
+ }
+ aDir = aPlane->Axis().Direction();
+ } else {
+ return;
+ }
+
+ // Objects bounds
+ Standard_Real lowBnd, upperBnd;
+ getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd);
+
+ // Base bounds
+ Standard_Real lowBase, upperBase;
+ getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase);
+
+ // ----------.-----.---------.--------------.-----------> theDir
+ // lowBnd lowBase upperBase upperBnd
+
+ double aToSize_i = upperBnd - lowBase;
+ double aFromSize_i = upperBase - lowBnd;
+
+ if (aToSize_i > theToSize) theToSize = aToSize_i;
+ if (aFromSize_i > theFromSize) theFromSize = aFromSize_i;
+ }
+ }
+}