From a7fb645f2cbd6269da8699c5752c89a69384da6f Mon Sep 17 00:00:00 2001 From: jfa Date: Thu, 14 Aug 2025 13:24:00 +0100 Subject: [PATCH] [Salome issue 45822] Pipe feature errors --- src/Extrema/Extrema_ExtCC.cxx | 40 ++++++++- src/Extrema/Extrema_ExtElC.cxx | 147 +++++++++++++++++++++++++++++++++ src/Extrema/Extrema_ExtElC.hxx | 9 +- 3 files changed, 191 insertions(+), 5 deletions(-) diff --git a/src/Extrema/Extrema_ExtCC.cxx b/src/Extrema/Extrema_ExtCC.cxx index 907876414c..0d8dc940d1 100644 --- a/src/Extrema/Extrema_ExtCC.cxx +++ b/src/Extrema/Extrema_ExtCC.cxx @@ -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()) diff --git a/src/Extrema/Extrema_ExtElC.cxx b/src/Extrema/Extrema_ExtElC.cxx index 43b1c800bd..6a34e21210 100644 --- a/src/Extrema/Extrema_ExtElC.cxx +++ b/src/Extrema/Extrema_ExtElC.cxx @@ -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; } diff --git a/src/Extrema/Extrema_ExtElC.hxx b/src/Extrema/Extrema_ExtElC.hxx index ebca165b8d..546da312c7 100644 --- a/src/Extrema/Extrema_ExtElC.hxx +++ b/src/Extrema/Extrema_ExtElC.hxx @@ -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;