How to Get Element Parameters in Teigha BIM

Artur Vakhramov

March 30, 2018

This article describes just some of the Teigha BIM features used for obtaining and implementing element parameters.

The list of available built-in parameters is located in the BmBuiltInParameter.h file. The Teigha BIM user interface for obtaining element parameters is available in the BmElement.h and BmObject.h files:

  • getListParams function — Gets a list of available built-in parameters for the element.
  • getParam function — Gets the value of the specified parameter. The parameter can have four types: integer (OdInt32), floating-point number (double), string (OdString), object identifier (OdBmObjectId). The parameter is also available as OdTfVariant.
  • getFilterElement function — Gets the element from which you need to take a parameter to perform the filtering.

The general principles of working with parameters are:

  • If necessary, you request a list of available element parameters via getListParams.
  • To get the element that has the parameter that should be used when performing the filtering, request it via getFilterElement.
  • The element for the requested parameter requests its value via getParam.
  • The return value of the function is checked:
    • eOk — The requested parameter is present in the list of available parameters and the parameter value was successfully received.
    • eNotImplementedYet — The requested parameter is present in the list of available parameters, but the parameter value is not yet implemented.
    • eNotApplicable — The requested parameter is present in the list of available parameters, but the value of the parameter is absent (HasValue = False).
    • eKeyNotFound — The requested parameter is not in the list of available parameters.

Using getFilterElement

In Teigha BIM, the getFilterElement function is used when performing filtering on visible elements in the OdBmFilterDoubleRule, OdBmFilterElementIdRule, OdBmFilterIntegerRule, and OdBmFilterStringRule rules.

The rules are set in Autodesk® Revit® using the View-> Filters menu.

Filtering by these parameters can be performed not by the value of the parameter from the element itself, but from an associated element. An example is the FamilyInstance element, where the filtering uses the value of the UNIFORMAT_CODE parameter not from itself, but from the associated MasterSymbolId element.

OdBmElementPtr OdBmFamilyInstanceImpl::getFilterElement(const OdBm::BuiltInParameter::Enum& parameterId) const {
  switch (parameterId) {
    case OdBm::BuiltInParameter::UNIFORMAT_CODE: {
      if (!getMasterSymbolId().isNull()) {
        return getMasterSymbolId().safeOpenObject();
      }
    } break;
  }

  return super::getFilterElement(parameterId);
}

By default, the getFilterElement function for an element returns the element itself.

OdBmElementPtr OdBmElementImpl::getFilterElement(const OdBm::BuiltInParameter::Enum& parameterId) const {
  return this->getFacade();
}

OdBmElementPtr OdBmElementImpl::getFilterElement(const OdBmObjectId& parameterId) const {
  OdUInt64 value = parameterId.getHandle();
  if (OdBm::BuiltInParameter::contains(value)) {
    return getFilterElement(static_cast<OdBm::BuiltInParameter::Enum>(value));
  }
  return this->getFacade ();
}

How it works

The implementation of parameter DESIGN_OPTION_ID

The DESIGN_OPTION_ID parameter is a parameter that is present for all elements, so it was added to the parameter list in the function OdBmElementImpl::getListParams.

Its implementation in Teigha BIM is performed in a function (wrapped in a macro):

ODBM_BUILTIN_PARAMETERS_COMMON_IMPLEMENTATION(OdBmElementImpl, OdBmObjectId,
                                                    pThis, parameter, value).

However, in the case where the value of the parameter takes "-4", Revit Lookup substitutes it for "-1". This substitution was implemented in Teigha BIM.

const OdBmObjectId& OdBmElementImpl::getDesignOptionIdAsParam() const {
  const OdBmObjectId& designOptionId = getDesignOptionId();
  return OdBmObjectId::isRegularHandle(designOptionId.getHandle()) ? designOptionId : OdBmObjectId::kNull;
}

Obtaining parameters using the example of the FamilySymbol element

