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 #include <BRepTools.hxx>
36 //=================================================================================================
37 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
38 const double theToSize,
39 const double theFromSize)
41 build(theBaseShape, std::shared_ptr<GeomAPI_Dir>(), GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize);
44 //=================================================================================================
45 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
46 const std::shared_ptr<GeomAPI_Dir> theDirection,
47 const double theToSize,
48 const double theFromSize)
50 build(theBaseShape, theDirection, GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize);
53 //=================================================================================================
54 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
55 const GeomShapePtr theToShape,
56 const double theToSize,
57 const GeomShapePtr theFromShape,
58 const double theFromSize)
60 build(theBaseShape, std::shared_ptr<GeomAPI_Dir>(), theToShape, theToSize, theFromShape, theFromSize);
63 //=================================================================================================
64 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
65 const std::shared_ptr<GeomAPI_Dir> theDirection,
66 const GeomShapePtr theToShape,
67 const double theToSize,
68 const GeomShapePtr theFromShape,
69 const double theFromSize)
71 build(theBaseShape, theDirection, theToShape, theToSize, theFromShape, theFromSize);
74 //=================================================================================================
75 void GeomAlgoAPI_Prism::build(const GeomShapePtr& theBaseShape,
76 const std::shared_ptr<GeomAPI_Dir> theDirection,
77 const GeomShapePtr& theToShape,
78 const double theToSize,
79 const GeomShapePtr& theFromShape,
80 const double theFromSize)
82 if(!theBaseShape.get() ||
83 (((!theFromShape.get() && !theToShape.get()) || (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape)))
84 && (theFromSize == -theToSize))) {
88 // Getting base shape.
89 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
90 TopAbs_ShapeEnum aShapeTypeToExp;
91 switch(aBaseShape.ShapeType()) {
93 aShapeTypeToExp = TopAbs_VERTEX;
97 aShapeTypeToExp = TopAbs_EDGE;
101 aShapeTypeToExp = TopAbs_FACE;
107 // Getting direction.
109 std::shared_ptr<GeomAPI_Pnt> aBaseLoc;
110 std::shared_ptr<GeomAPI_Dir> aBaseDir;
111 GeomShapePtr aBasePlane;
112 const bool isBoundingShapesSet = theFromShape.get() || theToShape.get();
113 BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
114 if(aBaseShape.ShapeType() == TopAbs_VERTEX || aBaseShape.ShapeType() == TopAbs_EDGE ||
115 aFindPlane.Found() != Standard_True) {
116 // Direction and both bounding planes should be set or empty.
117 if(!theDirection.get() || (isBoundingShapesSet && (!theToShape.get() || !theFromShape.get()))) {
121 aBaseDir = theDirection;
122 aDirVec = theDirection->impl<gp_Dir>();
124 Handle(Geom_Plane) aPlane = aFindPlane.Plane();
125 gp_Pnt aLoc = aPlane->Axis().Location();
126 aDirVec = aPlane->Axis().Direction();
128 aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
129 aBaseDir.reset(new GeomAPI_Dir(aDirVec.X(), aDirVec.Y(), aDirVec.Z()));
130 aBasePlane = GeomAlgoAPI_FaceBuilder::planarFace(aBaseLoc, aBaseDir);
133 TopoDS_Shape aResult;
134 if(!isBoundingShapesSet) {
135 // Moving base shape.
137 aTrsf.SetTranslation(aDirVec * -theFromSize);
138 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
139 if(!aTransformBuilder) {
142 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
143 if(!aTransformBuilder->IsDone()) {
146 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
149 BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * (theFromSize + theToSize));
153 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
154 if(!aPrismBuilder->IsDone()) {
157 aResult = aPrismBuilder->Shape();
160 for(TopExp_Explorer anExp(aMovedBase, aShapeTypeToExp); anExp.More(); anExp.Next()) {
161 const TopoDS_Shape& aFace = anExp.Current();
162 GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
163 aFromShape->setImpl(new TopoDS_Shape(aPrismBuilder->FirstShape(aFace)));
164 aToShape->setImpl(new TopoDS_Shape(aPrismBuilder->LastShape(aFace)));
165 this->addFromShape(aFromShape);
166 this->addToShape(aToShape);
169 GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
170 GeomShapePtr aBoundingToShape = theToShape ? theToShape : aBasePlane;
172 // Moving prism bounding faces according to "from" and "to" sizes.
173 std::shared_ptr<GeomAPI_Face> aFromFace(new GeomAPI_Face(aBoundingFromShape));
174 std::shared_ptr<GeomAPI_Pln> aFromPln = aFromFace->getPlane();
175 std::shared_ptr<GeomAPI_Pnt> aFromLoc = aFromPln->location();
176 std::shared_ptr<GeomAPI_Dir> aFromDir = aFromPln->direction();
178 std::shared_ptr<GeomAPI_Face> aToFace(new GeomAPI_Face(aBoundingToShape));
179 std::shared_ptr<GeomAPI_Pln> aToPln = aToFace->getPlane();
180 std::shared_ptr<GeomAPI_Pnt> aToLoc = aToPln->location();
181 std::shared_ptr<GeomAPI_Dir> aToDir = aToPln->direction();
183 bool aSign = aFromLoc->xyz()->dot(aBaseDir->xyz()) > aToLoc->xyz()->dot(aBaseDir->xyz());
185 std::shared_ptr<GeomAPI_Pnt> aFromPnt(new GeomAPI_Pnt(aFromLoc->xyz()->added(aBaseDir->xyz()->multiplied(
186 aSign ? theFromSize : -theFromSize))));
187 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
189 std::shared_ptr<GeomAPI_Pnt> aToPnt(new GeomAPI_Pnt(aToLoc->xyz()->added(aBaseDir->xyz()->multiplied(
190 aSign ? -theToSize : theToSize))));
191 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
193 // Getting bounding box for base shape.
195 BRepBndLib::Add(aBaseShape, aBndBox);
196 Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
197 Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
198 Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
201 for(int i = 0; i < 2; i++) {
202 for(int j = 0; j < 2; j++) {
203 for(int k = 0; k < 2; k++) {
204 aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
210 // Project points to bounding planes. Search max distance to them.
211 IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
212 IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
213 Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
214 for(int i = 0; i < 8; i++) {
215 gp_Lin aLine(aPoints[i], aDirVec);
216 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
217 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
218 if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
221 const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
222 const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
223 if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
224 aMaxToDist = aPoints[i].Distance(aPntOnToFace);
226 if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
227 aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
231 // We added 1 just to be sure that prism is long enough for boolean operation.
232 double aPrismLength = aMaxToDist + aMaxFromDist + 1;
234 // Moving base shape.
236 aTrsf.SetTranslation(aDirVec * -aPrismLength);
237 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
238 if(!aTransformBuilder) {
241 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aTransformBuilder)));
242 if(!aTransformBuilder->IsDone()) {
245 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
248 BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * 2 * aPrismLength);
252 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aPrismBuilder)));
253 if(!aPrismBuilder->IsDone()) {
256 aResult = aPrismBuilder->Shape();
258 // Orienting bounding planes.
259 std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
260 const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
261 gp_Lin aLine(aCentrePnt, aDirVec);
262 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
263 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
264 Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
265 Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
266 if(aToParameter > aFromParameter) {
267 gp_Vec aVec = aToDir->impl<gp_Dir>();
268 if((aVec * aDirVec) > 0) {
269 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
270 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
272 aVec = aFromDir->impl<gp_Dir>();
273 if((aVec * aDirVec) < 0) {
274 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
275 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
278 gp_Vec aVec = aToDir->impl<gp_Dir>();
279 if((aVec * aDirVec) < 0) {
280 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
281 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
283 aVec = aFromDir->impl<gp_Dir>();
284 if((aVec * aDirVec) > 0) {
285 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
286 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
290 // Making solids from bounding planes.
291 TopoDS_Shell aToShell, aFromShell;
292 TopoDS_Solid aToSolid, aFromSolid;
293 const TopoDS_Shape& aToShape = aBoundingToShape->impl<TopoDS_Shape>();
294 const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
295 BRep_Builder aBoundingBuilder;
296 aBoundingBuilder.MakeShell(aToShell);
297 aBoundingBuilder.Add(aToShell, aToShape);
298 aBoundingBuilder.MakeShell(aFromShell);
299 aBoundingBuilder.Add(aFromShell, aFromShape);
300 aBoundingBuilder.MakeSolid(aToSolid);
301 aBoundingBuilder.Add(aToSolid, aToShell);
302 aBoundingBuilder.MakeSolid(aFromSolid);
303 aBoundingBuilder.Add(aFromSolid, aFromShell);
305 // Cutting with to plane.
306 BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
307 aToCutBuilder->Build();
308 if(!aToCutBuilder->IsDone()) {
311 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
312 const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
313 for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
314 GeomShapePtr aShape(new GeomAPI_Shape());
315 aShape->setImpl(new TopoDS_Shape(anIt.Value()));
316 this->addToShape(aShape);
318 aResult = aToCutBuilder->Shape();
319 if(aResult.ShapeType() == TopAbs_COMPOUND) {
320 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
323 // Cutting with from plane.
324 BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
325 aFromCutBuilder->Build();
326 if(!aFromCutBuilder->IsDone()) {
329 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
330 const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
331 for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
332 GeomShapePtr aShape(new GeomAPI_Shape());
333 aShape->setImpl(new TopoDS_Shape(anIt.Value()));
334 this->addFromShape(aShape);
336 aResult = aFromCutBuilder->Shape();
338 TopoDS_Iterator anIt(aResult);
342 if(aResult.ShapeType() == TopAbs_COMPOUND) {
343 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
345 if(aResult.ShapeType() == TopAbs_COMPOUND) {
346 GeomShapePtr aCompound(new GeomAPI_Shape);
347 aCompound->setImpl(new TopoDS_Shape(aResult));
348 ListOfShape aCompSolids, aFreeSolids;
349 GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids);
350 if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) {
351 aResult = aCompSolids.front()->impl<TopoDS_Shape>();
352 } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) {
353 TopoDS_Compound aResultComp;
354 TopoDS_Builder aBuilder;
355 aBuilder.MakeCompound(aResultComp);
356 for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) {
357 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
359 for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) {
360 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
362 aResult = aResultComp;
368 if(aResult.IsNull()) {
371 GeomShapePtr aShape(new GeomAPI_Shape());
372 aShape->setImpl(new TopoDS_Shape(aResult));
373 this->setShape(aShape);