2.1 Simple load and export

HOOPS Exchange can be used within your application in two different ways - as a direct or indirect integration.

A direct integration means you are accessing the assembly tree structure, parsing entities, and using that information to inspect the model data or otherwise provide a feature-rich experience to the end user. For information on how you would do this, see section 4, Reading model geometry.

An indirect integration means you are simply reading a model file and using HOOPS Exchange to write it in a different format without reading the assembly tree.

Loading a model

Start HOOPS Exchange by initializing the libraries and setting the license key. That process is described in the initialization section.

Once HOOPS Exchange is initialized, you can use it to load a CAD model into memory. CAD files can be imported with a minimal amount of code:

A3DSDKHOOPSExchangeLoader sHoopsExchangeLoader(myFilename);
A3DStatus importResult = sHoopsExchangeLoader.Import(A3DImport(filename));

If you're doing an indirect integration, you're done. You can export the file as another format by using the code in the next subsection.

For direct integrations, you'll need access to the model file pointer. This pointer gives you a reference to the root of the assembly tree:

A3DAsmModelFile* myModelPtr = sHoopsExchangeLoader.m_psModelFile;

Loading a CAD file with custom options

Many file formats contain extraneous data that is not necessary for all situations. Therefore, before loading the file, you should set the file import parameters to load only the specific data required by your application. Doing so decreases the memory footprint, CPU load, and load time. These parameters are set using the A3DRWParamsLoadData structure:

A3DRWParamsLoadData sReadParam;
A3D_INITIALIZE_DATA(A3DRWParamsLoadData, sReadParam);
sReadParam.m_sGeneral.m_bReadSolids = true;
sReadParam.m_sGeneral.m_bReadSurfaces = true;
sReadParam.m_sGeneral.m_bReadPmis = true;
// ... set other A3DRWParamsLoadData fields as necessary
A3DAsmModelFile* pModelFile = NULL;
A3DAsmModelFileLoadFromFile("output.3.prc", &sReadParam, &pModelFile);
// alternatively, if you've used the A3DSDKHOOPSExchangeLoader:
A3DAsmModelFileGet(sHoopsExchangeLoader.m_psModelFile, &modelFileData);

The end result of successful file load is a model file pointer. This structure represents the root entity for a model file. Through it, you can access the assembly tree. There is only one model file per model.

Once in memory, the model is represented by a PRC assembly tree that is equivalent to its native structure. Note that pModelFile points to a model file node. Nodes always have data associated with them, but this data is not populated by default. The following code sample fills the node's data structure so that you can access the information within:

A3DAsmModelFileData modelFileData; // will contain node data
A3D_INITIALIZE_DATA(A3DAsmModelFileData, modelFileData);
A3DAsmModelFileGet(pModelFile, &modelFileData);

At this point, the model file is loaded into memory and you can use the modelFileData structure to access the assembly tree. As noted above, this is the route you would take to perform a direct integration. For information on how you would do this, see section 7, Reading model geometry.

A PRC assembly tree can contain any number of nodes, and in many cases, they will be nested several levels deep. In order to gather all the information from the PRC, your traversal algorithm must visit every node. Typically, this is done through recursion.

Multiprocess loading

Using multiple processes to load a file will usually improve performance. To use multiprocess loading, set the number of processes in the m_sGeneral::m_iNbMultiProcess member variable of A3DRWParamsLoadData:

sReadParam.m_sGeneral.m_iNbMultiProcess = 4;

Please note that when loading a model using multiprocess, the head assembly display list will not be used; this may affect the visibility of parts in the resulting tessellation.

Incremental loading

With incremental load, it's possible to load specific parts into memory without loading extraneous parts. More precisely, Exchange will load the full assembly structure but only the geometry and tessellation of the specified parts, thereby reducing the overhead of the application and boosting relative performance. This is especially useful for large CAD models.

Incremental load is only available for certain file formats, including SolidWorks, NX (Unigraphics), Creo (Pro/E), and CATIA V5. Incremental load support is specified on the information pages for most formats, linked from this table. A full code example of incremental load is available in the downloadable package, and a working demo of incremental mode can be evaluated by opening a supported CAD model in the HOOPS Demo Viewer or the Parasolid Demo Viewer. Instructions for loading a model in the HDV in incremental mode are available in the HDV docs.

The following code example demonstrates a simple example of an incremental load of a single part:

