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