1 // Copyright (C) 2014-2020 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));
105 static void changeOrientationIfNeeded(const TopoDS_Shape& theShape, gp_Vec& theNormal)
107 TopExp_Explorer anExp(theShape, TopAbs_VERTEX);
108 gp_Pnt aPnt0 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
110 for (anExp.Next(); anExp.More(); anExp.Next()) {
111 gp_Pnt aPnt1 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
112 if (aPnt1.SquareDistance(aPnt0) > Precision::SquareConfusion()) {
113 aDir01 = gp_Dir(gp_Vec(aPnt0, aPnt1));
118 for (; anExp.More(); anExp.Next()) {
119 gp_Pnt aPnt2 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
120 if (aPnt2.SquareDistance(aPnt0) > Precision::SquareConfusion()) {
121 aNormal = gp_Vec(aDir01) ^ gp_Vec(aPnt0, aPnt2);
122 if (aNormal.SquareMagnitude() > Precision::SquareConfusion())
126 if (anExp.More() && aNormal.XYZ().Dot(theNormal.XYZ()) < -Precision::Confusion()) {
127 // directions differ, reverse the normal
132 //==================================================================================================
133 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
134 const GeomDirPtr theDirection,
135 const GeomShapePtr theToShape,
136 const double theToSize,
137 const GeomShapePtr theFromShape,
138 const double theFromSize)
140 if(!theBaseShape.get() ||
141 (((!theFromShape.get() && !theToShape.get()) ||
142 (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape)))
143 && (theFromSize == -theToSize))) {
147 // Getting base shape.
148 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
149 GeomAPI_Shape::ShapeType aShapeTypeToExp;
150 switch(aBaseShape.ShapeType()) {
152 aShapeTypeToExp = GeomAPI_Shape::VERTEX;
156 aShapeTypeToExp = GeomAPI_Shape::EDGE;
160 aShapeTypeToExp = GeomAPI_Shape::FACE;
162 case TopAbs_COMPOUND:
163 aShapeTypeToExp = GeomAPI_Shape::COMPOUND;
169 // Getting direction.
171 std::shared_ptr<GeomAPI_Pnt> aBaseLoc;
172 std::shared_ptr<GeomAPI_Dir> aBaseDir;
173 BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
174 if(aFindPlane.Found() == Standard_True)
176 bool checkOrientation = false;
177 Handle(Geom_Plane) aPlane;
178 if(aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) {
179 TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
180 const TopoDS_Shape& aFace = anExp.Current();
181 Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace));
182 if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
183 Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
184 Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
185 aSurface = aTrimSurface->BasisSurface();
187 if(aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
190 aPlane = Handle(Geom_Plane)::DownCast(aSurface);
192 aPlane = aFindPlane.Plane();
193 checkOrientation = true;
195 gp_Pnt aLoc = aPlane->Axis().Location();
196 aBaseVec = aPlane->Axis().Direction();
198 if (checkOrientation) {
199 // to stabilize the result of algorithm, if base shape is a wire, compare the orientation
200 // of calculated plane with the normal vector got iterating on vertices
201 changeOrientationIfNeeded(aBaseShape, aBaseVec);
204 aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
205 aBaseDir.reset(new GeomAPI_Dir(aBaseVec.X(), aBaseVec.Y(), aBaseVec.Z()));
207 else if (theDirection.get())
209 aBaseDir = theDirection;
210 aBaseVec = theDirection->impl<gp_Dir>();
217 if(!aBaseLoc.get()) {
219 gp_XYZ aDirXYZ = aBaseVec.XYZ();
220 Standard_Real aMinParam = Precision::Infinite();
221 for(TopExp_Explorer anExp(aBaseShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) {
222 const TopoDS_Shape& aVertex = anExp.Current();
223 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
224 double aParam = aDirXYZ.Dot(aPnt.XYZ());
225 if(aParam < aMinParam) {
230 aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
234 std::shared_ptr<GeomAPI_Dir> anExtDir;
235 if (theDirection.get())
237 anExtDir = theDirection;
238 anExtVec = theDirection->impl<gp_Dir>();
243 anExtVec = aBaseDir->impl<gp_Dir>();
247 TopoDS_Shape aResult;
248 const bool isBoundingShapesSet = theFromShape.get() || theToShape.get();
249 if(!isBoundingShapesSet) {
250 buildBySizes(theBaseShape, anExtDir, theToSize, theFromSize, aShapeTypeToExp);
252 GeomShapePtr aBasePlane = GeomAlgoAPI_FaceBuilder::squareFace(aBaseLoc, aBaseDir, 100.0);
254 GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
255 GeomShapePtr aBoundingToShape = theToShape ? theToShape : aBasePlane;
257 bool isFromShapePlanar = aBoundingFromShape->isPlanar();
258 bool isToShapePlanar = aBoundingToShape->isPlanar();
260 // Set signs of offsets if both bounding shapes are planar
261 if (isFromShapePlanar && isToShapePlanar) {
262 std::shared_ptr<GeomAPI_Pln> aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane();
263 std::shared_ptr<GeomAPI_Pln> aToPln = GeomAPI_Face(aBoundingToShape).getPlane();
264 buildByPlanes(theBaseShape, anExtDir,
266 aFromPln, theFromSize,
270 buildByFaces(theBaseShape, anExtDir,
271 aBoundingToShape, theToSize, isToShapePlanar,
272 aBoundingFromShape, theFromSize, isFromShapePlanar,
278 //==================================================================================================
279 void GeomAlgoAPI_Prism::buildBySizes(const GeomShapePtr theBaseShape,
280 const GeomDirPtr theDirection,
281 const double theToSize,
282 const double theFromSize,
283 const GeomAPI_Shape::ShapeType theTypeToExp)
285 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
286 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
288 // Moving base shape.
290 aTrsf.SetTranslation(anExtVec * -theFromSize);
291 BRepBuilderAPI_Transform* aTransformBuilder =
292 new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
293 if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
296 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
297 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
298 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
301 BRepPrimAPI_MakePrism* aPrismBuilder =
302 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * (theFromSize + theToSize));
303 if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
306 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
307 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
308 TopoDS_Shape aResult = aPrismBuilder->Shape();
311 if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
312 storeGenerationHistory(this, aMovedBase, TopAbs_EDGE, aPrismBuilder);
313 storeGenerationHistory(this, aMovedBase, TopAbs_FACE, aPrismBuilder);
315 storeGenerationHistory(this, aMovedBase, (TopAbs_ShapeEnum)theTypeToExp, aPrismBuilder);
319 if (!aResult.IsNull()) {
320 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
321 this->setShape(toShape(aResult));
326 //==================================================================================================
327 void GeomAlgoAPI_Prism::buildByPlanes(const GeomShapePtr theBaseShape,
328 const GeomDirPtr theDirection,
329 const GeomPlanePtr theToPlane,
330 const double theToSize,
331 const GeomPlanePtr theFromPlane,
332 const double theFromSize,
333 const GeomAPI_Shape::ShapeType theTypeToExp)
335 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
336 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
338 // Moving prism bounding faces according to "from" and "to" sizes.
339 std::shared_ptr<GeomAPI_Pnt> aFromLoc = theFromPlane->location();
340 std::shared_ptr<GeomAPI_Dir> aFromDir = theFromPlane->direction();
342 std::shared_ptr<GeomAPI_Pnt> aToLoc = theToPlane->location();
343 std::shared_ptr<GeomAPI_Dir> aToDir = theToPlane->direction();
345 std::shared_ptr<GeomAPI_XYZ> anExtDir = theDirection->xyz();
346 bool aSign = aFromLoc->xyz()->dot(anExtDir) > aToLoc->xyz()->dot(anExtDir);
348 std::shared_ptr<GeomAPI_Pnt> aFromPnt(
349 new GeomAPI_Pnt(aFromLoc->xyz()->added(anExtDir->multiplied(
350 aSign ? theFromSize : -theFromSize))));
352 std::shared_ptr<GeomAPI_Pnt> aToPnt(
353 new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->multiplied(
354 aSign ? -theToSize : theToSize))));
356 // Getting bounding box for base shape.
358 BRepBndLib::Add(aBaseShape, aBndBox);
359 Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
360 Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
361 Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
364 for(int i = 0; i < 2; i++) {
365 for(int j = 0; j < 2; j++) {
366 for(int k = 0; k < 2; k++) {
367 aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
373 // Project points to bounding planes. Search max distance to them.
374 IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
375 IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
376 Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
377 for(int i = 0; i < 8; i++) {
378 gp_Lin aLine(aPoints[i], anExtVec);
379 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
380 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
381 if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
384 const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
385 const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
386 if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
387 aMaxToDist = aPoints[i].Distance(aPntOnToFace);
389 if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
390 aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
394 // We added 1 just to be sure that prism is long enough for boolean operation.
395 double aPrismLength = aMaxToDist + aMaxFromDist + 1;
397 // Moving base shape.
399 aTrsf.SetTranslation(anExtVec * -aPrismLength);
400 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
401 if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
404 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
405 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
406 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
409 BRepPrimAPI_MakePrism* aPrismBuilder =
410 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
411 if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
414 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
415 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
416 TopoDS_Shape aResult = aPrismBuilder->Shape();
418 BRepBndLib::Add(aResult, aBndBox);
419 Standard_Real aBndBoxSize = aBndBox.CornerMin().Distance(aBndBox.CornerMax());
421 // Orienting bounding planes.
422 std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
423 const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
424 gp_Lin aLine(aCentrePnt, anExtVec);
425 IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
426 IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
427 Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
428 Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
429 if(aToParameter > aFromParameter) {
430 gp_Vec aVec = aToDir->impl<gp_Dir>();
431 if((aVec * anExtVec) > 0)
432 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
433 aVec = aFromDir->impl<gp_Dir>();
434 if((aVec * anExtVec) < 0)
435 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
437 gp_Vec aVec = aToDir->impl<gp_Dir>();
438 if((aVec * anExtVec) < 0)
439 aToDir->setImpl(new gp_Dir(aVec.Reversed()));
440 aVec = aFromDir->impl<gp_Dir>();
441 if((aVec * anExtVec) > 0)
442 aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
445 static const double THE_FACE_SIZE_COEFF = 10.0;
446 GeomShapePtr aBoundingFromShape =
447 GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
448 GeomShapePtr aBoundingToShape =
449 GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize);
452 const TopoDS_Shape& aToShape = aBoundingToShape->impl<TopoDS_Shape>();
453 const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
454 TopoDS_Face aToFace = TopoDS::Face(aToShape);
455 TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
457 // Solid based on "To" bounding plane
458 gp_Vec aNormal = aToDir->impl<gp_Dir>();
459 BRepPrimAPI_MakePrism* aToPrismBuilder =
460 new BRepPrimAPI_MakePrism(aToShape, aNormal * (-2.0 * aBndBoxSize));
461 if (!aToPrismBuilder || !aToPrismBuilder->IsDone()) {
464 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
465 new GeomAlgoAPI_MakeShape(aToPrismBuilder)));
466 TopoDS_Shape aToSolid = aToPrismBuilder->Shape();
468 // Cutting with to plane.
469 BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
470 aToCutBuilder->Build();
471 if(!aToCutBuilder->IsDone()) {
474 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
475 new GeomAlgoAPI_MakeShape(aToCutBuilder)));
476 aResult = aToCutBuilder->Shape();
477 if(aResult.ShapeType() == TopAbs_COMPOUND) {
478 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
480 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
481 TopTools_ListOfShape aPrismShapes = aToPrismBuilder->Modified(aToShape);
482 if (aPrismShapes.IsEmpty())
483 aPrismShapes.Append(aToShape);
484 for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
485 const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(anIt1.Value());
486 for (TopTools_ListIteratorOfListOfShape anIt2(aToShapes); anIt2.More(); anIt2.Next()) {
487 GeomShapePtr aGeomSh = toShape(anIt2.Value());
488 fixOrientation(aGeomSh);
489 this->addToShape(aGeomSh);
494 // Solid based on "From" bounding plane
495 aNormal = aFromDir->impl<gp_Dir>();
496 BRepPrimAPI_MakePrism* aFromPrismBuilder =
497 new BRepPrimAPI_MakePrism(aFromShape, aNormal * (-2.0 * aBndBoxSize));
498 if (!aFromPrismBuilder || !aFromPrismBuilder->IsDone()) {
501 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
502 new GeomAlgoAPI_MakeShape(aFromPrismBuilder)));
503 TopoDS_Shape aFromSolid = aFromPrismBuilder->Shape();
505 // Cutting with from plane.
506 BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
507 aFromCutBuilder->Build();
508 if(!aFromCutBuilder->IsDone()) {
511 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
512 new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
513 aResult = aFromCutBuilder->Shape();
514 TopoDS_Iterator aCheckIt(aResult);
515 if(!aCheckIt.More()) {
518 if(aResult.ShapeType() == TopAbs_COMPOUND) {
519 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
521 if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
522 TopTools_ListOfShape aPrismShapes = aFromPrismBuilder->Modified(aFromShape);
523 if (aPrismShapes.IsEmpty())
524 aPrismShapes.Append(aFromShape);
525 for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) {
526 const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(anIt1.Value());
527 for (TopTools_ListIteratorOfListOfShape anIt2(aFromShapes); anIt2.More(); anIt2.Next()) {
528 GeomShapePtr aGeomSh = toShape(anIt2.Value());
529 fixOrientation(aGeomSh);
530 this->addFromShape(aGeomSh);
535 // Naming for extrusion from vertex, edge.
536 if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
537 storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
538 storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
540 storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace);
543 if(aResult.ShapeType() == TopAbs_COMPOUND) {
544 GeomShapePtr aGeomShape = toShape(aResult);
545 ListOfShape aResults;
546 aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
547 GeomAPI_Shape::COMPSOLID,
549 aResult = aGeomShape->impl<TopoDS_Shape>();
553 if (!aResult.IsNull()) {
554 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
555 this->setShape(toShape(aResult));
560 //==================================================================================================
561 void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr theBaseShape,
562 const GeomDirPtr theDirection,
563 const GeomShapePtr theToShape,
564 const double theToSize,
565 const bool theToIsPlanar,
566 const GeomShapePtr theFromShape,
567 const double theFromSize,
568 const bool theFromIsPlanar,
569 const GeomAPI_Shape::ShapeType theTypeToExp)
571 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
572 gp_Vec anExtVec = theDirection->impl<gp_Dir>();
574 // Moving prism bounding faces according to "from" and "to" sizes.
575 GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, -theFromSize, theDirection, *this);
576 GeomShapePtr aBoundingToShape = buildOffset(theToShape, theToSize, theDirection, *this);
578 // Bounding box for shapes used in prism building.
580 BRepBndLib::Add(aBaseShape, aBndBox);
581 BRepBndLib::Add(aBoundingFromShape->impl<TopoDS_Shape>(), aBndBox);
582 BRepBndLib::Add(aBoundingToShape->impl<TopoDS_Shape>(), aBndBox);
583 double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax());
587 aTrsf.SetTranslation(anExtVec * -aPrismLength);
588 BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
589 if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
592 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
593 new GeomAlgoAPI_MakeShape(aTransformBuilder)));
594 TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
597 BRepPrimAPI_MakePrism* aPrismBuilder =
598 new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
599 if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
602 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
603 new GeomAlgoAPI_MakeShape(aPrismBuilder)));
605 GeomShapePtr aResult = toShape(aPrismBuilder->Shape());
608 ListOfShape aPrismBaseFaces;
609 collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp);
611 // Build planar faces intersecting the prism fully.
612 BRepBndLib::Add(aResult->impl<TopoDS_Shape>(), aBndBox);
613 aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox);
614 aBoundingToShape = buildPlanarFace(aBoundingToShape, aBndBox);
616 // Perform partition.
617 ListOfShape anObjects, aTools;
618 anObjects.push_back(aResult);
619 aTools.push_back(aBoundingFromShape);
620 aTools.push_back(aBoundingToShape);
622 GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools));
623 if (!aPartition->isDone())
626 this->appendAlgo(aPartition);
628 // Collect pieces of boundary shapes, split by Partition.
629 if (theFromIsPlanar) {
630 ListOfShape anImagesFrom;
631 aPartition->modified(aBoundingFromShape, anImagesFrom);
632 for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt)
637 ListOfShape anImagesTo;
638 aPartition->modified(aBoundingToShape, anImagesTo);
639 for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt)
643 // Collect results which have both boundaries, selected for extrusion,
644 // but which do not contain top and bottom faces of the prism
645 // (these faces are treated as infinitely distant).
646 aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp);
647 if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) {
648 ListOfShape aResults;
649 aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult,
650 theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID,
653 if (aResults.size() > 1 &&
654 (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) ||
655 GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) {
656 // results shuold not have shared topology
657 aResult = GeomShapePtr();
662 this->setShape(aResult);
668 // Auxilary functions:
669 //==================================================================================================
670 GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
671 const Bnd_Box& theBaseShapeBB)
673 GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
675 return theOriginalShape;
677 gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
678 gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
679 double aSize = aCornerMin.SquareDistance(aCornerMax);
681 gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
684 for (int x = 0; x < 2; ++x) {
685 aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
686 for (int y = 0; y < 2; ++y) {
687 aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
688 for (int z = 0; z < 2; ++z) {
689 aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
690 double aDist = aCurPnt.SquareDistance(aLocation);
698 return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
701 //==================================================================================================
702 GeomShapePtr buildOffset(const GeomShapePtr& theShape,
703 const double theOffset,
704 const GeomDirPtr theDirection,
705 GeomAlgoAPI_MakeShapeList& theMakeShapeList)
707 if (Abs(theOffset) < Precision::Confusion())
708 return theShape; // no need zero offset
710 GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
711 if (!anAlgo->isDone()) {
712 // offset not done, perform translation
713 std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
714 anAxis->setDir(theDirection);
715 anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
718 GeomShapePtr aResult = theShape;
719 if (anAlgo->isDone()) {
720 theMakeShapeList.appendAlgo(anAlgo);
721 aResult = anAlgo->shape();
726 //==================================================================================================
727 void collectPrismBases(const TopoDS_Shape& theBaseShape,
728 BRepPrimAPI_MakePrism& thePrismAlgo,
729 ListOfShape& theBoundaries,
730 const GeomAPI_Shape::ShapeType theTypeToExp)
732 for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
733 anExp.More(); anExp.Next()) {
734 theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
735 theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
739 //==================================================================================================
740 typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
742 bool isShapeApplicable(const GeomShapePtr& theSolid,
743 const std::list<ListOfShape>& theShapesToExist,
744 const SetOfShape& theShapesToExclude,
745 const GeomAPI_Shape::ShapeType theTypeToExp)
748 for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
749 aFExp.more(); aFExp.next()) {
750 GeomShapePtr aCurrent = aFExp.current();
751 if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
753 aFaces.insert(aCurrent);
756 // check all faces are in solid
757 bool isApplicable = true;
758 for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
759 it1 != theShapesToExist.end() && isApplicable; ++it1) {
760 ListOfShape::const_iterator it2 = it1->begin();
761 for (; it2 != it1->end(); ++it2)
762 if (aFaces.find(*it2) != aFaces.end())
764 isApplicable = it2 != it1->end();
769 void collectModified(const GeomMakeShapePtr& theOperation,
770 const ListOfShape& theShapes,
771 std::list<ListOfShape>& theModified)
773 for (ListOfShape::const_iterator anIt = theShapes.begin();
774 anIt != theShapes.end(); ++anIt) {
775 theModified.push_back(ListOfShape());
776 theOperation->modified(*anIt, theModified.back());
777 theOperation->generated(*anIt, theModified.back());
778 theModified.back().push_back(*anIt);
782 GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
783 const ListOfShape& theBoundaries,
784 const ListOfShape& theShapesToExclude,
785 const GeomAPI_Shape::ShapeType theTypeToExp)
787 ListOfShape aResults;
789 // collect modified shapes
790 std::list<ListOfShape> aModifiedBoundaries;
791 collectModified(theOperation, theBoundaries, aModifiedBoundaries);
793 std::list<ListOfShape> aModifiedExclude;
794 collectModified(theOperation, theShapesToExclude, aModifiedExclude);
795 SetOfShape aTabooShapes;
796 for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
797 anIt != aModifiedExclude.end(); ++anIt)
798 aTabooShapes.insert(anIt->begin(), anIt->end());
800 // type of sub-shapes to explode
801 GeomAPI_Shape::ShapeType aSubshapeType;
802 switch (theTypeToExp) {
803 case GeomAPI_Shape::VERTEX:
804 aSubshapeType = GeomAPI_Shape::EDGE;
806 case GeomAPI_Shape::EDGE:
807 aSubshapeType = GeomAPI_Shape::FACE;
809 case GeomAPI_Shape::FACE:
810 aSubshapeType = GeomAPI_Shape::SOLID;
813 aSubshapeType = GeomAPI_Shape::COMPOUND;
816 // search applicable solids
817 GeomShapePtr anOperationResult = theOperation->shape();
818 for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
819 anExp.more(); anExp.next()) {
820 if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
821 aResults.push_back(anExp.current());
824 GeomShapePtr aResult;
825 if (aResults.size() == 1)
826 aResult = aResults.front();
827 else if (!aResults.empty())
828 aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
832 //==================================================================================================
833 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
834 const TopoDS_Shape& theBase,
835 const TopAbs_ShapeEnum theType,
836 BRepPrimAPI_MakePrism* thePrismBuilder)
838 for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) {
839 const TopoDS_Shape& aShape = anExp.Current();
840 GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
841 aFromShape->setImpl(new TopoDS_Shape(thePrismBuilder->FirstShape(aShape)));
842 aToShape->setImpl(new TopoDS_Shape(thePrismBuilder->LastShape(aShape)));
843 thePrismAlgo->fixOrientation(aFromShape);
844 thePrismAlgo->fixOrientation(aToShape);
845 thePrismAlgo->addFromShape(aFromShape);
846 thePrismAlgo->addToShape(aToShape);
850 //==================================================================================================
851 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
852 const TopoDS_Shape& theResult,
853 const TopAbs_ShapeEnum theType,
854 const TopoDS_Face& theToFace,
855 const TopoDS_Face& theFromFace)
857 for(TopExp_Explorer anExp(theResult, theType); anExp.More(); anExp.Next()) {
858 const TopoDS_Shape& aShape = anExp.Current();
859 GeomShapePtr aGeomSh(new GeomAPI_Shape());
860 if(theType == TopAbs_VERTEX) {
861 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
862 IntTools_Context anIntTools;
863 if(anIntTools.IsValidPointForFace(aPnt,
864 theToFace, Precision::Confusion()) == Standard_True) {
865 aGeomSh->setImpl(new TopoDS_Shape(aShape));
866 thePrismAlgo->fixOrientation(aGeomSh);
867 thePrismAlgo->addToShape(aGeomSh);
869 if(anIntTools.IsValidPointForFace(aPnt,
870 theFromFace, Precision::Confusion()) == Standard_True) {
871 aGeomSh->setImpl(new TopoDS_Shape(aShape));
872 thePrismAlgo->fixOrientation(aGeomSh);
873 thePrismAlgo->addFromShape(aGeomSh);
875 } else if(theType == TopAbs_EDGE) {
876 TopoDS_Edge anEdge = TopoDS::Edge(aShape);
877 BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, theToFace);
878 anEdgeCheck.Perform();
879 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
880 aGeomSh->setImpl(new TopoDS_Shape(aShape));
881 thePrismAlgo->fixOrientation(aGeomSh);
882 thePrismAlgo->addToShape(aGeomSh);
884 anEdgeCheck.Init(anEdge, theFromFace);
885 anEdgeCheck.Perform();
886 if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
887 aGeomSh->setImpl(new TopoDS_Shape(aShape));
888 thePrismAlgo->fixOrientation(aGeomSh);
889 thePrismAlgo->addFromShape(aGeomSh);