0026106: BRepMesh - revision of data model
[occt.git] / src / BRepMesh / BRepMesh_EdgeDiscret.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_EdgeDiscret.hxx>
17 #include <BRepMesh_Deflection.hxx>
18 #include <IMeshData_Model.hxx>
19 #include <IMeshData_Edge.hxx>
20 #include <IMeshData_Face.hxx>
21 #include <IMeshData_PCurve.hxx>
22 #include <TopExp.hxx>
23 #include <BRepMesh_ShapeTool.hxx>
24 #include <BRepMesh_EdgeTessellationExtractor.hxx>
25 #include <IMeshData_ParametersListArrayAdaptor.hxx>
26 #include <BRepMesh_CurveTessellator.hxx>
27 #include <OSD_Parallel.hxx>
28
29 //=======================================================================
30 // Function: Constructor
31 // Purpose : 
32 //=======================================================================
33 BRepMesh_EdgeDiscret::BRepMesh_EdgeDiscret ()
34 {
35 }
36
37 //=======================================================================
38 // Function: Destructor
39 // Purpose : 
40 //=======================================================================
41 BRepMesh_EdgeDiscret::~BRepMesh_EdgeDiscret ()
42 {
43 }
44
45 //=======================================================================
46 // Function: CreateFreeEdgeTessellator
47 // Purpose : 
48 //=======================================================================
49 Handle(IMeshTools_CurveTessellator) BRepMesh_EdgeDiscret::CreateEdgeTessellator(
50   const IMeshData::IEdgeHandle& theDEdge,
51   const IMeshTools_Parameters&  theParameters)
52 {
53   return new BRepMesh_CurveTessellator(theDEdge, theParameters);
54 }
55
56 //=======================================================================
57 // Function: CreateEdgeTessellator
58 // Purpose : 
59 //=======================================================================
60 Handle(IMeshTools_CurveTessellator) BRepMesh_EdgeDiscret::CreateEdgeTessellator(
61   const IMeshData::IEdgeHandle& theDEdge,
62   const TopAbs_Orientation      theOrientation,
63   const IMeshData::IFaceHandle& theDFace,
64   const IMeshTools_Parameters&  theParameters)
65 {
66   return theDEdge->GetSameParam() ? 
67     new BRepMesh_CurveTessellator(theDEdge, theParameters) :
68     new BRepMesh_CurveTessellator(theDEdge, theOrientation, theDFace, theParameters);
69 }
70
71 //=======================================================================
72 // Function: CreateEdgeTessellationExtractor
73 // Purpose : 
74 //=======================================================================
75 Handle(IMeshTools_CurveTessellator) BRepMesh_EdgeDiscret::CreateEdgeTessellationExtractor(
76   const IMeshData::IEdgeHandle& theDEdge,
77   const IMeshData::IFaceHandle& theDFace)
78 {
79   return new BRepMesh_EdgeTessellationExtractor(theDEdge, theDFace);
80 }
81
82 //=======================================================================
83 // Function: Perform
84 // Purpose : 
85 //=======================================================================
86 Standard_Boolean BRepMesh_EdgeDiscret::Perform (
87   const Handle (IMeshData_Model)& theModel,
88   const IMeshTools_Parameters&    theParameters)
89 {
90   myModel      = theModel;
91   myParameters = theParameters;
92
93   if (myModel.IsNull())
94   {
95     return Standard_False;
96   }
97
98   OSD_Parallel::For (0, myModel->EdgesNb (), *this, !myParameters.InParallel);
99
100   myModel.Nullify(); // Do not hold link to model.
101   return Standard_True;
102 }
103
104 //=======================================================================
105 // Function: process
106 // Purpose : 
107 //=======================================================================
108 void BRepMesh_EdgeDiscret::process (const Standard_Integer theEdgeIndex) const
109 {
110   const IMeshData::IEdgeHandle& aDEdge = myModel->GetEdge (theEdgeIndex);
111   BRepMesh_Deflection::ComputeDeflection (aDEdge, myModel->GetMaxSize (), myParameters);
112
113   Handle (IMeshTools_CurveTessellator) aEdgeTessellator;
114   if (!aDEdge->IsFree ())
115   {
116     // Iterate over pcurves and check deflection on corresponding face.
117     Standard_Real    aMinDeflection = RealLast ();
118     Standard_Integer aMinPCurveIndex = -1;
119     for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb (); ++aPCurveIt)
120     {
121       const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve (aPCurveIt);
122       const Standard_Real aTmpDeflection = checkExistingPolygonAndUpdateStatus(aDEdge, aPCurve);
123       if (aTmpDeflection < aMinDeflection)
124       {
125         // Identify pcurve with the smallest deflection in order to
126         // retrieve polygon that represents the most smooth discretization.
127         aMinDeflection  = aTmpDeflection;
128         aMinPCurveIndex = aPCurveIt;
129       }
130
131       BRepMesh_ShapeTool::CheckAndUpdateFlags (aDEdge, aPCurve);
132     }
133
134     if (aMinPCurveIndex != -1)
135     {
136       aDEdge->SetDeflection (aMinDeflection);
137       const IMeshData::IFaceHandle aDFace = aDEdge->GetPCurve(aMinPCurveIndex)->GetFace();
138       aEdgeTessellator = CreateEdgeTessellationExtractor(aDEdge, aDFace);
139     }
140     else
141     {
142       const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(0);
143       const IMeshData::IFaceHandle    aDFace  = aPCurve->GetFace();
144       aEdgeTessellator = BRepMesh_EdgeDiscret::CreateEdgeTessellator(
145         aDEdge, aPCurve->GetOrientation(), aDFace, myParameters);
146     }
147   }
148   else
149   {
150     TopLoc_Location aLoc;
151     const Handle (Poly_Polygon3D)& aPoly3D = BRep_Tool::Polygon3D (aDEdge->GetEdge (), aLoc);
152     if (!aPoly3D.IsNull ())
153     {
154       if (aPoly3D->HasParameters () &&
155           aPoly3D->Deflection () < 1.1 * aDEdge->GetDeflection ())
156       {
157         // Edge already has suitable 3d polygon.
158         aDEdge->SetStatus(IMeshData_Reused);
159         return;
160       }
161       else
162       {
163         aDEdge->SetStatus(IMeshData_Outdated);
164       }
165     }
166
167     aEdgeTessellator = CreateEdgeTessellator(aDEdge, myParameters);
168   }
169
170   Tessellate3d (aDEdge, aEdgeTessellator, Standard_True);
171   if (!aDEdge->IsFree())
172   {
173     Tessellate2d(aDEdge, Standard_True);
174   }
175 }
176
177 //=======================================================================
178 // Function: checkExistingPolygonAndUpdateStatus
179 // Purpose : 
180 //=======================================================================
181 Standard_Real BRepMesh_EdgeDiscret::checkExistingPolygonAndUpdateStatus(
182   const IMeshData::IEdgeHandle&   theDEdge,
183   const IMeshData::IPCurveHandle& thePCurve) const
184 {
185   const TopoDS_Edge& aEdge = theDEdge->GetEdge ();
186   const TopoDS_Face& aFace = thePCurve->GetFace ()->GetFace ();
187
188   TopLoc_Location aLoc;
189   const Handle (Poly_Triangulation)& aFaceTriangulation =
190     BRep_Tool::Triangulation (aFace, aLoc);
191
192   Standard_Real aDeflection = RealLast ();
193   if (aFaceTriangulation.IsNull())
194   {
195     return aDeflection;
196   }
197
198   const Handle (Poly_PolygonOnTriangulation)& aPolygon =
199     BRep_Tool::PolygonOnTriangulation (aEdge, aFaceTriangulation, aLoc);
200
201   if (!aPolygon.IsNull ())
202   {
203     Standard_Boolean isConsistent = aPolygon->HasParameters () &&
204       aPolygon->Deflection () < 1.1 * theDEdge->GetDeflection ();
205
206     if (!isConsistent)
207     {
208       // Nullify edge data and mark discrete pcurve to 
209       // notify necessity to mesh the entire face.
210       theDEdge->SetStatus(IMeshData_Outdated);
211     }
212     else
213     {
214       aDeflection = aPolygon->Deflection();
215     }
216   }
217
218   return aDeflection;
219 }
220
221 //=======================================================================
222 // Function: Tessellate3d
223 // Purpose : 
224 //=======================================================================
225 void BRepMesh_EdgeDiscret::Tessellate3d(
226   const IMeshData::IEdgeHandle&               theDEdge,
227   const Handle (IMeshTools_CurveTessellator)& theTessellator,
228   const Standard_Boolean                      theUpdateEnds)
229 {
230   // Create 3d polygon.
231   const IMeshData::ICurveHandle& aCurve = theDEdge->GetCurve();
232
233   const TopoDS_Edge& aEdge = theDEdge->GetEdge();
234   TopoDS_Vertex aFirstVertex, aLastVertex;
235   TopExp::Vertices(aEdge, aFirstVertex, aLastVertex);
236
237   if(aFirstVertex.IsNull() || aLastVertex.IsNull())
238     return;
239
240   if (theUpdateEnds)
241   {
242     gp_Pnt aPoint;
243     Standard_Real aParam;
244     theTessellator->Value(1, aPoint, aParam);
245     aCurve->AddPoint(BRep_Tool::Pnt(aFirstVertex), aParam);
246   }
247
248   if (!theDEdge->GetDegenerated())
249   {
250     for (Standard_Integer i = 2; i < theTessellator->PointsNb(); ++i)
251     {
252       gp_Pnt aPoint;
253       Standard_Real aParam;
254       if (!theTessellator->Value(i, aPoint, aParam))
255         continue;
256
257       if (theUpdateEnds)
258       {
259         aCurve->AddPoint(aPoint, aParam);
260       }
261       else
262       {
263         aCurve->InsertPoint(aCurve->ParametersNb() - 1, aPoint, aParam);
264       }
265     }
266   }
267
268   if (theUpdateEnds)
269   {
270     gp_Pnt aPoint;
271     Standard_Real aParam;
272     theTessellator->Value(theTessellator->PointsNb(), aPoint, aParam);
273     aCurve->AddPoint(BRep_Tool::Pnt(aLastVertex), aParam);
274   }
275 }
276
277 //=======================================================================
278 // Function: Tessellate2d
279 // Purpose : 
280 //=======================================================================
281 void BRepMesh_EdgeDiscret::Tessellate2d(
282   const IMeshData::IEdgeHandle& theDEdge,
283   const Standard_Boolean        theUpdateEnds)
284 {
285   const IMeshData::ICurveHandle& aCurve = theDEdge->GetCurve();
286   for (Standard_Integer aPCurveIt = 0; aPCurveIt < theDEdge->PCurvesNb(); ++aPCurveIt)
287   {
288     const IMeshData::IPCurveHandle& aPCurve = theDEdge->GetPCurve(aPCurveIt);
289     const IMeshData::IFaceHandle    aDFace  = aPCurve->GetFace();
290     IMeshData::ICurveArrayAdaptorHandle aCurveArray(new IMeshData::ICurveArrayAdaptor(aCurve));
291     BRepMesh_EdgeParameterProvider<IMeshData::ICurveArrayAdaptorHandle> aProvider(
292       theDEdge, aPCurve->GetOrientation(), aDFace, aCurveArray);
293
294     const Handle(Adaptor2d_HCurve2d)& aGeomPCurve = aProvider.GetPCurve();
295
296     Standard_Integer aParamIdx, aParamNb;
297     if (theUpdateEnds)
298     {
299       aParamIdx = 0;
300       aParamNb  = aCurve->ParametersNb();
301     }
302     else
303     {
304       aParamIdx = 1;
305       aParamNb  = aCurve->ParametersNb() - 1;
306     }
307
308     for (; aParamIdx < aParamNb; ++aParamIdx)
309     {
310       const Standard_Real aParam = aProvider.Parameter(aParamIdx, aCurve->GetPoint(aParamIdx));
311
312       gp_Pnt2d aPoint2d;
313       aGeomPCurve->D0(aParam, aPoint2d);
314       if (theUpdateEnds)
315       {
316         aPCurve->AddPoint(aPoint2d, aParam);
317       }
318       else
319       {
320         aPCurve->InsertPoint(aPCurve->ParametersNb() - 1, aPoint2d, aParam);
321       }
322     }
323   }
324 }