0030090: Modeling Algorithms - BRepLib::FindValidRange does not find valid range...
[occt.git] / src / BRepLib / BRepLib_1.cxx
1 // Created on: 2017-03-24
2 // Created by: Mikhail Sazonov
3 // Copyright (c) 2017 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <BRepLib.hxx>
17 #include <BRep_Builder.hxx>
18 #include <BRep_Tool.hxx>
19 #include <BRepAdaptor_Curve.hxx>
20 #include <Geom_OffsetCurve.hxx>
21 #include <Precision.hxx>
22 #include <TopExp.hxx>
23 #include <TopoDS_Vertex.hxx>
24
25 //=======================================================================
26 // function: findNearestValidPoint
27 // purpose : Starting from the appointed end of the curve, find the nearest
28 //           point on the curve that is an intersection with the sphere with
29 //           center theVertPnt and radius theTol.
30 //=======================================================================
31 static Standard_Boolean findNearestValidPoint(
32   const Adaptor3d_Curve& theCurve,
33   const Standard_Real theFirst, const Standard_Real theLast,
34   const Standard_Boolean isFirst,
35   const gp_Pnt& theVertPnt,
36   const Standard_Real theTol,
37   const Standard_Real theEps,
38   Standard_Real& thePar)
39 {
40   // 1. Check that the needed end is inside the sphere
41
42   Standard_Real aStartU = theFirst;
43   Standard_Real anEndU = theLast;
44   if (!isFirst)
45     std::swap(aStartU, anEndU);
46   gp_Pnt aP = theCurve.Value(aStartU);
47   const Standard_Real aSqTol = theTol * theTol;
48   if (aP.SquareDistance(theVertPnt) > aSqTol)
49     // the vertex does not cover the corresponding to this vertex end of the curve
50     return Standard_False;
51
52   // 2. Find a nearest point that is outside
53
54   // stepping along the curve by theTol till go out
55   //
56   // the general step is computed using general curve resolution
57   Standard_Real aStep = theCurve.Resolution(theTol) * 1.01;
58   // aD1Mag is a threshold to consider local derivative magnitude too small
59   // and to accelerate going out of sphere
60   // (inverse of resolution is the maximal derivative);
61   // this is actual for bezier and b-spline types only
62   Standard_Real aD1Mag = 0.;
63   GeomAbs_CurveType aType = theCurve.GetType();
64   if (aType == GeomAbs_OffsetCurve)
65   {
66     Handle(Geom_OffsetCurve) anOffsetCurve = theCurve.OffsetCurve();
67     Handle(Geom_Curve) aBaseCurve = anOffsetCurve->BasisCurve();
68     aType = GeomAdaptor_Curve(aBaseCurve).GetType();
69   }
70   if (aType == GeomAbs_BezierCurve || aType == GeomAbs_BSplineCurve)
71   {
72     aD1Mag = 1. / theCurve.Resolution(1.) * 0.01;
73     aD1Mag *= aD1Mag;
74   }
75   if (!isFirst)
76     aStep = -aStep;
77   Standard_Boolean isOut = Standard_False;
78   Standard_Real anUIn = aStartU;
79   Standard_Real anUOut = anUIn;
80   while (!isOut)
81   {
82     anUIn = anUOut;
83     anUOut += aStep;
84     if ((isFirst && anUOut > anEndU) || (!isFirst && anUOut < anEndU))
85     {
86       // step is too big and we go out of bounds,
87       // check if the opposite bound is outside
88       aP = theCurve.Value(anEndU);
89       isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
90       if (!isOut)
91         // all range is inside sphere
92         return Standard_False;
93       anUOut = anEndU;
94       break;
95     }
96     if (aD1Mag > 0.)
97     {
98       Standard_Real aStepLocal = aStep;
99       for (;;)
100       {
101         // cycle to go out of local singularity
102         gp_Vec aD1;
103         theCurve.D1(anUOut, aP, aD1);
104         isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
105         if (!isOut && aD1.SquareMagnitude() < aD1Mag)
106         {
107           aStepLocal *= 2.;
108           anUOut += aStepLocal;
109           if ((isFirst && anUOut < anEndU) || (!isFirst && anUOut > anEndU))
110             // still in range
111             continue;
112           // went out of range, so check if the end point has out state
113           anUOut = anEndU;
114           aP = theCurve.Value(anUOut);
115           isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
116           if (!isOut)
117             // all range is inside sphere
118             return Standard_False;
119         }
120         break;
121       }
122     }
123     else
124     {
125       aP = theCurve.Value(anUOut);
126     }
127     if (!isOut)
128       isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
129   }
130
131   // 3. Precise solution with binary search
132
133   Standard_Real aDelta = Abs(anUOut - anUIn);
134   while (aDelta > theEps)
135   {
136     Standard_Real aMidU = (anUIn + anUOut) * 0.5;
137     aP = theCurve.Value(aMidU);
138     isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
139     if (isOut)
140       anUOut = aMidU;
141     else
142       anUIn = aMidU;
143     aDelta = Abs(anUOut - anUIn);
144   }
145   thePar = (anUIn + anUOut) * 0.5;
146   return Standard_True;
147 }
148
149 //=======================================================================
150 // function: FindValidRange
151 // purpose : 
152 //=======================================================================
153 Standard_Boolean BRepLib::FindValidRange
154   (const Adaptor3d_Curve& theCurve, const Standard_Real theTolE,
155    const Standard_Real theParV1, const gp_Pnt& thePntV1, const Standard_Real theTolV1,
156    const Standard_Real theParV2, const gp_Pnt& thePntV2, const Standard_Real theTolV2,
157    Standard_Real& theFirst, Standard_Real& theLast)
158 {
159   if (theParV2 - theParV1 < Precision::PConfusion())
160     return Standard_False;
161   
162   Standard_Real anEps = Max(theCurve.Resolution(theTolE) * 0.1, Precision::PConfusion());
163
164   if (Precision::IsInfinite(theParV1))
165     theFirst = theParV1;
166   else
167   {
168     if (!findNearestValidPoint(theCurve, theParV1, theParV2, Standard_True,
169                                thePntV1, theTolV1, anEps, theFirst))
170       return Standard_False;
171     if (theParV2 - theFirst < anEps)
172       return Standard_False;
173   }
174
175   if (Precision::IsInfinite(theParV2))
176     theLast = theParV2;
177   else
178   {
179     if (!findNearestValidPoint(theCurve, theParV1, theParV2, Standard_False,
180                                thePntV2, theTolV2, anEps, theLast))
181       return Standard_False;
182     if (theLast - theParV1 < anEps)
183       return Standard_False;
184   }
185
186   // check found parameters
187   if (theFirst > theLast)
188   {
189     // overlapping, not valid range
190     return Standard_False;
191   }
192
193   return Standard_True;
194 }
195
196 //=======================================================================
197 // function: FindValidRange
198 // purpose : 
199 //=======================================================================
200 Standard_Boolean BRepLib::FindValidRange
201   (const TopoDS_Edge& theEdge, Standard_Real& theFirst, Standard_Real& theLast)
202 {
203   TopLoc_Location aLoc;
204   Standard_Real f, l;
205   if (BRep_Tool::Curve(theEdge, aLoc, f, l).IsNull())
206     return Standard_False;
207   BRepAdaptor_Curve anAC(theEdge);
208   Standard_Real aParV[2] = { anAC.FirstParameter(), anAC.LastParameter() };
209   if (aParV[1] - aParV[0] < Precision::PConfusion())
210     return Standard_False;
211
212   // get vertices
213   TopoDS_Vertex aV[2];
214   TopExp::Vertices(theEdge, aV[0], aV[1]);
215
216   Standard_Real aTolE = BRep_Tool::Tolerance(theEdge);
217   // to have correspondence with intersection precision
218   // the tolerances of vertices are increased on Precision::Confusion()
219   Standard_Real aTolV[2] = { Precision::Confusion(), Precision::Confusion() };
220   gp_Pnt aPntV[2];
221   for (Standard_Integer i = 0; i < 2; i++)
222   {
223     if (!aV[i].IsNull())
224     {
225       aTolV[i] += BRep_Tool::Tolerance(aV[i]);
226       aPntV[i] = BRep_Tool::Pnt(aV[i]);
227     }
228     else if (!Precision::IsInfinite(aParV[i]))
229     {
230       aTolV[i] += aTolE;
231       aPntV[i] = anAC.Value(aParV[i]);
232     }
233   }
234   return FindValidRange(anAC, aTolE, 
235                         aParV[0], aPntV[0], aTolV[0],
236                         aParV[1], aPntV[1], aTolV[1],
237                         theFirst, theLast);
238 }
239
240 //=======================================================================
241 //function : BuildPCurveForEdgeOnPlane
242 //purpose  : 
243 //=======================================================================
244 void BRepLib::BuildPCurveForEdgeOnPlane(const TopoDS_Edge& aE,
245                                         const TopoDS_Face& aF)
246 {
247   Standard_Boolean bToUpdate;
248   Standard_Real aTolE;
249   Handle(Geom2d_Curve) aC2D;
250   BRep_Builder aBB;
251   //
252   BuildPCurveForEdgeOnPlane(aE, aF, aC2D, bToUpdate);
253   if (bToUpdate) {
254     aTolE = BRep_Tool::Tolerance(aE);
255     aBB.UpdateEdge(aE, aC2D, aF, aTolE);
256   }
257 }
258
259 //=======================================================================
260 //function : BuildPCurveForEdgeOnPlane
261 //purpose  : 
262 //=======================================================================
263 void BRepLib::BuildPCurveForEdgeOnPlane(const TopoDS_Edge& aE,
264                                         const TopoDS_Face& aF,
265                                         Handle(Geom2d_Curve)& aC2D,
266                                         Standard_Boolean& bToUpdate)
267 {
268   Standard_Real aT1, aT2;
269   Standard_Boolean isStored;
270   aC2D = BRep_Tool::CurveOnSurface(aE, aF, aT1, aT2, &isStored);
271   bToUpdate = !isStored && !aC2D.IsNull();
272 }