1 // Copyright (c) 2021 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13 
14 #include <BRepLib_ValidateEdge.hxx>
15 
16 #include <Adaptor3d_Curve.hxx>
17 #include <Adaptor3d_CurveOnSurface.hxx>
18 #include <BRepCheck.hxx>
19 #include <Extrema_LocateExtPC.hxx>
20 
21 //=============================================================================
22 //function : BRepLib_ValidateEdge
23 //purpose  : Constructor
24 //=============================================================================
BRepLib_ValidateEdge(Handle (Adaptor3d_Curve)theReferenceCurve,Handle (Adaptor3d_CurveOnSurface)theOtherCurve,Standard_Boolean theSameParameter)25 BRepLib_ValidateEdge::BRepLib_ValidateEdge(Handle(Adaptor3d_Curve) theReferenceCurve,
26                                            Handle(Adaptor3d_CurveOnSurface) theOtherCurve,
27                                            Standard_Boolean theSameParameter):
28   myReferenceCurve(theReferenceCurve),
29   myOtherCurve(theOtherCurve),
30   mySameParameter(theSameParameter),
31   myControlPointsNumber(22),
32   myToleranceForChecking(0),
33   myCalculatedDistance(0),
34   myExitIfToleranceExceeded(Standard_False),
35   myIsDone(Standard_False)
36 { }
37 
38 //=============================================================================
39 //function : CheckTolerance
40 //purpose  :
41 //=============================================================================
CheckTolerance(Standard_Real theToleranceToCheck)42 Standard_Boolean BRepLib_ValidateEdge::CheckTolerance(Standard_Real theToleranceToCheck)
43 {
44   return correctTolerance(theToleranceToCheck) > myCalculatedDistance;
45 }
46 
47 //=============================================================================
48 //function : GetMaxDistance
49 //purpose  :
50 //=============================================================================
GetMaxDistance()51 Standard_Real BRepLib_ValidateEdge::GetMaxDistance()
52 {
53   Standard_Real aCorrectedTolerance = myCalculatedDistance * 1.00001;
54   return aCorrectedTolerance;
55 }
56 
57 //=============================================================================
58 //function : UpdateTolerance
59 //purpose  :
60 //=============================================================================
UpdateTolerance(Standard_Real & theToleranceToUpdate)61 void BRepLib_ValidateEdge::UpdateTolerance(Standard_Real& theToleranceToUpdate)
62 {
63   Standard_Real aCorrectedTolerance = myCalculatedDistance * 1.00001;
64   if (aCorrectedTolerance > theToleranceToUpdate)
65   {
66     theToleranceToUpdate = aCorrectedTolerance;
67   }
68 }
69 
70 //=============================================================================
71 //function : correctTolerance
72 //purpose  :
73 //=============================================================================
correctTolerance(Standard_Real theTolerance)74 Standard_Real BRepLib_ValidateEdge::correctTolerance(Standard_Real theTolerance)
75 {
76   const Handle(Adaptor3d_Surface)& aSurface = myOtherCurve->GetSurface();
77   Standard_Real aCurvePrecision = BRepCheck::PrecCurve(*myReferenceCurve);
78   Standard_Real aSurfacePrecision = BRepCheck::PrecSurface(aSurface);
79   Standard_Real aToleranceDelta = (aCurvePrecision > aSurfacePrecision) ? aCurvePrecision : aSurfacePrecision;
80   Standard_Real aCorrectedTolerance = theTolerance + aToleranceDelta;
81   return aCorrectedTolerance;
82 }
83 
84 //=============================================================================
85 //function : SetExitIfToleranceExceeded
86 //purpose  :
87 //=============================================================================
SetExitIfToleranceExceeded(Standard_Real theToleranceForChecking)88 void BRepLib_ValidateEdge::SetExitIfToleranceExceeded(Standard_Real theToleranceForChecking)
89 {
90   myExitIfToleranceExceeded = Standard_True;
91   myToleranceForChecking = correctTolerance(theToleranceForChecking);
92 }
93 
94 //=============================================================================
95 //function : Process
96 //purpose  :
97 //=============================================================================
Process()98 void BRepLib_ValidateEdge::Process()
99 {
100   myIsDone = Standard_True;
101   Standard_Real aSquareToleranceForChecking = myToleranceForChecking * myToleranceForChecking;
102   Standard_Real aReferenceFirstParam = myReferenceCurve->FirstParameter();
103   Standard_Real aReferenceLastParam = myReferenceCurve->LastParameter();
104   Standard_Real anOtherFirstParam = myOtherCurve->FirstParameter();
105   Standard_Real anOtherLastParam = myOtherCurve->LastParameter();
106   Standard_Real aMaxSquareDistance = 0.;
107 
108   Standard_Integer aControlPointsNumber = (myControlPointsNumber < 1) ? 1 : myControlPointsNumber;
109   Standard_Boolean anIsProjection = (!mySameParameter ||
110     Abs(anOtherFirstParam - aReferenceFirstParam) > Precision::PConfusion() ||
111     Abs(anOtherLastParam - aReferenceLastParam) > Precision::PConfusion());
112 
113   if (!anIsProjection)
114   {
115     for (Standard_Integer i = 0; i <= aControlPointsNumber; ++i)
116     {
117       Standard_Real aControlPointParam =
118         ((aControlPointsNumber - i) * aReferenceFirstParam + i * aReferenceLastParam) / aControlPointsNumber;
119       gp_Pnt aReferencePoint = myReferenceCurve->Value(aControlPointParam);
120       gp_Pnt anOtherPoint = myOtherCurve->Value(aControlPointParam);
121       Standard_Real aSquareDistance = aReferencePoint.SquareDistance(anOtherPoint);
122       if (aSquareDistance > aMaxSquareDistance)
123       {
124           aMaxSquareDistance = aSquareDistance;
125       }
126       // Stop process for best performance
127       if (myExitIfToleranceExceeded && aMaxSquareDistance > aSquareToleranceForChecking)
128       {
129         myCalculatedDistance = Sqrt(aMaxSquareDistance);
130         return;
131       }
132     }
133   }
134   else
135   {
136     gp_Pnt aReferencePoint = myReferenceCurve->Value(aReferenceFirstParam);
137     gp_Pnt anOtherPoint = myOtherCurve->Value(anOtherFirstParam);
138     Standard_Real aSquareDistance = aReferencePoint.SquareDistance(anOtherPoint);
139     if (aSquareDistance > aMaxSquareDistance)
140     {
141         aMaxSquareDistance = aSquareDistance;
142     }
143     if (myExitIfToleranceExceeded && aMaxSquareDistance > aSquareToleranceForChecking)
144     {
145       myCalculatedDistance = Sqrt(aMaxSquareDistance);
146       return;
147     }
148 
149     aReferencePoint = myReferenceCurve->Value(aReferenceLastParam);
150     anOtherPoint = myOtherCurve->Value(anOtherLastParam);
151     aSquareDistance = aReferencePoint.SquareDistance(anOtherPoint);
152     if (aSquareDistance > aMaxSquareDistance)
153     {
154       aMaxSquareDistance = aSquareDistance;
155     }
156     if (myExitIfToleranceExceeded && aMaxSquareDistance > aSquareToleranceForChecking)
157     {
158       myCalculatedDistance = Sqrt(aMaxSquareDistance);
159       return;
160     }
161 
162     Extrema_LocateExtPC aReferenceExtrema, anOtherExtrema;
163     aReferenceExtrema.Initialize(*myReferenceCurve, aReferenceFirstParam, aReferenceLastParam, myReferenceCurve->Resolution(Precision::Confusion()));
164     anOtherExtrema.Initialize(*myOtherCurve, anOtherFirstParam, anOtherLastParam, myOtherCurve->Resolution(Precision::Confusion()));
165     for (Standard_Integer i = 1; i < aControlPointsNumber; i++)
166     {
167       Standard_Real aReferenceParam = ((aControlPointsNumber - i) * aReferenceFirstParam + i * aReferenceLastParam) / aControlPointsNumber;
168       gp_Pnt aReferenceExtremaPoint = myReferenceCurve->Value(aReferenceParam);
169       Standard_Real anOtherParam = ((aControlPointsNumber - i) * anOtherFirstParam + i * anOtherLastParam) / aControlPointsNumber;
170       gp_Pnt anOtherExtremaPoint = myOtherCurve->Value(anOtherParam);
171 
172       aReferenceExtrema.Perform(anOtherExtremaPoint, aReferenceParam);
173       if (aReferenceExtrema.IsDone())
174       {
175         if (aReferenceExtrema.SquareDistance() > aMaxSquareDistance)
176         {
177           aMaxSquareDistance = aReferenceExtrema.SquareDistance();
178         }
179         if (myExitIfToleranceExceeded && aMaxSquareDistance > aSquareToleranceForChecking)
180         {
181           myCalculatedDistance = Sqrt(aMaxSquareDistance);
182           return;
183         }
184       }
185       else
186       {
187         myIsDone = Standard_False;
188         // Stop process for best performance
189         return;
190       }
191 
192       anOtherExtrema.Perform(aReferenceExtremaPoint, anOtherParam);
193       if (anOtherExtrema.IsDone())
194       {
195         if (anOtherExtrema.SquareDistance() > aMaxSquareDistance)
196         {
197           aMaxSquareDistance = anOtherExtrema.SquareDistance();
198         }
199         if (myExitIfToleranceExceeded && aMaxSquareDistance > aSquareToleranceForChecking)
200         {
201           myCalculatedDistance = Sqrt(aMaxSquareDistance);
202           return;
203         }
204       }
205       else
206       {
207         myIsDone = Standard_False;
208         // Stop process for best performance
209         return;
210       }
211     }
212   }
213   myCalculatedDistance = Sqrt(aMaxSquareDistance);
214 }
215