]> OCCT Git - occt.git/commitdiff
[Salome issue 45822] Pipe feature errors
authorjfa <jfa@opencascade.com>
Thu, 14 Aug 2025 12:24:00 +0000 (13:24 +0100)
committerjfa <jfa@opencascade.com>
Thu, 14 Aug 2025 12:24:00 +0000 (13:24 +0100)
src/Extrema/Extrema_ExtCC.cxx
src/Extrema/Extrema_ExtElC.cxx
src/Extrema/Extrema_ExtElC.hxx

index 907876414cded8a2cbf685ee8185dc929ac04c8e..0d8dc940d148fa83a940a98ad74a217f36aec5cb 100644 (file)
@@ -646,6 +646,15 @@ void Extrema_ExtCC::PrepareParallelResult(const Standard_Real theUt11,
                                 Precision::Confusion(),
                                 theUt11,
                                 theUt12);
+        // if (!ExtPCir.IsDone())
+        // {
+        //   // The point is in the center of the circle => there are infinite solutions
+        //   ClearSolutions();
+        //   const Standard_Real aRadius = Extrema_CurveTool::Circle(*myC[0]).Radius();
+        //   mySqDist.Append(aRadius * aRadius);
+        //   myIsParallel = Standard_True;
+        //   break;
+        // }
         if (ExtPCir.NbExt() < 1)
         {
           continue;
@@ -702,6 +711,15 @@ void Extrema_ExtCC::PrepareParallelResult(const Standard_Real theUt11,
                                 Precision::Confusion(),
                                 theUt11,
                                 theUt12);
+        // if (!ExtPCir.IsDone())
+        // {
+        //   // The point is in the center of the circle => there are infinite solutions
+        //   ClearSolutions();
+        //   const Standard_Real aRadius = Extrema_CurveTool::Circle(*myC[0]).Radius();
+        //   mySqDist.Append(aRadius * aRadius);
+        //   myIsParallel = Standard_True;
+        //   break;
+        // }
 
         Standard_Boolean isFound = !myIsParallel;
 
@@ -809,13 +827,13 @@ void Extrema_ExtCC::PrepareResults(const Extrema_ExtElC&  AlgExt,
   if (myDone)
   {
     myIsParallel = AlgExt.IsParallel();
-    if (myIsParallel)
+    NbExt = AlgExt.NbExt();
+    if (myIsParallel && NbExt == 0)
     {
       PrepareParallelResult(Ut11, Ut12, Ut21, Ut22, AlgExt.SquareDistance());
     }
     else
     {
-      NbExt = AlgExt.NbExt();
       for (i = 1; i <= NbExt; i++)
       {
         // Verification de la validite des parametres
@@ -833,11 +851,25 @@ void Extrema_ExtCC::PrepareResults(const Extrema_ExtElC&  AlgExt,
 
         if (Extrema_CurveTool::IsPeriodic(*myC[0]))
         {
-          U = ElCLib::InPeriod(U, Ut11, Ut11 + Extrema_CurveTool::Period(*myC[0]));
+          if (Abs(U - Ut11) < Precision::Confusion())
+          {
+            U = Ut11;
+          }
+          else
+          {
+            U = ElCLib::InPeriod(U, Ut11, Ut11 + Extrema_CurveTool::Period(*myC[0]));
+          }
         }
         if (Extrema_CurveTool::IsPeriodic(*myC[1]))
         {
-          U2 = ElCLib::InPeriod(U2, Ut21, Ut21 + Extrema_CurveTool::Period(*myC[1]));
+          if (Abs(U2 - Ut21) < Precision::Confusion())
+          {
+            U2 = Ut21;
+          }
+          else
+          {
+            U2 = ElCLib::InPeriod(U2, Ut21, Ut21 + Extrema_CurveTool::Period(*myC[1]));
+          }
         }
 
         if ((U >= Ut11 - RealEpsilon()) && (U <= Ut12 + RealEpsilon())
index 43b1c800bd145e136c14f6675c94fbec49b50a60..6a34e21210d8368b4303f8acb2b068703cdf0580 100644 (file)
@@ -436,6 +436,137 @@ Standard_Boolean Extrema_ExtElC::PlanarLineCircleExtrema(const gp_Lin&  theLin,
   return Standard_True;
 }
 
+//=================================================================================================
+
+Standard_Boolean Extrema_ExtElC::PerpendicularCirclesExtrema(const gp_Circ&      C1,
+                                                             const gp_Circ&      C2,
+                                                             const gp_Pln&       aPlc1,
+                                                             const gp_Pln&       aPlc2,
+                                                             const Standard_Real aTolD,
+                                                             const Standard_Real angPlanes)
+{
+  if (angPlanes <= M_PI_4)
+  {
+    return Standard_False; // The planes are more "parallel" than "perpendicular"
+  }
+
+  Standard_Real aTolD2 = aTolD * aTolD;
+  gp_Pnt aPc1 = C1.Location();
+  gp_Pnt aPc2 = C2.Location();
+  Standard_Real aD1 = aPlc2.SquareDistance(aPc1);
+  if (aD1 < aTolD2)
+  {
+    // The center of the first circle is on the plane of the second circle,
+    // and the center of the second circle is on the plane of the first circle.
+    // => the intersection line of the two planes is along the connection of the circles' centers.
+    // Compute the number of extremes based on the distance between the centers of the circles.
+    Standard_Real aDist = aPc1.Distance(aPc2);
+    Standard_Real aMinR = Min(C1.Radius(), C2.Radius());
+    Standard_Real aMaxR = Max(C1.Radius(), C2.Radius());
+    if (aDist >= aMaxR + aMinR - aTolD)
+    {
+      // The circles are either far apart or just touching.
+      // There is one solution for the closest points on the circles.
+      myNbExt = 1;
+      gp_Vec aVec(aPc1, aPc2);
+      aVec.Normalize();
+      gp_Pnt aP1 = aPc1.Translated(aVec * C1.Radius());
+      gp_Pnt aP2 = aPc2.Translated(-aVec * C2.Radius());
+      aDist -= aMaxR + aMinR;
+      mySqDist[0] = aDist * aDist;
+      myPoint[0][0].SetValues(ElCLib::Parameter(C1, aP1), aP1);
+      myPoint[0][1].SetValues(ElCLib::Parameter(C2, aP2), aP2);
+      myIsPar = Standard_False;
+      return Standard_True;
+    }
+
+    if (Abs(aDist - aMaxR) < aTolD)
+    {
+      // The bigger circle is going through the center of the smaller circle.
+      // There are infinite solutions on the small circle.
+      myNbExt = 1;
+      gp_Vec aVec(aPc1, aPc2);
+      aVec.Normalize();
+      gp_Pnt aP1  = aPc1.Translated(aVec * C1.Radius());
+      gp_Pnt aP2  = aPc2.Translated(-aVec * C2.Radius());
+      aDist       = aMinR;
+      mySqDist[0] = aDist * aDist;
+      myPoint[0][0].SetValues(ElCLib::Parameter(C1, aP1), aP1);
+      myPoint[0][1].SetValues(ElCLib::Parameter(C2, aP2), aP2);
+      myIsPar = Standard_True; // indicator for infinite solutions
+      return Standard_True;
+    }
+
+    if (aDist <= aMaxR - aMinR + aTolD)
+    {
+      // The smaller circle is completely inside the bigger circle.
+      // There is one solution for the closest points on the circles.
+      myNbExt = 1;
+      gp_Vec aVec(aPc1, aPc2);
+      if (aVec.Magnitude() < aTolD)
+      {
+        // Both circle centers are coincident.
+        aVec = aPlc1.Axis().Direction().Crossed(aPlc2.Axis().Direction());
+        myNbExt++;
+      }
+      aVec.Normalize();
+      if (C1.Radius() < C2.Radius())
+      {
+        aVec.Reverse();
+      }
+      gp_Pnt        aP1 = aPc1.Translated(aVec * C1.Radius());
+      gp_Pnt        aP2 = aPc2.Translated(aVec * C2.Radius());
+      Standard_Real aD  = aMaxR - aDist - aMinR;
+      mySqDist[0]       = aD * aD;
+      myPoint[0][0].SetValues(ElCLib::Parameter(C1, aP1), aP1);
+      myPoint[0][1].SetValues(ElCLib::Parameter(C2, aP2), aP2);
+      if (myNbExt > 1)
+      {
+        gp_Pnt aP3 = aPc1.Translated(-aVec * C1.Radius());
+        gp_Pnt aP4 = aPc2.Translated(-aVec * C2.Radius());
+        mySqDist[1] = mySqDist[0];
+        myPoint[1][0].SetValues(ElCLib::Parameter(C1, aP3), aP3);
+        myPoint[1][1].SetValues(ElCLib::Parameter(C2, aP4), aP4);
+      }
+      myIsPar = Standard_False;
+      return Standard_True;
+    }
+
+    if (aDist < aMaxR + aMinR - aTolD)
+    {
+      // The circles are intersecting.
+      // There is one solution for the closest points on the circles.
+      myNbExt = 1;
+      gp_Vec aVec(aPc2, aPc1);
+      if (aVec.Magnitude() < aMaxR)
+      {
+        // The center of the small circle is inside the big circle.
+        aVec.Reverse();
+      }
+      aVec.Normalize();
+      if (C1.Radius() < C2.Radius())
+      {
+        aVec.Reverse();
+      }
+      gp_Pnt        aP1 = aPc1.Translated(aVec * C1.Radius());
+      gp_Pnt        aP2 = aPc2.Translated(aVec * C2.Radius());
+      Standard_Real aD  = (aMaxR + aMinR - aDist);
+      mySqDist[0]       = aD * aD;
+      myPoint[0][0].SetValues(ElCLib::Parameter(C1, aP1), aP1);
+      myPoint[0][1].SetValues(ElCLib::Parameter(C2, aP2), aP2);
+      myIsPar = Standard_False;
+      return Standard_True;
+    }
+
+    // std::cout << "====> Extrema_ExtElC: unsupported case for circles in different planes." << std::endl;
+    // std::cout << "  Distance between centers: " << aDist << std::endl;
+    // std::cout << "  Angle between planes ...: " << angPlanes * 180.0 / M_PI << " deg" << std::endl;
+    // std::cout << "  Radius Circle 1 ........: " << C1.Radius() << std::endl;
+    // std::cout << "  Radius Circle 2 ........: " << C2.Radius() << std::endl;
+  }
+  return Standard_False;
+}
+
 //=======================================================================
 // function : Extrema_ExtElC
 // purpose  :
@@ -973,6 +1104,22 @@ Extrema_ExtElC::Extrema_ExtElC(const gp_Circ& C1, const gp_Circ& C2)
   bIsSamePlane = aDc1.IsParallel(aDc2, aTolA) && aD2 < aTolD2;
   if (!bIsSamePlane)
   {
+    // Handle the specific case:
+    //  * where both planes are "almost perpendicular" (=> angle between planes > 45 deg)
+    //  * where the center of each circle is on the plane of the other circle
+    //    (=> the circle centers are on the intersection line of the two planes)
+    const Standard_Real angPlanes = aDc1.Angle(aDc2);
+    if (aD2 < aTolD2 && angPlanes > M_PI_4)
+    {
+      // The center of the second circle is on the plane of the first circle and
+      // both planes are "almost perpendicular".
+      gp_Pln aPlc2(aPc2, aDc2);
+      if (PerpendicularCirclesExtrema(C1, C2, aPlc1, aPlc2, aTolD, angPlanes))
+      {
+        myDone = Standard_True;
+        return;
+      }
+    }
     return;
   }
 
index ebca165b8d01949d1f3c05fd36ca1506803c916e..546da312c79e017b652503886c68161b615726bc 100644 (file)
@@ -28,6 +28,7 @@ class gp_Circ;
 class gp_Elips;
 class gp_Hypr;
 class gp_Parab;
+class gp_Pln;
 
 //! It calculates all the distance between two elementary
 //! curves.
@@ -85,7 +86,13 @@ public:
 protected:
   //! Computes extrema in case when considered line and circle are in one plane
   Standard_EXPORT Standard_Boolean PlanarLineCircleExtrema(const gp_Lin& C1, const gp_Circ& C2);
-
+  //! Computes extrema in case when two circles are in almost perpendicular planes
+  //! and their centers are on the intersection line of these planes
+  //! (angle between planes > 45 degrees)
+  Standard_EXPORT Standard_Boolean PerpendicularCirclesExtrema(const gp_Circ& C1, const gp_Circ& C2,
+                                                               const gp_Pln& aPlc1, const gp_Pln& aPlc2,
+                                                               const Standard_Real aTolD,
+                                                               const Standard_Real angPlanes);
 private:
   Standard_Boolean myDone;
   Standard_Boolean myIsPar;