简介
交互模式是 Teigha 图形系统的一项新功能。如果绘图过程耗时过长,它允许自动中断绘图过程。当然,在这种情况下,绘图不会完全完成,但此功能对于多次连续重绘非常有用,因为中间重绘的结果并不那么重要。
使用交互模式
交互模式通过 OdGsView API 控制。但是,如果相应的设备不支持此模式,则此模式无效。OdGsBaseVectorizeDevice 的以下方法检查设备是否支持此模式:
bool supportInteractiveViewMode() const;
此外,OdGsBaseVectorizeDevice 有一个方法允许您手动更改交互模式的支持:
void setSupportInteractiveViewMode( bool );
OdGsView API 为交互模式提供了以下方法:
-
virtual void beginInteractivityMode( double frameRateInHz )
此方法启用视图交互模式。frameRateInHz 指定所需的帧速率 (FPS)。此值定义了每秒所需的最小帧数。换句话说,如果您想限制每次重绘操作所需的时间(例如,“不超过 X 秒”),frameRateInHz 应该是此时间限制的倒数比率 (1 / X)。
-
virtual bool isInInteractivity() const
如果此视图处于交互模式,则返回 true。
-
virtual double interactivityFrameRate() const
返回在 beginInteractivityMode() 中指定的所需帧速率。
-
virtual void endInteractivity()
此方法禁用视图交互模式。
实现细节
当视图处于交互模式时,每次调用 OdGsBaseVectorizer::beginViewVectorization(通常来自 OdGsDevice::update())时,都会启动一个特殊计时器,该计时器将在 OdGsBaseVectorizer::endViewVectorization 中停止。每次对 OdGsBaseVectorizer::renderAbort 的请求都会检查此计时器。如果经过的时间超过 1 / interactivityFrameRate(),OdGsBaseVectorizer::renderAbort() 将返回 true,并且渲染循环将被中断。
交互模式有一些限制:
- 由于此模式基于 OdGsBaseVectorizer::renderAbort(),如果设备不支持 renderAbort() 功能,则此模式无效。
- 由于此模式在 OdGsNode 级别工作,如果绘图只包含少量大型(绘制时间长)节点(例如外部参照),则可能没有视觉效果。
- 有时渲染循环无法通过 renderAbort() 中断,只能被抑制。在这种情况下,交互模式仍然有效,但最终帧速率可能与预设值不同。
目前 Teigha 支持以下设备的交互模式:WinGDI、WinDirectX 和 WinOpenGL。
示例
OdaMfcApp 示例应用程序将交互模式用于 Orbit 命令。控制台命令“interactivity”允许您禁用或启用此模式并更改所需的帧速率:
交互模式的用法可以在 TD_DrawingExamplesCommon 的 EditorObject.cpp 中找到。我们使用一个辅助类来启用和禁用交互模式:
class ViewInteractivityMode
{
bool m_enabled;
OdGsView* m_pView;
public:
ViewInteractivityMode( OdRxVariantValue enable, OdRxVariantValue frameRate, OdGsView* pView )
{
m_enabled = false;
m_pView = pView;
if( !enable.isNull() )
{
m_enabled = (bool)(enable);
if( m_enabled && !frameRate.isNull() )
{
double rate = (double)(( (frameRate.get())->getDouble() ));
pView->beginInteractivity( rate );
}
}
}
~ViewInteractivityMode()
{
if( m_enabled ) m_pView->endInteractivity();
}
};
ViewInteractivityMode 的构造函数启用(如果需要)交互模式,析构函数禁用它。
函数 OdEx3dOrbitCmd::execute 在进入事件循环之前创建 ViewInteractivityMode 的实例:
void OdEx3dOrbitCmd::execute(OdEdCommandContext* pCmdCtx)
{
OdDbCommandContextPtr pDbCmdCtx(pCmdCtx);
OdDbDatabasePtr pDb = pDbCmdCtx->database();
OdSmartPtr<OdDbUserIO> pIO = pDbCmdCtx->userIO();
OdDbObjectPtr pVpObj = pDb->activeViewportId().safeOpenObject(OdDb::kForWrite);
OdDbAbstractViewportDataPtr pAVD(pVpObj);
OdGsView* pView = pAVD->gsView(pVpObj);
// There is one special case: layout with enabled 'draw viewports first' mode
{
if (!pDb->getTILEMODE())
{
OdDbLayoutPtr pLayout = pDb->currentLayoutId().openObject();
if (pLayout->drawViewportsFirst())
{
if (pView->device()->viewAt(pView->device()->numViews() - 1) == pView)
pView = pView->device()->viewAt(0);
}
}
}
//
OdRxVariantValue interactiveMode = (OdRxVariantValue)pCmdCtx->arbitraryData( OD_T("OdaMfcApp InteractiveMode" ) );
OdRxVariantValue interactiveFrameRate = (OdRxVariantValue)pCmdCtx->arbitraryData( OD_T("OdaMfcApp InteractiveFrameRate" ) );
ViewInteractivityMode mode( interactiveMode, interactiveFrameRate, pView );
OdStaticRxObject<RTOrbitTracker> tracker;
for(;;)
{
try
{
tracker.init(pView, pIO->getPoint(OD_T("Press ESC or ENTER to exit."),
OdEd::kInpThrowEmpty|OdEd::kGptNoUCS|OdEd::kGptNoOSnap|OdEd::kGptBeginDrag, 0, OdString::kEmpty, &tracker));
pIO->getPoint(OD_T("Press ESC or ENTER to exit."),
OdEd::kInpThrowEmpty|OdEd::kGptNoUCS|OdEd::kGptNoOSnap|OdEd::kGptEndDrag, 0, OdString::kEmpty, &tracker);
tracker.reset();
}
catch(const OdEdCancel)
{
break;
}
}
}
当函数结束时,ViewInteractivityMode 的实例会自动删除,这将调用 OdGsView::endInteractivity()。
下面是一些示例。在第一个示例中,帧速率足够小,因此在执行 Orbit 命令时会显示所有实体:
此处帧速率增加,因此绘图的某些部分消失了:
此处帧速率再次增加,因此只显示了原始实体中的少数几个: