From 4d60da8c58839e9a64741be513cdebb2acd9eab0 Mon Sep 17 00:00:00 2001
From: ifv <ifv@opencascade.com>
Date: Tue, 6 Dec 2022 10:12:22 +0300
Subject: [PATCH] 0033244: Modeling Algorithms - Surface-surface intersection
 produces the double curves

IntAna_QuadQuadGeo.cxx - estimation of angular tolerance is added for case cone-cone

tests/lowalgos/intss/bug33244 - new test case added
---
 src/IntAna/IntAna_QuadQuadGeo.cxx | 123 ++++++++++++++++++++++++++----
 tests/lowalgos/intss/bug33244     |  48 ++++++++++++
 2 files changed, 157 insertions(+), 14 deletions(-)
 create mode 100644 tests/lowalgos/intss/bug33244

diff --git a/src/IntAna/IntAna_QuadQuadGeo.cxx b/src/IntAna/IntAna_QuadQuadGeo.cxx
index 3ab50bcd85..c3dcf2c767 100644
--- a/src/IntAna/IntAna_QuadQuadGeo.cxx
+++ b/src/IntAna/IntAna_QuadQuadGeo.cxx
@@ -50,11 +50,21 @@
 #include <Standard_DomainError.hxx>
 #include <Standard_OutOfRange.hxx>
 #include <StdFail_NotDone.hxx>
+#include <gce_MakePln.hxx>
+#include <ProjLib.hxx>
+#include <IntAna2d_AnaIntersection.hxx>
+#include <IntAna2d_IntPoint.hxx>
+
+#ifdef DEBUGLINES
+#include <Geom2d_Line.hxx>
+#endif
 
 static
   gp_Ax2 DirToAx2(const gp_Pnt& P,const gp_Dir& D);
 static
   void RefineDir(gp_Dir& aDir);
+static
+  Standard_Real EstimDist(const gp_Cone& theCon1, const gp_Cone& theCon2);
 
 //=======================================================================
 //class :  AxeOperator
@@ -249,6 +259,72 @@ gp_Ax2 DirToAx2(const gp_Pnt& P,const gp_Dir& D)
     return(gp_Ax2(P,D,gp_Dir(gp_Vec(-y,x,0.0))));
   }
 }
+
+//=======================================================================
+//function : EstimDist
+//purpose  : returns a minimal distance from apex to any solution
+//=======================================================================
+Standard_Real EstimDist(const gp_Cone& theCon1, const gp_Cone& theCon2)
+{
+  //It is supposed that axes of cones are coplanar and 
+  //distance between them > Precision::Confusion()
+  gp_Pnt aPA1 = theCon1.Apex(), aPA2 = theCon2.Apex();
+
+  gp_Pnt aP3 = aPA1.Translated(theCon1.Position().Direction());
+
+  gce_MakePln aMkPln(aPA1, aPA2, aP3);
+  if(!aMkPln.IsDone())
+    return Precision::Infinite();
+
+  const gp_Pln& aPln = aMkPln.Value();
+
+  gp_Lin anAx1(aPA1, theCon1.Position().Direction());
+  gp_Lin2d anAx12d = ProjLib::Project(aPln, anAx1);
+  gp_Lin2d Lines1[2];
+  Standard_Real anAng1 = theCon1.SemiAngle();
+  Lines1[0] = anAx12d.Rotated(anAx12d.Location(), anAng1);
+  Lines1[1] = anAx12d.Rotated(anAx12d.Location(), -anAng1);
+  //
+  gp_Lin anAx2(aPA2, theCon2.Position().Direction());
+  gp_Lin2d anAx22d = ProjLib::Project(aPln, anAx2);
+  gp_Lin2d Lines2[2];
+  Standard_Real anAng2 = theCon2.SemiAngle();
+  Lines2[0] = anAx22d.Rotated(anAx22d.Location(), anAng2);
+  Lines2[1] = anAx22d.Rotated(anAx22d.Location(), -anAng2);
+
+#ifdef DEBUGLINES
+  Handle(Geom2d_Line) L10 = new Geom2d_Line(Lines1[0]);
+  Handle(Geom2d_Line) L11 = new Geom2d_Line(Lines1[1]);
+  Handle(Geom2d_Line) L20 = new Geom2d_Line(Lines2[0]);
+  Handle(Geom2d_Line) L21 = new Geom2d_Line(Lines2[1]);
+#endif
+
+  Standard_Real aMinDist[2] = { Precision::Infinite(), Precision::Infinite() };
+  Standard_Integer i, j, k;
+  IntAna2d_AnaIntersection anInter;
+  for (i = 0; i < 2; ++i)
+  {
+    for (j = 0; j < 2; ++j)
+    {
+      anInter.Perform(Lines1[i], Lines2[j]);
+      if (anInter.IsDone())
+      {
+        Standard_Integer aNbPoints = anInter.NbPoints();
+        for (k = 1; k <= aNbPoints; ++k)
+        {
+          const IntAna2d_IntPoint& anIntP = anInter.Point(k);
+          Standard_Real aPar1 = Abs(anIntP.ParamOnFirst());
+          aMinDist[0] = Min(aPar1, aMinDist[0]);
+          Standard_Real aPar2 = Abs(anIntP.ParamOnSecond());
+          aMinDist[1] = Min(aPar2, aMinDist[1]);
+        }
+      }
+    }
+  }
+
+  Standard_Real aDist = Max(aMinDist[0], aMinDist[1]);
+  return aDist;
+}
 //=======================================================================
 //function : IntAna_QuadQuadGeo
 //purpose  : Empty constructor
