c3f9d42f14682226a7547c8739610997f9aca2a0
[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 <OSD_Parallel.hxx>
20 #include <Precision.hxx>
21 #include <Standard_ErrorHandler.hxx>
22
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 IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_IncrementalMesh,BRepMesh_DiscretRoot)
57
58 namespace
59 {
60   //! Default flag to control parallelization for BRepMesh_IncrementalMesh
61   //! tool returned for Mesh Factory
62   static Standard_Boolean IS_IN_PARALLEL = Standard_False;
63 }
64
65
66 //=======================================================================
67 //function : Default constructor
68 //purpose  : 
69 //=======================================================================
70 BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh()
71 : myMaxShapeSize(0.),
72   myModified(Standard_False),
73   myStatus(0)
74 {
75 }
76
77 //=======================================================================
78 //function : Constructor
79 //purpose  : 
80 //=======================================================================
81 BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh( const TopoDS_Shape&    theShape,
82                                                     const Standard_Real    theLinDeflection,
83                                                     const Standard_Boolean isRelative,
84                                                     const Standard_Real    theAngDeflection,
85                                                     const Standard_Boolean isInParallel,
86                                                     const Standard_Boolean adaptiveMin)
87 : myMaxShapeSize(0.),
88   myModified(Standard_False),
89   myStatus(0)
90 {
91   myParameters.Deflection = theLinDeflection;
92   myParameters.Relative = isRelative;
93   myParameters.Angle = theAngDeflection;
94   myParameters.InParallel = isInParallel;
95   myParameters.AdaptiveMin = adaptiveMin;
96
97   myShape = theShape;
98   Perform();
99 }
100
101 //=======================================================================
102 //function : Constructor
103 //purpose  : 
104 //=======================================================================
105 BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh(const TopoDS_Shape& theShape,
106                                                    const BRepMesh_FastDiscret::Parameters& theParameters)
107   : myParameters(theParameters)
108 {
109   myShape       = theShape;
110   
111   Perform();
112 }
113
114 //=======================================================================
115 //function : Destructor
116 //purpose  : 
117 //=======================================================================
118 BRepMesh_IncrementalMesh::~BRepMesh_IncrementalMesh()
119 {
120 }
121
122 //=======================================================================
123 //function : clear
124 //purpose  : 
125 //=======================================================================
126 void BRepMesh_IncrementalMesh::clear()
127 {
128   myEdges.Clear();
129   myEdgeDeflection.Clear();
130   myFaces.Clear();
131   myMesh.Nullify();
132 }
133
134 //=======================================================================
135 //function : init
136 //purpose  : 
137 //=======================================================================
138 void BRepMesh_IncrementalMesh::init() 
139 {
140   myStatus   = 0;
141   myModified = Standard_False;
142
143   setDone();
144   clear();
145
146   collectFaces();
147
148   Bnd_Box aBox;
149   BRepBndLib::Add(myShape, aBox, Standard_False);
150
151   if (aBox.IsVoid())
152   {
153     // Nothing to mesh.
154     return;
155   }
156
157   BRepMesh_ShapeTool::BoxMaxDimension(aBox, myMaxShapeSize);
158
159   myMesh = new BRepMesh_FastDiscret (aBox, myParameters);
160   
161   myMesh->InitSharedFaces(myShape);
162 }
163
164 //=======================================================================
165 //function : collectFaces
166 //purpose  : 
167 //=======================================================================
168 void BRepMesh_IncrementalMesh::collectFaces()
169 {
170   TopTools_ListOfShape aFaceList;
171   BRepLib::ReverseSortFaces(myShape, aFaceList);
172   TopTools_MapOfShape aFaceMap;
173
174   // make array of faces suitable for processing (excluding faces without surface)
175   TopLoc_Location aDummyLoc;
176   const TopLoc_Location aEmptyLoc;
177   TopTools_ListIteratorOfListOfShape aFaceIter(aFaceList);
178   for (; aFaceIter.More(); aFaceIter.Next())
179   {
180     TopoDS_Shape aFaceNoLoc = aFaceIter.Value();
181     aFaceNoLoc.Location(aEmptyLoc);
182     if (!aFaceMap.Add (aFaceNoLoc))
183       continue; // already processed
184
185     TopoDS_Face aFace = TopoDS::Face(aFaceIter.Value());
186     const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aDummyLoc);
187     if (aSurf.IsNull())
188       continue;
189
190     myFaces.Append(aFace);
191   }
192 }
193
194 //=======================================================================
195 //function : Perform
196 //purpose  : 
197 //=======================================================================
198 void BRepMesh_IncrementalMesh::Perform()
199 {
200   init();
201
202   if (myMesh.IsNull())
203     return;
204
205   update();
206 }
207
208 //=======================================================================
209 //function : update()
210 //purpose  : 
211 //=======================================================================
212 void BRepMesh_IncrementalMesh::update()
213 {
214   // Update edges data
215   TopExp_Explorer aExplorer(myShape, TopAbs_EDGE);
216   for (; aExplorer.More(); aExplorer.Next())
217   {
218     const TopoDS_Edge& aEdge = TopoDS::Edge(aExplorer.Current());
219     if(!BRep_Tool::IsGeometric(aEdge))
220       continue;
221
222     update(aEdge);
223   }
224
225   // Update faces data
226   NCollection_Vector<TopoDS_Face>::Iterator aFaceIt(myFaces);
227   for (; aFaceIt.More(); aFaceIt.Next())
228     update(aFaceIt.Value());
229
230   // Mesh faces
231   OSD_Parallel::ForEach(myFaces.begin(), myFaces.end(), *myMesh, !myParameters.InParallel);
232
233   commit();
234   clear();
235 }
236
237 //=======================================================================
238 //function : discretizeFreeEdges
239 //purpose  : 
240 //=======================================================================
241 void BRepMesh_IncrementalMesh::discretizeFreeEdges()
242 {
243   TopExp_Explorer aExplorer(myShape ,TopAbs_EDGE, TopAbs_FACE);
244   for (; aExplorer.More(); aExplorer.Next())
245   {
246     const TopoDS_Edge& aEdge = TopoDS::Edge(aExplorer.Current());
247     if(!BRep_Tool::IsGeometric(aEdge))
248       continue;
249     
250     TopLoc_Location aLoc;
251     Standard_Real aEdgeDeflection  = edgeDeflection(aEdge);
252     Handle(Poly_Polygon3D) aPoly3D = BRep_Tool::Polygon3D(aEdge, aLoc);
253     if (!aPoly3D.IsNull() && aPoly3D->Deflection() < 1.1 * aEdgeDeflection)
254       continue;
255
256     BRepAdaptor_Curve aCurve(aEdge);
257     GCPnts_TangentialDeflection aDiscret(aCurve, aCurve.FirstParameter(),
258       aCurve.LastParameter(), myParameters.Angle, aEdgeDeflection, 2,
259       Precision::PConfusion(), myParameters.MinSize);
260
261     Standard_Integer aNodesNb = aDiscret.NbPoints();
262     TColgp_Array1OfPnt   aNodes  (1, aNodesNb);
263     TColStd_Array1OfReal aUVNodes(1, aNodesNb);
264     for (Standard_Integer i = 1; i <= aNodesNb; ++i)
265     {
266       aNodes  (i) = aDiscret.Value(i);
267       aUVNodes(i) = aDiscret.Parameter(i);
268     }
269     
270     aPoly3D = new Poly_Polygon3D(aNodes, aUVNodes);
271     aPoly3D->Deflection(myParameters.Deflection);
272
273     BRep_Builder aBuilder;
274     aBuilder.UpdateEdge(aEdge, aPoly3D);
275   }
276 }
277
278 //=======================================================================
279 //function : edgeDeflection
280 //purpose  : 
281 //=======================================================================
282 Standard_Real BRepMesh_IncrementalMesh::edgeDeflection(
283   const TopoDS_Edge& theEdge)
284 {
285   if (myEdgeDeflection.IsBound(theEdge))
286     return myEdgeDeflection(theEdge);
287
288   Standard_Real aEdgeDeflection;
289   if ( myParameters.Relative ) 
290   {
291     Standard_Real aScale;
292     aEdgeDeflection = BRepMesh_ShapeTool::RelativeEdgeDeflection(theEdge, 
293       myParameters.Deflection, myMaxShapeSize, aScale);
294   }
295   else
296     aEdgeDeflection = myParameters.Deflection;
297
298   myEdgeDeflection.Bind(theEdge, aEdgeDeflection);
299   return aEdgeDeflection;
300 }
301
302 //=======================================================================
303 //function : faceDeflection
304 //purpose  : 
305 //=======================================================================
306 Standard_Real BRepMesh_IncrementalMesh::faceDeflection(
307   const TopoDS_Face& theFace)
308 {
309   if ( !myParameters.Relative )
310     return myParameters.Deflection;
311
312   Standard_Integer aEdgesNb        = 0;
313   Standard_Real    aFaceDeflection = 0.;
314
315   TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
316   for (; aEdgeIt.More(); aEdgeIt.Next(), ++aEdgesNb)
317   {
318     const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
319     aFaceDeflection += edgeDeflection(aEdge);
320   }
321
322   return (aEdgesNb == 0) ? myParameters.Deflection : (aFaceDeflection / aEdgesNb);
323 }
324
325 //=======================================================================
326 //function : update(edge)
327 //purpose  : 
328 //=======================================================================
329 void BRepMesh_IncrementalMesh::update(const TopoDS_Edge& theEdge)
330 {
331   if (!myEdges.IsBound(theEdge))
332     myEdges.Bind(theEdge, BRepMesh::DMapOfTriangulationBool());
333
334   Standard_Real aEdgeDeflection = edgeDeflection(theEdge);
335   // Check that triangulation relies to face of the given shape.
336   const TopTools_IndexedDataMapOfShapeListOfShape& aMapOfSharedFaces = 
337     myMesh->SharedFaces();
338
339   const TopTools_ListOfShape& aSharedFaces = 
340     aMapOfSharedFaces.FindFromKey(theEdge);
341
342   TopTools_ListIteratorOfListOfShape aSharedFaceIt(aSharedFaces);
343   for (; aSharedFaceIt.More(); aSharedFaceIt.Next())
344   {
345     TopLoc_Location aLoc;
346     const TopoDS_Face& aFace = TopoDS::Face(aSharedFaceIt.Value());
347     const Handle(Poly_Triangulation)& aFaceTriangulation = 
348       BRep_Tool::Triangulation(aFace, aLoc);
349
350     if (aFaceTriangulation.IsNull())
351       continue;
352
353     Standard_Boolean isConsistent = Standard_False;
354     const Handle(Poly_PolygonOnTriangulation)& aPolygon =
355       BRep_Tool::PolygonOnTriangulation(theEdge, aFaceTriangulation, aLoc);
356
357     if (!aPolygon.IsNull())
358     {
359       isConsistent = aPolygon->Deflection() < 1.1 * aEdgeDeflection &&
360         aPolygon->HasParameters();
361
362       if (!isConsistent)
363       {
364         myModified = Standard_True;
365         BRepMesh_ShapeTool::NullifyEdge(theEdge, aFaceTriangulation, aLoc);
366       }
367     }
368
369     myEdges(theEdge).Bind(aFaceTriangulation, isConsistent);
370   }
371 }
372
373 //=======================================================================
374 //function : isToBeMeshed
375 //purpose  : 
376 //=======================================================================
377 Standard_Boolean BRepMesh_IncrementalMesh::toBeMeshed(
378   const TopoDS_Face&     theFace,
379   const Standard_Boolean isWithCheck)
380 {
381   TopLoc_Location aLoc;
382   const Handle(Poly_Triangulation)& aTriangulation = 
383     BRep_Tool::Triangulation(theFace, aLoc);
384
385   if (aTriangulation.IsNull())
386     return Standard_True;
387
388   if (isWithCheck)
389   {
390     Standard_Real aFaceDeflection = faceDeflection(theFace);
391     if (aTriangulation->Deflection() < 1.1 * aFaceDeflection)
392     {
393       Standard_Boolean isEdgesConsistent = Standard_True;
394       TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
395       for (; aEdgeIt.More() && isEdgesConsistent; aEdgeIt.Next())
396       {
397         const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
398         if (!myEdges.IsBound(aEdge))
399           continue;
400
401         BRepMesh::DMapOfTriangulationBool& aTriMap = myEdges(aEdge);
402         isEdgesConsistent &= aTriMap.IsBound(aTriangulation) &&
403           aTriMap(aTriangulation);
404       }
405
406       if (isEdgesConsistent)
407       {
408         // #25080: check that indices of links forming triangles are in range.
409         Standard_Boolean isTriangulationConsistent = Standard_True;
410         const Standard_Integer aNodesNb = aTriangulation->NbNodes();
411         const Poly_Array1OfTriangle& aTriangles = aTriangulation->Triangles();
412         Standard_Integer i = aTriangles.Lower();
413         for (; i <= aTriangles.Upper() && isTriangulationConsistent; ++i)
414         {
415           const Poly_Triangle& aTriangle = aTriangles(i);
416           Standard_Integer n[3];
417           aTriangle.Get(n[0], n[1], n[2]);
418           for (Standard_Integer j = 0; j < 3 && isTriangulationConsistent; ++j)
419             isTriangulationConsistent = (n[j] >= 1 && n[j] <= aNodesNb);
420         }
421
422         if (isTriangulationConsistent)
423           return Standard_False;
424       }
425     }
426   }
427
428   // Nullify edges
429   TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
430   for (; aEdgeIt.More(); aEdgeIt.Next())
431   {
432     const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
433     BRepMesh_ShapeTool::NullifyEdge(aEdge, aTriangulation, aLoc);
434   }
435
436   BRepMesh_ShapeTool::NullifyFace(theFace);
437   return Standard_True;
438 }
439
440 //=======================================================================
441 //function : update(face)
442 //purpose  : 
443 //=======================================================================
444 void BRepMesh_IncrementalMesh::update(const TopoDS_Face& theFace)
445 {
446   if (!toBeMeshed(theFace, Standard_True))
447     return;
448
449   myModified = Standard_True;
450   Standard_Integer aStatus = myMesh->Add(theFace);
451
452   myStatus |= aStatus;
453   if (aStatus != BRepMesh_ReMesh)
454     return;
455
456   BRepMesh::MapOfShape aUsedFaces;
457   aUsedFaces.Add(theFace);
458
459   const TopTools_IndexedDataMapOfShapeListOfShape& aMapOfSharedFaces = 
460     myMesh->SharedFaces();
461
462   TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE);
463   for (; aEdgeIt.More(); aEdgeIt.Next())
464   {
465     const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
466     if (aMapOfSharedFaces.FindIndex(aEdge) == 0)
467       continue;
468      
469     const TopTools_ListOfShape& aSharedFaces = aMapOfSharedFaces.FindFromKey(aEdge);
470     TopTools_ListIteratorOfListOfShape aSharedFaceIt(aSharedFaces);
471     for (; aSharedFaceIt.More(); aSharedFaceIt.Next())
472     {
473       const TopoDS_Face& aFace = TopoDS::Face(aSharedFaceIt.Value());
474       if (aUsedFaces.Contains(aFace))
475         continue;
476
477       aUsedFaces.Add(aFace);
478       toBeMeshed(aFace, Standard_False);
479
480       myStatus |= myMesh->Add(aFace);
481     }
482   }
483 }
484
485 //=======================================================================
486 //function : commit
487 //purpose  : 
488 //=======================================================================
489 void BRepMesh_IncrementalMesh::commit()
490 {
491   NCollection_Vector<TopoDS_Face>::Iterator aFaceIt(myFaces);
492   for (; aFaceIt.More(); aFaceIt.Next())
493     commitEdges(aFaceIt.Value());
494
495   discretizeFreeEdges();
496 }
497
498 //=======================================================================
499 //function : commitEdges
500 //purpose  : 
501 //=======================================================================
502 void BRepMesh_IncrementalMesh::commitEdges(const TopoDS_Face& theFace)
503 {
504   TopoDS_Face aFace = theFace;
505   aFace.Orientation(TopAbs_FORWARD);
506
507   Handle(BRepMesh_FaceAttribute) aFaceAttribute;
508   if (!myMesh->GetFaceAttribute(aFace, aFaceAttribute))
509     return;
510
511   if (!aFaceAttribute->IsValid())
512   {
513     myStatus |= aFaceAttribute->GetStatus();
514     return;
515   }
516
517   TopLoc_Location aLoc;
518   Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(aFace, aLoc);
519
520   if (aTriangulation.IsNull())
521     return;
522
523   try
524   {
525     OCC_CATCH_SIGNALS
526
527     // Store discretization of edges
528     BRepMesh::HDMapOfShapePairOfPolygon& aInternalEdges = aFaceAttribute->ChangeInternalEdges();
529     BRepMesh::DMapOfShapePairOfPolygon::Iterator aEdgeIt(*aInternalEdges);
530     for (; aEdgeIt.More(); aEdgeIt.Next())
531     {
532       const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Key());
533       const BRepMesh_PairOfPolygon& aPolyPair = aEdgeIt.Value();
534       const Handle(Poly_PolygonOnTriangulation)& aPolygon1 = aPolyPair.First();
535       const Handle(Poly_PolygonOnTriangulation)& aPolygon2 = aPolyPair.Last();
536
537       if (aPolygon1 == aPolygon2)
538         BRepMesh_ShapeTool::UpdateEdge(aEdge, aPolygon1, aTriangulation, aLoc);
539       else
540         BRepMesh_ShapeTool::UpdateEdge(aEdge, aPolygon1, aPolygon2, aTriangulation, aLoc);
541     }
542   }
543   catch (Standard_Failure)
544   {
545     myStatus |= BRepMesh_Failure;
546   }
547 }
548
549 //=======================================================================
550 //function : Discret
551 //purpose  :
552 //=======================================================================
553 Standard_Integer BRepMesh_IncrementalMesh::Discret(
554   const TopoDS_Shape&    theShape,
555   const Standard_Real    theDeflection,
556   const Standard_Real    theAngle,
557   BRepMesh_DiscretRoot* &theAlgo)
558 {
559   BRepMesh_IncrementalMesh* anAlgo = new BRepMesh_IncrementalMesh();
560   anAlgo->ChangeParameters().Deflection = theDeflection;
561   anAlgo->ChangeParameters().Angle = theAngle;
562   anAlgo->ChangeParameters().InParallel = IS_IN_PARALLEL;
563   anAlgo->SetShape     (theShape);
564   theAlgo = anAlgo;
565   return 0; // no error
566 }
567
568 //=======================================================================
569 //function : IsParallelDefault
570 //purpose  :
571 //=======================================================================
572 Standard_Boolean BRepMesh_IncrementalMesh::IsParallelDefault()
573 {
574   return IS_IN_PARALLEL;
575 }
576
577 //=======================================================================
578 //function : Discret
579 //purpose  :
580 //=======================================================================
581 void BRepMesh_IncrementalMesh::SetParallelDefault(
582   const Standard_Boolean theInParallel)
583 {
584   IS_IN_PARALLEL = theInParallel;
585 }
586
587 //! Export Mesh Plugin entry function
588 DISCRETPLUGIN(BRepMesh_IncrementalMesh)