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))));
317 std::shared_ptr<GeomAPI_Pnt> aToPnt(
318 new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->multiplied(
319 aSign ? -theToSize : theToSize))));
321 // Getting bounding box for base shape.
323 BRepBndLib::Add(aBaseShape, aBndBox);
324 Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
325 Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
326 Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
329 for(int i = 0; i < 2; i++) {
330 for(int j = 0; j < 2; j++) {
331 for(int k = 0; k < 2; k++) {
332 aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
338 // Project points to bounding planes. Search max distance to them.
339 IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
340 IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
341 Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
342 for(int i = 0; i < 8; i++) {
343 gp_Lin aLine(aPoints[i], anExtVec);
344 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
345 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
346 if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
349 const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
350 const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
351 if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
352 aMaxToDist = aPoints[i].Distance(aPntOnToFace);
354 if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
355 aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
359 // We added 1 just to be sure that prism is long enough for boolean operation.
360 double aPrismLength = aMaxToDist + aMaxFromDist + 1;
362 // Moving base shape.
364 aTrsf.SetTranslation(anExtVec * -aPrismLength);
365 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
366 if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
369 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
370 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
371 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
374 BRepPrimAPI_MakePrism* aPrismBuilder =
375 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
376 if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
379 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
380 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
381 TopoDS_Shape aResult = aPrismBuilder->Shape();
383 BRepBndLib::Add(aResult, aBndBox);
384 Standard_Real aBndBoxSize = aBndBox.CornerMin().Distance(aBndBox.CornerMax());
386 // Orienting bounding planes.
387 std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
388 const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
389 gp_Lin aLine(aCentrePnt, anExtVec);
390 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
391 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
392 Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
393 Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
394 if(aToParameter > aFromParameter) {
395 gp_Vec aVec = aToDir->impl<gp_Dir>();
396 if((aVec * anExtVec) > 0)
397 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
398 aVec = aFromDir->impl<gp_Dir>();
399 if((aVec * anExtVec) < 0)
400 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
402 gp_Vec aVec = aToDir->impl<gp_Dir>();
403 if((aVec * anExtVec) < 0)
404 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
405 aVec = aFromDir->impl<gp_Dir>();
406 if((aVec * anExtVec) > 0)
407 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
410 static const double THE_FACE_SIZE_COEFF = 10.0;
411 GeomShapePtr aBoundingFromShape =
412 GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
413 GeomShapePtr aBoundingToShape =
414 GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
417 const TopoDS_Shape& aToShape = aBoundingToShape->impl<TopoDS_Shape>();
418 const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
419 TopoDS_Face aToFace = TopoDS::Face(aToShape);
420 TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
422 // Solid based on "To" bounding plane
423 gp_Vec aNormal = aToDir->impl<gp_Dir>();
424 BRepPrimAPI_MakePrism* aToPrismBuilder =
425 new BRepPrimAPI_MakePrism(aToShape, aNormal * (-2.0 * aBndBoxSize));
426 if (!aToPrismBuilder || !aToPrismBuilder->IsDone()) {
429 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
430 new GeomAlgoAPI_MakeShape(aToPrismBuilder)));
431 TopoDS_Shape aToSolid = aToPrismBuilder->Shape();
433 // Cutting with to plane.
434 BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
435 aToCutBuilder->Build();
436 if(!aToCutBuilder->IsDone()) {
439 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
440 new GeomAlgoAPI_MakeShape(aToCutBuilder)));
441 aResult = aToCutBuilder->Shape();
442 if(aResult.ShapeType() == TopAbs_COMPOUND) {
443 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
445 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
446 TopTools_ListOfShape aPrismShapes = aToPrismBuilder->Modified(aToShape);
447 if (aPrismShapes.IsEmpty())
448 aPrismShapes.Append(aToShape);
449 for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
450 const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(anIt1.Value());
451 for (TopTools_ListIteratorOfListOfShape anIt2(aToShapes); anIt2.More(); anIt2.Next()) {
452 GeomShapePtr aGeomSh = toShape(anIt2.Value());
453 fixOrientation(aGeomSh);
454 this->addToShape(aGeomSh);
459 // Solid based on "From" bounding plane
460 aNormal = aFromDir->impl<gp_Dir>();
461 BRepPrimAPI_MakePrism* aFromPrismBuilder =
462 new BRepPrimAPI_MakePrism(aFromShape, aNormal * (-2.0 * aBndBoxSize));
463 if (!aFromPrismBuilder || !aFromPrismBuilder->IsDone()) {
466 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
467 new GeomAlgoAPI_MakeShape(aFromPrismBuilder)));
468 TopoDS_Shape aFromSolid = aFromPrismBuilder->Shape();
470 // Cutting with from plane.
471 BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
472 aFromCutBuilder->Build();
473 if(!aFromCutBuilder->IsDone()) {
476 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
477 new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
478 aResult = aFromCutBuilder->Shape();
479 TopoDS_Iterator aCheckIt(aResult);
480 if(!aCheckIt.More()) {
483 if(aResult.ShapeType() == TopAbs_COMPOUND) {
484 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
486 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
487 TopTools_ListOfShape aPrismShapes = aFromPrismBuilder->Modified(aFromShape);
488 if (aPrismShapes.IsEmpty())
489 aPrismShapes.Append(aFromShape);
490 for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
491 const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(anIt1.Value());
492 for (TopTools_ListIteratorOfListOfShape anIt2(aFromShapes); anIt2.More(); anIt2.Next()) {
493 GeomShapePtr aGeomSh = toShape(anIt2.Value());
494 fixOrientation(aGeomSh);
495 this->addFromShape(aGeomSh);
500 // Naming for extrusion from vertex, edge.
501 if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
502 storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
503 storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
505 storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace);
508 if(aResult.ShapeType() == TopAbs_COMPOUND) {
509 GeomShapePtr aGeomShape = toShape(aResult);
510 ListOfShape aResults;
511 aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
512 GeomAPI_Shape::COMPSOLID,
514 aResult = aGeomShape->impl<TopoDS_Shape>();
518 if (!aResult.IsNull()) {
519 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
520 this->setShape(toShape(aResult));
525 //==================================================================================================
526 void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr theBaseShape,
527 const GeomDirPtr theDirection,
528 const GeomShapePtr theToShape,
529 const double theToSize,
530 const bool theToIsPlanar,
531 const GeomShapePtr theFromShape,
532 const double theFromSize,
533 const bool theFromIsPlanar,
534 const GeomAPI_Shape::ShapeType theTypeToExp)
536 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
537 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
539 // Moving prism bounding faces according to "from" and "to" sizes.
540 GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, -theFromSize, theDirection, *this);
541 GeomShapePtr aBoundingToShape = buildOffset(theToShape, theToSize, theDirection, *this);
543 // Bounding box for shapes used in prism building.
545 BRepBndLib::Add(aBaseShape, aBndBox);
546 BRepBndLib::Add(aBoundingFromShape->impl<TopoDS_Shape>(), aBndBox);
547 BRepBndLib::Add(aBoundingToShape->impl<TopoDS_Shape>(), aBndBox);
548 double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax());
552 aTrsf.SetTranslation(anExtVec * -aPrismLength);
553 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
554 if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
557 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
558 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
559 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
562 BRepPrimAPI_MakePrism* aPrismBuilder =
563 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
564 if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
567 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
568 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
570 GeomShapePtr aResult = toShape(aPrismBuilder->Shape());
573 ListOfShape aPrismBaseFaces;
574 collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp);
576 // Build planar faces intersecting the prism fully.
577 BRepBndLib::Add(aResult->impl<TopoDS_Shape>(), aBndBox);
578 aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox);
579 aBoundingToShape = buildPlanarFace(aBoundingToShape, aBndBox);
581 // Perform partition.
582 ListOfShape anObjects, aTools;
583 anObjects.push_back(aResult);
584 aTools.push_back(aBoundingFromShape);
585 aTools.push_back(aBoundingToShape);
587 GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools));
588 if (!aPartition->isDone())
591 this->appendAlgo(aPartition);
593 // Collect pieces of boundary shapes, split by Partition.
594 if (theFromIsPlanar) {
595 ListOfShape anImagesFrom;
596 aPartition->modified(aBoundingFromShape, anImagesFrom);
597 for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt)
602 ListOfShape anImagesTo;
603 aPartition->modified(aBoundingToShape, anImagesTo);
604 for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt)
608 // Collect results which have both boundaries, selected for extrusion,
609 // but which do not contain top and bottom faces of the prism
610 // (these faces are treated as infinitely distant).
611 aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp);
612 if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) {
613 ListOfShape aResults;
614 aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult,
615 theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID,
618 if (aResults.size() > 1 &&
619 (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) ||
620 GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) {
621 // results shuold not have shared topology
622 aResult = GeomShapePtr();
627 this->setShape(aResult);
633 // Auxilary functions:
634 //==================================================================================================
635 GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
636 const Bnd_Box& theBaseShapeBB)
638 GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
640 return theOriginalShape;
642 gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
643 gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
644 double aSize = aCornerMin.SquareDistance(aCornerMax);
646 gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
649 for (int x = 0; x < 2; ++x) {
650 aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
651 for (int y = 0; y < 2; ++y) {
652 aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
653 for (int z = 0; z < 2; ++z) {
654 aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
655 double aDist = aCurPnt.SquareDistance(aLocation);
663 return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
666 //==================================================================================================
667 GeomShapePtr buildOffset(const GeomShapePtr& theShape,
668 const double theOffset,
669 const GeomDirPtr theDirection,
670 GeomAlgoAPI_MakeShapeList& theMakeShapeList)
672 if (Abs(theOffset) < Precision::Confusion())
673 return theShape; // no need zero offset
675 GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
676 if (!anAlgo->isDone()) {
677 // offset not done, perform translation
678 std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
679 anAxis->setDir(theDirection);
680 anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
683 GeomShapePtr aResult = theShape;
684 if (anAlgo->isDone()) {
685 theMakeShapeList.appendAlgo(anAlgo);
686 aResult = anAlgo->shape();
691 //==================================================================================================
692 void collectPrismBases(const TopoDS_Shape& theBaseShape,
693 BRepPrimAPI_MakePrism& thePrismAlgo,
694 ListOfShape& theBoundaries,
695 const GeomAPI_Shape::ShapeType theTypeToExp)
697 for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
698 anExp.More(); anExp.Next()) {
699 theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
700 theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
704 //==================================================================================================
705 typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
707 bool isShapeApplicable(const GeomShapePtr& theSolid,
708 const std::list<ListOfShape>& theShapesToExist,
709 const SetOfShape& theShapesToExclude,
710 const GeomAPI_Shape::ShapeType theTypeToExp)
713 for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
714 aFExp.more(); aFExp.next()) {
715 GeomShapePtr aCurrent = aFExp.current();
716 if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
718 aFaces.insert(aCurrent);
721 // check all faces are in solid
722 bool isApplicable = true;
723 for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
724 it1 != theShapesToExist.end() && isApplicable; ++it1) {
725 ListOfShape::const_iterator it2 = it1->begin();
726 for (; it2 != it1->end(); ++it2)
727 if (aFaces.find(*it2) != aFaces.end())
729 isApplicable = it2 != it1->end();
734 void collectModified(const GeomMakeShapePtr& theOperation,
735 const ListOfShape& theShapes,
736 std::list<ListOfShape>& theModified)
738 for (ListOfShape::const_iterator anIt = theShapes.begin();
739 anIt != theShapes.end(); ++anIt) {
740 theModified.push_back(ListOfShape());
741 theOperation->modified(*anIt, theModified.back());
742 theOperation->generated(*anIt, theModified.back());
743 theModified.back().push_back(*anIt);
747 GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
748 const ListOfShape& theBoundaries,
749 const ListOfShape& theShapesToExclude,
750 const GeomAPI_Shape::ShapeType theTypeToExp)
752 ListOfShape aResults;
754 // collect modified shapes
755 std::list<ListOfShape> aModifiedBoundaries;
756 collectModified(theOperation, theBoundaries, aModifiedBoundaries);
758 std::list<ListOfShape> aModifiedExclude;
759 collectModified(theOperation, theShapesToExclude, aModifiedExclude);
760 SetOfShape aTabooShapes;
761 for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
762 anIt != aModifiedExclude.end(); ++anIt)
763 aTabooShapes.insert(anIt->begin(), anIt->end());
765 // type of sub-shapes to explode
766 GeomAPI_Shape::ShapeType aSubshapeType;
767 switch (theTypeToExp) {
768 case GeomAPI_Shape::VERTEX:
769 aSubshapeType = GeomAPI_Shape::EDGE;
771 case GeomAPI_Shape::EDGE:
772 aSubshapeType = GeomAPI_Shape::FACE;
774 case GeomAPI_Shape::FACE:
775 aSubshapeType = GeomAPI_Shape::SOLID;
778 aSubshapeType = GeomAPI_Shape::COMPOUND;
781 // search applicable solids
782 GeomShapePtr anOperationResult = theOperation->shape();
783 for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
784 anExp.more(); anExp.next()) {
785 if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
786 aResults.push_back(anExp.current());
789 GeomShapePtr aResult;
790 if (aResults.size() == 1)
791 aResult = aResults.front();
792 else if (!aResults.empty())
793 aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
797 //==================================================================================================
798 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
799 const TopoDS_Shape& theBase,
800 const TopAbs_ShapeEnum theType,
801 BRepPrimAPI_MakePrism* thePrismBuilder)
803 for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) {
804 const TopoDS_Shape& aShape = anExp.Current();
805 GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
806 aFromShape->setImpl(new TopoDS_Shape(thePrismBuilder->FirstShape(aShape)));
807 aToShape->setImpl(new TopoDS_Shape(thePrismBuilder->LastShape(aShape)));
808 thePrismAlgo->fixOrientation(aFromShape);
809 thePrismAlgo->fixOrientation(aToShape);
810 thePrismAlgo->addFromShape(aFromShape);
811 thePrismAlgo->addToShape(aToShape);
815 //==================================================================================================
816 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
817 const TopoDS_Shape& theResult,
818 const TopAbs_ShapeEnum theType,
819 const TopoDS_Face& theToFace,
820 const TopoDS_Face& theFromFace)
822 for(TopExp_Explorer anExp(theResult, theType); anExp.More(); anExp.Next()) {
823 const TopoDS_Shape& aShape = anExp.Current();
824 GeomShapePtr aGeomSh(new GeomAPI_Shape());
825 if(theType == TopAbs_VERTEX) {
826 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
827 IntTools_Context anIntTools;
828 if(anIntTools.IsValidPointForFace(aPnt,
829 theToFace, Precision::Confusion()) == Standard_True) {
830 aGeomSh->setImpl(new TopoDS_Shape(aShape));
831 thePrismAlgo->fixOrientation(aGeomSh);
832 thePrismAlgo->addToShape(aGeomSh);
834 if(anIntTools.IsValidPointForFace(aPnt,
835 theFromFace, Precision::Confusion()) == Standard_True) {
836 aGeomSh->setImpl(new TopoDS_Shape(aShape));
837 thePrismAlgo->fixOrientation(aGeomSh);
838 thePrismAlgo->addFromShape(aGeomSh);
840 } else if(theType == TopAbs_EDGE) {
841 TopoDS_Edge anEdge = TopoDS::Edge(aShape);
842 BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, theToFace);
843 anEdgeCheck.Perform();
844 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
845 aGeomSh->setImpl(new TopoDS_Shape(aShape));
846 thePrismAlgo->fixOrientation(aGeomSh);
847 thePrismAlgo->addToShape(aGeomSh);
849 anEdgeCheck.Init(anEdge, theFromFace);
850 anEdgeCheck.Perform();
851 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
852 aGeomSh->setImpl(new TopoDS_Shape(aShape));
853 thePrismAlgo->fixOrientation(aGeomSh);
854 thePrismAlgo->addFromShape(aGeomSh);