Salome HOME
c979b77674758f3cee8303a17ccf56207d85440c
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Sphere.cpp
1 // Copyright (C) 2017-2023  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 // File:        GeomAlgoAPI_Sphere.h
21 // Created:     16 Mar 2017
22 // Author:      Clarisse Genrault (CEA)
23
24 #include <GeomAlgoAPI_Sphere.h>
25
26 #include <gp_Circ.hxx>
27
28 #include <BRepBuilderAPI_MakeEdge.hxx>
29 #include <BRepBuilderAPI_MakeFace.hxx>
30 #include <BRepBuilderAPI_MakeWire.hxx>
31
32 #include <BRepPrimAPI_MakeRevol.hxx>
33 #include <BRepPrimAPI_MakeSphere.hxx>
34
35 //=================================================================================================
36 GeomAlgoAPI_Sphere::GeomAlgoAPI_Sphere(std::shared_ptr<GeomAPI_Pnt> theCenterPoint,
37                                        const double theRadius)
38 {
39   isRootGeo = false;
40   myCenterPoint = theCenterPoint;
41   myRadius = theRadius;
42 }
43
44 //=================================================================================================
45 GeomAlgoAPI_Sphere::GeomAlgoAPI_Sphere(const double theRMin, const double theRMax,
46                                        const double thePhiMin, const double thePhiMax,
47                                        const double theThetaMin, const double theThetaMax)
48 {
49   isRootGeo = true;
50   myRMin = theRMin;
51   myRMax = theRMax;
52   myPhiMin = thePhiMin;
53   myPhiMax = thePhiMax;
54   myThetaMin = theThetaMin;
55   myThetaMax = theThetaMax;
56 }
57
58 //=================================================================================================
59 bool GeomAlgoAPI_Sphere::check()
60 {
61   if (isRootGeo) {
62     if ((myRMin-myRMax) > Precision::Confusion()) {
63       myError = "Sphere builder :: RMin is larger than RMax.";
64       return false;
65     }
66   } else {
67     if (!myCenterPoint) {
68       myError = "Sphere builder :: center is not valid.";
69       return false;
70     }
71     if (myRadius < Precision::Confusion()) {
72       myError = "Sphere builder :: radius is negative or null.";
73       return false;
74     }
75   }
76   return true;
77 }
78
79 //=================================================================================================
80 void GeomAlgoAPI_Sphere::build()
81 {
82   myCreatedFaces.clear();
83   if (isRootGeo) {
84     buildRootSphere();
85   } else {
86     const gp_Pnt& aCenterPoint = myCenterPoint->impl<gp_Pnt>();
87
88     // Construct the sphere
89     BRepPrimAPI_MakeSphere *aSphereMaker = new BRepPrimAPI_MakeSphere(aCenterPoint, myRadius);
90
91     aSphereMaker->Build();
92
93     if (!aSphereMaker->IsDone()) {
94       return;
95     }
96
97     TopoDS_Shape aResult = aSphereMaker->Shape();
98     std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
99     aShape->setImpl(new TopoDS_Shape(aResult));
100     setShape(aShape);
101
102     // Test on the shapes
103     if (!aShape.get() || aShape->isNull()) {
104       myError = "Sphere builder :: resulting shape is null.";
105       return;
106     }
107
108     setImpl(aSphereMaker);
109
110     setDone(true);
111   }
112 }
113
114 //=================================================================================================
115 void GeomAlgoAPI_Sphere::buildRootSphere()
116 {
117   myCreatedFaces.clear();
118
119   const double aStartPhiRad = myPhiMin * M_PI / 180.;
120   BRepBuilderAPI_MakeWire aWireBuilder;
121
122   gp_Pnt anOrigin(0., 0., 0.);
123   gp_Dir aNormal(-sin(aStartPhiRad), cos(aStartPhiRad), 0.);
124
125
126   // The section is defined by 4 points and up to 4 wires. In the rmin = 0 case, two of the points
127   // will actually be the origin
128   double aX = myRMax*sin(myThetaMin * M_PI/180.);
129   double aZ = myRMax*cos(myThetaMin * M_PI/180.);
130   gp_Pnt aTopOuterStart(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
131
132   aX = myRMax*sin((myThetaMin+myThetaMax) * M_PI/180.);
133   aZ = myRMax*cos((myThetaMin+myThetaMax) * M_PI/180.);
134   gp_Pnt aBaseOuterEnd(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
135
136   aX = myRMin*sin(myThetaMin * M_PI/180.);
137   aZ = myRMin*cos(myThetaMin * M_PI/180.);
138   gp_Pnt aTopInnerStart(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
139
140   aX = myRMin*sin((myThetaMin+myThetaMax) * M_PI/180.);
141   aZ = myRMin*cos((myThetaMin+myThetaMax) * M_PI/180.);
142   gp_Pnt aBaseInnerEnd(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
143
144   // There will always be the rmax arc since rmax can't be zero
145   gp_Circ anOuterCircle(gp_Ax2(anOrigin, aNormal), myRMax);
146   BRepBuilderAPI_MakeEdge anArcOuterBuilder;
147   if (aTopOuterStart.IsEqual(aBaseOuterEnd, Precision::Confusion()))
148     anArcOuterBuilder = BRepBuilderAPI_MakeEdge(anOuterCircle);
149   else
150     anArcOuterBuilder = BRepBuilderAPI_MakeEdge(anOuterCircle, aTopOuterStart, aBaseOuterEnd);
151   anArcOuterBuilder.Build();
152
153   // Two cases : either we need four edges (one being an arc with curvature radius rmin) or we
154   // need three (if rmin=0).
155   // In the later case the top and bottom edges intersect at the origin
156   // Add the edges to the wire in consecutive order (very important for the face to make sense
157   // topologically)
158   if(myRMin >= Precision::Confusion()){
159     gp_Circ anInnerCircle(gp_Ax2(anOrigin, aNormal), myRMin);
160     BRepBuilderAPI_MakeEdge anArcInnerBuilder;
161     if (aTopInnerStart.IsEqual(aBaseInnerEnd, Precision::Confusion()))
162       anArcInnerBuilder = BRepBuilderAPI_MakeEdge(anInnerCircle);
163     else
164       anArcInnerBuilder = BRepBuilderAPI_MakeEdge(anInnerCircle, aTopInnerStart, aBaseInnerEnd);
165     anArcInnerBuilder.Build();
166
167     BRepBuilderAPI_MakeEdge anEdgeStartBuilder(aTopInnerStart, aTopOuterStart);
168     anEdgeStartBuilder.Build();
169     BRepBuilderAPI_MakeEdge anEdgeEndBuilder(aBaseInnerEnd, aBaseOuterEnd);
170     anEdgeEndBuilder.Build();
171
172     aWireBuilder.Add(anEdgeStartBuilder.Edge());
173     aWireBuilder.Add(anArcOuterBuilder.Edge());
174     aWireBuilder.Add(anEdgeEndBuilder.Edge());
175     aWireBuilder.Add(anArcInnerBuilder.Edge());
176   }
177   else{
178     BRepBuilderAPI_MakeEdge anEdgeStartBuilder(anOrigin, aTopOuterStart);
179     anEdgeStartBuilder.Build();
180     BRepBuilderAPI_MakeEdge anEdgeEndBuilder(anOrigin, aBaseOuterEnd);
181     anEdgeEndBuilder.Build();
182
183     aWireBuilder.Add(anArcOuterBuilder.Edge());
184     aWireBuilder.Add(anEdgeStartBuilder.Edge());
185     aWireBuilder.Add(anEdgeEndBuilder.Edge());
186   }
187
188   // Make a face from the wire
189   aWireBuilder.Build();
190   BRepBuilderAPI_MakeFace aFaceBuilder(aWireBuilder.Wire());
191   aFaceBuilder.Build();
192
193   if (!aFaceBuilder.IsDone()){
194     myError = "GDML sphere builder :: section is not valid";
195     return;
196   }
197
198   // Mathematical tool objects needed by the revolution builder
199   gp_Dir aZDir(0., 0., 1.);
200   gp_Ax1 aZAxis(anOrigin, aZDir);
201
202   // Build the solid using the section face we've created and a revolution builder
203   BRepPrimAPI_MakeRevol* aRevolBuilder =
204     new BRepPrimAPI_MakeRevol(aFaceBuilder.Face(), aZAxis, myPhiMax * M_PI / 180., Standard_True);
205   if(!aRevolBuilder) {
206     return;
207     myError = "GDML Sphere builder :: section revolution did not succeed";
208   }
209   if(!aRevolBuilder->IsDone()) {
210     myError = "GDML Sphere builder :: section revolution did not succeed";
211     return;
212   }
213
214   // Get the shape, verify it, build a GeomAPI_Shape.
215   std::shared_ptr<GeomAPI_Shape> aResultShape =
216     std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
217   aResultShape->setImpl(new TopoDS_Shape(aRevolBuilder->Shape()));
218   setShape(aResultShape);
219
220   // Test on the shapes
221   if (!(aResultShape).get() || aResultShape->isNull()) {
222     myError = "GDML Sphere builder  :: resulting shape is null.";
223     return;
224   }
225
226   setImpl(aRevolBuilder);
227   setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
228
229   setDone(true);
230 }