Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Sphere.cpp
index d307fe54e649718a70f01d8d61f1dc14586d4f7c..c979b77674758f3cee8303a17ccf56207d85440c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017-2019  CEA/DEN, EDF R&D
+// Copyright (C) 2017-2023  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 
 #include <GeomAlgoAPI_Sphere.h>
 
+#include <gp_Circ.hxx>
+
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+
+#include <BRepPrimAPI_MakeRevol.hxx>
 #include <BRepPrimAPI_MakeSphere.hxx>
 
 //=================================================================================================
 GeomAlgoAPI_Sphere::GeomAlgoAPI_Sphere(std::shared_ptr<GeomAPI_Pnt> theCenterPoint,
                                        const double theRadius)
 {
+  isRootGeo = false;
   myCenterPoint = theCenterPoint;
   myRadius = theRadius;
 }
 
+//=================================================================================================
+GeomAlgoAPI_Sphere::GeomAlgoAPI_Sphere(const double theRMin, const double theRMax,
+                                       const double thePhiMin, const double thePhiMax,
+                                       const double theThetaMin, const double theThetaMax)
+{
+  isRootGeo = true;
+  myRMin = theRMin;
+  myRMax = theRMax;
+  myPhiMin = thePhiMin;
+  myPhiMax = thePhiMax;
+  myThetaMin = theThetaMin;
+  myThetaMax = theThetaMax;
+}
+
 //=================================================================================================
 bool GeomAlgoAPI_Sphere::check()
 {
-  if (!myCenterPoint) {
-    myError = "Sphere builder :: center is not valid.";
-    return false;
-  }
-  if (myRadius < Precision::Confusion()) {
-    myError = "Sphere builder :: radius is negative or null.";
-    return false;
+  if (isRootGeo) {
+    if ((myRMin-myRMax) > Precision::Confusion()) {
+      myError = "Sphere builder :: RMin is larger than RMax.";
+      return false;
+    }
+  } else {
+    if (!myCenterPoint) {
+      myError = "Sphere builder :: center is not valid.";
+      return false;
+    }
+    if (myRadius < Precision::Confusion()) {
+      myError = "Sphere builder :: radius is negative or null.";
+      return false;
+    }
   }
   return true;
 }
@@ -51,30 +80,151 @@ bool GeomAlgoAPI_Sphere::check()
 void GeomAlgoAPI_Sphere::build()
 {
   myCreatedFaces.clear();
+  if (isRootGeo) {
+    buildRootSphere();
+  } else {
+    const gp_Pnt& aCenterPoint = myCenterPoint->impl<gp_Pnt>();
+
+    // Construct the sphere
+    BRepPrimAPI_MakeSphere *aSphereMaker = new BRepPrimAPI_MakeSphere(aCenterPoint, myRadius);
+
+    aSphereMaker->Build();
+
+    if (!aSphereMaker->IsDone()) {
+      return;
+    }
+
+    TopoDS_Shape aResult = aSphereMaker->Shape();
+    std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+    aShape->setImpl(new TopoDS_Shape(aResult));
+    setShape(aShape);
+
+    // Test on the shapes
+    if (!aShape.get() || aShape->isNull()) {
+      myError = "Sphere builder :: resulting shape is null.";
+      return;
+    }
+
+    setImpl(aSphereMaker);
+
+    setDone(true);
+  }
+}
+
+//=================================================================================================
+void GeomAlgoAPI_Sphere::buildRootSphere()
+{
+  myCreatedFaces.clear();
+
+  const double aStartPhiRad = myPhiMin * M_PI / 180.;
+  BRepBuilderAPI_MakeWire aWireBuilder;
+
+  gp_Pnt anOrigin(0., 0., 0.);
+  gp_Dir aNormal(-sin(aStartPhiRad), cos(aStartPhiRad), 0.);
+
+
+  // The section is defined by 4 points and up to 4 wires. In the rmin = 0 case, two of the points
+  // will actually be the origin
+  double aX = myRMax*sin(myThetaMin * M_PI/180.);
+  double aZ = myRMax*cos(myThetaMin * M_PI/180.);
+  gp_Pnt aTopOuterStart(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
 
-  const gp_Pnt& aCenterPoint = myCenterPoint->impl<gp_Pnt>();
+  aX = myRMax*sin((myThetaMin+myThetaMax) * M_PI/180.);
+  aZ = myRMax*cos((myThetaMin+myThetaMax) * M_PI/180.);
+  gp_Pnt aBaseOuterEnd(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
 
-  // Construct the sphere
-  BRepPrimAPI_MakeSphere *aSphereMaker = new BRepPrimAPI_MakeSphere(aCenterPoint, myRadius);
+  aX = myRMin*sin(myThetaMin * M_PI/180.);
+  aZ = myRMin*cos(myThetaMin * M_PI/180.);
+  gp_Pnt aTopInnerStart(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
 
-  aSphereMaker->Build();
+  aX = myRMin*sin((myThetaMin+myThetaMax) * M_PI/180.);
+  aZ = myRMin*cos((myThetaMin+myThetaMax) * M_PI/180.);
+  gp_Pnt aBaseInnerEnd(aX*cos(aStartPhiRad), aX*sin(aStartPhiRad), aZ);
+
+  // There will always be the rmax arc since rmax can't be zero
+  gp_Circ anOuterCircle(gp_Ax2(anOrigin, aNormal), myRMax);
+  BRepBuilderAPI_MakeEdge anArcOuterBuilder;
+  if (aTopOuterStart.IsEqual(aBaseOuterEnd, Precision::Confusion()))
+    anArcOuterBuilder = BRepBuilderAPI_MakeEdge(anOuterCircle);
+  else
+    anArcOuterBuilder = BRepBuilderAPI_MakeEdge(anOuterCircle, aTopOuterStart, aBaseOuterEnd);
+  anArcOuterBuilder.Build();
+
+  // Two cases : either we need four edges (one being an arc with curvature radius rmin) or we
+  // need three (if rmin=0).
+  // In the later case the top and bottom edges intersect at the origin
+  // Add the edges to the wire in consecutive order (very important for the face to make sense
+  // topologically)
+  if(myRMin >= Precision::Confusion()){
+    gp_Circ anInnerCircle(gp_Ax2(anOrigin, aNormal), myRMin);
+    BRepBuilderAPI_MakeEdge anArcInnerBuilder;
+    if (aTopInnerStart.IsEqual(aBaseInnerEnd, Precision::Confusion()))
+      anArcInnerBuilder = BRepBuilderAPI_MakeEdge(anInnerCircle);
+    else
+      anArcInnerBuilder = BRepBuilderAPI_MakeEdge(anInnerCircle, aTopInnerStart, aBaseInnerEnd);
+    anArcInnerBuilder.Build();
+
+    BRepBuilderAPI_MakeEdge anEdgeStartBuilder(aTopInnerStart, aTopOuterStart);
+    anEdgeStartBuilder.Build();
+    BRepBuilderAPI_MakeEdge anEdgeEndBuilder(aBaseInnerEnd, aBaseOuterEnd);
+    anEdgeEndBuilder.Build();
+
+    aWireBuilder.Add(anEdgeStartBuilder.Edge());
+    aWireBuilder.Add(anArcOuterBuilder.Edge());
+    aWireBuilder.Add(anEdgeEndBuilder.Edge());
+    aWireBuilder.Add(anArcInnerBuilder.Edge());
+  }
+  else{
+    BRepBuilderAPI_MakeEdge anEdgeStartBuilder(anOrigin, aTopOuterStart);
+    anEdgeStartBuilder.Build();
+    BRepBuilderAPI_MakeEdge anEdgeEndBuilder(anOrigin, aBaseOuterEnd);
+    anEdgeEndBuilder.Build();
 
-  if (!aSphereMaker->IsDone()) {
+    aWireBuilder.Add(anArcOuterBuilder.Edge());
+    aWireBuilder.Add(anEdgeStartBuilder.Edge());
+    aWireBuilder.Add(anEdgeEndBuilder.Edge());
+  }
+
+  // Make a face from the wire
+  aWireBuilder.Build();
+  BRepBuilderAPI_MakeFace aFaceBuilder(aWireBuilder.Wire());
+  aFaceBuilder.Build();
+
+  if (!aFaceBuilder.IsDone()){
+    myError = "GDML sphere builder :: section is not valid";
+    return;
+  }
+
+  // Mathematical tool objects needed by the revolution builder
+  gp_Dir aZDir(0., 0., 1.);
+  gp_Ax1 aZAxis(anOrigin, aZDir);
+
+  // Build the solid using the section face we've created and a revolution builder
+  BRepPrimAPI_MakeRevol* aRevolBuilder =
+    new BRepPrimAPI_MakeRevol(aFaceBuilder.Face(), aZAxis, myPhiMax * M_PI / 180., Standard_True);
+  if(!aRevolBuilder) {
+    return;
+    myError = "GDML Sphere builder :: section revolution did not succeed";
+  }
+  if(!aRevolBuilder->IsDone()) {
+    myError = "GDML Sphere builder :: section revolution did not succeed";
     return;
   }
 
-  TopoDS_Shape aResult = aSphereMaker->Shape();
-  std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
-  aShape->setImpl(new TopoDS_Shape(aResult));
-  setShape(aShape);
+  // Get the shape, verify it, build a GeomAPI_Shape.
+  std::shared_ptr<GeomAPI_Shape> aResultShape =
+    std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
+  aResultShape->setImpl(new TopoDS_Shape(aRevolBuilder->Shape()));
+  setShape(aResultShape);
 
   // Test on the shapes
-  if (!aShape.get() || aShape->isNull()) {
-    myError = "Sphere builder :: resulting shape is null.";
+  if (!(aResultShape).get() || aResultShape->isNull()) {
+    myError = "GDML Sphere builder  :: resulting shape is null.";
     return;
   }
 
-  setImpl(aSphereMaker);
+  setImpl(aRevolBuilder);
+  setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
 
   setDone(true);
 }