0027991: Modeling Algorithms - BRepGProp_Face crashes on face without geometric surface
[occt.git] / src / BRepGProp / BRepGProp.cxx
1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <BRepGProp.hxx>
16 #include <BRepGProp_Cinert.hxx>
17 #include <BRepGProp_Sinert.hxx>
18 #include <BRepGProp_Vinert.hxx>
19 #include <BRepGProp_VinertGK.hxx>
20 #include <GProp_PGProps.hxx>
21 #include <BRepGProp_Face.hxx>
22 #include <BRepGProp_Domain.hxx>
23 #include <TopoDS.hxx>
24 #include <BRepAdaptor_Curve.hxx>
25
26 #include <TopTools.hxx>
27 #include <BRep_Tool.hxx>  
28 #include <TopTools_ListOfShape.hxx>
29 #include <TopTools_MapOfShape.hxx>
30 #include <BRepCheck_Shell.hxx>
31 #include <TopTools_ListIteratorOfListOfShape.hxx>
32 #ifdef OCCT_DEBUG
33 static Standard_Integer AffichEps = 0;
34 #endif
35
36 static gp_Pnt roughBaryCenter(const TopoDS_Shape& S){
37   Standard_Integer i;  TopExp_Explorer ex;
38   gp_XYZ xyz(0,0,0);
39   for (ex.Init(S,TopAbs_VERTEX), i = 0; ex.More(); ex.Next(), i++) 
40     xyz += BRep_Tool::Pnt(TopoDS::Vertex(ex.Current())).XYZ();
41   if ( i > 0 ) xyz /= i;
42   return gp_Pnt(xyz);
43 }
44
45 void  BRepGProp::LinearProperties(const TopoDS_Shape& S, GProp_GProps& SProps, const Standard_Boolean SkipShared){
46   // find the origin
47   gp_Pnt P(0,0,0);
48   P.Transform(S.Location());
49   SProps = GProp_GProps(P);
50
51   BRepAdaptor_Curve   BAC;
52   Standard_Real eps = Epsilon(1.);
53   TopTools_MapOfShape anEMap;
54   TopExp_Explorer ex;
55   for (ex.Init(S,TopAbs_EDGE); ex.More(); ex.Next()) {
56     const TopoDS_Edge& aE = TopoDS::Edge(ex.Current());
57     if(SkipShared && !anEMap.Add(aE))
58     {
59       continue;
60     }
61     if(!BRep_Tool::IsGeometric(aE))
62     {
63       GProp_PGProps aPProps;
64       TopoDS_Iterator anIter(aE);
65       for(; anIter.More(); anIter.Next())
66       {
67         const TopoDS_Vertex& aV = TopoDS::Vertex(anIter.Value());
68         aPProps.AddPoint(BRep_Tool::Pnt(aV), eps);
69       }
70       SProps.Add(aPProps);
71     }
72     else
73     {
74       BAC.Initialize(aE);
75       BRepGProp_Cinert CG(BAC,P);
76       SProps.Add(CG);
77     }
78   }
79 }
80
81 static Standard_Real surfaceProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Real Eps, const Standard_Boolean SkipShared){
82   Standard_Integer i;
83 #ifdef OCCT_DEBUG
84   Standard_Integer iErrorMax = 0;
85 #endif
86   Standard_Real ErrorMax = 0.0, Error;
87   TopExp_Explorer ex; 
88   gp_Pnt P(roughBaryCenter(S));
89   BRepGProp_Sinert G;  G.SetLocation(P);
90
91   BRepGProp_Face   BF;
92   BRepGProp_Domain BD;
93   TopTools_MapOfShape aFMap;
94   TopLoc_Location aLocDummy;
95
96   for (ex.Init(S,TopAbs_FACE), i = 1; ex.More(); ex.Next(), i++) {
97     const TopoDS_Face& F = TopoDS::Face(ex.Current());
98     if(SkipShared && !aFMap.Add(F))
99     {
100       continue;
101     }
102
103     {
104       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (F, aLocDummy);
105       if (aSurf.IsNull())
106       {
107         // skip faces without geometry
108         continue;
109       }
110     }
111
112     BF.Load(F);
113     TopoDS_Iterator aWIter(F);
114     Standard_Boolean IsNatRestr = !aWIter.More();
115     if(!IsNatRestr) BD.Init(F);
116     if(Eps < 1.0) {
117       G.Perform(BF, BD, Eps); 
118       Error = G.GetEpsilon();
119       if(ErrorMax < Error) {
120         ErrorMax = Error;
121 #ifdef OCCT_DEBUG
122         iErrorMax = i;
123 #endif
124       }
125     } else {
126       if(IsNatRestr) G.Perform(BF);
127       else G.Perform(BF, BD);
128     }
129     Props.Add(G);
130 #ifdef OCCT_DEBUG
131     if(AffichEps) cout<<"\n"<<i<<":\tEpsArea = "<< G.GetEpsilon();
132 #endif
133   }
134 #ifdef OCCT_DEBUG
135   if(AffichEps) cout<<"\n-----------------\n"<<iErrorMax<<":\tMaxError = "<<ErrorMax<<"\n";
136 #endif
137   return ErrorMax;
138 }
139 void  BRepGProp::SurfaceProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Boolean SkipShared){
140   // find the origin
141   gp_Pnt P(0,0,0);
142   P.Transform(S.Location());
143   Props = GProp_GProps(P);
144   surfaceProperties(S,Props,1.0, SkipShared);
145 }
146 Standard_Real BRepGProp::SurfaceProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Real Eps, const Standard_Boolean SkipShared){ 
147   // find the origin
148   gp_Pnt P(0,0,0);  P.Transform(S.Location());
149   Props = GProp_GProps(P);
150   Standard_Real ErrorMax = surfaceProperties(S,Props,Eps,SkipShared);
151   return ErrorMax;
152 }
153
154 //=======================================================================
155 //function : volumeProperties
156 //purpose  : 
157 //=======================================================================
158
159 static Standard_Real volumeProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Real Eps, const Standard_Boolean SkipShared){
160   Standard_Integer i;
161 #ifdef OCCT_DEBUG
162   Standard_Integer iErrorMax = 0;
163 #endif
164   Standard_Real ErrorMax = 0.0, Error = 0.0;
165   TopExp_Explorer ex; 
166   gp_Pnt P(roughBaryCenter(S)); 
167   BRepGProp_Vinert G;  G.SetLocation(P);
168
169   BRepGProp_Face   BF;
170   BRepGProp_Domain BD;
171   TopTools_MapOfShape aFwdFMap;
172   TopTools_MapOfShape aRvsFMap;
173
174   for (ex.Init(S,TopAbs_FACE), i = 1; ex.More(); ex.Next(), i++) {
175     const TopoDS_Face& F = TopoDS::Face(ex.Current());
176     TopAbs_Orientation anOri = F.Orientation();
177     Standard_Boolean isFwd = anOri == TopAbs_FORWARD;
178     Standard_Boolean isRvs = Standard_False;
179     if(!isFwd)
180     {
181       isRvs = anOri == TopAbs_REVERSED;
182     }
183     if(SkipShared)
184     {
185       if((isFwd && !aFwdFMap.Add(F)) || (isRvs && !aRvsFMap.Add(F)))
186       {
187         continue;
188       }
189     }
190     if (isFwd || isRvs){
191       BF.Load(F);
192       TopoDS_Iterator aWIter(F);
193       Standard_Boolean IsNatRestr = !aWIter.More();
194       if(!IsNatRestr) BD.Init(F);
195       if(Eps < 1.0) {
196         G.Perform(BF, BD, Eps); 
197         Error = G.GetEpsilon();
198         if(ErrorMax < Error) {
199           ErrorMax = Error;
200 #ifdef OCCT_DEBUG
201           iErrorMax = i;
202 #endif
203         }
204       }
205       else {
206         if(IsNatRestr) G.Perform(BF);
207         else G.Perform(BF, BD);
208       }
209       Props.Add(G);
210 #ifdef OCCT_DEBUG
211       if(AffichEps) cout<<"\n"<<i<<":\tEpsVolume = "<< G.GetEpsilon();
212 #endif
213     }
214   }
215 #ifdef OCCT_DEBUG
216   if(AffichEps) cout<<"\n-----------------\n"<<iErrorMax<<":\tMaxError = "<<ErrorMax<<"\n";
217 #endif
218   return ErrorMax;
219 }
220 void  BRepGProp::VolumeProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Boolean OnlyClosed, const Standard_Boolean SkipShared){
221   // find the origin
222   gp_Pnt P(0,0,0);  P.Transform(S.Location());
223   Props = GProp_GProps(P);
224   if(OnlyClosed){
225     TopTools_MapOfShape aShMap;
226     TopExp_Explorer ex(S,TopAbs_SHELL);
227     for (; ex.More(); ex.Next()) {
228       const TopoDS_Shape& Sh = ex.Current();
229       if(SkipShared && !aShMap.Add(Sh))
230       {
231         continue;
232       }
233       if(BRep_Tool::IsClosed(Sh)) volumeProperties(Sh,Props,1.0,SkipShared);
234     }
235   } else volumeProperties(S,Props,1.0,SkipShared);
236 }
237
238 //=======================================================================
239 //function : VolumeProperties
240 //purpose  : 
241 //=======================================================================
242
243 Standard_Real BRepGProp::VolumeProperties(const TopoDS_Shape& S, GProp_GProps& Props, 
244   const Standard_Real Eps, const Standard_Boolean OnlyClosed, const Standard_Boolean SkipShared)
245
246   // find the origin
247   gp_Pnt P(0,0,0);  P.Transform(S.Location());
248   Props = GProp_GProps(P);
249   Standard_Integer i;
250 #ifdef OCCT_DEBUG
251   Standard_Integer iErrorMax = 0;
252 #endif
253   Standard_Real ErrorMax = 0.0, Error = 0.0;
254   if(OnlyClosed){
255     TopTools_MapOfShape aShMap;
256     TopExp_Explorer ex(S,TopAbs_SHELL);
257     for (i = 1; ex.More(); ex.Next(), i++) {
258       const TopoDS_Shape& Sh = ex.Current();
259       if(SkipShared && !aShMap.Add(Sh))
260       {
261         continue;
262       }
263       if(BRep_Tool::IsClosed(Sh)) {
264         Error = volumeProperties(Sh,Props,Eps,SkipShared);
265         if(ErrorMax < Error) {
266           ErrorMax = Error;
267 #ifdef OCCT_DEBUG
268           iErrorMax = i;
269 #endif
270         }
271       }
272     }
273   } else ErrorMax = volumeProperties(S,Props,Eps,SkipShared);
274 #ifdef OCCT_DEBUG
275   if(AffichEps) cout<<"\n\n==================="<<iErrorMax<<":\tMaxEpsVolume = "<<ErrorMax<<"\n";
276 #endif
277   return ErrorMax;
278
279
280 //===========================================================================================//
281 // Volume properties by Gauss-Kronrod integration
282 //===========================================================================================//
283 //=======================================================================
284 //function : VolumePropertiesGK
285 //purpose  : 
286 //=======================================================================
287
288 static Standard_Real volumePropertiesGK(const TopoDS_Shape     &theShape,
289   GProp_GProps     &theProps,
290   const Standard_Real     theTol,
291   const Standard_Boolean  IsUseSpan,
292   const Standard_Boolean  CGFlag,
293   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
294 {
295   TopExp_Explorer  anExp;
296   anExp.Init(theShape, TopAbs_FACE);
297
298   Standard_Real aTol = theTol;
299
300   // Compute properties.
301   gp_Pnt           aLoc(roughBaryCenter(theShape)); 
302   BRepGProp_VinertGK aVProps;
303   BRepGProp_Face   aPropFace(IsUseSpan);
304   BRepGProp_Domain aPropDomain;
305   Standard_Real    aLocalError;
306   Standard_Real    anError = 0.;
307   TopTools_MapOfShape aFwdFMap;
308   TopTools_MapOfShape aRvsFMap;
309
310   aVProps.SetLocation(aLoc);
311
312   for (; anExp.More(); anExp.Next()) {
313     TopoDS_Face aFace = TopoDS::Face(anExp.Current());
314     TopAbs_Orientation anOri = aFace.Orientation();
315     Standard_Boolean isFwd = anOri == TopAbs_FORWARD;
316     Standard_Boolean isRvs = Standard_False;
317     if(!isFwd)
318     {
319       isRvs = anOri == TopAbs_REVERSED;
320     }
321     if(SkipShared)
322     {
323       if((isFwd && !aFwdFMap.Add(aFace)) || (isRvs && !aRvsFMap.Add(aFace)))
324       {
325         continue;
326       }
327     }
328     if (isFwd || isRvs){
329         aPropFace.Load(aFace);
330
331         TopoDS_Iterator aWIter(aFace);
332         Standard_Boolean IsNatRestr = !aWIter.More();
333         if(IsNatRestr)
334           aLocalError = aVProps.Perform(aPropFace, aTol, CGFlag, IFlag);
335         else {
336           aPropDomain.Init(aFace);
337           aLocalError = aVProps.Perform(aPropFace, aPropDomain, aTol, CGFlag, IFlag);
338         }
339
340         if (aLocalError < 0.)
341           return aLocalError;
342
343         anError += aLocalError;
344         theProps.Add(aVProps);
345     }
346   }
347
348   return anError;
349 }
350
351 //=======================================================================
352 //function : VolumePropertiesGK
353 //purpose  : 
354 //=======================================================================
355
356 Standard_Real BRepGProp::VolumePropertiesGK(const TopoDS_Shape     &S,
357   GProp_GProps     &Props, 
358   const Standard_Real     Eps,
359   const Standard_Boolean  OnlyClosed,
360   const Standard_Boolean  IsUseSpan,
361   const Standard_Boolean  CGFlag,
362   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
363
364   gp_Pnt        P(0,0,0);
365   Standard_Real anError = 0.;
366
367   P.Transform(S.Location());
368   Props = GProp_GProps(P);
369
370   if(OnlyClosed) {
371     // To select closed shells.
372     TopExp_Explorer  anExp;
373     TopTools_ListOfShape aClosedShells;
374     TopTools_MapOfShape aShMap;
375
376     anExp.Init(S, TopAbs_SHELL);
377
378     for (; anExp.More(); anExp.Next()) {
379       const TopoDS_Shape &aShell = anExp.Current();
380       if(SkipShared && !aShMap.Add(aShell))
381       {
382         continue;
383       }
384
385       BRepCheck_Shell aChecker(TopoDS::Shell(aShell));
386       BRepCheck_Status aStatus = aChecker.Closed(Standard_False);
387
388       if(aStatus == BRepCheck_NoError) 
389         aClosedShells.Append(aShell);
390
391     }
392
393     if (aClosedShells.IsEmpty())
394       return -1.;
395
396     // Compute the properties for each closed shell.
397     Standard_Real aTol    = Eps;
398     Standard_Real aLocalError;
399     TopTools_ListIteratorOfListOfShape anIter(aClosedShells);
400
401     for (; anIter.More(); anIter.Next()) {
402       const TopoDS_Shape &aShell = anIter.Value();
403
404       aLocalError = volumePropertiesGK(aShell, Props, aTol, IsUseSpan, CGFlag, IFlag,SkipShared);
405
406       if (aLocalError < 0)
407         return aLocalError;
408
409       anError += aLocalError;
410     }
411
412   } else
413     anError = volumePropertiesGK(S, Props, Eps, IsUseSpan, CGFlag, IFlag,SkipShared);
414
415   Standard_Real vol = Props.Mass();
416   if(vol > Epsilon(1.)) anError /= vol;
417   return anError;
418 }
419
420 //=======================================================================
421 //function : VolumeProperties
422 //purpose  : 
423 //=======================================================================
424
425 static Standard_Real volumePropertiesGK(const TopoDS_Shape     &theShape,
426   GProp_GProps     &theProps,
427   const gp_Pln           &thePln,
428   const Standard_Real     theTol,
429   const Standard_Boolean  IsUseSpan,
430   const Standard_Boolean  CGFlag,
431   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
432 {
433   TopExp_Explorer  anExp;
434   anExp.Init(theShape, TopAbs_FACE);
435
436   Standard_Real aTol = theTol;
437
438   // Compute properties.
439   gp_Pnt           aLoc(roughBaryCenter(theShape)); 
440   BRepGProp_VinertGK aVProps;
441   BRepGProp_Face   aPropFace(IsUseSpan);
442   BRepGProp_Domain aPropDomain;
443   Standard_Real    aLocalError;
444   Standard_Real    anError = 0.;
445   TopTools_MapOfShape aFwdFMap;
446   TopTools_MapOfShape aRvsFMap;
447
448   aVProps.SetLocation(aLoc);
449
450   for (; anExp.More(); anExp.Next()) {
451     TopoDS_Face aFace = TopoDS::Face(anExp.Current());
452     TopAbs_Orientation anOri = aFace.Orientation();
453     Standard_Boolean isFwd = anOri == TopAbs_FORWARD;
454     Standard_Boolean isRvs = Standard_False;
455     if(!isFwd)
456     {
457       isRvs = anOri == TopAbs_REVERSED;
458     }
459     if(SkipShared)
460     {
461       if((isFwd && !aFwdFMap.Add(aFace)) || (isRvs && !aRvsFMap.Add(aFace)))
462       {
463         continue;
464       }
465     }
466     if (isFwd || isRvs){
467         aPropFace.Load(aFace);
468
469         TopoDS_Iterator aWIter(aFace);
470         Standard_Boolean IsNatRestr = !aWIter.More();
471         if(IsNatRestr)
472           aLocalError = aVProps.Perform(aPropFace, thePln, aTol, CGFlag, IFlag);
473         else {
474           aPropDomain.Init(aFace);
475           aLocalError = aVProps.Perform(aPropFace, aPropDomain, thePln, aTol, CGFlag, IFlag);
476         }
477
478         if (aLocalError < 0.)
479           return aLocalError;
480
481         anError += aLocalError;
482         theProps.Add(aVProps);
483     }
484   }
485
486   return anError;
487 }
488
489 //=======================================================================
490 //function : VolumeProperties
491 //purpose  : 
492 //=======================================================================
493
494 Standard_Real BRepGProp::VolumePropertiesGK(const TopoDS_Shape     &S,
495   GProp_GProps     &Props,
496   const gp_Pln           &thePln,
497   const Standard_Real     Eps,
498   const Standard_Boolean  OnlyClosed,
499   const Standard_Boolean  IsUseSpan,
500   const Standard_Boolean  CGFlag,
501   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
502
503   gp_Pnt        P(0,0,0);
504   Standard_Real anError = 0.;
505
506   P.Transform(S.Location());
507   Props = GProp_GProps(P);
508
509   if(OnlyClosed) {
510     // To select closed shells.
511     TopExp_Explorer  anExp;
512     TopTools_ListOfShape aClosedShells;
513     TopTools_MapOfShape aShMap;
514
515     anExp.Init(S, TopAbs_SHELL);
516
517     for (; anExp.More(); anExp.Next()) {
518       const TopoDS_Shape &aShell = anExp.Current();
519       if(SkipShared && !aShMap.Add(aShell))
520       {
521         continue;
522       }
523
524       BRepCheck_Shell aChecker(TopoDS::Shell(aShell));
525       BRepCheck_Status aStatus = aChecker.Closed(Standard_False);
526
527       if(aStatus == BRepCheck_NoError) 
528         aClosedShells.Append(aShell);
529
530     }
531
532     if (aClosedShells.IsEmpty())
533       return -1.;
534
535     // Compute the properties for each closed shell.
536     Standard_Real aTol    = Eps;
537     Standard_Real aLocalError;
538     TopTools_ListIteratorOfListOfShape anIter(aClosedShells);
539
540     for (; anIter.More(); anIter.Next()) {
541       const TopoDS_Shape &aShell = anIter.Value();
542
543       aLocalError = volumePropertiesGK(aShell, Props, thePln, aTol, IsUseSpan, CGFlag, IFlag,SkipShared);
544
545       if (aLocalError < 0)
546         return aLocalError;
547
548       anError += aLocalError;
549     }
550   } else
551     anError = volumePropertiesGK(S, Props, thePln, Eps, IsUseSpan, CGFlag, IFlag,SkipShared);
552
553   Standard_Real vol = Props.Mass();
554   if(vol > Epsilon(1.)) anError /= vol;
555
556   return anError;
557 }