[返回博客](/cn/blog) # Teigha 内核：OdGsView 交互模式

Egor Slupko 十二月 07, 2017 [\#rendering](/cn/blog/tag/rendering) [\#Example](/cn/blog/tag/example) [\#sources](/cn/blog/tag/sources)

<a class="a2a_button_facebook"></a><a class="a2a_button_twitter"></a><a class="a2a_button_linkedin"></a>

#### 简介

交互模式是 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”允许您禁用或启用此模式并更改所需的帧速率：

![image1](/files/inline-images/image002_9.jpg)交互模式的用法可以在 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 命令时会显示所有实体：

![image2](/files/inline-images/image004_3.jpg)此处帧速率增加，因此绘图的某些部分消失了：

![image3](/files/inline-images/image006_1.jpg)此处帧速率再次增加，因此只显示了原始实体中的少数几个：

![image4](/files/inline-images/image008_1.jpg)

## 今天就开始行动

**免费试用 ODA 软件 60 天。  
无风险，无需信用卡。**

[免费试用](https://www.opendesign.com/cn/free-trial)
