Salome HOME
Update of big models tests and the corresponding corrections.
[modules/shaper.git] / src / GeomAPI / GeomAPI_Shape.cpp
1 // Copyright (C) 2014-2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "GeomAPI_Shape.h"
22
23 #include <BRep_Tool.hxx>
24 #include <BRepAlgoAPI_Section.hxx>
25 #include <BRepBndLib.hxx>
26 #include <BRepBuilderAPI_FindPlane.hxx>
27 #include <BRepExtrema_DistShapeShape.hxx>
28 #include <BRepTools.hxx>
29 #include <Bnd_Box.hxx>
30 #include <Geom_Circle.hxx>
31 #include <Geom_Conic.hxx>
32 #include <Geom_Curve.hxx>
33 #include <Geom_Ellipse.hxx>
34 #include <Geom_Hyperbola.hxx>
35 #include <Geom_Line.hxx>
36 #include <Geom_Parabola.hxx>
37 #include <Geom_Plane.hxx>
38 #include <Geom_RectangularTrimmedSurface.hxx>
39 #include <Geom_TrimmedCurve.hxx>
40 #include <TopExp_Explorer.hxx>
41 #include <TopoDS.hxx>
42 #include <TopoDS_Iterator.hxx>
43 #include <TopoDS_Shape.hxx>
44 #include <NCollection_List.hxx>
45
46 #include <sstream>
47 #include <algorithm> // for std::transform
48
49 #include <BRepTools.hxx>
50
51 #define MY_SHAPE implPtr<TopoDS_Shape>()
52
53 GeomAPI_Shape::GeomAPI_Shape()
54     : GeomAPI_Interface(new TopoDS_Shape())
55 {
56 }
57
58 std::shared_ptr<GeomAPI_Shape> GeomAPI_Shape::emptyCopied() const
59 {
60   GeomShapePtr aShape(new GeomAPI_Shape());
61   aShape->setImpl(new TopoDS_Shape(MY_SHAPE->EmptyCopied()));
62   return aShape;
63 }
64
65 bool GeomAPI_Shape::isNull() const
66 {
67   return MY_SHAPE->IsNull() == Standard_True;
68 }
69
70 bool GeomAPI_Shape::isEqual(const std::shared_ptr<GeomAPI_Shape> theShape) const
71 {
72   if (!theShape.get())
73     return false;
74   if (isNull())
75     return theShape->isNull();
76   if (theShape->isNull())
77     return false;
78
79   return MY_SHAPE->IsEqual(theShape->impl<TopoDS_Shape>()) == Standard_True;
80 }
81
82 bool GeomAPI_Shape::isSame(const std::shared_ptr<GeomAPI_Shape> theShape) const
83 {
84   if (!theShape.get())
85     return false;
86   if (isNull())
87     return theShape->isNull();
88   if (theShape->isNull())
89     return false;
90
91   return MY_SHAPE->IsSame(theShape->impl<TopoDS_Shape>()) == Standard_True;
92 }
93
94 bool GeomAPI_Shape::isVertex() const
95 {
96   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
97   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX;
98 }
99
100 bool GeomAPI_Shape::isEdge() const
101 {
102   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
103   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_EDGE;
104 }
105
106 bool GeomAPI_Shape::isWire() const
107 {
108   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
109   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_WIRE;
110 }
111
112 bool GeomAPI_Shape::isFace() const
113 {
114   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
115   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_FACE;
116 }
117
118 bool GeomAPI_Shape::isCompound() const
119 {
120   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
121   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND;
122 }
123
124 bool GeomAPI_Shape::isCompoundOfSolids() const
125 {
126   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
127   if (aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND)
128     return false;
129   bool isAtLeastOne = false;
130   for(TopoDS_Iterator aSubs(aShape); aSubs.More(); aSubs.Next()) {
131     if (aSubs.Value().IsNull() || aSubs.Value().ShapeType() != TopAbs_SOLID)
132       return false;
133     isAtLeastOne = true;
134   }
135   return isAtLeastOne;
136 }
137
138 GeomAPI_Shape::ShapeType GeomAPI_Shape::typeOfCompoundShapes() const
139 {
140   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
141   if (aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND)
142     return SHAPE;
143   int aType = -1;
144   for(TopoDS_Iterator aSubs(aShape); aSubs.More(); aSubs.Next()) {
145     if (!aSubs.Value().IsNull()) {
146       if (aType == -1)
147         aType = aSubs.Value().ShapeType();
148       else if (aSubs.Value().ShapeType() != aType)
149         return SHAPE;
150     }
151   }
152   return (GeomAPI_Shape::ShapeType) aType;
153 }
154
155 // adds the nopt-compound elements recursively to the list
156 static void addSimpleToList(const TopoDS_Shape& theShape, NCollection_List<TopoDS_Shape>& theList)
157 {
158   if (!theShape.IsNull()) {
159     if (theShape.ShapeType() == TopAbs_COMPOUND) {
160       for(TopoDS_Iterator aSubs(theShape); aSubs.More(); aSubs.Next()) {
161         addSimpleToList(aSubs.Value(), theList);
162       }
163     } else {
164       theList.Append(theShape);
165     }
166   }
167 }
168
169 bool GeomAPI_Shape::isConnectedTopology() const
170 {
171   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
172   if (aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND)
173     return false;
174   // list of simple elements that are not detected in connection to others
175   NCollection_List<TopoDS_Shape> aNotConnected;
176   addSimpleToList(aShape, aNotConnected);
177   if (aNotConnected.IsEmpty()) // an empty compound
178     return false;
179
180   // collect here the group of connected subs, starting with one first element
181   NCollection_List<TopoDS_Shape> aNewConnected;
182   aNewConnected.Append(aNotConnected.First());
183   aNotConnected.RemoveFirst();
184   // iterate until some new element become connected
185   while(!aNewConnected.IsEmpty() && !aNotConnected.IsEmpty()) {
186     NCollection_List<TopoDS_Shape> aNew; // very new connected to new connected
187     NCollection_List<TopoDS_Shape>::Iterator aNotIter(aNotConnected);
188     while(aNotIter.More()) {
189       // optimization to avoid TopExp_Explorer double-cycle, collect all vertices in the list first
190       NCollection_List<TopoDS_Shape> aNotVertices;
191       for(TopExp_Explorer anExp1(aNotIter.Value(), TopAbs_VERTEX); anExp1.More(); anExp1.Next()) {
192         aNotVertices.Append(anExp1.Current());
193       }
194
195       bool aConnected =  false;
196       NCollection_List<TopoDS_Shape>::Iterator aNewIter(aNewConnected);
197       for(; !aConnected && aNewIter.More(); aNewIter.Next()) {
198         // checking topological connecion of aNotIter and aNewIter
199         // (if shapes are connected, vertices are connected for sure)
200         TopExp_Explorer anExp2(aNewIter.Value(), TopAbs_VERTEX);
201         for(; !aConnected && anExp2.More(); anExp2.Next()) {
202           NCollection_List<TopoDS_Shape>::Iterator aNotIter(aNotVertices);
203           for(; aNotIter.More(); aNotIter.Next()) {
204             if (aNotIter.Value().IsSame(anExp2.Current())) {
205               aConnected = true;
206               break;
207             }
208           }
209         }
210       }
211       if (aConnected) {
212         aNew.Append(aNotIter.Value());
213         aNotConnected.Remove(aNotIter);
214       } else {
215         aNotIter.Next();
216       }
217     }
218     // remove all new connected and put to this list very new connected
219     aNewConnected.Clear();
220     aNewConnected.Append(aNew);
221   }
222   return aNotConnected.IsEmpty() == Standard_True;
223 }
224
225 bool GeomAPI_Shape::isSolid() const
226 {
227   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
228   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_SOLID;
229 }
230
231 bool GeomAPI_Shape::isCompSolid() const
232 {
233   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
234   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPSOLID;
235 }
236
237 bool GeomAPI_Shape::isPlanar() const
238 {
239   TopoDS_Shape aShape = impl<TopoDS_Shape>();
240
241   if(aShape.IsNull()) {
242     return false;
243   }
244
245   TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
246   if(aShapeType == TopAbs_COMPOUND) {
247     TopoDS_Iterator anIt(aShape);
248     int aShNum = 0;
249     for(; anIt.More(); anIt.Next()) {
250       ++aShNum;
251     }
252     if(aShNum == 1) {
253       anIt.Initialize(aShape);
254       aShape = anIt.Value();
255     }
256   }
257
258   aShapeType = aShape.ShapeType();
259   if(aShapeType == TopAbs_VERTEX) {
260     return true;
261   } else if(aShapeType == TopAbs_FACE) {
262     const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface(TopoDS::Face(aShape));
263     Handle(Standard_Type) aType = aSurface->DynamicType();
264
265     if(aType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
266       Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
267         Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
268       aType = aTrimSurface->BasisSurface()->DynamicType();
269     }
270     return (aType == STANDARD_TYPE(Geom_Plane)) == Standard_True;
271   } else {
272     BRepBuilderAPI_FindPlane aFindPlane(aShape);
273     bool isFound = aFindPlane.Found() == Standard_True;
274
275     if(!isFound && aShapeType == TopAbs_EDGE) {
276       Standard_Real aFirst, aLast;
277       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(aShape), aFirst, aLast);
278       Handle(Standard_Type) aType = aCurve->DynamicType();
279
280       if(aType == STANDARD_TYPE(Geom_TrimmedCurve)) {
281         Handle(Geom_TrimmedCurve) aTrimCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve);
282         aType = aTrimCurve->BasisCurve()->DynamicType();
283       }
284
285       if(aType == STANDARD_TYPE(Geom_Line)
286           || aType == STANDARD_TYPE(Geom_Conic)
287           || aType == STANDARD_TYPE(Geom_Circle)
288           || aType == STANDARD_TYPE(Geom_Ellipse)
289           || aType == STANDARD_TYPE(Geom_Hyperbola)
290           || aType == STANDARD_TYPE(Geom_Parabola)) {
291         isFound = true;
292       }
293     }
294
295     return isFound;
296   }
297
298   return false;
299 }
300
301 GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeType() const
302 {
303   const TopoDS_Shape& aShape = impl<TopoDS_Shape>();
304   if (aShape.IsNull())
305     return GeomAPI_Shape::SHAPE;
306
307   ShapeType aST = GeomAPI_Shape::SHAPE;
308
309   switch(aShape.ShapeType()) {
310   case TopAbs_COMPOUND:
311     aST = GeomAPI_Shape::COMPOUND;
312     break;
313   case TopAbs_COMPSOLID:
314     aST = GeomAPI_Shape::COMPSOLID;
315     break;
316   case TopAbs_SOLID:
317     aST = GeomAPI_Shape::SOLID;
318     break;
319   case TopAbs_SHELL:
320     aST = GeomAPI_Shape::SHELL;
321     break;
322   case TopAbs_FACE:
323     aST = GeomAPI_Shape::FACE;
324     break;
325   case TopAbs_WIRE:
326     aST = GeomAPI_Shape::WIRE;
327     break;
328   case TopAbs_EDGE:
329     aST = GeomAPI_Shape::EDGE;
330     break;
331   case TopAbs_VERTEX:
332     aST = GeomAPI_Shape::VERTEX;
333     break;
334   case TopAbs_SHAPE:
335     aST = GeomAPI_Shape::SHAPE;
336     break;
337   }
338
339   return aST;
340 }
341
342 GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeTypeByStr(std::string theType)
343 {
344   std::transform(theType.begin(), theType.end(), theType.begin(), ::toupper);
345   if (theType == "COMPOUND")
346     return COMPOUND;
347   if (theType == "COMPSOLID")
348     return COMPSOLID;
349   if (theType == "SOLID")
350     return SOLID;
351   if (theType == "SHELL")
352     return SHELL;
353   if (theType == "FACE")
354     return FACE;
355   if (theType == "WIRE")
356     return WIRE;
357   if (theType == "EDGE")
358     return EDGE;
359   if (theType == "VERTEX")
360     return VERTEX;
361   return SHAPE; // default
362 }
363
364 std::string GeomAPI_Shape::shapeTypeStr() const
365 {
366   ShapeType aShapeType = shapeType();
367   std::string aShapeTypeStr;
368
369   switch(aShapeType) {
370     case COMPOUND: {
371       aShapeTypeStr = "COMPOUND";
372       break;
373     }
374     case COMPSOLID: {
375       aShapeTypeStr = "COMPSOLID";
376       break;
377     }
378     case SOLID: {
379       aShapeTypeStr = "SOLID";
380       break;
381     }
382     case SHELL: {
383       aShapeTypeStr = "SHELL";
384       break;
385     }
386     case FACE: {
387       aShapeTypeStr = "FACE";
388       break;
389     }
390     case WIRE: {
391       aShapeTypeStr = "WIRE";
392       break;
393     }
394     case EDGE: {
395       aShapeTypeStr = "EDGE";
396       break;
397     }
398     case VERTEX: {
399       aShapeTypeStr = "VERTEX";
400       break;
401     }
402     case SHAPE: {
403       aShapeTypeStr = "SHAPE";
404       break;
405     }
406   }
407
408   return aShapeTypeStr;
409 }
410
411 GeomAPI_Shape::Orientation GeomAPI_Shape::orientation() const
412 {
413   TopAbs_Orientation anOrientation = MY_SHAPE->Orientation();
414
415   switch(anOrientation) {
416     case TopAbs_FORWARD:  return FORWARD;
417     case TopAbs_REVERSED: return REVERSED;
418     case TopAbs_INTERNAL: return INTERNAL;
419     case TopAbs_EXTERNAL: return EXTERNAL;
420     default:              return FORWARD;
421   }
422 }
423
424 void GeomAPI_Shape::setOrientation(const GeomAPI_Shape::Orientation theOrientation)
425 {
426   TopAbs_Orientation anOrientation = MY_SHAPE->Orientation();
427
428   switch(theOrientation) {
429     case FORWARD:  MY_SHAPE->Orientation(TopAbs_FORWARD);  break;
430     case REVERSED: MY_SHAPE->Orientation(TopAbs_REVERSED); break;
431     case INTERNAL: MY_SHAPE->Orientation(TopAbs_INTERNAL); break;
432     case EXTERNAL: MY_SHAPE->Orientation(TopAbs_EXTERNAL); break;
433   }
434 }
435
436 void GeomAPI_Shape::reverse()
437 {
438   MY_SHAPE->Reverse();
439 }
440
441 bool GeomAPI_Shape::isSubShape(const std::shared_ptr<GeomAPI_Shape> theShape,
442                                const bool theCheckOrientation) const
443 {
444   if(!theShape.get()) {
445     return false;
446   }
447
448   const TopoDS_Shape& aShapeToSearch = theShape->impl<TopoDS_Shape>();
449   if(aShapeToSearch.IsNull()) {
450     return false;
451   }
452
453   for(TopExp_Explorer anExp(*MY_SHAPE, aShapeToSearch.ShapeType()); anExp.More(); anExp.Next()) {
454     if(theCheckOrientation ?
455        aShapeToSearch.IsEqual(anExp.Current()) : aShapeToSearch.IsSame(anExp.Current())) {
456       return true;
457     }
458   }
459
460   return false;
461 }
462
463 bool GeomAPI_Shape::computeSize(double& theXmin, double& theYmin, double& theZmin,
464                                 double& theXmax, double& theYmax, double& theZmax) const
465 {
466   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
467   if (aShape.IsNull())
468     return false;
469   Bnd_Box aBndBox;
470   BRepBndLib::Add(aShape, aBndBox);
471   aBndBox.Get(theXmin, theYmin, theZmin, theXmax, theYmax, theZmax);
472   return true;
473 }
474
475 std::string GeomAPI_Shape::getShapeStream() const
476 {
477   std::ostringstream aStream;
478   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
479   BRepTools::Write(aShape, aStream);
480   return aStream.str();
481 }
482
483 GeomShapePtr GeomAPI_Shape::intersect(const GeomShapePtr theShape) const
484 {
485   const TopoDS_Shape& aShape1 = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
486   const TopoDS_Shape& aShape2 = theShape->impl<TopoDS_Shape>();
487
488   BRepAlgoAPI_Section aCommon(aShape1, aShape2);
489   if (!aCommon.IsDone())
490     return GeomShapePtr();
491
492   TopoDS_Shape aResult = aCommon.Shape();
493   if (aResult.ShapeType() == TopAbs_COMPOUND) {
494     NCollection_List<TopoDS_Shape> aSubs;
495     addSimpleToList(aResult, aSubs);
496     if(aSubs.Size() == 1) {
497       aResult = aSubs.First();
498     } else if(aSubs.Size() == 0) {
499       return GeomShapePtr();
500     }
501   }
502
503   GeomShapePtr aResShape(new GeomAPI_Shape);
504   aResShape->setImpl(new TopoDS_Shape(aResult));
505   return aResShape;
506 }
507
508 bool GeomAPI_Shape::isIntersect(const GeomShapePtr theShape) const
509 {
510   if(!theShape.get()) {
511     return false;
512   }
513
514   const TopoDS_Shape& aShape1 = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
515   const TopoDS_Shape& aShape2 = theShape->impl<TopoDS_Shape>();
516
517   BRepExtrema_DistShapeShape aDist(aShape1, aShape2);
518   aDist.Perform();
519   if(aDist.IsDone() && aDist.Value() < Precision::Confusion()) {
520     return true;
521   }
522
523   return false;
524 }
525
526 void GeomAPI_Shape::translate(const std::shared_ptr<GeomAPI_Dir> theDir, const double theOffset)
527 {
528   gp_Dir aDir = theDir->impl<gp_Dir>();
529   gp_Vec aTrsfVec(aDir.XYZ() * theOffset);
530   gp_Trsf aTranslation;
531   aTranslation.SetTranslation(aTrsfVec);
532   TopoDS_Shape aResult = MY_SHAPE->Moved(aTranslation);
533   setImpl(new TopoDS_Shape(aResult));
534 }