引言
我们发现视图不包含所有图形元素的特殊列表。在渲染过程中,会根据规则从公共数据库中选择必要的元素。本文将阐述基本规则,展示如何开始构建自定义图形查看器。
启动视图
我们发现文件打开会启动对要渲染的视图的搜索。这是通过 DBDrawingInfo 管理器完成的,该管理器包含 DBDrawing 元素列表和指向活动 DBDrawing 元素的指针。下面是 DBDrawingInfo 管理器的转储:
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
此管理器包含一个 ID 数组——DBDrawingIndex,用于所有可用的 DBDrawing 元素。它还包含带有活动 DBDrawing 元素的启动窗口设置。如果未设置启动窗口设置,则使用第一个 DBDrawing 元素。
代码示例,演示如何获取活动的 DBDrawing:
OdBmDBDrawingInfoPtr pDBDrawingInfo = pDatabase->getAppInfo(OdBm::ManagerType::DBDrawingInfo);
OdBmDBDrawingPtr pDBDrawing = pDBDrawingInfo->getActiveDBDrawingId().safeOpenObject();
我们还可以获取有关主视口和主视图的信息:
OdBmViewportPtr pBaseViewport = pDBDrawing->getBaseViewportId().safeOpenObject();
OdBmDBViewPtr pView = pBaseViewport->getDbViewId().safeOpenObject();
因此,我们获取用于渲染的起始视图。您可以使用 DBDrawingInfo 管理器中提供的有关 DBDrawing 元素的信息,以相同的方式获取任何其他视图。
注意:有关获取活动视图的信息可在此处找到 https://docs.opendesign.com/tbim/tbim_views.html
视图元素选择
每个视图都可以提供可用于渲染的元素列表。可以使用以下函数来完成此操作:
/** \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);
这些函数执行:
- 根据文件类型(.rvt/.rfa)选择可用于渲染的元素;
- 从元素头中选择信息;
- 将元素分为两组:在前面渲染的元素和“普通”元素。
元素过滤
如果元素可用于渲染,这并不意味着它必须强制渲染。元素可能有自己的自定义渲染规则,应予以考虑。
unplacedOwnerId 是禁止元素渲染的规则之一:
if (! pElement->getUnplacedOwnerId().isNull() ) {/*skip vectorization*/}
此外,每个视图都有自己的一套规则和过滤器,在渲染时需要考虑。
设计过滤
每个视图元素都可能属于特定的设计(element->getDesignOptionId())。以下是针对一个设计“主模型”的元素渲染实现示例
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;
}
类别过滤
每个元素都可以有一个类别(element->getCategroryId())。可以使用类别作为过滤选项。以下是类别过滤的示例:
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;
}
请注意,在上面的示例中,类别过滤选项是从所需视图中获取的。类别类型和父类别也一并考虑。
元素过滤
视图可以有一个隐藏的元素列表。以下是基于隐藏元素列表的元素过滤示例:
// check element filter
{
OdBmObjectIdArray aExcludedElementIds;
const OdBmHiddenElementsViewSettingsPtr& pHiddenElemSettings = getHiddenElementsViewSettings();
pHiddenElemSettings->getHiddenElements(aExcludedElementIds);
if (aExcludedElementIds.contains(element->objectId()))
return false;
}
元素参数过滤
视图可以有一个隐藏的元素参数列表。以下是基于隐藏元素参数的过滤示例:
// 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;
}
}
}
注意:过滤时使用 OdBmFilerRule (https://docs.opendesign.com/tbim/frames.html?frmname=topic&frmfile=tbim_filtering.html)
总结
过滤完成后,可以开始渲染。渲染时可以使用几何体缓存(element->getGeometry())。
有时,一个元素可能被认为是可见的,但不会被渲染。例如,如果元素没有几何体缓存,就可能发生这种情况。元素可能是一个过渡元素,需要处理另一个元素(例如,FamilyInstance 包含 FamilySymbol 几何体的变换矩阵——在渲染 FamilySymbol 几何体时应考虑此矩阵)。
元素几何体可以具有不同的属性/选项,这些属性/选项会影响元素是否被渲染。GFiler 对象或 GInfo 标志就是此类选项的示例。