The internal implementation of getting parameters is done in impl-files, in our case BmFamilySymbolImpl.h and BmFamilySymbolImpl.cpp.

The header is added to the file:

  1. Macro of auxiliary definitions:
    ODBM_BUILTIN_PARAM_STUFF(OdBmFamilySymbolInternalImpl);
    
  2. If necessary, the function definition macros for the parameters in the breakdown by types:
    ODBM_BUILTIN_PARAM_METHOD_DECLARATION(OdInt32);
    ODBM_BUILTIN_PARAM_METHOD_DECLARATION(double);
    ODBM_BUILTIN_PARAM_METHOD_DECLARATION(OdString);
    ODBM_BUILTIN_PARAM_METHOD_DECLARATION(OdBmObjectId);
    
  3. If necessary, the macro for general parameter processing:
    ODBM_PARAM_SET_TYPES(ODBM_PARAM_METHODS_DECLARATION, ODBM_VIRTUAL, , ODBM_SEMICOLON);
    
  4. Function of obtaining the list of parameters::
    virtual void getListParams(OdBuiltInParamArray& aParams) const ODRX_OVERRIDE;
    
  5. If necessary, the filter function:
    virtual OdBmElementPtr getFilterElement(const OdBm::BuiltInParameter::Enum& parameterId) const ODRX_OVERRIDE;
    

In the cpp-file are added:

  1. Implementation of the general processing of parameters using macros (in our case, the parameter is first searched in the FamilyParams attribute):
    #define ODBM_PARAM_METHOD_FAMILYSYMBOLIMPL_IMPLEMENTATION(METHOD)            \
      {                                                                          \
        OdResult es =                                                   \
            OdBmFamilyParamsPtr(getParams())->METHOD##Param(parameterId, value); \
        if (es == eOk || es == eNotImplementedYet || es == eNotApplicable) {      \
          return es;                                                             \
        }                                                                        \
        return super::METHOD##Param(parameterId, value);                         \
      }
    
    
    ODBM_PARAM_SET_TYPES(ODBM_PARAM_METHODS_DECLARATION, ,
      OdBmFamilySymbolImpl::,
      ODBM_PARAM_METHOD_FAMILYSYMBOLIMPL_IMPLEMENTATION);
    
  2. Realization of obtaining a list of parameters (in our case, first the list is formed by calling the base class, then the parameters specific for FamilySymbol are added):
    void OdBmFamilySymbolImpl::getListParams(OdBuiltInParamArray& aParams) const {
      super::getListParams(aParams);
      
      //...
    }
    
  3. Implementation of functions for working with parameters through macros (given as an example in the general view for only one type of OdInt32):
    ODBM_BUILTIN_PARAMETERS_COMMON_IMPLEMENTATION(OdBmFamilySymbolImpl, OdInt32,
      pThis, parameter, value) {
      switch (parameter) {
        case OdBm::BuiltInParameter::SOME_PARAMETER_1: {
          //...
        } break;
    
        case OdBm::BuiltInParameter::SOME_NOT_IMPLEMENTED_PARAMETER: {
          return eNotImplementedYet;
        } break;
      }
    
      return eKeyNotFound;
    }
    
  4. Implementation of the filtering function (taken from the FamilyInstance element):
    OdBmElementPtr OdBmFamilyInstanceImpl::getFilterElement(const OdBm::BuiltInParameter::Enum& parameterId) const {
      switch (parameterId) {
        case OdBm::BuiltInParameter::UNIFORMAT_CODE: {
          if (!getMasterSymbolId().isNull()) {
            return getMasterSymbolId().safeOpenObject();
          }
        } break;
      }
    
      return super::getFilterElement(parameterId);
    }
    

Using template methods when implementing parameters

When implementing parameters, template methods are used:

  • forwardParam — Throws the parameter's processing to another object.
  • universalAccess — Indicates the access functions to the parameter.
  • onlyStaticValue — Processes the parameter as a static value.