1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: GeomAlgoAPI_Prism.cpp
5 // Author: Dmitry Bobylev
7 #include "GeomAlgoAPI_Prism.h"
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>
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 <BRepPrimAPI_MakePrism.hxx>
25 #include <Geom_Plane.hxx>
27 #include <IntAna_IntConicQuad.hxx>
28 #include <IntAna_Quadric.hxx>
29 #include <TopExp_Explorer.hxx>
30 #include <TopoDS_Shell.hxx>
31 #include <TopoDS_Solid.hxx>
32 #include <TopTools_ListIteratorOfListOfShape.hxx>
34 //=================================================================================================
35 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
36 const double theToSize,
37 const double theFromSize)
39 build(theBaseShape, std::shared_ptr<GeomAPI_Dir>(), GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize);
42 //=================================================================================================
43 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
44 const std::shared_ptr<GeomAPI_Dir> theDirection,
45 const double theToSize,
46 const double theFromSize)
48 build(theBaseShape, theDirection, GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize);
51 //=================================================================================================
52 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
53 const GeomShapePtr theToShape,
54 const double theToSize,
55 const GeomShapePtr theFromShape,
56 const double theFromSize)
58 build(theBaseShape, std::shared_ptr<GeomAPI_Dir>(), theToShape, theToSize, theFromShape, theFromSize);
61 //=================================================================================================
62 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
63 const std::shared_ptr<GeomAPI_Dir> theDirection,
64 const GeomShapePtr theToShape,
65 const double theToSize,
66 const GeomShapePtr theFromShape,
67 const double theFromSize)
69 build(theBaseShape, theDirection, theToShape, theToSize, theFromShape, theFromSize);
72 //=================================================================================================
73 void GeomAlgoAPI_Prism::build(const GeomShapePtr& theBaseShape,
74 const std::shared_ptr<GeomAPI_Dir> theDirection,
75 const GeomShapePtr& theToShape,
76 const double theToSize,
77 const GeomShapePtr& theFromShape,
78 const double theFromSize)
80 if(!theBaseShape.get() ||
81 (((!theFromShape.get() && !theToShape.get()) || (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape)))
82 && (theFromSize == -theToSize))) {
86 // Getting base shape.
87 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
91 std::shared_ptr<GeomAPI_Pnt> aBaseLoc;
92 std::shared_ptr<GeomAPI_Dir> aBaseDir;
93 GeomShapePtr aBasePlane;
94 const bool isBoundingShapesSet = theFromShape.get() || theToShape.get();
95 BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
96 if(aBaseShape.ShapeType() == TopAbs_VERTEX || aBaseShape.ShapeType() == TopAbs_EDGE ||
97 aFindPlane.Found() != Standard_True) {
98 // Direction and both bounding planes should be set or empty.
99 if(!theDirection.get() || (isBoundingShapesSet && (!theToShape.get() || !theFromShape.get()))) {
103 Handle(Geom_Plane) aPlane = aFindPlane.Plane();
104 gp_Pnt aLoc = aPlane->Axis().Location();
105 aDirVec = aPlane->Axis().Direction();
107 aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
108 aBaseDir.reset(new GeomAPI_Dir(aDirVec.X(), aDirVec.Y(), aDirVec.Z()));
109 aBasePlane = GeomAlgoAPI_FaceBuilder::planarFace(aBaseLoc, aBaseDir);
112 TopoDS_Shape aResult;
113 if(!isBoundingShapesSet) {
114 // Moving base shape.
116 aTrsf.SetTranslation(aDirVec * -theFromSize);
117 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
118 if(!aTransformBuilder) {
121 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
122 if(!aTransformBuilder->IsDone()) {
125 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
128 BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * (theFromSize + theToSize));
132 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
133 if(!aPrismBuilder->IsDone()) {
136 aResult = aPrismBuilder->Shape();
139 for(TopExp_Explorer anExp(aMovedBase, TopAbs_FACE); anExp.More(); anExp.Next()) {
140 const TopoDS_Shape& aFace = anExp.Current();
141 GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
142 aFromShape->setImpl(new TopoDS_Shape(aPrismBuilder->FirstShape(aFace)));
143 aToShape->setImpl(new TopoDS_Shape(aPrismBuilder->LastShape(aFace)));
144 this->addFromShape(aFromShape);
145 this->addToShape(aToShape);
148 GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
149 GeomShapePtr aBoundingToShape = theToShape ? theToShape : aBasePlane;
151 // Moving prism bounding faces according to "from" and "to" sizes.
152 std::shared_ptr<GeomAPI_Face> aFromFace(new GeomAPI_Face(aBoundingFromShape));
153 std::shared_ptr<GeomAPI_Pln> aFromPln = aFromFace->getPlane();
154 std::shared_ptr<GeomAPI_Pnt> aFromLoc = aFromPln->location();
155 std::shared_ptr<GeomAPI_Dir> aFromDir = aFromPln->direction();
157 std::shared_ptr<GeomAPI_Face> aToFace(new GeomAPI_Face(aBoundingToShape));
158 std::shared_ptr<GeomAPI_Pln> aToPln = aToFace->getPlane();
159 std::shared_ptr<GeomAPI_Pnt> aToLoc = aToPln->location();
160 std::shared_ptr<GeomAPI_Dir> aToDir = aToPln->direction();
162 bool aSign = aFromLoc->xyz()->dot(aBaseDir->xyz()) > aToLoc->xyz()->dot(aBaseDir->xyz());
164 std::shared_ptr<GeomAPI_Pnt> aFromPnt(new GeomAPI_Pnt(aFromLoc->xyz()->added(aBaseDir->xyz()->multiplied(
165 aSign ? theFromSize : -theFromSize))));
166 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
168 std::shared_ptr<GeomAPI_Pnt> aToPnt(new GeomAPI_Pnt(aToLoc->xyz()->added(aBaseDir->xyz()->multiplied(
169 aSign ? -theToSize : theToSize))));
170 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
172 // Getting bounding box for base shape.
174 BRepBndLib::Add(aBaseShape, aBndBox);
175 Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
176 Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
177 Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
180 for(int i = 0; i < 2; i++) {
181 for(int j = 0; j < 2; j++) {
182 for(int k = 0; k < 2; k++) {
183 aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
189 // Project points to bounding planes. Search max distance to them.
190 IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
191 IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
192 Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
193 for(int i = 0; i < 8; i++) {
194 gp_Lin aLine(aPoints[i], aDirVec);
195 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
196 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
197 if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
200 const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
201 const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
202 if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
203 aMaxToDist = aPoints[i].Distance(aPntOnToFace);
205 if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
206 aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
210 // We added 1 just to be sure that prism is long enough for boolean operation.
211 double aPrismLength = aMaxToDist + aMaxFromDist + 1;
213 // Moving base shape.
215 aTrsf.SetTranslation(aDirVec * -aPrismLength);
216 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
217 if(!aTransformBuilder) {
220 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
221 if(!aTransformBuilder->IsDone()) {
224 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
227 BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * 2 * aPrismLength);
231 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
232 if(!aPrismBuilder->IsDone()) {
235 aResult = aPrismBuilder->Shape();
237 // Orienting bounding planes.
238 std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
239 const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
240 gp_Lin aLine(aCentrePnt, aDirVec);
241 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
242 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
243 Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
244 Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
245 if(aToParameter > aFromParameter) {
246 gp_Vec aVec = aToDir->impl<gp_Dir>();
247 if((aVec * aDirVec) > 0) {
248 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
249 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
251 aVec = aFromDir->impl<gp_Dir>();
252 if((aVec * aDirVec) < 0) {
253 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
254 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
257 gp_Vec aVec = aToDir->impl<gp_Dir>();
258 if((aVec * aDirVec) < 0) {
259 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
260 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
262 aVec = aFromDir->impl<gp_Dir>();
263 if((aVec * aDirVec) > 0) {
264 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
265 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
269 // Making solids from bounding planes.
270 TopoDS_Shell aToShell, aFromShell;
271 TopoDS_Solid aToSolid, aFromSolid;
272 const TopoDS_Shape& aToShape = aBoundingToShape->impl<TopoDS_Shape>();
273 const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
274 BRep_Builder aBoundingBuilder;
275 aBoundingBuilder.MakeShell(aToShell);
276 aBoundingBuilder.Add(aToShell, aToShape);
277 aBoundingBuilder.MakeShell(aFromShell);
278 aBoundingBuilder.Add(aFromShell, aFromShape);
279 aBoundingBuilder.MakeSolid(aToSolid);
280 aBoundingBuilder.Add(aToSolid, aToShell);
281 aBoundingBuilder.MakeSolid(aFromSolid);
282 aBoundingBuilder.Add(aFromSolid, aFromShell);
284 // Cutting with to plane.
285 BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
286 aToCutBuilder->Build();
287 if(!aToCutBuilder->IsDone()) {
290 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
291 const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
292 for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
293 GeomShapePtr aShape(new GeomAPI_Shape());
294 aShape->setImpl(new TopoDS_Shape(anIt.Value()));
295 this->addToShape(aShape);
297 aResult = aToCutBuilder->Shape();
299 // Cutting with from plane.
300 BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
301 aFromCutBuilder->Build();
302 if(!aFromCutBuilder->IsDone()) {
305 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
306 const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
307 for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
308 GeomShapePtr aShape(new GeomAPI_Shape());
309 aShape->setImpl(new TopoDS_Shape(anIt.Value()));
310 this->addFromShape(aShape);
312 aResult = aFromCutBuilder->Shape();
314 TopExp_Explorer anExp(aResult, TopAbs_SOLID);
318 if(aResult.ShapeType() == TopAbs_COMPOUND) {
319 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
321 if(aResult.ShapeType() == TopAbs_COMPOUND) {
322 GeomShapePtr aCompound(new GeomAPI_Shape);
323 aCompound->setImpl(new TopoDS_Shape(aResult));
324 ListOfShape aCompSolids, aFreeSolids;
325 GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids);
326 if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) {
327 aResult = aCompSolids.front()->impl<TopoDS_Shape>();
328 } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) {
329 TopoDS_Compound aResultComp;
330 TopoDS_Builder aBuilder;
331 aBuilder.MakeCompound(aResultComp);
332 for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) {
333 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
335 for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) {
336 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
338 aResult = aResultComp;
344 if(aResult.IsNull()) {
347 GeomShapePtr aShape(new GeomAPI_Shape());
348 aShape->setImpl(new TopoDS_Shape(aResult));
349 this->setShape(aShape);