0026106: BRepMesh - revision of data model
[occt.git] / src / BRepMesh / BRepMesh_CurveTessellator.cxx
1 // Created on: 2016-04-19
2 // Copyright (c) 2016 OPEN CASCADE SAS
3 // Created by: Oleg AGASHIN
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_CurveTessellator.hxx>
17 #include <gp_Pnt.hxx>
18 #include <BRep_Tool.hxx>
19 #include <TopoDS_Edge.hxx>
20 #include <IMeshData_Edge.hxx>
21 #include <IMeshData_PCurve.hxx>
22 #include <IMeshTools_Parameters.hxx>
23 #include <TopExp_Explorer.hxx>
24 #include <Geom_Plane.hxx>
25 #include <TopExp.hxx>
26 #include <Adaptor3d_HCurveOnSurface.hxx>
27 #include <Adaptor2d_HCurve2d.hxx>
28 #include <Standard_Failure.hxx>
29
30 //=======================================================================
31 //function : Constructor
32 //purpose  : 
33 //=======================================================================
34 BRepMesh_CurveTessellator::BRepMesh_CurveTessellator(
35   const IMeshData::IEdgeHandle& theEdge,
36   const IMeshTools_Parameters&  theParameters)
37   : myDEdge(theEdge),
38     myParameters(theParameters),
39     myEdge(theEdge->GetEdge()),
40     myCurve(myEdge)
41 {
42   init();
43 }
44
45 //=======================================================================
46 //function : Constructor
47 //purpose  : 
48 //=======================================================================
49 BRepMesh_CurveTessellator::BRepMesh_CurveTessellator (
50   const IMeshData::IEdgeHandle& theEdge,
51   const TopAbs_Orientation      theOrientation,
52   const IMeshData::IFaceHandle& theFace,
53   const IMeshTools_Parameters&  theParameters)
54   : myDEdge(theEdge),
55     myParameters(theParameters),
56     myEdge(TopoDS::Edge(theEdge->GetEdge().Oriented(theOrientation))),
57     myCurve(myEdge, theFace->GetFace())
58 {
59   init();
60 }
61
62 //=======================================================================
63 //function : init
64 //purpose  : 
65 //=======================================================================
66 void BRepMesh_CurveTessellator::init()
67 {
68   if (myParameters.MinSize <= 0.0)
69   {
70     Standard_Failure::Raise ("The structure \"myParameters\" is not initialized");
71   }
72
73   TopExp::Vertices(myEdge, myFirstVertex, myLastVertex);
74
75   Standard_Real aPreciseAngDef = 0.5 * myDEdge->GetAngularDeflection();
76   Standard_Real aPreciseLinDef = 0.5 * myDEdge->GetDeflection();
77   if (myEdge.Orientation() == TopAbs_INTERNAL)
78   {
79     aPreciseLinDef *= 0.5;
80   }
81
82   mySquareEdgeDef = aPreciseLinDef * aPreciseLinDef;
83   mySquareMinSize = Max(mySquareEdgeDef, myParameters.MinSize * myParameters.MinSize);
84
85   myEdgeSqTol  = BRep_Tool::Tolerance(myEdge);
86   myEdgeSqTol *= myEdgeSqTol;
87
88   const Standard_Integer aMinPntNb = (myCurve.GetType() == GeomAbs_Circle) ? 4 : 2; //OCC287
89
90   myDiscretTool.Initialize(myCurve,
91                            myCurve.FirstParameter(), myCurve.LastParameter(),
92                            aPreciseAngDef, aPreciseLinDef, aMinPntNb,
93                            Precision::PConfusion(), myParameters.MinSize);
94
95   if (myCurve.IsCurveOnSurface())
96   {
97     const Adaptor3d_CurveOnSurface& aCurve = myCurve.CurveOnSurface();
98     const Handle(Adaptor3d_HSurface)& aSurface = aCurve.GetSurface();
99
100     const Standard_Real aTol = Precision::Confusion();
101     const Standard_Real aDu = aSurface->UResolution(aTol);
102     const Standard_Real aDv = aSurface->VResolution(aTol);
103
104     myFaceRangeU[0] = aSurface->FirstUParameter() - aDu;
105     myFaceRangeU[1] = aSurface->LastUParameter()  + aDu;
106
107     myFaceRangeV[0] = aSurface->FirstVParameter() - aDv;
108     myFaceRangeV[1] = aSurface->LastVParameter()  + aDv;
109   }
110
111   addInternalVertices();
112   splitByDeflection2d();
113 }
114
115 //=======================================================================
116 //function : Destructor
117 //purpose  : 
118 //=======================================================================
119 BRepMesh_CurveTessellator::~BRepMesh_CurveTessellator ()
120 {
121 }
122
123 //=======================================================================
124 //function : NbPoints
125 //purpose  : 
126 //=======================================================================
127 Standard_Integer BRepMesh_CurveTessellator::PointsNb () const
128 {
129   return myDiscretTool.NbPoints ();
130 }
131
132 //=======================================================================
133 //function : splitByDeflection2d
134 //purpose  : 
135 //=======================================================================
136 void BRepMesh_CurveTessellator::splitByDeflection2d ()
137 {
138   const Standard_Integer aNodesNb = myDiscretTool.NbPoints ();
139   if (!myDEdge->IsFree ()      &&
140       myDEdge->GetSameParam () &&
141       myDEdge->GetSameRange () &&
142       aNodesNb > 1)
143   {
144     for (Standard_Integer aPCurveIt = 0; aPCurveIt < myDEdge->PCurvesNb (); ++aPCurveIt)
145     {
146       TopLoc_Location aLoc;
147       const IMeshData::IPCurveHandle& aPCurve = myDEdge->GetPCurve(aPCurveIt);
148       const TopoDS_Face&              aFace   = aPCurve->GetFace ()->GetFace ();
149       const Handle (Geom_Surface)&    aSurface = BRep_Tool::Surface (aFace, aLoc);
150       if (aSurface->IsInstance(STANDARD_TYPE(Geom_Plane)))
151       {
152         continue;
153       }
154
155       const TopoDS_Edge aCurrEdge = TopoDS::Edge(myEdge.Oriented(aPCurve->GetOrientation()));
156
157       Standard_Real aF, aL;
158       Handle (Geom2d_Curve) aCurve2d = BRep_Tool::CurveOnSurface (aCurrEdge, aFace, aF, aL);
159       TColStd_Array1OfReal aParamArray (1, aNodesNb);
160       for (Standard_Integer i = 1; i <= aNodesNb; ++i)
161         aParamArray.SetValue (i, myDiscretTool.Parameter (i));
162
163       for (Standard_Integer i = 1; i < aNodesNb; ++i)
164         splitSegment (aSurface, aCurve2d, aParamArray (i), aParamArray (i + 1), 1);
165     }
166   }
167 }
168
169 //=======================================================================
170 //function : addInternalVertices
171 //purpose  : 
172 //=======================================================================
173 void BRepMesh_CurveTessellator::addInternalVertices ()
174 {
175   // PTv, chl/922/G9, Take into account internal vertices
176   // it is necessary for internal edges, which do not split other edges, by their vertex
177   TopExp_Explorer aVertexIt (myEdge, TopAbs_VERTEX);
178   for (; aVertexIt.More (); aVertexIt.Next ())
179   {
180     const TopoDS_Vertex& aVertex = TopoDS::Vertex (aVertexIt.Current ());
181     if (aVertex.Orientation() != TopAbs_INTERNAL)
182     {
183       continue;
184     }
185
186     myDiscretTool.AddPoint (BRep_Tool::Pnt (aVertex),
187       BRep_Tool::Parameter (aVertex, myEdge), Standard_True);
188   }
189 }
190
191 //=======================================================================
192 //function : isInToleranceOfVertex
193 //purpose  : 
194 //=======================================================================
195 Standard_Boolean BRepMesh_CurveTessellator::isInToleranceOfVertex (
196   const gp_Pnt&        thePoint,
197   const TopoDS_Vertex& theVertex) const
198 {
199   const gp_Pnt        aPoint     = BRep_Tool::Pnt(theVertex);
200   const Standard_Real aTolerance = BRep_Tool::Tolerance(theVertex);
201
202   return (thePoint.SquareDistance (aPoint) < aTolerance * aTolerance);
203 }
204
205 //=======================================================================
206 //function : Value
207 //purpose  : 
208 //=======================================================================
209 Standard_Boolean BRepMesh_CurveTessellator::Value (
210   const Standard_Integer theIndex,
211   gp_Pnt&                thePoint,
212   Standard_Real&         theParameter) const
213 {
214   thePoint     = myDiscretTool.Value     (theIndex);
215   theParameter = myDiscretTool.Parameter (theIndex);
216
217   /*if (!isInToleranceOfVertex(thePoint, myFirstVertex) &&
218       !isInToleranceOfVertex(thePoint, myLastVertex))
219   {*/
220     if (!myCurve.IsCurveOnSurface())
221     {
222       return Standard_True;
223     }
224
225     // If point coordinates are out of surface range, 
226     // it is necessary to re-project point.
227     const Adaptor3d_CurveOnSurface& aCurve = myCurve.CurveOnSurface();
228     const Handle(Adaptor3d_HSurface)& aSurface = aCurve.GetSurface();
229     if (aSurface->GetType() != GeomAbs_BSplineSurface &&
230         aSurface->GetType() != GeomAbs_BezierSurface  &&
231         aSurface->GetType() != GeomAbs_OtherSurface)
232     {
233       return Standard_True;
234     }
235
236     // Let skip periodic case.
237     if (aSurface->IsUPeriodic() || aSurface->IsVPeriodic())
238     {
239       return Standard_True;
240     }
241
242     gp_Pnt2d aUV;
243     aCurve.GetCurve()->D0(theParameter, aUV);
244     // Point lies within the surface range - nothing to do.
245     if (aUV.X() > myFaceRangeU[0] && aUV.X() < myFaceRangeU[1] &&
246         aUV.Y() > myFaceRangeV[0] && aUV.Y() < myFaceRangeV[1])
247     {
248       return Standard_True;
249     }
250
251     gp_Pnt aPntOnSurf;
252     aSurface->D0(aUV.X(), aUV.Y(), aPntOnSurf);
253
254     return (thePoint.SquareDistance(aPntOnSurf) < myEdgeSqTol);
255   /*}
256
257   return Standard_False;*/
258 }
259
260 //=======================================================================
261 //function : splitSegment
262 //purpose  : 
263 //=======================================================================
264 void BRepMesh_CurveTessellator::splitSegment (
265   const Handle (Geom_Surface)& theSurf,
266   const Handle (Geom2d_Curve)& theCurve2d,
267   const Standard_Real          theFirst,
268   const Standard_Real          theLast,
269   const Standard_Integer       theNbIter)
270 {
271   // limit iteration depth
272   if (theNbIter > 10)
273   {
274     return;
275   }
276
277   gp_Pnt2d uvf, uvl, uvm;
278   gp_Pnt   P3dF, P3dL, midP3d, midP3dFromSurf;
279   Standard_Real midpar;
280
281   if (Abs(theLast - theFirst) < 2 * Precision::PConfusion())
282   {
283     return;
284   }
285
286   if ((theCurve2d->FirstParameter() - theFirst > Precision::PConfusion()) ||
287       (theLast - theCurve2d->LastParameter() > Precision::PConfusion()))
288   {
289     // E.g. test bugs moddata_3 bug30133
290     return;
291   }
292
293   theCurve2d->D0 (theFirst, uvf);
294   theCurve2d->D0 (theLast, uvl);
295
296   P3dF = theSurf->Value (uvf.X (), uvf.Y ());
297   P3dL = theSurf->Value (uvl.X (), uvl.Y ());
298
299   if (P3dF.SquareDistance(P3dL) < mySquareMinSize)
300   {
301     return;
302   }
303
304   uvm = gp_Pnt2d ((uvf.XY () + uvl.XY ())*0.5);
305   midP3dFromSurf = theSurf->Value (uvm.X (), uvm.Y ());
306
307   gp_XYZ Vec1 = midP3dFromSurf.XYZ () - P3dF.XYZ ();
308   if (Vec1.SquareModulus() < mySquareMinSize)
309   {
310     return;
311   }
312
313   gp_XYZ aVec = P3dL.XYZ () - P3dF.XYZ ();
314   aVec.Normalize ();
315
316   Standard_Real aModulus = Vec1.Dot (aVec);
317   gp_XYZ aProj = aVec * aModulus;
318   gp_XYZ aDist = Vec1 - aProj;
319
320   if (aDist.SquareModulus() < mySquareEdgeDef)
321   {
322     return;
323   }
324
325   midpar = (theFirst + theLast) * 0.5;
326   myCurve.D0 (midpar, midP3d);
327   myDiscretTool.AddPoint (midP3d, midpar, Standard_False);
328
329   splitSegment (theSurf, theCurve2d, theFirst, midpar, theNbIter + 1);
330   splitSegment (theSurf, theCurve2d, midpar, theLast, theNbIter + 1);
331 }