0029734: Modeling Algorithms - Compute global properties of tessellated shape
[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_MeshProps.hxx>
20 #include <BRepGProp_MeshCinert.hxx>
21 #include <BRepGProp_VinertGK.hxx>
22 #include <GProp_PGProps.hxx>
23 #include <BRepGProp_Face.hxx>
24 #include <BRepGProp_Domain.hxx>
25 #include <TopoDS.hxx>
26 #include <BRepAdaptor_Curve.hxx>
27
28 #include <TopTools.hxx>
29 #include <BRep_Tool.hxx>  
30 #include <TopTools_ListOfShape.hxx>
31 #include <TopTools_MapOfShape.hxx>
32 #include <BRepCheck_Shell.hxx>
33 #include <TopTools_ListIteratorOfListOfShape.hxx>
34
35 #ifdef OCCT_DEBUG
36 static Standard_Integer AffichEps = 0;
37 #endif
38
39 static gp_Pnt roughBaryCenter(const TopoDS_Shape& S){
40   Standard_Integer i;  TopExp_Explorer ex;
41   gp_XYZ xyz(0,0,0);
42   for (ex.Init(S,TopAbs_VERTEX), i = 0; ex.More(); ex.Next(), i++) 
43     xyz += BRep_Tool::Pnt(TopoDS::Vertex(ex.Current())).XYZ();
44   if (i > 0)
45   {
46     xyz /= i;
47   }
48   else
49   {
50     //Try using triangulation
51     ex.Init(S, TopAbs_FACE);
52     for (; ex.More(); ex.Next())
53     {
54       const TopoDS_Shape& aF = ex.Current();
55       TopLoc_Location aLocDummy;
56       const Handle(Poly_Triangulation)& aTri =
57         BRep_Tool::Triangulation(TopoDS::Face(aF), aLocDummy);
58       if (!aTri.IsNull())
59       {
60         xyz = aTri->Node(1).XYZ();
61         if (!aLocDummy.IsIdentity())
62         {
63           aLocDummy.Transformation().Transforms(xyz);
64         }
65         break;
66       }
67     }
68   }
69   return gp_Pnt(xyz);
70 }
71
72
73
74 void  BRepGProp::LinearProperties(const TopoDS_Shape& S, GProp_GProps& SProps, const Standard_Boolean SkipShared,
75                                   const Standard_Boolean UseTriangulation)
76 {
77   // find the origin
78   gp_Pnt P(0,0,0);
79   P.Transform(S.Location());
80   SProps = GProp_GProps(P);
81
82   BRepAdaptor_Curve   BAC;
83   TopTools_MapOfShape anEMap;
84   TopExp_Explorer ex;
85   for (ex.Init(S,TopAbs_EDGE); ex.More(); ex.Next()) {
86     const TopoDS_Edge& aE = TopoDS::Edge(ex.Current());
87     if(SkipShared && !anEMap.Add(aE))
88     {
89       continue;
90     }
91
92     Handle(TColgp_HArray1OfPnt) theNodes;
93     Standard_Boolean IsGeom = BRep_Tool::IsGeometric(aE);
94     if (UseTriangulation || !IsGeom)
95     {
96       BRepGProp_MeshCinert::PreparePolygon(aE, theNodes);
97     }
98     if(!theNodes.IsNull())
99     {
100       BRepGProp_MeshCinert MG;
101       MG.SetLocation(P);
102       MG.Perform(theNodes->Array1());
103       SProps.Add(MG);
104     }
105     else
106     {
107       if (IsGeom)
108       {
109         BAC.Initialize(aE);
110         BRepGProp_Cinert CG(BAC, P);
111         SProps.Add(CG);
112       }
113     }
114   }
115 }
116
117 static Standard_Real surfaceProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Real Eps, const Standard_Boolean SkipShared,
118                                        const Standard_Boolean UseTriangulation)
119 {
120   Standard_Integer i;
121 #ifdef OCCT_DEBUG
122   Standard_Integer iErrorMax = 0;
123 #endif
124   Standard_Real ErrorMax = 0.0, Error;
125   TopExp_Explorer ex; 
126   gp_Pnt P(roughBaryCenter(S));
127   BRepGProp_Sinert G;  G.SetLocation(P);
128   BRepGProp_MeshProps MG(BRepGProp_MeshProps::Sinert);  
129   MG.SetLocation(P);
130
131   BRepGProp_Face   BF;
132   BRepGProp_Domain BD;
133   TopTools_MapOfShape aFMap;
134   TopLoc_Location aLocDummy;
135
136   for (ex.Init(S, TopAbs_FACE), i = 1; ex.More(); ex.Next(), i++) {
137     const TopoDS_Face& F = TopoDS::Face(ex.Current());
138     if (SkipShared && !aFMap.Add(F))
139     {
140       continue;
141     }
142
143     Standard_Boolean NoSurf = Standard_False, NoTri = Standard_False;
144     {
145       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(F, aLocDummy);
146       if (aSurf.IsNull())
147       {
148         NoSurf = Standard_True;
149       }
150       const Handle(Poly_Triangulation)& aTri = BRep_Tool::Triangulation(F, aLocDummy);
151       if (aTri.IsNull())
152       {
153         NoTri = Standard_True;
154       }
155       if (NoTri && NoSurf)
156       {
157         continue;
158       }
159     }
160
161     if ((UseTriangulation && !NoTri) || (NoSurf && !NoTri))
162     {
163       TopAbs_Orientation anOri = F.Orientation();
164       const Handle(Poly_Triangulation)& aTri = BRep_Tool::Triangulation(F, aLocDummy);
165       MG.Perform(aTri, aLocDummy, anOri);
166       Props.Add(MG);
167     }
168     else
169     {
170       BF.Load(F);
171       Standard_Boolean IsNatRestr = (F.NbChildren() == 0);
172       if (!IsNatRestr) BD.Init(F);
173       if (Eps < 1.0) {
174         G.Perform(BF, BD, Eps);
175         Error = G.GetEpsilon();
176         if (ErrorMax < Error) {
177           ErrorMax = Error;
178 #ifdef OCCT_DEBUG
179           iErrorMax = i;
180 #endif
181         }
182       }
183       else {
184         if (IsNatRestr) G.Perform(BF);
185         else G.Perform(BF, BD);
186       }
187       Props.Add(G);
188 #ifdef OCCT_DEBUG
189       if(AffichEps) cout<<"\n"<<i<<":\tEpsArea = "<< G.GetEpsilon();
190 #endif
191     }
192   }
193 #ifdef OCCT_DEBUG
194   if(AffichEps) cout<<"\n-----------------\n"<<iErrorMax<<":\tMaxError = "<<ErrorMax<<"\n";
195 #endif
196   return ErrorMax;
197 }
198 void  BRepGProp::SurfaceProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Boolean SkipShared,
199                                    const Standard_Boolean UseTriangulation)
200 {
201   // find the origin
202   gp_Pnt P(0,0,0);
203   P.Transform(S.Location());
204   Props = GProp_GProps(P);
205   surfaceProperties(S,Props,1.0, SkipShared, UseTriangulation);
206 }
207 Standard_Real BRepGProp::SurfaceProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Real Eps, const Standard_Boolean SkipShared){ 
208   // find the origin
209   gp_Pnt P(0,0,0);  P.Transform(S.Location());
210   Props = GProp_GProps(P);
211   Standard_Real ErrorMax = surfaceProperties(S,Props,Eps,SkipShared, Standard_False);
212   return ErrorMax;
213 }
214
215 //=======================================================================
216 //function : volumeProperties
217 //purpose  : 
218 //=======================================================================
219
220 static Standard_Real volumeProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Real Eps, const Standard_Boolean SkipShared,
221                                       const Standard_Boolean UseTriangulation)
222 {
223   Standard_Integer i;
224 #ifdef OCCT_DEBUG
225   Standard_Integer iErrorMax = 0;
226 #endif
227   Standard_Real ErrorMax = 0.0, Error = 0.0;
228   TopExp_Explorer ex; 
229   gp_Pnt P(roughBaryCenter(S)); 
230   BRepGProp_Vinert G;  G.SetLocation(P);
231   BRepGProp_MeshProps MG(BRepGProp_MeshProps::Vinert);
232   MG.SetLocation(P);
233
234   BRepGProp_Face   BF;
235   BRepGProp_Domain BD;
236   TopTools_MapOfShape aFwdFMap;
237   TopTools_MapOfShape aRvsFMap;
238   TopLoc_Location aLocDummy;
239
240   for (ex.Init(S,TopAbs_FACE), i = 1; ex.More(); ex.Next(), i++) {
241     const TopoDS_Face& F = TopoDS::Face(ex.Current());
242     TopAbs_Orientation anOri = F.Orientation();
243     Standard_Boolean isFwd = anOri == TopAbs_FORWARD;
244     Standard_Boolean isRvs = Standard_False;
245     if(!isFwd)
246     {
247       isRvs = anOri == TopAbs_REVERSED;
248     }
249     if(SkipShared)
250     {
251       if((isFwd && !aFwdFMap.Add(F)) || (isRvs && !aRvsFMap.Add(F)))
252       {
253         continue;
254       }
255     }
256     Standard_Boolean NoSurf = Standard_False, NoTri = Standard_False;
257     {
258       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (F, aLocDummy);
259       if (aSurf.IsNull())
260       {
261         NoSurf = Standard_True;
262       }
263       const Handle(Poly_Triangulation)& aTri = BRep_Tool::Triangulation(F, aLocDummy);
264       if (aTri.IsNull())
265       {
266         NoTri = Standard_True;
267       }
268       if (NoTri && NoSurf)
269       {
270         continue;
271       }
272     }
273
274     if (isFwd || isRvs)
275     {
276       if ((UseTriangulation && !NoTri) || (NoSurf && !NoTri))
277       {
278         const Handle(Poly_Triangulation)& aTri = BRep_Tool::Triangulation(F, aLocDummy);
279         MG.Perform(aTri, aLocDummy, anOri);
280         Props.Add(MG);
281       }
282       else
283       {
284         BF.Load(F);
285         Standard_Boolean IsNatRestr = (F.NbChildren () == 0);
286         if (!IsNatRestr) BD.Init(F);
287         if (Eps < 1.0) {
288           G.Perform(BF, BD, Eps);
289           Error = G.GetEpsilon();
290           if (ErrorMax < Error) {
291             ErrorMax = Error;
292 #ifdef OCCT_DEBUG
293             iErrorMax = i;
294 #endif
295           }
296         }
297         else {
298           if (IsNatRestr) G.Perform(BF);
299           else G.Perform(BF, BD);
300         }
301         Props.Add(G);
302 #ifdef OCCT_DEBUG
303         if(AffichEps) cout<<"\n"<<i<<":\tEpsVolume = "<< G.GetEpsilon();
304 #endif
305       }
306     }
307   }
308 #ifdef OCCT_DEBUG
309   if(AffichEps) cout<<"\n-----------------\n"<<iErrorMax<<":\tMaxError = "<<ErrorMax<<"\n";
310 #endif
311   return ErrorMax;
312 }
313 void  BRepGProp::VolumeProperties(const TopoDS_Shape& S, GProp_GProps& Props, const Standard_Boolean OnlyClosed, const Standard_Boolean SkipShared,
314                                   const Standard_Boolean UseTriangulation)
315 {
316   // find the origin
317   gp_Pnt P(0,0,0);  P.Transform(S.Location());
318   Props = GProp_GProps(P);
319   if(OnlyClosed){
320     TopTools_MapOfShape aShMap;
321     TopExp_Explorer ex(S,TopAbs_SHELL);
322     for (; ex.More(); ex.Next()) {
323       const TopoDS_Shape& Sh = ex.Current();
324       if(SkipShared && !aShMap.Add(Sh))
325       {
326         continue;
327       }
328       if(BRep_Tool::IsClosed(Sh)) volumeProperties(Sh,Props,1.0,SkipShared, UseTriangulation);
329     }
330   } else volumeProperties(S,Props,1.0,SkipShared, UseTriangulation);
331 }
332
333 //=======================================================================
334 //function : VolumeProperties
335 //purpose  : 
336 //=======================================================================
337
338 Standard_Real BRepGProp::VolumeProperties(const TopoDS_Shape& S, GProp_GProps& Props, 
339   const Standard_Real Eps, const Standard_Boolean OnlyClosed, const Standard_Boolean SkipShared)
340
341   // find the origin
342   gp_Pnt P(0,0,0);  P.Transform(S.Location());
343   Props = GProp_GProps(P);
344   Standard_Integer i;
345 #ifdef OCCT_DEBUG
346   Standard_Integer iErrorMax = 0;
347 #endif
348   Standard_Real ErrorMax = 0.0, Error = 0.0;
349   if(OnlyClosed){
350     TopTools_MapOfShape aShMap;
351     TopExp_Explorer ex(S,TopAbs_SHELL);
352     for (i = 1; ex.More(); ex.Next(), i++) {
353       const TopoDS_Shape& Sh = ex.Current();
354       if(SkipShared && !aShMap.Add(Sh))
355       {
356         continue;
357       }
358       if(BRep_Tool::IsClosed(Sh)) {
359         Error = volumeProperties(Sh,Props,Eps,SkipShared, Standard_False);
360         if(ErrorMax < Error) {
361           ErrorMax = Error;
362 #ifdef OCCT_DEBUG
363           iErrorMax = i;
364 #endif
365         }
366       }
367     }
368   } else ErrorMax = volumeProperties(S,Props,Eps,SkipShared, Standard_False);
369 #ifdef OCCT_DEBUG
370   if(AffichEps) cout<<"\n\n==================="<<iErrorMax<<":\tMaxEpsVolume = "<<ErrorMax<<"\n";
371 #endif
372   return ErrorMax;
373
374
375 //===========================================================================================//
376 // Volume properties by Gauss-Kronrod integration
377 //===========================================================================================//
378 //=======================================================================
379 //function : VolumePropertiesGK
380 //purpose  : 
381 //=======================================================================
382
383 static Standard_Real volumePropertiesGK(const TopoDS_Shape     &theShape,
384   GProp_GProps     &theProps,
385   const Standard_Real     theTol,
386   const Standard_Boolean  IsUseSpan,
387   const Standard_Boolean  CGFlag,
388   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
389 {
390   TopExp_Explorer  anExp;
391   anExp.Init(theShape, TopAbs_FACE);
392
393   Standard_Real aTol = theTol;
394
395   // Compute properties.
396   gp_Pnt           aLoc(roughBaryCenter(theShape)); 
397   BRepGProp_VinertGK aVProps;
398   BRepGProp_Face   aPropFace(IsUseSpan);
399   BRepGProp_Domain aPropDomain;
400   Standard_Real    aLocalError;
401   Standard_Real    anError = 0.;
402   TopTools_MapOfShape aFwdFMap;
403   TopTools_MapOfShape aRvsFMap;
404   TopLoc_Location aLocDummy;
405
406   aVProps.SetLocation(aLoc);
407
408   for (; anExp.More(); anExp.Next()) {
409     TopoDS_Face aFace = TopoDS::Face(anExp.Current());
410     TopAbs_Orientation anOri = aFace.Orientation();
411     Standard_Boolean isFwd = anOri == TopAbs_FORWARD;
412     Standard_Boolean isRvs = Standard_False;
413     if(!isFwd)
414     {
415       isRvs = anOri == TopAbs_REVERSED;
416     }
417     if(SkipShared)
418     {
419       if((isFwd && !aFwdFMap.Add(aFace)) || (isRvs && !aRvsFMap.Add(aFace)))
420       {
421         continue;
422       }
423     }
424     {
425       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (aFace, aLocDummy);
426       if (aSurf.IsNull())
427       {
428         // skip faces without geometry
429         continue;
430       }
431     }
432
433     if (isFwd || isRvs){
434         aPropFace.Load(aFace);
435
436         Standard_Boolean IsNatRestr = (aFace.NbChildren () == 0);
437         if(IsNatRestr)
438           aLocalError = aVProps.Perform(aPropFace, aTol, CGFlag, IFlag);
439         else {
440           aPropDomain.Init(aFace);
441           aLocalError = aVProps.Perform(aPropFace, aPropDomain, aTol, CGFlag, IFlag);
442         }
443
444         if (aLocalError < 0.)
445           return aLocalError;
446
447         anError += aLocalError;
448         theProps.Add(aVProps);
449     }
450   }
451
452   return anError;
453 }
454
455 //=======================================================================
456 //function : VolumePropertiesGK
457 //purpose  : 
458 //=======================================================================
459
460 Standard_Real BRepGProp::VolumePropertiesGK(const TopoDS_Shape     &S,
461   GProp_GProps     &Props, 
462   const Standard_Real     Eps,
463   const Standard_Boolean  OnlyClosed,
464   const Standard_Boolean  IsUseSpan,
465   const Standard_Boolean  CGFlag,
466   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
467
468   gp_Pnt        P(0,0,0);
469   Standard_Real anError = 0.;
470
471   P.Transform(S.Location());
472   Props = GProp_GProps(P);
473
474   if(OnlyClosed) {
475     // To select closed shells.
476     TopExp_Explorer  anExp;
477     TopTools_ListOfShape aClosedShells;
478     TopTools_MapOfShape aShMap;
479
480     anExp.Init(S, TopAbs_SHELL);
481
482     for (; anExp.More(); anExp.Next()) {
483       const TopoDS_Shape &aShell = anExp.Current();
484       if(SkipShared && !aShMap.Add(aShell))
485       {
486         continue;
487       }
488
489       BRepCheck_Shell aChecker(TopoDS::Shell(aShell));
490       BRepCheck_Status aStatus = aChecker.Closed(Standard_False);
491
492       if(aStatus == BRepCheck_NoError) 
493         aClosedShells.Append(aShell);
494
495     }
496
497     if (aClosedShells.IsEmpty())
498       return -1.;
499
500     // Compute the properties for each closed shell.
501     Standard_Real aTol    = Eps;
502     Standard_Real aLocalError;
503     TopTools_ListIteratorOfListOfShape anIter(aClosedShells);
504
505     for (; anIter.More(); anIter.Next()) {
506       const TopoDS_Shape &aShell = anIter.Value();
507
508       aLocalError = volumePropertiesGK(aShell, Props, aTol, IsUseSpan, CGFlag, IFlag,SkipShared);
509
510       if (aLocalError < 0)
511         return aLocalError;
512
513       anError += aLocalError;
514     }
515
516   } else
517     anError = volumePropertiesGK(S, Props, Eps, IsUseSpan, CGFlag, IFlag,SkipShared);
518
519   Standard_Real vol = Props.Mass();
520   if(vol > Epsilon(1.)) anError /= vol;
521   return anError;
522 }
523
524 //=======================================================================
525 //function : VolumeProperties
526 //purpose  : 
527 //=======================================================================
528
529 static Standard_Real volumePropertiesGK(const TopoDS_Shape     &theShape,
530   GProp_GProps     &theProps,
531   const gp_Pln           &thePln,
532   const Standard_Real     theTol,
533   const Standard_Boolean  IsUseSpan,
534   const Standard_Boolean  CGFlag,
535   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
536 {
537   TopExp_Explorer  anExp;
538   anExp.Init(theShape, TopAbs_FACE);
539
540   Standard_Real aTol = theTol;
541
542   // Compute properties.
543   gp_Pnt           aLoc(roughBaryCenter(theShape)); 
544   BRepGProp_VinertGK aVProps;
545   BRepGProp_Face   aPropFace(IsUseSpan);
546   BRepGProp_Domain aPropDomain;
547   Standard_Real    aLocalError;
548   Standard_Real    anError = 0.;
549   TopTools_MapOfShape aFwdFMap;
550   TopTools_MapOfShape aRvsFMap;
551   TopLoc_Location aLocDummy;
552
553   aVProps.SetLocation(aLoc);
554
555   for (; anExp.More(); anExp.Next()) {
556     TopoDS_Face aFace = TopoDS::Face(anExp.Current());
557     TopAbs_Orientation anOri = aFace.Orientation();
558     Standard_Boolean isFwd = anOri == TopAbs_FORWARD;
559     Standard_Boolean isRvs = Standard_False;
560     if(!isFwd)
561     {
562       isRvs = anOri == TopAbs_REVERSED;
563     }
564     if(SkipShared)
565     {
566       if((isFwd && !aFwdFMap.Add(aFace)) || (isRvs && !aRvsFMap.Add(aFace)))
567       {
568         continue;
569       }
570     }
571     {
572       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (aFace, aLocDummy);
573       if (aSurf.IsNull())
574       {
575         // skip faces without geometry
576         continue;
577       }
578     }
579
580     if (isFwd || isRvs){
581         aPropFace.Load(aFace);
582
583         Standard_Boolean IsNatRestr = (aFace.NbChildren () == 0);
584         if(IsNatRestr)
585           aLocalError = aVProps.Perform(aPropFace, thePln, aTol, CGFlag, IFlag);
586         else {
587           aPropDomain.Init(aFace);
588           aLocalError = aVProps.Perform(aPropFace, aPropDomain, thePln, aTol, CGFlag, IFlag);
589         }
590
591         if (aLocalError < 0.)
592           return aLocalError;
593
594         anError += aLocalError;
595         theProps.Add(aVProps);
596     }
597   }
598
599   return anError;
600 }
601
602 //=======================================================================
603 //function : VolumeProperties
604 //purpose  : 
605 //=======================================================================
606
607 Standard_Real BRepGProp::VolumePropertiesGK(const TopoDS_Shape     &S,
608   GProp_GProps     &Props,
609   const gp_Pln           &thePln,
610   const Standard_Real     Eps,
611   const Standard_Boolean  OnlyClosed,
612   const Standard_Boolean  IsUseSpan,
613   const Standard_Boolean  CGFlag,
614   const Standard_Boolean  IFlag, const Standard_Boolean SkipShared)
615
616   gp_Pnt        P(0,0,0);
617   Standard_Real anError = 0.;
618
619   P.Transform(S.Location());
620   Props = GProp_GProps(P);
621
622   if(OnlyClosed) {
623     // To select closed shells.
624     TopExp_Explorer  anExp;
625     TopTools_ListOfShape aClosedShells;
626     TopTools_MapOfShape aShMap;
627
628     anExp.Init(S, TopAbs_SHELL);
629
630     for (; anExp.More(); anExp.Next()) {
631       const TopoDS_Shape &aShell = anExp.Current();
632       if(SkipShared && !aShMap.Add(aShell))
633       {
634         continue;
635       }
636
637       BRepCheck_Shell aChecker(TopoDS::Shell(aShell));
638       BRepCheck_Status aStatus = aChecker.Closed(Standard_False);
639
640       if(aStatus == BRepCheck_NoError) 
641         aClosedShells.Append(aShell);
642
643     }
644
645     if (aClosedShells.IsEmpty())
646       return -1.;
647
648     // Compute the properties for each closed shell.
649     Standard_Real aTol    = Eps;
650     Standard_Real aLocalError;
651     TopTools_ListIteratorOfListOfShape anIter(aClosedShells);
652
653     for (; anIter.More(); anIter.Next()) {
654       const TopoDS_Shape &aShell = anIter.Value();
655
656       aLocalError = volumePropertiesGK(aShell, Props, thePln, aTol, IsUseSpan, CGFlag, IFlag,SkipShared);
657
658       if (aLocalError < 0)
659         return aLocalError;
660
661       anError += aLocalError;
662     }
663   } else
664     anError = volumePropertiesGK(S, Props, thePln, Eps, IsUseSpan, CGFlag, IFlag,SkipShared);
665
666   Standard_Real vol = Props.Mass();
667   if(vol > Epsilon(1.)) anError /= vol;
668
669   return anError;
670 }