0029915: Porting to VC 2017 : Regressions in Modeling Algorithms on VC 2017
[occt.git] / src / BRepMesh / BRepMesh_GeomTool.cxx
1 // Created on: 1993-09-29
2 // Created by: Isabelle GRIGNON
3 // Copyright (c) 1993-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 #include <BRepMesh_GeomTool.hxx>
18
19 #include <TopAbs_Orientation.hxx>
20 #include <CSLib.hxx>
21 #include <Precision.hxx>
22 #include <Adaptor3d_IsoCurve.hxx>
23 #include <BRepAdaptor_Curve.hxx>
24 #include <BRepAdaptor_HSurface.hxx>
25 #include <Geom2d_Curve.hxx>
26 #include <BRep_Tool.hxx>
27
28 //=======================================================================
29 //function : Constructor
30 //purpose  :
31 //=======================================================================
32 BRepMesh_GeomTool::BRepMesh_GeomTool(
33   const BRepAdaptor_Curve& theCurve,
34   const Standard_Real      theFirstParam,
35   const Standard_Real      theLastParam,
36   const Standard_Real      theLinDeflection,
37   const Standard_Real      theAngDeflection,
38   const Standard_Integer   theMinPointsNb,
39   const Standard_Real      theMinSize)
40   : myEdge(&theCurve.Edge()),
41     myIsoType(GeomAbs_NoneIso)
42 {
43   myDiscretTool.Initialize(theCurve, theFirstParam, theLastParam,
44     theAngDeflection, theLinDeflection, theMinPointsNb, 
45     Precision::PConfusion(), theMinSize);
46 }
47
48 //=======================================================================
49 //function : Constructor
50 //purpose  :
51 //=======================================================================
52 BRepMesh_GeomTool::BRepMesh_GeomTool(
53   const Handle(BRepAdaptor_HSurface)& theSurface,
54   const GeomAbs_IsoType               theIsoType,
55   const Standard_Real                 theParamIso,
56   const Standard_Real                 theFirstParam,
57   const Standard_Real                 theLastParam,
58   const Standard_Real                 theLinDeflection,
59   const Standard_Real                 theAngDeflection,
60   const Standard_Integer              theMinPointsNb,
61   const Standard_Real                 theMinSize)
62   : myEdge(NULL),
63     myIsoType(theIsoType)
64 {
65   Adaptor3d_IsoCurve aIso(theSurface, theIsoType, theParamIso,
66     theFirstParam, theLastParam);
67
68   myDiscretTool.Initialize(aIso, theFirstParam, theLastParam,
69     theAngDeflection, theLinDeflection, theMinPointsNb,
70     Precision::PConfusion(), theMinSize);
71 }
72
73 //=======================================================================
74 //function : Value
75 //purpose  :
76 //=======================================================================
77 Standard_Boolean BRepMesh_GeomTool::Value(
78   const Standard_Integer              theIndex,
79   Standard_Real&                      theParam,
80   gp_Pnt&                             thePoint) const
81 {
82   if (theIndex < 1 || theIndex > NbPoints())
83     return Standard_False;
84
85   if (myEdge == NULL)
86     return Standard_False;
87
88   thePoint = myDiscretTool.Value(theIndex);
89   theParam = myDiscretTool.Parameter(theIndex);
90
91   return Standard_True;
92 }
93
94 //=======================================================================
95 //function : Value
96 //purpose  :
97 //=======================================================================
98 Standard_Boolean BRepMesh_GeomTool::Value(const Standard_Integer theIndex,
99                                           const Standard_Real    theIsoParam,
100                                           Standard_Real&         theParam,
101                                           gp_Pnt&                thePoint,
102                                           gp_Pnt2d&              theUV) const
103 {
104   if (theIndex < 1 || theIndex > NbPoints())
105     return Standard_False;
106
107   thePoint = myDiscretTool.Value(theIndex);
108   theParam = myDiscretTool.Parameter(theIndex);
109
110   if (myIsoType == GeomAbs_IsoU)
111     theUV.SetCoord(theIsoParam, theParam);
112   else
113     theUV.SetCoord(theParam, theIsoParam);
114
115   return Standard_True;
116 }
117
118 //=======================================================================
119 //function : Normal
120 //purpose  :
121 //=======================================================================
122 Standard_Boolean BRepMesh_GeomTool::Normal(
123   const Handle(BRepAdaptor_HSurface)& theSurface,
124   const Standard_Real                 theParamU,
125   const Standard_Real                 theParamV,
126   gp_Pnt&                             thePoint,
127   gp_Dir&                             theNormal)
128 {
129   Standard_Boolean isOK = Standard_True;
130   gp_Vec aD1U, aD1V;
131
132   theSurface->D1(theParamU, theParamV, thePoint, aD1U, aD1V);
133
134   CSLib_DerivativeStatus aStatus;
135   CSLib::Normal(aD1U, aD1V, Precision::Angular(), aStatus, theNormal);
136   if (aStatus != CSLib_Done)
137   {
138     gp_Vec aD2U,aD2V,aD2UV;
139     theSurface->D2(theParamU, theParamV, thePoint, aD1U, aD1V, aD2U, aD2V, aD2UV);
140     CSLib_NormalStatus aNormalStatus;
141     CSLib::Normal(aD1U, aD1V, aD2U, aD2V, aD2UV, Precision::Angular(), 
142       isOK, aNormalStatus, theNormal);
143   }
144
145   if (!isOK)
146     return Standard_False;
147
148   const TopoDS_Face& aFace = ((BRepAdaptor_Surface*)&(theSurface->Surface()))->Face();
149   TopAbs_Orientation aOri = aFace.Orientation();
150   if (aOri == TopAbs_REVERSED)
151     theNormal.Reverse();
152
153   return Standard_True;
154 }
155
156 //=============================================================================
157 //function : IntLinLin
158 //purpose  : 
159 //=============================================================================
160 BRepMesh_GeomTool::IntFlag BRepMesh_GeomTool::IntLinLin(
161   const gp_XY&  theStartPnt1,
162   const gp_XY&  theEndPnt1,
163   const gp_XY&  theStartPnt2,
164   const gp_XY&  theEndPnt2,
165   gp_XY&        theIntPnt,
166   Standard_Real (&theParamOnSegment)[2])
167 {
168   gp_XY aVec1    = theEndPnt1   - theStartPnt1;
169   gp_XY aVec2    = theEndPnt2   - theStartPnt2;
170   gp_XY aVecO1O2 = theStartPnt2 - theStartPnt1;
171     
172   Standard_Real aCrossD1D2 = aVec1    ^ aVec2;
173   Standard_Real aCrossD1D3 = aVecO1O2 ^ aVec2;
174
175   const Standard_Real aPrec = gp::Resolution();
176   // Are edgegs codirectional
177   if ( Abs( aCrossD1D2 ) < aPrec )
178   {
179     // Just a parallel case?
180     if( Abs( aCrossD1D3 ) < aPrec )
181       return BRepMesh_GeomTool::Same;
182     else
183       return BRepMesh_GeomTool::NoIntersection;
184   }
185
186   theParamOnSegment[0] = aCrossD1D3 / aCrossD1D2;
187   theIntPnt = theStartPnt1 + theParamOnSegment[0] * aVec1;
188
189   Standard_Real aCrossD2D3 = aVecO1O2 ^ aVec1;
190   theParamOnSegment[1] = aCrossD2D3 / aCrossD1D2;
191
192   return BRepMesh_GeomTool::Cross;
193 }
194
195 //=============================================================================
196 //function : IntSegSeg
197 //purpose  : 
198 //=============================================================================
199 BRepMesh_GeomTool::IntFlag BRepMesh_GeomTool::IntSegSeg(
200   const gp_XY&           theStartPnt1,
201   const gp_XY&           theEndPnt1,
202   const gp_XY&           theStartPnt2,
203   const gp_XY&           theEndPnt2,
204   const Standard_Boolean isConsiderEndPointTouch,
205   const Standard_Boolean isConsiderPointOnSegment,
206   gp_Pnt2d&              theIntPnt)
207 {
208   Standard_Integer aPointHash[] = {
209     classifyPoint(theStartPnt1, theEndPnt1, theStartPnt2),
210     classifyPoint(theStartPnt1, theEndPnt1, theEndPnt2  ),
211     classifyPoint(theStartPnt2, theEndPnt2, theStartPnt1),
212     classifyPoint(theStartPnt2, theEndPnt2, theEndPnt1  )
213   };
214
215   // Consider case when edges have shared vertex
216   if ( aPointHash[0] < 0 || aPointHash[1] < 0 )
217   {
218     if ( isConsiderEndPointTouch )
219       return BRepMesh_GeomTool::EndPointTouch;
220
221     return BRepMesh_GeomTool::NoIntersection;
222   }
223
224   Standard_Integer aPosHash = 
225     aPointHash[0] + aPointHash[1] + aPointHash[2] + aPointHash[3];
226
227   /*=========================================*/
228   /*  1) hash code == 1:
229
230                     0+
231                     /
232            0      1/         0
233            +======+==========+
234   
235       2) hash code == 2:
236
237            0    1        1   0
238         a) +----+========+---+
239
240            0       1   1     0
241         b) +-------+===+=====+
242
243                                              */
244   /*=========================================*/
245   if ( aPosHash == 1 )
246   {
247     if (isConsiderPointOnSegment)
248     {
249       if (aPointHash[0] == 1)
250         theIntPnt = theStartPnt1;
251       else if (aPointHash[1] == 1)
252         theIntPnt = theEndPnt1;
253       else if (aPointHash[2] == 1)
254         theIntPnt = theStartPnt2;
255       else
256         theIntPnt = theEndPnt2;
257
258       return BRepMesh_GeomTool::PointOnSegment;
259     }
260
261     return BRepMesh_GeomTool::NoIntersection;
262   }
263   else if ( aPosHash == 2 )
264     return BRepMesh_GeomTool::Glued;
265
266   Standard_Real aParam[2];
267   IntFlag aIntFlag = IntLinLin(theStartPnt1, theEndPnt1, 
268     theStartPnt2, theEndPnt2, theIntPnt.ChangeCoord(), aParam);
269
270   if (aIntFlag == BRepMesh_GeomTool::NoIntersection)
271     return BRepMesh_GeomTool::NoIntersection;
272
273   if (aIntFlag == BRepMesh_GeomTool::Same)
274   {
275     if ( aPosHash < -2 )
276       return BRepMesh_GeomTool::Same;
277     else if ( aPosHash == -1 )
278       return BRepMesh_GeomTool::Glued;
279
280     return BRepMesh_GeomTool::NoIntersection;
281   }
282
283   // Cross
284   // Intersection is out of segments ranges
285   const Standard_Real aPrec    = Precision::PConfusion();
286   const Standard_Real aEndPrec = 1 - aPrec;
287   for (Standard_Integer i = 0; i < 2; ++i)
288   {
289     if( aParam[i] < aPrec || aParam[i] > aEndPrec )
290       return BRepMesh_GeomTool::NoIntersection;
291   }
292  
293   return BRepMesh_GeomTool::Cross;
294 }
295
296 //=============================================================================
297 //function : classifyPoint
298 //purpose  : 
299 //=============================================================================
300 Standard_Integer BRepMesh_GeomTool::classifyPoint(
301   const gp_XY& thePoint1,
302   const gp_XY& thePoint2,
303   const gp_XY& thePointToCheck)
304 {
305   gp_XY aP1 = thePoint2       - thePoint1;
306   gp_XY aP2 = thePointToCheck - thePoint1;
307   
308   const Standard_Real aPrec   = Precision::PConfusion();
309   const Standard_Real aSqPrec = aPrec * aPrec;
310   Standard_Real aDist = Abs(aP1 ^ aP2);
311   if (aDist > aPrec)
312   {
313     aDist = (aDist * aDist) / aP1.SquareModulus();
314     if (aDist > aSqPrec)
315       return 0; //out
316   }
317     
318   gp_XY aMult = aP1.Multiplied(aP2);
319   if ( aMult.X() < 0.0 || aMult.Y() < 0.0 )
320     return 0; //out
321     
322   if (aP1.SquareModulus() < aP2.SquareModulus())
323     return 0; //out
324     
325   if (thePointToCheck.IsEqual(thePoint1, aPrec) || 
326       thePointToCheck.IsEqual(thePoint2, aPrec))
327   {
328     return -1; //coinsides with an end point
329   }
330     
331   return 1;
332 }