How do I calculate the surface area on a solid using C++?

Hi All,
In one example calculate the solid volumes.

How do I calculate the surface area on a solid ?

``````CRhinoCommand::result CCommandTest::RunCommand(const CRhinoCommandContext& context)
{
CRhinoGetObject go;
go.SetCommandPrompt(L"Select surface or polysurface");
go.EnableSubObjectSelect(FALSE);
go.EnableGroupSelect(TRUE);
go.GetObjects(1, 0);
if (go.CommandResult() != CRhinoCommand::success)	return go.CommandResult();
for (int i = 0; i < go.ObjectCount(); i++)
{
const CRhinoObjRef& ref = go.Object(i);
const CRhinoObject* pObject = ref.Object();
if (0 == pObject)	continue;
ON_SimpleArray<ON_COMPONENT_INDEX> subidxs;
pObject->GetSelectedSubObjects(subidxs);
for (int su = 0; su < subidxs.Count(); su++) {
if (subidxs[su].m_type == ON_COMPONENT_INDEX::brep_face) {
if (const ON_Surface* srf = ON_Surface::Cast(pObject->Geometry())) {
ON_SimpleArray<ON_MassProperties> MassProp(1);
ON_MassProperties* mp = &MassProp.AppendNew();
srf->AreaMassProperties(*mp, true, false, false, false);
::RhinoApp().Print(L"Object[%d] Area[%d] = %f\n", i, su, mp->Area());
}
}
}
}
return CRhinoCommand::success;
}
``````

How ?

β Karlos

Get the solid as `ON_Brep` and use its member function AreaMassProperties.

https://developer.rhino3d.com/api/cpp/class_o_n___brep.html#ab1a4d17b895d22868cd2ee1c9dddab77

Hi Menno.

``````CRhinoCommand::result CCommandTest::RunCommand(const CRhinoCommandContext& context)
{
CRhinoGetObject go;
go.EnablePreSelect();
go.SetCommandPrompt(L"Select surface or polysurface");
go.SetGeometryFilter(CRhinoGetObject::surface_object | CRhinoGetObject::polysrf_object);
go.EnableSubObjectSelect(FALSE);
go.EnableGroupSelect(TRUE);
go.GetObjects(1, 0);
if (go.CommandResult() != CRhinoCommand::success)	return go.CommandResult();
ON_SimpleArray<const ON_Brep*> Breps;
for (int i = 0; i < go.ObjectCount(); i++)
{
::RhinoApp().ActiveDoc()->UnselectAll();
const CRhinoObjRef& ref = go.Object(i);
const CRhinoObject* obj = ref.Object();
const ON_Brep* brep = ref.Brep();
if (!obj | !brep)	continue;
Breps.Append(brep);
}
int Bn = 0;
Bn = Breps.Count();
if (Bn > 0)
{
::RhinoApp().Print(L"for (int j = 0; j < Breps.Count(%d); j++)\t\n\{\n", Bn);
for (int j = 0; j < Bn; j++)
{
const ON_Brep* brep = Breps[j];
if (brep)
{
if (brep->m_S.Count() > 0)
{
int n = 0;
n = brep->m_S.Count();
::RhinoApp().Print(L"\tfor (int k = 0; k < brep->m_S.Count(%d); k++)\t( Brep[%d] )\n\t\{\n", n, j);
for (int k = 0; k < n; k++) {
::RhinoApp().Print(L"\t\tSurface[%d]", k);
const ON_Surface* brep_srf = brep->m_S[k];
if (!brep_srf) continue;
ON_Surface* dup_brep_srf = brep->m_S[k]->DuplicateSurface();
if (!dup_brep_srf) continue;
if (dup_brep_srf->IsCone())		::RhinoApp().Print(L"\tIsCone()\t");
if (dup_brep_srf->IsCylinder())	::RhinoApp().Print(L"\tIsCylinder()\t");
if (dup_brep_srf->IsPlanar())	::RhinoApp().Print(L"\tIsPlanar()\t");
if (dup_brep_srf->IsSolid())	::RhinoApp().Print(L"\tIsSolid()\t");
if (dup_brep_srf->IsSphere())	::RhinoApp().Print(L"\tIsSphere()\t");
if (dup_brep_srf->IsTorus())	::RhinoApp().Print(L"\tIsTorus()\t");
if (brep_srf) {
::RhinoApp().Print(L"\tbrep[%d] m_S[%d]\t", j, k);
ON_SimpleArray<ON_MassProperties> MassProp(1);
ON_MassProperties* mp = &MassProp.AppendNew();
if (brep_srf->AreaMassProperties(*mp, true, false, false, false))
{
::RhinoApp().Print(L"\tArea[%d] = %f\n", k, mp->Area());
CRhinoSurfaceObject* srf_obj = new CRhinoSurfaceObject();
srf_obj->SetSurface(dup_brep_srf);
context.m_doc.Redraw();
else
{
delete srf_obj;
srf_obj = NULL;
}
}
}
}
}
}
::RhinoApp().Print(L"\t\}\n");
}
::RhinoApp().Print(L"\}\n");
}
return CRhinoCommand::success;
}
``````