@@ -1356,30 +1432,49 @@ IntAna_QuadQuadGeo::IntAna_QuadQuadGeo(const gp_Cylinder& Cyl,
 //=======================================================================
   void IntAna_QuadQuadGeo::Perform(const gp_Cone& Con1,
                                    const gp_Cone& Con2,
-                                   const Standard_Real Tol) 
+                                   const Standard_Real Tol)
 {
-  done=Standard_True;
+  done = Standard_True;
   //
   Standard_Real tg1, tg2, aDA1A2, aTol2;
   gp_Pnt aPApex1, aPApex2;
 
   Standard_Real TOL_APEX_CONF = 1.e-10;
-  
-  //
-  tg1=Tan(Con1.SemiAngle());
-  tg2=Tan(Con2.SemiAngle());
 
-  if((tg1 * tg2) < 0.) {
+  //
+  tg1 = Tan(Con1.SemiAngle());
+  tg2 = Tan(Con2.SemiAngle());
+
+  if ((tg1 * tg2) < 0.) {
     tg2 = -tg2;
   }
   //
-  aTol2=Tol*Tol;
-  aPApex1=Con1.Apex();
-  aPApex2=Con2.Apex();
-  aDA1A2=aPApex1.SquareDistance(aPApex2);
+  aTol2 = Tol*Tol;
+  aPApex1 = Con1.Apex();
+  aPApex2 = Con2.Apex();
+  aDA1A2 = aPApex1.SquareDistance(aPApex2);
   //
-  AxeOperator A1A2(Con1.Axis(),Con2.Axis());
+  AxeOperator A1A2(Con1.Axis(), Con2.Axis());
   //
+  Standard_Real aTolAng = myEPSILON_ANGLE_CONE;
+  if ((Abs(tg1 - tg2) < Tol) && (A1A2.Parallel()))
+  {
+    Standard_Real DistA1A2 = A1A2.Distance();
+    if (DistA1A2 > 100. * Tol)
+    {
+      Standard_Real aMinSolDist = EstimDist(Con1, Con2);
+      if (aMinSolDist < Epsilon(1.))
+      {
+        aTolAng = Tol;
+      }
+      else
+      {
+        aTolAng = Max(myEPSILON_ANGLE_CONE, Tol / aMinSolDist);
+        aTolAng = Min(aTolAng, Tol);
+      }
+    }
+  }
+
   // 1
   if(A1A2.Same()) {
     //-- two circles 
@@ -1427,8 +1522,8 @@ IntAna_QuadQuadGeo::IntAna_QuadQuadGeo(const gp_Cylinder& Cyl,
     }
   } //-- fin A1A2.Same
   // 2
-  else if((Abs(tg1-tg2)<myEPSILON_ANGLE_CONE) && (A1A2.Parallel())) {
-    //-- voir AnVer12mai98
+  else if((Abs(tg1-tg2) < aTolAng ) && (A1A2.Parallel())) {
+
     Standard_Real DistA1A2=A1A2.Distance();
     gp_Dir DA1=Con1.Position().Direction();
     gp_Vec O1O2(Con1.Apex(),Con2.Apex());
diff --git a/tests/lowalgos/intss/bug33244 b/tests/lowalgos/intss/bug33244
new file mode 100644
index 0000000000..8a571926a0
--- /dev/null
+++ b/tests/lowalgos/intss/bug33244
@@ -0,0 +1,48 @@
+
+puts "============"
+puts "0033244: Modeling Algorithms - Surface-surface intersection produces the double curves"
+puts "============"
+puts ""
+
+
+set PI180 0.017453292519943295
+
+set x -1.11630646267172
+set y -4.54487349779333
+set z 13.2493435203532
+set dx -1.05794851588922e-07
+set dy -1.39278337794573e-08
+set dz  0.999999999999994
+set ux 0.999999999999994
+set uy 5.91645678915759e-31
+set uz 1.05794851588922e-07
+set semi-angle [expr 0.785398163360967 / ${PI180}]
+set radius 0.560000000061149
+
+cone s1 ${x} ${y} ${z} ${dx} ${dy} ${dz} ${semi-angle} ${radius}
+
+set x -2.08647872350287e-07
+set y -5.78732475509323
+set z 13.2493436211
+set dx -1.05794850062242e-07
+set dy -1.39278350756825e-08
+set dz  0.999999999999994
+set ux 0.999999999999995
+set uy 0
+set uz 1.05794850062242e-07
+set semi-angle [expr 0.785398163396248 / ${PI180}]
+set radius 0.785398163396248
+
+cone s2 ${x} ${y} ${z} ${dx} ${dy} ${dz} ${semi-angle} ${radius}
+
+intersect ii s1 s2
+if { ![isdraw ii_1] || ![isdraw ii_2] || [isdraw ii_3] } {
+   puts "ERROR. Intersection is wrong"
+}
+
+intersect jj s2 s1
+if { ![isdraw jj_1] || ![isdraw jj_2] || [isdraw jj_3] } {
+   puts "ERROR. Intersection is wrong"
+}
+
+