Preparing 3D (PRC) Models for Document Creation using ODA Publish

Sergey Sorvenkov

April 11, 2019


To use animation and some predefined controls in ODA Publish, you need to get unique node names and be able to set attributes for the nodes. This article provides an overview of using this functionality.

Obtaining node names from the 3D model

To use animation with Publish SDK, you need to know the unique names of the nodes in order to change their color, visibility, and set of movements. Below is a sample JavaScript code snippet for moving a node “Car_08_4.a0d4eb333557af83ada02ad56b4ba54da02a60”.

var node = scene.nodes.getByName('Car_08_4.a0d4eb333557af83ada02ad56b4ba54da02a60');
var transform_matrix = node.transform;
transform_matrix.translateInPlace(new Vector3(12, 0, 0));

For more information about using animation in Publish SDK, see Publish SDK Documentation (login required).

The predefined control for a Parts List also requires a list of node names.

void setPartsList(const OdStringArray node_names, const OdRect& location, const OdStringArray& headers, const OdDoubleArray& columns, 
    const OdTextFieldPtr text_style, const OdTextFieldPtr header_style);

For more information about using a Parts List in Publish SDK, see Publish SDK Documentation.

To get the list of node names, you can use the CalculateUniqueNames function.

void traverseTree(OdPrcProductOccurrencePtr productOccurrence, OdStack<OdPrcProductOccurrencePtr> &stackPO)
  OdString name = productOccurrence->name().name();
  int count = productOccurrence->referencesOfProductOccurrence().getSonProductOccurrences().size();
  for (int idx = 0; idx < count; ++idx)
    // - child.traverse
    OdPrcObjectPtr objPO = productOccurrence->referencesOfProductOccurrence().getSonProductOccurrences()[idx].openObject();
OdPrcProductOccurrencePtr pPO = (OdPrcProductOccurrence *) objPO.get(); ODA_ASSERT(!pPO.isNull());
    OdString name1 = pPO->name().name();
    traverseTree(pPO, stackPO);

  const OdPrcPartDefinition *pPartDef = productOccurrence->getPartDefinition();
    const OdPrcObjectIdArray &rItemArr = pPartDef->representationItem();
    if(0 != rItemArr.size())

OdStringArray CalculateUniqueNames(const OdPrcFilePtr &pPrcFile)
  OdStringArray arrOutStr;
  if (!pPrcFile.isNull())
    const OdPrcObjectIdArray &roots = pPrcFile->modelFileData().getStartRootOccurrences();
    OdUInt32 countRoots = roots.size();
    for (OdUInt32 idx = 0; idx < countRoots; idx++)
      OdPrcProductOccurrencePtr rootProductOccurrence = pPrcFile->modelFileData().getStartRootOccurrences()[idx].safeOpenObject();
      if (!rootProductOccurrence.isNull())
        OdStack<OdPrcProductOccurrencePtr> stackPO;
        traverseTree(rootProductOccurrence, stackPO);
          if (
            OdPrcProductOccurrencePtr &pTopPO = *;
            if (!pTopPO.isNull())
  return arrOutStr;

This function retrieves a list of all nodes from the 3D model that have a representation item. Elements that don't have a representation item cannot be used to create an animation or Parts List. By changing the CalculateUniqueNames function, you can get a Parts List for any part of a 3D model.

Changing the attributes of the 3D model element for use in the Property List

To use the predefined Property List control (see below), you must set the corresponding attributes for the 3D model elements.




An example of the attribute specification code follows:

OdPrcObjectPtr objPO = productOccurrence->referencesOfProductOccurrence().getSonProductOccurrences()[idx].openObject();
OdPrcProductOccurrencePtr pPO = (OdPrcProductOccurrence *) objPO.get(); ODA_ASSERT(!pPO.isNull());

OdPrcAttributeData attrdata = pPO->attributeData();

OdPrcAttributeArray &attrArr = attrdata.attributes();
OdPrcAttribute* newAttribute = attrArr.append();

  // create pair
OdPrcContentSingleAttribute attributeDataPair;

  // add pair to attribute

OdPrcAttributeEntry title;