Files
OCCT/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp.cxx
T
Pasukhin Dmitry 0f57a42d89 Coding - Modernize handle APIs and deprecate out-parameter overloads (#1185)
Introduce return-by-value APIs for handle-returning methods across touched toolkits, with nodiscard where appropriate, and keep legacy out-parameter signatures as deprecated wrappers for source compatibility.

- Add new return-by-value overloads for previously output-parameter methods in key classes across ApplicationFramework, DataExchange, ModelingAlgorithms, ModelingData, and Visualization
- Mark legacy output-parameter methods as deprecated and route them through the new overloads
- Update call sites to use the new APIs and simplify temporary-variable patterns
- Extend method documentation in OCCT Doxygen style with param/return sections and deprecation guidance
- Apply const-correctness updates for read-only handle arguments in STEP reader related interfaces
- Preserve compatibility for deprecated public wrappers by keeping exported out-of-line definitions where needed
- Perform minor cleanup of comments and parameter naming consistency

No functional behavior change is intended; this is an API modernization and migration-facilitation update.
2026-04-04 12:09:46 +01:00

922 lines
28 KiB
C++

// Copyright (c) 1995-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BRepGProp.hxx>
#include <BRepGProp_Cinert.hxx>
#include <BRepGProp_Sinert.hxx>
#include <BRepGProp_Vinert.hxx>
#include <BRepGProp_MeshProps.hxx>
#include <BRepGProp_MeshCinert.hxx>
#include <BRepGProp_VinertGK.hxx>
#include <BRepGProp_Face.hxx>
#include <BRepGProp_Domain.hxx>
#include <TopoDS.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_Map.hxx>
#include <BRepCheck_Shell.hxx>
#include <TopTools_ShapeMapHasher.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Shape.hxx>
#include <cmath>
#ifdef OCCT_DEBUG
static int AffichEps = 0;
#endif
namespace
{
//! Helper to transform GProp_GProps by accessing protected members.
//! Used for solid-level caching: compute properties once per unique solid,
//! then transform for duplicate instances at different locations.
class GPropTransformer : public GProp_GProps
{
public:
GPropTransformer(const GProp_GProps& theSource)
: GProp_GProps(theSource)
{
}
//! Apply a rigid transform to the stored properties.
//! Transforms reference point (loc) as absolute point, gravity center offset (g)
//! as relative vector (rotation only, no translation), and rotates inertia tensor.
void ApplyTransform(const gp_Trsf& theTrsf)
{
loc.Transform(theTrsf);
const gp_TrsfForm aForm = theTrsf.Form();
if (aForm != gp_Identity && aForm != gp_Translation)
{
// g is a relative offset from loc to center of mass - rotate only.
const gp_Mat aR = theTrsf.VectorialPart();
gp_XYZ aGxyz = g.XYZ();
aGxyz.Multiply(aR);
g.SetXYZ(aGxyz);
const gp_Mat aRt = aR.Transposed();
inertia = aR.Multiplied(inertia).Multiplied(aRt);
}
}
//! Negate volume contribution (for reversed solid orientation).
void Negate()
{
dim = -dim;
inertia.Multiply(-1.0);
}
};
} // anonymous namespace
static gp_Pnt roughBaryCenter(const TopoDS_Shape& S)
{
int i;
TopExp_Explorer ex;
gp_XYZ xyz(0, 0, 0);
for (ex.Init(S, TopAbs_VERTEX), i = 0; ex.More(); ex.Next(), i++)
xyz += BRep_Tool::Pnt(TopoDS::Vertex(ex.Current())).XYZ();
if (i > 0)
{
xyz /= i;
}
else
{
// Try using triangulation
ex.Init(S, TopAbs_FACE);
for (; ex.More(); ex.Next())
{
const TopoDS_Shape& aF = ex.Current();
TopLoc_Location aLocDummy;
const occ::handle<Poly_Triangulation>& aTri =
BRep_Tool::Triangulation(TopoDS::Face(aF), aLocDummy);
if (!aTri.IsNull() && aTri->NbNodes() > 0)
{
xyz = aTri->Node(1).XYZ();
if (!aLocDummy.IsIdentity())
{
aLocDummy.Transformation().Transforms(xyz);
}
break;
}
}
}
return gp_Pnt(xyz);
}
void BRepGProp::LinearProperties(const TopoDS_Shape& S,
GProp_GProps& SProps,
const bool SkipShared,
const bool UseTriangulation)
{
// find the origin
gp_Pnt P(0, 0, 0);
P.Transform(S.Location());
SProps = GProp_GProps(P);
BRepAdaptor_Curve BAC;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> anEMap;
TopExp_Explorer ex;
for (ex.Init(S, TopAbs_EDGE); ex.More(); ex.Next())
{
const TopoDS_Edge& aE = TopoDS::Edge(ex.Current());
if (SkipShared && !anEMap.Add(aE))
{
continue;
}
occ::handle<NCollection_HArray1<gp_Pnt>> theNodes;
bool IsGeom = BRep_Tool::IsGeometric(aE);
if (UseTriangulation || !IsGeom)
{
theNodes = BRepGProp_MeshCinert::PreparePolygon(aE);
}
if (!theNodes.IsNull())
{
BRepGProp_MeshCinert MG;
MG.SetLocation(P);
MG.Perform(theNodes->Array1());
SProps.Add(MG);
}
else
{
if (IsGeom)
{
BAC.Initialize(aE);
BRepGProp_Cinert CG(BAC, P);
SProps.Add(CG);
}
}
}
}
static double surfaceProperties(const TopoDS_Shape& S,
GProp_GProps& Props,
const double Eps,
const bool SkipShared,
const bool UseTriangulation)
{
int i;
#ifdef OCCT_DEBUG
int iErrorMax = 0;
#endif
double ErrorMax = 0.0, Error;
TopExp_Explorer ex;
gp_Pnt P(roughBaryCenter(S));
BRepGProp_Sinert G;
G.SetLocation(P);
BRepGProp_MeshProps MG(BRepGProp_MeshProps::Sinert);
MG.SetLocation(P);
BRepGProp_Face BF;
BRepGProp_Domain BD;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aFMap;
TopLoc_Location aLocDummy;
for (ex.Init(S, TopAbs_FACE), i = 1; ex.More(); ex.Next(), i++)
{
const TopoDS_Face& F = TopoDS::Face(ex.Current());
if (SkipShared && !aFMap.Add(F))
{
continue;
}
bool NoSurf = false, NoTri = false;
{
const occ::handle<Geom_Surface>& aSurf = BRep_Tool::Surface(F, aLocDummy);
if (aSurf.IsNull())
{
NoSurf = true;
}
const occ::handle<Poly_Triangulation>& aTri = BRep_Tool::Triangulation(F, aLocDummy);
if (aTri.IsNull() || aTri->NbNodes() == 0 || aTri->NbTriangles() == 0)
{
NoTri = true;
}
if (NoTri && NoSurf)
{
continue;
}
}
if ((UseTriangulation && !NoTri) || (NoSurf && !NoTri))
{
TopAbs_Orientation anOri = F.Orientation();
const occ::handle<Poly_Triangulation>& aTri = BRep_Tool::Triangulation(F, aLocDummy);
MG.Perform(aTri, aLocDummy, anOri);
Props.Add(MG);
}
else
{
BF.Load(F);
bool IsNatRestr = (F.NbChildren() == 0);
if (!IsNatRestr)
BD.Init(F);
if (Eps < 1.0)
{
G.Perform(BF, BD, Eps);
Error = G.GetEpsilon();
if (ErrorMax < Error)
{
ErrorMax = Error;
#ifdef OCCT_DEBUG
iErrorMax = i;
#endif
}
}
else
{
if (IsNatRestr)
G.Perform(BF);
else
G.Perform(BF, BD);
}
Props.Add(G);
#ifdef OCCT_DEBUG
if (AffichEps)
std::cout << "\n" << i << ":\tEpsArea = " << G.GetEpsilon();
#endif
}
}
#ifdef OCCT_DEBUG
if (AffichEps)
std::cout << "\n-----------------\n" << iErrorMax << ":\tMaxError = " << ErrorMax << "\n";
#endif
return ErrorMax;
}
void BRepGProp::SurfaceProperties(const TopoDS_Shape& S,
GProp_GProps& Props,
const bool SkipShared,
const bool UseTriangulation)
{
// find the origin
gp_Pnt P(0, 0, 0);
P.Transform(S.Location());
Props = GProp_GProps(P);
surfaceProperties(S, Props, 1.0, SkipShared, UseTriangulation);
}
double BRepGProp::SurfaceProperties(const TopoDS_Shape& S,
GProp_GProps& Props,
const double Eps,
const bool SkipShared)
{
// find the origin
gp_Pnt P(0, 0, 0);
P.Transform(S.Location());
Props = GProp_GProps(P);
double ErrorMax = surfaceProperties(S, Props, Eps, SkipShared, false);
return ErrorMax;
}
//=================================================================================================
//! Process faces of a shape for volume properties computation.
//! This is the core face-level integration loop used both for unique solids
//! and for shapes without shared solids.
static double volumePropertiesFaces(const TopoDS_Shape& S,
GProp_GProps& Props,
const gp_Pnt& theRefPnt,
const double Eps,
const bool SkipShared,
const bool UseTriangulation)
{
int i;
#ifdef OCCT_DEBUG
int iErrorMax = 0;
#endif
double ErrorMax = 0.0, Error = 0.0;
TopExp_Explorer ex;
BRepGProp_Vinert G;
G.SetLocation(theRefPnt);
BRepGProp_MeshProps MG(BRepGProp_MeshProps::Vinert);
MG.SetLocation(theRefPnt);
BRepGProp_Face BF;
BRepGProp_Domain BD;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aFwdFMap;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aRvsFMap;
TopLoc_Location aLocDummy;
for (ex.Init(S, TopAbs_FACE), i = 1; ex.More(); ex.Next(), i++)
{
const TopoDS_Face& F = TopoDS::Face(ex.Current());
TopAbs_Orientation anOri = F.Orientation();
bool isFwd = anOri == TopAbs_FORWARD;
bool isRvs = false;
if (!isFwd)
{
isRvs = anOri == TopAbs_REVERSED;
}
if (SkipShared)
{
if ((isFwd && !aFwdFMap.Add(F)) || (isRvs && !aRvsFMap.Add(F)))
{
continue;
}
}
bool NoSurf = false, NoTri = false;
{
const occ::handle<Geom_Surface>& aSurf = BRep_Tool::Surface(F, aLocDummy);
if (aSurf.IsNull())
{
NoSurf = true;
}
const occ::handle<Poly_Triangulation>& aTri = BRep_Tool::Triangulation(F, aLocDummy);
if (aTri.IsNull() || aTri->NbNodes() == 0 || aTri->NbTriangles() == 0)
{
NoTri = true;
}
if (NoTri && NoSurf)
{
continue;
}
}
if (isFwd || isRvs)
{
if ((UseTriangulation && !NoTri) || (NoSurf && !NoTri))
{
const occ::handle<Poly_Triangulation>& aTri = BRep_Tool::Triangulation(F, aLocDummy);
MG.Perform(aTri, aLocDummy, anOri);
Props.Add(MG);
}
else
{
BF.Load(F);
bool IsNatRestr = (F.NbChildren() == 0);
if (!IsNatRestr)
BD.Init(F);
if (Eps < 1.0)
{
G.Perform(BF, BD, Eps);
Error = G.GetEpsilon();
if (ErrorMax < Error)
{
ErrorMax = Error;
#ifdef OCCT_DEBUG
iErrorMax = i;
#endif
}
}
else
{
if (IsNatRestr)
G.Perform(BF);
else
G.Perform(BF, BD);
}
Props.Add(G);
#ifdef OCCT_DEBUG
if (AffichEps)
std::cout << "\n" << i << ":\tEpsVolume = " << G.GetEpsilon();
#endif
}
}
}
#ifdef OCCT_DEBUG
if (AffichEps)
std::cout << "\n-----------------\n" << iErrorMax << ":\tMaxError = " << ErrorMax << "\n";
#endif
return ErrorMax;
}
//=================================================================================================
static double volumeProperties(const TopoDS_Shape& S,
GProp_GProps& Props,
const double Eps,
const bool SkipShared,
const bool UseTriangulation)
{
const gp_Pnt P(roughBaryCenter(S));
// Check for shared solids: if the same TShape appears multiple times
// (via compound nesting with different locations), we compute properties
// once per unique solid and reuse via rigid transform for duplicates.
bool hasSharedSolids = false;
{
NCollection_Map<opencascade::handle<TopoDS_TShape>> aSeenSolids;
for (TopExp_Explorer exS(S, TopAbs_SOLID); exS.More(); exS.Next())
{
if (!aSeenSolids.Add(exS.Current().TShape()))
{
hasSharedSolids = true;
break;
}
}
}
if (!hasSharedSolids)
{
// No shared solids: use direct face-level iteration (original path).
return volumePropertiesFaces(S, Props, P, Eps, SkipShared, UseTriangulation);
}
// Shared solids detected: iterate at solid level with caching.
// For each unique TShape, compute properties once via face integration.
// For duplicate instances, transform the cached result by the relative
// location and add to Props (using Huygens theorem via GProp_GProps::Add).
struct SolidCacheEntry
{
GProp_GProps Props;
TopLoc_Location Location;
TopAbs_Orientation Orientation;
};
NCollection_DataMap<opencascade::handle<TopoDS_TShape>, SolidCacheEntry> aSolidCache;
double ErrorMax = 0.0;
for (TopExp_Explorer exS(S, TopAbs_SOLID); exS.More(); exS.Next())
{
const TopoDS_Shape& aSolid = exS.Current();
const opencascade::handle<TopoDS_TShape>& aTS = aSolid.TShape();
if (aSolidCache.IsBound(aTS))
{
// Duplicate instance: transform cached properties.
const SolidCacheEntry& aCached = aSolidCache(aTS);
const TopLoc_Location aRelLoc = aSolid.Location().Multiplied(aCached.Location.Inverted());
// When SkipShared is enabled, skip exact duplicate instances
// (same placement and orientation) - matches original face-level dedup behavior.
if (SkipShared && aRelLoc.IsIdentity() && aSolid.Orientation() == aCached.Orientation)
{
continue;
}
// Cache reuse is only valid for rigid (isometric) transforms.
// Shape locations may contain scaling or negative determinant
// (TopoDS_Shape::Location() does not enforce rigidity by default),
// which would produce incorrect volume/inertia with rotation-only transform.
const gp_Trsf& aRelTrsf = aRelLoc.Transformation();
if (std::abs(std::abs(aRelTrsf.ScaleFactor()) - 1.0) > TopLoc_Location::ScalePrec()
|| aRelTrsf.IsNegative())
{
// Non-rigid relative transform: fall back to direct face-level computation.
GProp_GProps aSolidProps(P);
const double anError =
volumePropertiesFaces(aSolid, aSolidProps, P, Eps, SkipShared, UseTriangulation);
if (ErrorMax < anError)
{
ErrorMax = anError;
}
Props.Add(aSolidProps);
continue;
}
GPropTransformer aTransformed(aCached.Props);
if (!aRelLoc.IsIdentity())
{
aTransformed.ApplyTransform(aRelTrsf);
}
if (aSolid.Orientation() != aCached.Orientation)
{
aTransformed.Negate();
}
Props.Add(aTransformed);
}
else
{
// First instance of this TShape: compute via face integration.
GProp_GProps aSolidProps(P);
const double anError =
volumePropertiesFaces(aSolid, aSolidProps, P, Eps, SkipShared, UseTriangulation);
if (ErrorMax < anError)
{
ErrorMax = anError;
}
SolidCacheEntry anEntry;
anEntry.Props = aSolidProps;
anEntry.Location = aSolid.Location();
anEntry.Orientation = aSolid.Orientation();
aSolidCache.Bind(aTS, anEntry);
Props.Add(aSolidProps);
}
}
// Handle faces not belonging to any solid (free shells/faces in the compound).
{
bool hasFree = false;
TopoDS_Compound aFreeComp;
BRep_Builder aBld;
aBld.MakeCompound(aFreeComp);
for (TopExp_Explorer exF(S, TopAbs_FACE, TopAbs_SOLID); exF.More(); exF.Next())
{
aBld.Add(aFreeComp, exF.Current());
hasFree = true;
}
if (hasFree)
{
GProp_GProps aFreeProps(P);
const double aFreeError =
volumePropertiesFaces(aFreeComp, aFreeProps, P, Eps, SkipShared, UseTriangulation);
if (ErrorMax < aFreeError)
{
ErrorMax = aFreeError;
}
Props.Add(aFreeProps);
}
}
return ErrorMax;
}
void BRepGProp::VolumeProperties(const TopoDS_Shape& S,
GProp_GProps& Props,
const bool OnlyClosed,
const bool SkipShared,
const bool UseTriangulation)
{
// find the origin
gp_Pnt P(0, 0, 0);
P.Transform(S.Location());
Props = GProp_GProps(P);
if (OnlyClosed)
{
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aShMap;
TopExp_Explorer ex(S, TopAbs_SHELL);
for (; ex.More(); ex.Next())
{
const TopoDS_Shape& Sh = ex.Current();
if (SkipShared && !aShMap.Add(Sh))
{
continue;
}
if (BRep_Tool::IsClosed(Sh))
volumeProperties(Sh, Props, 1.0, SkipShared, UseTriangulation);
}
}
else
volumeProperties(S, Props, 1.0, SkipShared, UseTriangulation);
}
//=================================================================================================
double BRepGProp::VolumeProperties(const TopoDS_Shape& S,
GProp_GProps& Props,
const double Eps,
const bool OnlyClosed,
const bool SkipShared)
{
// find the origin
gp_Pnt P(0, 0, 0);
P.Transform(S.Location());
Props = GProp_GProps(P);
int i;
#ifdef OCCT_DEBUG
int iErrorMax = 0;
#endif
double ErrorMax = 0.0, Error = 0.0;
if (OnlyClosed)
{
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aShMap;
TopExp_Explorer ex(S, TopAbs_SHELL);
for (i = 1; ex.More(); ex.Next(), i++)
{
const TopoDS_Shape& Sh = ex.Current();
if (SkipShared && !aShMap.Add(Sh))
{
continue;
}
if (BRep_Tool::IsClosed(Sh))
{
Error = volumeProperties(Sh, Props, Eps, SkipShared, false);
if (ErrorMax < Error)
{
ErrorMax = Error;
#ifdef OCCT_DEBUG
iErrorMax = i;
#endif
}
}
}
}
else
ErrorMax = volumeProperties(S, Props, Eps, SkipShared, false);
#ifdef OCCT_DEBUG
if (AffichEps)
std::cout << "\n\n===================" << iErrorMax << ":\tMaxEpsVolume = " << ErrorMax << "\n";
#endif
return ErrorMax;
}
//===========================================================================================//
// Volume properties by Gauss-Kronrod integration
//===========================================================================================//
//=================================================================================================
static double volumePropertiesGK(const TopoDS_Shape& theShape,
GProp_GProps& theProps,
const double theTol,
const bool IsUseSpan,
const bool CGFlag,
const bool IFlag,
const bool SkipShared)
{
TopExp_Explorer anExp;
anExp.Init(theShape, TopAbs_FACE);
double aTol = theTol;
// Compute properties.
gp_Pnt aLoc(roughBaryCenter(theShape));
BRepGProp_VinertGK aVProps;
BRepGProp_Face aPropFace(IsUseSpan);
BRepGProp_Domain aPropDomain;
double aLocalError;
double anError = 0.;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aFwdFMap;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aRvsFMap;
TopLoc_Location aLocDummy;
aVProps.SetLocation(aLoc);
for (; anExp.More(); anExp.Next())
{
TopoDS_Face aFace = TopoDS::Face(anExp.Current());
TopAbs_Orientation anOri = aFace.Orientation();
bool isFwd = anOri == TopAbs_FORWARD;
bool isRvs = false;
if (!isFwd)
{
isRvs = anOri == TopAbs_REVERSED;
}
if (SkipShared)
{
if ((isFwd && !aFwdFMap.Add(aFace)) || (isRvs && !aRvsFMap.Add(aFace)))
{
continue;
}
}
{
const occ::handle<Geom_Surface>& aSurf = BRep_Tool::Surface(aFace, aLocDummy);
if (aSurf.IsNull())
{
// skip faces without geometry
continue;
}
}
if (isFwd || isRvs)
{
aPropFace.Load(aFace);
bool IsNatRestr = (aFace.NbChildren() == 0);
if (IsNatRestr)
aLocalError = aVProps.Perform(aPropFace, aTol, CGFlag, IFlag);
else
{
aPropDomain.Init(aFace);
aLocalError = aVProps.Perform(aPropFace, aPropDomain, aTol, CGFlag, IFlag);
}
if (aLocalError < 0.)
return aLocalError;
anError += aLocalError;
theProps.Add(aVProps);
}
}
return anError;
}
//=================================================================================================
double BRepGProp::VolumePropertiesGK(const TopoDS_Shape& S,
GProp_GProps& Props,
const double Eps,
const bool OnlyClosed,
const bool IsUseSpan,
const bool CGFlag,
const bool IFlag,
const bool SkipShared)
{
gp_Pnt P(0, 0, 0);
double anError = 0.;
P.Transform(S.Location());
Props = GProp_GProps(P);
if (OnlyClosed)
{
// To select closed shells.
TopExp_Explorer anExp;
NCollection_List<TopoDS_Shape> aClosedShells;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aShMap;
anExp.Init(S, TopAbs_SHELL);
for (; anExp.More(); anExp.Next())
{
const TopoDS_Shape& aShell = anExp.Current();
if (SkipShared && !aShMap.Add(aShell))
{
continue;
}
BRepCheck_Shell aChecker(TopoDS::Shell(aShell));
BRepCheck_Status aStatus = aChecker.Closed(false);
if (aStatus == BRepCheck_NoError)
aClosedShells.Append(aShell);
}
if (aClosedShells.IsEmpty())
return -1.;
// Compute the properties for each closed shell.
double aTol = Eps;
double aLocalError;
NCollection_List<TopoDS_Shape>::Iterator anIter(aClosedShells);
for (; anIter.More(); anIter.Next())
{
const TopoDS_Shape& aShell = anIter.Value();
aLocalError = volumePropertiesGK(aShell, Props, aTol, IsUseSpan, CGFlag, IFlag, SkipShared);
if (aLocalError < 0)
return aLocalError;
anError += aLocalError;
}
}
else
anError = volumePropertiesGK(S, Props, Eps, IsUseSpan, CGFlag, IFlag, SkipShared);
double vol = Props.Mass();
if (vol > Epsilon(1.))
anError /= vol;
return anError;
}
//=================================================================================================
static double volumePropertiesGK(const TopoDS_Shape& theShape,
GProp_GProps& theProps,
const gp_Pln& thePln,
const double theTol,
const bool IsUseSpan,
const bool CGFlag,
const bool IFlag,
const bool SkipShared)
{
TopExp_Explorer anExp;
anExp.Init(theShape, TopAbs_FACE);
double aTol = theTol;
// Compute properties.
gp_Pnt aLoc(roughBaryCenter(theShape));
BRepGProp_VinertGK aVProps;
BRepGProp_Face aPropFace(IsUseSpan);
BRepGProp_Domain aPropDomain;
double aLocalError;
double anError = 0.;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aFwdFMap;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aRvsFMap;
TopLoc_Location aLocDummy;
aVProps.SetLocation(aLoc);
for (; anExp.More(); anExp.Next())
{
TopoDS_Face aFace = TopoDS::Face(anExp.Current());
TopAbs_Orientation anOri = aFace.Orientation();
bool isFwd = anOri == TopAbs_FORWARD;
bool isRvs = false;
if (!isFwd)
{
isRvs = anOri == TopAbs_REVERSED;
}
if (SkipShared)
{
if ((isFwd && !aFwdFMap.Add(aFace)) || (isRvs && !aRvsFMap.Add(aFace)))
{
continue;
}
}
{
const occ::handle<Geom_Surface>& aSurf = BRep_Tool::Surface(aFace, aLocDummy);
if (aSurf.IsNull())
{
// skip faces without geometry
continue;
}
}
if (isFwd || isRvs)
{
aPropFace.Load(aFace);
bool IsNatRestr = (aFace.NbChildren() == 0);
if (IsNatRestr)
aLocalError = aVProps.Perform(aPropFace, thePln, aTol, CGFlag, IFlag);
else
{
aPropDomain.Init(aFace);
aLocalError = aVProps.Perform(aPropFace, aPropDomain, thePln, aTol, CGFlag, IFlag);
}
if (aLocalError < 0.)
return aLocalError;
anError += aLocalError;
theProps.Add(aVProps);
}
}
return anError;
}
//=================================================================================================
double BRepGProp::VolumePropertiesGK(const TopoDS_Shape& S,
GProp_GProps& Props,
const gp_Pln& thePln,
const double Eps,
const bool OnlyClosed,
const bool IsUseSpan,
const bool CGFlag,
const bool IFlag,
const bool SkipShared)
{
gp_Pnt P(0, 0, 0);
double anError = 0.;
P.Transform(S.Location());
Props = GProp_GProps(P);
if (OnlyClosed)
{
// To select closed shells.
TopExp_Explorer anExp;
NCollection_List<TopoDS_Shape> aClosedShells;
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> aShMap;
anExp.Init(S, TopAbs_SHELL);
for (; anExp.More(); anExp.Next())
{
const TopoDS_Shape& aShell = anExp.Current();
if (SkipShared && !aShMap.Add(aShell))
{
continue;
}
BRepCheck_Shell aChecker(TopoDS::Shell(aShell));
BRepCheck_Status aStatus = aChecker.Closed(false);
if (aStatus == BRepCheck_NoError)
aClosedShells.Append(aShell);
}
if (aClosedShells.IsEmpty())
return -1.;
// Compute the properties for each closed shell.
double aTol = Eps;
double aLocalError;
NCollection_List<TopoDS_Shape>::Iterator anIter(aClosedShells);
for (; anIter.More(); anIter.Next())
{
const TopoDS_Shape& aShell = anIter.Value();
aLocalError =
volumePropertiesGK(aShell, Props, thePln, aTol, IsUseSpan, CGFlag, IFlag, SkipShared);
if (aLocalError < 0)
return aLocalError;
anError += aLocalError;
}
}
else
anError = volumePropertiesGK(S, Props, thePln, Eps, IsUseSpan, CGFlag, IFlag, SkipShared);
double vol = Props.Mass();
if (vol > Epsilon(1.))
anError /= vol;
return anError;
}