// Load the assembly structure only
A3DImport sImport(path_to_CAD_file);
sImport.m_sLoadData.m_sIncremental.m_bLoadStructureOnly = true;
A3DStatus iRet = sHoopsExchangeLoader.Import(sImport);
// Here, you would traverse the assembly tree until you locate the leaf node you want to load...
// ...and store it in pMyProductOccurrence and its containing product occurrence in pRoot.
// For a detailed walkthrough, see the Incremental Load example in the package.
// Initialize our root and leaf product occurrence data
A3DAsmProductOccurrenceData sRootProductOccurrenceData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sRootProductOccurrenceData);
CHECK_RET(A3DAsmProductOccurrenceGet(pRoot, &sRootProductOccurrenceData));
A3DAsmProductOccurrenceData sProductOccurrenceData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sProductOccurrenceData);
CHECK_RET(A3DAsmProductOccurrenceGet(pMyProductOccurrence, &sProductOccurrenceData));
// Set options
sImport.m_sLoadData.m_sGeneral.m_eReadGeomTessMode = kA3DReadGeomAndTess;
sImport.m_sLoadData.m_sIncremental.m_bLoadStructureOnly = false;
sImport.m_sLoadData.m_sIncremental.m_ppProductOccurrences = &pMyProductOccurrence;
sImport.m_sLoadData.m_sIncremental.m_pRootProductOccurrence = pRoot;
sImport.m_sLoadData.m_sIncremental.m_uiProductOccurrencesSize = 1;

In this example, pMyProductOccurrence is a pointer to a leaf node containing geometry and/or tessellation. The variable pRoot is the Product Occurrence containing the leaf node pMyProductOccurrence.

After these variables are initialized, the options for the incremental load are set via the m_sLoadData member, which is an object of type A3DRWParamsIncrementalLoadData. Although we're only loading one leaf node in our example above, it is also possible to load more than one leaf node at a single time.

Once a part has been loaded, it can subsequently be unloaded with a call to the function A3DAsmModelFileUnloadParts().

Please note, CAD views are not supported in incremental mode.

Loading a PDF model

A PDF file can potentially contain multiple 3D data streams. Therefore, simply using A3DAsmModelFileLoadFromFile or A3DAsmModelFileGet will not work because those functions can only handle a single data stream. To load a PDF, you need to use A3DGet3DPDFStreams.

PDF data can be either in PRC or U3D format. If the data is PRC, you can load it from memory. If U3D, you must write the data to a temporary file before reading it using A3DPDF3DStreamCreateFromFile.

A3DStream3DPDFData* pStream3DPDFData;
A3DInt32 iNumStreams;
A3DGet3DPDFStreams((char*) pcFileName, &pStream3DPDFData, &iNumStreams);
// a real use case might parse every stream in the input file. Here, we just take the first one (pStream3DPDFData[0]).
if (pStream3DPDFData[0].m_bIsPrc) // test whether the data is PRC or U3D
// even an input PRC file must be read in memory and mapped into modelfile data structures
A3DRWParamsPrcReadHelper* pPrcReadHelper;
A3DAsmModelFileLoadFromPrcStream(pStream3DPDFData[0].m_pcStream, pStream3DPDFData[0].m_iLength, &pPrcReadHelper, ppModelFile);
// A U3D stream must first be stored as a physical file, then read by A3DAsmModelFileLoadFromFile
sprintf(tempfilename, "%s.u3d", OUT_FILE);
FILE * pFile = fopen(tempfilename , "wb");
fwrite(pStream3DPDFData[0].m_pcStream, 1, pStream3DPDFData[0].m_iLength , pFile);
// physical file to stream
A3DAsmModelFileLoadFromFile(tempfilename, sReadParam, ppModelFile);
// the temp file can be disposed of afterwards

Exporting a model

Exporting your model is similar to importing - simply reverse the procedure. You need only three things: the model file pointer, the export parameters structure, and the target filename. The supported export formats can be found here.

Indirect integration with the HOOPSExchangeLoader

Exporting a file with the HOOPSExchangeLoader is the preferred method when you are doing an indirect integration. Simply specify the filename of the import file and the export file. The export file type is determined by the file extension, so you should use a known file extension for the file format.

A3DImport sImport(importFilename);
A3DExport sExport(exportFilename);
A3DStatus iRet = sHoopsExchangeLoader.Convert(sImport, sExport);

Direct integration

Export options vary widely between file types. However, all export data structures have the following name:


...where * is substituted with the file type. Suppose you are exporting a STEP file. Configure a A3DRWParamsExportStepData data structure to suit your needs. Then, to export your model, you would do something like this:

A3DRWParamsExportStepData sParamsExportData;
A3D_INITIALIZE_DATA(A3DRWParamsExportStepData, sParamsExportData);
// set export options
sParamsExportData.m_bSaveFacetedToWireframe = true;
sParamsExportData.m_bSaveAnalyticsToNurbs = true;
iRet = A3DAsmModelFileExportToStepFile(pModelFile, &sParamsExportData, pcOutputFileName);
if (iRet != A3D_SUCCESS)
// handle error
top_level:1 prog_guide:1