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 //=======================================================================
findNearestValidPoint(const Adaptor3d_Curve & theCurve,const Standard_Real theFirst,const Standard_Real theLast,const Standard_Boolean isFirst,const gp_Pnt & theVertPnt,const Standard_Real theTol,const Standard_Real theEps,Standard_Real & thePar)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   if (aStep < theEps)
59     aStep = theEps;
60   // aD1Mag is a threshold to consider local derivative magnitude too small
61   // and to accelerate going out of sphere
62   // (inverse of resolution is the maximal derivative);
63   // this is actual for bezier and b-spline types only
64   Standard_Real aD1Mag = 0.;
65   GeomAbs_CurveType aType = theCurve.GetType();
66   if (aType == GeomAbs_OffsetCurve)
67   {
68     Handle(Geom_OffsetCurve) anOffsetCurve = theCurve.OffsetCurve();
69     Handle(Geom_Curve) aBaseCurve = anOffsetCurve->BasisCurve();
70     aType = GeomAdaptor_Curve(aBaseCurve).GetType();
71   }
72   if (aType == GeomAbs_BezierCurve || aType == GeomAbs_BSplineCurve)
73   {
74     aD1Mag = 1. / theCurve.Resolution(1.) * 0.01;
75     aD1Mag *= aD1Mag;
76   }
77   if (!isFirst)
78     aStep = -aStep;
79   Standard_Boolean isOut = Standard_False;
80   Standard_Real anUIn = aStartU;
81   Standard_Real anUOut = anUIn;
82   while (!isOut)
83   {
84     anUIn = anUOut;
85     anUOut += aStep;
86     if ((isFirst && anUOut > anEndU) || (!isFirst && anUOut < anEndU))
87     {
88       // step is too big and we go out of bounds,
89       // check if the opposite bound is outside
90       aP = theCurve.Value(anEndU);
91       isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
92       if (!isOut)
93         // all range is inside sphere
94         return Standard_False;
95       anUOut = anEndU;
96       break;
97     }
98     if (aD1Mag > 0.)
99     {
100       Standard_Real aStepLocal = aStep;
101       for (;;)
102       {
103         // cycle to go out of local singularity
104         gp_Vec aD1;
105         theCurve.D1(anUOut, aP, aD1);
106         isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
107         if (!isOut && aD1.SquareMagnitude() < aD1Mag)
108         {
109           aStepLocal *= 2.;
110           anUOut += aStepLocal;
111           if ((isFirst && anUOut < anEndU) || (!isFirst && anUOut > anEndU))
112             // still in range
113             continue;
114           // went out of range, so check if the end point has out state
115           anUOut = anEndU;
116           aP = theCurve.Value(anUOut);
117           isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
118           if (!isOut)
119             // all range is inside sphere
120             return Standard_False;
121         }
122         break;
123       }
124     }
125     else
126     {
127       aP = theCurve.Value(anUOut);
128     }
129     if (!isOut)
130       isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
131   }
132 
133   // 3. Precise solution with binary search
134 
135   Standard_Real aDelta = Abs(anUOut - anUIn);
136   while (aDelta > theEps)
137   {
138     Standard_Real aMidU = (anUIn + anUOut) * 0.5;
139     aP = theCurve.Value(aMidU);
140     isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
141     if (isOut)
142       anUOut = aMidU;
143     else
144       anUIn = aMidU;
145     aDelta = Abs(anUOut - anUIn);
146   }
147   thePar = (anUIn + anUOut) * 0.5;
148   return Standard_True;
149 }
150 
151 //=======================================================================
152 // function: FindValidRange
153 // purpose :
154 //=======================================================================
FindValidRange(const Adaptor3d_Curve & theCurve,const Standard_Real theTolE,const Standard_Real theParV1,const gp_Pnt & thePntV1,const Standard_Real theTolV1,const Standard_Real theParV2,const gp_Pnt & thePntV2,const Standard_Real theTolV2,Standard_Real & theFirst,Standard_Real & theLast)155 Standard_Boolean BRepLib::FindValidRange
156   (const Adaptor3d_Curve& theCurve, const Standard_Real theTolE,
157    const Standard_Real theParV1, const gp_Pnt& thePntV1, const Standard_Real theTolV1,
158    const Standard_Real theParV2, const gp_Pnt& thePntV2, const Standard_Real theTolV2,
159    Standard_Real& theFirst, Standard_Real& theLast)
160 {
161   if (theParV2 - theParV1 < Precision::PConfusion())
162     return Standard_False;
163 
164   Standard_Boolean isInfParV1 = Precision::IsInfinite (theParV1),
165                    isInfParV2 = Precision::IsInfinite (theParV2);
166 
167   Standard_Real aMaxPar = 0.0;
168   if (!isInfParV1)
169     aMaxPar = Abs (theParV1);
170   if (!isInfParV2)
171     aMaxPar = Max (aMaxPar, Abs (theParV2));
172 
173   Standard_Real anEps = Max (Max (theCurve.Resolution (theTolE) * 0.1, Epsilon (aMaxPar)),
174                              Precision::PConfusion());
175 
176   if (isInfParV1)
177     theFirst = theParV1;
178   else
179   {
180     if (!findNearestValidPoint(theCurve, theParV1, theParV2, Standard_True,
181                                thePntV1, theTolV1, anEps, theFirst))
182       return Standard_False;
183     if (theParV2 - theFirst < anEps)
184       return Standard_False;
185   }
186 
187   if (isInfParV2)
188     theLast = theParV2;
189   else
190   {
191     if (!findNearestValidPoint(theCurve, theParV1, theParV2, Standard_False,
192                                thePntV2, theTolV2, anEps, theLast))
193       return Standard_False;
194     if (theLast - theParV1 < anEps)
195       return Standard_False;
196   }
197 
198   // check found parameters
199   if (theFirst > theLast)
200   {
201     // overlapping, not valid range
202     return Standard_False;
203   }
204 
205   return Standard_True;
206 }
207 
208 //=======================================================================
209 // function: FindValidRange
210 // purpose :
211 //=======================================================================
FindValidRange(const TopoDS_Edge & theEdge,Standard_Real & theFirst,Standard_Real & theLast)212 Standard_Boolean BRepLib::FindValidRange
213   (const TopoDS_Edge& theEdge, Standard_Real& theFirst, Standard_Real& theLast)
214 {
215   TopLoc_Location aLoc;
216   Standard_Real f, l;
217   if (BRep_Tool::Curve(theEdge, aLoc, f, l).IsNull())
218     return Standard_False;
219   BRepAdaptor_Curve anAC(theEdge);
220   Standard_Real aParV[2] = { anAC.FirstParameter(), anAC.LastParameter() };
221   if (aParV[1] - aParV[0] < Precision::PConfusion())
222     return Standard_False;
223 
224   // get vertices
225   TopoDS_Vertex aV[2];
226   TopExp::Vertices(theEdge, aV[0], aV[1]);
227 
228   Standard_Real aTolE = BRep_Tool::Tolerance(theEdge);
229   // to have correspondence with intersection precision
230   // the tolerances of vertices are increased on Precision::Confusion()
231   Standard_Real aTolV[2] = { Precision::Confusion(), Precision::Confusion() };
232   gp_Pnt aPntV[2];
233   for (Standard_Integer i = 0; i < 2; i++)
234   {
235     if (!aV[i].IsNull())
236     {
237       aTolV[i] += BRep_Tool::Tolerance(aV[i]);
238       aPntV[i] = BRep_Tool::Pnt(aV[i]);
239     }
240     else if (!Precision::IsInfinite(aParV[i]))
241     {
242       aTolV[i] += aTolE;
243       aPntV[i] = anAC.Value(aParV[i]);
244     }
245   }
246   return FindValidRange(anAC, aTolE,
247                         aParV[0], aPntV[0], aTolV[0],
248                         aParV[1], aPntV[1], aTolV[1],
249                         theFirst, theLast);
250 }
251 
252 //=======================================================================
253 //function : BuildPCurveForEdgeOnPlane
254 //purpose  :
255 //=======================================================================
BuildPCurveForEdgeOnPlane(const TopoDS_Edge & aE,const TopoDS_Face & aF)256 void BRepLib::BuildPCurveForEdgeOnPlane(const TopoDS_Edge& aE,
257                                         const TopoDS_Face& aF)
258 {
259   Standard_Boolean bToUpdate;
260   Standard_Real aTolE;
261   Handle(Geom2d_Curve) aC2D;
262   BRep_Builder aBB;
263   //
264   BuildPCurveForEdgeOnPlane(aE, aF, aC2D, bToUpdate);
265   if (bToUpdate) {
266     aTolE = BRep_Tool::Tolerance(aE);
267     aBB.UpdateEdge(aE, aC2D, aF, aTolE);
268   }
269 }
270 
271 //=======================================================================
272 //function : BuildPCurveForEdgeOnPlane
273 //purpose  :
274 //=======================================================================
BuildPCurveForEdgeOnPlane(const TopoDS_Edge & aE,const TopoDS_Face & aF,Handle (Geom2d_Curve)& aC2D,Standard_Boolean & bToUpdate)275 void BRepLib::BuildPCurveForEdgeOnPlane(const TopoDS_Edge& aE,
276                                         const TopoDS_Face& aF,
277                                         Handle(Geom2d_Curve)& aC2D,
278                                         Standard_Boolean& bToUpdate)
279 {
280   Standard_Real aT1, aT2;
281   Standard_Boolean isStored;
282   aC2D = BRep_Tool::CurveOnSurface(aE, aF, aT1, aT2, &isStored);
283   bToUpdate = !isStored && !aC2D.IsNull();
284 }
285