1 // Copyright (C) 2018-2020 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "GeomAPI_Solid.h"
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"
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>
41 //==================================================================================================
42 GeomAPI_Solid::GeomAPI_Solid() : GeomAPI_Shape()
46 //==================================================================================================
47 GeomAPI_Solid::GeomAPI_Solid(const std::shared_ptr<GeomAPI_Shape>& theShape)
49 if (!theShape->isNull() && theShape->isSolid()) {
50 setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
54 //==================================================================================================
55 std::shared_ptr<GeomAPI_Sphere> GeomAPI_Solid::getSphere() const
57 GeomSpherePtr aSphere;
58 ListOfShape aShells = subShapes(SHELL);
59 if (aShells.size() == 1)
60 aSphere = aShells.front()->shell()->getSphere();
64 //==================================================================================================
65 std::shared_ptr<GeomAPI_Cylinder> GeomAPI_Solid::getCylinder() const
67 bool isCylinder = false;
69 GeomPointPtr aLocation;
74 GeomPlanePtr aCaps[2];
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()));
80 GeomCylinderPtr aCurCyl = aFace->getCylinder();
82 if (isCylinder) { // at least one cylindrical face is found
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()) {
94 else { // first cylinder is found
95 aLocation = aCurCyl->location();
97 // the plane is found => compare directions
98 if (!anAxis->isParallel(aCurCyl->axis()))
102 anAxis = aCurCyl->axis();
103 aRadius = aCurCyl->radius();
104 aHeight = aCurCyl->height();
109 // check the face is planar
110 bool isPlaneApplicable = false;
111 GeomPlanePtr aCurPln = aFace->getPlane();
113 // verify the plane is already exists
114 int aLastPlanIndex = 0;
115 while (aLastPlanIndex < 2) {
116 if (!aCaps[aLastPlanIndex]) {
118 aCaps[aLastPlanIndex] = aCurPln;
121 if (aCaps[aLastPlanIndex]->isCoincident(aCurPln))
126 isPlaneApplicable = aLastPlanIndex < 2;
129 if (isPlaneApplicable) {
130 if (!anAxis) // no cylinder is found, store the normal as further cylinder's axis
131 anAxis = aCurPln->direction();
140 isCylinder = isCylinder && aCaps[0] && aCaps[1] &&
141 aCaps[0]->direction()->isParallel(anAxis) &&
142 aCaps[1]->direction()->isParallel(anAxis);
144 GeomCylinderPtr aCylinder;
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;
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());
162 aHeight = aParam1 - aParam0;
164 aCylinder = GeomCylinderPtr(new GeomAPI_Cylinder(aLocation, anAxis, aRadius, aHeight));
169 //==================================================================================================
170 std::shared_ptr<GeomAPI_Cone> GeomAPI_Solid::getCone() const
176 double aSemiAngle = 0.0;
178 GeomPlanePtr aCaps[2];
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()));
184 GeomConePtr aCurCone = aFace->getCone();
186 if (isCone) { // at least one conical face is found
187 // check equal apexes
188 if (anApex->distance(aCurCone->apex()) >= Precision::Confusion() ||
190 Abs(aSemiAngle - aCurCone->semiAngle() >= Precision::Confusion()) ||
191 // check axes are collinear
192 !anAxis->isParallel(aCurCone->axis())) {
197 else { // first cone is found
198 anApex = aCurCone->apex();
200 // the plane is found => compare directions
201 if (!anAxis->isParallel(aCurCone->axis()))
205 anAxis = aCurCone->axis();
206 aSemiAngle = aCurCone->semiAngle();
211 // check the face is planar
212 bool isPlaneApplicable = false;
213 GeomPlanePtr aCurPln = aFace->getPlane();
215 // verify the plane is already exists
216 int aLastPlanIndex = 0;
217 while (aLastPlanIndex < 2) {
218 if (!aCaps[aLastPlanIndex]) {
220 aCaps[aLastPlanIndex] = aCurPln;
223 if (aCaps[aLastPlanIndex]->isCoincident(aCurPln))
228 isPlaneApplicable = aLastPlanIndex < 2;
231 if (isPlaneApplicable) {
232 if (!anAxis) // no cone is found, store the normal as further cone's axis
233 anAxis = aCurPln->direction();
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);
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));
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
260 if (aParam0 > aParam1 + Precision::Confusion()) {
261 double tmp = aParam0;
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()));
272 // calculate radii of caps
273 aParam0 *= Tan(aSemiAngle);
274 aParam1 *= Tan(aSemiAngle);
276 aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aParam0, aParam1));
281 //==================================================================================================
282 std::shared_ptr<GeomAPI_Torus> GeomAPI_Solid::getTorus() const
285 ListOfShape aShells = subShapes(SHELL);
286 if (aShells.size() == 1)
287 aTorus = aShells.front()->shell()->getTorus();
291 //==================================================================================================
292 std::shared_ptr<GeomAPI_Box> GeomAPI_Solid::getParallelepiped() const
295 ListOfShape aShells = subShapes(SHELL);
296 if (aShells.size() == 1)
297 aBox = aShells.front()->shell()->getParallelepiped();
301 //==================================================================================================
302 GeomPointPtr GeomAPI_Solid::middlePoint() const
304 GeomPointPtr anInnerPoint;
306 const TopoDS_Solid& aSolid = impl<TopoDS_Solid>();
311 BRepGProp::VolumeProperties(aSolid, aProps, 1.e-4);
313 gp_Pnt aPnt = aProps.CentreOfMass();
314 anInnerPoint = GeomPointPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));