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