# 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[] = {
kA3DTypeSurfCone,
kA3DTypeSurfCylinder,
kA3DTypeSurfPlane,
kA3DTypeSurfSphere
};
// Acceptable curves
A3DUns32 curves[] = {
kA3DTypeCrvCircle,
kA3DTypeCrvLine
};
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.

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:

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.

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.

```
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.

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.

```
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.

```
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(
in_pModelFile,
&sConfig
);
}
```

`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;
A3DCopyAndAdaptBrepModelAdvanced(
in_pSourceEntity,
&sConfig,
&out_pDestEntity,
&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()`

.