0031047: Modeling Algorithms - BRepExtrema_DistShapeShape gives wrong result
[occt.git] / src / BRepClass / BRepClass_FaceExplorer.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 //  Modified by skv - Thu Jul 13 17:42:58 2006 OCC12627
18 //  Total rewriting of the method Segment; add the method OtherSegment.
19
20 #include <BRep_Tool.hxx>
21 #include <BRepClass_Edge.hxx>
22 #include <BRepClass_FaceExplorer.hxx>
23 #include <BRepTools.hxx>
24 #include <Geom2d_Curve.hxx>
25 #include <Precision.hxx>
26 #include <TopoDS.hxx>
27 #include <TopExp.hxx>
28 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
29
30 static const Standard_Real Probing_Start = 0.123;
31 static const Standard_Real Probing_End = 0.7;
32 static const Standard_Real Probing_Step = 0.2111;
33
34 //=======================================================================
35 //function : BRepClass_FaceExplorer
36 //purpose  : 
37 //=======================================================================
38
39 BRepClass_FaceExplorer::BRepClass_FaceExplorer(const TopoDS_Face& F) :
40        myFace(F),
41        myCurEdgeInd(1),
42        myCurEdgePar(Probing_Start),
43        myUMin (Precision::Infinite()),
44        myUMax (-Precision::Infinite()),
45        myVMin (Precision::Infinite()),
46        myVMax (-Precision::Infinite())
47 {
48   myFace.Orientation(TopAbs_FORWARD);
49 }
50
51 //=======================================================================
52 //function : ComputeFaceBounds
53 //purpose  : 
54 //=======================================================================
55 void BRepClass_FaceExplorer::ComputeFaceBounds()
56 {
57   TopLoc_Location aLocation;
58   const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface (myFace, aLocation);
59   aSurface->Bounds (myUMin, myUMax, myVMin, myVMax);
60   if (Precision::IsInfinite (myUMin) || Precision::IsInfinite (myUMax) ||
61       Precision::IsInfinite (myVMin) || Precision::IsInfinite (myVMax))
62   {
63     BRepTools::UVBounds(myFace, myUMin, myUMax, myVMin, myVMax);
64   }
65 }
66
67 //=======================================================================
68 //function : CheckPoint
69 //purpose  : 
70 //=======================================================================
71
72 Standard_Boolean BRepClass_FaceExplorer::CheckPoint(gp_Pnt2d& thePoint)
73 {
74   if (myUMin > myUMax)
75   {
76     ComputeFaceBounds();
77   }
78
79   if (Precision::IsInfinite(myUMin) || Precision::IsInfinite(myUMax) ||
80       Precision::IsInfinite(myVMin) || Precision::IsInfinite(myVMax))
81   {
82     return Standard_True;
83   }
84
85   gp_Pnt2d aCenterPnt(( myUMin + myUMax ) / 2, ( myVMin + myVMax ) / 2);
86   Standard_Real aDistance = aCenterPnt.Distance(thePoint);
87   if (Precision::IsInfinite(aDistance))
88   {
89     thePoint.SetCoord (myUMin - (myUMax - myUMin ),
90                        myVMin - (myVMax - myVMin ));
91     return Standard_False;
92   }
93   else
94   {
95     Standard_Real anEpsilon = Epsilon(aDistance);
96     if (anEpsilon > Max (myUMax - myUMin, myVMax - myVMin))
97     {
98       gp_Vec2d aLinVec(aCenterPnt, thePoint);
99       gp_Dir2d aLinDir(aLinVec);
100       thePoint = aCenterPnt.XY() + aLinDir.XY() * ( 2. * anEpsilon );
101       return Standard_False;
102     }
103   }
104
105   return Standard_True;
106 }
107
108 //=======================================================================
109 //function : Reject
110 //purpose  : 
111 //=======================================================================
112
113 Standard_Boolean  BRepClass_FaceExplorer::Reject(const gp_Pnt2d&)const 
114 {
115   return Standard_False;
116 }
117
118 //=======================================================================
119 //function : Segment
120 //purpose  : 
121 //=======================================================================
122
123 Standard_Boolean BRepClass_FaceExplorer::Segment(const gp_Pnt2d& P, 
124                                                  gp_Lin2d& L,
125                                                  Standard_Real& Par)
126 {
127   myCurEdgeInd = 1;
128   myCurEdgePar = Probing_Start;
129
130   return OtherSegment(P, L, Par);
131 }
132
133 //=======================================================================
134 //function : OtherSegment
135 //purpose  : 
136 //=======================================================================
137
138 Standard_Boolean BRepClass_FaceExplorer::OtherSegment(const gp_Pnt2d& P, 
139                                                       gp_Lin2d& L,
140                                                       Standard_Real& Par)
141 {
142   TopExp_Explorer      anExpF(myFace, TopAbs_EDGE);
143   Standard_Integer     i;
144   Standard_Real        aFPar;
145   Standard_Real        aLPar;
146   Handle(Geom2d_Curve) aC2d;
147   Standard_Real        aTolParConf2 = Precision::PConfusion() * Precision::PConfusion();
148   gp_Pnt2d             aPOnC;
149   Standard_Real        aParamIn;
150
151   for (i = 1; anExpF.More(); anExpF.Next(), i++) {
152     if (i != myCurEdgeInd)
153       continue;
154
155     const TopoDS_Shape       &aLocalShape = anExpF.Current();
156     const TopAbs_Orientation  anOrientation = aLocalShape.Orientation();
157
158     if (anOrientation == TopAbs_FORWARD || anOrientation == TopAbs_REVERSED) {
159       const TopoDS_Edge &anEdge = TopoDS::Edge(aLocalShape);
160
161       aC2d = BRep_Tool::CurveOnSurface(anEdge, myFace, aFPar, aLPar);
162
163       if (!aC2d.IsNull()) {
164         // Treatment of infinite cases.
165         if (Precision::IsNegativeInfinite(aFPar)) {
166           if (Precision::IsPositiveInfinite(aLPar)) {
167             aFPar = -1.;
168             aLPar = 1.;
169           }
170           else {
171             aFPar = aLPar - 1.;
172           }
173         }
174         else if (Precision::IsPositiveInfinite(aLPar))
175           aLPar = aFPar + 1.;
176
177         for (; myCurEdgePar < Probing_End; myCurEdgePar += Probing_Step) {
178           aParamIn = myCurEdgePar*aFPar + (1. - myCurEdgePar)*aLPar;
179
180           gp_Vec2d aTanVec;
181           aC2d->D1(aParamIn, aPOnC, aTanVec);
182           Par = aPOnC.SquareDistance(P);
183
184           if (Par > aTolParConf2) {
185             gp_Vec2d aLinVec(P, aPOnC);
186             gp_Dir2d aLinDir(aLinVec);
187
188             Standard_Real aTanMod = aTanVec.SquareMagnitude();
189             if (aTanMod < aTolParConf2)
190               continue;
191             aTanVec /= Sqrt(aTanMod);
192             Standard_Real aSinA = aTanVec.Crossed(aLinDir.XY());
193             const Standard_Real SmallAngle = 0.001;
194             Standard_Boolean isSmallAngle = Standard_False;
195             if (Abs(aSinA) < SmallAngle)
196             {
197               isSmallAngle = Standard_True;
198               // The line from the input point P to the current point on edge
199               // is tangent to the edge curve. This condition is bad for classification.
200               // Therefore try to go to another point in the hope that there will be 
201               // no tangent. If there tangent is preserved then leave the last point in 
202               // order to get this edge chanse to participate in classification.
203               if (myCurEdgePar + Probing_Step < Probing_End)
204                 continue;
205             }
206
207             L = gp_Lin2d(P, aLinDir);
208
209             // Check if ends of a curve lie on a line.
210             aC2d->D0(aFPar, aPOnC);
211             gp_Pnt2d aFPOnC = aPOnC;
212             if (L.SquareDistance(aPOnC) > aTolParConf2) {
213               aC2d->D0(aLPar, aPOnC);
214               if (L.SquareDistance(aPOnC) > aTolParConf2) {
215
216                 if (isSmallAngle)
217                 {
218                   //Try to find minimal distance between curve and line
219
220                   Geom2dAPI_ProjectPointOnCurve aProj;
221                   aProj.Init(P, aC2d, aFPar, aLPar);
222                   if (aProj.NbPoints() > 0)
223                   {
224                     gp_Pnt2d aLPOnC = aPOnC;
225                     Standard_Real aFDist = P.SquareDistance(aFPOnC);
226                     Standard_Real aLDist = P.SquareDistance(aLPOnC);
227                     Standard_Real aMinDist = aProj.LowerDistance();
228                     aMinDist *= aMinDist;
229                     aPOnC = aProj.NearestPoint();
230                     if (aMinDist > aFDist)
231                     {
232                       aMinDist = aFDist;
233                       aPOnC = aFPOnC;
234                     }
235                     //
236                     if (aMinDist > aLDist)
237                     {
238                       aMinDist = aLDist;
239                       aPOnC = aLPOnC;
240                     }
241                     //
242                     if (aMinDist < Par)
243                     {
244                       Par = aMinDist;
245                       if (Par < aTolParConf2)
246                       {
247                         continue;
248                       }
249                       aLinVec.SetXY((aPOnC.XY() - P.XY()));
250                       aLinDir.SetXY(aLinVec.XY());
251                       L = gp_Lin2d(P, aLinDir);
252                     }
253                   }
254                 }
255                 myCurEdgePar += Probing_Step;
256                 if (myCurEdgePar >= Probing_End) {
257                   myCurEdgeInd++;
258                   myCurEdgePar = Probing_Start;
259                 }
260
261                 Par = Sqrt(Par);
262                 return Standard_True;
263               }
264             }
265           }
266         }
267       } // if (!aC2d.IsNull()) {
268     } // if (anOrientation == TopAbs_FORWARD ...
269
270     // This curve is not valid for line construction. Go to another edge.
271     myCurEdgeInd++;
272     myCurEdgePar = Probing_Start;
273   }
274
275   // nothing found, return an horizontal line
276   Par = RealLast();
277   L = gp_Lin2d(P, gp_Dir2d(1, 0));
278
279   return Standard_False;
280 }
281
282 //=======================================================================
283 //function : InitWires
284 //purpose  : 
285 //=======================================================================
286
287 void  BRepClass_FaceExplorer::InitWires()
288 {
289   myWExplorer.Init(myFace,TopAbs_WIRE);
290 }
291
292 //=======================================================================
293 //function : RejectWire NYI
294 //purpose  : 
295 //=======================================================================
296
297 Standard_Boolean  BRepClass_FaceExplorer::RejectWire
298   (const gp_Lin2d& , 
299    const Standard_Real)const 
300 {
301   return Standard_False;
302 }
303
304 //=======================================================================
305 //function : InitEdges
306 //purpose  : 
307 //=======================================================================
308
309 void  BRepClass_FaceExplorer::InitEdges()
310 {
311   myEExplorer.Init(myWExplorer.Current(),TopAbs_EDGE);
312   myMapVE.Clear();
313   TopExp::MapShapesAndAncestors(myWExplorer.Current(), TopAbs_VERTEX, TopAbs_EDGE, myMapVE);
314 }
315
316 //=======================================================================
317 //function : RejectEdge NYI
318 //purpose  : 
319 //=======================================================================
320
321 Standard_Boolean  BRepClass_FaceExplorer::RejectEdge
322   (const gp_Lin2d& , 
323    const Standard_Real )const 
324 {
325   return Standard_False;
326 }
327
328
329 //=======================================================================
330 //function : CurrentEdge
331 //purpose  : 
332 //=======================================================================
333
334 void  BRepClass_FaceExplorer::CurrentEdge(BRepClass_Edge& E, 
335                                           TopAbs_Orientation& Or) const 
336 {
337   E.Edge() = TopoDS::Edge(myEExplorer.Current());
338   E.Face() = myFace;
339   Or = E.Edge().Orientation();
340   E.SetNextEdge(myMapVE);
341 }
342