MITK中State machine和configuration详解和调用顺序

(学习笔记,错误难免,请指正;私人劳动,转载请注明出处)

下面以MITK自带的mitkPointSetDataInteractor.h、mitkPointSetDataInteractor.cpp、PointSet.xml、PointSetConfig.xml为例,解释MITK中的交互原理,以及State machine和configuration的调用顺序。

PointSet.xml:

<statemachine>
    <state name="start" startstate="true">
        <transition event_class="InteractionPositionEvent" event_variant="AddPointClick" target="start">
             <action name="addpoint"/>
        </transition>
        <transition event_class="MouseMoveEvent" event_variant="CheckSelected" target="selected">
            <condition name="isoverpoint"/>
            <action name="selectpoint"/>
        </transition>
        <transition event_class="InteractionKeyEvent" event_variant="Abort" target="start">
          <action name="abort"/>
        </transition>
    </state>
    <state name="selected">
        <transition event_class="MouseMoveEvent" event_variant="CheckSelected" target="start">
            <condition name="isoverpoint" inverted="true"/>
            <action name="unselectAll"/>
        </transition>
        <transition event_class="MousePressEvent" event_variant="DeletePoint" target="start">
            <action name="removePoint"/>
        </transition>
        <transition event_class="MousePressEvent" event_variant="StartMove" target="MovementInitalized">
            <action name="initMove"/>
        </transition>
    </state>
    <state name="MovementInitalized">
      <transition event_class="MouseMoveEvent" event_variant="PointMove" target="MovementInitalized">
          <action name="movePoint"/>
      </transition>
      <transition event_class="MouseReleaseEvent" event_variant="EndMovement" target="selected">
         <action name="finishMovement"/>
      </transition>
    </state>
</statemachine>

PointSetConfig.xml:

<config>
  <!--   Set a maximal number of points here:
  <param name="MaxPoints" value="4"/>
  -->
  <event_variant class="InternalEvent" name="EnoughPoints">
    <attribute name="SignalName" value="MaxNumberOfPoints"/>
  </event_variant>
  <event_variant class="InternalEvent" name="NotEnoughPoints">
    <attribute name="SignalName" value="haslessthen3points"/>
  </event_variant>
  <event_variant class="InteractionKeyEvent" name="Abort">
    <attribute name="Key" value="Escape"/>
  </event_variant>
  <event_variant class="MousePressEvent" name="DeletePoint">
    <attribute name="EventButton" value="LeftMouseButton"/>
    <attribute name="Modifiers" value="alt"/>
  </event_variant>
  <event_variant class="MousePressEvent" name="AddPointClick">
    <attribute name="EventButton" value="LeftMouseButton"/>
    <attribute name="Modifiers" value="shift"/>
  </event_variant>
  <event_variant class="MousePressEvent" name="StartMove">
    <attribute name="EventButton" value="LeftMouseButton"/>
  </event_variant>
  <event_variant class="MouseMoveEvent" name="CheckSelected"/>
  <event_variant class="MouseReleaseEvent" name="EndMovement">
    <attribute name="EventButton" value="LeftMouseButton"/>
  </event_variant>
  <event_variant class="MouseMoveEvent" name="PointMove">
    <attribute name="ButtonState" value="LeftMouseButton"/>
  </event_variant>
</config>

自定义DataInteraction需要继承mitk::DataInteractor。自定义的函数必须通过重写ConnectActionsAndFunctions()函数与statemachine中的行为连接起来。比如mitkPointSetDataInteractor.cpp中:

void mitk::PointSetDataInteractor::ConnectActionsAndFunctions()
{
  // Condition which is evaluated before transition is taken
  // following actions in the statemachine are only executed if it returns TRUE
  CONNECT_CONDITION("isoverpoint", CheckSelection);
  CONNECT_FUNCTION("addpoint", AddPoint);
  CONNECT_FUNCTION("selectpoint", SelectPoint);
  CONNECT_FUNCTION("unselect", UnSelectPointAtPosition);
  CONNECT_FUNCTION("unselectAll", UnSelectAll);
  CONNECT_FUNCTION("initMove", InitMove);
  CONNECT_FUNCTION("movePoint", MovePoint);
  CONNECT_FUNCTION("finishMovement", FinishMove);
  CONNECT_FUNCTION("removePoint", RemovePoint);
}

调用顺序

当一个用户交互事件,如按住shift键单击左键发生时,MousePressEvent,经mitk::Dispatcher分发给对应的mitk::DataInteractor。该mitk::DataInteractor根据随事件传递过来的参数(value=”LeftMouseButton”、value=”shift”)会检查PointSetConfig.xml,结果发现有对应的事件:

  <event_variant class="MousePressEvent" name="AddPointClick">
    <attribute name="EventButton" value="LeftMouseButton"/>
    <attribute name="Modifiers" value="shift"/>
  </event_variant>

这里两个attribute标签即为事件的参数。找到shift+左键对应的event variant,返回event variant的名字“AddPointClick”。接着状态机在PointSet.xml中查找目前状态下是否存在能够被触发的transition,发现有,event_variant=”AddPointClick”。这个transition在start状态里,执行动作“AddPoint”(这个动作对应的函数在上面已经连接好了,为AddPoint()),然后跳到状态”start”。

如果触发的是configuration文件里的CheckSelected,则状态机里对应的是“start”状态里的MouseMoveEvent,检查条件“isoverpoint”是否满足(调用函数CheckSelection()),如果满足,执行行为”selectpoint”(调用函数SelectPoint()),然后根据target=”selected”跳到“selected”状态。这时如果configuration文件里的CheckSelected再被触发,则对应的transition是“selected”状态里的:

 <transition event_class="MouseMoveEvent" event_variant="CheckSelected" target="start">
            <condition name="isoverpoint" inverted="true"/>
            <action name="unselectAll"/>

我们看到,这时应该执行的行为就变为”unselectAll”了。

上行代码中 inverted=”true”是什么意思?

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。