Converting B-Rep to NURBS

HOOPS Exchange provides a rich set of boundary representation (B-rep) features. However, because some of these features may not be compatible with the requirements of your environment, HOOPS Exchange provides a facility called B-rep adaptation that converts any boundary representation model to Non-uniform rational basis spline (NURBS), as an alternative designed to help you manipulate more commonly used geometric representations.

The conversion operation can be customized using a fine-grained configuration structure:

typedef struct
  A3DUns16       m_usStructSize;
  A3DBool        m_bUseSameParam;
  A3DDouble      m_dTol;
  A3DBool        m_bDeleteCrossingUV;
  A3DBool        m_bSplitFaces;
  A3DBool        m_bSplitClosedFaces;
  A3DBool        m_bForceComputeUV;
  A3DBool        m_bAllowUVCrossingSeams;
  A3DBool        m_bForceCompute3D;
  A3DUns32       m_uiAcceptableSurfacesSize;
  A3DUns32*      m_puiAcceptableSurfaces;
  A3DUns32       m_uiAcceptableCurvesSize;
  A3DUns32*      m_puiAcceptableCurves;
  A3DBool        m_bContinueOnError;
  A3DBool        m_bClampTolerantUVCurvesInsideUVDomain;
  A3DBool        m_bForceDuplicateGeometries;
} A3DCopyAndAdaptBrepModelData;

To use this data structure, initialize an instance just like any other HOOPS Exchange structure:

A3DCopyAndAdaptBrepModelData data;
A3D_INITIALIZE_DATA(A3DCopyAndAdaptBrepModelData, data);

// Customize the NURBS conversion

Filtering the Converter

By default, all geometric entities are converted into NURBS. However, you may want to customize this behavior and allow specific geometry types to simply pass through the process without being converted. These geometric entities are defined as acceptable.

You can define your own list of acceptable curves and surface types with A3DCopyAndAdaptBrepModelData.m_puiAcceptableSurfaces and A3DCopyAndAdaptBrepModelData respectively. Each array expects values from A3DEEntityType.

