Adding Predefined Controls to 3D Models using Teigha Publish

Sergey Sorvenkov

February 09, 2018

Introduction

For quick document creation of 3D models using Teigha Publish, there is a class OdAnnotation with a set of functions that implement ready-to-use basic controls that can:

  • Switch 3D model views
  • Display a 3D model element list and select those elements
  • Display a selected element’s properties list
  • Display a particular element’s properties in text fields

Carousel buttons

To create a group of buttons that can be used to switch between 3D model views, use two functions:

void setCarouselButtons(const OdStringArray& button_names, const OdString& previous_button_name, const OdString& next_button_name, OdUInt16 scroll_size);

and

void setCarouselViews(const OdUInt32Array& indices, const OdImagePtrArray& images);

This group of buttons is located at the bottom of the OdAnnotation object. View selection is performed by clicking the corresponding button. Arrows are used to scroll the list of views back and forth. An example is shown below.

image1

The function setCarouselButtons sets the button names, as well as the back and forth list buttons if necessary (optional). List button names can also be used for setting additional actions (not only listing). The last parameter set by this function is the listing step.

The function setCarouselViews sets the view index array in the corresponding OdArtworkPtr object and an array of images for the buttons. The array of images may be obtained from the 3D model using the OdPrcPreviewGenerator class object:

OdStreamBufPtr pStreamPrc = odrxSystemServices()->createFile(sIn, Oda::kFileRead);

OdStaticRxObject prcHostAppServ;
OdPrcFilePtr pPrcFile = prcHostAppServ.readFile(pStreamPrc);

OdGiRasterImagePtrArray arrRasImg;
OdPrcPreviewGeneratorPtr pPreviewGen = OdPrcPreviewGenerator::createObject();
ODA_VERIFY(pPreviewGen->init(pDb) == eOk);

pPreviewGen->setBackground(ODRGB(192, 220, 248));
pPreviewGen->setBitmapSize(286, 150);

ODA_VERIFY(pPreviewGen->generatePreviewSet(arrRasImg) == eOk);

List of views

To switch views of the 3D model, we have another pair of functions:

void setViewList(const OdRect& location, const OdListBoxPtr& list);

Creates a list of views in the OdListBox object and sets this object in the location position.

void setViewListByField(const OdString& field);

Creates an OdListBox object, which contains a list of views with names. This name will be displayed in the upper right part of the OdAnnotation object. Selecting an item from this list (in the upper right) selects the view. The upper part of the picture below shows the results of the setViewListByField function and the lower part shows the results of the setViewList function.

image2

List of parts

The following function is used to create a parts list:

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

It creates a table that consists of three columns with a list of 3D model parts. The first column is the number, the second one is the part name, and the third one is the quantity of such parts located in the model. The table header is set by the corresponding function parameters. When a table string is selected, the corresponding detail is highlighted. To switch the highlighting off, double-click an empty area in the model display window. A parts list example is shown below.

image3

The names list (OdStringArray node_names), which is the setPartsList function parameter, should contain the list of node names obtained from the 3D model. To provide selection capability, those nodes should contain a geometry model. To get the list of part names, you can use the CalculateUniqueNames function.

void traverseTree(OdPrcProductOccurrencePtr productOccurrence, OdStack &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();
  if(pPartDef)
  {
    const OdPrcObjectIdArray &rItemArr = pPartDef->representationItem();
    if(0 != rItemArr.size())
      stackPO.push(productOccurrence);
  }
}

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 stackPO;
        traverseTree(rootProductOccurrence, stackPO);
        while(!stackPO.empty())
        {
          if (stackPO.top())
          {
            OdPrcProductOccurrencePtr &pTopPO = *stackPO.top();
            if (!pTopPO.isNull())
            {
              arrOutStr.push_back(pTopPO->calculateUniqueName(NULL));
            }
          }
          stackPO.pop();
        }
      }
    }
  }
  return arrOutStr;
}

List of properties

To create a control that lists all properties of a 3D model element, the following function is used:

void setPropertyList(const OdRect& location);

Each item of this list consists of two parts: the upper one is the property name and the lower one is the property value. An example of a properties list is shown below.

image4

When a 3D model element is selected, the list is filled with name-value pairs for the element (if the element has properties).

Element properties in separate text fields

Here is the function:

void setPropertyToTextField(const OdString& property_name, const OdTextFieldPtr text_field);

This function outputs the property_name property value to the text field text_field for an object that is selected in a 3D model. If the element does not have properties with this name, the text field will stay empty. An example of properties outputted to text fields is shown below.

image5