7.0 Advanced functions

7.1 Computing lengths

In HOOPS Exchange, all lines, edges, and curves have an associated curve, whose base type is A3DCrvBase. This geometry always exists as part of a representation item. Recall that representation items may have many different types, thus, it is necessary to check the type before operating on it. In this case, we'll examine a tessellated entity of type kA3DTypeRiCurve. Computing the curve length requires drilling down a few levels in order to get the necessary parameters:

A3DEntityGetType(repItem, &eType);
if (eType == kA3DTypeRiCurve)
{
A3DRiCurveData riCurveData;
A3DRiCurveGet((A3DRiCurve*) repItem, &riCurveData);
A3DTopoSingleWireBody* tswb = riCurveData.m_pBody;
A3DTopoSingleWireBodyGet(tswb, &tswbd);
A3DTopoWireEdgeGet(twe, &twed);
A3DCrvBase* crvBase = twed.m_p3dCurve;
A3DDouble curveLength;
status = A3DCurveLength(crvBase, nullptr, &curveLength);
// at this point "curveLength" will equal the length of the curve
}

Getting curve length for B-rep data is similar to the above example, but due to the complex nature of B-rep, you have to drill down much further into the assembly tree to get the A3DCrvBase :

if (eType == kA3DTypeRiBrepModel)
{
A3DRiBrepModelData riBrepModelData;
A3DRiBrepModelGet((A3DRiBrepModel*) repItem, &riBrepModelData);
// continue drilling down
// ...A3DTopoBrepData
// ...A3DTopoConnexData
// ...A3DTopoShellData
// ...A3DTopoFaceData
// ...A3DTopoLoopData
// ...A3DTopoCoEdgeData
A3DTopoEdgeData topoEdgeData;
A3DTopoEdgeGet(topoEdge.m_pEdge, topoEdgeData);
A3DCrvBase* crvBase = topoEdgeData.m_p3dCurve;
A3DDouble curveLength;
status = A3DCurveLength(crvBase, nullptr, &curveLength);
// at this point "curveLength" will equal the length of the curve
}

7.2 Getting physical properties

A model's physical properties include its volume, center of gravity, and surface area. The computation functions exist for the model file as a whole as well as individual B-rep models within an assembly. Here is an example of how it is computed at the model file level:

A3DPhysicalPropertiesData physicalPropertiesData;
A3DComputeModelFilePhysicalProperties(sHoopsExchangeLoader.m_psModelFile, &physicalPropertiesData);
// the fields in 'physicalPropertiesData' contain the results

For computation of individual B-rep models, use the similar functions A3DComputePhysicalProperties and A3DComputePolyBrepPhysicalProperties.

For A3DComputeModelFilePhysicalProperties, the data is returned in the model file's units. A3DComputePhysicalProperties returns values in the local B-rep model's units. Note these functions also accept a scale parameter (not used in the above example) which can be used to transform the local unit into something else. For instance, if the local unit is millimeters and the scale is 1000, the values will be returned in meters for the gravity center, square meters for the area, and cubic meters for the volume.

Computing area for a single face

To compute the area for a single face, you'll need a TopoFace object and its context. This procedure is more complicated because the required objects are nested deep within the B-rep hierarchy. Starting with a B-rep model representation item [repItem in the code snippet below], the first step is to get a reference to the TopoContext.

A3DEntityGetType(repItem, &eType);
if (eType == kA3DTypeRiBrepModel)
{
A3DRiBrepModel* brepModel = (A3DRiBrepModel*) repItem;
A3DRiBrepModelData brepModelData;
A3DRiBrepModelGet(brepModel, &brepModelData);
A3DTopoBrepData* topoBrepData = brepModelData.m_pBrepData;
A3DTopoBrepDataData topoBrepDataData;
A3DTopoBrepDataGet(topoBrepData, &topoBrepDataData);
A3DTopoBodyData topoBodyData;
A3DTopoBodyGet(topoBrepData, &topoBodyData);
// save this reference to the topoContextData
A3DTopoContextData topoContextData;
A3DTopoContextGet(topoBodyData.m_pContext, &topoContextData);

Now, you are able to drill down further to get the TopoFace you're interested in. The following example loops through all faces and simply prints the area for each one:

A3DTopoConnexData topoConnexData;
A3DTopoShellData topoShellData;
A3DTopoFaceData topoFaceData;
for (size_t i = 0; i < topoBrepDataData.m_uiConnexSize; i++)
{
A3DTopoConnexGet(topoBrepDataData.m_ppConnexes[i], &topoConnexData);
for (size_t j = 0; j < topoConnexData.m_uiShellSize; j++)
{
A3DTopoShellGet(topoConnexData.m_ppShells[j], &topoShellData);
for (size_t k = 0; k < topoShellData.m_uiFaceSize; k++)
{
A3DTopoFaceGet(topoShellData.m_ppFaces[k], &topoFaceData);
A3DDouble faceArea;
A3DComputeFaceArea(topoShellData.m_ppFaces[k], topoBodyData.m_pContext, &faceArea);
// here is the data we're looking for
cout << "topo face " << k << ", area: " << faceArea << std::endl;
A3DTopoFaceGet(nullptr, &topoFaceData);
}
A3DTopoShellGet(nullptr, &topoShellData);
}
A3DTopoConnexGet(nullptr, &topoConnexData);
}
}

