Salome HOME
Copyright update 2022
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Ellipsoid.cpp
1 // Copyright (C) 2014-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 <GeomAlgoAPI_Ellipsoid.h>
21
22 #include <gp_Ax2.hxx>
23 #include <gp_Elips.hxx>
24 #include <gp_GTrsf.hxx>
25 #include <BRepBuilderAPI_GTransform.hxx>
26 #include <BRepBuilderAPI_MakeEdge.hxx>
27 #include <BRepOffsetAPI_Sewing.hxx>
28 #include <BRepBuilderAPI_MakeFace.hxx>
29 #include <BRepBuilderAPI_MakeSolid.hxx>
30 #include <BRepBuilderAPI_MakeWire.hxx>
31 #include <BRepPrimAPI_MakeRevol.hxx>
32
33 #include <TopoDS.hxx>
34 #include <TopoDS_Edge.hxx>
35
36 //=================================================================================================
37
38 GeomAlgoAPI_Ellipsoid::GeomAlgoAPI_Ellipsoid(const double theAx,
39                                              const double theBy,
40                                              const double theCz,
41                                              const double theZCut1,
42                                              const double theZCut2)
43 {
44   myAx = theAx;
45   myBy = theBy;
46   myCz = theCz;
47   myZCut1 = theZCut1;
48   myZCut2 = theZCut2;
49 }
50
51 //=================================================================================================
52 bool GeomAlgoAPI_Ellipsoid::check()
53 {
54   if (myAx < Precision::Confusion()) {
55     myError = "Ellipsoid builder :: ax is negative or null.";
56     return false;
57   } else if (myBy < Precision::Confusion()) {
58     myError = "Ellipsoid builder :: by is negative or null.";
59     return false;
60   } else if (myCz < Precision::Confusion()) {
61     myError = "Ellipsoid builder :: cz is negative or null.";
62     return false;
63   } else if (myZCut1 < 0.) {
64     myError = "Ellipsoid builder :: zcut1 is negative.";
65     return false;
66   } else if (myZCut2 < 0.) {
67     myError = "Ellipsoid builder :: zcut2 is negative.";
68     return false;
69   } else if (myZCut1 < Precision::Confusion() && myZCut2 < Precision::Confusion()) {
70     myError = "Ellipsoid builder :: zcut1 and zcut2 are null.";
71     return false;
72   }
73
74   return true;
75 }
76
77 //=================================================================================================
78 void GeomAlgoAPI_Ellipsoid::build()
79 {
80   myCreatedFaces.clear();
81
82   BRepOffsetAPI_Sewing aSewer;
83   gp_Ax2 aRefAx2;
84   gp_Elips anElips;
85
86   gp_Pnt anOrigin(0., 0., 0.);
87   gp_Dir aDirX(1., 0., 0.);
88   gp_Dir aDirY(0., 1., 0.);
89   gp_Dir aDirZ(0., 0., 1.);
90   gp_Ax1 aZAxis(anOrigin, aDirZ);
91
92   // Calculate the parameters needed to make the edges and the faces
93   // gp_Elips needs the second parameter to be greater than the third (major axis)
94   if (myCz < myAx) {
95     aRefAx2 = gp_Ax2(anOrigin, aDirY, aDirX);
96     anElips = gp_Elips(aRefAx2, myAx / 2., myCz / 2.);
97   } else {
98     aRefAx2 = gp_Ax2(anOrigin, aDirY, aDirZ);
99     anElips = gp_Elips(aRefAx2, myCz / 2., myAx / 2.);
100   }
101
102   double aLowPositionFactor = sqrt(1. - (myZCut1 * myZCut1 * 4. / (myCz * myCz))) / 2.;
103   double aHighPositionFactor = sqrt(1. - (myZCut2 * myZCut2 * 4. / (myCz * myCz))) / 2.;
104
105   double aXEndTop = myAx * aHighPositionFactor;
106   double aXEndBottom = myAx *  aLowPositionFactor;
107
108   // Build the XZ ellipse
109   gp_Pnt anEndPoint1(aXEndTop, 0., myZCut2);
110   gp_Pnt anEndPoint2(aXEndBottom, 0., -myZCut1);
111   BRepBuilderAPI_MakeEdge anElipsBuilder(anElips, anEndPoint1, anEndPoint2);
112   anElipsBuilder.Build();
113   TopoDS_Edge anOuterEdge = anElipsBuilder.Edge();
114
115   // Perform a revolution based on the section to build a simple version of the outer face
116   // (isotropic in XY)
117   BRepPrimAPI_MakeRevol aRevolBuilder(anOuterEdge, aZAxis, 2. * M_PI, Standard_True);
118   if (!aRevolBuilder.IsDone()) {
119     myError = "Ellipsoid builder :: section revolution did not succeed";
120     return;
121   }
122
123   gp_GTrsf aGTrsf;
124   gp_Mat rot (1.,          0., 0.,
125               0., myBy / myAx, 0.,
126               0.,          0., 1.);
127
128   aGTrsf.SetVectorialPart(rot);
129
130   BRepBuilderAPI_GTransform aScaleBuilder(aRevolBuilder.Shape(), aGTrsf, true);
131   if (!aScaleBuilder.IsDone()) {
132     myError = "Ellipsoid builder :: scale did not succeed";
133     return;
134   }
135
136   TopoDS_Face anOuterFace = TopoDS::Face(aScaleBuilder.Shape());
137   aSewer.Add(TopoDS::Face(anOuterFace.Reversed()));
138
139   // Build the high and low ellipse if needed
140   gp_Ax2 aLowAx2;
141   gp_Ax2 aHighAx2;
142   gp_Elips aLowElips;
143   gp_Elips aHighElips;
144   if (myBy < myAx) {
145     if ((myCz / 2. - myZCut1) > Precision::Confusion()) {
146       aLowAx2 = gp_Ax2(gp_Pnt(0., 0., -myZCut1), aDirZ, aDirX);
147       aLowElips = gp_Elips(aLowAx2, aLowPositionFactor * myAx, aLowPositionFactor * myBy);
148     }
149     if ((myCz / 2. - myZCut2) > Precision::Confusion()) {
150       aHighAx2 = gp_Ax2(gp_Pnt(0., 0., myZCut2), aDirZ, aDirX);
151       aHighElips = gp_Elips(aHighAx2, aHighPositionFactor * myAx, aHighPositionFactor * myBy);
152     }
153   } else {
154     if ((myCz / 2. - myZCut1) > Precision::Confusion()) {
155       aLowAx2 = gp_Ax2(gp_Pnt(0., 0., -myZCut1), aDirZ, aDirY);
156       aLowElips = gp_Elips(aLowAx2, aLowPositionFactor * myBy, aLowPositionFactor * myAx);
157     }
158     if ((myCz / 2. - myZCut2) > Precision::Confusion()) {
159       aHighAx2 = gp_Ax2(gp_Pnt(0., 0., myZCut2), aDirZ, aDirY);
160       aHighElips = gp_Elips(aHighAx2, aHighPositionFactor * myBy, aHighPositionFactor * myAx);
161     }
162   }
163
164   // Make higher and lower elliptical faces if needed
165   if ((myCz / 2. - myZCut1) > Precision::Confusion()) {
166     TopoDS_Face aBottomFace;
167     BRepBuilderAPI_MakeEdge aBottomEdgeMk(aLowElips);
168     aBottomEdgeMk.Build();
169     BRepBuilderAPI_MakeWire aBottomWireMk;
170     aBottomWireMk.Add(aBottomEdgeMk.Edge());
171     BRepBuilderAPI_MakeFace aBottomFaceMk(aBottomWireMk.Wire());
172     aBottomFace = aBottomFaceMk.Face();
173     aSewer.Add(TopoDS::Face(aBottomFace.Reversed()));
174   }
175   if ((myCz / 2. - myZCut2) > Precision::Confusion()) {
176     TopoDS_Face aTopFace;
177     BRepBuilderAPI_MakeEdge aTopEdgeMk(aHighElips);
178     aTopEdgeMk.Build();
179     BRepBuilderAPI_MakeWire aTopWireMk;
180     aTopWireMk.Add(aTopEdgeMk.Edge());
181     BRepBuilderAPI_MakeFace aTopFaceMk(aTopWireMk.Wire());
182     aTopFace = aTopFaceMk.Face();
183     aSewer.Add(TopoDS::Face(aTopFace.Reversed()));
184   }
185
186   TopoDS_Shell aShell;
187   aSewer.Perform();
188   if ((myCz / 2. - myZCut2) > Precision::Confusion() ||
189       (myCz / 2. - myZCut1) > Precision::Confusion()) {
190     aShell = TopoDS::Shell(aSewer.SewedShape());
191   } else {
192     TopoDS_Builder aBuilder;
193     aBuilder.MakeShell(aShell);
194     aBuilder.Add(aShell, aSewer.SewedShape());
195   }
196
197   BRepBuilderAPI_MakeSolid *anEllipsoidMk = new BRepBuilderAPI_MakeSolid(aShell);
198   anEllipsoidMk->Build();
199
200   // Store and publish the results
201   std::shared_ptr<GeomAPI_Shape> aResultShape =
202     std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
203   aResultShape->setImpl(new TopoDS_Shape(anEllipsoidMk->Solid()));
204   setShape(aResultShape);
205
206   // Test on the shapes
207   if (!(aResultShape).get() || aResultShape->isNull()) {
208     myError = "Ellipsoid builder  :: resulting shape is null.";
209     return;
210   }
211
212   setImpl(anEllipsoidMk);
213   setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
214
215   setDone(true);
216 }