0025310: Regressions in visualization
[occt.git] / src / BRepMesh / BRepMesh_IncrementalMesh.cxx
1 // Created on: 1995-06-20
2 // Created by: Stagiaire Alain JOURDAIN
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <BRepMesh_IncrementalMesh.hxx>
18
19 #include <Precision.hxx>
20 #include <Standard_ErrorHandler.hxx>
21
22 #include <BRepMesh_FaceChecker.hxx>
23 #include <BRepMesh_ShapeTool.hxx>
24 #include <BRepMesh_Edge.hxx>
25 #include <BRepMesh_PluginMacro.hxx>
26
27 #include <Bnd_Box.hxx>
28 #include <BRep_Builder.hxx>
29 #include <BRep_Tool.hxx>
30 #include <BRepTools.hxx>
31 #include <BRepLib.hxx>
32 #include <BRepBndLib.hxx>
33 #include <BRepAdaptor_Curve.hxx>
34
35 #include <Poly_Triangulation.hxx>
36 #include <Poly_Polygon3D.hxx>
37 #include <Poly_PolygonOnTriangulation.hxx>
38
39 #include <TopoDS.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Shape.hxx>
43 #include <TopAbs.hxx>
44 #include <TopExp.hxx>
45 #include <TopExp_Explorer.hxx>
46
47 #include <TopTools_ListIteratorOfListOfShape.hxx>
48 #include <TColgp_Array1OfPnt.hxx>
49 #include <TColgp_Array1OfPnt2d.hxx>
50 #include <TColStd_Array1OfReal.hxx>
51 #include <TopTools_HArray1OfShape.hxx>
52 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
53
54 #include <GCPnts_TangentialDeflection.hxx>
55
56 #ifdef HAVE_TBB
57   // paralleling using Intel TBB
58   #include <tbb/parallel_for_each.h>
59 #endif
60
61 namespace
62 {
63   //! Default flag to control parallelization for BRepMesh_IncrementalMesh
64   //! tool returned for Mesh Factory
65   static Standard_Boolean IS_IN_PARALLEL = Standard_False;
66 };
67
68 IMPLEMENT_STANDARD_HANDLE (BRepMesh_IncrementalMesh, BRepMesh_DiscretRoot)
69 IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_IncrementalMesh, BRepMesh_DiscretRoot)
70
71 //=======================================================================
72 //function : Default constructor
73 //purpose  : 
74 //=======================================================================
75 BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh()
76 : myRelative (Standard_False),
77   myInParallel (Standard_False)
78 {
79 }
80
81 //=======================================================================
82 //function : Constructor
83 //purpose  : 
84 //=======================================================================
85 BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh(
86   const TopoDS_Shape&    theShape,
87   const Standard_Real    theLinDeflection,
88   const Standard_Boolean isRelative,
89   const Standard_Real    theAngDeflection,
90   const Standard_Boolean isInParallel)
91   : myRelative  (isRelative),
92     myInParallel(isInParallel)
93 {
94   myDeflection  = theLinDeflection;
95   myAngle       = theAngDeflection;
96   myShape       = theShape;
97   
98   Perform();
99 }
100
101 //=======================================================================
102 //function : Destructor
103 //purpose  : 
104 //=======================================================================
105 BRepMesh_IncrementalMesh::~BRepMesh_IncrementalMesh()
106 {
107 }
108
109 //=======================================================================
110 //function : init
111 //purpose  : 
112 //=======================================================================
113 void BRepMesh_IncrementalMesh::init() 
114 {
115   myStatus   = 0;
116   myModified = Standard_False;
117
118   myEdgeDeflection.Clear();
119   myFaces.clear();
120
121   setDone();
122
123   if (!isCorrectPolyData())
124     BRepTools::Clean(myShape);
125
126   Bnd_Box aBox;
127   BRepBndLib::Add(myShape, aBox, Standard_False);
128
129   if (aBox.IsVoid())
130   {
131     // Nothing to mesh.
132     myMesh.Nullify();
133     return;
134   }
135
136   BRepMesh_ShapeTool::BoxMaxDimension(aBox, myMaxShapeSize);
137
138   myMesh = new BRepMesh_FastDiscret(myDeflection, myAngle, aBox,
139     Standard_True, Standard_True, myRelative, Standard_True, myInParallel);
140
141   myMesh->InitSharedFaces(myShape);
142 }
143
144 //=======================================================================
145 //function : isCorrectPolyData
146 //purpose  : 
147 //=======================================================================
148 Standard_Boolean BRepMesh_IncrementalMesh::isCorrectPolyData()
149 {
150   collectFaces();
151
152   BRepMesh_FaceChecker aFaceChecker(myInParallel);
153
154 #ifdef HAVE_TBB
155   if (myInParallel)
156   {
157     // check faces in parallel threads using TBB
158     tbb::parallel_for_each(myFaces.begin(), myFaces.end(), aFaceChecker);
159   }
160   else
161   {
162 #endif
163     std::vector<TopoDS_Face>::iterator aFaceIt = myFaces.begin();
164     for (; aFaceIt != myFaces.end(); aFaceIt++)
165       aFaceChecker(*aFaceIt);
166 #ifdef HAVE_TBB
167   }
168 #endif
169
170   return aFaceChecker.IsValid();
171 }
172
173 //=======================================================================
174 //function : collectFaces
175 //purpose  : 
176 //=======================================================================
177 void BRepMesh_IncrementalMesh::collectFaces()
178 {
179   TopTools_ListOfShape aFaceList;
180   BRepLib::ReverseSortFaces(myShape, aFaceList);
181   TopTools_MapOfShape aFaceMap;
182   myFaces.reserve(aFaceList.Extent());
183
184   // make array of faces suitable for processing (excluding faces without surface)
185   TopLoc_Location aDummyLoc;
186   const TopLoc_Location aEmptyLoc;
187   TopTools_ListIteratorOfListOfShape aFaceIter(aFaceList);
188   for (; aFaceIter.More(); aFaceIter.Next())
189   {
190     TopoDS_Shape aFaceNoLoc = aFaceIter.Value();
191     aFaceNoLoc.Location(aEmptyLoc);
192     if (!aFaceMap.Add (aFaceNoLoc))
193       continue; // already processed
194
195     TopoDS_Face aFace = TopoDS::Face(aFaceIter.Value());
196     const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aDummyLoc);
197     if (aSurf.IsNull())
198       continue;
199
200     myFaces.push_back(aFace);
201   }
202 }
203
204 //=======================================================================
205 //function : Perform
206 //purpose  : 
207 //=======================================================================
208 void BRepMesh_IncrementalMesh::Perform()
209 {
210   init();
211
212   if (myMesh.IsNull())
213     return;
214
215   update();
216 }
217
218 //=======================================================================
219 //function : update()
220 //purpose  : 
221 //=======================================================================
222 void BRepMesh_IncrementalMesh::update()
223 {
224   // Update edges data
225   TopExp_Explorer aExplorer(myShape, TopAbs_EDGE);
226   for (; aExplorer.More(); aExplorer.Next())
227   {
228     const TopoDS_Edge& aEdge = TopoDS::Edge(aExplorer.Current());
229     if(!BRep_Tool::IsGeometric(aEdge))
230       continue;
231
232     update(aEdge);
233   }
234
235   // Update faces data
236   std::vector<TopoDS_Face>::iterator aFaceIt(myFaces.begin());
237   for (; aFaceIt != myFaces.end(); aFaceIt++)
238     update(*aFaceIt);
239
240   // Mesh faces
241 #ifdef HAVE_TBB
242   if (myInParallel)
243   {
244     tbb::parallel_for_each(myFaces.begin(), myFaces.end(), *myMesh);
245   }
246   else
247   {
248 #endif
249     for (aFaceIt = myFaces.begin(); aFaceIt != myFaces.end(); aFaceIt++)
250       myMesh->Process(*aFaceIt);
251 #ifdef HAVE_TBB
252   }
253 #endif
254
255   commit();
256 }
257
258 //=======================================================================
259 //function : discretizeFreeEdges
260 //purpose  : 
261 //=======================================================================
262 void BRepMesh_IncrementalMesh::discretizeFreeEdges()
263 {
264   TopExp_Explorer aExplorer(myShape ,TopAbs_EDGE, TopAbs_FACE);
265   for (; aExplorer.More(); aExplorer.Next())
266   {
267     const TopoDS_Edge& aEdge = TopoDS::Edge(aExplorer.Current());
268     if(!BRep_Tool::IsGeometric(aEdge))
269       continue;
270     
271     TopLoc_Location aLoc;
272     Standard_Real aEdgeDeflection  = edgeDeflection(aEdge);
273     Handle(Poly_Polygon3D) aPoly3D = BRep_Tool::Polygon3D(aEdge, aLoc);
274     if (!aPoly3D.IsNull() && aPoly3D->Deflection() < 1.1 * aEdgeDeflection)
275       continue;
276
277     BRepAdaptor_Curve aCurve(aEdge);
278     GCPnts_TangentialDeflection aDiscret(aCurve, aCurve.FirstParameter(),
279       aCurve.LastParameter(), myAngle, aEdgeDeflection, 2);
280
281     Standard_Integer aNodesNb = aDiscret.NbPoints();
282     TColgp_Array1OfPnt   aNodes  (1, aNodesNb);
283     TColStd_Array1OfReal aUVNodes(1, aNodesNb);
284     for (Standard_Integer i = 1; i <= aNodesNb; ++i)
285     {
286       aNodes  (i) = aDiscret.Value(i);
287       aUVNodes(i) = aDiscret.Parameter(i);
288     }
289     
290     aPoly3D = new Poly_Polygon3D(aNodes, aUVNodes);
291     aPoly3D->Deflection(myDeflection);
292
293     BRep_Builder aBuilder;
294     aBuilder.UpdateEdge(aEdge, aPoly3D);
295   }
296 }
297
298 //=======================================================================
299 //function : edgeDeflection
300 //purpose  : 
301 //=======================================================================
302 Standard_Real BRepMesh_IncrementalMesh::edgeDeflection(
303   const TopoDS_Edge& theEdge)
304 {
305   if (myEdgeDeflection.IsBound(theEdge))
306     return myEdgeDeflection(theEdge);
307
308   Standard_Real aEdgeDeflection;
309   if (myRelative) 
310   {
311     Standard_Real aScale;
312     aEdgeDeflection = BRepMesh_ShapeTool::RelativeEdgeDeflection(theEdge, 
313       myDeflection, myMaxShapeSize, aScale);
314   }
315   else
316     aEdgeDeflection = myDeflection;
317
318   myEdgeDeflection.Bind(theEdge, aEdgeDeflection);
319   return aEdgeDeflection;
320 }
321
322 //=======================================================================
323 //function : faceDeflection
324 //purpose  : 
325 //=======================================================================
326 Standard_Real BRepMesh_IncrementalMesh::faceDeflection(
327   const TopoDS_Face& theFace)
328 {
329   if (!myRelative)
330     return myDeflection;
331
332   Standard_Integer aEdgesNb        = 0;
333   Standard_Real    aFaceDeflection = 0.;
334
335   TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
336   for (; aEdgeIt.More(); aEdgeIt.Next(), ++aEdgesNb)
337   {
338     const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
339     aFaceDeflection += edgeDeflection(aEdge);
340   }
341
342   return (aEdgesNb == 0) ? myDeflection : (aFaceDeflection / aEdgesNb);
343 }
344
345 //=======================================================================
346 //function : update(edge)
347 //purpose  : 
348 //=======================================================================
349 void BRepMesh_IncrementalMesh::update(const TopoDS_Edge& theEdge)
350 {
351   Standard_Integer aPolyIndex   = 1;
352   Standard_Real aEdgeDeflection = edgeDeflection(theEdge);
353   Handle(Poly_PolygonOnTriangulation) aPolygon;
354   do
355   {
356     TopLoc_Location aLoc;
357     Handle(Poly_Triangulation) aTriangulation;
358     BRep_Tool::PolygonOnTriangulation(theEdge, aPolygon, 
359       aTriangulation, aLoc, aPolyIndex++);
360
361     if (!aTriangulation.IsNull() && !aPolygon.IsNull())
362     {
363       if (aPolygon->Deflection() < 1.1 * aEdgeDeflection &&
364           aPolygon->HasParameters())
365       {
366         continue;
367       }
368
369       myModified = Standard_True;
370       BRepMesh_ShapeTool::NullifyEdge(theEdge, aTriangulation, aLoc);
371     }
372
373     if (!myEmptyEdges.IsBound(theEdge))
374       myEmptyEdges.Bind(theEdge, BRepMesh::MapOfTriangulation());
375
376     if (!aTriangulation.IsNull())
377       myEmptyEdges(theEdge).Add(aTriangulation);
378   }
379   while (!aPolygon.IsNull());
380 }
381
382 //=======================================================================
383 //function : isToBeMeshed
384 //purpose  : 
385 //=======================================================================
386 Standard_Boolean BRepMesh_IncrementalMesh::toBeMeshed(
387   const TopoDS_Face&     theFace,
388   const Standard_Boolean isWithCheck)
389 {
390   TopLoc_Location aLoc;
391   Handle(Poly_Triangulation) aTriangulation = 
392     BRep_Tool::Triangulation(theFace, aLoc);
393
394   if (aTriangulation.IsNull())
395     return Standard_True;
396
397   if (isWithCheck)
398   {
399     Standard_Real aFaceDeflection = faceDeflection(theFace);
400     if (aTriangulation->Deflection() < 1.1 * aFaceDeflection)
401     {
402       Standard_Boolean isEdgesConsistent = Standard_True;
403       TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
404       for (; aEdgeIt.More() && isEdgesConsistent; aEdgeIt.Next())
405       {
406         const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
407         if (!myEmptyEdges.IsBound(aEdge))
408           continue;
409
410         BRepMesh::MapOfTriangulation& aTriMap = myEmptyEdges(aEdge);
411         isEdgesConsistent &= !aTriMap.IsEmpty() && !aTriMap.Contains(aTriangulation);
412       }
413
414       if (isEdgesConsistent)
415         return Standard_False;
416     }
417   }
418
419   // Nullify edges
420   TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
421   for (; aEdgeIt.More(); aEdgeIt.Next())
422   {
423     const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
424     BRepMesh_ShapeTool::NullifyEdge(aEdge, aTriangulation, aLoc);
425   }
426
427   BRepMesh_ShapeTool::NullifyFace(theFace);
428   return Standard_True;
429 }
430
431 //=======================================================================
432 //function : update(face)
433 //purpose  : 
434 //=======================================================================
435 void BRepMesh_IncrementalMesh::update(const TopoDS_Face& theFace)
436 {
437   if (!toBeMeshed(theFace, Standard_True))
438     return;
439
440   myModified = Standard_True;
441   Standard_Integer aStatus = myMesh->Add(theFace);
442
443   myStatus |= aStatus;
444   if (aStatus != BRepMesh_ReMesh)
445     return;
446
447   BRepMesh::MapOfShape aUsedFaces;
448   aUsedFaces.Add(theFace);
449
450   const TopTools_IndexedDataMapOfShapeListOfShape& aMapOfSharedFaces = 
451     myMesh->SharedFaces();
452
453   TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
454   for (; aEdgeIt.More(); aEdgeIt.Next())
455   {
456     const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
457     if (aMapOfSharedFaces.FindIndex(aEdge) == 0)
458       continue;
459      
460     const TopTools_ListOfShape& aSharedFaces = aMapOfSharedFaces.FindFromKey(aEdge);
461     TopTools_ListIteratorOfListOfShape aSharedFaceIt(aSharedFaces);
462     for (; aSharedFaceIt.More(); aSharedFaceIt.Next())
463     {
464       const TopoDS_Face& aFace = TopoDS::Face(aSharedFaceIt.Value());
465       if (aUsedFaces.Contains(aFace))
466         continue;
467
468       aUsedFaces.Add(aFace);
469       toBeMeshed(aFace, Standard_False);
470
471       myStatus |= myMesh->Add(aFace);
472     }
473   }
474 }
475
476 //=======================================================================
477 //function : commit
478 //purpose  : 
479 //=======================================================================
480 void BRepMesh_IncrementalMesh::commit()
481 {
482   std::vector<TopoDS_Face>::iterator aFaceIt(myFaces.begin());
483   for (; aFaceIt != myFaces.end(); aFaceIt++)
484     commitEdges(*aFaceIt);
485
486   discretizeFreeEdges();
487 }
488
489 //=======================================================================
490 //function : commitEdges
491 //purpose  : 
492 //=======================================================================
493 void BRepMesh_IncrementalMesh::commitEdges(const TopoDS_Face& theFace)
494 {
495   TopoDS_Face aFace = theFace;
496   aFace.Orientation(TopAbs_FORWARD);
497
498   Handle(BRepMesh_FaceAttribute) aFaceAttribute;
499   if (!myMesh->GetFaceAttribute(aFace, aFaceAttribute))
500     return;
501
502   if (!aFaceAttribute->IsValid())
503   {
504     myStatus |= aFaceAttribute->GetStatus();
505     return;
506   }
507
508   TopLoc_Location            aLoc = aFace.Location();
509   Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(aFace, aLoc);
510
511   if (aTriangulation.IsNull())
512   {
513     aFaceAttribute->Clear();
514     return;
515   }
516
517   try
518   {
519     OCC_CATCH_SIGNALS
520
521     // Store discretization of edges
522     BRepMesh::HDMapOfShapePairOfPolygon& aInternalEdges = aFaceAttribute->ChangeInternalEdges();
523     BRepMesh::DMapOfShapePairOfPolygon::Iterator aEdgeIt(*aInternalEdges);
524     for (; aEdgeIt.More(); aEdgeIt.Next())
525     {
526       const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Key());
527       const BRepMesh_PairOfPolygon& aPolyPair = aEdgeIt.Value();
528       const Handle(Poly_PolygonOnTriangulation)& aPolygon1 = aPolyPair.First();
529       const Handle(Poly_PolygonOnTriangulation)& aPolygon2 = aPolyPair.Last();
530
531       if (aPolygon1 == aPolygon2)
532         BRepMesh_ShapeTool::UpdateEdge(aEdge, aPolygon1, aTriangulation, aLoc);
533       else
534         BRepMesh_ShapeTool::UpdateEdge(aEdge, aPolygon1, aPolygon2, aTriangulation, aLoc);
535     }
536
537     aFaceAttribute->Clear();
538   }
539   catch (Standard_Failure)
540   {
541     myStatus |= BRepMesh_Failure;
542   }
543 }
544
545 //=======================================================================
546 //function : Discret
547 //purpose  :
548 //=======================================================================
549 Standard_Integer BRepMesh_IncrementalMesh::Discret(
550   const TopoDS_Shape&    theShape,
551   const Standard_Real    theDeflection,
552   const Standard_Real    theAngle,
553   BRepMesh_DiscretRoot* &theAlgo)
554 {
555   BRepMesh_IncrementalMesh* anAlgo = new BRepMesh_IncrementalMesh();
556   anAlgo->SetDeflection(theDeflection);
557   anAlgo->SetAngle     (theAngle);
558   anAlgo->SetShape     (theShape);
559   anAlgo->SetParallel  (IS_IN_PARALLEL);
560   theAlgo = anAlgo;
561   return 0; // no error
562 }
563
564 //=======================================================================
565 //function : IsParallelDefault
566 //purpose  :
567 //=======================================================================
568 Standard_Boolean BRepMesh_IncrementalMesh::IsParallelDefault()
569 {
570 #ifdef HAVE_TBB
571   return IS_IN_PARALLEL;
572 #else
573   // no alternative parallelization yet - flag has no meaning
574   return Standard_False;
575 #endif
576 }
577
578 //=======================================================================
579 //function : Discret
580 //purpose  :
581 //=======================================================================
582 void BRepMesh_IncrementalMesh::SetParallelDefault(
583   const Standard_Boolean theInParallel)
584 {
585   IS_IN_PARALLEL = theInParallel;
586 }
587
588 //! Export Mesh Plugin entry function
589 DISCRETPLUGIN(BRepMesh_IncrementalMesh)