Getting acquainted with the element filtering in the views

Artur Vakhramov

October 25, 2018

Introduction

It was revealed that views do not include a special list with all the graphic elements. During the rendering procedure the necessary elements are selected from the common database according to the rules. This article will illustrate the basic rules, which show what to start your custom graphic viewer with.

Start view

It was revealed that file open starts the search of the view to be rendered. This is done using DBDrawingInfo manager, which includes DBDrawing elements list and a pointer to the active DBDrawing element. Below is the dump with the DBDrawingInfo manager:

OdBmDBDrawingInfoPtr Item[6]: . . . . . . . address is not Null
  RxObjectWeakPtr ADocument . . . . . . . . 52
  VariantArray DBDrawingsIndex. . . . . . . Size: 6
    Handle Item[0]. . . . . . . . . . . . . 1109
    Handle Item[1]. . . . . . . . . . . . . 1499
    Handle Item[2]. . . . . . . . . . . . . 1509
    Handle Item[3]. . . . . . . . . . . . . 1518
    Handle Item[4]. . . . . . . . . . . . . 1892
    Handle Item[5]. . . . . . . . . . . . . 2320
  VariantArray OpenWindowStates . . . . . . Size: 1
    OdBmWindowStatePtr Item[0]: . . . . . . address is not Null
      GePoint3d ProjLeftBottom. . . . . . . [-1.1; -0.5; 0.0]
      GePoint3d ProjRightTop. . . . . . . . [0.9; 0.3; 0.0]
      Handle DBDrawingId. . . . . . . . . . 2320
      int ShowState . . . . . . . . . . . . 2
      int ScreenWidth . . . . . . . . . . . 1676
      int ScreenHeight. . . . . . . . . . . 718
      int ScreenLeft. . . . . . . . . . . . -6
      int ScreenRight . . . . . . . . . . . -6
      int ScreenTop . . . . . . . . . . . . -25
      int ScreenBottom. . . . . . . . . . . -6
  int HorizontalRes . . . . . . . . . . . . 1920
  int VerticalRes . . . . . . . . . . . . . 952

This manager includes an array of IDs – DBDrawingIndex for all DBDrawing elements available. It also includes start window settings with the active DBDrawing element. If the start window settings aren’t set – the first DBDrawing element is used.

Code example, that illustrates getting of the active DBDrawing:

OdBmDBDrawingInfoPtr pDBDrawingInfo = pDatabase->getAppInfo(OdBm::ManagerType::DBDrawingInfo);
OdBmDBDrawingPtr pDBDrawing = pDBDrawingInfo->getActiveDBDrawingId().safeOpenObject();

We can also get the information about the main Viewport and main View:

OdBmViewportPtr pBaseViewport = pDBDrawing->getBaseViewportId().safeOpenObject();
OdBmDBViewPtr pView = pBaseViewport->getDbViewId().safeOpenObject();

So we get the start view, which is used for the rendering. You can get any other view in the same way using the information about the DBDrawing elements available in DBDrawingInfo manager.

NOTE: the information about getting the active view may be found here https://docs.opendesign.com/tbim/tbim_views.html

View elements selection

Every view can give the list of elements available for rendering. Functions below may be used to do that:

/** \details
Returns the list of the annotated elements of the view.
		
\param  arr [out] Output list of drawable elements.
*/
void getFrontDrawableElements(OdBmObjectIdArray& arr);

/** \details
Returns the list of the non-annotated of the view.
		
\param  arr [out] Output list of drawable elements.
*/
void getDrawableElements(OdBmObjectIdArray& arr);

Those functions perform:

  • the selection of elements available for rendering basing on the file type (.rvt/.rfa);
  • the selections of information from the elements’ headers;
  • the splitting elements into 2 groups: being rendered on the front and “common” ones.

Elements filtering

If the element is available for rendering that does not mean that it should be rendered obligatory. Element may have its own custom rendering rules, that should be considered.

