Salome HOME
Issue #2971: Naming issue in a group when loading a dump file
[modules/shaper.git] / src / GeomAPI / GeomAPI_Shape.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "GeomAPI_Shape.h"
21
22 #include <GeomAPI_Pnt.h>
23 #include <GeomAPI_Vertex.h>
24 #include <GeomAPI_Edge.h>
25 #include <GeomAPI_Wire.h>
26 #include <GeomAPI_Face.h>
27 #include <GeomAPI_Shell.h>
28 #include <GeomAPI_Solid.h>
29
30 #include <BRep_Tool.hxx>
31 #include <BRepAlgoAPI_Section.hxx>
32 #include <BRepBndLib.hxx>
33 #include <BRepBuilderAPI_FindPlane.hxx>
34 #include <BRepExtrema_DistShapeShape.hxx>
35 #include <BRepTools.hxx>
36 #include <Bnd_Box.hxx>
37 #include <Geom_Circle.hxx>
38 #include <Geom_Conic.hxx>
39 #include <Geom_Curve.hxx>
40 #include <Geom_Ellipse.hxx>
41 #include <Geom_Hyperbola.hxx>
42 #include <Geom_Line.hxx>
43 #include <Geom_Parabola.hxx>
44 #include <Geom_Plane.hxx>
45 #include <Geom_RectangularTrimmedSurface.hxx>
46 #include <Geom_TrimmedCurve.hxx>
47 #include <TopExp_Explorer.hxx>
48 #include <TopoDS.hxx>
49 #include <TopoDS_Iterator.hxx>
50 #include <TopoDS_Shape.hxx>
51 #include <NCollection_List.hxx>
52
53 #include <BOPAlgo_CheckerSI.hxx>
54 #include <BOPDS_DS.hxx>
55
56 #include <sstream>
57 #include <algorithm> // for std::transform
58
59 #include <BRepTools.hxx>
60
61 #define MY_SHAPE implPtr<TopoDS_Shape>()
62
63 GeomAPI_Shape::GeomAPI_Shape()
64     : GeomAPI_Interface(new TopoDS_Shape())
65 {
66 }
67
68 std::shared_ptr<GeomAPI_Shape> GeomAPI_Shape::emptyCopied() const
69 {
70   GeomShapePtr aShape(new GeomAPI_Shape());
71   aShape->setImpl(new TopoDS_Shape(MY_SHAPE->EmptyCopied()));
72   return aShape;
73 }
74
75 bool GeomAPI_Shape::isNull() const
76 {
77   return MY_SHAPE->IsNull() == Standard_True;
78 }
79
80 bool GeomAPI_Shape::isEqual(const std::shared_ptr<GeomAPI_Shape> theShape) const
81 {
82   if (!theShape.get())
83     return false;
84   if (isNull())
85     return theShape->isNull();
86   if (theShape->isNull())
87     return false;
88
89   return MY_SHAPE->IsEqual(theShape->impl<TopoDS_Shape>()) == Standard_True;
90 }
91
92 bool GeomAPI_Shape::isSame(const std::shared_ptr<GeomAPI_Shape> theShape) const
93 {
94   if (!theShape.get())
95     return false;
96   if (isNull())
97     return theShape->isNull();
98   if (theShape->isNull())
99     return false;
100
101   return MY_SHAPE->IsSame(theShape->impl<TopoDS_Shape>()) == Standard_True;
102 }
103
104 bool GeomAPI_Shape::isSameGeometry(const std::shared_ptr<GeomAPI_Shape> theShape) const
105 {
106   if (isFace())
107     return face()->isSameGeometry(theShape);
108   else if (isEdge())
109     return edge()->isSameGeometry(theShape);
110   return false;
111 }
112
113 bool GeomAPI_Shape::isVertex() const
114 {
115   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
116   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX;
117 }
118
119 bool GeomAPI_Shape::isEdge() const
120 {
121   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
122   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_EDGE;
123 }
124
125 bool GeomAPI_Shape::isWire() const
126 {
127   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
128   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_WIRE;
129 }
130
131 bool GeomAPI_Shape::isFace() const
132 {
133   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
134   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_FACE;
135 }
136
137 bool GeomAPI_Shape::isShell() const
138 {
139   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
140   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_SHELL;
141 }
142
143 bool GeomAPI_Shape::isCompound() const
144 {
145   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
146   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND;
147 }
148
149 bool GeomAPI_Shape::isCompoundOfSolids() const
150 {
151   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
152   if (aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND)
153     return false;
154   bool isAtLeastOne = false;
155   for(TopoDS_Iterator aSubs(aShape); aSubs.More(); aSubs.Next()) {
156     if (aSubs.Value().IsNull() || aSubs.Value().ShapeType() != TopAbs_SOLID)
157       return false;
158     isAtLeastOne = true;
159   }
160   return isAtLeastOne;
161 }
162
163 // LCOV_EXCL_START
164 GeomAPI_Shape::ShapeType GeomAPI_Shape::typeOfCompoundShapes() const
165 {
166   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
167   if (aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND)
168     return SHAPE;
169   int aType = -1;
170   for(TopoDS_Iterator aSubs(aShape); aSubs.More(); aSubs.Next()) {
171     if (!aSubs.Value().IsNull()) {
172       if (aType == -1)
173         aType = aSubs.Value().ShapeType();
174       else if (aSubs.Value().ShapeType() != aType)
175         return SHAPE;
176     }
177   }
178   return (GeomAPI_Shape::ShapeType) aType;
179 }
180 // LCOV_EXCL_STOP
181
182 // adds the nopt-compound elements recursively to the list
183 static void addSimpleToList(const TopoDS_Shape& theShape, NCollection_List<TopoDS_Shape>& theList)
184 {
185   if (!theShape.IsNull()) {
186     if (theShape.ShapeType() == TopAbs_COMPOUND) {
187       for(TopoDS_Iterator aSubs(theShape); aSubs.More(); aSubs.Next()) {
188         addSimpleToList(aSubs.Value(), theList);
189       }
190     } else {
191       theList.Append(theShape);
192     }
193   }
194 }
195
196 bool GeomAPI_Shape::isConnectedTopology() const
197 {
198   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
199   if (aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND)
200     return false;
201   // list of simple elements that are not detected in connection to others
202   NCollection_List<TopoDS_Shape> aNotConnected;
203   addSimpleToList(aShape, aNotConnected);
204   if (aNotConnected.IsEmpty()) // an empty compound
205     return false;
206
207   // collect here the group of connected subs, starting with one first element
208   NCollection_List<TopoDS_Shape> aNewConnected;
209   aNewConnected.Append(aNotConnected.First());
210   aNotConnected.RemoveFirst();
211   // iterate until some new element become connected
212   while(!aNewConnected.IsEmpty() && !aNotConnected.IsEmpty()) {
213     NCollection_List<TopoDS_Shape> aNew; // very new connected to new connected
214     NCollection_List<TopoDS_Shape>::Iterator aNotIter(aNotConnected);
215     while(aNotIter.More()) {
216       // optimization to avoid TopExp_Explorer double-cycle, collect all vertices in the list first
217       NCollection_List<TopoDS_Shape> aNotVertices;
218       for(TopExp_Explorer anExp1(aNotIter.Value(), TopAbs_VERTEX); anExp1.More(); anExp1.Next()) {
219         aNotVertices.Append(anExp1.Current());
220       }
221
222       bool aConnected =  false;
223       NCollection_List<TopoDS_Shape>::Iterator aNewIter(aNewConnected);
224       for(; !aConnected && aNewIter.More(); aNewIter.Next()) {
225         // checking topological connecion of aNotIter and aNewIter
226         // (if shapes are connected, vertices are connected for sure)
227         TopExp_Explorer anExp2(aNewIter.Value(), TopAbs_VERTEX);
228         for(; !aConnected && anExp2.More(); anExp2.Next()) {
229           NCollection_List<TopoDS_Shape>::Iterator aNotIter(aNotVertices);
230           for(; aNotIter.More(); aNotIter.Next()) {
231             if (aNotIter.Value().IsSame(anExp2.Current())) {
232               aConnected = true;
233               break;
234             }
235           }
236         }
237       }
238       if (aConnected) {
239         aNew.Append(aNotIter.Value());
240         aNotConnected.Remove(aNotIter);
241       } else {
242         aNotIter.Next();
243       }
244     }
245     // remove all new connected and put to this list very new connected
246     aNewConnected.Clear();
247     aNewConnected.Append(aNew);
248   }
249   return aNotConnected.IsEmpty() == Standard_True;
250 }
251
252 bool GeomAPI_Shape::isSolid() const
253 {
254   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
255   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_SOLID;
256 }
257
258 bool GeomAPI_Shape::isCompSolid() const
259 {
260   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
261   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPSOLID;
262 }
263
264 bool GeomAPI_Shape::isPlanar() const
265 {
266   TopoDS_Shape aShape = impl<TopoDS_Shape>();
267
268   if(aShape.IsNull()) {
269     return false;
270   }
271
272   TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
273   if(aShapeType == TopAbs_COMPOUND) {
274     TopoDS_Iterator anIt(aShape);
275     int aShNum = 0;
276     for(; anIt.More(); anIt.Next()) {
277       ++aShNum;
278     }
279     if(aShNum == 1) {
280       anIt.Initialize(aShape);
281       aShape = anIt.Value();
282     }
283   }
284
285   aShapeType = aShape.ShapeType();
286   if(aShapeType == TopAbs_VERTEX) {
287     return true;
288   } else if(aShapeType == TopAbs_FACE) {
289     const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface(TopoDS::Face(aShape));
290     Handle(Standard_Type) aType = aSurface->DynamicType();
291
292     if(aType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
293       Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
294         Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
295       aType = aTrimSurface->BasisSurface()->DynamicType();
296     }
297     return (aType == STANDARD_TYPE(Geom_Plane)) == Standard_True;
298   } else {
299     BRepBuilderAPI_FindPlane aFindPlane(aShape);
300     bool isFound = aFindPlane.Found() == Standard_True;
301
302     if(!isFound && aShapeType == TopAbs_EDGE) {
303       Standard_Real aFirst, aLast;
304       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(aShape), aFirst, aLast);
305       Handle(Standard_Type) aType = aCurve->DynamicType();
306
307       if(aType == STANDARD_TYPE(Geom_TrimmedCurve)) {
308         Handle(Geom_TrimmedCurve) aTrimCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve);
309         aType = aTrimCurve->BasisCurve()->DynamicType();
310       }
311
312       if(aType == STANDARD_TYPE(Geom_Line)
313           || aType == STANDARD_TYPE(Geom_Conic)
314           || aType == STANDARD_TYPE(Geom_Circle)
315           || aType == STANDARD_TYPE(Geom_Ellipse)
316           || aType == STANDARD_TYPE(Geom_Hyperbola)
317           || aType == STANDARD_TYPE(Geom_Parabola)) {
318         isFound = true;
319       }
320     }
321
322     return isFound;
323   }
324
325   return false;
326 }
327
328 std::shared_ptr<GeomAPI_Vertex> GeomAPI_Shape::vertex() const
329 {
330   GeomVertexPtr aVertex;
331   if (isVertex()) {
332     const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
333     aVertex = GeomVertexPtr(new GeomAPI_Vertex);
334     aVertex->setImpl(new TopoDS_Shape(aShape));
335   }
336   return aVertex;
337 }
338
339 std::shared_ptr<GeomAPI_Edge> GeomAPI_Shape::edge() const
340 {
341   GeomEdgePtr anEdge;
342   if (isEdge()) {
343     const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
344     anEdge = GeomEdgePtr(new GeomAPI_Edge);
345     anEdge->setImpl(new TopoDS_Shape(aShape));
346   }
347   return anEdge;
348 }
349
350 std::shared_ptr<GeomAPI_Wire> GeomAPI_Shape::wire() const
351 {
352   GeomWirePtr aWire;
353   if (isWire()) {
354     const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
355     aWire = GeomWirePtr(new GeomAPI_Wire);
356     aWire->setImpl(new TopoDS_Shape(aShape));
357   }
358   return aWire;
359 }
360
361 std::shared_ptr<GeomAPI_Face> GeomAPI_Shape::face() const
362 {
363   GeomFacePtr aFace;
364   if (isFace()) {
365     const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
366     aFace = GeomFacePtr(new GeomAPI_Face);
367     aFace->setImpl(new TopoDS_Shape(aShape));
368   }
369   return aFace;
370 }
371
372 std::shared_ptr<GeomAPI_Shell> GeomAPI_Shape::shell() const
373 {
374   GeomShellPtr aShell;
375   if (isShell()) {
376     const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
377     aShell = GeomShellPtr(new GeomAPI_Shell);
378     aShell->setImpl(new TopoDS_Shape(aShape));
379   }
380   return aShell;
381 }
382
383 std::shared_ptr<GeomAPI_Solid> GeomAPI_Shape::solid() const
384 {
385   GeomSolidPtr aSolid;
386   if (isSolid()) {
387     const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
388     aSolid = GeomSolidPtr(new GeomAPI_Solid);
389     aSolid->setImpl(new TopoDS_Shape(aShape));
390   }
391   return aSolid;
392 }
393
394 std::list<std::shared_ptr<GeomAPI_Shape> >
395 GeomAPI_Shape::subShapes(ShapeType theSubShapeType) const
396 {
397   ListOfShape aSubs;
398   const TopoDS_Shape& aShape = impl<TopoDS_Shape>();
399   if (aShape.IsNull())
400     return aSubs;
401
402   // process multi-level compounds
403   if (shapeType() == COMPOUND && theSubShapeType == COMPOUND) {
404     for (TopoDS_Iterator anIt(aShape); anIt.More(); anIt.Next()) {
405       const TopoDS_Shape& aCurrent = anIt.Value();
406       if (aCurrent.ShapeType() == TopAbs_COMPOUND) {
407         GeomShapePtr aSub(new GeomAPI_Shape);
408         aSub->setImpl(new TopoDS_Shape(aCurrent));
409         aSubs.push_back(aSub);
410       }
411     }
412     // add self
413     GeomShapePtr aSub(new GeomAPI_Shape);
414     aSub->setImpl(new TopoDS_Shape(aShape));
415     aSubs.push_back(aSub);
416   }
417   else {
418     for (TopExp_Explorer anExp(aShape, (TopAbs_ShapeEnum)theSubShapeType);
419          anExp.More(); anExp.Next()) {
420       GeomShapePtr aSub(new GeomAPI_Shape);
421       aSub->setImpl(new TopoDS_Shape(anExp.Current()));
422       aSubs.push_back(aSub);
423     }
424   }
425   return aSubs;
426 }
427
428 GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeType() const
429 {
430   const TopoDS_Shape& aShape = impl<TopoDS_Shape>();
431   if (aShape.IsNull())
432     return GeomAPI_Shape::SHAPE;
433
434   ShapeType aST = GeomAPI_Shape::SHAPE;
435
436   switch(aShape.ShapeType()) {
437   case TopAbs_COMPOUND:
438     aST = GeomAPI_Shape::COMPOUND;
439     break;
440   case TopAbs_COMPSOLID:
441     aST = GeomAPI_Shape::COMPSOLID;
442     break;
443   case TopAbs_SOLID:
444     aST = GeomAPI_Shape::SOLID;
445     break;
446   case TopAbs_SHELL:
447     aST = GeomAPI_Shape::SHELL;
448     break;
449   case TopAbs_FACE:
450     aST = GeomAPI_Shape::FACE;
451     break;
452   case TopAbs_WIRE:
453     aST = GeomAPI_Shape::WIRE;
454     break;
455   case TopAbs_EDGE:
456     aST = GeomAPI_Shape::EDGE;
457     break;
458   case TopAbs_VERTEX:
459     aST = GeomAPI_Shape::VERTEX;
460     break;
461   case TopAbs_SHAPE:
462     aST = GeomAPI_Shape::SHAPE;
463     break;
464   }
465
466   return aST;
467 }
468
469 GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeTypeByStr(std::string theType)
470 {
471   std::transform(theType.begin(), theType.end(), theType.begin(), ::toupper);
472   if (theType == "COMPOUND" || theType == "COMPOUNDS")
473     return COMPOUND;
474   if (theType == "COMPSOLID" || theType == "COMPSOLIDS")
475     return COMPSOLID;
476   if (theType == "SOLID" || theType == "SOLIDS")
477     return SOLID;
478   if (theType == "SHELL" || theType == "SHELLS")
479     return SHELL;
480   if (theType == "FACE" || theType == "FACES")
481     return FACE;
482   if (theType == "WIRE" || theType == "WIRES")
483     return WIRE;
484   if (theType == "EDGE" || theType == "EDGES")
485     return EDGE;
486   if (theType == "VERTEX" || theType == "VERTICES")
487     return VERTEX;
488   return SHAPE; // default
489 }
490
491 std::string GeomAPI_Shape::shapeTypeStr() const
492 {
493   ShapeType aShapeType = shapeType();
494   std::string aShapeTypeStr;
495
496   switch(aShapeType) {
497     case COMPOUND: {
498       aShapeTypeStr = "COMPOUND";
499       break;
500     }
501     case COMPSOLID: {
502       aShapeTypeStr = "COMPSOLID";
503       break;
504     }
505     case SOLID: {
506       aShapeTypeStr = "SOLID";
507       break;
508     }
509     case SHELL: {
510       aShapeTypeStr = "SHELL";
511       break;
512     }
513     case FACE: {
514       aShapeTypeStr = "FACE";
515       break;
516     }
517     case WIRE: {
518       aShapeTypeStr = "WIRE";
519       break;
520     }
521     case EDGE: {
522       aShapeTypeStr = "EDGE";
523       break;
524     }
525     case VERTEX: {
526       aShapeTypeStr = "VERTEX";
527       break;
528     }
529     case SHAPE: {
530       aShapeTypeStr = "SHAPE";
531       break;
532     }
533   }
534
535   return aShapeTypeStr;
536 }
537
538 GeomAPI_Shape::Orientation GeomAPI_Shape::orientation() const
539 {
540   TopAbs_Orientation anOrientation = MY_SHAPE->Orientation();
541
542   switch(anOrientation) {
543     case TopAbs_FORWARD:  return FORWARD;
544     case TopAbs_REVERSED: return REVERSED;
545     case TopAbs_INTERNAL: return INTERNAL;
546     case TopAbs_EXTERNAL: return EXTERNAL;
547     default:              return FORWARD;
548   }
549 }
550
551 void GeomAPI_Shape::setOrientation(const GeomAPI_Shape::Orientation theOrientation)
552 {
553   TopAbs_Orientation anOrientation = MY_SHAPE->Orientation();
554
555   switch(theOrientation) {
556     case FORWARD:  MY_SHAPE->Orientation(TopAbs_FORWARD);  break;
557     case REVERSED: MY_SHAPE->Orientation(TopAbs_REVERSED); break;
558     case INTERNAL: MY_SHAPE->Orientation(TopAbs_INTERNAL); break;
559     case EXTERNAL: MY_SHAPE->Orientation(TopAbs_EXTERNAL); break;
560   }
561 }
562
563 void GeomAPI_Shape::reverse()
564 {
565   MY_SHAPE->Reverse();
566 }
567
568 bool GeomAPI_Shape::isSubShape(const std::shared_ptr<GeomAPI_Shape> theShape,
569                                const bool theCheckOrientation) const
570 {
571   if(!theShape.get()) {
572     return false;
573   }
574
575   const TopoDS_Shape& aShapeToSearch = theShape->impl<TopoDS_Shape>();
576   if(aShapeToSearch.IsNull()) {
577     return false;
578   }
579
580   for(TopExp_Explorer anExp(*MY_SHAPE, aShapeToSearch.ShapeType()); anExp.More(); anExp.Next()) {
581     if(theCheckOrientation ?
582        aShapeToSearch.IsEqual(anExp.Current()) : aShapeToSearch.IsSame(anExp.Current())) {
583       return true;
584     }
585   }
586
587   return false;
588 }
589
590 bool GeomAPI_Shape::computeSize(double& theXmin, double& theYmin, double& theZmin,
591                                 double& theXmax, double& theYmax, double& theZmax) const
592 {
593   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
594   if (aShape.IsNull())
595     return false;
596   Bnd_Box aBndBox;
597   BRepBndLib::Add(aShape, aBndBox, false);
598   if (aBndBox.IsVoid())
599     return false;
600   aBndBox.Get(theXmin, theYmin, theZmin, theXmax, theYmax, theZmax);
601   return true;
602 }
603
604 GeomPointPtr GeomAPI_Shape::middlePoint() const
605 {
606   GeomPointPtr aMiddlePoint;
607
608   switch (shapeType()) {
609   case VERTEX:
610     aMiddlePoint = vertex()->point();
611     break;
612   case EDGE:
613     aMiddlePoint = edge()->middlePoint();
614     break;
615   case WIRE:
616     aMiddlePoint = wire()->middlePoint();
617     break;
618   case FACE:
619     aMiddlePoint = face()->middlePoint();
620     break;
621   case SHELL:
622     aMiddlePoint = shell()->middlePoint();
623     break;
624   case SOLID:
625     aMiddlePoint = solid()->middlePoint();
626     break;
627   default: {
628       // get middle point as center of the bounding box
629       double aMinX, aMinY, aMinZ, aMaxX, aMaxY, aMaxZ;
630       computeSize(aMinX, aMinY, aMinZ, aMaxX, aMaxY, aMaxZ);
631       aMiddlePoint = GeomPointPtr(new GeomAPI_Pnt(
632           (aMinX + aMaxX) * 0.5, (aMinY + aMaxY) * 0.5, (aMinZ + aMaxZ) * 0.5));
633     }
634   }
635
636   return aMiddlePoint;
637 }
638
639 // LCOV_EXCL_START
640 std::string GeomAPI_Shape::getShapeStream() const
641 {
642   std::ostringstream aStream;
643   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
644   BRepTools::Write(aShape, aStream);
645   return aStream.str();
646 }
647 // LCOV_EXCL_STOP
648
649 GeomShapePtr GeomAPI_Shape::intersect(const GeomShapePtr theShape) const
650 {
651   const TopoDS_Shape& aShape1 = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
652   const TopoDS_Shape& aShape2 = theShape->impl<TopoDS_Shape>();
653
654   BRepAlgoAPI_Section aCommon(aShape1, aShape2);
655   if (!aCommon.IsDone())
656     return GeomShapePtr();
657
658   TopoDS_Shape aResult = aCommon.Shape();
659   if (aResult.ShapeType() == TopAbs_COMPOUND) {
660     NCollection_List<TopoDS_Shape> aSubs;
661     addSimpleToList(aResult, aSubs);
662     if(aSubs.Size() == 1) {
663       aResult = aSubs.First();
664     } else if(aSubs.Size() == 0) {
665       return GeomShapePtr();
666     }
667   }
668
669   GeomShapePtr aResShape(new GeomAPI_Shape);
670   aResShape->setImpl(new TopoDS_Shape(aResult));
671   return aResShape;
672 }
673
674 bool GeomAPI_Shape::isIntersect(const GeomShapePtr theShape) const
675 {
676   if(!theShape.get()) {
677     return false;
678   }
679
680   const TopoDS_Shape& aShape1 = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
681   const TopoDS_Shape& aShape2 = theShape->impl<TopoDS_Shape>();
682
683   BRepExtrema_DistShapeShape aDist(aShape1, aShape2);
684   aDist.Perform();
685   if(aDist.IsDone() && aDist.Value() < Precision::Confusion()) {
686     return true;
687   }
688
689   return false;
690 }
691
692 void GeomAPI_Shape::translate(const std::shared_ptr<GeomAPI_Dir> theDir, const double theOffset)
693 {
694   gp_Dir aDir = theDir->impl<gp_Dir>();
695   gp_Vec aTrsfVec(aDir.XYZ() * theOffset);
696   gp_Trsf aTranslation;
697   aTranslation.SetTranslation(aTrsfVec);
698   TopoDS_Shape aResult = MY_SHAPE->Moved(aTranslation);
699   setImpl(new TopoDS_Shape(aResult));
700 }
701
702 bool GeomAPI_Shape::isSelfIntersected(const int theLevelOfCheck) const
703 {
704   BOPAlgo_CheckerSI aCSI;  // checker of self-interferences
705   aCSI.SetLevelOfCheck(theLevelOfCheck);
706   TopTools_ListOfShape aList;
707   const TopoDS_Shape& aThisShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
708   aList.Append(aThisShape);
709   aCSI.SetArguments(aList);
710   aCSI.Perform();
711   if (aCSI.HasErrors() || aCSI.DS().Interferences().Extent() > 0) {
712     return true;
713   }
714
715   return false;
716 }
717
718 bool GeomAPI_Shape::Comparator::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
719                                            const std::shared_ptr<GeomAPI_Shape>& theShape2) const
720 {
721   const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
722   const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
723   bool isLess = aShape1.TShape() < aShape2.TShape();
724   if (aShape1.TShape() == aShape2.TShape()) {
725     Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
726     Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
727     isLess = aHash1 < aHash2;
728   }
729   return isLess;
730 }
731
732 bool GeomAPI_Shape::ComparatorWithOri::operator()(
733     const std::shared_ptr<GeomAPI_Shape>& theShape1,
734     const std::shared_ptr<GeomAPI_Shape>& theShape2) const
735 {
736   const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
737   const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
738   bool isLess = aShape1.TShape() < aShape2.TShape();
739   if (aShape1.TShape() == aShape2.TShape()) {
740     Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
741     Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
742     isLess = (aHash1 < aHash2) ||
743              (aHash1 == aHash2 && aShape1.Orientation() < aShape2.Orientation());
744   }
745   return isLess;
746 }