Salome HOME
Pipe feature
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Prism.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        GeomAlgoAPI_Prism.cpp
4 // Created:     5 May 2015
5 // Author:      Dmitry Bobylev
6
7 #include "GeomAlgoAPI_Prism.h"
8
9 #include <GeomAPI_Face.h>
10 #include <GeomAPI_Pln.h>
11 #include <GeomAPI_Pnt.h>
12 #include <GeomAPI_ShapeExplorer.h>
13 #include <GeomAPI_XYZ.h>
14 #include <GeomAlgoAPI_DFLoader.h>
15 #include <GeomAlgoAPI_FaceBuilder.h>
16 #include <GeomAlgoAPI_ShapeTools.h>
17
18 #include <Bnd_Box.hxx>
19 #include <BRep_Builder.hxx>
20 #include <BRepAlgoAPI_Cut.hxx>
21 #include <BRepBndLib.hxx>
22 #include <BRepBuilderAPI_Transform.hxx>
23 #include <BRepPrimAPI_MakePrism.hxx>
24 #include <gp_Pln.hxx>
25 #include <IntAna_IntConicQuad.hxx>
26 #include <IntAna_Quadric.hxx>
27 #include <TopExp_Explorer.hxx>
28 #include <TopoDS_Shell.hxx>
29 #include <TopoDS_Solid.hxx>
30 #include <TopTools_ListIteratorOfListOfShape.hxx>
31
32 //=================================================================================================
33 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(std::shared_ptr<GeomAPI_Shape> theBaseShape,
34                                      double                         theToSize,
35                                      double                         theFromSize)
36 {
37   build(theBaseShape, std::shared_ptr<GeomAPI_Shape>(), theToSize, std::shared_ptr<GeomAPI_Shape>(), theFromSize);
38 }
39
40 //=================================================================================================
41 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(std::shared_ptr<GeomAPI_Shape> theBaseShape,
42                                      std::shared_ptr<GeomAPI_Shape> theToShape,
43                                      double                         theToSize,
44                                      std::shared_ptr<GeomAPI_Shape> theFromShape,
45                                      double                         theFromSize)
46 {
47   build(theBaseShape, theToShape, theToSize, theFromShape, theFromSize);
48 }
49
50 //=================================================================================================
51 void GeomAlgoAPI_Prism::build(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
52                               const std::shared_ptr<GeomAPI_Shape>& theToShape,
53                               double                                theToSize,
54                               const std::shared_ptr<GeomAPI_Shape>& theFromShape,
55                               double                                theFromSize)
56 {
57   if(!theBaseShape ||
58     (((!theFromShape && !theToShape) || (theFromShape && theToShape && theFromShape->isEqual(theToShape)))
59     && (theFromSize == -theToSize))) {
60     return;
61   }
62
63   // Getting base plane.
64   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
65   std::shared_ptr<GeomAPI_Face> aBaseFace;
66   if(theBaseShape->shapeType() == GeomAPI_Shape::FACE) {
67     aBaseFace = std::shared_ptr<GeomAPI_Face>(new GeomAPI_Face(theBaseShape));
68   } else if(theBaseShape->shapeType() == GeomAPI_Shape::SHELL){
69     GeomAPI_ShapeExplorer anExp(theBaseShape, GeomAPI_Shape::FACE);
70     if(anExp.more()) {
71       std::shared_ptr<GeomAPI_Shape> aFaceOnShell = anExp.current();
72       aBaseFace = std::shared_ptr<GeomAPI_Face>(new GeomAPI_Face(aFaceOnShell));
73     }
74   }
75   if(!aBaseFace.get()) {
76     return;
77   }
78
79   std::shared_ptr<GeomAPI_Pln>   aBasePln = aBaseFace->getPlane();
80   std::shared_ptr<GeomAPI_Dir>   aBaseDir = aBasePln->direction();
81   std::shared_ptr<GeomAPI_Pnt>   aBaseLoc = aBasePln->location();
82   std::shared_ptr<GeomAPI_Shape> aBasePlane = GeomAlgoAPI_FaceBuilder::planarFace(aBaseLoc, aBaseDir);
83
84   gp_Vec aBaseVec(aBaseDir->impl<gp_Dir>());
85   const gp_Pnt& aBasePnt = aBaseLoc->impl<gp_Pnt>();
86
87   TopoDS_Shape aResult;
88   bool isBoundingShapesSet = theFromShape || theToShape;
89   if(!isBoundingShapesSet) {
90     // Moving base shape.
91     gp_Trsf aTrsf;
92     aTrsf.SetTranslation(aBaseVec * -theFromSize);
93     BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
94     if(!aTransformBuilder) {
95       return;
96     }
97     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
98     if(!aTransformBuilder->IsDone()) {
99       return;
100     }
101     TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
102
103     // Making prism.
104     BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aBaseVec * (theFromSize + theToSize));
105     if(!aPrismBuilder) {
106       return;
107     }
108     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
109     if(!aPrismBuilder->IsDone()) {
110       return;
111     }
112     aResult = aPrismBuilder->Shape();
113
114     // Setting naming.
115     for(TopExp_Explorer anExp(aMovedBase, TopAbs_FACE); anExp.More(); anExp.Next()) {
116       const TopoDS_Shape& aFace = anExp.Current();
117       std::shared_ptr<GeomAPI_Shape> aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
118       aFromShape->setImpl(new TopoDS_Shape(aPrismBuilder->FirstShape(aFace)));
119       aToShape->setImpl(new TopoDS_Shape(aPrismBuilder->LastShape(aFace)));
120       this->addFromShape(aFromShape);
121       this->addToShape(aToShape);
122     }
123   } else {
124     std::shared_ptr<GeomAPI_Shape> aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
125     std::shared_ptr<GeomAPI_Shape> aBoundingToShape   = theToShape   ? theToShape   : aBasePlane;
126
127     // Moving prism bounding faces according to "from" and "to" sizes.
128     std::shared_ptr<GeomAPI_Face> aFromFace(new GeomAPI_Face(aBoundingFromShape));
129     std::shared_ptr<GeomAPI_Pln>  aFromPln = aFromFace->getPlane();
130     std::shared_ptr<GeomAPI_Pnt>  aFromLoc = aFromPln->location();
131     std::shared_ptr<GeomAPI_Dir>  aFromDir = aFromPln->direction();
132
133     std::shared_ptr<GeomAPI_Face> aToFace(new GeomAPI_Face(aBoundingToShape));
134     std::shared_ptr<GeomAPI_Pln>  aToPln = aToFace->getPlane();
135     std::shared_ptr<GeomAPI_Pnt>  aToLoc = aToPln->location();
136     std::shared_ptr<GeomAPI_Dir>  aToDir = aToPln->direction();
137
138     bool aSign = aFromLoc->xyz()->dot(aBaseDir->xyz()) > aToLoc->xyz()->dot(aBaseDir->xyz());
139
140     std::shared_ptr<GeomAPI_Pnt> aFromPnt(new GeomAPI_Pnt(aFromLoc->xyz()->added(aBaseDir->xyz()->multiplied(
141                                                           aSign ? theFromSize : -theFromSize))));
142     aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
143
144     std::shared_ptr<GeomAPI_Pnt> aToPnt(new GeomAPI_Pnt(aToLoc->xyz()->added(aBaseDir->xyz()->multiplied(
145                                                         aSign ? -theToSize : theToSize))));
146     aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
147
148     // Getting bounding box for base shape.
149     Bnd_Box aBndBox;
150     BRepBndLib::Add(aBaseShape, aBndBox);
151     Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
152     Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
153     Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
154     gp_Pnt aPoints[8];
155     int aNum = 0;
156     for(int i = 0; i < 2; i++) {
157       for(int j = 0; j < 2; j++) {
158         for(int k = 0; k < 2; k++) {
159           aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
160           aNum++;
161         }
162       }
163     }
164
165     // Project points to bounding planes. Search max distance to them.
166     IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
167     IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
168     Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
169     for(int i = 0; i < 8; i++) {
170       gp_Lin aLine(aPoints[i], aBaseVec);
171       IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
172       IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
173       if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
174         return;
175       }
176       const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
177       const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
178       if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
179         aMaxToDist = aPoints[i].Distance(aPntOnToFace);
180       }
181       if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
182         aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
183       }
184     }
185
186     // We added 1 just to be sure that prism is long enough for boolean operation.
187     double aPrismLength = aMaxToDist + aMaxFromDist + 1;
188
189     // Moving base shape.
190     gp_Trsf aTrsf;
191     aTrsf.SetTranslation(aBaseVec * -aPrismLength);
192     BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
193     if(!aTransformBuilder) {
194       return;
195     }
196     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
197     if(!aTransformBuilder->IsDone()) {
198       return;
199     }
200     TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
201
202     // Making prism.
203     BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aBaseVec * 2 * aPrismLength);
204     if(!aPrismBuilder) {
205       return;
206     }
207     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
208     if(!aPrismBuilder->IsDone()) {
209       return;
210     }
211     aResult = aPrismBuilder->Shape();
212
213     // Orienting bounding planes.
214     std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
215     const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
216     gp_Lin aLine(aCentrePnt, aBaseVec);
217     IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
218     IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
219     Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
220     Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
221     if(aToParameter > aFromParameter) {
222       gp_Vec aVec = aToDir->impl<gp_Dir>();
223       if((aVec * aBaseVec) > 0) {
224         aToDir->setImpl(new gp_Dir(aVec.Reversed()));
225         aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
226       }
227       aVec = aFromDir->impl<gp_Dir>();
228       if((aVec * aBaseVec) < 0) {
229         aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
230         aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
231       }
232     } else {
233       gp_Vec aVec = aToDir->impl<gp_Dir>();
234       if((aVec * aBaseVec) < 0) {
235         aToDir->setImpl(new gp_Dir(aVec.Reversed()));
236         aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
237       }
238       aVec = aFromDir->impl<gp_Dir>();
239       if((aVec * aBaseVec) > 0) {
240         aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
241         aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
242       }
243     }
244
245     // Making solids from bounding planes.
246     TopoDS_Shell aToShell, aFromShell;
247     TopoDS_Solid aToSolid, aFromSolid;
248     const TopoDS_Shape& aToShape   = aBoundingToShape->impl<TopoDS_Shape>();
249     const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
250     BRep_Builder aBoundingBuilder;
251     aBoundingBuilder.MakeShell(aToShell);
252     aBoundingBuilder.MakeShell(aFromShell);
253     aBoundingBuilder.Add(aToShell, aToShape);
254     aBoundingBuilder.Add(aFromShell, aFromShape);
255     aBoundingBuilder.MakeSolid(aToSolid);
256     aBoundingBuilder.MakeSolid(aFromSolid);
257     aBoundingBuilder.Add(aToSolid, aToShell);
258     aBoundingBuilder.Add(aFromSolid, aFromShell);
259
260     // Cutting with to plane.
261     BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
262     aToCutBuilder->Build();
263     if(!aToCutBuilder->IsDone()) {
264       return;
265     }
266     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
267     const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
268     for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
269       std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
270       aShape->setImpl(new TopoDS_Shape(anIt.Value()));
271       this->addToShape(aShape);
272     }
273     aResult = aToCutBuilder->Shape();
274
275     // Cutting with from plane.
276     BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
277     aFromCutBuilder->Build();
278     if(!aFromCutBuilder->IsDone()) {
279       return;
280     }
281     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
282     const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
283     for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
284       std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
285       aShape->setImpl(new TopoDS_Shape(anIt.Value()));
286       this->addFromShape(aShape);
287     }
288     aResult = aFromCutBuilder->Shape();
289
290     TopExp_Explorer anExp(aResult, TopAbs_SOLID);
291     if(!anExp.More()) {
292       return;
293     }
294     if(aResult.ShapeType() == TopAbs_COMPOUND) {
295       aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
296     }
297     if(aResult.ShapeType() == TopAbs_COMPOUND) {
298       std::shared_ptr<GeomAPI_Shape> aCompound(new GeomAPI_Shape);
299       aCompound->setImpl(new TopoDS_Shape(aResult));
300       ListOfShape aCompSolids, aFreeSolids;
301       GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids);
302       if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) {
303         aResult = aCompSolids.front()->impl<TopoDS_Shape>();
304       } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) {
305         TopoDS_Compound aResultComp;
306         TopoDS_Builder aBuilder;
307         aBuilder.MakeCompound(aResultComp);
308         for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) {
309           aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
310         }
311         for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) {
312           aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
313         }
314         aResult = aResultComp;
315       }
316     }
317   }
318
319   // Setting result.
320   if(aResult.IsNull()) {
321     return;
322   }
323   std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
324   aShape->setImpl(new TopoDS_Shape(aResult));
325   this->setShape(aShape);
326   this->setDone(true);
327 }