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