Salome HOME
Extrusion: fix error with offset plane. Make Extrusion CUT and FUSE be able to be...
[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
317   std::shared_ptr<GeomAPI_Pnt> aToPnt(
318     new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->multiplied(
319                     aSign ? -theToSize : theToSize))));
320
321   // Getting bounding box for base shape.
322   Bnd_Box aBndBox;
323   BRepBndLib::Add(aBaseShape, aBndBox);
324   Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
325   Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
326   Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
327   gp_Pnt aPoints[8];
328   int aNum = 0;
329   for(int i = 0; i < 2; i++) {
330     for(int j = 0; j < 2; j++) {
331       for(int k = 0; k < 2; k++) {
332         aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
333         aNum++;
334       }
335     }
336   }
337
338   // Project points to bounding planes. Search max distance to them.
339   IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
340   IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
341   Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
342   for(int i = 0; i < 8; i++) {
343     gp_Lin aLine(aPoints[i], anExtVec);
344     IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
345     IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
346     if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
347       return;
348     }
349     const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
350     const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
351     if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
352       aMaxToDist = aPoints[i].Distance(aPntOnToFace);
353     }
354     if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
355       aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
356     }
357   }
358
359   // We added 1 just to be sure that prism is long enough for boolean operation.
360   double aPrismLength = aMaxToDist + aMaxFromDist + 1;
361
362   // Moving base shape.
363   gp_Trsf aTrsf;
364   aTrsf.SetTranslation(anExtVec * -aPrismLength);
365   BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
366   if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
367     return;
368   }
369   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
370     new GeomAlgoAPI_MakeShape(aTransformBuilder)));
371   TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
372
373   // Making prism.
374   BRepPrimAPI_MakePrism* aPrismBuilder =
375     new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
376   if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
377     return;
378   }
379   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
380     new GeomAlgoAPI_MakeShape(aPrismBuilder)));
381   TopoDS_Shape aResult = aPrismBuilder->Shape();
382
383   BRepBndLib::Add(aResult, aBndBox);
384   Standard_Real aBndBoxSize = aBndBox.CornerMin().Distance(aBndBox.CornerMax());
385
386   // Orienting bounding planes.
387   std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
388   const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
389   gp_Lin aLine(aCentrePnt, anExtVec);
390   IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
391   IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
392   Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
393   Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
394   if(aToParameter > aFromParameter) {
395     gp_Vec aVec = aToDir->impl<gp_Dir>();
396     if((aVec * anExtVec) > 0)
397       aToDir->setImpl(new gp_Dir(aVec.Reversed()));
398     aVec = aFromDir->impl<gp_Dir>();
399     if((aVec * anExtVec) < 0)
400       aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
401   } else {
402     gp_Vec aVec = aToDir->impl<gp_Dir>();
403     if((aVec * anExtVec) < 0)
404       aToDir->setImpl(new gp_Dir(aVec.Reversed()));
405     aVec = aFromDir->impl<gp_Dir>();
406     if((aVec * anExtVec) > 0)
407       aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
408   }
409
410   static const double THE_FACE_SIZE_COEFF = 10.0;
411   GeomShapePtr aBoundingFromShape =
412       GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
413   GeomShapePtr aBoundingToShape =
414       GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
415
416   // bounding planes
417   const TopoDS_Shape& aToShape   = aBoundingToShape->impl<TopoDS_Shape>();
418   const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
419   TopoDS_Face aToFace   = TopoDS::Face(aToShape);
420   TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
421
422   // Solid based on "To" bounding plane
423   gp_Vec aNormal = aToDir->impl<gp_Dir>();
424   BRepPrimAPI_MakePrism* aToPrismBuilder =
425       new BRepPrimAPI_MakePrism(aToShape, aNormal * (-2.0 * aBndBoxSize));
426   if (!aToPrismBuilder || !aToPrismBuilder->IsDone()) {
427     return;
428   }
429   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
430     new GeomAlgoAPI_MakeShape(aToPrismBuilder)));
431   TopoDS_Shape aToSolid = aToPrismBuilder->Shape();
432
433   // Cutting with to plane.
434   BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
435   aToCutBuilder->Build();
436   if(!aToCutBuilder->IsDone()) {
437     return;
438   }
439   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
440     new GeomAlgoAPI_MakeShape(aToCutBuilder)));
441   aResult = aToCutBuilder->Shape();
442   if(aResult.ShapeType() == TopAbs_COMPOUND) {
443     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
444   }
445   if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
446     TopTools_ListOfShape aPrismShapes = aToPrismBuilder->Modified(aToShape);
447     if (aPrismShapes.IsEmpty())
448       aPrismShapes.Append(aToShape);
449     for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
450       const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(anIt1.Value());
451       for (TopTools_ListIteratorOfListOfShape anIt2(aToShapes); anIt2.More(); anIt2.Next()) {
452         GeomShapePtr aGeomSh = toShape(anIt2.Value());
453         fixOrientation(aGeomSh);
454         this->addToShape(aGeomSh);
455       }
456     }
457   }
458
459   // Solid based on "From" bounding plane
460   aNormal = aFromDir->impl<gp_Dir>();
461   BRepPrimAPI_MakePrism* aFromPrismBuilder =
462       new BRepPrimAPI_MakePrism(aFromShape, aNormal * (-2.0 * aBndBoxSize));
463   if (!aFromPrismBuilder || !aFromPrismBuilder->IsDone()) {
464     return;
465   }
466   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
467     new GeomAlgoAPI_MakeShape(aFromPrismBuilder)));
468   TopoDS_Shape aFromSolid = aFromPrismBuilder->Shape();
469
470   // Cutting with from plane.
471   BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
472   aFromCutBuilder->Build();
473   if(!aFromCutBuilder->IsDone()) {
474     return;
475   }
476   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
477     new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
478   aResult = aFromCutBuilder->Shape();
479   TopoDS_Iterator aCheckIt(aResult);
480   if(!aCheckIt.More()) {
481     return;
482   }
483   if(aResult.ShapeType() == TopAbs_COMPOUND) {
484     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
485   }
486   if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
487     TopTools_ListOfShape aPrismShapes = aFromPrismBuilder->Modified(aFromShape);
488     if (aPrismShapes.IsEmpty())
489       aPrismShapes.Append(aFromShape);
490     for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
491       const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(anIt1.Value());
492       for (TopTools_ListIteratorOfListOfShape anIt2(aFromShapes); anIt2.More(); anIt2.Next()) {
493         GeomShapePtr aGeomSh = toShape(anIt2.Value());
494         fixOrientation(aGeomSh);
495         this->addFromShape(aGeomSh);
496       }
497     }
498   }
499
500   // Naming for extrusion from vertex, edge.
501   if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
502     storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
503     storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
504   } else {
505     storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace);
506   }
507
508   if(aResult.ShapeType() == TopAbs_COMPOUND) {
509     GeomShapePtr aGeomShape = toShape(aResult);
510     ListOfShape aResults;
511     aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
512                                                         GeomAPI_Shape::COMPSOLID,
513                                                         aResults);
514     aResult = aGeomShape->impl<TopoDS_Shape>();
515   }
516
517   // Setting result.
518   if (!aResult.IsNull()) {
519     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
520     this->setShape(toShape(aResult));
521     this->setDone(true);
522   }
523 }
524
525 //==================================================================================================
526 void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr             theBaseShape,
527                                      const GeomDirPtr               theDirection,
528                                      const GeomShapePtr             theToShape,
529                                      const double                   theToSize,
530                                      const bool                     theToIsPlanar,
531                                      const GeomShapePtr             theFromShape,
532                                      const double                   theFromSize,
533                                      const bool                     theFromIsPlanar,
534                                      const GeomAPI_Shape::ShapeType theTypeToExp)
535 {
536   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
537   gp_Vec anExtVec = theDirection->impl<gp_Dir>();
538
539   // Moving prism bounding faces according to "from" and "to" sizes.
540   GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, -theFromSize, theDirection, *this);
541   GeomShapePtr aBoundingToShape   = buildOffset(theToShape, theToSize, theDirection, *this);
542
543   // Bounding box for shapes used in prism building.
544   Bnd_Box aBndBox;
545   BRepBndLib::Add(aBaseShape, aBndBox);
546   BRepBndLib::Add(aBoundingFromShape->impl<TopoDS_Shape>(), aBndBox);
547   BRepBndLib::Add(aBoundingToShape->impl<TopoDS_Shape>(), aBndBox);
548   double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax());
549
550   // Prism building.
551   gp_Trsf aTrsf;
552   aTrsf.SetTranslation(anExtVec * -aPrismLength);
553   BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
554   if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
555     return;
556   }
557   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
558       new GeomAlgoAPI_MakeShape(aTransformBuilder)));
559   TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
560
561   // Making prism.
562   BRepPrimAPI_MakePrism* aPrismBuilder =
563       new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
564   if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
565     return;
566   }
567   this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
568       new GeomAlgoAPI_MakeShape(aPrismBuilder)));
569
570   GeomShapePtr aResult = toShape(aPrismBuilder->Shape());
571
572   // Prism generatrix
573   ListOfShape aPrismBaseFaces;
574   collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp);
575
576   // Build planar faces intersecting the prism fully.
577   BRepBndLib::Add(aResult->impl<TopoDS_Shape>(), aBndBox);
578   aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox);
579   aBoundingToShape   = buildPlanarFace(aBoundingToShape, aBndBox);
580
581   // Perform partition.
582   ListOfShape anObjects, aTools;
583   anObjects.push_back(aResult);
584   aTools.push_back(aBoundingFromShape);
585   aTools.push_back(aBoundingToShape);
586
587   GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools));
588   if (!aPartition->isDone())
589     return;
590
591   this->appendAlgo(aPartition);
592
593   // Collect pieces of boundary shapes, split by Partition.
594   if (theFromIsPlanar) {
595     ListOfShape anImagesFrom;
596     aPartition->modified(aBoundingFromShape, anImagesFrom);
597     for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt)
598       addFromShape(*anIt);
599   }
600
601   if (theToIsPlanar) {
602     ListOfShape anImagesTo;
603     aPartition->modified(aBoundingToShape, anImagesTo);
604     for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt)
605       addToShape(*anIt);
606   }
607
608   // Collect results which have both boundaries, selected for extrusion,
609   // but which do not contain top and bottom faces of the prism
610   // (these faces are treated as infinitely distant).
611   aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp);
612   if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) {
613     ListOfShape aResults;
614     aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult,
615         theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID,
616         aResults);
617
618     if (aResults.size() > 1 &&
619        (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) ||
620         GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) {
621       // results shuold not have shared topology
622       aResult = GeomShapePtr();
623     }
624   }
625
626   if (aResult) {
627     this->setShape(aResult);
628     this->setDone(true);
629   }
630 }
631
632
633 // Auxilary functions:
634 //==================================================================================================
635 GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
636                              const Bnd_Box& theBaseShapeBB)
637 {
638   GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
639   if (!aPlane)
640     return theOriginalShape;
641
642   gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
643   gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
644   double aSize = aCornerMin.SquareDistance(aCornerMax);
645
646   gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
647
648   gp_Pnt aCurPnt;
649   for (int x = 0; x < 2; ++x) {
650     aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
651     for (int y = 0; y < 2; ++y) {
652       aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
653       for (int z = 0; z < 2; ++z) {
654         aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
655         double aDist = aCurPnt.SquareDistance(aLocation);
656         if (aDist > aSize)
657           aSize = aDist;
658       }
659     }
660   }
661
662   aSize = Sqrt(aSize);
663   return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
664 }
665
666 //==================================================================================================
667 GeomShapePtr buildOffset(const GeomShapePtr& theShape,
668                          const double theOffset,
669                          const GeomDirPtr theDirection,
670                          GeomAlgoAPI_MakeShapeList& theMakeShapeList)
671 {
672   if (Abs(theOffset) < Precision::Confusion())
673     return theShape; // no need zero offset
674
675   GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
676   if (!anAlgo->isDone()) {
677     // offset not done, perform translation
678     std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
679     anAxis->setDir(theDirection);
680     anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
681   }
682
683   GeomShapePtr aResult = theShape;
684   if (anAlgo->isDone()) {
685     theMakeShapeList.appendAlgo(anAlgo);
686     aResult = anAlgo->shape();
687   }
688   return aResult;
689 }
690
691 //==================================================================================================
692 void collectPrismBases(const TopoDS_Shape& theBaseShape,
693                        BRepPrimAPI_MakePrism& thePrismAlgo,
694                        ListOfShape& theBoundaries,
695                        const GeomAPI_Shape::ShapeType theTypeToExp)
696 {
697   for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
698        anExp.More(); anExp.Next()) {
699     theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
700     theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
701   }
702 }
703
704 //==================================================================================================
705 typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
706
707 bool isShapeApplicable(const GeomShapePtr& theSolid,
708                        const std::list<ListOfShape>& theShapesToExist,
709                        const SetOfShape& theShapesToExclude,
710                        const GeomAPI_Shape::ShapeType theTypeToExp)
711 {
712   SetOfShape aFaces;
713   for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
714        aFExp.more(); aFExp.next()) {
715     GeomShapePtr aCurrent = aFExp.current();
716     if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
717       return false;
718     aFaces.insert(aCurrent);
719   }
720
721   // check all faces are in solid
722   bool isApplicable = true;
723   for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
724        it1 != theShapesToExist.end() && isApplicable; ++it1) {
725     ListOfShape::const_iterator it2 = it1->begin();
726     for (; it2 != it1->end(); ++it2)
727       if (aFaces.find(*it2) != aFaces.end())
728         break;
729     isApplicable = it2 != it1->end();
730   }
731   return isApplicable;
732 }
733
734 void collectModified(const GeomMakeShapePtr& theOperation,
735                      const ListOfShape& theShapes,
736                      std::list<ListOfShape>& theModified)
737 {
738   for (ListOfShape::const_iterator anIt = theShapes.begin();
739        anIt != theShapes.end(); ++anIt) {
740     theModified.push_back(ListOfShape());
741     theOperation->modified(*anIt, theModified.back());
742     theOperation->generated(*anIt, theModified.back());
743     theModified.back().push_back(*anIt);
744   }
745 }
746
747 GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
748                             const ListOfShape& theBoundaries,
749                             const ListOfShape& theShapesToExclude,
750                             const GeomAPI_Shape::ShapeType theTypeToExp)
751 {
752   ListOfShape aResults;
753
754   // collect modified shapes
755   std::list<ListOfShape> aModifiedBoundaries;
756   collectModified(theOperation, theBoundaries, aModifiedBoundaries);
757
758   std::list<ListOfShape> aModifiedExclude;
759   collectModified(theOperation, theShapesToExclude, aModifiedExclude);
760   SetOfShape aTabooShapes;
761   for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
762        anIt != aModifiedExclude.end(); ++anIt)
763     aTabooShapes.insert(anIt->begin(), anIt->end());
764
765   // type of sub-shapes to explode
766   GeomAPI_Shape::ShapeType aSubshapeType;
767   switch (theTypeToExp) {
768   case GeomAPI_Shape::VERTEX:
769     aSubshapeType = GeomAPI_Shape::EDGE;
770     break;
771   case GeomAPI_Shape::EDGE:
772     aSubshapeType = GeomAPI_Shape::FACE;
773     break;
774   case GeomAPI_Shape::FACE:
775     aSubshapeType = GeomAPI_Shape::SOLID;
776     break;
777   default:
778     aSubshapeType = GeomAPI_Shape::COMPOUND;
779   }
780
781   // search applicable solids
782   GeomShapePtr anOperationResult = theOperation->shape();
783   for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
784         anExp.more(); anExp.next()) {
785     if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
786       aResults.push_back(anExp.current());
787   }
788
789   GeomShapePtr aResult;
790   if (aResults.size() == 1)
791     aResult = aResults.front();
792   else if (!aResults.empty())
793     aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
794   return aResult;
795 }
796
797 //==================================================================================================
798 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
799                             const TopoDS_Shape& theBase,
800                             const TopAbs_ShapeEnum theType,
801                             BRepPrimAPI_MakePrism* thePrismBuilder)
802 {
803   for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) {
804     const TopoDS_Shape& aShape = anExp.Current();
805     GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
806     aFromShape->setImpl(new TopoDS_Shape(thePrismBuilder->FirstShape(aShape)));
807     aToShape->setImpl(new TopoDS_Shape(thePrismBuilder->LastShape(aShape)));
808     thePrismAlgo->fixOrientation(aFromShape);
809     thePrismAlgo->fixOrientation(aToShape);
810     thePrismAlgo->addFromShape(aFromShape);
811     thePrismAlgo->addToShape(aToShape);
812   }
813 }
814
815 //==================================================================================================
816 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
817                             const TopoDS_Shape& theResult,
818                             const TopAbs_ShapeEnum theType,
819                             const TopoDS_Face& theToFace,
820                             const TopoDS_Face& theFromFace)
821 {
822   for(TopExp_Explorer anExp(theResult, theType); anExp.More(); anExp.Next()) {
823     const TopoDS_Shape& aShape = anExp.Current();
824     GeomShapePtr aGeomSh(new GeomAPI_Shape());
825     if(theType == TopAbs_VERTEX) {
826       gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
827       IntTools_Context anIntTools;
828       if(anIntTools.IsValidPointForFace(aPnt,
829           theToFace, Precision::Confusion()) == Standard_True) {
830         aGeomSh->setImpl(new TopoDS_Shape(aShape));
831         thePrismAlgo->fixOrientation(aGeomSh);
832         thePrismAlgo->addToShape(aGeomSh);
833       }
834       if(anIntTools.IsValidPointForFace(aPnt,
835           theFromFace, Precision::Confusion()) == Standard_True) {
836         aGeomSh->setImpl(new TopoDS_Shape(aShape));
837         thePrismAlgo->fixOrientation(aGeomSh);
838         thePrismAlgo->addFromShape(aGeomSh);
839       }
840     } else if(theType == TopAbs_EDGE) {
841       TopoDS_Edge anEdge = TopoDS::Edge(aShape);
842       BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, theToFace);
843       anEdgeCheck.Perform();
844       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
845         aGeomSh->setImpl(new TopoDS_Shape(aShape));
846         thePrismAlgo->fixOrientation(aGeomSh);
847         thePrismAlgo->addToShape(aGeomSh);
848       }
849       anEdgeCheck.Init(anEdge, theFromFace);
850       anEdgeCheck.Perform();
851       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
852         aGeomSh->setImpl(new TopoDS_Shape(aShape));
853         thePrismAlgo->fixOrientation(aGeomSh);
854         thePrismAlgo->addFromShape(aGeomSh);
855       }
856     } else {
857       break;
858     }
859   }
860 }