0025113: Mesh - Progress indication and user break functionality for BRepMesh component
[occt.git] / src / BRepMesh / BRepMesh_ModelPreProcessor.cxx
1 // Created on: 2016-07-04
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_ModelPreProcessor.hxx>
17 #include <BRepMesh_Deflection.hxx>
18 #include <BRepMesh_ShapeTool.hxx>
19 #include <BRep_Tool.hxx>
20 #include <IMeshData_Model.hxx>
21 #include <IMeshData_Edge.hxx>
22 #include <IMeshData_Wire.hxx>
23 #include <IMeshData_PCurve.hxx>
24 #include <OSD_Parallel.hxx>
25 #include <BRepMesh_ConeRangeSplitter.hxx>
26
27 namespace
28 {
29   //! Checks consistency of triangulation stored in topological face.
30   class TriangulationConsistency
31   {
32   public:
33     //! Constructor
34     TriangulationConsistency(const Handle(IMeshData_Model)& theModel,
35                              const Standard_Boolean theAllowQualityDecrease)
36       : myModel (theModel)
37       , myAllowQualityDecrease (theAllowQualityDecrease)
38     {
39     }
40
41     //! Main functor.
42     void operator()(const Standard_Integer theFaceIndex) const
43     {
44       const IMeshData::IFaceHandle& aDFace = myModel->GetFace(theFaceIndex);
45       if (aDFace->IsSet(IMeshData_Outdated))
46       {
47         return;
48       }
49
50       TopLoc_Location aLoc;
51       const Handle(Poly_Triangulation)& aTriangulation =
52         BRep_Tool::Triangulation(aDFace->GetFace(), aLoc);
53
54       if (!aTriangulation.IsNull())
55       {
56         Standard_Boolean isTriangulationConsistent = 
57           BRepMesh_Deflection::IsConsistent (aTriangulation->Deflection(),
58                                              aDFace->GetDeflection(),
59                                              myAllowQualityDecrease);
60
61         if (isTriangulationConsistent)
62         {
63           // #25080: check that indices of links forming triangles are in range.
64           const Standard_Integer aNodesNb = aTriangulation->NbNodes();
65           const Poly_Array1OfTriangle& aTriangles = aTriangulation->Triangles();
66
67           Standard_Integer i = aTriangles.Lower();
68           for (; i <= aTriangles.Upper() && isTriangulationConsistent; ++i)
69           {
70             const Poly_Triangle& aTriangle = aTriangles(i);
71
72             Standard_Integer aNode[3];
73             aTriangle.Get(aNode[0], aNode[1], aNode[2]);
74             for (Standard_Integer j = 0; j < 3 && isTriangulationConsistent; ++j)
75             {
76               isTriangulationConsistent = (aNode[j] >= 1 && aNode[j] <= aNodesNb);
77             }
78           }
79         }
80
81         if (isTriangulationConsistent)
82         {
83           aDFace->SetStatus(IMeshData_Reused);
84           aDFace->SetDeflection(aTriangulation->Deflection());
85         }
86         else
87         {
88           aDFace->SetStatus(IMeshData_Outdated);
89         }
90       }
91     }
92
93   private:
94
95     Handle(IMeshData_Model) myModel;
96     Standard_Boolean myAllowQualityDecrease; //!< Flag used for consistency check
97   };
98
99   //! Adds additional points to seam edges on specific surfaces.
100   class SeamEdgeAmplifier
101   {
102   public:
103     //! Constructor
104     SeamEdgeAmplifier(const Handle(IMeshData_Model)& theModel,
105                       const IMeshTools_Parameters&   theParameters)
106       : myModel (theModel)
107       , myParameters (theParameters)
108     {
109     }
110
111     //! Main functor.
112     void operator()(const Standard_Integer theFaceIndex) const
113     {
114       const IMeshData::IFaceHandle& aDFace = myModel->GetFace(theFaceIndex);
115       if (aDFace->GetSurface()->GetType() != GeomAbs_Cone)
116       {
117         return;
118       }
119
120       const IMeshData::IWireHandle& aDWire = aDFace->GetWire (0);
121       for (Standard_Integer aEdgeIdx = 0; aEdgeIdx < aDWire->EdgesNb() - 1; ++aEdgeIdx)
122       {
123         const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge (aEdgeIdx);
124         
125         if (aDEdge->GetPCurve(aDFace.get(), TopAbs_FORWARD) != aDEdge->GetPCurve(aDFace.get(), TopAbs_REVERSED))
126         {
127           if (aDEdge->GetCurve()->ParametersNb() == 2)
128           {
129             if (splitEdge (aDEdge, Abs (getConeStep (aDFace))))
130             {
131               TopLoc_Location aLoc;
132               const Handle (Poly_Triangulation)& aTriangulation =
133                 BRep_Tool::Triangulation (aDFace->GetFace (), aLoc);
134
135               if (!aTriangulation.IsNull ())
136               {
137                 aDFace->SetStatus (IMeshData_Outdated);
138               }
139             }
140           }
141           return;
142         } 
143       }
144     }
145
146   private:
147
148     //! Returns step for splitting seam edge of a cone.
149     Standard_Real getConeStep(const IMeshData::IFaceHandle& theDFace) const
150     {
151       BRepMesh_ConeRangeSplitter aSplitter;
152       aSplitter.Reset (theDFace, myParameters);
153
154       const IMeshData::IWireHandle& aDWire = theDFace->GetWire (0);
155       for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt)
156       {
157         const IMeshData::IEdgeHandle    aDEdge  = aDWire->GetEdge(aEdgeIt);
158         const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(
159           theDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt));
160
161         for (Standard_Integer aPointIt = 0; aPointIt < aPCurve->ParametersNb(); ++aPointIt)
162         {
163           const gp_Pnt2d& aPnt2d = aPCurve->GetPoint(aPointIt);
164           aSplitter.AddPoint(aPnt2d);
165         }
166       }
167
168       std::pair<Standard_Integer, Standard_Integer> aStepsNb;
169       std::pair<Standard_Real, Standard_Real> aSteps = aSplitter.GetSplitSteps (myParameters, aStepsNb);
170       return aSteps.second;
171     } 
172
173     //! Splits 3D and all pcurves accoring using the specified step.
174     Standard_Boolean splitEdge(const IMeshData::IEdgePtr& theDEdge,
175                                const Standard_Real        theDU) const
176     {
177       if (!splitCurve<gp_XYZ> (theDEdge->GetCurve (), theDU))
178       {
179         return Standard_False;
180       }
181
182       for (Standard_Integer aPCurveIdx = 0; aPCurveIdx < theDEdge->PCurvesNb(); ++aPCurveIdx)
183       {
184         splitCurve<gp_XY> (theDEdge->GetPCurve (aPCurveIdx), theDU);
185       }
186
187       return Standard_True;
188     }
189
190     //! Splits the given curve using the specified step.
191     template<class PointType, class Curve>
192     Standard_Boolean splitCurve(Curve& theCurve, const Standard_Real theDU) const
193     {
194       Standard_Boolean isUpdated = Standard_False;
195       PointType aDir = theCurve->GetPoint(theCurve->ParametersNb() - 1).Coord() - theCurve->GetPoint(0).Coord();
196       const Standard_Real aModulus = aDir.Modulus();
197       if (aModulus < gp::Resolution())
198       {
199         return isUpdated;
200       }
201       aDir /= aModulus;
202
203       const Standard_Real    aLastParam = theCurve->GetParameter(theCurve->ParametersNb() - 1);
204       const Standard_Boolean isReversed = theCurve->GetParameter(0) > aLastParam;  
205       for (Standard_Integer aPointIdx = 1; ; ++aPointIdx)
206       {
207         const Standard_Real aCurrParam = theCurve->GetParameter(0) + aPointIdx * theDU * (isReversed ? -1.0 : 1.0); 
208         if (( isReversed &&  (aCurrParam < aLastParam)) ||
209             (!isReversed && !(aCurrParam < aLastParam)))
210         {
211           break;
212         }
213
214         theCurve->InsertPoint(theCurve->ParametersNb() - 1,
215           theCurve->GetPoint(0).Translated (aDir * aPointIdx * theDU),
216           aCurrParam);
217
218         isUpdated = Standard_True;
219       }
220
221       return isUpdated;
222     }
223
224   private:
225
226     Handle(IMeshData_Model) myModel;
227     IMeshTools_Parameters   myParameters;
228   };
229 }
230
231 //=======================================================================
232 // Function: Constructor
233 // Purpose : 
234 //=======================================================================
235 BRepMesh_ModelPreProcessor::BRepMesh_ModelPreProcessor()
236 {
237 }
238
239 //=======================================================================
240 // Function: Destructor
241 // Purpose : 
242 //=======================================================================
243 BRepMesh_ModelPreProcessor::~BRepMesh_ModelPreProcessor()
244 {
245 }
246
247 //=======================================================================
248 // Function: Perform
249 // Purpose : 
250 //=======================================================================
251 Standard_Boolean BRepMesh_ModelPreProcessor::performInternal(
252   const Handle(IMeshData_Model)& theModel,
253   const IMeshTools_Parameters&   theParameters,
254   const Message_ProgressRange&   theRange)
255 {
256   (void )theRange;
257   if (theModel.IsNull())
258   {
259     return Standard_False;
260   }
261
262   const Standard_Integer aFacesNb    = theModel->FacesNb();
263   const Standard_Boolean isOneThread = !theParameters.InParallel;
264   OSD_Parallel::For(0, aFacesNb, SeamEdgeAmplifier        (theModel, theParameters),                      isOneThread);
265   OSD_Parallel::For(0, aFacesNb, TriangulationConsistency (theModel, theParameters.AllowQualityDecrease), isOneThread);
266
267   // Clean edges and faces from outdated polygons.
268   Handle(NCollection_IncAllocator) aTmpAlloc(new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE));
269   NCollection_Map<IMeshData_Face*> aUsedFaces(1, aTmpAlloc);
270   for (Standard_Integer aEdgeIt = 0; aEdgeIt < theModel->EdgesNb(); ++aEdgeIt)
271   {
272     const IMeshData::IEdgeHandle& aDEdge = theModel->GetEdge(aEdgeIt);
273     if (aDEdge->IsFree())
274     {
275       if (aDEdge->IsSet(IMeshData_Outdated))
276       {
277         TopLoc_Location aLoc;
278         BRep_Tool::Polygon3D(aDEdge->GetEdge(), aLoc);
279         BRepMesh_ShapeTool::NullifyEdge(aDEdge->GetEdge(), aLoc);
280       }
281
282       continue;
283     }
284     
285     for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb(); ++aPCurveIt)
286     {
287       // Find adjacent outdated face.
288       const IMeshData::IFaceHandle aDFace = aDEdge->GetPCurve(aPCurveIt)->GetFace();
289       if (!aUsedFaces.Contains(aDFace.get()))
290       {
291         aUsedFaces.Add(aDFace.get());
292         if (aDFace->IsSet(IMeshData_Outdated))
293         {
294           TopLoc_Location aLoc;
295           const Handle(Poly_Triangulation)& aTriangulation =
296             BRep_Tool::Triangulation(aDFace->GetFace(), aLoc);
297
298           // Clean all edges of oudated face.
299           for (Standard_Integer aWireIt = 0; aWireIt < aDFace->WiresNb(); ++aWireIt)
300           {
301             const IMeshData::IWireHandle& aDWire = aDFace->GetWire(aWireIt);
302             for (Standard_Integer aWireEdgeIt = 0; aWireEdgeIt < aDWire->EdgesNb(); ++aWireEdgeIt)
303             {
304               const IMeshData::IEdgeHandle aTmpDEdge = aDWire->GetEdge(aWireEdgeIt);
305               BRepMesh_ShapeTool::NullifyEdge(aTmpDEdge->GetEdge(), aTriangulation, aLoc);
306             }
307           }
308
309           BRepMesh_ShapeTool::NullifyFace(aDFace->GetFace());
310         }
311       }
312     }
313   }
314
315   return Standard_True;
316 }
317