unplacedOwnerId is one of the rules that forbades the element rendering:

if (! pElement->getUnplacedOwnerId().isNull() ) {/*skip vectorization*/}

In addition every view has its own set of rules and filters to be considered during the rendering.

Design filtering

Every view element ma belong to a particular design (element->getDesignOptionId()). A rendering implementation example for elements of one design “Main model”

bool OdBmDBViewImpl::isElementDesignOptionVisible(const OdBmObjectId& designOptionId) const
{
  if (!designOptionId.isValid() ||
    !OdBmObjectId::isRegularHandle(designOptionId.getHandle())) { // element is from Main model, so it is always visible
    return true;
  }
  
  const OdBmDesignOptionPtr pElementDesignOption = designOptionId.safeOpenObject();
  const OdBmDesignOptionViewSettingsPtr& pDOVS = getDesignOptionViewSettings();
  
  if (!pElementDesignOption.isNull() && !pDOVS.isNull()) {

    const OdBmObjectId elementDesignOptionSetId = pElementDesignOption->getDesignOptionSetId();
  
    OdBmMap<OdBmObjectId, OdBmObjectId> mapSettingsOptions;
    pDOVS->getOverridingOptions2(mapSettingsOptions);
  
    OdBmMap<OdBmObjectId, OdBmObjectId>::const_iterator it = mapSettingsOptions.find(elementDesignOptionSetId);
    if (it != mapSettingsOptions.end()) {
      if (designOptionId != it->second) {
        return false;
      }
    }
    else {
      const OdBmDesignOptionSetPtr pElementDesignOptionSet = elementDesignOptionSetId.safeOpenObject();
      if (pElementDesignOptionSet->getMainDesignOption() != designOptionId) {
        return false;
      }
    }
  }

  return true;
}

Category filtering

Every element can have a category (element->getCategroryId()). It is possible to use Category as a filtering option. An example of category filtering is below:

bool OdBmDBViewImpl::isElementCategoryVisible(const OdBmObjectId& categoryId) const
{
  if (categoryId.isNull())
    return true;

  // check IckyExcludedCategoriesSetPtrWrapper
  OdBmObjectIdArray aExcludedCategoryIds;
  const OdBmDrawFilterPtrArray& aDrawFilters = getDrawFilters();
  OdBmDrawFilterPtrArray::const_iterator itEnd = aDrawFilters.end();
  for (OdBmDrawFilterPtrArray::const_iterator it = aDrawFilters.begin(); it != itEnd; ++it)
  {
    if ((*it)->isA() == OdBmIckyExcludedCategoriesSetPtrWrapper::desc())
    {
      OdBmIckyExcludedCategoriesSetPtrWrapperPtr pExclSet = *it;

      // check excluded categories
      pExclSet->getCategoryIds(aExcludedCategoryIds);
      if (aExcludedCategoryIds.contains(categoryId))
        return false;

      // get category data
      const OdBmCategoryElemPtr pCategoryElem = categoryId.safeOpenObject();
      const OdBmCategoryPtr category = pCategoryElem->getCategory();

      OdInt32 categoryType(OdBm::CategoryType::Invalid);
      OdBmObjectId::handle_type parentId;

      if (category.get()) {
        categoryType = category->getCategoryType();
        parentId = category->getParentCategoryId();
      }

      // check excluded category types
      switch (categoryType) {
        //case OdBm::CategoryType::Invalid:
        //  // do nothing
        //  break;
      case OdBm::CategoryType::Model:
        if (pExclSet->getModelsExcluded()) return false;
        break;
      case OdBm::CategoryType::Annotation:
        if (pExclSet->getAnnotationsExcluded()) return false;
        break;
        //case OdBm::CategoryType::Internal:
        //  // do nothing
        //  break;
      case OdBm::CategoryType::AnalyticalModel:
        if (pExclSet->getAnalyticalModelsExcluded()) return false;
        break;
      }

      //TODO if (pExclSet->getMassShellExcluded()) {} //do smth
      //TODO if (pExclSet->getImportsExcluded()) {} // do smth

      // check excluded parent categories
      if (parentId != OdBmObjectId::kNullHandle)
      {
        for (OdBmObjectIdArray::const_iterator it = aExcludedCategoryIds.begin();
          it != aExcludedCategoryIds.end(); ++it) {
          if ((*it).getHandle() == parentId)
            return false;
        }
      }

      break;
    } // if ((*it)->isA() == OdBmIckyExcludedCategoriesSetPtrWrapper::desc())
  } // for (OdBmObjectPtrArray::const_iterator it = m_DrawFilters.begin(); it != m_DrawFilters.end(); ++it)

  return true;
}

