Salome HOME
Copyright update 2022
[modules/shaper.git] / src / GeomAPI / GeomAPI_Solid.cpp
1 // Copyright (C) 2018-2022  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_Solid.h"
21
22 #include "GeomAPI_Box.h"
23 #include "GeomAPI_Cone.h"
24 #include "GeomAPI_Cylinder.h"
25 #include "GeomAPI_Dir.h"
26 #include "GeomAPI_Face.h"
27 #include "GeomAPI_Pln.h"
28 #include "GeomAPI_Pnt.h"
29 #include "GeomAPI_Shell.h"
30 #include "GeomAPI_Sphere.h"
31 #include "GeomAPI_Torus.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_Wire.hxx>
40
41 //==================================================================================================
42 GeomAPI_Solid::GeomAPI_Solid() : GeomAPI_Shape()
43 {
44 }
45
46 //==================================================================================================
47 GeomAPI_Solid::GeomAPI_Solid(const std::shared_ptr<GeomAPI_Shape>& theShape)
48 {
49   if (!theShape->isNull() && theShape->isSolid()) {
50     setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
51   }
52 }
53
54 //==================================================================================================
55 std::shared_ptr<GeomAPI_Sphere> GeomAPI_Solid::getSphere() const
56 {
57   GeomSpherePtr aSphere;
58   ListOfShape aShells = subShapes(SHELL);
59   if (aShells.size() == 1)
60     aSphere = aShells.front()->shell()->getSphere();
61   return aSphere;
62 }
63
64 //==================================================================================================
65 std::shared_ptr<GeomAPI_Cylinder> GeomAPI_Solid::getCylinder() const
66 {
67   bool isCylinder = false;
68
69   GeomPointPtr aLocation;
70   GeomDirPtr anAxis;
71   double aRadius = 0.0;
72   double aHeight = 0.0;
73
74   GeomPlanePtr aCaps[2];
75
76   for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
77     GeomFacePtr aFace(new GeomAPI_Face);
78     aFace->setImpl(new TopoDS_Shape(anExp.Current()));
79
80     GeomCylinderPtr aCurCyl = aFace->getCylinder();
81     if (aCurCyl) {
82       if (isCylinder) { // at least one cylindrical face is found
83         // compare radii
84         if (Abs(aRadius - aCurCyl->radius()) >= Precision::Confusion() ||
85           // check directions are collinear
86           !anAxis->isParallel(aCurCyl->axis()) ||
87           // check current center is on the main axis
88           anAxis->xyz()->cross(aLocation->xyz()->decreased(aCurCyl->location()->xyz())
89           )->squareModulus() >= Precision::SquareConfusion()) {
90           isCylinder = false;
91           break;
92         }
93       }
94       else { // first cylinder is found
95         aLocation = aCurCyl->location();
96         if (anAxis) {
97           // the plane is found => compare directions
98           if (!anAxis->isParallel(aCurCyl->axis()))
99             break;
100         }
101         else
102           anAxis = aCurCyl->axis();
103         aRadius = aCurCyl->radius();
104         aHeight = aCurCyl->height();
105         isCylinder = true;
106       }
107     }
108     else {
109       // check the face is planar
110       bool isPlaneApplicable = false;
111       GeomPlanePtr aCurPln = aFace->getPlane();
112       if (aCurPln) {
113         // verify the plane is already exists
114         int aLastPlanIndex = 0;
115         while (aLastPlanIndex < 2) {
116           if (!aCaps[aLastPlanIndex]) {
117             // add new plane
118             aCaps[aLastPlanIndex] = aCurPln;
119             break;
120           }
121           if (aCaps[aLastPlanIndex]->isCoincident(aCurPln))
122             break;
123           ++aLastPlanIndex;
124         }
125
126         isPlaneApplicable = aLastPlanIndex < 2;
127       }
128
129       if (isPlaneApplicable) {
130         if (!anAxis) // no cylinder is found, store the normal as further cylinder's axis
131           anAxis = aCurPln->direction();
132       }
133       else {
134         isCylinder = false;
135         break;
136       }
137     }
138   }
139
140   isCylinder = isCylinder && aCaps[0] && aCaps[1] &&
141                aCaps[0]->direction()->isParallel(anAxis) &&
142                aCaps[1]->direction()->isParallel(anAxis);
143
144   GeomCylinderPtr aCylinder;
145   if (isCylinder) {
146     // intersect planes with cylinder's axis
147     std::shared_ptr<GeomAPI_XYZ> anAxisXYZ = anAxis->xyz();
148     std::shared_ptr<GeomAPI_XYZ> aLocationXYZ = aLocation->xyz();
149     double aParam0 = anAxisXYZ->dot( aCaps[0]->location()->xyz()->decreased(aLocationXYZ) );
150     double aParam1 = anAxisXYZ->dot( aCaps[1]->location()->xyz()->decreased(aLocationXYZ) );
151     if (aParam0 > aParam1 + Precision::Confusion()) {
152       double tmp = aParam0;
153       aParam0 = aParam1;
154       aParam1 = tmp;
155     }
156
157     // update location of cylinder to be coincident with one of planes
158     aLocation->setX(aLocation->x() + aParam0 * anAxis->x());
159     aLocation->setY(aLocation->y() + aParam0 * anAxis->y());
160     aLocation->setZ(aLocation->z() + aParam0 * anAxis->z());
161
162     aHeight = aParam1 - aParam0;
163
164     aCylinder = GeomCylinderPtr(new GeomAPI_Cylinder(aLocation, anAxis, aRadius, aHeight));
165   }
166   return aCylinder;
167 }
168
169 //==================================================================================================
170 std::shared_ptr<GeomAPI_Cone> GeomAPI_Solid::getCone() const
171 {
172   bool isCone = false;
173
174   GeomPointPtr anApex;
175   GeomDirPtr anAxis;
176   double aSemiAngle = 0.0;
177
178   GeomPlanePtr aCaps[2];
179
180   for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
181     GeomFacePtr aFace(new GeomAPI_Face);
182     aFace->setImpl(new TopoDS_Shape(anExp.Current()));
183
184     GeomConePtr aCurCone = aFace->getCone();
185     if (aCurCone) {
186       if (isCone) { // at least one conical face is found
187         // check equal apexes
188         if (anApex->distance(aCurCone->apex()) >= Precision::Confusion() ||
189         // check semi-angle
190             Abs(aSemiAngle - aCurCone->semiAngle() >= Precision::Confusion()) ||
191         // check axes are collinear
192             !anAxis->isParallel(aCurCone->axis())) {
193           isCone = false;
194           break;
195         }
196       }
197       else { // first cone is found
198         anApex = aCurCone->apex();
199         if (anAxis) {
200           // the plane is found => compare directions
201           if (!anAxis->isParallel(aCurCone->axis()))
202             break;
203         }
204         else
205           anAxis = aCurCone->axis();
206         aSemiAngle = aCurCone->semiAngle();
207         isCone = true;
208       }
209     }
210     else {
211       // check the face is planar
212       bool isPlaneApplicable = false;
213       GeomPlanePtr aCurPln = aFace->getPlane();
214       if (aCurPln) {
215         // verify the plane is already exists
216         int aLastPlanIndex = 0;
217         while (aLastPlanIndex < 2) {
218           if (!aCaps[aLastPlanIndex]) {
219             // add new plane
220             aCaps[aLastPlanIndex] = aCurPln;
221             break;
222           }
223           if (aCaps[aLastPlanIndex]->isCoincident(aCurPln))
224             break;
225           ++aLastPlanIndex;
226         }
227
228         isPlaneApplicable = aLastPlanIndex < 2;
229       }
230
231       if (isPlaneApplicable) {
232         if (!anAxis) // no cone is found, store the normal as further cone's axis
233           anAxis = aCurPln->direction();
234       }
235       else {
236         isCone = false;
237         break;
238       }
239     }
240   }
241
242   isCone = isCone && aCaps[0] && aCaps[0]->direction()->isParallel(anAxis);
243   if (isCone && aCaps[1]) // cone map have only one cap, if it is bounded by the apex
244     isCone = aCaps[1]->direction()->isParallel(anAxis);
245
246   GeomConePtr aCone;
247   if (isCone) {
248     // intersect planes with cone's axis
249     std::shared_ptr<GeomAPI_XYZ> anAxisXYZ = anAxis->xyz();
250     std::shared_ptr<GeomAPI_XYZ> anApexXYZ = anApex->xyz();
251     double aParam0 = anAxisXYZ->dot(aCaps[0]->location()->xyz()->decreased(anApexXYZ));
252     double aParam1 =
253         aCaps[1] ? anAxisXYZ->dot(aCaps[1]->location()->xyz()->decreased(anApexXYZ)) : 0.0;
254     if (aParam0 <= 0.0 && aParam1 <= 0.0) {
255       // reverse axis to make smaller cap be the first
256       anAxis->reverse();
257       aParam0 = -aParam0;
258       aParam1 = -aParam1;
259     }
260     if (aParam0 > aParam1 + Precision::Confusion()) {
261       double tmp = aParam0;
262       aParam0 = aParam1;
263       aParam1 = tmp;
264     }
265
266     // calculate location of cone to be coincident with one of planes
267     GeomPointPtr aLocation(new GeomAPI_Pnt(
268         anApex->x() + aParam0 * anAxis->x(),
269         anApex->y() + aParam0 * anAxis->y(),
270         anApex->z() + aParam0 * anAxis->z()));
271
272     // calculate radii of caps
273     aParam0 *= Tan(aSemiAngle);
274     aParam1 *= Tan(aSemiAngle);
275
276     aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aParam0, aParam1));
277   }
278   return aCone;
279 }
280
281 //==================================================================================================
282 std::shared_ptr<GeomAPI_Torus> GeomAPI_Solid::getTorus() const
283 {
284   GeomTorusPtr aTorus;
285   ListOfShape aShells = subShapes(SHELL);
286   if (aShells.size() == 1)
287     aTorus = aShells.front()->shell()->getTorus();
288   return aTorus;
289 }
290
291 //==================================================================================================
292 std::shared_ptr<GeomAPI_Box> GeomAPI_Solid::getParallelepiped() const
293 {
294   GeomBoxPtr aBox;
295   ListOfShape aShells = subShapes(SHELL);
296   if (aShells.size() == 1)
297     aBox = aShells.front()->shell()->getParallelepiped();
298   return aBox;
299 }
300
301 //==================================================================================================
302 GeomPointPtr GeomAPI_Solid::middlePoint() const
303 {
304   GeomPointPtr anInnerPoint;
305
306   const TopoDS_Solid& aSolid = impl<TopoDS_Solid>();
307   if (aSolid.IsNull())
308     return anInnerPoint;
309
310   GProp_GProps aProps;
311   BRepGProp::VolumeProperties(aSolid, aProps, 1.e-4);
312
313   gp_Pnt aPnt = aProps.CentreOfMass();
314   anInnerPoint = GeomPointPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
315   return anInnerPoint;
316 }