一、背景描述:
MITK的Measurement插件支持多种二维测量工具,但是也有一定的缺点:完成一次测量后,测量工具对应的按钮自动弹起,需要再次选择工具方可再次测量,特别是对于连续进行一种类型的测量工具时,操作不连贯。
二、源码分析:
分析MITK的源码,每次测量时,点击按钮时将对应创建一个mitk::DataNode,并创建一个工具对应PlanarFigure类型的数据设置data。然后在view中实现NodeAdded()虚函数,并在该函数中为新创建的数据类型添加事件监听。
typedef itk::SimpleMemberCommand<QmitkMeasurementView> SimpleCommandType;
typedef itk::MemberCommand<QmitkMeasurementView> MemberCommandType;
// add observer for event when figure has been placed
auto initializationCommand = SimpleCommandType::New();
initializationCommand->SetCallbackFunction(this, &QmitkMeasurementView::PlanarFigureInitialized);
data.m_EndPlacementObserverTag = planarFigure->AddObserver(mitk::EndPlacementPlanarFigureEvent(), initializationCommand);
// add observer for event when figure is picked (selected)
auto selectCommand = MemberCommandType::New();
selectCommand->SetCallbackFunction(this, &QmitkMeasurementView::PlanarFigureSelected);
data.m_SelectObserverTag = planarFigure->AddObserver(mitk::SelectPlanarFigureEvent(), selectCommand);
// add observer for event during interaction when a point is moved
auto duringInteractionCommand = SimpleCommandType::New();
duringInteractionCommand->SetCallbackFunction(this, &QmitkMeasurementView::UpdateMeasurementText);
data.m_DuringInteractionObserverTag = planarFigure->AddObserver(mitk::PointMovedPlanarFigureEvent(), duringInteractionCommand);
其中,监听mitk::EndPlacementPlanarFigureEvent()事件,即为完成一次测量时触发该事件,在PlanarFigureInitialized这个回调函数中将所有的测量工具初始化为未按下状态。
从而实现了点击一次按钮进行一次测量,测量结束后将所有的按钮初始化。
三、连接测量实现:
实现的基本思路是测量结束后,不去初始化按钮,而是根据按钮创建一个新的DataNode并给该dataNode设置上交互器,从而实现了连接测量。
1. 首先修改mitk::EndPlacementPlanarFigureEvent()的回调函数:
auto initializationCommand = SimpleCommandType::New();
initializationCommand->SetCallbackFunction(this, &QmitkCommonToolView::After2DMeasurement);
data.m_EndPlacementObserverTag =
planarFigure->AddObserver(mitk::EndPlacementPlanarFigureEvent(), initializationCommand);
在After2DMeasurement()函数中实现根据按钮名创建新的PlanarFigure类型的数据节点,由于公司的项目修改了UI,使用了一个下拉框供用户选择测量工具,代码不具参考性,只将创建新node的函数粘贴如下:
void QmitkCommonToolView::CreateNewFigureDataNodeByType(QString type)
{
if (type.isEmpty())
{
return;
}
auto newNode = mitk::DataNode::New();
if (type == tr("Select Tools"))
{
newNode = nullptr;
return;
}
else if (type == tr("Line"))
{
newNode->SetName(QString("Line%1").arg(++m_LineCounter).toStdString());
newNode->SetData(mitk::PlanarLine::New());
}
else if (type == tr("Angle"))
{
newNode->SetName(QString("Angle%1").arg(++m_AngleCounter).toStdString());
newNode->SetData(mitk::PlanarAngle::New());
}
else if (type == tr("Rectangle"))
{
newNode->SetName(QString("Rectangle%1").arg(++m_RectangleCounter).toStdString());
auto rect = mitk::PlanarRectangle::New();
newNode->SetData(rect);
}
else if (type == tr("Polygon"))
{
auto Polygon = mitk::PlanarPolygon::New();
Polygon->ClosedOn();
newNode->SetName(QString("Polygon%1").arg(++m_PolygonCounter).toStdString());
newNode->SetData(Polygon);
newNode->SetBoolProperty("planarfigure.isextendable", true);
}
else if (type == tr("Ellipse"))
{
newNode->SetName(QString("Ellipse%1").arg(++m_EllipseCounter).toStdString());
newNode->SetData(mitk::PlanarEllipse::New());
}
else
{
MITK_ERROR << "Input param is an invlid type name: " << type;
newNode = nullptr;
return;
}
//为新建的dataNode设置交互。
auto interactor = mitk::PlanarFigureInteractor::New();
auto planarFigureModule = us::ModuleRegistry::GetModule("MitkPlanarFigure");
interactor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule);
interactor->SetEventConfig("PlanarFigureConfig.xml", planarFigureModule);
interactor->SetDataNode(newNode);
newNode->SetSelected(true);
this->GetDataStorage()->Add(newNode);
}
这时,已经实现了连续测量的效果,需要注意的是,当用户切换工具时或者结束测量时,需要清理未完成测量的空DataNode.