Please pay attention that in the sample above category filtering options are obtained from the required view. Category type and parent category are considered as well.

Element filtering

A view can have a hidden list of elements. An example of element filtering basing on a hidden element list:

// check element filter
{
  OdBmObjectIdArray aExcludedElementIds;
  const OdBmHiddenElementsViewSettingsPtr& pHiddenElemSettings = getHiddenElementsViewSettings();
  pHiddenElemSettings->getHiddenElements(aExcludedElementIds);

  if (aExcludedElementIds.contains(element->objectId()))
    return false;
}

Element parameter filtering

A view can have a list of hidden element parameters. An example of filtering basing on a hidden element parameters:

// check element parameter filter
{
  OdBmObjectPtrArray aParameterFilters;
  const OdBmFilterOverridesPtr& pFilterOverrides = getFilterOverrides();
  OdBmObjectPtrArray aFilterSettings;
  pFilterOverrides->getSettings(aFilterSettings);
  OdBmObjectPtrArray::const_iterator itFSEnd = aFilterSettings.end();
  for (OdBmObjectPtrArray::const_iterator it = aFilterSettings.begin(); it != itFSEnd; ++it)
  {
    if ((*it)->isA() == OdBmFilterGraphicSettings::desc())
    {
      OdBmFilterGraphicSettingsPtr pFilterGraphicsSettings = (*it);
      if (!pFilterGraphicsSettings->getVisibilityFlag())
      {
        OdBmParameterFilterElementPtr pFilterElem = pFilterGraphicsSettings->getFilterElemId().safeOpenObject();
        aParameterFilters.push_back(pFilterElem);
      }
    }
  }

  OdBmObjectPtrArray::const_iterator itPFEnd = aParameterFilters.end();
  for (OdBmObjectPtrArray::const_iterator it = aParameterFilters.begin(); it != itPFEnd; ++it)
  {
    OdBmParameterFilterElementPtr pFilterElem = (*it);
    OdBmObjectIdArray aCategories;
    pFilterElem->getCategoryRule()->getCategories(aCategories);
    if (!aCategories.contains(element->getCategroryId()))
      return false;

    // check rules
    OdBmObjectPtrArray aRules;
    pFilterElem->getRules(aRules);
    for (OdBmObjectPtrArray::const_iterator it = aRules.begin(); it != aRules.end(); ++it)
    {
      OdBmFilterRulePtr pFilterRule = (*it);
      if (!pFilterRule->elementPasses(element))
        return false;
    }
  }
}

NOTE: when filtering, OdBmFilerRule is used (https://docs.opendesign.com/tbim/frames.html?frmname=topic&frmfile=tbim_filtering.html)

Conclusion

After filtering is performed it is possible to start rendering. It is possible to use geometry cash while rendering (element->getGeometry()).

Sometimes an element may be considered visible, but won’t be rendered. For instance that may happen if the element does not have geometry cash. Element may be a transit element and it is necessary to address another element (for example, FamilyInstance includes transformation matrix for FamilySymbol geometry – this matrix should be considered while rendering FamilySymbol geometry).

Element geometry can have different attributes/options that influence whether or not an element is rendered. GFiler object or GInfo flags are the examples of such options.