Salome HOME
Change algorithms for extrusion and revolution building. Now they use algos from...
[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_MakeShapeList.h>
17 #include <GeomAlgoAPI_ShapeTools.h>
18
19 #include <Bnd_Box.hxx>
20 #include <BRep_Builder.hxx>
21 #include <BRepAlgoAPI_Cut.hxx>
22 #include <BRepBndLib.hxx>
23 #include <BRepBuilderAPI_Transform.hxx>
24 #include <BRepCheck_Analyzer.hxx>
25 #include <BRepExtrema_ExtCF.hxx>
26 #include <BRepGProp.hxx>
27 #include <BRepPrimAPI_MakePrism.hxx>
28 #include <gp_Pln.hxx>
29 #include <GProp_GProps.hxx>
30 #include <IntAna_IntConicQuad.hxx>
31 #include <IntAna_Quadric.hxx>
32 #include <TopExp_Explorer.hxx>
33 #include <TopoDS_Shell.hxx>
34 #include <TopoDS_Solid.hxx>
35 #include <TopTools_ListIteratorOfListOfShape.hxx>
36
37 //=================================================================================================
38 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(std::shared_ptr<GeomAPI_Shape> theBaseShape,
39                                      double                         theToSize,
40                                      double                         theFromSize)
41 : myDone(false)
42 {
43   build(theBaseShape, std::shared_ptr<GeomAPI_Shape>(), theToSize, std::shared_ptr<GeomAPI_Shape>(), theFromSize);
44 }
45
46 //=================================================================================================
47 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(std::shared_ptr<GeomAPI_Shape> theBaseShape,
48                                      std::shared_ptr<GeomAPI_Shape> theToShape,
49                                      double                         theToSize,
50                                      std::shared_ptr<GeomAPI_Shape> theFromShape,
51                                      double                         theFromSize)
52 : myDone(false)
53 {
54   build(theBaseShape, theToShape, theToSize, theFromShape, theFromSize);
55 }
56
57 //=================================================================================================
58 void GeomAlgoAPI_Prism::build(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
59                               const std::shared_ptr<GeomAPI_Shape>& theToShape,
60                               double                                theToSize,
61                               const std::shared_ptr<GeomAPI_Shape>& theFromShape,
62                               double                                theFromSize)
63 {
64   if(!theBaseShape ||
65     (((!theFromShape && !theToShape) || (theFromShape && theToShape && theFromShape->isEqual(theToShape)))
66     && (theFromSize == -theToSize))) {
67     return;
68   }
69
70   // Getting base plane.
71   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
72   std::shared_ptr<GeomAPI_Face> aBaseFace;
73   if(theBaseShape->shapeType() == GeomAPI_Shape::FACE) {
74     aBaseFace = std::shared_ptr<GeomAPI_Face>(new GeomAPI_Face(theBaseShape));
75   } else if(theBaseShape->shapeType() == GeomAPI_Shape::SHELL){
76     GeomAPI_ShapeExplorer anExp(theBaseShape, GeomAPI_Shape::FACE);
77     if(anExp.more()) {
78       std::shared_ptr<GeomAPI_Shape> aFaceOnShell = anExp.current();
79       aBaseFace = std::shared_ptr<GeomAPI_Face>(new GeomAPI_Face(aFaceOnShell));
80     }
81   }
82   if(!aBaseFace.get()) {
83     return;
84   }
85
86   std::shared_ptr<GeomAPI_Pln>   aBasePln = aBaseFace->getPlane();
87   std::shared_ptr<GeomAPI_Dir>   aBaseDir = aBasePln->direction();
88   std::shared_ptr<GeomAPI_Pnt>   aBaseLoc = aBasePln->location();
89   std::shared_ptr<GeomAPI_Shape> aBasePlane = GeomAlgoAPI_FaceBuilder::planarFace(aBaseLoc, aBaseDir);
90
91   gp_Vec aBaseVec(aBaseDir->impl<gp_Dir>());
92   const gp_Pnt& aBasePnt = aBaseLoc->impl<gp_Pnt>();
93
94   TopoDS_Shape aResult;
95   ListOfMakeShape aListOfMakeShape;
96   bool isBoundingShapesSet = theFromShape || theToShape;
97   if(!isBoundingShapesSet) {
98     // Moving base shape.
99     gp_Trsf aTrsf;
100     aTrsf.SetTranslation(aBaseVec * -theFromSize);
101     BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
102     if(!aTransformBuilder) {
103       return;
104     }
105     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
106     if(!aTransformBuilder->IsDone()) {
107       return;
108     }
109     TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
110
111     // Making prism.
112     BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aBaseVec * (theFromSize + theToSize));
113     if(!aPrismBuilder) {
114       return;
115     }
116     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
117     if(!aPrismBuilder->IsDone()) {
118       return;
119     }
120     aResult = aPrismBuilder->Shape();
121
122     // Setting naming.
123     for(TopExp_Explorer anExp(aMovedBase, TopAbs_FACE); anExp.More(); anExp.Next()) {
124       const TopoDS_Shape& aFace = anExp.Current();
125       std::shared_ptr<GeomAPI_Shape> aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
126       aFromShape->setImpl(new TopoDS_Shape(aPrismBuilder->FirstShape(aFace)));
127       aToShape->setImpl(new TopoDS_Shape(aPrismBuilder->LastShape(aFace)));
128       myFromFaces.push_back(aFromShape);
129       myToFaces.push_back(aToShape);
130     }
131   } else {
132     std::shared_ptr<GeomAPI_Shape> aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
133     std::shared_ptr<GeomAPI_Shape> aBoundingToShape   = theToShape   ? theToShape   : aBasePlane;
134
135     // Moving prism bounding faces according to "from" and "to" sizes.
136     std::shared_ptr<GeomAPI_Face> aFromFace(new GeomAPI_Face(aBoundingFromShape));
137     std::shared_ptr<GeomAPI_Pln>  aFromPln = aFromFace->getPlane();
138     std::shared_ptr<GeomAPI_Pnt>  aFromLoc = aFromPln->location();
139     std::shared_ptr<GeomAPI_Dir>  aFromDir = aFromPln->direction();
140
141     std::shared_ptr<GeomAPI_Face> aToFace(new GeomAPI_Face(aBoundingToShape));
142     std::shared_ptr<GeomAPI_Pln>  aToPln = aToFace->getPlane();
143     std::shared_ptr<GeomAPI_Pnt>  aToLoc = aToPln->location();
144     std::shared_ptr<GeomAPI_Dir>  aToDir = aToPln->direction();
145
146     bool aSign = aFromLoc->xyz()->dot(aBaseDir->xyz()) > aToLoc->xyz()->dot(aBaseDir->xyz());
147
148     std::shared_ptr<GeomAPI_Pnt> aFromPnt(new GeomAPI_Pnt(aFromLoc->xyz()->added(aBaseDir->xyz()->multiplied(
149                                                           aSign ? theFromSize : -theFromSize))));
150     aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
151
152     std::shared_ptr<GeomAPI_Pnt> aToPnt(new GeomAPI_Pnt(aToLoc->xyz()->added(aBaseDir->xyz()->multiplied(
153                                                         aSign ? -theToSize : theToSize))));
154     aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
155
156     // Getting bounding box for base shape.
157     Bnd_Box aBndBox;
158     BRepBndLib::Add(aBaseShape, aBndBox);
159     Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
160     Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
161     Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
162     gp_Pnt aPoints[8];
163     int aNum = 0;
164     for(int i = 0; i < 2; i++) {
165       for(int j = 0; j < 2; j++) {
166         for(int k = 0; k < 2; k++) {
167           aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
168           aNum++;
169         }
170       }
171     }
172
173     // Project points to bounding planes. Search max distance to them.
174     IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
175     IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
176     Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
177     for(int i = 0; i < 8; i++) {
178       gp_Lin aLine(aPoints[i], aBaseVec);
179       IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
180       IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
181       if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
182         return;
183       }
184       const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
185       const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
186       if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
187         aMaxToDist = aPoints[i].Distance(aPntOnToFace);
188       }
189       if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
190         aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
191       }
192     }
193
194     // We added 1 just to be sure that prism is long enough for boolean operation.
195     double aPrismLength = aMaxToDist + aMaxFromDist + 1;
196
197     // Moving base shape.
198     gp_Trsf aTrsf;
199     aTrsf.SetTranslation(aBaseVec * -aPrismLength);
200     BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
201     if(!aTransformBuilder) {
202       return;
203     }
204     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
205     if(!aTransformBuilder->IsDone()) {
206       return;
207     }
208     TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
209
210     // Making prism.
211     BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aBaseVec * 2 * aPrismLength);
212     if(!aPrismBuilder) {
213       return;
214     }
215     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
216     if(!aPrismBuilder->IsDone()) {
217       return;
218     }
219     aResult = aPrismBuilder->Shape();
220
221     // Orienting bounding planes.
222     std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
223     const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
224     gp_Lin aLine(aCentrePnt, aBaseVec);
225     IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
226     IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
227     Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
228     Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
229     if(aToParameter > aFromParameter) {
230       gp_Vec aVec = aToDir->impl<gp_Dir>();
231       if((aVec * aBaseVec) > 0) {
232         aToDir->setImpl(new gp_Dir(aVec.Reversed()));
233         aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
234       }
235       aVec = aFromDir->impl<gp_Dir>();
236       if((aVec * aBaseVec) < 0) {
237         aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
238         aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
239       }
240     } else {
241       gp_Vec aVec = aToDir->impl<gp_Dir>();
242       if((aVec * aBaseVec) < 0) {
243         aToDir->setImpl(new gp_Dir(aVec.Reversed()));
244         aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
245       }
246       aVec = aFromDir->impl<gp_Dir>();
247       if((aVec * aBaseVec) > 0) {
248         aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
249         aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
250       }
251     }
252
253     // Making solids from bounding planes.
254     TopoDS_Shell aToShell, aFromShell;
255     TopoDS_Solid aToSolid, aFromSolid;
256     const TopoDS_Shape& aToShape   = aBoundingToShape->impl<TopoDS_Shape>();
257     const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
258     BRep_Builder aBoundingBuilder;
259     aBoundingBuilder.MakeShell(aToShell);
260     aBoundingBuilder.MakeShell(aFromShell);
261     aBoundingBuilder.Add(aToShell, aToShape);
262     aBoundingBuilder.Add(aFromShell, aFromShape);
263     aBoundingBuilder.MakeSolid(aToSolid);
264     aBoundingBuilder.MakeSolid(aFromSolid);
265     aBoundingBuilder.Add(aToSolid, aToShell);
266     aBoundingBuilder.Add(aFromSolid, aFromShell);
267
268     // Cutting with to plane.
269     BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
270     aToCutBuilder->Build();
271     if(!aToCutBuilder->IsDone()) {
272       return;
273     }
274     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
275     const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
276     for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
277       std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
278       aShape->setImpl(new TopoDS_Shape(anIt.Value()));
279       myToFaces.push_back(aShape);
280     }
281     aResult = aToCutBuilder->Shape();
282
283     // Cutting with from plane.
284     BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
285     aFromCutBuilder->Build();
286     if(!aFromCutBuilder->IsDone()) {
287       return;
288     }
289     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
290     const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
291     for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
292       std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
293       aShape->setImpl(new TopoDS_Shape(anIt.Value()));
294       myFromFaces.push_back(aShape);
295     }
296     aResult = aFromCutBuilder->Shape();
297
298     TopExp_Explorer anExp(aResult, TopAbs_SOLID);
299     if(!anExp.More()) {
300       return;
301     }
302     if(aResult.ShapeType() == TopAbs_COMPOUND) {
303       aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
304     }
305     if(aResult.ShapeType() == TopAbs_COMPOUND) {
306       std::shared_ptr<GeomAPI_Shape> aCompound(new GeomAPI_Shape);
307       aCompound->setImpl(new TopoDS_Shape(aResult));
308       ListOfShape aCompSolids, aFreeSolids;
309       GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids);
310       if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) {
311         aResult = aCompSolids.front()->impl<TopoDS_Shape>();
312       } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) {
313         TopoDS_Compound aResultComp;
314         TopoDS_Builder aBuilder;
315         aBuilder.MakeCompound(aResultComp);
316         for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) {
317           aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
318         }
319         for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) {
320           aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
321         }
322         aResult = aResultComp;
323       }
324     }
325   }
326
327   // Setting result.
328   if(aResult.IsNull()) {
329     return;
330   }
331   myShape.reset(new GeomAPI_Shape);
332   myShape->setImpl(new TopoDS_Shape(aResult));
333
334   // Filling data map to keep correct orientation of sub-shapes.
335   myMap.reset(new GeomAPI_DataMapOfShapeShape);
336   for (TopExp_Explorer Exp(aResult,TopAbs_FACE); Exp.More(); Exp.Next()) {
337     std::shared_ptr<GeomAPI_Shape> aCurrentShape(new GeomAPI_Shape);
338     aCurrentShape->setImpl(new TopoDS_Shape(Exp.Current()));
339     myMap->bind(aCurrentShape, aCurrentShape);
340   }
341
342   // Setting list of make shape.
343   myMkShape.reset(new GeomAlgoAPI_MakeShapeList(aListOfMakeShape));
344
345   myDone = true;
346 }
347
348 //=================================================================================================
349 bool GeomAlgoAPI_Prism::isDone() const
350 {
351   return myDone;
352 }
353
354 //=================================================================================================
355 bool GeomAlgoAPI_Prism::isValid() const
356 {
357   BRepCheck_Analyzer aChecker(myShape->impl<TopoDS_Shape>());
358   return (aChecker.IsValid() == Standard_True);
359 }
360
361 //=================================================================================================
362 bool GeomAlgoAPI_Prism::hasVolume() const
363 {
364   bool hasVolume(false);
365   if(isValid()) {
366     const TopoDS_Shape& aRShape = myShape->impl<TopoDS_Shape>();
367     GProp_GProps aGProp;
368     BRepGProp::VolumeProperties(aRShape, aGProp);
369     if(aGProp.Mass() > Precision::Confusion())
370       hasVolume = true;
371   }
372   return hasVolume;
373 }
374
375 //=================================================================================================
376 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_Prism::shape() const
377 {
378   return myShape;
379 }
380
381 //=================================================================================================
382 const ListOfShape& GeomAlgoAPI_Prism::fromFaces() const
383 {
384   return myFromFaces;
385 }
386
387 //=================================================================================================
388 const ListOfShape& GeomAlgoAPI_Prism::toFaces() const
389 {
390   return myToFaces;
391 }
392
393 //=================================================================================================
394 std::shared_ptr<GeomAPI_DataMapOfShapeShape> GeomAlgoAPI_Prism::mapOfShapes() const
395 {
396   return myMap;
397 }
398
399 //=================================================================================================
400 std::shared_ptr<GeomAlgoAPI_MakeShape> GeomAlgoAPI_Prism::makeShape() const
401 {
402   return myMkShape;
403 }