Salome HOME
Correct case when the weak-named attribute is dumped in Geom mode: geometrical repres...
[modules/shaper.git] / src / GeomAPI / GeomAPI_Shell.cpp
1 // Copyright (C) 2018-20xx  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_Shell.h"
22
23 #include "GeomAPI_Ax3.h"
24 #include "GeomAPI_Box.h"
25 #include "GeomAPI_Cone.h"
26 #include "GeomAPI_Cylinder.h"
27 #include "GeomAPI_Face.h"
28 #include "GeomAPI_Pnt.h"
29 #include "GeomAPI_Sphere.h"
30 #include "GeomAPI_Torus.h"
31 #include "GeomAPI_Wire.h"
32 #include "GeomAPI_XYZ.h"
33
34 #include <BRep_Builder.hxx>
35 #include <BRepGProp.hxx>
36 #include <GProp_GProps.hxx>
37 #include <Precision.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <TopoDS.hxx>
40
41 #include <map>
42
43 //=================================================================================================
44 GeomAPI_Shell::GeomAPI_Shell()
45 {
46   TopoDS_Shell* aShell = new TopoDS_Shell();
47
48   BRep_Builder aBuilder;
49   aBuilder.MakeShell(*aShell);
50
51   this->setImpl(aShell);
52 }
53
54 //=================================================================================================
55 GeomAPI_Shell::GeomAPI_Shell(const std::shared_ptr<GeomAPI_Shape>& theShape)
56 {
57   if (!theShape->isNull() && theShape->isShell()) {
58     setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
59   }
60 }
61
62 //=================================================================================================
63 std::shared_ptr<GeomAPI_Sphere> GeomAPI_Shell::getSphere() const
64 {
65   bool isSphere = true;
66   bool isFirstFace = true;
67   GeomSpherePtr aSphere;
68
69   for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
70     GeomFacePtr aFace(new GeomAPI_Face);
71     aFace->setImpl(new TopoDS_Shape(anExp.Current()));
72
73     GeomSpherePtr aCurSphere = aFace->getSphere();
74     if (!aCurSphere) {
75       isSphere = false;
76       break;
77     }
78
79     if (isFirstFace) {
80       aSphere = aCurSphere;
81       isFirstFace = false;
82     }
83     else if (aSphere->center()->distance(aCurSphere->center()) >= Precision::Confusion() ||
84              Abs(aSphere->radius() - aCurSphere->radius()) >= Precision::Confusion()) {
85       isSphere = false;
86       break;
87     }
88   }
89
90   return isSphere ? aSphere : GeomSpherePtr();
91 }
92
93 //=================================================================================================
94 std::shared_ptr<GeomAPI_Cylinder> GeomAPI_Shell::getCylinder() const
95 {
96   bool isCylinder = true;
97   bool isFirstFace = true;
98
99   GeomPointPtr aLocation;
100   GeomDirPtr anAxis;
101   double aRadius;
102   double aHeight;
103
104   for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
105     GeomFacePtr aFace(new GeomAPI_Face);
106     aFace->setImpl(new TopoDS_Shape(anExp.Current()));
107
108     GeomCylinderPtr aCurCyl = aFace->getCylinder();
109     if (!aCurCyl) {
110       isCylinder = false;
111       break;
112     }
113
114     if (isFirstFace) {
115       aLocation = aCurCyl->location();
116       anAxis = aCurCyl->axis();
117       aRadius = aCurCyl->radius();
118       aHeight = aCurCyl->height();
119       isFirstFace = false;
120     }
121     else {
122       // compare radii
123       if (Abs(aRadius - aCurCyl->radius()) >= Precision::Confusion() ||
124         // check directions are collinear
125         !anAxis->isParallel(aCurCyl->axis()) ||
126         // check current center is on the main axis
127         anAxis->xyz()->cross(aLocation->xyz()->decreased(aCurCyl->location()->xyz())
128         )->squareModulus() >= Precision::SquareConfusion()) {
129         isCylinder = false;
130         break;
131       }
132
133       double aMinHeight = 0.0;
134       double aMaxHeight = aHeight;
135
136       std::shared_ptr<GeomAPI_XYZ> aCurCylLoc = aCurCyl->location()->xyz();
137       std::shared_ptr<GeomAPI_XYZ> aCurCylLocHeight =
138         aCurCylLoc->added(aCurCyl->axis()->xyz()->multiplied(aCurCyl->height()));
139
140       std::shared_ptr<GeomAPI_XYZ> anAxisXYZ = anAxis->xyz();
141
142       double aDist = anAxisXYZ->dot(aCurCylLoc->decreased(aLocation->xyz()));
143       if (aDist < aMinHeight)
144         aMinHeight = aDist;
145       else if (aDist > aMaxHeight)
146         aMaxHeight = aDist;
147
148       aDist = anAxisXYZ->dot(aCurCylLocHeight->decreased(aLocation->xyz()));
149       if (aDist < aMinHeight)
150         aMinHeight = aDist;
151       else if (aDist > aMaxHeight)
152         aMaxHeight = aDist;
153
154       if (aMinHeight < 0.0) {
155         // move location of full cylinder
156         aLocation->setX(aLocation->x() + aMinHeight * anAxis->x());
157         aLocation->setY(aLocation->y() + aMinHeight * anAxis->y());
158         aLocation->setZ(aLocation->z() + aMinHeight * anAxis->z());
159       }
160
161       aHeight = aMaxHeight - aMinHeight;
162     }
163   }
164
165   GeomCylinderPtr aCylinder;
166   if (isCylinder)
167     aCylinder = GeomCylinderPtr(new GeomAPI_Cylinder(aLocation, anAxis, aRadius, aHeight));
168   return aCylinder;
169 }
170
171 //=================================================================================================
172 std::shared_ptr<GeomAPI_Cone> GeomAPI_Shell::getCone() const
173 {
174   bool isCone = true;
175   bool isFirstFace = true;
176
177   GeomPointPtr anApex;
178   GeomDirPtr anAxis;
179   double aSemiAngle, aTanSemiAngle;
180   double aHeight1, aHeight2;
181
182   for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
183     GeomFacePtr aFace(new GeomAPI_Face);
184     aFace->setImpl(new TopoDS_Shape(anExp.Current()));
185
186     GeomConePtr aCurCone = aFace->getCone();
187     if (!aCurCone) {
188       isCone = false;
189       break;
190     }
191
192     if (isFirstFace) {
193       anApex = aCurCone->apex();
194       anAxis = aCurCone->axis();
195       aSemiAngle = aCurCone->semiAngle();
196       aTanSemiAngle = Tan(aSemiAngle);
197       aHeight1 = aCurCone->radius1() / aTanSemiAngle;
198       aHeight2 = aCurCone->radius2() / aTanSemiAngle;
199       isFirstFace = false;
200     }
201     else {
202       // check equal locations
203       if (anApex->distance(aCurCone->apex()) >= Precision::Confusion() ||
204       // check equal angles
205           Abs(aSemiAngle - aCurCone->semiAngle()) >= Precision::Confusion() ||
206       // check directions are collinear
207           !anAxis->isParallel(aCurCone->axis())) {
208         isCone = false;
209         break;
210       }
211
212       double aSign = anAxis->dot(aCurCone->axis());
213       double aCurSemiAngle = aCurCone->semiAngle();
214       double aTanCurSemiAngle = Tan(aSemiAngle);
215
216       double aH = aCurCone->radius1() / aTanCurSemiAngle * aSign;
217       if (aH < aHeight1)
218         aHeight1 = aH;
219       else if (aH > aHeight2)
220         aHeight2 = aH;
221
222       aH = aCurCone->radius2() / aTanCurSemiAngle * aSign;
223       if (aH < aHeight1)
224         aHeight1 = aH;
225       else if (aH > aHeight2)
226         aHeight2 = aH;
227     }
228   }
229
230   GeomConePtr aCone;
231   if (isCone) {
232     GeomPointPtr aLocation(new GeomAPI_Pnt(
233       anApex->xyz()->added(anAxis->xyz()->multiplied(aHeight1))));
234     double aRadius1 = aHeight1 * aTanSemiAngle;
235     double aRadius2 = aHeight2 * aTanSemiAngle;
236
237     aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aRadius1, aRadius2));
238   }
239   return aCone;
240 }
241
242 //=================================================================================================
243 std::shared_ptr<GeomAPI_Torus> GeomAPI_Shell::getTorus() const
244 {
245   bool isTorus = true;
246   bool isFirstFace = true;
247   GeomTorusPtr aTorus;
248
249   for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
250     GeomFacePtr aFace(new GeomAPI_Face);
251     aFace->setImpl(new TopoDS_Shape(anExp.Current()));
252
253     GeomTorusPtr aCurTorus = aFace->getTorus();
254     if (!aCurTorus) {
255       isTorus = false;
256       break;
257     }
258
259     if (isFirstFace) {
260       aTorus = aCurTorus;
261       isFirstFace = false;
262     }
263     else {
264       // compare radii
265       if (Abs(aTorus->majorRadius() - aCurTorus->majorRadius()) >= Precision::Confusion() ||
266           Abs(aTorus->minorRadius() - aCurTorus->minorRadius()) >= Precision::Confusion() ||
267       // check equal centers
268           aTorus->center()->distance(aCurTorus->center()) >= Precision::SquareConfusion() ||
269       // check directions are collinear
270           !aTorus->direction()->isParallel(aCurTorus->direction())) {
271         isTorus = false;
272         break;
273       }
274     }
275   }
276
277   return isTorus ? aTorus : GeomTorusPtr();
278 }
279
280 //=================================================================================================
281 std::shared_ptr<GeomAPI_Box> GeomAPI_Shell::getParallelepiped() const
282 {
283   struct Plane
284   {
285     std::shared_ptr<GeomAPI_Ax3> myAxes;
286     double myWidth;
287     double myDepth;
288     double myHeight;
289   } aPlanes[6];
290   std::map<int, int> aParallelPlanes;
291
292   int aNbPlanes = 0;
293   for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_WIRE);
294        anExp.More() && aNbPlanes < 6; anExp.Next()) {
295     GeomWirePtr aWire(new GeomAPI_Wire);
296     aWire->setImpl(new TopoDS_Shape(anExp.Current()));
297
298     std::list<GeomPointPtr> aCorners;
299     if (aWire->isRectangle(aCorners)) {
300       // convert rectangle to plane with dimensions
301
302       // find corner with the smallest coordinates
303       std::list<GeomPointPtr>::const_iterator aPrev = --aCorners.end();
304       std::list<GeomPointPtr>::const_iterator aCur = aPrev--;
305       std::list<GeomPointPtr>::const_iterator aNext = aCorners.begin();
306       GeomPointPtr anOrigin = *aCur;
307       GeomPointPtr aFront = *aNext;
308       GeomPointPtr aBack = *aPrev;
309       aPrev = aCur;
310       aCur = aNext++;
311       while (aNext != aCorners.end()) {
312         if ((*aCur)->isLess(anOrigin)) {
313           anOrigin = *aCur;
314           aFront = *aNext;
315           aBack = *aPrev;
316         }
317         aPrev = aCur;
318         aCur = aNext++;
319       }
320
321       aPlanes[aNbPlanes].myWidth = aBack->distance(anOrigin);
322       aPlanes[aNbPlanes].myDepth = aFront->distance(anOrigin);
323       aPlanes[aNbPlanes].myHeight = Precision::Infinite();
324
325       GeomDirPtr aDX(new GeomAPI_Dir(aBack->x() - anOrigin->x(),
326                                      aBack->y() - anOrigin->y(),
327                                      aBack->z() - anOrigin->z()));
328       GeomDirPtr aDY(new GeomAPI_Dir(aFront->x() - anOrigin->x(),
329                                      aFront->y() - anOrigin->y(),
330                                      aFront->z() - anOrigin->z()));
331       GeomDirPtr aDZ(new GeomAPI_Dir(aDX->cross(aDY)));
332       aPlanes[aNbPlanes].myAxes =
333           std::shared_ptr<GeomAPI_Ax3>(new GeomAPI_Ax3(anOrigin, aDX, aDZ));
334
335       // find parallel plane
336       for (int i = 0; i < aNbPlanes; ++i) {
337         double aDot = aPlanes[i].myAxes->normal()->dot(aDZ);
338         if (Abs(aDot + 1.0) < Precision::Angular()) {
339           if (aParallelPlanes.find(i) == aParallelPlanes.end())
340             aParallelPlanes[i] = aNbPlanes;
341           else
342             break; // parallel planes already exist
343         }
344       }
345
346       ++aNbPlanes;
347
348     } else
349       break;
350   }
351
352   if (aNbPlanes != 6 || aParallelPlanes.size() != 3) // not a parallelepiped
353     return GeomBoxPtr();
354
355   // calculate heights for planes computed by rectangles
356   for (std::map<int, int>::iterator it = aParallelPlanes.begin();
357        it != aParallelPlanes.end(); ++it) {
358     GeomDirPtr aNormal = aPlanes[it->first].myAxes->normal();
359     GeomPointPtr anOrigin = aPlanes[it->first].myAxes->origin();
360     GeomPointPtr aNeighbor = aPlanes[it->second].myAxes->origin();
361
362     aPlanes[it->first].myHeight =
363     aPlanes[it->second].myHeight =
364         aNormal->xyz()->dot( aNeighbor->xyz()->decreased(anOrigin->xyz()) );
365   }
366
367   // check if the box is oriented in the main axes
368   int anIndex = 0;
369   for (int i = 0; i < 6; ++i) {
370     if (Abs(aPlanes[i].myAxes->dirX()->x() - 1.) < Precision::Angular() &&
371         Abs(aPlanes[i].myAxes->normal()->z() - 1.) < Precision::Angular()) {
372       anIndex = i;
373       break;
374     }
375   }
376
377   // construct a box
378   GeomBoxPtr aBox(new GeomAPI_Box(aPlanes[anIndex].myAxes,
379                                   aPlanes[anIndex].myWidth,
380                                   aPlanes[anIndex].myDepth,
381                                   aPlanes[anIndex].myHeight));
382   return aBox;
383 }
384
385 //=================================================================================================
386 GeomPointPtr GeomAPI_Shell::middlePoint() const
387 {
388   GeomPointPtr anInnerPoint;
389
390   const TopoDS_Shell& aShell = impl<TopoDS_Shell>();
391   if (aShell.IsNull())
392     return anInnerPoint;
393
394   GProp_GProps aProps;
395   BRepGProp::SurfaceProperties(aShell, aProps, 1.e-4);
396
397   gp_Pnt aPnt = aProps.CentreOfMass();
398   anInnerPoint = GeomPointPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
399   return anInnerPoint;
400 }