why does the area of a planar surface read the surface of a rectangle ?

?
β Karlos

What youβre doing is getting the underlying surfaces from the `m_S` array. These surfaces are not trimmed, and form part of the `ON_Brep` data structure. More info on that data structure can be found here https://developer.rhino3d.com/guides/cpp/brep-data-structure/

What you should do is when you loop over the selected BReps, is calculate the mass properties on the whole thing, not each surface:

``````// these need to come from the document or you need to choose an absolute and a relative tolerance
double abs_tolerance = TODO;
double rel_tolerance = TODO;

for (int j = 0; j < Bn; j++)
{
const ON_Brep* brep = Breps[j];
if (brep)
{
ON_MassProperties mp;
// get the area-mass-properties for the whole b-rep:
if (brep->AreaMassProperties(mp, true, false, false, false, abs_tolerance, rel_tolerance))
{
// do stuff
}
}
}``````
``````CRhinoCommand::result CCommandTest::RunCommand(const CRhinoCommandContext& context)
{
CRhinoGetObject go;
go.EnablePreSelect();
go.SetCommandPrompt(L"Select surface or polysurface");
go.SetGeometryFilter(CRhinoGetObject::surface_object | CRhinoGetObject::polysrf_object);
go.EnableSubObjectSelect(FALSE);
go.EnableGroupSelect(TRUE);
go.GetObjects(1, 0);
if (go.CommandResult() != CRhinoCommand::success)	return go.CommandResult();
ON_SimpleArray<const ON_Brep*> Breps;
for (int i = 0; i < go.ObjectCount(); i++)
{
::RhinoApp().ActiveDoc()->UnselectAll();
const CRhinoObjRef& ref = go.Object(i);
const CRhinoObject* obj = ref.Object();
const ON_Brep* brep = ref.Brep();
if (!obj | !brep)	continue;
Breps.Append(brep);
}
int Bn = 0;
Bn = Breps.Count();
if (Bn > 0)
{
::RhinoApp().Print(L"for (int j = 0; j < Breps.Count(%d); j++)\t\n\{\n", Bn);
// these need to come from the document or you need to choose an absolute and a relative tolerance
double abs_tolerance = 1.0e-6;
double rel_tolerance = 1.0e-6;
for (int j = 0; j < Bn; j++)
{
const ON_Brep* brep = Breps[j];
if (brep)
{
//Given a brep and a face index
const int face_index = 0;

const ON_BrepFace* face = brep->Face(face_index);
if (0 == face)
return CRhinoCommand::failure;

int BFn = brep->m_F.Count();
::RhinoApp().Print(L"\tBFn[%d]\n", BFn);

if (brep->m_F.Count() > 0)
{
::RhinoApp().Print(L"\tfor (int fi = 0; fi < brep->m_F.Count(%d); fi++)\t( Brep[%d] )\n\t\{\n", brep->m_F.Count(), j);
for (int fi = 0; fi < brep->m_F.Count(); fi++)
{
::RhinoApp().Print(L"\t\tSurface[%d]", fi);
ON_MassProperties mp_F;
// get the area-mass-properties for the whole b-rep:
if (brep->m_F[fi].AreaMassProperties(mp_F, true, false, false, false, abs_tolerance, rel_tolerance))
{
ON_Surface* dup_brep_srf = brep->m_F[fi].DuplicateSurface();
if (!dup_brep_srf) continue;
if (dup_brep_srf->IsCone())		::RhinoApp().Print(L"\tIsCone()\t");
if (dup_brep_srf->IsCylinder())	::RhinoApp().Print(L"\tIsCylinder()\t");
if (dup_brep_srf->IsPlanar())	::RhinoApp().Print(L"\tIsPlanar()\t");
if (dup_brep_srf->IsSolid())	::RhinoApp().Print(L"\tIsSolid()\t");
if (dup_brep_srf->IsSphere())	::RhinoApp().Print(L"\tIsSphere()\t");
if (dup_brep_srf->IsTorus())	::RhinoApp().Print(L"\tIsTorus()\t");
::RhinoApp().Print(L"\tbrep[%d] m_F[%d]\t\tArea[%d] = %f\n", j, fi, fi, mp_F.Area());
CRhinoSurfaceObject* srf_obj = new CRhinoSurfaceObject();
srf_obj->SetSurface(dup_brep_srf);
context.m_doc.Redraw();
else
{
delete srf_obj;
srf_obj = NULL;
}
}
}
}
}
::RhinoApp().Print(L"\t\}\n");
}
::RhinoApp().Print(L"\}\n");
}
return CRhinoCommand::success;
}``````
1 Like

Thank you very much, Menno.
How can I correctly get all the surfaces separately for analysis?
β Karlos

Here is one way:

β Dale

2 Likes

Thank you very much Dale.
Thank you very much Menno.
β Karlos

1 Like