]> SALOME platform Git repositories - modules/shaper.git/blob - src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp
Salome HOME
45e0adfebd1e93672ab87a0ea390d4a417535411
[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_FindPlane.hxx>
23 #include <BRepBuilderAPI_Transform.hxx>
24 #include <BRepTools.hxx>
25 #include <Geom_Curve.hxx>
26 #include <Geom2d_Curve.hxx>
27 #include <BRepLib_CheckCurveOnSurface.hxx>
28 #include <BRepPrimAPI_MakePrism.hxx>
29 #include <Geom_Plane.hxx>
30 #include <gp_Pln.hxx>
31 #include <IntAna_IntConicQuad.hxx>
32 #include <IntAna_Quadric.hxx>
33 #include <IntTools_Context.hxx>
34 #include <TopExp_Explorer.hxx>
35 #include <TopoDS.hxx>
36 #include <TopoDS_Edge.hxx>
37 #include <TopoDS_Shell.hxx>
38 #include <TopoDS_Solid.hxx>
39 #include <TopTools_ListIteratorOfListOfShape.hxx>
40
41 //=================================================================================================
42 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
43                                      const double       theToSize,
44                                      const double       theFromSize)
45 {
46   build(theBaseShape, std::shared_ptr<GeomAPI_Dir>(), GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize);
47 }
48
49 //=================================================================================================
50 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr                 theBaseShape,
51                                      const std::shared_ptr<GeomAPI_Dir> theDirection,
52                                      const double                       theToSize,
53                                      const double                       theFromSize)
54 {
55   build(theBaseShape, theDirection, GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize);
56 }
57
58 //=================================================================================================
59 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
60                                      const GeomShapePtr theToShape,
61                                      const double       theToSize,
62                                      const GeomShapePtr theFromShape,
63                                      const double       theFromSize)
64 {
65   build(theBaseShape, std::shared_ptr<GeomAPI_Dir>(), theToShape, theToSize, theFromShape, theFromSize);
66 }
67
68 //=================================================================================================
69 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr                 theBaseShape,
70                                      const std::shared_ptr<GeomAPI_Dir> theDirection,
71                                      const GeomShapePtr                 theToShape,
72                                      const double                       theToSize,
73                                      const GeomShapePtr                 theFromShape,
74                                      const double                       theFromSize)
75 {
76   build(theBaseShape, theDirection, theToShape, theToSize, theFromShape, theFromSize);
77 }
78
79 //=================================================================================================
80 void GeomAlgoAPI_Prism::build(const GeomShapePtr&                theBaseShape,
81                               const std::shared_ptr<GeomAPI_Dir> theDirection,
82                               const GeomShapePtr&                theToShape,
83                               const double                       theToSize,
84                               const GeomShapePtr&                theFromShape,
85                               const double                       theFromSize)
86 {
87   if(!theBaseShape.get() ||
88     (((!theFromShape.get() && !theToShape.get()) || (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape)))
89     && (theFromSize == -theToSize))) {
90     return;
91   }
92
93   // Getting base shape.
94   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
95   TopAbs_ShapeEnum aShapeTypeToExp;
96   switch(aBaseShape.ShapeType()) {
97     case TopAbs_VERTEX:
98       aShapeTypeToExp = TopAbs_VERTEX;
99       break;
100     case TopAbs_EDGE:
101     case TopAbs_WIRE:
102       aShapeTypeToExp = TopAbs_EDGE;
103       break;
104     case TopAbs_FACE:
105     case TopAbs_SHELL:
106       aShapeTypeToExp = TopAbs_FACE;
107       break;
108     default:
109       return;
110   }
111
112   // Getting direction.
113   gp_Pnt aLoc;
114   gp_Vec aDirVec;
115   std::shared_ptr<GeomAPI_Pnt> aBaseLoc;
116   std::shared_ptr<GeomAPI_Dir> aBaseDir;
117   GeomShapePtr aBasePlane;
118   const bool isBoundingShapesSet = theFromShape.get() || theToShape.get();
119   BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
120   if(aBaseShape.ShapeType() == TopAbs_VERTEX || aBaseShape.ShapeType() == TopAbs_EDGE ||
121      aFindPlane.Found() != Standard_True) {
122     // Direction should be set.
123     if(!theDirection.get()) {
124       return;
125     }
126
127     aBaseDir = theDirection;
128     aDirVec = theDirection->impl<gp_Dir>();
129     gp_XYZ aDirXYZ = aDirVec.XYZ();
130     Standard_Real aMinParam = Precision::Infinite();
131
132     for(TopExp_Explorer anExp(aBaseShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) {
133       const TopoDS_Shape& aVertex = anExp.Current();
134       gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
135       double aParam = aDirXYZ.Dot(aPnt.XYZ());
136       if(aParam < aMinParam) {
137         aMinParam = aParam;
138         aLoc = aPnt;
139       }
140     }
141   } else {
142     if(!theDirection.get()) {
143       Handle(Geom_Plane) aPlane = aFindPlane.Plane();
144       aLoc = aPlane->Axis().Location();
145       aDirVec = aPlane->Axis().Direction();
146
147       aBaseDir.reset(new GeomAPI_Dir(aDirVec.X(), aDirVec.Y(), aDirVec.Z()));
148     } else {
149       aBaseDir = theDirection;
150       aDirVec = theDirection->impl<gp_Dir>();
151     }
152   }
153   aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
154   aBasePlane = GeomAlgoAPI_FaceBuilder::planarFace(aBaseLoc, aBaseDir);
155
156   TopoDS_Shape aResult;
157   if(!isBoundingShapesSet) {
158     // Moving base shape.
159     gp_Trsf aTrsf;
160     aTrsf.SetTranslation(aDirVec * -theFromSize);
161     BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
162     if(!aTransformBuilder) {
163       return;
164     }
165     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
166     if(!aTransformBuilder->IsDone()) {
167       return;
168     }
169     TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
170
171     // Making prism.
172     BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * (theFromSize + theToSize));
173     if(!aPrismBuilder) {
174       return;
175     }
176     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
177     if(!aPrismBuilder->IsDone()) {
178       return;
179     }
180     aResult = aPrismBuilder->Shape();
181
182     // Setting naming.
183     for(TopExp_Explorer anExp(aMovedBase, aShapeTypeToExp); anExp.More(); anExp.Next()) {
184       const TopoDS_Shape& aShape = anExp.Current();
185       GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
186       aFromShape->setImpl(new TopoDS_Shape(aPrismBuilder->FirstShape(aShape)));
187       aToShape->setImpl(new TopoDS_Shape(aPrismBuilder->LastShape(aShape)));
188       this->addFromShape(aFromShape);
189       this->addToShape(aToShape);
190     }
191   } else {
192     GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
193     GeomShapePtr aBoundingToShape   = theToShape   ? theToShape   : aBasePlane;
194
195     // Moving prism bounding faces according to "from" and "to" sizes.
196     std::shared_ptr<GeomAPI_Pln> aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane();
197     std::shared_ptr<GeomAPI_Pnt> aFromLoc = aFromPln->location();
198     std::shared_ptr<GeomAPI_Dir> aFromDir = aFromPln->direction();
199
200     std::shared_ptr<GeomAPI_Pln> aToPln = GeomAPI_Face(aBoundingToShape).getPlane();
201     std::shared_ptr<GeomAPI_Pnt> aToLoc = aToPln->location();
202     std::shared_ptr<GeomAPI_Dir> aToDir = aToPln->direction();
203
204     bool aSign = aFromLoc->xyz()->dot(aBaseDir->xyz()) > aToLoc->xyz()->dot(aBaseDir->xyz());
205
206     std::shared_ptr<GeomAPI_Pnt> aFromPnt(new GeomAPI_Pnt(aFromLoc->xyz()->added(aBaseDir->xyz()->multiplied(
207                                                           aSign ? theFromSize : -theFromSize))));
208     aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
209
210     std::shared_ptr<GeomAPI_Pnt> aToPnt(new GeomAPI_Pnt(aToLoc->xyz()->added(aBaseDir->xyz()->multiplied(
211                                                         aSign ? -theToSize : theToSize))));
212     aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
213
214     // Getting bounding box for base shape.
215     Bnd_Box aBndBox;
216     BRepBndLib::Add(aBaseShape, aBndBox);
217     Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
218     Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
219     Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
220     gp_Pnt aPoints[8];
221     int aNum = 0;
222     for(int i = 0; i < 2; i++) {
223       for(int j = 0; j < 2; j++) {
224         for(int k = 0; k < 2; k++) {
225           aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
226           aNum++;
227         }
228       }
229     }
230
231     // Project points to bounding planes. Search max distance to them.
232     IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
233     IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
234     Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
235     for(int i = 0; i < 8; i++) {
236       gp_Lin aLine(aPoints[i], aDirVec);
237       IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
238       IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
239       if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
240         return;
241       }
242       const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
243       const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
244       if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
245         aMaxToDist = aPoints[i].Distance(aPntOnToFace);
246       }
247       if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
248         aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
249       }
250     }
251
252     // We added 1 just to be sure that prism is long enough for boolean operation.
253     double aPrismLength = aMaxToDist + aMaxFromDist + 1;
254
255     // Moving base shape.
256     gp_Trsf aTrsf;
257     aTrsf.SetTranslation(aDirVec * -aPrismLength);
258     BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
259     if(!aTransformBuilder) {
260       return;
261     }
262     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
263     if(!aTransformBuilder->IsDone()) {
264       return;
265     }
266     TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
267
268     // Making prism.
269     BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * 2 * aPrismLength);
270     if(!aPrismBuilder) {
271       return;
272     }
273     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
274     if(!aPrismBuilder->IsDone()) {
275       return;
276     }
277     aResult = aPrismBuilder->Shape();
278
279     // Orienting bounding planes.
280     std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
281     const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
282     gp_Lin aLine(aCentrePnt, aDirVec);
283     IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
284     IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
285     Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
286     Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
287     if(aToParameter > aFromParameter) {
288       gp_Vec aVec = aToDir->impl<gp_Dir>();
289       if((aVec * aDirVec) > 0) {
290         aToDir->setImpl(new gp_Dir(aVec.Reversed()));
291         aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
292       }
293       aVec = aFromDir->impl<gp_Dir>();
294       if((aVec * aDirVec) < 0) {
295         aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
296         aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
297       }
298     } else {
299       gp_Vec aVec = aToDir->impl<gp_Dir>();
300       if((aVec * aDirVec) < 0) {
301         aToDir->setImpl(new gp_Dir(aVec.Reversed()));
302         aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
303       }
304       aVec = aFromDir->impl<gp_Dir>();
305       if((aVec * aDirVec) > 0) {
306         aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
307         aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
308       }
309     }
310
311     // Making solids from bounding planes.
312     TopoDS_Shell aToShell, aFromShell;
313     TopoDS_Solid aToSolid, aFromSolid;
314     const TopoDS_Shape& aToShape   = aBoundingToShape->impl<TopoDS_Shape>();
315     const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
316     TopoDS_Face aToFace   = TopoDS::Face(aToShape);
317     TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
318     BRep_Builder aBoundingBuilder;
319     aBoundingBuilder.MakeShell(aToShell);
320     aBoundingBuilder.Add(aToShell, aToShape);
321     aBoundingBuilder.MakeShell(aFromShell);
322     aBoundingBuilder.Add(aFromShell, aFromShape);
323     aBoundingBuilder.MakeSolid(aToSolid);
324     aBoundingBuilder.Add(aToSolid, aToShell);
325     aBoundingBuilder.MakeSolid(aFromSolid);
326     aBoundingBuilder.Add(aFromSolid, aFromShell);
327
328     // Cutting with to plane.
329     BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
330     aToCutBuilder->Build();
331     if(!aToCutBuilder->IsDone()) {
332       return;
333     }
334     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
335     aResult = aToCutBuilder->Shape();
336     if(aResult.ShapeType() == TopAbs_COMPOUND) {
337       aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
338     }
339     if(aShapeTypeToExp == TopAbs_FACE) {
340       const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
341       for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
342         GeomShapePtr aGeomSh(new GeomAPI_Shape());
343         aGeomSh->setImpl(new TopoDS_Shape(anIt.Value()));
344         this->addToShape(aGeomSh);
345       }
346     }
347
348     // Cutting with from plane.
349     BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
350     aFromCutBuilder->Build();
351     if(!aFromCutBuilder->IsDone()) {
352       return;
353     }
354     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
355     aResult = aFromCutBuilder->Shape();
356     TopoDS_Iterator aCheckIt(aResult);
357     if(!aCheckIt.More()) {
358       return;
359     }
360     if(aResult.ShapeType() == TopAbs_COMPOUND) {
361       aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
362     }
363     if(aShapeTypeToExp == TopAbs_FACE) {
364       const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
365       for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
366         GeomShapePtr aGeomSh(new GeomAPI_Shape());
367         aGeomSh->setImpl(new TopoDS_Shape(anIt.Value()));
368         this->addFromShape(aGeomSh);
369       }
370     }
371
372     // Naming for extrusion from vertex, edge.
373     for(TopExp_Explorer anExp(aResult, aShapeTypeToExp); anExp.More(); anExp.Next()) {
374       const TopoDS_Shape& aShape = anExp.Current();
375       if(aShapeTypeToExp == TopAbs_VERTEX) {
376         gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
377         IntTools_Context anIntTools;
378         if(anIntTools.IsValidPointForFace(aPnt, aToFace, Precision::Confusion()) == Standard_True) {
379           GeomShapePtr aGeomSh(new GeomAPI_Shape());
380           aGeomSh->setImpl(new TopoDS_Shape(aShape));
381           this->addToShape(aGeomSh);
382         }
383         if(anIntTools.IsValidPointForFace(aPnt, aFromFace, Precision::Confusion()) == Standard_True) {
384           GeomShapePtr aGeomSh(new GeomAPI_Shape());
385           aGeomSh->setImpl(new TopoDS_Shape(aShape));
386           this->addFromShape(aGeomSh);
387         }
388       } else if(aShapeTypeToExp == TopAbs_EDGE) {
389         TopoDS_Edge anEdge = TopoDS::Edge(aShape);
390         BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, aToFace);
391         anEdgeCheck.Perform();
392         if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
393           GeomShapePtr aGeomSh(new GeomAPI_Shape());
394           aGeomSh->setImpl(new TopoDS_Shape(aShape));
395           this->addToShape(aGeomSh);
396         }
397         anEdgeCheck.Init(anEdge, aFromFace);
398         anEdgeCheck.Perform();
399         if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
400           GeomShapePtr aGeomSh(new GeomAPI_Shape());
401           aGeomSh->setImpl(new TopoDS_Shape(aShape));
402           this->addFromShape(aGeomSh);
403         }
404       } else {
405         break;
406       }
407     }
408
409     if(aResult.ShapeType() == TopAbs_COMPOUND) {
410       GeomShapePtr aCompound(new GeomAPI_Shape);
411       aCompound->setImpl(new TopoDS_Shape(aResult));
412       ListOfShape aCompSolids, aFreeSolids;
413       GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids);
414       if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) {
415         aResult = aCompSolids.front()->impl<TopoDS_Shape>();
416       } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) {
417         TopoDS_Compound aResultComp;
418         TopoDS_Builder aBuilder;
419         aBuilder.MakeCompound(aResultComp);
420         for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) {
421           aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
422         }
423         for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) {
424           aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
425         }
426         aResult = aResultComp;
427       }
428     }
429   }
430
431   // Setting result.
432   if(aResult.IsNull()) {
433     return;
434   }
435   GeomShapePtr aGeomSh(new GeomAPI_Shape());
436   aGeomSh->setImpl(new TopoDS_Shape(aResult));
437   this->setShape(aGeomSh);
438   this->setDone(true);
439 }