// Acceptable surfaces
A3DUns32 surfaces[] = {

// Acceptable curves
A3DUns32 curves[] = {

data.m_uiAcceptableSurfacesSize = 4;
data.m_puiAcceptableSurfaces    = surfaces;
data.m_uiAcceptableCurvesSize   = 2;
data.m_puiAcceptableCurves      = curves;

This example marks the following entity types as acceptable:

  • Planes: kA3DTypeSurfPlane

  • Cylinders: kA3DTypeSurfCylinder

  • Cones: kA3DTypeSurfCone

  • Spheres: kA3DTypeSurfSphere

  • Lines: kA3DTypeCrvLine

  • Circles: kA3DTypeCrvCircle

While all other geometry will be converted to NURBS, these geometry types will pass through the conversion and remain unchanged.

Matching Parameterization of Curves and Surfaces

Geometric constructions based on B-rep and NURBS are said to be “parameterized”. This simply means that their resulting geometry is obtained from the input of parameters into mathematical models.

Converting from original geometry to NURBS implies changing from one mathematical model to another. As a consequence of these parameterization changes, the same input parameter used in the original CAD model geometry won’t provide the same result in the adapted (NURBS) geometry.

You may still want to enforce some level of parameterization expectations after conversion so that parameterization requirements will be respected inside a specified margin of error.


Matching parameterization of curves and surfaces

The example above shows two examples where the option is activated (right) or not (left). As you see, this operation may imply the generation of additional control points.

To enforce parameterization requirements in the resulting NURBS, set the m_bUseSameParam field to A3D_TRUE along with a specific tolerance value with m_dTol:

data.m_bUseSameParam = A3D_TRUE;
data.m_dTol = 1.e-3;

Tweaking Closed Surfaces

Periodic faces are closed surfaces that preserve their continuity between the end and the start of the surface. A common example is a cylindrical surface:


Splitting periodic faces

When converting to NURBS, a periodic surface can be modified by splitting periodic surface or by splitting closed faces.

Splitting Periodic Faces

A periodic face can be split in order to form a seam, this can be achieved using the m_bSplitFaces option.

data.m_bSplitFaces = A3D_TRUE;

In the below picture, a seam is visible, marking the split of the face.


Splitting periodic faces

This option can lead to the creation of new faces. They will then share their surface and 3D curves.

Splitting Closed Faces

Closed faces can be cut into new faces that will share the same surfaces and 3D curves. If you convert to a format that does not support closed faces, this option will prove useful.


Splitting closed faces

data.m_bSplitClosedFaces = A3D_TRUE;

Duplicating Geometry

Sometimes several topological entities are associated to the same geometry. For example, two faces can be built on the same surface. If needed, exclusivity of the association can be enforced by duplicating the geometry.

data.m_bForceDuplicateGeometries = A3D_TRUE;

As an important note, the fact that the source model does not initially provide such sharing does not mean your resulting NURBS conversion won’t contain shared geometry as well. Indeed, calling either m_bSplitFaces or m_bSplitClosedFaces can create faces with shared surfaces and 3D curves. Hence, the duplication operation will be performed after the splitting of faces.

Manipulating Curves

Various operations can be performed on curves when converting to NURBS. HOOPS Exchange makes a distinction between two major sorts of parametric curves: 3D curves and UV curves. They differ in the parametric space used. A 3D curve is defined in the three-dimensional space of the geometry while the UV curve is defined inside the 2D space represented by a surface.

Forcing Either UV or 3D Curves

Your geometry can contain any set of 3D curves and UV curves it needs. According to your requirements you may prefer having either one type of curve or the other.

For that purpose we provide you with two options which will generate UV or 3D curves for you. When m_bForceCompute3D is set to A3D_TRUE, all UV curves will lead to the computation of a new 3D curve. Already existing 3D curves won’t be affected.

data.m_bForceCompute3D = A3D_TRUE;

With the same idea you can use m_bForceComputeUV to activate the computation of UV curves from existing 3D curves.

data.m_bForceComputeUV = A3D_TRUE;

In the image below all the curve are available as UV curves thanks to m_bForceComputeUV. The image on the right is a visualization of the UV curves.


Generating UV curves from 3D curves

If needed for the computation, this operation may implicitly split the surface as if m_bSplitFaces was set. This is the case for the example above.

Tweaking UV Curve Generation

With m_bForceComputeUV, the generated UV curves will be closed. If you want to prevent that, use m_bAllowUVCrossingSeams. With this option enabled, the curves cannot be closed and are allowed to lay outside of the parametric domain of its surface.


Generating UV curves from 3D curves

data.m_bAllowUVCrossingSeams = A3D_TRUE;

Please note that this option is mutually exclusive with m_bSplitFaces and m_bSplitClosedFaces. If any of these parameters is A3D_TRUE, m_bAllowUVCrossingSeams will be considered as A3D_FALSE.

Deleting Crossing UV Curves

Sometimes having UV curves that cross the seams of a periodic surface is not desirable. With m_bDeleteCrossingUV set to A3D_TRUE such curves will be converted to 3D curves.


Deleting crossing UV curves

data.m_bDeleteCrossingUV = A3D_TRUE;

In the geometry from the previous example, a UV curve was crossing a seam. It has been converted to 3D curve.

Clamping UV Curves

By default UV curves are allowed to stray outside the UV domain. By setting m_bClampTolerantUVCurvesInsideUVDomain to A3D_TRUE, UV curves will be clamped to the UV domain as long as the 3D edge tolerance is respected.

data.m_bClampTolerantUVCurvesInsideUVDomain = A3D_TRUE;

# Code example

This example uses some of the options above to prevent any closed surfaces during conversion:

void no_closed_surfaces(A3DAsmModelFile* in_pModelFile)
    A3DCopyAndAdaptBrepModelData sConfig;
    A3D_INITIALIZE_DATA(A3DCopyAndAdaptBrepModelData, sConfig);

    sConfig.m_bSplitFaces               = A3D_TRUE;
    sConfig.m_bSplitClosedFaces         = A3D_TRUE;
    sConfig.m_bForceComputeUV           = A3D_TRUE;
    sConfig.m_bForceDuplicateGeometries = A3D_TRUE;


A3DAdaptAndReplaceAllBrepInModelFile() takes two parameters, which are the A3DAsmModelFile instance to convert and the settings.

This function makes the conversion in-place, which means that the original Model File will be destroyed. If you want to leave the original file unchanged and create a converted copy instead, use ref A3DCopyAndAdaptBrepModel() function instead.

Managing Errors

Converting your geometry to NURBS is a long process and errors can occur at any step of the operation. By default the first error encountered when converting will be returned by the function, thus stopping the conversion.

You can force the conversion to resume even if errors occur:

m_data.m_bContinueOnError = A3D_TRUE;

To let you maintain control on the error flow, the conversion functions come with an advanced mode where all errors encountered while converting are stored for being returned. This is only available if m_bContinueOnError is set:

void no_closed_surfaces(A3DEntity* in_pSourceEntity, A3DEntity** out_pDestEntity)
    A3DCopyAndAdaptBrepModelData sConfig;
    A3D_INITIALIZE_DATA(A3DCopyAndAdaptBrepModelData, sConfig);

    sConfig.m_bContinueOnError          = A3D_TRUE;

    A3DUns32  uiNErrors = 0;
    A3DInt32* piErrors = NULL;

      &uiNErrors, &piErrors

    for(A3DUns32 e = 0;  e < uiNErrors ; ++e)
        printf("Error Code: %x\n", piErrors[e]);

The in-place conversion also provides this error checking mechanism with A3DAdaptAndReplaceAllBrepInModelFileAdvanced().