1 // Copyright (C) 2018-20xx 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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include "GeomAPI_Shell.h"
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"
34 #include <BRep_Builder.hxx>
35 #include <BRepGProp.hxx>
36 #include <GProp_GProps.hxx>
37 #include <Precision.hxx>
38 #include <TopExp_Explorer.hxx>
43 //=================================================================================================
44 GeomAPI_Shell::GeomAPI_Shell()
46 TopoDS_Shell* aShell = new TopoDS_Shell();
48 BRep_Builder aBuilder;
49 aBuilder.MakeShell(*aShell);
51 this->setImpl(aShell);
54 //=================================================================================================
55 GeomAPI_Shell::GeomAPI_Shell(const std::shared_ptr<GeomAPI_Shape>& theShape)
57 if (!theShape->isNull() && theShape->isShell()) {
58 setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
62 //=================================================================================================
63 std::shared_ptr<GeomAPI_Sphere> GeomAPI_Shell::getSphere() const
66 bool isFirstFace = true;
67 GeomSpherePtr aSphere;
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()));
73 GeomSpherePtr aCurSphere = aFace->getSphere();
83 else if (aSphere->center()->distance(aCurSphere->center()) >= Precision::Confusion() ||
84 Abs(aSphere->radius() - aCurSphere->radius()) >= Precision::Confusion()) {
90 return isSphere ? aSphere : GeomSpherePtr();
93 //=================================================================================================
94 std::shared_ptr<GeomAPI_Cylinder> GeomAPI_Shell::getCylinder() const
96 bool isCylinder = true;
97 bool isFirstFace = true;
99 GeomPointPtr aLocation;
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()));
108 GeomCylinderPtr aCurCyl = aFace->getCylinder();
115 aLocation = aCurCyl->location();
116 anAxis = aCurCyl->axis();
117 aRadius = aCurCyl->radius();
118 aHeight = aCurCyl->height();
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()) {
133 double aMinHeight = 0.0;
134 double aMaxHeight = aHeight;
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()));
140 std::shared_ptr<GeomAPI_XYZ> anAxisXYZ = anAxis->xyz();
142 double aDist = anAxisXYZ->dot(aCurCylLoc->decreased(aLocation->xyz()));
143 if (aDist < aMinHeight)
145 else if (aDist > aMaxHeight)
148 aDist = anAxisXYZ->dot(aCurCylLocHeight->decreased(aLocation->xyz()));
149 if (aDist < aMinHeight)
151 else if (aDist > aMaxHeight)
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());
161 aHeight = aMaxHeight - aMinHeight;
165 GeomCylinderPtr aCylinder;
167 aCylinder = GeomCylinderPtr(new GeomAPI_Cylinder(aLocation, anAxis, aRadius, aHeight));
171 //=================================================================================================
172 std::shared_ptr<GeomAPI_Cone> GeomAPI_Shell::getCone() const
175 bool isFirstFace = true;
179 double aSemiAngle, aTanSemiAngle;
180 double aHeight1, aHeight2;
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()));
186 GeomConePtr aCurCone = aFace->getCone();
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;
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())) {
212 double aSign = anAxis->dot(aCurCone->axis());
213 double aCurSemiAngle = aCurCone->semiAngle();
214 double aTanCurSemiAngle = Tan(aSemiAngle);
216 double aH = aCurCone->radius1() / aTanCurSemiAngle * aSign;
219 else if (aH > aHeight2)
222 aH = aCurCone->radius2() / aTanCurSemiAngle * aSign;
225 else if (aH > aHeight2)
232 GeomPointPtr aLocation(new GeomAPI_Pnt(
233 anApex->xyz()->added(anAxis->xyz()->multiplied(aHeight1))));
234 double aRadius1 = aHeight1 * aTanSemiAngle;
235 double aRadius2 = aHeight2 * aTanSemiAngle;
237 aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aRadius1, aRadius2));
242 //=================================================================================================
243 std::shared_ptr<GeomAPI_Torus> GeomAPI_Shell::getTorus() const
246 bool isFirstFace = true;
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()));
253 GeomTorusPtr aCurTorus = aFace->getTorus();
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())) {
277 return isTorus ? aTorus : GeomTorusPtr();
280 //=================================================================================================
281 std::shared_ptr<GeomAPI_Box> GeomAPI_Shell::getParallelepiped() const
285 std::shared_ptr<GeomAPI_Ax3> myAxes;
290 std::map<int, int> aParallelPlanes;
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()));
298 std::list<GeomPointPtr> aCorners;
299 if (aWire->isRectangle(aCorners)) {
300 // convert rectangle to plane with dimensions
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;
311 while (aNext != aCorners.end()) {
312 if ((*aCur)->isLess(anOrigin)) {
321 aPlanes[aNbPlanes].myWidth = aBack->distance(anOrigin);
322 aPlanes[aNbPlanes].myDepth = aFront->distance(anOrigin);
323 aPlanes[aNbPlanes].myHeight = Precision::Infinite();
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));
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;
342 break; // parallel planes already exist
352 if (aNbPlanes != 6 || aParallelPlanes.size() != 3) // not a parallelepiped
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();
362 aPlanes[it->first].myHeight =
363 aPlanes[it->second].myHeight =
364 aNormal->xyz()->dot( aNeighbor->xyz()->decreased(anOrigin->xyz()) );
367 // check if the box is oriented in the main axes
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()) {
378 GeomBoxPtr aBox(new GeomAPI_Box(aPlanes[anIndex].myAxes,
379 aPlanes[anIndex].myWidth,
380 aPlanes[anIndex].myDepth,
381 aPlanes[anIndex].myHeight));
385 //=================================================================================================
386 GeomPointPtr GeomAPI_Shell::middlePoint() const
388 GeomPointPtr anInnerPoint;
390 const TopoDS_Shell& aShell = impl<TopoDS_Shell>();
395 BRepGProp::SurfaceProperties(aShell, aProps, 1.e-4);
397 gp_Pnt aPnt = aProps.CentreOfMass();
398 anInnerPoint = GeomPointPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));