1 // Copyright (C) 2014-2019 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "GeomAlgoAPI_Prism.h"
22 #include <GeomAPI_Ax1.h>
23 #include <GeomAPI_Dir.h>
24 #include <GeomAPI_Face.h>
25 #include <GeomAPI_Pln.h>
26 #include <GeomAPI_Pnt.h>
27 #include <GeomAPI_ShapeExplorer.h>
28 #include <GeomAPI_XYZ.h>
30 #include <GeomAlgoAPI_CompoundBuilder.h>
31 #include <GeomAlgoAPI_DFLoader.h>
32 #include <GeomAlgoAPI_FaceBuilder.h>
33 #include <GeomAlgoAPI_Offset.h>
34 #include <GeomAlgoAPI_Partition.h>
35 #include <GeomAlgoAPI_ShapeTools.h>
36 #include <GeomAlgoAPI_Translation.h>
38 #include <Bnd_Box.hxx>
39 #include <BRep_Builder.hxx>
40 #include <BRepAlgoAPI_Cut.hxx>
41 #include <BRepBndLib.hxx>
42 #include <BRepBuilderAPI_FindPlane.hxx>
43 #include <BRepBuilderAPI_Transform.hxx>
44 #include <BRepTools.hxx>
45 #include <Geom_Curve.hxx>
46 #include <Geom2d_Curve.hxx>
47 #include <BRepLib_CheckCurveOnSurface.hxx>
48 #include <BRepPrimAPI_MakePrism.hxx>
49 #include <Geom_Plane.hxx>
50 #include <Geom_RectangularTrimmedSurface.hxx>
52 #include <IntAna_IntConicQuad.hxx>
53 #include <IntAna_Quadric.hxx>
54 #include <IntTools_Context.hxx>
55 #include <TopExp_Explorer.hxx>
57 #include <TopoDS_Edge.hxx>
58 #include <TopoDS_Shell.hxx>
59 #include <TopoDS_Solid.hxx>
60 #include <TopTools_ListIteratorOfListOfShape.hxx>
63 /// Expand planar face to cover the bounding box if theOriginalShape is planar.
64 /// Otherwise, return the same shape;
65 static GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
66 const Bnd_Box& theBaseShapeBB);
68 /// Build offset for the given shape.
69 /// If the offset algorithm failed, translate the shape along the direction.
70 static GeomShapePtr buildOffset(const GeomShapePtr& theShape,
71 const double theOffset,
72 const GeomDirPtr theDirection,
73 GeomAlgoAPI_MakeShapeList& theMakeShapeList);
75 /// Collect base faces of the prism.
76 static void collectPrismBases(const TopoDS_Shape& theBaseShape,
77 BRepPrimAPI_MakePrism& thePrismAlgo,
78 ListOfShape& theBoundaries,
79 const GeomAPI_Shape::ShapeType theTypeToExp);
81 /// Collect all solids which contain boundaries but do not contain bases of prism.
82 static GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
83 const ListOfShape& theBoundaries,
84 const ListOfShape& theShapesToExclude,
85 const GeomAPI_Shape::ShapeType theTypeToExp);
87 static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
88 const TopoDS_Shape& theBase,
89 const TopAbs_ShapeEnum theType,
90 BRepPrimAPI_MakePrism* thePrismBuilder);
92 static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
93 const TopoDS_Shape& theResult,
94 const TopAbs_ShapeEnum theType,
95 const TopoDS_Face& theToFace,
96 const TopoDS_Face& theFromFace);
98 static GeomShapePtr toShape(const TopoDS_Shape& theShape)
100 GeomShapePtr aShape(new GeomAPI_Shape());
101 aShape->setImpl(new TopoDS_Shape(theShape));
106 //==================================================================================================
107 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
108 const GeomDirPtr theDirection,
109 const GeomShapePtr theToShape,
110 const double theToSize,
111 const GeomShapePtr theFromShape,
112 const double theFromSize)
114 if(!theBaseShape.get() ||
115 (((!theFromShape.get() && !theToShape.get()) ||
116 (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape)))
117 && (theFromSize == -theToSize))) {
121 // Getting base shape.
122 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
123 GeomAPI_Shape::ShapeType aShapeTypeToExp;
124 switch(aBaseShape.ShapeType()) {
126 aShapeTypeToExp = GeomAPI_Shape::VERTEX;
130 aShapeTypeToExp = GeomAPI_Shape::EDGE;
134 aShapeTypeToExp = GeomAPI_Shape::FACE;
136 case TopAbs_COMPOUND:
137 aShapeTypeToExp = GeomAPI_Shape::COMPOUND;
143 // Getting direction.
145 std::shared_ptr<GeomAPI_Pnt> aBaseLoc;
146 std::shared_ptr<GeomAPI_Dir> aBaseDir;
147 BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
148 if(aFindPlane.Found() == Standard_True)
150 Handle(Geom_Plane) aPlane;
151 if(aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) {
152 TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
153 const TopoDS_Shape& aFace = anExp.Current();
154 Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace));
155 if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
156 Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
157 Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
158 aSurface = aTrimSurface->BasisSurface();
160 if(aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
163 aPlane = Handle(Geom_Plane)::DownCast(aSurface);
165 aPlane = aFindPlane.Plane();
167 gp_Pnt aLoc = aPlane->Axis().Location();
168 aBaseVec = aPlane->Axis().Direction();
169 aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
170 aBaseDir.reset(new GeomAPI_Dir(aBaseVec.X(), aBaseVec.Y(), aBaseVec.Z()));
172 else if (theDirection.get())
174 aBaseDir = theDirection;
175 aBaseVec = theDirection->impl<gp_Dir>();
182 if(!aBaseLoc.get()) {
184 gp_XYZ aDirXYZ = aBaseVec.XYZ();
185 Standard_Real aMinParam = Precision::Infinite();
186 for(TopExp_Explorer anExp(aBaseShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) {
187 const TopoDS_Shape& aVertex = anExp.Current();
188 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
189 double aParam = aDirXYZ.Dot(aPnt.XYZ());
190 if(aParam < aMinParam) {
195 aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
199 std::shared_ptr<GeomAPI_Dir> anExtDir;
200 if (theDirection.get())
202 anExtDir = theDirection;
203 anExtVec = theDirection->impl<gp_Dir>();
208 anExtVec = aBaseDir->impl<gp_Dir>();
212 TopoDS_Shape aResult;
213 const bool isBoundingShapesSet = theFromShape.get() || theToShape.get();
214 if(!isBoundingShapesSet) {
215 buildBySizes(theBaseShape, anExtDir, theToSize, theFromSize, aShapeTypeToExp);
217 GeomShapePtr aBasePlane = GeomAlgoAPI_FaceBuilder::squareFace(aBaseLoc, aBaseDir, 100.0);
219 GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
220 GeomShapePtr aBoundingToShape = theToShape ? theToShape : aBasePlane;
222 bool isFromShapePlanar = aBoundingFromShape->isPlanar();
223 bool isToShapePlanar = aBoundingToShape->isPlanar();
225 // Set signs of offsets if both bounding shapes are planar
226 if (isFromShapePlanar && isToShapePlanar) {
227 std::shared_ptr<GeomAPI_Pln> aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane();
228 std::shared_ptr<GeomAPI_Pln> aToPln = GeomAPI_Face(aBoundingToShape).getPlane();
229 buildByPlanes(theBaseShape, anExtDir,
231 aFromPln, theFromSize,
235 buildByFaces(theBaseShape, anExtDir,
236 aBoundingToShape, theToSize, isToShapePlanar,
237 aBoundingFromShape, theFromSize, isFromShapePlanar,
243 //==================================================================================================
244 void GeomAlgoAPI_Prism::buildBySizes(const GeomShapePtr theBaseShape,
245 const GeomDirPtr theDirection,
246 const double theToSize,
247 const double theFromSize,
248 const GeomAPI_Shape::ShapeType theTypeToExp)
250 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
251 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
253 // Moving base shape.
255 aTrsf.SetTranslation(anExtVec * -theFromSize);
256 BRepBuilderAPI_Transform* aTransformBuilder =
257 new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
258 if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
261 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
262 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
263 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
266 BRepPrimAPI_MakePrism* aPrismBuilder =
267 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * (theFromSize + theToSize));
268 if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
271 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
272 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
273 TopoDS_Shape aResult = aPrismBuilder->Shape();
276 if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
277 storeGenerationHistory(this, aMovedBase, TopAbs_EDGE, aPrismBuilder);
278 storeGenerationHistory(this, aMovedBase, TopAbs_FACE, aPrismBuilder);
280 storeGenerationHistory(this, aMovedBase, (TopAbs_ShapeEnum)theTypeToExp, aPrismBuilder);
284 if (!aResult.IsNull()) {
285 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
286 this->setShape(toShape(aResult));
291 //==================================================================================================
292 void GeomAlgoAPI_Prism::buildByPlanes(const GeomShapePtr theBaseShape,
293 const GeomDirPtr theDirection,
294 const GeomPlanePtr theToPlane,
295 const double theToSize,
296 const GeomPlanePtr theFromPlane,
297 const double theFromSize,
298 const GeomAPI_Shape::ShapeType theTypeToExp)
300 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
301 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
303 // Moving prism bounding faces according to "from" and "to" sizes.
304 std::shared_ptr<GeomAPI_Pnt> aFromLoc = theFromPlane->location();
305 std::shared_ptr<GeomAPI_Dir> aFromDir = theFromPlane->direction();
307 std::shared_ptr<GeomAPI_Pnt> aToLoc = theToPlane->location();
308 std::shared_ptr<GeomAPI_Dir> aToDir = theToPlane->direction();
310 std::shared_ptr<GeomAPI_XYZ> anExtDir = theDirection->xyz();
311 bool aSign = aFromLoc->xyz()->dot(anExtDir) > aToLoc->xyz()->dot(anExtDir);
313 std::shared_ptr<GeomAPI_Pnt> aFromPnt(
314 new GeomAPI_Pnt(aFromLoc->xyz()->added(anExtDir->multiplied(
315 aSign ? theFromSize : -theFromSize))));
316 GeomShapePtr aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
318 std::shared_ptr<GeomAPI_Pnt> aToPnt(
319 new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->multiplied(
320 aSign ? -theToSize : theToSize))));
321 GeomShapePtr aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
323 // Getting bounding box for base shape.
325 BRepBndLib::Add(aBaseShape, aBndBox);
326 Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
327 Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
328 Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
331 for(int i = 0; i < 2; i++) {
332 for(int j = 0; j < 2; j++) {
333 for(int k = 0; k < 2; k++) {
334 aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
340 // Project points to bounding planes. Search max distance to them.
341 IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
342 IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
343 Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
344 for(int i = 0; i < 8; i++) {
345 gp_Lin aLine(aPoints[i], anExtVec);
346 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
347 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
348 if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
351 const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
352 const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
353 if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
354 aMaxToDist = aPoints[i].Distance(aPntOnToFace);
356 if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
357 aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
361 // We added 1 just to be sure that prism is long enough for boolean operation.
362 double aPrismLength = aMaxToDist + aMaxFromDist + 1;
364 // Moving base shape.
366 aTrsf.SetTranslation(anExtVec * -aPrismLength);
367 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
368 if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
371 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
372 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
373 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
376 BRepPrimAPI_MakePrism* aPrismBuilder =
377 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
378 if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
381 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
382 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
383 TopoDS_Shape aResult = aPrismBuilder->Shape();
385 BRepBndLib::Add(aResult, aBndBox);
386 Standard_Real aBndBoxSize = aBndBox.CornerMin().Distance(aBndBox.CornerMax());
388 // Orienting bounding planes.
389 std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
390 const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
391 gp_Lin aLine(aCentrePnt, anExtVec);
392 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
393 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
394 Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
395 Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
396 static const double THE_FACE_SIZE_COEFF = 10.0;
397 if(aToParameter > aFromParameter) {
398 gp_Vec aVec = aToDir->impl<gp_Dir>();
399 if((aVec * anExtVec) > 0) {
400 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
402 GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
404 aVec = aFromDir->impl<gp_Dir>();
405 if((aVec * anExtVec) < 0) {
406 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
408 GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
411 gp_Vec aVec = aToDir->impl<gp_Dir>();
412 if((aVec * anExtVec) < 0) {
413 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
415 GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
417 aVec = aFromDir->impl<gp_Dir>();
418 if((aVec * anExtVec) > 0) {
419 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
421 GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
426 const TopoDS_Shape& aToShape = aBoundingToShape->impl<TopoDS_Shape>();
427 const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
428 TopoDS_Face aToFace = TopoDS::Face(aToShape);
429 TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
431 // Solid based on "To" bounding plane
432 gp_Vec aNormal = aToDir->impl<gp_Dir>();
433 BRepPrimAPI_MakePrism* aToPrismBuilder =
434 new BRepPrimAPI_MakePrism(aToShape, aNormal * (-2.0 * aBndBoxSize));
435 if (!aToPrismBuilder || !aToPrismBuilder->IsDone()) {
438 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
439 new GeomAlgoAPI_MakeShape(aToPrismBuilder)));
440 TopoDS_Shape aToSolid = aToPrismBuilder->Shape();
442 // Cutting with to plane.
443 BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
444 aToCutBuilder->Build();
445 if(!aToCutBuilder->IsDone()) {
448 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
449 new GeomAlgoAPI_MakeShape(aToCutBuilder)));
450 aResult = aToCutBuilder->Shape();
451 if(aResult.ShapeType() == TopAbs_COMPOUND) {
452 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
454 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
455 TopTools_ListOfShape aPrismShapes = aToPrismBuilder->Modified(aToShape);
456 if (aPrismShapes.IsEmpty())
457 aPrismShapes.Append(aToShape);
458 for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
459 const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(anIt1.Value());
460 for (TopTools_ListIteratorOfListOfShape anIt2(aToShapes); anIt2.More(); anIt2.Next()) {
461 GeomShapePtr aGeomSh = toShape(anIt2.Value());
462 fixOrientation(aGeomSh);
463 this->addToShape(aGeomSh);
468 // Solid based on "From" bounding plane
469 aNormal = aFromDir->impl<gp_Dir>();
470 BRepPrimAPI_MakePrism* aFromPrismBuilder =
471 new BRepPrimAPI_MakePrism(aFromShape, aNormal * (-aBndBoxSize));
472 if (!aFromPrismBuilder || !aFromPrismBuilder->IsDone()) {
475 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
476 new GeomAlgoAPI_MakeShape(aFromPrismBuilder)));
477 TopoDS_Shape aFromSolid = aFromPrismBuilder->Shape();
479 // Cutting with from plane.
480 BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
481 aFromCutBuilder->Build();
482 if(!aFromCutBuilder->IsDone()) {
485 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
486 new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
487 aResult = aFromCutBuilder->Shape();
488 TopoDS_Iterator aCheckIt(aResult);
489 if(!aCheckIt.More()) {
492 if(aResult.ShapeType() == TopAbs_COMPOUND) {
493 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
495 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
496 TopTools_ListOfShape aPrismShapes = aFromPrismBuilder->Modified(aFromShape);
497 if (aPrismShapes.IsEmpty())
498 aPrismShapes.Append(aFromShape);
499 for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
500 const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(anIt1.Value());
501 for (TopTools_ListIteratorOfListOfShape anIt2(aFromShapes); anIt2.More(); anIt2.Next()) {
502 GeomShapePtr aGeomSh = toShape(anIt2.Value());
503 fixOrientation(aGeomSh);
504 this->addFromShape(aGeomSh);
509 // Naming for extrusion from vertex, edge.
510 if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
511 storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
512 storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
514 storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace);
517 if(aResult.ShapeType() == TopAbs_COMPOUND) {
518 GeomShapePtr aGeomShape = toShape(aResult);
519 ListOfShape aResults;
520 aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
521 GeomAPI_Shape::COMPSOLID,
523 aResult = aGeomShape->impl<TopoDS_Shape>();
527 if (!aResult.IsNull()) {
528 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
529 this->setShape(toShape(aResult));
534 //==================================================================================================
535 void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr theBaseShape,
536 const GeomDirPtr theDirection,
537 const GeomShapePtr theToShape,
538 const double theToSize,
539 const bool theToIsPlanar,
540 const GeomShapePtr theFromShape,
541 const double theFromSize,
542 const bool theFromIsPlanar,
543 const GeomAPI_Shape::ShapeType theTypeToExp)
545 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
546 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
548 // Moving prism bounding faces according to "from" and "to" sizes.
549 GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, theFromSize, theDirection, *this);
550 GeomShapePtr aBoundingToShape = buildOffset(theToShape, theToSize, theDirection, *this);
552 // Bounding box for shapes used in prism building.
554 BRepBndLib::Add(aBaseShape, aBndBox);
555 BRepBndLib::Add(aBoundingFromShape->impl<TopoDS_Shape>(), aBndBox);
556 BRepBndLib::Add(aBoundingToShape->impl<TopoDS_Shape>(), aBndBox);
557 double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax());
561 aTrsf.SetTranslation(anExtVec * -aPrismLength);
562 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
563 if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
566 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
567 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
568 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
571 BRepPrimAPI_MakePrism* aPrismBuilder =
572 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
573 if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
576 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
577 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
579 GeomShapePtr aResult = toShape(aPrismBuilder->Shape());
582 ListOfShape aPrismBaseFaces;
583 collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp);
585 // Build planar faces intersecting the prism fully.
586 BRepBndLib::Add(aResult->impl<TopoDS_Shape>(), aBndBox);
587 aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox);
588 aBoundingToShape = buildPlanarFace(aBoundingToShape, aBndBox);
590 // Perform partition.
591 ListOfShape anObjects, aTools;
592 anObjects.push_back(aResult);
593 aTools.push_back(aBoundingFromShape);
594 aTools.push_back(aBoundingToShape);
596 GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools));
597 if (!aPartition->isDone())
600 this->appendAlgo(aPartition);
602 // Collect pieces of boundary shapes, split by Partition.
603 if (theFromIsPlanar) {
604 ListOfShape anImagesFrom;
605 aPartition->modified(aBoundingFromShape, anImagesFrom);
606 for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt)
611 ListOfShape anImagesTo;
612 aPartition->modified(aBoundingToShape, anImagesTo);
613 for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt)
617 // Collect results which have both boundaries, selected for extrusion,
618 // but which do not contain top and bottom faces of the prism
619 // (these faces are treated as infinitely distant).
620 aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp);
621 if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) {
622 ListOfShape aResults;
623 aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult,
624 theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID,
627 if (aResults.size() > 1 &&
628 (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) ||
629 GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) {
630 // results shuold not have shared topology
631 aResult = GeomShapePtr();
636 this->setShape(aResult);
642 // Auxilary functions:
643 //==================================================================================================
644 GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
645 const Bnd_Box& theBaseShapeBB)
647 GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
649 return theOriginalShape;
651 gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
652 gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
653 double aSize = aCornerMin.SquareDistance(aCornerMax);
655 gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
658 for (int x = 0; x < 2; ++x) {
659 aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
660 for (int y = 0; y < 2; ++y) {
661 aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
662 for (int z = 0; z < 2; ++z) {
663 aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
664 double aDist = aCurPnt.SquareDistance(aLocation);
672 return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
675 //==================================================================================================
676 GeomShapePtr buildOffset(const GeomShapePtr& theShape,
677 const double theOffset,
678 const GeomDirPtr theDirection,
679 GeomAlgoAPI_MakeShapeList& theMakeShapeList)
681 if (Abs(theOffset) < Precision::Confusion())
682 return theShape; // no need zero offset
684 GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
685 if (!anAlgo->isDone()) {
686 // offset not done, perform translation
687 std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
688 anAxis->setDir(theDirection);
689 anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
692 GeomShapePtr aResult = theShape;
693 if (anAlgo->isDone()) {
694 theMakeShapeList.appendAlgo(anAlgo);
695 aResult = anAlgo->shape();
700 //==================================================================================================
701 void collectPrismBases(const TopoDS_Shape& theBaseShape,
702 BRepPrimAPI_MakePrism& thePrismAlgo,
703 ListOfShape& theBoundaries,
704 const GeomAPI_Shape::ShapeType theTypeToExp)
706 for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
707 anExp.More(); anExp.Next()) {
708 theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
709 theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
713 //==================================================================================================
714 typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
716 bool isShapeApplicable(const GeomShapePtr& theSolid,
717 const std::list<ListOfShape>& theShapesToExist,
718 const SetOfShape& theShapesToExclude,
719 const GeomAPI_Shape::ShapeType theTypeToExp)
722 for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
723 aFExp.more(); aFExp.next()) {
724 GeomShapePtr aCurrent = aFExp.current();
725 if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
727 aFaces.insert(aCurrent);
730 // check all faces are in solid
731 bool isApplicable = true;
732 for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
733 it1 != theShapesToExist.end() && isApplicable; ++it1) {
734 ListOfShape::const_iterator it2 = it1->begin();
735 for (; it2 != it1->end(); ++it2)
736 if (aFaces.find(*it2) != aFaces.end())
738 isApplicable = it2 != it1->end();
743 void collectModified(const GeomMakeShapePtr& theOperation,
744 const ListOfShape& theShapes,
745 std::list<ListOfShape>& theModified)
747 for (ListOfShape::const_iterator anIt = theShapes.begin();
748 anIt != theShapes.end(); ++anIt) {
749 theModified.push_back(ListOfShape());
750 theOperation->modified(*anIt, theModified.back());
751 theOperation->generated(*anIt, theModified.back());
752 theModified.back().push_back(*anIt);
756 GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
757 const ListOfShape& theBoundaries,
758 const ListOfShape& theShapesToExclude,
759 const GeomAPI_Shape::ShapeType theTypeToExp)
761 ListOfShape aResults;
763 // collect modified shapes
764 std::list<ListOfShape> aModifiedBoundaries;
765 collectModified(theOperation, theBoundaries, aModifiedBoundaries);
767 std::list<ListOfShape> aModifiedExclude;
768 collectModified(theOperation, theShapesToExclude, aModifiedExclude);
769 SetOfShape aTabooShapes;
770 for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
771 anIt != aModifiedExclude.end(); ++anIt)
772 aTabooShapes.insert(anIt->begin(), anIt->end());
774 // type of sub-shapes to explode
775 GeomAPI_Shape::ShapeType aSubshapeType;
776 switch (theTypeToExp) {
777 case GeomAPI_Shape::VERTEX:
778 aSubshapeType = GeomAPI_Shape::EDGE;
780 case GeomAPI_Shape::EDGE:
781 aSubshapeType = GeomAPI_Shape::FACE;
783 case GeomAPI_Shape::FACE:
784 aSubshapeType = GeomAPI_Shape::SOLID;
787 aSubshapeType = GeomAPI_Shape::COMPOUND;
790 // search applicable solids
791 GeomShapePtr anOperationResult = theOperation->shape();
792 for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
793 anExp.more(); anExp.next()) {
794 if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
795 aResults.push_back(anExp.current());
798 GeomShapePtr aResult;
799 if (aResults.size() == 1)
800 aResult = aResults.front();
801 else if (!aResults.empty())
802 aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
806 //==================================================================================================
807 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
808 const TopoDS_Shape& theBase,
809 const TopAbs_ShapeEnum theType,
810 BRepPrimAPI_MakePrism* thePrismBuilder)
812 for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) {
813 const TopoDS_Shape& aShape = anExp.Current();
814 GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
815 aFromShape->setImpl(new TopoDS_Shape(thePrismBuilder->FirstShape(aShape)));
816 aToShape->setImpl(new TopoDS_Shape(thePrismBuilder->LastShape(aShape)));
817 thePrismAlgo->fixOrientation(aFromShape);
818 thePrismAlgo->fixOrientation(aToShape);
819 thePrismAlgo->addFromShape(aFromShape);
820 thePrismAlgo->addToShape(aToShape);
824 //==================================================================================================
825 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
826 const TopoDS_Shape& theResult,
827 const TopAbs_ShapeEnum theType,
828 const TopoDS_Face& theToFace,
829 const TopoDS_Face& theFromFace)
831 for(TopExp_Explorer anExp(theResult, theType); anExp.More(); anExp.Next()) {
832 const TopoDS_Shape& aShape = anExp.Current();
833 GeomShapePtr aGeomSh(new GeomAPI_Shape());
834 if(theType == TopAbs_VERTEX) {
835 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
836 IntTools_Context anIntTools;
837 if(anIntTools.IsValidPointForFace(aPnt,
838 theToFace, Precision::Confusion()) == Standard_True) {
839 aGeomSh->setImpl(new TopoDS_Shape(aShape));
840 thePrismAlgo->fixOrientation(aGeomSh);
841 thePrismAlgo->addToShape(aGeomSh);
843 if(anIntTools.IsValidPointForFace(aPnt,
844 theFromFace, Precision::Confusion()) == Standard_True) {
845 aGeomSh->setImpl(new TopoDS_Shape(aShape));
846 thePrismAlgo->fixOrientation(aGeomSh);
847 thePrismAlgo->addFromShape(aGeomSh);
849 } else if(theType == TopAbs_EDGE) {
850 TopoDS_Edge anEdge = TopoDS::Edge(aShape);
851 BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, theToFace);
852 anEdgeCheck.Perform();
853 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
854 aGeomSh->setImpl(new TopoDS_Shape(aShape));
855 thePrismAlgo->fixOrientation(aGeomSh);
856 thePrismAlgo->addToShape(aGeomSh);
858 anEdgeCheck.Init(anEdge, theFromFace);
859 anEdgeCheck.Perform();
860 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
861 aGeomSh->setImpl(new TopoDS_Shape(aShape));
862 thePrismAlgo->fixOrientation(aGeomSh);
863 thePrismAlgo->addFromShape(aGeomSh);