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