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 <Precision.hxx>
36 #include <TopExp_Explorer.hxx>
41 //=================================================================================================
42 GeomAPI_Shell::GeomAPI_Shell()
44 TopoDS_Shell* aShell = new TopoDS_Shell();
46 BRep_Builder aBuilder;
47 aBuilder.MakeShell(*aShell);
49 this->setImpl(aShell);
52 //=================================================================================================
53 GeomAPI_Shell::GeomAPI_Shell(const std::shared_ptr<GeomAPI_Shape>& theShape)
55 if (!theShape->isNull() && theShape->isShell()) {
56 setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
60 //=================================================================================================
61 std::shared_ptr<GeomAPI_Sphere> GeomAPI_Shell::getSphere() const
64 bool isFirstFace = true;
65 GeomSpherePtr aSphere;
67 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
68 GeomFacePtr aFace(new GeomAPI_Face);
69 aFace->setImpl(new TopoDS_Shape(anExp.Current()));
71 GeomSpherePtr aCurSphere = aFace->getSphere();
81 else if (aSphere->center()->distance(aCurSphere->center()) >= Precision::Confusion() ||
82 Abs(aSphere->radius() - aCurSphere->radius()) >= Precision::Confusion()) {
88 return isSphere ? aSphere : GeomSpherePtr();
91 //=================================================================================================
92 std::shared_ptr<GeomAPI_Cylinder> GeomAPI_Shell::getCylinder() const
94 bool isCylinder = true;
95 bool isFirstFace = true;
97 GeomPointPtr aLocation;
102 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
103 GeomFacePtr aFace(new GeomAPI_Face);
104 aFace->setImpl(new TopoDS_Shape(anExp.Current()));
106 GeomCylinderPtr aCurCyl = aFace->getCylinder();
113 aLocation = aCurCyl->location();
114 anAxis = aCurCyl->axis();
115 aRadius = aCurCyl->radius();
116 aHeight = aCurCyl->height();
121 if (Abs(aRadius - aCurCyl->radius()) >= Precision::Confusion() ||
122 // check directions are collinear
123 !anAxis->isParallel(aCurCyl->axis()) ||
124 // check current center is on the main axis
125 anAxis->xyz()->cross(aLocation->xyz()->decreased(aCurCyl->location()->xyz())
126 )->squareModulus() >= Precision::SquareConfusion()) {
131 double aMinHeight = 0.0;
132 double aMaxHeight = aHeight;
134 std::shared_ptr<GeomAPI_XYZ> aCurCylLoc = aCurCyl->location()->xyz();
135 std::shared_ptr<GeomAPI_XYZ> aCurCylLocHeight =
136 aCurCylLoc->added(aCurCyl->axis()->xyz()->multiplied(aCurCyl->height()));
138 std::shared_ptr<GeomAPI_XYZ> anAxisXYZ = anAxis->xyz();
140 double aDist = anAxisXYZ->dot(aCurCylLoc->decreased(aLocation->xyz()));
141 if (aDist < aMinHeight)
143 else if (aDist > aMaxHeight)
146 aDist = anAxisXYZ->dot(aCurCylLocHeight->decreased(aLocation->xyz()));
147 if (aDist < aMinHeight)
149 else if (aDist > aMaxHeight)
152 if (aMinHeight < 0.0) {
153 // move location of full cylinder
154 aLocation->setX(aLocation->x() + aMinHeight * anAxis->x());
155 aLocation->setY(aLocation->y() + aMinHeight * anAxis->y());
156 aLocation->setZ(aLocation->z() + aMinHeight * anAxis->z());
159 aHeight = aMaxHeight - aMinHeight;
163 GeomCylinderPtr aCylinder;
165 aCylinder = GeomCylinderPtr(new GeomAPI_Cylinder(aLocation, anAxis, aRadius, aHeight));
169 //=================================================================================================
170 std::shared_ptr<GeomAPI_Cone> GeomAPI_Shell::getCone() const
173 bool isFirstFace = true;
177 double aSemiAngle, aCosSemiAngle;
178 double aHeight1, aHeight2;
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();
191 anApex = aCurCone->apex();
192 anAxis = aCurCone->axis();
193 aSemiAngle = aCurCone->semiAngle();
194 aCosSemiAngle = Cos(aSemiAngle);
195 aHeight1 = aCurCone->radius1() * aCosSemiAngle;
196 aHeight2 = aCurCone->radius2() * aCosSemiAngle;
200 // check equal locations
201 if (anApex->distance(aCurCone->apex()) >= Precision::Confusion() ||
202 // check equal angles
203 Abs(aSemiAngle - aCurCone->semiAngle()) >= Precision::Confusion() ||
204 // check directions are collinear
205 !anAxis->isParallel(aCurCone->axis())) {
210 double aSign = anAxis->dot(aCurCone->axis());
211 double aCurSemiAngle = aCurCone->semiAngle();
212 double aCosCurSemiAngle = Cos(aSemiAngle);
214 double aH = aCurCone->radius1() * aCosCurSemiAngle * aSign;
217 else if (aH > aHeight2)
220 aH = aCurCone->radius2() * aCosCurSemiAngle * aSign;
223 else if (aH > aHeight2)
230 GeomPointPtr aLocation(new GeomAPI_Pnt(
231 anApex->xyz()->added(anAxis->xyz()->multiplied(aHeight1))));
232 double aRadius1 = aHeight1 * Tan(aSemiAngle);
233 double aRadius2 = aHeight2 * Tan(aSemiAngle);
235 aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aRadius1, aRadius2));
240 //=================================================================================================
241 std::shared_ptr<GeomAPI_Torus> GeomAPI_Shell::getTorus() const
244 bool isFirstFace = true;
247 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
248 GeomFacePtr aFace(new GeomAPI_Face);
249 aFace->setImpl(new TopoDS_Shape(anExp.Current()));
251 GeomTorusPtr aCurTorus = aFace->getTorus();
263 if (Abs(aTorus->majorRadius() - aCurTorus->majorRadius()) >= Precision::Confusion() ||
264 Abs(aTorus->minorRadius() - aCurTorus->minorRadius()) >= Precision::Confusion() ||
265 // check equal centers
266 aTorus->center()->distance(aCurTorus->center()) >= Precision::SquareConfusion() ||
267 // check directions are collinear
268 !aTorus->direction()->isParallel(aCurTorus->direction())) {
275 return isTorus ? aTorus : GeomTorusPtr();
278 //=================================================================================================
279 std::shared_ptr<GeomAPI_Box> GeomAPI_Shell::getParallelepiped() const
283 std::shared_ptr<GeomAPI_Ax3> myAxes;
288 std::map<int, int> aParallelPlanes;
291 for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_WIRE);
292 anExp.More() && aNbPlanes < 6; anExp.Next()) {
293 GeomWirePtr aWire(new GeomAPI_Wire);
294 aWire->setImpl(new TopoDS_Shape(anExp.Current()));
296 std::list<GeomPointPtr> aCorners;
297 if (aWire->isRectangle(aCorners)) {
298 // convert rectangle to plane with dimensions
299 GeomPointPtr anOrigin = aCorners.front();
300 aCorners.pop_front();
302 GeomPointPtr aFront = aCorners.front();
303 GeomPointPtr aBack = aCorners.back();
305 aPlanes[aNbPlanes].myWidth = aBack->distance(anOrigin);
306 aPlanes[aNbPlanes].myDepth = aFront->distance(anOrigin);
307 aPlanes[aNbPlanes].myHeight = Precision::Infinite();
309 GeomDirPtr aDX(new GeomAPI_Dir(aBack->x() - anOrigin->x(),
310 aBack->y() - anOrigin->y(),
311 aBack->z() - anOrigin->z()));
312 GeomDirPtr aDY(new GeomAPI_Dir(aFront->x() - anOrigin->x(),
313 aFront->y() - anOrigin->y(),
314 aFront->z() - anOrigin->z()));
315 GeomDirPtr aDZ(new GeomAPI_Dir(aDX->cross(aDY)));
316 aPlanes[aNbPlanes].myAxes =
317 std::shared_ptr<GeomAPI_Ax3>(new GeomAPI_Ax3(anOrigin, aDX, aDZ));
319 // find parallel plane
320 for (int i = 0; i < aNbPlanes; ++i) {
321 double aDot = aPlanes[i].myAxes->normal()->dot(aDZ);
322 if (Abs(aDot + 1.0) < Precision::Angular()) {
323 if (aParallelPlanes.find(i) == aParallelPlanes.end())
324 aParallelPlanes[i] = aNbPlanes;
326 break; // parallel planes already exist
336 if (aNbPlanes != 6 || aParallelPlanes.size() != 3) // not a parallelepiped
339 // calculate heights for planes computed by rectangles
340 for (std::map<int, int>::iterator it = aParallelPlanes.begin();
341 it != aParallelPlanes.end(); ++it) {
342 GeomDirPtr aNormal = aPlanes[it->first].myAxes->normal();
343 GeomPointPtr anOrigin = aPlanes[it->first].myAxes->origin();
344 GeomPointPtr aNeighbor = aPlanes[it->second].myAxes->origin();
346 aPlanes[it->first].myHeight =
347 aPlanes[it->second].myHeight =
348 aNormal->xyz()->dot( aNeighbor->xyz()->decreased(anOrigin->xyz()) );
351 // check if the box is oriented in the main axes
353 for (int i = 0; i < 6; ++i) {
354 if (Abs(aPlanes[i].myAxes->dirX()->x() - 1.) < Precision::Angular() &&
355 Abs(aPlanes[i].myAxes->normal()->z() - 1.) < Precision::Angular()) {
362 GeomBoxPtr aBox(new GeomAPI_Box(aPlanes[anIndex].myAxes,
363 aPlanes[anIndex].myWidth,
364 aPlanes[anIndex].myDepth,
365 aPlanes[anIndex].myHeight));