0031047: Modeling Algorithms - BRepExtrema_DistShapeShape gives wrong result
[occt.git] / src / BRepClass / BRepClass_Intersector.cxx
CommitLineData
b311480e 1// Created on: 1992-11-19
2// Created by: Remi LEQUETTE
3// Copyright (c) 1992-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
42cf5bc1 17
7fd59977 18#include <BRep_Tool.hxx>
19#include <BRepAdaptor_Curve2d.hxx>
20#include <BRepAdaptor_Surface.hxx>
42cf5bc1 21#include <BRepClass_Edge.hxx>
22#include <BRepClass_Intersector.hxx>
7fd59977 23#include <ElCLib.hxx>
42cf5bc1 24#include <Extrema_ExtPC2d.hxx>
cb7f9239 25#include <GCE2d_MakeSegment.hxx>
42cf5bc1 26#include <Geom2d_Curve.hxx>
7fd59977 27#include <Geom2d_Line.hxx>
7fd59977 28#include <Geom2dInt_GInter.hxx>
42cf5bc1 29#include <Geom2dLProp_CLProps2d.hxx>
30#include <gp_Dir2d.hxx>
31#include <gp_Lin2d.hxx>
32#include <IntRes2d_Domain.hxx>
312cd1f5 33#include <IntRes2d_IntersectionPoint.hxx>
42cf5bc1 34#include <IntRes2d_Transition.hxx>
35#include <Precision.hxx>
36#include <TopExp.hxx>
37#include <TopoDS_Vertex.hxx>
312cd1f5 38
5a2f31c8 39static
40void GetTangentAsChord(const Handle(Geom2d_Curve)& thePCurve,
41 gp_Dir2d& theTangent,
42 const Standard_Real theParam,
43 const Standard_Real theFirst,
44 const Standard_Real theLast);
45
8f9a9b9d 46static
73cd8a8a 47void RefineTolerance(const TopoDS_Face& aF,
47cd8af2 48 const Geom2dAdaptor_Curve& aC,
73cd8a8a 49 const Standard_Real aT,
50 Standard_Real& aTolZ);
8f9a9b9d 51
cb7f9239 52static
53Standard_Boolean CheckOn(IntRes2d_IntersectionPoint& thePntInter,
54 const TopoDS_Face& theF,
55 const gp_Lin2d& theL,
56 Geom2dAdaptor_Curve& theCur,
57 Standard_Real theTolZ,
58 Standard_Real theFin,
59 Standard_Real theDeb);
60
61static
62void CheckSkip(Geom2dInt_GInter& theInter,
63 const gp_Lin2d& theL,
64 const BRepClass_Edge& theE,
65 const Handle(Geom2d_Curve)& theC2D,
66 const IntRes2d_Domain& theDL,
67 Geom2dAdaptor_Curve& theCur,
68 const Geom2dAdaptor_Curve& theCGA,
69 Standard_Real theFin,
70 Standard_Real theDeb,
71 Standard_Real theMaxTol,
72 gp_Pnt2d thePdeb,
73 gp_Pnt2d thePfin);
74
75
7fd59977 76//=======================================================================
77//function : BRepClass_Intersector
78//purpose :
79//=======================================================================
80
cb7f9239 81BRepClass_Intersector::BRepClass_Intersector() : myMaxTolerance(0.1)
7fd59977 82{
83}
84
cb7f9239 85//=======================================================================
86//function : CheckOn
87//purpose :
88//=======================================================================
89Standard_Boolean CheckOn(IntRes2d_IntersectionPoint& thePntInter,
90 const TopoDS_Face& theF,
91 const gp_Lin2d& theL,
92 Geom2dAdaptor_Curve& theCur,
93 Standard_Real theTolZ,
94 Standard_Real theFin,
95 Standard_Real theDeb)
96{
97 Extrema_ExtPC2d anExtPC2d(theL.Location(), theCur);
98 Standard_Real aMinDist = RealLast();
99 Standard_Integer aMinInd = 0;
100 if (anExtPC2d.IsDone())
101 {
102 const Standard_Integer aNbPnts = anExtPC2d.NbExt();
103 for (Standard_Integer i = 1; i <= aNbPnts; ++i)
104 {
105 Standard_Real aDist = anExtPC2d.SquareDistance(i);
106
107 if (aDist < aMinDist)
108 {
109 aMinDist = aDist;
110 aMinInd = i;
111 }
112 }
113 }
114
115 if (aMinInd != 0) {
116 aMinDist = Sqrt(aMinDist);
117 }
118 if (aMinDist <= theTolZ) {
119 gp_Pnt2d aPntExact = (anExtPC2d.Point(aMinInd)).Value();
120 Standard_Real aPar = (anExtPC2d.Point(aMinInd)).Parameter();
121 //
122 RefineTolerance(theF, theCur, aPar, theTolZ);
123 //
124 if (aMinDist <= theTolZ) {
125 IntRes2d_Transition aTrOnLin(IntRes2d_Head);
126 IntRes2d_Position aPosOnCurve = IntRes2d_Middle;
127 if (Abs(aPar - theDeb) <= Precision::Confusion()) {
128 aPosOnCurve = IntRes2d_Head;
129 }
130 else if (Abs(aPar - theFin) <= Precision::Confusion()) {
131 aPosOnCurve = IntRes2d_End;
132 }
133 //
134 IntRes2d_Transition aTrOnCurve(aPosOnCurve);
135 thePntInter = IntRes2d_IntersectionPoint(aPntExact, 0., aPar,
136 aTrOnLin, aTrOnCurve,
137 Standard_False);
138 //
139 return Standard_True;
140 }
141 }
142 return Standard_False;
143}
144
145//=======================================================================
146//function : CheckSkip
147//purpose :
148//=======================================================================
149void CheckSkip(Geom2dInt_GInter& theInter,
150 const gp_Lin2d& theL,
151 const BRepClass_Edge& theE,
152 const Handle(Geom2d_Curve)& theC2D,
153 const IntRes2d_Domain& theDL,
154 Geom2dAdaptor_Curve& theCur,
155 const Geom2dAdaptor_Curve& theCGA,
156 Standard_Real theFin,
157 Standard_Real theDeb,
158 Standard_Real theMaxTol,
159 gp_Pnt2d thePdeb,
160 gp_Pnt2d thePfin)
161{
162 if (theE.Edge().IsNull() || theE.Face().IsNull())
163 {
164 return;
165 }
166 Standard_Boolean anIsLSkip = Standard_False;
167 TopoDS_Vertex aVl; // the last vertex of current edge
168
169 Handle(Geom2d_Curve) aSkipC2D;
170
171 aVl = TopExp::LastVertex(theE.Edge(), Standard_True);
172 if (aVl.IsNull())
173 {
174 return;
175 }
176 const TopoDS_Edge anEl = theE.NextEdge(); // the next edge
177 if (!(BRep_Tool::Tolerance(aVl) > theMaxTol) || theE.NextEdge().IsNull())
178 {
179 return;
180 }
181 Standard_Real aLdeb = 0.0, aLfin = 0.0;
182 Handle(Geom2d_Curve) aLC2D; // the next curve
183
184 aLC2D = BRep_Tool::CurveOnSurface(theE.NextEdge(), theE.Face(), aLdeb, aLfin);
185 if (aLC2D.IsNull())
186 {
187 return;
188 }
189 Standard_Real anA, aB, aC; // coefficients of the straight line
190 Standard_Real aX1, anY1, aX2, anY2; // coordinates of the ends of edges
191 gp_Pnt2d aP1, aP2; // the ends of edges
192
193 theL.Coefficients(anA, aB, aC);
194
195 Standard_Real at1 = theFin;
196 if (theE.Edge().Orientation() != TopAbs_FORWARD)
197 {
198 at1 = theDeb;
199 }
200
201 Standard_Real at2 = aLdeb;
202 if (theE.NextEdge().Orientation() != TopAbs_FORWARD)
203 {
204 at2 = aLfin;
205 }
206
207 aP1 = theC2D->Value(at1);
208 aP2 = aLC2D->Value(at2);
209
210 // Check if points belong to DL domain
211 Standard_Real aPar1 = ElCLib::Parameter(theL, aP1);
212 Standard_Real aPar2 = ElCLib::Parameter(theL, aP2);
213
214 if (!(aPar1 > theDL.FirstParameter() && aPar1 < theDL.LastParameter()) ||
215 !(aPar2 > theDL.FirstParameter() && aPar2 < theDL.LastParameter()))
216 {
217 return;
218 }
219 aX1 = aP1.X(); anY1 = aP1.Y(); aX2 = aP2.X(); anY2 = aP2.Y();
220 Standard_Real aFV = anA * aX1 + aB * anY1 + aC;
221 Standard_Real aSV = anA * aX2 + aB * anY2 + aC;
222
223 // Check for getting into vertex with high tolerance
224 if ((aFV * aSV) >= 0)
225 {
226 anIsLSkip = Standard_False;
227 }
228 else
229 {
230 anIsLSkip = Standard_True;
231 GCE2d_MakeSegment aMkSeg(aP1, aP2);
232 if (!aMkSeg.IsDone())
233 {
234 return;
235 }
236 aSkipC2D = aMkSeg.Value();
237
238 if (aSkipC2D.IsNull() || !anIsLSkip)
239 {
240 return;
241 }
242 // if we got
243 theCur.Load(aSkipC2D);
244 if (theCur.Curve().IsNull())
245 {
246 return;
247 }
248 Standard_Real atoldeb = 1.e-5, atolfin = 1.e-5;
249
250 theDeb = theCur.FirstParameter();
251 theFin = theCur.LastParameter();
252 theCur.D0(theDeb, thePdeb);
253 theCur.D0(theFin, thePfin);
254
255 IntRes2d_Domain aDE(thePdeb, theDeb, atoldeb, thePfin, theFin, atolfin);
256 // temporary periodic domain
257 if (theCur.Curve()->IsPeriodic())
258 {
259 aDE.SetEquivalentParameters(theCur.FirstParameter(),
260 theCur.FirstParameter() +
261 theCur.Curve()->LastParameter() -
262 theCur.Curve()->FirstParameter());
263 }
264
265 theInter = Geom2dInt_GInter(theCGA, theDL, theCur, aDE,
266 Precision::PConfusion(),
267 Precision::PIntersection());
268 }
269}
270
7fd59977 271//=======================================================================
272//function : Perform
273//purpose :
274//=======================================================================
7fd59977 275void BRepClass_Intersector::Perform(const gp_Lin2d& L,
73cd8a8a 276 const Standard_Real P,
277 const Standard_Real Tol,
278 const BRepClass_Edge& E)
7fd59977 279{
73cd8a8a 280 Standard_Real deb = 0.0, fin = 0.0, aTolZ = Tol;
8f9a9b9d 281 Handle(Geom2d_Curve) aC2D;
282 //
8f9a9b9d 283 const TopoDS_Edge& EE = E.Edge();
284 const TopoDS_Face& F = E.Face();
73cd8a8a 285
8f9a9b9d 286 //
287 aC2D=BRep_Tool::CurveOnSurface(EE, F, deb, fin);
288 if (aC2D.IsNull()) {
7fd59977 289 done = Standard_False; // !IsDone()
8f9a9b9d 290 return;
7fd59977 291 }
8f9a9b9d 292 //
47cd8af2 293 Geom2dAdaptor_Curve C(aC2D, deb, fin);
8f9a9b9d 294 //
295 deb = C.FirstParameter();
296 fin = C.LastParameter();
297 //
298 // Case of "ON": direct check of belonging to edge
299 // taking into account the tolerance
cb7f9239 300 Standard_Boolean aStatusOn = Standard_False;
301 IntRes2d_IntersectionPoint aPntInter;
73cd8a8a 302
cb7f9239 303 aStatusOn = CheckOn(aPntInter, F, L, C, aTolZ, fin, deb);
304 if (aStatusOn)
305 {
306 Append(aPntInter);
307 done = Standard_True;
308 return;
7fd59977 309 }
cb7f9239 310
8f9a9b9d 311 //
312 gp_Pnt2d pdeb,pfin;
313 C.D0(deb,pdeb);
314 C.D0(fin,pfin);
315 Standard_Real toldeb = 1.e-5, tolfin = 1.e-5;
73cd8a8a 316
8f9a9b9d 317 IntRes2d_Domain DL;
318 //
319 if(P!=RealLast()) {
4680b22c 320 DL.SetValues(L.Location(),0.,Precision::PConfusion(),ElCLib::Value(P,L),P,Precision::PConfusion());
8f9a9b9d 321 }
322 else {
4680b22c 323 DL.SetValues(L.Location(),0.,Precision::PConfusion(),Standard_True);
8f9a9b9d 324 }
73cd8a8a 325
8f9a9b9d 326 IntRes2d_Domain DE(pdeb,deb,toldeb,pfin,fin,tolfin);
327 // temporary periodic domain
328 if (C.Curve()->IsPeriodic()) {
329 DE.SetEquivalentParameters(C.FirstParameter(),
73cd8a8a 330 C.FirstParameter() +
331 C.Curve()->LastParameter() -
332 C.Curve()->FirstParameter());
8f9a9b9d 333 }
73cd8a8a 334
8f9a9b9d 335 Handle(Geom2d_Line) GL= new Geom2d_Line(L);
336 Geom2dAdaptor_Curve CGA(GL);
337 Geom2dInt_GInter Inter(CGA,DL,C,DE,
73cd8a8a 338 Precision::PConfusion(),
339 Precision::PIntersection());
8f9a9b9d 340 //
cb7f9239 341 // The check is for hitting the intersector to
342 // a vertex with high tolerance
343 if (Inter.IsEmpty())
344 {
345 CheckSkip(Inter, L, E, aC2D, DL,
346 C, CGA, fin, deb, MaxTolerance(), pdeb, pfin);
347 }
348
349 //
8f9a9b9d 350 SetValues(Inter);
7fd59977 351}
352
353//=======================================================================
354//function : LocalGeometry
355//purpose :
356//=======================================================================
7fd59977 357void BRepClass_Intersector::LocalGeometry(const BRepClass_Edge& E,
73cd8a8a 358 const Standard_Real U,
359 gp_Dir2d& Tang,
360 gp_Dir2d& Norm,
361 Standard_Real& C) const
7fd59977 362{
5a2f31c8 363 Standard_Real fpar, lpar;
364 Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface(E.Edge(), E.Face(), fpar, lpar);
365 Geom2dLProp_CLProps2d Prop(aPCurve, U, 2, Precision::PConfusion());
366
367 C = 0.;
368 if (Prop.IsTangentDefined())
369 {
370 Prop.Tangent(Tang);
371 C = Prop.Curvature();
372 }
373 else
374 GetTangentAsChord(aPCurve, Tang, U, fpar, lpar);
375
376 if (C > Precision::PConfusion() &&
377 !Precision::IsInfinite(C))
7fd59977 378 Prop.Normal(Norm);
379 else
380 Norm.SetCoord(Tang.Y(),-Tang.X());
381}
382
8f9a9b9d 383//=======================================================================
384//function : RefineTolerance
385//purpose :
386//=======================================================================
387void RefineTolerance(const TopoDS_Face& aF,
47cd8af2 388 const Geom2dAdaptor_Curve& aC,
73cd8a8a 389 const Standard_Real aT,
390 Standard_Real& aTolZ)
8f9a9b9d 391{
392 GeomAbs_SurfaceType aTypeS;
393 //
394 BRepAdaptor_Surface aBAS(aF, Standard_False);
395 //
396 aTypeS=aBAS.GetType();
397 if (aTypeS==GeomAbs_Cylinder) {
398 Standard_Real aURes, aVRes, aTolX;
399 gp_Pnt2d aP2D;
400 gp_Vec2d aV2D;
401 //
402 aURes=aBAS.UResolution(aTolZ);
403 aVRes=aBAS.VResolution(aTolZ);
404 //
405 aC.D1(aT, aP2D, aV2D);
406 gp_Dir2d aD2D(aV2D);
407 //
408 aTolX=aURes*aD2D.Y()+aVRes*aD2D.X();
409 if (aTolX<0.) {
410 aTolX=-aTolX;
411 }
412 //
ce101cac 413 if (aTolX < Precision::Confusion()) {
414 aTolX = Precision::Confusion();
415 }
416 //
8f9a9b9d 417 if (aTolX<aTolZ) {
418 aTolZ=aTolX;
419 }
420 }
421}
7fd59977 422
5a2f31c8 423//=======================================================================
424//function : GetTangentAsChord
425//purpose :
426//=======================================================================
427void GetTangentAsChord(const Handle(Geom2d_Curve)& thePCurve,
428 gp_Dir2d& theTangent,
429 const Standard_Real theParam,
430 const Standard_Real theFirst,
431 const Standard_Real theLast)
432{
433 Standard_Real Offset = 0.1*(theLast - theFirst);
434
435 if (theLast - theParam < Precision::PConfusion()) //theParam == theLast
436 Offset *= -1;
437 else if (theParam + Offset > theLast) //<theParam> is close to <theLast>
438 Offset = 0.5*(theLast - theParam);
7fd59977 439
5a2f31c8 440 gp_Pnt2d aPnt2d = thePCurve->Value(theParam);
441 gp_Pnt2d OffsetPnt2d = thePCurve->Value(theParam + Offset);
442
443 gp_Vec2d aChord(aPnt2d, OffsetPnt2d);
444 if (Offset < 0.)
445 aChord.Reverse();
446
447 Standard_Real SqLength = aChord.SquareMagnitude();
448 if (SqLength > Precision::SquarePConfusion())
449 theTangent = aChord;
450}