Note the de-initializations with nullptr which free memory when each structure is no longer needed.

7.3 Model compare

HOOPS Exchange offers a convenient way for comparing two models to determine which faces are different. This is useful, for example, to understand what has changed in a model between two versions: perhaps a hole has been added or an edge has been blended. Comparisons can be made at the model level or at the B-rep level. Imagine you would like HOOPS Exchange to compare these models:

This example demonstrates how to perform the comparison:

sHoopsExchangeLoader.Import(A3DImport(filename1));
A3DAsmModelFile* modelFile1 = sHoopsExchangeLoader.m_psModelFile;
sHoopsExchangeLoader.Import(A3DImport(filename2));
A3DAsmModelFile* modelFile2 = sHoopsExchangeLoader.m_psModelFile;
A3DCompareFacesInBrepModels(modelFile1, modelFile2, 1, &pOutput);

The output structure contains information related to which faces are changed. For example, the A3DCompareOutputData::m_pOldFaceMatch array corresponds to the array of faces, A3DCompareOutputData::m_pOldFace, found in the model. m_pOldFaceMatch contains a true value for each face that remains the same. Perhaps most interesting is the m_pResultAsmModeFile field, which can be exported to PRC. The PRC will contain all the faces color-coded according to their status in m_pOldFaceMatch. The result is something like this:

7.4 Model sewing

In some legacy file translators - especially those doing STEP or IGES translation - the relationship between adjacent faces in a solid body may be broken. HOOPS Exchange can repair this data through model sewing, which is a form of healing. Sewing reconnects adjacent faces in a solid. Sewing can be done at the model file level or at the B-rep level. An example of model sewing is demonstrated below:

sHoopsExchangeLoader.Import(A3DImport(filename1));
A3DRiBrepModel* model1 = getBrepModel(sHoopsExchangeLoader.m_psModelFile);
sHoopsExchangeLoader.Import(A3DImport(filename2));
A3DRiBrepModel* model2 = getBrepModel(sHoopsExchangeLoader.m_psModelFile);
A3DRiBrepModel* inModels[] = { model1, model2 };
A3DRiBrepModel** pInModels = inModels;
A3DRiBrepModel** outModels;
A3DUns32 numOutModels;
A3DSewBrep(&pInModels, 2, 1.0, &outModels, &numOutModels);
// at this point, outModels contains the sewn B-rep models

7.5 Computing sections

HOOPS Exchange is capable of performing model sectioning. You provide a model and define a plane. Then, HOOPS Exchange will create an infinitely thin slice of the model which intersects the plane. The output is an exact geometric B-rep slice, not just a tessellated polyline. The slice is provided as a set of B-rep representation items.

// initialize the section plane
A3DPlanarSectionData sectionPlane;
// plane origin point
origin.m_dX = 0;
origin.m_dY = 0;
origin.m_dZ = 0;
sectionPlane.m_sOrigin = origin;
// plane direction
A3DVector3dData direction;
direction.m_dX = 0;
direction.m_dY = 1;
direction.m_dZ = 0;
sectionPlane.m_sDirection = direction;
A3DUns32 numSections;
A3DRiSet** sectionElements;
A3DComputePlanarSectionOnModelFile(sHoopsExchangeLoader.m_psModelFile,
&sectionPlane,
&numSections,
&sectionElements);
// 'sectionElements' contains the B-Rep for the sections

HOOPS Exchange also offers the ability to compute a section for individual B-rep models within an assembly. The process is similar to the above example, except you would use the function A3DComputePlanarSectionOnRepresentationItem. An example result of the section functions is shown below. The original model is on the left. The computed section is on the right.

7.6 Model to point cloud comparison

Many manufacturers of high-precision machined parts have a need to quickly verify whether a finished part meets required tolerances. HOOPS Exchange can perform such an operation by comparing a CAD model with a point cloud dataset of the finished part. The comparison can be performed against the model's exact mathematical definition or its tessellated representation. When projecting a point cloud onto a mesh, please note that the coordinates of the projected point and the B-rep data of the face are not provided.

The function that does this work is A3DProjectPointCloud. This function accepts the model definition and a point cloud supplied from a laser scanner or other tool. It returns a projected point cloud, which represents the difference between the real-world part and its mathematical definition.

You can use the point cloud to visually inspect any tolerance deficiencies in the manufactured part. For example, in the image below, a CAD model is shown next to a point cloud of a scanned real-world object.

Using the projected point cloud returned from A3DProjectPointCloud, a the real-world surface can be overlaid (below, left) on the model. Or, a heat map (below, right) could be applied to the model to show defects in tolerance:

A3DProjectPointCloud is recommended over inspecting each point individually because our algorithm is able to inspect multiple points simultaneously using multithreading, automatically determines which points should be compared against each face, and is able to batch comparison operations together to further boost performance.