Salome HOME
faec830812c045e743a625ffbed9ddc92d8fa8c8
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Prism.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "GeomAlgoAPI_Prism.h"
21
22 #include <GeomAPI_Ax1.h>
23 #include <GeomAPI_Dir.h>
24 #include <GeomAPI_Face.h>
25 #include <GeomAPI_Pln.h>
26 #include <GeomAPI_Pnt.h>
27 #include <GeomAPI_ShapeExplorer.h>
28 #include <GeomAPI_XYZ.h>
29
30 #include <GeomAlgoAPI_CompoundBuilder.h>
31 #include <GeomAlgoAPI_DFLoader.h>
32 #include <GeomAlgoAPI_FaceBuilder.h>
33 #include <GeomAlgoAPI_Offset.h>
34 #include <GeomAlgoAPI_Partition.h>
35 #include <GeomAlgoAPI_ShapeTools.h>
36 #include <GeomAlgoAPI_Translation.h>
37
38 #include <Bnd_Box.hxx>
39 #include <BRep_Builder.hxx>
40 #include <BRepAlgoAPI_Cut.hxx>
41 #include <BRepBndLib.hxx>
42 #include <BRepBuilderAPI_FindPlane.hxx>
43 #include <BRepBuilderAPI_Transform.hxx>
44 #include <BRepTools.hxx>
45 #include <Geom_Curve.hxx>
46 #include <Geom2d_Curve.hxx>
47 #include <BRepLib_CheckCurveOnSurface.hxx>
48 #include <BRepPrimAPI_MakePrism.hxx>
49 #include <Geom_Plane.hxx>
50 #include <Geom_RectangularTrimmedSurface.hxx>
51 #include <gp_Pln.hxx>
52 #include <IntAna_IntConicQuad.hxx>
53 #include <IntAna_Quadric.hxx>
54 #include <IntTools_Context.hxx>
55 #include <TopExp_Explorer.hxx>
56 #include <TopoDS.hxx>
57 #include <TopoDS_Edge.hxx>
58 #include <TopoDS_Shell.hxx>
59 #include <TopoDS_Solid.hxx>
60 #include <TopTools_ListIteratorOfListOfShape.hxx>
61
62
63 /// Expand planar face to cover the bounding box if theOriginalShape is planar.
64 /// Otherwise, return the same shape;
65 static GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
66                                     const Bnd_Box& theBaseShapeBB);
67
68 /// Build offset for the given shape.
69 /// If the offset algorithm failed, translate the shape along the direction.
70 static GeomShapePtr buildOffset(const GeomShapePtr& theShape,
71                                 const double theOffset,
72                                 const GeomDirPtr theDirection,
73                                 GeomAlgoAPI_MakeShapeList& theMakeShapeList);
74
75 /// Collect base faces of the prism.
76 static void collectPrismBases(const TopoDS_Shape& theBaseShape,
77                               BRepPrimAPI_MakePrism& thePrismAlgo,
78                               ListOfShape& theBoundaries,
79                               const GeomAPI_Shape::ShapeType theTypeToExp);
80
81 /// Collect all solids which contain boundaries but do not contain bases of prism.
82 static GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
83                                    const ListOfShape& theBoundaries,
84                                    const ListOfShape& theShapesToExclude,
85                                    const GeomAPI_Shape::ShapeType theTypeToExp);
86
87 static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
88                                    const TopoDS_Shape& theBase,
89                                    const TopAbs_ShapeEnum theType,
90                                    BRepPrimAPI_MakePrism* thePrismBuilder);
91
92 static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
93                                    const TopoDS_Shape& theResult,
94                                    const TopAbs_ShapeEnum theType,
95                                    const TopoDS_Face& theToFace,
96                                    const TopoDS_Face& theFromFace);
97
98 static GeomShapePtr toShape(const TopoDS_Shape& theShape)
99 {
100   GeomShapePtr aShape(new GeomAPI_Shape());
101   aShape->setImpl(new TopoDS_Shape(theShape));
102   return aShape;
103 }
104
105
106 //==================================================================================================
107 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
108                                      const GeomDirPtr   theDirection,
109                                      const GeomShapePtr theToShape,
110                                      const double       theToSize,
111                                      const GeomShapePtr theFromShape,
112                                      const double       theFromSize)
113 {
114   if(!theBaseShape.get() ||
115     (((!theFromShape.get() && !theToShape.get()) ||
116     (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape)))
117     && (theFromSize == -theToSize))) {
118     return;
119   }
120
121   // Getting base shape.
122   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
123   GeomAPI_Shape::ShapeType aShapeTypeToExp;
124   switch(aBaseShape.ShapeType()) {
125     case TopAbs_VERTEX:
126       aShapeTypeToExp = GeomAPI_Shape::VERTEX;
127       break;
128     case TopAbs_EDGE:
129     case TopAbs_WIRE:
130       aShapeTypeToExp = GeomAPI_Shape::EDGE;
131       break;
132     case TopAbs_FACE:
133     case TopAbs_SHELL:
134       aShapeTypeToExp = GeomAPI_Shape::FACE;
135       break;
136     case TopAbs_COMPOUND:
137       aShapeTypeToExp = GeomAPI_Shape::COMPOUND;
138       break;
139     default:
140       return;
141   }
142
143   // Getting direction.
144   gp_Vec aBaseVec;
145   std::shared_ptr<GeomAPI_Pnt> aBaseLoc;
146   std::shared_ptr<GeomAPI_Dir> aBaseDir;
147   BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
148   if(aFindPlane.Found() == Standard_True)
149   {
150     Handle(Geom_Plane) aPlane;
151     if(aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) {
152       TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
153       const TopoDS_Shape& aFace = anExp.Current();
154       Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace));
155       if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
156         Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
157           Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
158         aSurface = aTrimSurface->BasisSurface();
159       }
160       if(aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
161         return;
162       }
163       aPlane = Handle(Geom_Plane)::DownCast(aSurface);
164     } else {
165       aPlane = aFindPlane.Plane();
166     }
167     gp_Pnt aLoc = aPlane->Axis().Location();
168     aBaseVec = aPlane->Axis().Direction();
169     aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
170     aBaseDir.reset(new GeomAPI_Dir(aBaseVec.X(), aBaseVec.Y(), aBaseVec.Z()));
171   }
172   else if (theDirection.get())
173   {
174     aBaseDir = theDirection;
175     aBaseVec = theDirection->impl<gp_Dir>();
176   }
177   else
178   {
179     return;
180   }
181
182   if(!aBaseLoc.get()) {
183     gp_Pnt aLoc;
184     gp_XYZ aDirXYZ = aBaseVec.XYZ();
185     Standard_Real aMinParam = Precision::Infinite();
186     for(TopExp_Explorer anExp(aBaseShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) {
187       const TopoDS_Shape& aVertex = anExp.Current();
188       gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
189       double aParam = aDirXYZ.Dot(aPnt.XYZ());
190       if(aParam < aMinParam) {
191         aMinParam = aParam;
192         aLoc = aPnt;
193       }
194     }
195     aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
196   }
197
198   gp_Vec anExtVec;
199   std::shared_ptr<GeomAPI_Dir> anExtDir;
200   if (theDirection.get())
201   {
202     anExtDir = theDirection;
203     anExtVec = theDirection->impl<gp_Dir>();
204   }
205   else
206   {
207     anExtDir = aBaseDir;
208     anExtVec = aBaseDir->impl<gp_Dir>();
209   }
210
211
212   TopoDS_Shape aResult;
213   const bool isBoundingShapesSet = theFromShape.get() || theToShape.get();
214   if(!isBoundingShapesSet) {
215     buildBySizes(theBaseShape, anExtDir, theToSize, theFromSize, aShapeTypeToExp);
216   } else {
217     GeomShapePtr aBasePlane = GeomAlgoAPI_FaceBuilder::squareFace(aBaseLoc, aBaseDir, 100.0);
218
219     GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
220     GeomShapePtr aBoundingToShape   = theToShape   ? theToShape   : aBasePlane;
221
222     bool isFromShapePlanar = aBoundingFromShape->isPlanar();
223     bool isToShapePlanar   = aBoundingToShape->isPlanar();
224
225     // Set signs of offsets if both bounding shapes are planar
226     if (isFromShapePlanar && isToShapePlanar) {
227       std::shared_ptr<GeomAPI_Pln> aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane();
228       std::shared_ptr<GeomAPI_Pln> aToPln = GeomAPI_Face(aBoundingToShape).getPlane();
229       buildByPlanes(theBaseShape, anExtDir,
230                     aToPln, theToSize,
231                     aFromPln, theFromSize,
232                     aShapeTypeToExp);
233     }
234     else {
235       buildByFaces(theBaseShape, anExtDir,
236                    aBoundingToShape, theToSize, isToShapePlanar,
237                    aBoundingFromShape, theFromSize, isFromShapePlanar,
238                    aShapeTypeToExp);
239     }
240   }
241 }
242
243 //==================================================================================================
244 void GeomAlgoAPI_Prism::buildBySizes(const GeomShapePtr             theBaseShape,
245                                      const GeomDirPtr               theDirection,
246                                      const double                   theToSize,
247                                      const double                   theFromSize,
248                                      const GeomAPI_Shape::ShapeType theTypeToExp)
249 {
250   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
251   gp_Vec anExtVec = theDirection->impl<gp_Dir>();
252
253   // Moving base shape.
254   gp_Trsf aTrsf;
255   aTrsf.SetTranslation(anExtVec * -theFromSize);
256   BRepBuilderAPI_Transform* aTransformBuilder =
257       new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
258   if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
259     return;
260   }
261   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
262       new GeomAlgoAPI_MakeShape(aTransformBuilder)));
263   TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
264
265   // Making prism.
266   BRepPrimAPI_MakePrism* aPrismBuilder =
267       new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * (theFromSize + theToSize));
268   if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
269     return;
270   }
271   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
272       new GeomAlgoAPI_MakeShape(aPrismBuilder)));
273   TopoDS_Shape aResult = aPrismBuilder->Shape();
274
275   // Setting naming.
276   if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
277     storeGenerationHistory(this, aMovedBase, TopAbs_EDGE, aPrismBuilder);
278     storeGenerationHistory(this, aMovedBase, TopAbs_FACE, aPrismBuilder);
279   } else {
280     storeGenerationHistory(this, aMovedBase, (TopAbs_ShapeEnum)theTypeToExp, aPrismBuilder);
281   }
282
283   // Setting result.
284   if (!aResult.IsNull()) {
285     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
286     this->setShape(toShape(aResult));
287     this->setDone(true);
288   }
289 }
290
291 //==================================================================================================
292 void GeomAlgoAPI_Prism::buildByPlanes(const GeomShapePtr             theBaseShape,
293                                       const GeomDirPtr               theDirection,
294                                       const GeomPlanePtr             theToPlane,
295                                       const double                   theToSize,
296                                       const GeomPlanePtr             theFromPlane,
297                                       const double                   theFromSize,
298                                       const GeomAPI_Shape::ShapeType theTypeToExp)
299 {
300   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
301   gp_Vec anExtVec = theDirection->impl<gp_Dir>();
302
303   // Moving prism bounding faces according to "from" and "to" sizes.
304   std::shared_ptr<GeomAPI_Pnt> aFromLoc = theFromPlane->location();
305   std::shared_ptr<GeomAPI_Dir> aFromDir = theFromPlane->direction();
306
307   std::shared_ptr<GeomAPI_Pnt> aToLoc = theToPlane->location();
308   std::shared_ptr<GeomAPI_Dir> aToDir = theToPlane->direction();
309
310   std::shared_ptr<GeomAPI_XYZ> anExtDir = theDirection->xyz();
311   bool aSign = aFromLoc->xyz()->dot(anExtDir) > aToLoc->xyz()->dot(anExtDir);
312
313   std::shared_ptr<GeomAPI_Pnt> aFromPnt(
314     new GeomAPI_Pnt(aFromLoc->xyz()->added(anExtDir->multiplied(
315                     aSign ? theFromSize : -theFromSize))));
316   GeomShapePtr aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
317
318   std::shared_ptr<GeomAPI_Pnt> aToPnt(
319     new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->multiplied(
320                     aSign ? -theToSize : theToSize))));
321   GeomShapePtr aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
322
323   // Getting bounding box for base shape.
324   Bnd_Box aBndBox;
325   BRepBndLib::Add(aBaseShape, aBndBox);
326   Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
327   Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
328   Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
329   gp_Pnt aPoints[8];
330   int aNum = 0;
331   for(int i = 0; i < 2; i++) {
332     for(int j = 0; j < 2; j++) {
333       for(int k = 0; k < 2; k++) {
334         aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
335         aNum++;
336       }
337     }
338   }
339
340   // Project points to bounding planes. Search max distance to them.
341   IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
342   IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
343   Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
344   for(int i = 0; i < 8; i++) {
345     gp_Lin aLine(aPoints[i], anExtVec);
346     IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
347     IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
348     if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
349       return;
350     }
351     const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
352     const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
353     if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
354       aMaxToDist = aPoints[i].Distance(aPntOnToFace);
355     }
356     if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
357       aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
358     }
359   }
360
361   // We added 1 just to be sure that prism is long enough for boolean operation.
362   double aPrismLength = aMaxToDist + aMaxFromDist + 1;
363
364   // Moving base shape.
365   gp_Trsf aTrsf;
366   aTrsf.SetTranslation(anExtVec * -aPrismLength);
367   BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
368   if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
369     return;
370   }
371   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
372     new GeomAlgoAPI_MakeShape(aTransformBuilder)));
373   TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
374
375   // Making prism.
376   BRepPrimAPI_MakePrism* aPrismBuilder =
377     new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
378   if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
379     return;
380   }
381   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
382     new GeomAlgoAPI_MakeShape(aPrismBuilder)));
383   TopoDS_Shape aResult = aPrismBuilder->Shape();
384
385   BRepBndLib::Add(aResult, aBndBox);
386   Standard_Real aBndBoxSize = aBndBox.CornerMin().Distance(aBndBox.CornerMax());
387
388   // Orienting bounding planes.
389   std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
390   const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
391   gp_Lin aLine(aCentrePnt, anExtVec);
392   IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
393   IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
394   Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
395   Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
396   static const double THE_FACE_SIZE_COEFF = 10.0;
397   if(aToParameter > aFromParameter) {
398     gp_Vec aVec = aToDir->impl<gp_Dir>();
399     if((aVec * anExtVec) > 0) {
400       aToDir->setImpl(new gp_Dir(aVec.Reversed()));
401       aBoundingToShape =
402         GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
403     }
404     aVec = aFromDir->impl<gp_Dir>();
405     if((aVec * anExtVec) < 0) {
406       aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
407       aBoundingFromShape =
408         GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
409     }
410   } else {
411     gp_Vec aVec = aToDir->impl<gp_Dir>();
412     if((aVec * anExtVec) < 0) {
413       aToDir->setImpl(new gp_Dir(aVec.Reversed()));
414       aBoundingToShape =
415         GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
416     }
417     aVec = aFromDir->impl<gp_Dir>();
418     if((aVec * anExtVec) > 0) {
419       aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
420       aBoundingFromShape =
421         GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
422     }
423   }
424
425   // bounding planes
426   const TopoDS_Shape& aToShape   = aBoundingToShape->impl<TopoDS_Shape>();
427   const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
428   TopoDS_Face aToFace   = TopoDS::Face(aToShape);
429   TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
430
431   // Solid based on "To" bounding plane
432   gp_Vec aNormal = aToDir->impl<gp_Dir>();
433   BRepPrimAPI_MakePrism* aToPrismBuilder =
434       new BRepPrimAPI_MakePrism(aToShape, aNormal * (-2.0 * aBndBoxSize));
435   if (!aToPrismBuilder || !aToPrismBuilder->IsDone()) {
436     return;
437   }
438   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
439     new GeomAlgoAPI_MakeShape(aToPrismBuilder)));
440   TopoDS_Shape aToSolid = aToPrismBuilder->Shape();
441
442   // Cutting with to plane.
443   BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
444   aToCutBuilder->Build();
445   if(!aToCutBuilder->IsDone()) {
446     return;
447   }
448   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
449     new GeomAlgoAPI_MakeShape(aToCutBuilder)));
450   aResult = aToCutBuilder->Shape();
451   if(aResult.ShapeType() == TopAbs_COMPOUND) {
452     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
453   }
454   if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
455     TopTools_ListOfShape aPrismShapes = aToPrismBuilder->Modified(aToShape);
456     if (aPrismShapes.IsEmpty())
457       aPrismShapes.Append(aToShape);
458     for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
459       const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(anIt1.Value());
460       for (TopTools_ListIteratorOfListOfShape anIt2(aToShapes); anIt2.More(); anIt2.Next()) {
461         GeomShapePtr aGeomSh = toShape(anIt2.Value());
462         fixOrientation(aGeomSh);
463         this->addToShape(aGeomSh);
464       }
465     }
466   }
467
468   // Solid based on "From" bounding plane
469   aNormal = aFromDir->impl<gp_Dir>();
470   BRepPrimAPI_MakePrism* aFromPrismBuilder =
471       new BRepPrimAPI_MakePrism(aFromShape, aNormal * (-aBndBoxSize));
472   if (!aFromPrismBuilder || !aFromPrismBuilder->IsDone()) {
473     return;
474   }
475   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
476     new GeomAlgoAPI_MakeShape(aFromPrismBuilder)));
477   TopoDS_Shape aFromSolid = aFromPrismBuilder->Shape();
478
479   // Cutting with from plane.
480   BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
481   aFromCutBuilder->Build();
482   if(!aFromCutBuilder->IsDone()) {
483     return;
484   }
485   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
486     new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
487   aResult = aFromCutBuilder->Shape();
488   TopoDS_Iterator aCheckIt(aResult);
489   if(!aCheckIt.More()) {
490     return;
491   }
492   if(aResult.ShapeType() == TopAbs_COMPOUND) {
493     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
494   }
495   if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
496     TopTools_ListOfShape aPrismShapes = aFromPrismBuilder->Modified(aFromShape);
497     if (aPrismShapes.IsEmpty())
498       aPrismShapes.Append(aFromShape);
499     for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
500       const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(anIt1.Value());
501       for (TopTools_ListIteratorOfListOfShape anIt2(aFromShapes); anIt2.More(); anIt2.Next()) {
502         GeomShapePtr aGeomSh = toShape(anIt2.Value());
503         fixOrientation(aGeomSh);
504         this->addFromShape(aGeomSh);
505       }
506     }
507   }
508
509   // Naming for extrusion from vertex, edge.
510   if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
511     storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
512     storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
513   } else {
514     storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace);
515   }
516
517   if(aResult.ShapeType() == TopAbs_COMPOUND) {
518     GeomShapePtr aGeomShape = toShape(aResult);
519     ListOfShape aResults;
520     aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
521                                                         GeomAPI_Shape::COMPSOLID,
522                                                         aResults);
523     aResult = aGeomShape->impl<TopoDS_Shape>();
524   }
525
526   // Setting result.
527   if (!aResult.IsNull()) {
528     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
529     this->setShape(toShape(aResult));
530     this->setDone(true);
531   }
532 }
533
534 //==================================================================================================
535 void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr             theBaseShape,
536                                      const GeomDirPtr               theDirection,
537                                      const GeomShapePtr             theToShape,
538                                      const double                   theToSize,
539                                      const bool                     theToIsPlanar,
540                                      const GeomShapePtr             theFromShape,
541                                      const double                   theFromSize,
542                                      const bool                     theFromIsPlanar,
543                                      const GeomAPI_Shape::ShapeType theTypeToExp)
544 {
545   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
546   gp_Vec anExtVec = theDirection->impl<gp_Dir>();
547
548   // Moving prism bounding faces according to "from" and "to" sizes.
549   GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, theFromSize, theDirection, *this);
550   GeomShapePtr aBoundingToShape   = buildOffset(theToShape, theToSize, theDirection, *this);
551
552   // Bounding box for shapes used in prism building.
553   Bnd_Box aBndBox;
554   BRepBndLib::Add(aBaseShape, aBndBox);
555   BRepBndLib::Add(aBoundingFromShape->impl<TopoDS_Shape>(), aBndBox);
556   BRepBndLib::Add(aBoundingToShape->impl<TopoDS_Shape>(), aBndBox);
557   double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax());
558
559   // Prism building.
560   gp_Trsf aTrsf;
561   aTrsf.SetTranslation(anExtVec * -aPrismLength);
562   BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
563   if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
564     return;
565   }
566   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
567       new GeomAlgoAPI_MakeShape(aTransformBuilder)));
568   TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
569
570   // Making prism.
571   BRepPrimAPI_MakePrism* aPrismBuilder =
572       new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
573   if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
574     return;
575   }
576   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
577       new GeomAlgoAPI_MakeShape(aPrismBuilder)));
578
579   GeomShapePtr aResult = toShape(aPrismBuilder->Shape());
580
581   // Prism generatrix
582   ListOfShape aPrismBaseFaces;
583   collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp);
584
585   // Build planar faces intersecting the prism fully.
586   BRepBndLib::Add(aResult->impl<TopoDS_Shape>(), aBndBox);
587   aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox);
588   aBoundingToShape   = buildPlanarFace(aBoundingToShape, aBndBox);
589
590   // Perform partition.
591   ListOfShape anObjects, aTools;
592   anObjects.push_back(aResult);
593   aTools.push_back(aBoundingFromShape);
594   aTools.push_back(aBoundingToShape);
595
596   GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools));
597   if (!aPartition->isDone())
598     return;
599
600   this->appendAlgo(aPartition);
601
602   // Collect pieces of boundary shapes, split by Partition.
603   if (theFromIsPlanar) {
604     ListOfShape anImagesFrom;
605     aPartition->modified(aBoundingFromShape, anImagesFrom);
606     for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt)
607       addFromShape(*anIt);
608   }
609
610   if (theToIsPlanar) {
611     ListOfShape anImagesTo;
612     aPartition->modified(aBoundingToShape, anImagesTo);
613     for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt)
614       addToShape(*anIt);
615   }
616
617   // Collect results which have both boundaries, selected for extrusion,
618   // but which do not contain top and bottom faces of the prism
619   // (these faces are treated as infinitely distant).
620   aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp);
621   if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) {
622     ListOfShape aResults;
623     aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult,
624         theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID,
625         aResults);
626
627     if (aResults.size() > 1 &&
628        (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) ||
629         GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) {
630       // results shuold not have shared topology
631       aResult = GeomShapePtr();
632     }
633   }
634
635   if (aResult) {
636     this->setShape(aResult);
637     this->setDone(true);
638   }
639 }
640
641
642 // Auxilary functions:
643 //==================================================================================================
644 GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
645                              const Bnd_Box& theBaseShapeBB)
646 {
647   GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
648   if (!aPlane)
649     return theOriginalShape;
650
651   gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
652   gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
653   double aSize = aCornerMin.SquareDistance(aCornerMax);
654
655   gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
656
657   gp_Pnt aCurPnt;
658   for (int x = 0; x < 2; ++x) {
659     aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
660     for (int y = 0; y < 2; ++y) {
661       aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
662       for (int z = 0; z < 2; ++z) {
663         aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
664         double aDist = aCurPnt.SquareDistance(aLocation);
665         if (aDist > aSize)
666           aSize = aDist;
667       }
668     }
669   }
670
671   aSize = Sqrt(aSize);
672   return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
673 }
674
675 //==================================================================================================
676 GeomShapePtr buildOffset(const GeomShapePtr& theShape,
677                          const double theOffset,
678                          const GeomDirPtr theDirection,
679                          GeomAlgoAPI_MakeShapeList& theMakeShapeList)
680 {
681   if (Abs(theOffset) < Precision::Confusion())
682     return theShape; // no need zero offset
683
684   GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
685   if (!anAlgo->isDone()) {
686     // offset not done, perform translation
687     std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
688     anAxis->setDir(theDirection);
689     anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
690   }
691
692   GeomShapePtr aResult = theShape;
693   if (anAlgo->isDone()) {
694     theMakeShapeList.appendAlgo(anAlgo);
695     aResult = anAlgo->shape();
696   }
697   return aResult;
698 }
699
700 //==================================================================================================
701 void collectPrismBases(const TopoDS_Shape& theBaseShape,
702                        BRepPrimAPI_MakePrism& thePrismAlgo,
703                        ListOfShape& theBoundaries,
704                        const GeomAPI_Shape::ShapeType theTypeToExp)
705 {
706   for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
707        anExp.More(); anExp.Next()) {
708     theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
709     theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
710   }
711 }
712
713 //==================================================================================================
714 typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
715
716 bool isShapeApplicable(const GeomShapePtr& theSolid,
717                        const std::list<ListOfShape>& theShapesToExist,
718                        const SetOfShape& theShapesToExclude,
719                        const GeomAPI_Shape::ShapeType theTypeToExp)
720 {
721   SetOfShape aFaces;
722   for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
723        aFExp.more(); aFExp.next()) {
724     GeomShapePtr aCurrent = aFExp.current();
725     if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
726       return false;
727     aFaces.insert(aCurrent);
728   }
729
730   // check all faces are in solid
731   bool isApplicable = true;
732   for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
733        it1 != theShapesToExist.end() && isApplicable; ++it1) {
734     ListOfShape::const_iterator it2 = it1->begin();
735     for (; it2 != it1->end(); ++it2)
736       if (aFaces.find(*it2) != aFaces.end())
737         break;
738     isApplicable = it2 != it1->end();
739   }
740   return isApplicable;
741 }
742
743 void collectModified(const GeomMakeShapePtr& theOperation,
744                      const ListOfShape& theShapes,
745                      std::list<ListOfShape>& theModified)
746 {
747   for (ListOfShape::const_iterator anIt = theShapes.begin();
748        anIt != theShapes.end(); ++anIt) {
749     theModified.push_back(ListOfShape());
750     theOperation->modified(*anIt, theModified.back());
751     theOperation->generated(*anIt, theModified.back());
752     theModified.back().push_back(*anIt);
753   }
754 }
755
756 GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
757                             const ListOfShape& theBoundaries,
758                             const ListOfShape& theShapesToExclude,
759                             const GeomAPI_Shape::ShapeType theTypeToExp)
760 {
761   ListOfShape aResults;
762
763   // collect modified shapes
764   std::list<ListOfShape> aModifiedBoundaries;
765   collectModified(theOperation, theBoundaries, aModifiedBoundaries);
766
767   std::list<ListOfShape> aModifiedExclude;
768   collectModified(theOperation, theShapesToExclude, aModifiedExclude);
769   SetOfShape aTabooShapes;
770   for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
771        anIt != aModifiedExclude.end(); ++anIt)
772     aTabooShapes.insert(anIt->begin(), anIt->end());
773
774   // type of sub-shapes to explode
775   GeomAPI_Shape::ShapeType aSubshapeType;
776   switch (theTypeToExp) {
777   case GeomAPI_Shape::VERTEX:
778     aSubshapeType = GeomAPI_Shape::EDGE;
779     break;
780   case GeomAPI_Shape::EDGE:
781     aSubshapeType = GeomAPI_Shape::FACE;
782     break;
783   case GeomAPI_Shape::FACE:
784     aSubshapeType = GeomAPI_Shape::SOLID;
785     break;
786   default:
787     aSubshapeType = GeomAPI_Shape::COMPOUND;
788   }
789
790   // search applicable solids
791   GeomShapePtr anOperationResult = theOperation->shape();
792   for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
793         anExp.more(); anExp.next()) {
794     if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
795       aResults.push_back(anExp.current());
796   }
797
798   GeomShapePtr aResult;
799   if (aResults.size() == 1)
800     aResult = aResults.front();
801   else if (!aResults.empty())
802     aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
803   return aResult;
804 }
805
806 //==================================================================================================
807 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
808                             const TopoDS_Shape& theBase,
809                             const TopAbs_ShapeEnum theType,
810                             BRepPrimAPI_MakePrism* thePrismBuilder)
811 {
812   for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) {
813     const TopoDS_Shape& aShape = anExp.Current();
814     GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
815     aFromShape->setImpl(new TopoDS_Shape(thePrismBuilder->FirstShape(aShape)));
816     aToShape->setImpl(new TopoDS_Shape(thePrismBuilder->LastShape(aShape)));
817     thePrismAlgo->fixOrientation(aFromShape);
818     thePrismAlgo->fixOrientation(aToShape);
819     thePrismAlgo->addFromShape(aFromShape);
820     thePrismAlgo->addToShape(aToShape);
821   }
822 }
823
824 //==================================================================================================
825 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
826                             const TopoDS_Shape& theResult,
827                             const TopAbs_ShapeEnum theType,
828                             const TopoDS_Face& theToFace,
829                             const TopoDS_Face& theFromFace)
830 {
831   for(TopExp_Explorer anExp(theResult, theType); anExp.More(); anExp.Next()) {
832     const TopoDS_Shape& aShape = anExp.Current();
833     GeomShapePtr aGeomSh(new GeomAPI_Shape());
834     if(theType == TopAbs_VERTEX) {
835       gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
836       IntTools_Context anIntTools;
837       if(anIntTools.IsValidPointForFace(aPnt,
838           theToFace, Precision::Confusion()) == Standard_True) {
839         aGeomSh->setImpl(new TopoDS_Shape(aShape));
840         thePrismAlgo->fixOrientation(aGeomSh);
841         thePrismAlgo->addToShape(aGeomSh);
842       }
843       if(anIntTools.IsValidPointForFace(aPnt,
844           theFromFace, Precision::Confusion()) == Standard_True) {
845         aGeomSh->setImpl(new TopoDS_Shape(aShape));
846         thePrismAlgo->fixOrientation(aGeomSh);
847         thePrismAlgo->addFromShape(aGeomSh);
848       }
849     } else if(theType == TopAbs_EDGE) {
850       TopoDS_Edge anEdge = TopoDS::Edge(aShape);
851       BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, theToFace);
852       anEdgeCheck.Perform();
853       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
854         aGeomSh->setImpl(new TopoDS_Shape(aShape));
855         thePrismAlgo->fixOrientation(aGeomSh);
856         thePrismAlgo->addToShape(aGeomSh);
857       }
858       anEdgeCheck.Init(anEdge, theFromFace);
859       anEdgeCheck.Perform();
860       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
861         aGeomSh->setImpl(new TopoDS_Shape(aShape));
862         thePrismAlgo->fixOrientation(aGeomSh);
863         thePrismAlgo->addFromShape(aGeomSh);
864       }
865     } else {
866       break;
867     }
868   }
869 }