8e0cf6d81cb347279f307d528da4faa9faf0a73f
[occt.git] / src / BRepClass / BRepClass_Intersector.cxx
1 // Created on: 1992-11-19
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1992-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <BRep_Tool.hxx>
19 #include <BRepAdaptor_Curve2d.hxx>
20 #include <BRepAdaptor_Surface.hxx>
21 #include <BRepClass_Edge.hxx>
22 #include <BRepClass_Intersector.hxx>
23 #include <ElCLib.hxx>
24 #include <Extrema_ExtPC2d.hxx>
25 #include <GCE2d_MakeSegment.hxx>
26 #include <Geom2d_Curve.hxx>
27 #include <Geom2d_Line.hxx>
28 #include <Geom2dInt_GInter.hxx>
29 #include <Geom2dLProp_CLProps2d.hxx>
30 #include <gp_Dir2d.hxx>
31 #include <gp_Lin2d.hxx>
32 #include <IntRes2d_Domain.hxx>
33 #include <IntRes2d_IntersectionPoint.hxx>
34 #include <IntRes2d_Transition.hxx>
35 #include <Precision.hxx>
36 #include <TopExp.hxx>
37 #include <TopoDS_Vertex.hxx>
38
39 static
40 void 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
46 static 
47 void RefineTolerance(const TopoDS_Face& aF,
48                      const Geom2dAdaptor_Curve& aC,
49                      const Standard_Real aT,
50                      Standard_Real& aTolZ);
51
52 static
53 Standard_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
61 static
62 void 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
76 //=======================================================================
77 //function : BRepClass_Intersector
78 //purpose  : 
79 //=======================================================================
80
81 BRepClass_Intersector::BRepClass_Intersector() : myMaxTolerance(0.1)
82 {
83 }
84
85 //=======================================================================
86 //function : CheckOn
87 //purpose  :
88 //=======================================================================
89 Standard_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 //=======================================================================
149 void 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  
271 //=======================================================================
272 //function : Perform
273 //purpose  : 
274 //=======================================================================
275 void  BRepClass_Intersector::Perform(const gp_Lin2d& L, 
276                                      const Standard_Real P, 
277                                      const Standard_Real Tol, 
278                                      const BRepClass_Edge& E)
279 {
280   Standard_Real deb = 0.0, fin = 0.0, aTolZ = Tol;
281   Handle(Geom2d_Curve) aC2D;
282   //
283   const TopoDS_Edge& EE = E.Edge();
284   const TopoDS_Face& F = E.Face();
285
286   //
287   aC2D=BRep_Tool::CurveOnSurface(EE, F, deb, fin);
288   if (aC2D.IsNull()) {
289     done = Standard_False; // !IsDone()
290     return;
291   }
292   //
293   Geom2dAdaptor_Curve C(aC2D, deb, fin);
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
300   Standard_Boolean aStatusOn = Standard_False;
301   IntRes2d_IntersectionPoint aPntInter;
302
303   aStatusOn = CheckOn(aPntInter, F, L, C, aTolZ, fin, deb);
304   if (aStatusOn)
305   {
306     Append(aPntInter);
307     done = Standard_True;
308     return;
309   }
310   
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;
316
317   IntRes2d_Domain DL;
318   //
319   if(P!=RealLast()) {
320     DL.SetValues(L.Location(),0.,Precision::PConfusion(),ElCLib::Value(P,L),P,Precision::PConfusion());
321   }
322   else { 
323     DL.SetValues(L.Location(),0.,Precision::PConfusion(),Standard_True);
324   }
325
326   IntRes2d_Domain DE(pdeb,deb,toldeb,pfin,fin,tolfin);
327   // temporary periodic domain
328   if (C.Curve()->IsPeriodic()) {
329     DE.SetEquivalentParameters(C.FirstParameter(),
330       C.FirstParameter() + 
331       C.Curve()->LastParameter() -
332       C.Curve()->FirstParameter());
333   }
334
335   Handle(Geom2d_Line) GL= new Geom2d_Line(L);
336   Geom2dAdaptor_Curve CGA(GL);
337   Geom2dInt_GInter Inter(CGA,DL,C,DE,
338     Precision::PConfusion(),
339     Precision::PIntersection());
340   //
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  // 
350   SetValues(Inter);
351 }
352
353 //=======================================================================
354 //function : LocalGeometry
355 //purpose  : 
356 //=======================================================================
357 void  BRepClass_Intersector::LocalGeometry(const BRepClass_Edge& E, 
358                                            const Standard_Real U, 
359                                            gp_Dir2d& Tang, 
360                                            gp_Dir2d& Norm, 
361                                            Standard_Real& C) const 
362 {
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))
378     Prop.Normal(Norm);
379   else
380     Norm.SetCoord(Tang.Y(),-Tang.X());
381 }
382
383 //=======================================================================
384 //function : RefineTolerance
385 //purpose  : 
386 //=======================================================================
387 void RefineTolerance(const TopoDS_Face& aF,
388                      const Geom2dAdaptor_Curve& aC,
389                      const Standard_Real aT,
390                      Standard_Real& aTolZ)
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     //
413     if (aTolX < Precision::Confusion()) {
414       aTolX = Precision::Confusion();
415     }
416     //
417     if (aTolX<aTolZ) {
418       aTolZ=aTolX;
419     }
420   }
421 }
422
423 //=======================================================================
424 //function : GetTangentAsChord
425 //purpose  : 
426 //=======================================================================
427 void 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);
439
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 }