0031492: BRepBuilderAPI_MakeFace crashes on a wire
[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 <Geom2d_Curve.hxx>
26 #include <Geom2d_Line.hxx>
27 #include <Geom2dInt_GInter.hxx>
28 #include <Geom2dLProp_CLProps2d.hxx>
29 #include <gp_Dir2d.hxx>
30 #include <gp_Lin2d.hxx>
31 #include <IntRes2d_Domain.hxx>
32 #include <IntRes2d_IntersectionPoint.hxx>
33 #include <IntRes2d_Transition.hxx>
34 #include <Precision.hxx>
35 #include <TopExp.hxx>
36 #include <TopoDS_Vertex.hxx>
37
38 static
39 void GetTangentAsChord(const Handle(Geom2d_Curve)& thePCurve,
40                        gp_Dir2d&                   theTangent,
41                        const Standard_Real         theParam,
42                        const Standard_Real         theFirst,
43                        const Standard_Real         theLast);
44
45 static 
46 void RefineTolerance(const TopoDS_Face& aF,
47                      const Geom2dAdaptor_Curve& aC,
48                      const Standard_Real aT,
49                      Standard_Real& aTolZ);
50
51 //=======================================================================
52 //function : BRepClass_Intersector
53 //purpose  : 
54 //=======================================================================
55
56 BRepClass_Intersector::BRepClass_Intersector()
57 {
58 }
59
60 //=======================================================================
61 //function : Perform
62 //purpose  : 
63 //=======================================================================
64 void  BRepClass_Intersector::Perform(const gp_Lin2d& L, 
65                                      const Standard_Real P, 
66                                      const Standard_Real Tol, 
67                                      const BRepClass_Edge& E)
68 {
69   Standard_Real deb = 0.0, fin = 0.0, aTolZ = Tol;
70   Handle(Geom2d_Curve) aC2D;
71   //
72   const TopoDS_Edge& EE = E.Edge();
73   const TopoDS_Face& F = E.Face();
74
75   //
76   aC2D=BRep_Tool::CurveOnSurface(EE, F, deb, fin);
77   if (aC2D.IsNull()) {
78     done = Standard_False; // !IsDone()
79     return;
80   }
81   //
82   Geom2dAdaptor_Curve C(aC2D, deb, fin);
83   //
84   deb = C.FirstParameter();
85   fin = C.LastParameter();
86   //
87   // Case of "ON": direct check of belonging to edge
88   // taking into account the tolerance
89   Extrema_ExtPC2d anExtPC2d(L.Location(), C);
90   Standard_Real MinDist = RealLast(), aDist;
91   Standard_Integer MinInd = 0, i;
92   if (anExtPC2d.IsDone())
93   {
94     const Standard_Integer aNbPnts = anExtPC2d.NbExt();
95     for (i = 1; i <= aNbPnts; ++i)
96     {
97       aDist = anExtPC2d.SquareDistance(i);
98
99       if (aDist < MinDist)
100       {
101         MinDist = aDist;
102         MinInd = i;
103       }
104     }
105   }
106
107   if (MinInd) {
108     MinDist = sqrt(MinDist);
109   }
110   if (MinDist <= aTolZ) {
111     gp_Pnt2d pnt_exact = (anExtPC2d.Point(MinInd)).Value();
112     Standard_Real par = (anExtPC2d.Point(MinInd)).Parameter();
113     //
114     RefineTolerance(F, C, par, aTolZ);
115     //
116     if (MinDist <= aTolZ) {
117       IntRes2d_Transition tr_on_lin(IntRes2d_Head);
118       IntRes2d_Position pos_on_curve = IntRes2d_Middle;
119       if (Abs(par - deb) <= Precision::Confusion()) {
120         pos_on_curve = IntRes2d_Head;
121       }
122       else if (Abs(par - fin) <= Precision::Confusion()) {
123         pos_on_curve = IntRes2d_End;
124       }
125       //
126       IntRes2d_Transition tr_on_curve(pos_on_curve);
127       IntRes2d_IntersectionPoint pnt_inter(pnt_exact, 0., par,
128         tr_on_lin, tr_on_curve, 
129         Standard_False);
130       //
131       Append(pnt_inter);
132       done = Standard_True;
133       return;
134     }
135   }
136   //  
137   gp_Pnt2d pdeb,pfin;
138   C.D0(deb,pdeb);
139   C.D0(fin,pfin);
140   Standard_Real toldeb = 1.e-5, tolfin = 1.e-5;
141
142   IntRes2d_Domain DL;
143   //
144   if(P!=RealLast()) {
145     DL.SetValues(L.Location(),0.,Precision::PConfusion(),ElCLib::Value(P,L),P,Precision::PConfusion());
146   }
147   else { 
148     DL.SetValues(L.Location(),0.,Precision::PConfusion(),Standard_True);
149   }
150
151   IntRes2d_Domain DE(pdeb,deb,toldeb,pfin,fin,tolfin);
152   // temporary periodic domain
153   if (C.Curve()->IsPeriodic()) {
154     DE.SetEquivalentParameters(C.FirstParameter(),
155       C.FirstParameter() + 
156       C.Curve()->LastParameter() -
157       C.Curve()->FirstParameter());
158   }
159
160   Handle(Geom2d_Line) GL= new Geom2d_Line(L);
161   Geom2dAdaptor_Curve CGA(GL);
162   Geom2dInt_GInter Inter(CGA,DL,C,DE,
163     Precision::PConfusion(),
164     Precision::PIntersection());
165   //
166   SetValues(Inter);
167 }
168
169 //=======================================================================
170 //function : LocalGeometry
171 //purpose  : 
172 //=======================================================================
173 void  BRepClass_Intersector::LocalGeometry(const BRepClass_Edge& E, 
174                                            const Standard_Real U, 
175                                            gp_Dir2d& Tang, 
176                                            gp_Dir2d& Norm, 
177                                            Standard_Real& C) const 
178 {
179   Standard_Real fpar, lpar;
180   Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface(E.Edge(), E.Face(), fpar, lpar);
181   Geom2dLProp_CLProps2d Prop(aPCurve, U, 2, Precision::PConfusion());
182
183   C = 0.;
184   if (Prop.IsTangentDefined())
185   {
186     Prop.Tangent(Tang);
187     C = Prop.Curvature();
188   }
189   else
190     GetTangentAsChord(aPCurve, Tang, U, fpar, lpar);
191   
192   if (C > Precision::PConfusion() &&
193       !Precision::IsInfinite(C))
194     Prop.Normal(Norm);
195   else
196     Norm.SetCoord(Tang.Y(),-Tang.X());
197 }
198
199 //=======================================================================
200 //function : RefineTolerance
201 //purpose  : 
202 //=======================================================================
203 void RefineTolerance(const TopoDS_Face& aF,
204                      const Geom2dAdaptor_Curve& aC,
205                      const Standard_Real aT,
206                      Standard_Real& aTolZ)
207 {
208   GeomAbs_SurfaceType aTypeS;
209   //
210   BRepAdaptor_Surface aBAS(aF, Standard_False);
211   //
212   aTypeS=aBAS.GetType();
213   if (aTypeS==GeomAbs_Cylinder) {
214     Standard_Real aURes, aVRes, aTolX;
215     gp_Pnt2d aP2D;
216     gp_Vec2d aV2D;
217     //
218     aURes=aBAS.UResolution(aTolZ);
219     aVRes=aBAS.VResolution(aTolZ);
220     //
221     aC.D1(aT, aP2D, aV2D);
222     gp_Dir2d aD2D(aV2D);
223     //
224     aTolX=aURes*aD2D.Y()+aVRes*aD2D.X();
225     if (aTolX<0.) {
226       aTolX=-aTolX;
227     }
228     //
229     if (aTolX < Precision::Confusion()) {
230       aTolX = Precision::Confusion();
231     }
232     //
233     if (aTolX<aTolZ) {
234       aTolZ=aTolX;
235     }
236   }
237 }
238
239 //=======================================================================
240 //function : GetTangentAsChord
241 //purpose  : 
242 //=======================================================================
243 void GetTangentAsChord(const Handle(Geom2d_Curve)& thePCurve,
244                        gp_Dir2d&                   theTangent,
245                        const Standard_Real         theParam,
246                        const Standard_Real         theFirst,
247                        const Standard_Real         theLast)
248 {
249   Standard_Real Offset = 0.1*(theLast - theFirst);
250
251   if (theLast - theParam < Precision::PConfusion()) //theParam == theLast
252     Offset *= -1;
253   else if (theParam + Offset > theLast) //<theParam> is close to <theLast>
254     Offset = 0.5*(theLast - theParam);
255
256   gp_Pnt2d aPnt2d = thePCurve->Value(theParam);
257   gp_Pnt2d OffsetPnt2d = thePCurve->Value(theParam + Offset);
258
259   gp_Vec2d aChord(aPnt2d, OffsetPnt2d);
260   if (Offset < 0.)
261     aChord.Reverse();
262
263   Standard_Real SqLength = aChord.SquareMagnitude();
264   if (SqLength > Precision::SquarePConfusion())
265     theTangent = aChord;
266 }