1 // Copyright (C) 2018-2019 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_Shell.h"
22 #include "GeomAPI_Ax3.h"
23 #include "GeomAPI_Box.h"
24 #include "GeomAPI_Cone.h"
25 #include "GeomAPI_Cylinder.h"
26 #include "GeomAPI_Face.h"
27 #include "GeomAPI_Pnt.h"
28 #include "GeomAPI_Sphere.h"
29 #include "GeomAPI_Torus.h"
30 #include "GeomAPI_Wire.h"
31 #include "GeomAPI_XYZ.h"
33 #include <BRep_Builder.hxx>
34 #include <BRepGProp.hxx>
35 #include <GProp_GProps.hxx>
36 #include <Precision.hxx>
37 #include <TopExp_Explorer.hxx>
42 //=================================================================================================
43 GeomAPI_Shell::GeomAPI_Shell()
45 TopoDS_Shell* aShell = new TopoDS_Shell();
47 BRep_Builder aBuilder;
48 aBuilder.MakeShell(*aShell);
50 this->setImpl(aShell);
53 //=================================================================================================
54 GeomAPI_Shell::GeomAPI_Shell(const std::shared_ptr<GeomAPI_Shape>& theShape)
56 if (!theShape->isNull() && theShape->isShell()) {
57 setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
61 //=================================================================================================
62 std::shared_ptr<GeomAPI_Sphere> GeomAPI_Shell::getSphere() const
65 bool isFirstFace = true;
66 GeomSpherePtr aSphere;
68 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
69 GeomFacePtr aFace(new GeomAPI_Face);
70 aFace->setImpl(new TopoDS_Shape(anExp.Current()));
72 GeomSpherePtr aCurSphere = aFace->getSphere();
82 else if (aSphere->center()->distance(aCurSphere->center()) >= Precision::Confusion() ||
83 Abs(aSphere->radius() - aCurSphere->radius()) >= Precision::Confusion()) {
89 return isSphere ? aSphere : GeomSpherePtr();
92 //=================================================================================================
93 std::shared_ptr<GeomAPI_Cylinder> GeomAPI_Shell::getCylinder() const
95 bool isCylinder = true;
96 bool isFirstFace = true;
98 GeomPointPtr aLocation;
103 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
104 GeomFacePtr aFace(new GeomAPI_Face);
105 aFace->setImpl(new TopoDS_Shape(anExp.Current()));
107 GeomCylinderPtr aCurCyl = aFace->getCylinder();
114 aLocation = aCurCyl->location();
115 anAxis = aCurCyl->axis();
116 aRadius = aCurCyl->radius();
117 aHeight = aCurCyl->height();
122 if (Abs(aRadius - aCurCyl->radius()) >= Precision::Confusion() ||
123 // check directions are collinear
124 !anAxis->isParallel(aCurCyl->axis()) ||
125 // check current center is on the main axis
126 anAxis->xyz()->cross(aLocation->xyz()->decreased(aCurCyl->location()->xyz())
127 )->squareModulus() >= Precision::SquareConfusion()) {
132 double aMinHeight = 0.0;
133 double aMaxHeight = aHeight;
135 std::shared_ptr<GeomAPI_XYZ> aCurCylLoc = aCurCyl->location()->xyz();
136 std::shared_ptr<GeomAPI_XYZ> aCurCylLocHeight =
137 aCurCylLoc->added(aCurCyl->axis()->xyz()->multiplied(aCurCyl->height()));
139 std::shared_ptr<GeomAPI_XYZ> anAxisXYZ = anAxis->xyz();
141 double aDist = anAxisXYZ->dot(aCurCylLoc->decreased(aLocation->xyz()));
142 if (aDist < aMinHeight)
144 else if (aDist > aMaxHeight)
147 aDist = anAxisXYZ->dot(aCurCylLocHeight->decreased(aLocation->xyz()));
148 if (aDist < aMinHeight)
150 else if (aDist > aMaxHeight)
153 if (aMinHeight < 0.0) {
154 // move location of full cylinder
155 aLocation->setX(aLocation->x() + aMinHeight * anAxis->x());
156 aLocation->setY(aLocation->y() + aMinHeight * anAxis->y());
157 aLocation->setZ(aLocation->z() + aMinHeight * anAxis->z());
160 aHeight = aMaxHeight - aMinHeight;
164 GeomCylinderPtr aCylinder;
166 aCylinder = GeomCylinderPtr(new GeomAPI_Cylinder(aLocation, anAxis, aRadius, aHeight));
170 //=================================================================================================
171 std::shared_ptr<GeomAPI_Cone> GeomAPI_Shell::getCone() const
174 bool isFirstFace = true;
178 double aSemiAngle, aTanSemiAngle;
179 double aHeight1, aHeight2;
181 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
182 GeomFacePtr aFace(new GeomAPI_Face);
183 aFace->setImpl(new TopoDS_Shape(anExp.Current()));
185 GeomConePtr aCurCone = aFace->getCone();
192 anApex = aCurCone->apex();
193 anAxis = aCurCone->axis();
194 aSemiAngle = aCurCone->semiAngle();
195 aTanSemiAngle = Tan(aSemiAngle);
196 aHeight1 = aCurCone->radius1() / aTanSemiAngle;
197 aHeight2 = aCurCone->radius2() / aTanSemiAngle;
201 // check equal locations
202 if (anApex->distance(aCurCone->apex()) >= Precision::Confusion() ||
203 // check equal angles
204 Abs(aSemiAngle - aCurCone->semiAngle()) >= Precision::Confusion() ||
205 // check directions are collinear
206 !anAxis->isParallel(aCurCone->axis())) {
211 double aSign = anAxis->dot(aCurCone->axis());
212 double aCurSemiAngle = aCurCone->semiAngle();
213 double aTanCurSemiAngle = Tan(aSemiAngle);
215 double aH = aCurCone->radius1() / aTanCurSemiAngle * aSign;
218 else if (aH > aHeight2)
221 aH = aCurCone->radius2() / aTanCurSemiAngle * aSign;
224 else if (aH > aHeight2)
231 GeomPointPtr aLocation(new GeomAPI_Pnt(
232 anApex->xyz()->added(anAxis->xyz()->multiplied(aHeight1))));
233 double aRadius1 = aHeight1 * aTanSemiAngle;
234 double aRadius2 = aHeight2 * aTanSemiAngle;
236 aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aRadius1, aRadius2));
241 //=================================================================================================
242 std::shared_ptr<GeomAPI_Torus> GeomAPI_Shell::getTorus() const
245 bool isFirstFace = true;
248 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
249 GeomFacePtr aFace(new GeomAPI_Face);
250 aFace->setImpl(new TopoDS_Shape(anExp.Current()));
252 GeomTorusPtr aCurTorus = aFace->getTorus();
264 if (Abs(aTorus->majorRadius() - aCurTorus->majorRadius()) >= Precision::Confusion() ||
265 Abs(aTorus->minorRadius() - aCurTorus->minorRadius()) >= Precision::Confusion() ||
266 // check equal centers
267 aTorus->center()->distance(aCurTorus->center()) >= Precision::SquareConfusion() ||
268 // check directions are collinear
269 !aTorus->direction()->isParallel(aCurTorus->direction())) {
276 return isTorus ? aTorus : GeomTorusPtr();
279 //=================================================================================================
280 std::shared_ptr<GeomAPI_Box> GeomAPI_Shell::getParallelepiped() const
284 std::shared_ptr<GeomAPI_Ax3> myAxes;
289 std::map<int, int> aParallelPlanes;
292 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_WIRE);
293 anExp.More() && aNbPlanes < 6; anExp.Next()) {
294 GeomWirePtr aWire(new GeomAPI_Wire);
295 aWire->setImpl(new TopoDS_Shape(anExp.Current()));
297 std::list<GeomPointPtr> aCorners;
298 if (aWire->isRectangle(aCorners)) {
299 // convert rectangle to plane with dimensions
301 // find corner with the smallest coordinates
302 std::list<GeomPointPtr>::const_iterator aPrev = --aCorners.end();
303 std::list<GeomPointPtr>::const_iterator aCur = aPrev--;
304 std::list<GeomPointPtr>::const_iterator aNext = aCorners.begin();
305 GeomPointPtr anOrigin = *aCur;
306 GeomPointPtr aFront = *aNext;
307 GeomPointPtr aBack = *aPrev;
310 while (aNext != aCorners.end()) {
311 if ((*aCur)->isLess(anOrigin)) {
320 aPlanes[aNbPlanes].myWidth = aBack->distance(anOrigin);
321 aPlanes[aNbPlanes].myDepth = aFront->distance(anOrigin);
322 aPlanes[aNbPlanes].myHeight = Precision::Infinite();
324 GeomDirPtr aDX(new GeomAPI_Dir(aBack->x() - anOrigin->x(),
325 aBack->y() - anOrigin->y(),
326 aBack->z() - anOrigin->z()));
327 GeomDirPtr aDY(new GeomAPI_Dir(aFront->x() - anOrigin->x(),
328 aFront->y() - anOrigin->y(),
329 aFront->z() - anOrigin->z()));
330 GeomDirPtr aDZ(new GeomAPI_Dir(aDX->cross(aDY)));
331 aPlanes[aNbPlanes].myAxes =
332 std::shared_ptr<GeomAPI_Ax3>(new GeomAPI_Ax3(anOrigin, aDX, aDZ));
334 // find parallel plane
335 for (int i = 0; i < aNbPlanes; ++i) {
336 double aDot = aPlanes[i].myAxes->normal()->dot(aDZ);
337 if (Abs(aDot + 1.0) < Precision::Angular()) {
338 if (aParallelPlanes.find(i) == aParallelPlanes.end())
339 aParallelPlanes[i] = aNbPlanes;
341 break; // parallel planes already exist
351 if (aNbPlanes != 6 || aParallelPlanes.size() != 3) // not a parallelepiped
354 // calculate heights for planes computed by rectangles
355 for (std::map<int, int>::iterator it = aParallelPlanes.begin();
356 it != aParallelPlanes.end(); ++it) {
357 GeomDirPtr aNormal = aPlanes[it->first].myAxes->normal();
358 GeomPointPtr anOrigin = aPlanes[it->first].myAxes->origin();
359 GeomPointPtr aNeighbor = aPlanes[it->second].myAxes->origin();
361 aPlanes[it->first].myHeight =
362 aPlanes[it->second].myHeight =
363 aNormal->xyz()->dot( aNeighbor->xyz()->decreased(anOrigin->xyz()) );
366 // check if the box is oriented in the main axes
368 for (int i = 0; i < 6; ++i) {
369 if (Abs(aPlanes[i].myAxes->dirX()->x() - 1.) < Precision::Angular() &&
370 Abs(aPlanes[i].myAxes->normal()->z() - 1.) < Precision::Angular()) {
377 GeomBoxPtr aBox(new GeomAPI_Box(aPlanes[anIndex].myAxes,
378 aPlanes[anIndex].myWidth,
379 aPlanes[anIndex].myDepth,
380 aPlanes[anIndex].myHeight));
384 //=================================================================================================
385 GeomPointPtr GeomAPI_Shell::middlePoint() const
387 GeomPointPtr anInnerPoint;
389 const TopoDS_Shell& aShell = impl<TopoDS_Shell>();
394 BRepGProp::SurfaceProperties(aShell, aProps, 1.e-4);
396 gp_Pnt aPnt = aProps.CentreOfMass();
397 anInnerPoint = GeomPointPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));