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