0025113: Mesh - Progress indication and user break functionality for BRepMesh component
[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::performInternal (
87   const Handle (IMeshData_Model)& theModel,
88   const IMeshTools_Parameters&    theParameters,
89   const Message_ProgressRange&    theRange)
90 {
91   (void )theRange;
92   myModel      = theModel;
93   myParameters = theParameters;
94
95   if (myModel.IsNull())
96   {
97     return Standard_False;
98   }
99
100   OSD_Parallel::For (0, myModel->EdgesNb (), *this, !myParameters.InParallel);
101
102   myModel.Nullify(); // Do not hold link to model.
103   return Standard_True;
104 }
105
106 //=======================================================================
107 // Function: process
108 // Purpose : 
109 //=======================================================================
110 void BRepMesh_EdgeDiscret::process (const Standard_Integer theEdgeIndex) const
111 {
112   const IMeshData::IEdgeHandle& aDEdge = myModel->GetEdge (theEdgeIndex);
113   try
114   {
115     OCC_CATCH_SIGNALS
116
117     BRepMesh_Deflection::ComputeDeflection (aDEdge, myModel->GetMaxSize (), myParameters);
118   
119     Handle (IMeshTools_CurveTessellator) aEdgeTessellator;
120     if (!aDEdge->IsFree ())
121     {
122       // Iterate over pcurves and check deflection on corresponding face.
123       Standard_Real    aMinDeflection = RealLast ();
124       Standard_Integer aMinPCurveIndex = -1;
125       for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb (); ++aPCurveIt)
126       {
127         const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve (aPCurveIt);
128         const Standard_Real aTmpDeflection = checkExistingPolygonAndUpdateStatus(aDEdge, aPCurve);
129         if (aTmpDeflection < aMinDeflection)
130         {
131           // Identify pcurve with the smallest deflection in order to
132           // retrieve polygon that represents the most smooth discretization.
133           aMinDeflection  = aTmpDeflection;
134           aMinPCurveIndex = aPCurveIt;
135         }
136   
137         BRepMesh_ShapeTool::CheckAndUpdateFlags (aDEdge, aPCurve);
138       }
139   
140       if (aMinPCurveIndex != -1)
141       {
142         aDEdge->SetDeflection (aMinDeflection);
143         const IMeshData::IFaceHandle aDFace = aDEdge->GetPCurve(aMinPCurveIndex)->GetFace();
144         aEdgeTessellator = CreateEdgeTessellationExtractor(aDEdge, aDFace);
145       }
146       else
147       {
148         const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(0);
149         const IMeshData::IFaceHandle    aDFace  = aPCurve->GetFace();
150         aEdgeTessellator = BRepMesh_EdgeDiscret::CreateEdgeTessellator(
151           aDEdge, aPCurve->GetOrientation(), aDFace, myParameters);
152       }
153     }
154     else
155     {
156       TopLoc_Location aLoc;
157       const Handle (Poly_Polygon3D)& aPoly3D = BRep_Tool::Polygon3D (aDEdge->GetEdge (), aLoc);
158       if (!aPoly3D.IsNull ())
159       {
160         if (aPoly3D->HasParameters() &&
161             BRepMesh_Deflection::IsConsistent (aPoly3D->Deflection(),
162                                                aDEdge->GetDeflection(),
163                                                myParameters.AllowQualityDecrease))
164         {
165           // Edge already has suitable 3d polygon.
166           aDEdge->SetStatus(IMeshData_Reused);
167           return;
168         }
169         else
170         {
171           aDEdge->SetStatus(IMeshData_Outdated);
172         }
173       }
174   
175       aEdgeTessellator = CreateEdgeTessellator(aDEdge, myParameters);
176     }
177   
178     Tessellate3d (aDEdge, aEdgeTessellator, Standard_True);
179     if (!aDEdge->IsFree())
180     {
181       Tessellate2d(aDEdge, Standard_True);
182     }
183   }
184   catch (Standard_Failure const&)
185   {
186     aDEdge->SetStatus (IMeshData_Failure);
187   }
188 }
189
190 //=======================================================================
191 // Function: checkExistingPolygonAndUpdateStatus
192 // Purpose : 
193 //=======================================================================
194 Standard_Real BRepMesh_EdgeDiscret::checkExistingPolygonAndUpdateStatus(
195   const IMeshData::IEdgeHandle&   theDEdge,
196   const IMeshData::IPCurveHandle& thePCurve) const
197 {
198   const TopoDS_Edge& aEdge = theDEdge->GetEdge ();
199   const TopoDS_Face& aFace = thePCurve->GetFace ()->GetFace ();
200
201   TopLoc_Location aLoc;
202   const Handle (Poly_Triangulation)& aFaceTriangulation =
203     BRep_Tool::Triangulation (aFace, aLoc);
204
205   Standard_Real aDeflection = RealLast ();
206   if (aFaceTriangulation.IsNull())
207   {
208     return aDeflection;
209   }
210
211   const Handle (Poly_PolygonOnTriangulation)& aPolygon =
212     BRep_Tool::PolygonOnTriangulation (aEdge, aFaceTriangulation, aLoc);
213
214   if (!aPolygon.IsNull ())
215   {
216     Standard_Boolean isConsistent = aPolygon->HasParameters() &&
217       BRepMesh_Deflection::IsConsistent (aPolygon->Deflection(),
218                                          theDEdge->GetDeflection(),
219                                          myParameters.AllowQualityDecrease);
220
221     if (!isConsistent)
222     {
223       // Nullify edge data and mark discrete pcurve to 
224       // notify necessity to mesh the entire face.
225       theDEdge->SetStatus(IMeshData_Outdated);
226     }
227     else
228     {
229       aDeflection = aPolygon->Deflection();
230     }
231   }
232
233   return aDeflection;
234 }
235
236 //=======================================================================
237 // Function: Tessellate3d
238 // Purpose : 
239 //=======================================================================
240 void BRepMesh_EdgeDiscret::Tessellate3d(
241   const IMeshData::IEdgeHandle&               theDEdge,
242   const Handle (IMeshTools_CurveTessellator)& theTessellator,
243   const Standard_Boolean                      theUpdateEnds)
244 {
245   // Create 3d polygon.
246   const IMeshData::ICurveHandle& aCurve = theDEdge->GetCurve();
247
248   const TopoDS_Edge& aEdge = theDEdge->GetEdge();
249   TopoDS_Vertex aFirstVertex, aLastVertex;
250   TopExp::Vertices(aEdge, aFirstVertex, aLastVertex);
251
252   if(aFirstVertex.IsNull() || aLastVertex.IsNull())
253     return;
254
255   if (theUpdateEnds)
256   {
257     gp_Pnt aPoint;
258     Standard_Real aParam;
259     theTessellator->Value(1, aPoint, aParam);
260     aCurve->AddPoint(BRep_Tool::Pnt(aFirstVertex), aParam);
261   }
262
263   if (!theDEdge->GetDegenerated())
264   {
265     for (Standard_Integer i = 2; i < theTessellator->PointsNb(); ++i)
266     {
267       gp_Pnt aPoint;
268       Standard_Real aParam;
269       if (!theTessellator->Value(i, aPoint, aParam))
270         continue;
271
272       if (theUpdateEnds)
273       {
274         aCurve->AddPoint(aPoint, aParam);
275       }
276       else
277       {
278         aCurve->InsertPoint(aCurve->ParametersNb() - 1, aPoint, aParam);
279       }
280     }
281   }
282
283   if (theUpdateEnds)
284   {
285     gp_Pnt aPoint;
286     Standard_Real aParam;
287     theTessellator->Value(theTessellator->PointsNb(), aPoint, aParam);
288     aCurve->AddPoint(BRep_Tool::Pnt(aLastVertex), aParam);
289   }
290 }
291
292 //=======================================================================
293 // Function: Tessellate2d
294 // Purpose : 
295 //=======================================================================
296 void BRepMesh_EdgeDiscret::Tessellate2d(
297   const IMeshData::IEdgeHandle& theDEdge,
298   const Standard_Boolean        theUpdateEnds)
299 {
300   const IMeshData::ICurveHandle& aCurve = theDEdge->GetCurve();
301   for (Standard_Integer aPCurveIt = 0; aPCurveIt < theDEdge->PCurvesNb(); ++aPCurveIt)
302   {
303     const IMeshData::IPCurveHandle& aPCurve = theDEdge->GetPCurve(aPCurveIt);
304     const IMeshData::IFaceHandle    aDFace  = aPCurve->GetFace();
305     IMeshData::ICurveArrayAdaptorHandle aCurveArray(new IMeshData::ICurveArrayAdaptor(aCurve));
306     BRepMesh_EdgeParameterProvider<IMeshData::ICurveArrayAdaptorHandle> aProvider(
307       theDEdge, aPCurve->GetOrientation(), aDFace, aCurveArray);
308
309     const Handle(Adaptor2d_HCurve2d)& aGeomPCurve = aProvider.GetPCurve();
310
311     Standard_Integer aParamIdx, aParamNb;
312     if (theUpdateEnds)
313     {
314       aParamIdx = 0;
315       aParamNb  = aCurve->ParametersNb();
316     }
317     else
318     {
319       aParamIdx = 1;
320       aParamNb  = aCurve->ParametersNb() - 1;
321     }
322
323     for (; aParamIdx < aParamNb; ++aParamIdx)
324     {
325       const Standard_Real aParam = aProvider.Parameter(aParamIdx, aCurve->GetPoint(aParamIdx));
326
327       gp_Pnt2d aPoint2d;
328       aGeomPCurve->D0(aParam, aPoint2d);
329       if (theUpdateEnds)
330       {
331         aPCurve->AddPoint(aPoint2d, aParam);
332       }
333       else
334       {
335         aPCurve->InsertPoint(aPCurve->ParametersNb() - 1, aPoint2d, aParam);
336       }
337     }
338   }
339 }