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 // Orienting bounding planes.
386 std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
387 const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
388 gp_Lin aLine(aCentrePnt, anExtVec);
389 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
390 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
391 Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
392 Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
393 if(aToParameter > aFromParameter) {
394 gp_Vec aVec = aToDir->impl<gp_Dir>();
395 if((aVec * anExtVec) > 0) {
396 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
397 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
399 aVec = aFromDir->impl<gp_Dir>();
400 if((aVec * anExtVec) < 0) {
401 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
402 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
405 gp_Vec aVec = aToDir->impl<gp_Dir>();
406 if((aVec * anExtVec) < 0) {
407 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
408 aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
410 aVec = aFromDir->impl<gp_Dir>();
411 if((aVec * anExtVec) > 0) {
412 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
413 aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
417 // Making solids from bounding planes.
418 TopoDS_Shell aToShell, aFromShell;
419 TopoDS_Solid aToSolid, aFromSolid;
420 const TopoDS_Shape& aToShape = aBoundingToShape->impl<TopoDS_Shape>();
421 const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
422 TopoDS_Face aToFace = TopoDS::Face(aToShape);
423 TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
424 BRep_Builder aBoundingBuilder;
425 aBoundingBuilder.MakeShell(aToShell);
426 aBoundingBuilder.Add(aToShell, aToShape);
427 aBoundingBuilder.MakeShell(aFromShell);
428 aBoundingBuilder.Add(aFromShell, aFromShape);
429 aBoundingBuilder.MakeSolid(aToSolid);
430 aBoundingBuilder.Add(aToSolid, aToShell);
431 aBoundingBuilder.MakeSolid(aFromSolid);
432 aBoundingBuilder.Add(aFromSolid, aFromShell);
434 // Cutting with to plane.
435 BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
436 aToCutBuilder->Build();
437 if(!aToCutBuilder->IsDone()) {
440 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
441 new GeomAlgoAPI_MakeShape(aToCutBuilder)));
442 aResult = aToCutBuilder->Shape();
443 if(aResult.ShapeType() == TopAbs_COMPOUND) {
444 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
446 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
447 const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
448 for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
449 GeomShapePtr aGeomSh = toShape(anIt.Value());
450 fixOrientation(aGeomSh);
451 this->addToShape(aGeomSh);
455 // Cutting with from plane.
456 BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
457 aFromCutBuilder->Build();
458 if(!aFromCutBuilder->IsDone()) {
461 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
462 new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
463 aResult = aFromCutBuilder->Shape();
464 TopoDS_Iterator aCheckIt(aResult);
465 if(!aCheckIt.More()) {
468 if(aResult.ShapeType() == TopAbs_COMPOUND) {
469 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
471 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
472 const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
473 for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
474 GeomShapePtr aGeomSh = toShape(anIt.Value());
475 fixOrientation(aGeomSh);
476 this->addFromShape(aGeomSh);
480 // Naming for extrusion from vertex, edge.
481 if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
482 storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
483 storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
485 storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace);
488 if(aResult.ShapeType() == TopAbs_COMPOUND) {
489 GeomShapePtr aGeomShape = toShape(aResult);
490 ListOfShape aResults;
491 aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
492 GeomAPI_Shape::COMPSOLID,
494 aResult = aGeomShape->impl<TopoDS_Shape>();
498 if (!aResult.IsNull()) {
499 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
500 this->setShape(toShape(aResult));
505 //==================================================================================================
506 void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr theBaseShape,
507 const GeomDirPtr theDirection,
508 const GeomShapePtr theToShape,
509 const double theToSize,
510 const bool theToIsPlanar,
511 const GeomShapePtr theFromShape,
512 const double theFromSize,
513 const bool theFromIsPlanar,
514 const GeomAPI_Shape::ShapeType theTypeToExp)
516 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
517 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
519 // Moving prism bounding faces according to "from" and "to" sizes.
520 GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, theFromSize, theDirection, *this);
521 GeomShapePtr aBoundingToShape = buildOffset(theToShape, theToSize, theDirection, *this);
523 // Bounding box for shapes used in prism building.
525 BRepBndLib::Add(aBaseShape, aBndBox);
526 BRepBndLib::Add(aBoundingFromShape->impl<TopoDS_Shape>(), aBndBox);
527 BRepBndLib::Add(aBoundingToShape->impl<TopoDS_Shape>(), aBndBox);
528 double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax());
532 aTrsf.SetTranslation(anExtVec * -aPrismLength);
533 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
534 if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
537 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
538 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
539 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
542 BRepPrimAPI_MakePrism* aPrismBuilder =
543 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
544 if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
547 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
548 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
550 GeomShapePtr aResult = toShape(aPrismBuilder->Shape());
553 ListOfShape aPrismBaseFaces;
554 collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp);
556 // Build planar faces intersecting the prism fully.
557 BRepBndLib::Add(aResult->impl<TopoDS_Shape>(), aBndBox);
558 aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox);
559 aBoundingToShape = buildPlanarFace(aBoundingToShape, aBndBox);
561 // Perform partition.
562 ListOfShape anObjects, aTools;
563 anObjects.push_back(aResult);
564 aTools.push_back(aBoundingFromShape);
565 aTools.push_back(aBoundingToShape);
567 GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools));
568 if (!aPartition->isDone())
571 this->appendAlgo(aPartition);
573 // Collect pieces of boundary shapes, split by Partition.
574 if (theFromIsPlanar) {
575 ListOfShape anImagesFrom;
576 aPartition->modified(aBoundingFromShape, anImagesFrom);
577 for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt)
582 ListOfShape anImagesTo;
583 aPartition->modified(aBoundingToShape, anImagesTo);
584 for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt)
588 // Collect results which have both boundaries, selected for extrusion,
589 // but which do not contain top and bottom faces of the prism
590 // (these faces are treated as infinitely distant).
591 aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp);
592 if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) {
593 ListOfShape aResults;
594 aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult,
595 theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID,
598 if (aResults.size() > 1 &&
599 (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) ||
600 GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) {
601 // results shuold not have shared topology
602 aResult = GeomShapePtr();
607 this->setShape(aResult);
613 // Auxilary functions:
614 //==================================================================================================
615 GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
616 const Bnd_Box& theBaseShapeBB)
618 GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
620 return theOriginalShape;
622 gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
623 gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
624 double aSize = aCornerMin.SquareDistance(aCornerMax);
626 gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
629 for (int x = 0; x < 2; ++x) {
630 aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
631 for (int y = 0; y < 2; ++y) {
632 aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
633 for (int z = 0; z < 2; ++z) {
634 aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
635 double aDist = aCurPnt.SquareDistance(aLocation);
643 return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
646 //==================================================================================================
647 GeomShapePtr buildOffset(const GeomShapePtr& theShape,
648 const double theOffset,
649 const GeomDirPtr theDirection,
650 GeomAlgoAPI_MakeShapeList& theMakeShapeList)
652 if (Abs(theOffset) < Precision::Confusion())
653 return theShape; // no need zero offset
655 GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
656 if (!anAlgo->isDone()) {
657 // offset not done, perform translation
658 std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
659 anAxis->setDir(theDirection);
660 anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
663 GeomShapePtr aResult = theShape;
664 if (anAlgo->isDone()) {
665 theMakeShapeList.appendAlgo(anAlgo);
666 aResult = anAlgo->shape();
671 //==================================================================================================
672 void collectPrismBases(const TopoDS_Shape& theBaseShape,
673 BRepPrimAPI_MakePrism& thePrismAlgo,
674 ListOfShape& theBoundaries,
675 const GeomAPI_Shape::ShapeType theTypeToExp)
677 for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
678 anExp.More(); anExp.Next()) {
679 theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
680 theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
684 //==================================================================================================
685 typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
687 bool isShapeApplicable(const GeomShapePtr& theSolid,
688 const std::list<ListOfShape>& theShapesToExist,
689 const SetOfShape& theShapesToExclude,
690 const GeomAPI_Shape::ShapeType theTypeToExp)
693 for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
694 aFExp.more(); aFExp.next()) {
695 GeomShapePtr aCurrent = aFExp.current();
696 if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
698 aFaces.insert(aCurrent);
701 // check all faces are in solid
702 bool isApplicable = true;
703 for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
704 it1 != theShapesToExist.end() && isApplicable; ++it1) {
705 ListOfShape::const_iterator it2 = it1->begin();
706 for (; it2 != it1->end(); ++it2)
707 if (aFaces.find(*it2) != aFaces.end())
709 isApplicable = it2 != it1->end();
714 void collectModified(const GeomMakeShapePtr& theOperation,
715 const ListOfShape& theShapes,
716 std::list<ListOfShape>& theModified)
718 for (ListOfShape::const_iterator anIt = theShapes.begin();
719 anIt != theShapes.end(); ++anIt) {
720 theModified.push_back(ListOfShape());
721 theOperation->modified(*anIt, theModified.back());
722 theOperation->generated(*anIt, theModified.back());
723 theModified.back().push_back(*anIt);
727 GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
728 const ListOfShape& theBoundaries,
729 const ListOfShape& theShapesToExclude,
730 const GeomAPI_Shape::ShapeType theTypeToExp)
732 ListOfShape aResults;
734 // collect modified shapes
735 std::list<ListOfShape> aModifiedBoundaries;
736 collectModified(theOperation, theBoundaries, aModifiedBoundaries);
738 std::list<ListOfShape> aModifiedExclude;
739 collectModified(theOperation, theShapesToExclude, aModifiedExclude);
740 SetOfShape aTabooShapes;
741 for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
742 anIt != aModifiedExclude.end(); ++anIt)
743 aTabooShapes.insert(anIt->begin(), anIt->end());
745 // type of sub-shapes to explode
746 GeomAPI_Shape::ShapeType aSubshapeType;
747 switch (theTypeToExp) {
748 case GeomAPI_Shape::VERTEX:
749 aSubshapeType = GeomAPI_Shape::EDGE;
751 case GeomAPI_Shape::EDGE:
752 aSubshapeType = GeomAPI_Shape::FACE;
754 case GeomAPI_Shape::FACE:
755 aSubshapeType = GeomAPI_Shape::SOLID;
758 aSubshapeType = GeomAPI_Shape::COMPOUND;
761 // search applicable solids
762 GeomShapePtr anOperationResult = theOperation->shape();
763 for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
764 anExp.more(); anExp.next()) {
765 if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
766 aResults.push_back(anExp.current());
769 GeomShapePtr aResult;
770 if (aResults.size() == 1)
771 aResult = aResults.front();
772 else if (!aResults.empty())
773 aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
777 //==================================================================================================
778 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
779 const TopoDS_Shape& theBase,
780 const TopAbs_ShapeEnum theType,
781 BRepPrimAPI_MakePrism* thePrismBuilder)
783 for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) {
784 const TopoDS_Shape& aShape = anExp.Current();
785 GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
786 aFromShape->setImpl(new TopoDS_Shape(thePrismBuilder->FirstShape(aShape)));
787 aToShape->setImpl(new TopoDS_Shape(thePrismBuilder->LastShape(aShape)));
788 thePrismAlgo->fixOrientation(aFromShape);
789 thePrismAlgo->fixOrientation(aToShape);
790 thePrismAlgo->addFromShape(aFromShape);
791 thePrismAlgo->addToShape(aToShape);
795 //==================================================================================================
796 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
797 const TopoDS_Shape& theResult,
798 const TopAbs_ShapeEnum theType,
799 const TopoDS_Face& theToFace,
800 const TopoDS_Face& theFromFace)
802 for(TopExp_Explorer anExp(theResult, theType); anExp.More(); anExp.Next()) {
803 const TopoDS_Shape& aShape = anExp.Current();
804 GeomShapePtr aGeomSh(new GeomAPI_Shape());
805 if(theType == TopAbs_VERTEX) {
806 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
807 IntTools_Context anIntTools;
808 if(anIntTools.IsValidPointForFace(aPnt,
809 theToFace, Precision::Confusion()) == Standard_True) {
810 aGeomSh->setImpl(new TopoDS_Shape(aShape));
811 thePrismAlgo->fixOrientation(aGeomSh);
812 thePrismAlgo->addToShape(aGeomSh);
814 if(anIntTools.IsValidPointForFace(aPnt,
815 theFromFace, Precision::Confusion()) == Standard_True) {
816 aGeomSh->setImpl(new TopoDS_Shape(aShape));
817 thePrismAlgo->fixOrientation(aGeomSh);
818 thePrismAlgo->addFromShape(aGeomSh);
820 } else if(theType == TopAbs_EDGE) {
821 TopoDS_Edge anEdge = TopoDS::Edge(aShape);
822 BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, theToFace);
823 anEdgeCheck.Perform();
824 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
825 aGeomSh->setImpl(new TopoDS_Shape(aShape));
826 thePrismAlgo->fixOrientation(aGeomSh);
827 thePrismAlgo->addToShape(aGeomSh);
829 anEdgeCheck.Init(anEdge, theFromFace);
830 anEdgeCheck.Perform();
831 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
832 aGeomSh->setImpl(new TopoDS_Shape(aShape));
833 thePrismAlgo->fixOrientation(aGeomSh);
834 thePrismAlgo->addFromShape(aGeomSh);