d1895602c1dd1ec67d0953de28c85b53ff9620ce
[occt.git] / src / BRepMesh / BRepMesh_EdgeTessellator.cxx
1 // Created on: 2014-08-13
2 // Created by: Oleg AGASHIN
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <BRepMesh_EdgeTessellator.hxx>
17 #include <Geom_Surface.hxx>
18 #include <Geom_Plane.hxx>
19 #include <Geom2d_Curve.hxx>
20 #include <TopoDS_Edge.hxx>
21 #include <TopoDS_Face.hxx>
22 #include <BRepAdaptor_HSurface.hxx>
23 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
24 #include <TopLoc_Location.hxx>
25 #include <BRep_Tool.hxx>
26 #include <TColStd_Array1OfReal.hxx>
27 #include <TopExp_Explorer.hxx>
28 #include <TopoDS_Vertex.hxx>
29 #include <TopoDS.hxx>
30 #include <TopTools_ListIteratorOfListOfShape.hxx>
31 #include <TopTools_ListOfShape.hxx>
32 #include <TColStd_Array1OfReal.hxx>
33
34
35 IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_EdgeTessellator,BRepMesh_IEdgeTool)
36
37 //=======================================================================
38 //function : Constructor
39 //purpose  : 
40 //=======================================================================
41 BRepMesh_EdgeTessellator::BRepMesh_EdgeTessellator(
42   const TopoDS_Edge&                               theEdge,
43   const Handle(BRepMesh_FaceAttribute)&            theFaceAttribute,
44   const TopTools_IndexedDataMapOfShapeListOfShape& theMapOfSharedFaces,
45   const Standard_Real                              theLinDeflection,
46   const Standard_Real                              theAngDeflection,
47   const Standard_Real                              theMinSize)
48   : mySurface(theFaceAttribute->Surface())
49 {
50   Standard_Real aPreciseAngDef = 0.5 * theAngDeflection;
51   Standard_Real aPreciseLinDef = 0.5 * theLinDeflection;
52   if (theEdge.Orientation() == TopAbs_INTERNAL)
53     aPreciseLinDef *= 0.5;
54
55   mySquareEdgeDef = aPreciseLinDef * aPreciseLinDef;
56   mySquareMinSize = Max(mySquareEdgeDef, theMinSize * theMinSize);
57   myEdgeSqTol     = BRep_Tool::Tolerance (theEdge);
58   myEdgeSqTol    *= myEdgeSqTol;
59
60   Standard_Boolean isSameParam = BRep_Tool::SameParameter(theEdge);
61   if (isSameParam)
62     myCOnS.Initialize(theEdge);
63   else
64     myCOnS.Initialize(theEdge, theFaceAttribute->Face());
65
66   const GeomAbs_CurveType aCurveType = myCOnS.GetType();
67   Standard_Integer aMinPntNb = (aCurveType == GeomAbs_Circle) ? 4 : 2; //OCC287
68
69   // Get range on 2d curve
70   Standard_Real aFirstParam, aLastParam;
71   BRep_Tool::Range(theEdge, theFaceAttribute->Face(), aFirstParam, aLastParam);
72   myTool = new BRepMesh_GeomTool(myCOnS, aFirstParam, aLastParam, 
73     aPreciseLinDef, aPreciseAngDef, aMinPntNb, theMinSize);
74
75   if (aCurveType == GeomAbs_BSplineCurve)
76   {
77     // bug24220
78     const Standard_Integer aNbInt = myCOnS.NbIntervals(GeomAbs_C1);
79     if ( aNbInt > 0 )
80     {
81       TColStd_Array1OfReal anIntervals( 1, aNbInt + 1 );
82       myCOnS.Intervals(anIntervals, GeomAbs_C1);
83       for (Standard_Integer aIntIt = 1; aIntIt <= aNbInt; ++aIntIt)
84       {
85         const Standard_Real& aStartInt = anIntervals.Value( aIntIt );
86         const Standard_Real& anEndInt  = anIntervals.Value( aIntIt + 1 );
87
88         BRepMesh_GeomTool aDetalizator(myCOnS, aStartInt, anEndInt,
89           aPreciseLinDef, aPreciseAngDef, aMinPntNb, theMinSize);
90
91         Standard_Integer aNbAddNodes = aDetalizator.NbPoints();
92         for ( Standard_Integer aNodeIt = 1; aNodeIt <= aNbAddNodes; ++aNodeIt )
93         {
94           Standard_Real aParam;
95           gp_Pnt        aPoint3d;
96           gp_Pnt2d      aPoint2d;
97           aDetalizator.Value( aNodeIt, mySurface, aParam, aPoint3d, aPoint2d );
98           myTool->AddPoint( aPoint3d, aParam, Standard_False );
99         }
100       }
101     }
102   }
103
104   // PTv, chl/922/G9, Take into account internal vertices
105   // it is necessary for internal edges, which do not split other edges, by their vertex
106   TopExp_Explorer aVertexIt(theEdge, TopAbs_VERTEX);
107   for (; aVertexIt.More(); aVertexIt.Next())
108   {
109     const TopoDS_Vertex& aVertex = TopoDS::Vertex(aVertexIt.Current());
110     if (aVertex.Orientation() != TopAbs_INTERNAL)
111       continue;
112
113     myTool->AddPoint(BRep_Tool::Pnt(aVertex), 
114       BRep_Tool::Parameter(aVertex, theEdge), Standard_True);
115   }
116
117   Standard_Integer aNodesNb = myTool->NbPoints();
118   //Check deflection in 2d space for improvement of edge tesselation.
119   if( isSameParam && aNodesNb > 1)
120   {
121     const TopTools_ListOfShape& aSharedFaces = theMapOfSharedFaces.FindFromKey(theEdge);
122     TopTools_ListIteratorOfListOfShape aFaceIt(aSharedFaces);
123     for (; aFaceIt.More(); aFaceIt.Next())
124     {
125       TopLoc_Location aLoc;
126       const TopoDS_Face&   aFace = TopoDS::Face(aFaceIt.Value());
127       Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace, aLoc);
128
129       if (aSurf->IsInstance(STANDARD_TYPE(Geom_Plane)))
130         continue;
131
132       Standard_Real aF, aL;
133       Handle(Geom2d_Curve) aCurve2d = BRep_Tool::CurveOnSurface(theEdge, aFace, aF, aL);
134       if ( Abs(aF - aFirstParam) > Precision::PConfusion() ||
135            Abs(aL - aLastParam ) > Precision::PConfusion() )
136       {
137         continue;
138       }
139
140       aNodesNb = myTool->NbPoints();
141       TColStd_Array1OfReal aParamArray(1, aNodesNb);
142       for (Standard_Integer i = 1; i <= aNodesNb; ++i)
143       {
144         gp_Pnt2d      aTmpUV;
145         gp_Pnt        aTmpPnt;
146         Standard_Real aParam;
147         myTool->Value(i, mySurface, aParam, aTmpPnt, aTmpUV);
148         aParamArray.SetValue(i, aParam);
149       }
150
151       for (Standard_Integer i = 1; i < aNodesNb; ++i)
152         splitSegment(aSurf, aCurve2d, aParamArray(i), aParamArray(i + 1), 1);
153     }
154   }
155
156    const Standard_Real aTol = Precision::Confusion();
157    const Standard_Real aDu  = mySurface->UResolution (aTol);
158    const Standard_Real aDv  = mySurface->VResolution (aTol);
159
160    myFaceRangeU[0] = mySurface->FirstUParameter() - aDu;
161    myFaceRangeU[1] = mySurface->LastUParameter()  + aDu;
162
163    myFaceRangeV[0] = mySurface->FirstVParameter() - aDv;
164    myFaceRangeV[1] = mySurface->LastVParameter()  + aDv;
165 }
166
167 //=======================================================================
168 //function : Value
169 //purpose  : 
170 //=======================================================================
171 Standard_Boolean BRepMesh_EdgeTessellator::Value(
172   const Standard_Integer theIndex,
173   Standard_Real&         theParameter,
174   gp_Pnt&                thePoint,
175   gp_Pnt2d&              theUV)
176 {
177   myTool->Value(theIndex, mySurface, theParameter, thePoint, theUV);
178
179   // If point coordinates are out of surface range, 
180   // it is necessary to re-project point.
181   if (mySurface->GetType() != GeomAbs_BSplineSurface &&
182       mySurface->GetType() != GeomAbs_BezierSurface  &&
183       mySurface->GetType() != GeomAbs_OtherSurface)
184   {
185     return Standard_True;
186   }
187
188   // Let skip periodic case.
189   if (mySurface->IsUPeriodic() || mySurface->IsVPeriodic())
190     return Standard_True;
191
192   // Point lies within the surface range - nothing to do.
193   if (theUV.X() > myFaceRangeU[0] && theUV.X() < myFaceRangeU[1] &&
194       theUV.Y() > myFaceRangeV[0] && theUV.Y() < myFaceRangeV[1])
195   {
196     return Standard_True;
197   }
198
199   gp_Pnt aPntOnSurf;
200   mySurface->D0 (theUV.X (), theUV.Y (), aPntOnSurf);
201
202   return (thePoint.SquareDistance (aPntOnSurf) < myEdgeSqTol);
203 }
204
205 //=======================================================================
206 //function : splitSegment
207 //purpose  : 
208 //=======================================================================
209 void BRepMesh_EdgeTessellator::splitSegment(
210   const Handle(Geom_Surface)& theSurf,
211   const Handle(Geom2d_Curve)& theCurve2d,
212   const Standard_Real         theFirst,
213   const Standard_Real         theLast,
214   const Standard_Integer      theNbIter)
215 {
216   // limit iteration depth
217   if(theNbIter > 10)
218     return;
219
220   gp_Pnt2d uvf, uvl, uvm;
221   gp_Pnt   P3dF, P3dL, midP3d, midP3dFromSurf;
222   Standard_Real midpar;
223   
224   if(Abs(theLast - theFirst) < 2 * Precision::PConfusion())
225     return;
226
227   theCurve2d->D0(theFirst, uvf);
228   theCurve2d->D0(theLast,  uvl);
229
230   P3dF = theSurf->Value(uvf.X(), uvf.Y());
231   P3dL = theSurf->Value(uvl.X(), uvl.Y());
232   
233   if(P3dF.SquareDistance(P3dL) < mySquareMinSize)
234     return;
235
236   uvm = gp_Pnt2d((uvf.XY() + uvl.XY())*0.5);
237   midP3dFromSurf = theSurf->Value(uvm.X(), uvm.Y());
238
239   gp_XYZ Vec1 = midP3dFromSurf.XYZ() - P3dF.XYZ();
240   if(Vec1.SquareModulus() < mySquareMinSize)
241     return;
242
243   gp_XYZ aVec = P3dL.XYZ() - P3dF.XYZ();
244   aVec.Normalize();
245
246   Standard_Real aModulus = Vec1.Dot(aVec);
247   gp_XYZ aProj = aVec * aModulus;
248   gp_XYZ aDist = Vec1 - aProj;
249
250   if(aDist.SquareModulus() < mySquareEdgeDef)
251     return;
252
253   midpar = (theFirst + theLast) * 0.5;
254   myCOnS.D0(midpar, midP3d);
255   myTool->AddPoint(midP3d, midpar, Standard_False);
256
257   splitSegment(theSurf, theCurve2d, theFirst, midpar, theNbIter + 1);
258   splitSegment(theSurf, theCurve2d, midpar, theLast,  theNbIter + 1); 
259 }