Medical Imaging Interaction Toolkit  2018.4.99-3e3f1a6e
Medical Imaging Interaction Toolkit
QmitkBoundingObjectWidget.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 #include <mitkCone.h>
16 #include <mitkCuboid.h>
17 #include <mitkCylinder.h>
18 #include <mitkEllipsoid.h>
19 #include <mitkLine.h>
21 #include <mitkPlaneGeometry.h>
22 
23 #include <QBoxLayout>
24 #include <QCheckBox>
25 #include <QInputDialog>
26 #include <QPushButton>
27 #include <QStringList>
28 
30 // micro services
31 #include <usGetModuleContext.h>
32 #include <usModuleRegistry.h>
33 
34 QmitkBoundingObjectWidget::QmitkBoundingObjectWidget(QWidget *parent, Qt::WindowFlags f)
35  : QWidget(parent, f),
36  m_DataStorage(nullptr),
37  m_lastSelectedItem(nullptr),
38  m_lastAffineObserver(0),
39  m_ItemNodeMap(),
40  m_BoundingObjectCounter(1)
41 {
42  QBoxLayout *mainLayout = new QVBoxLayout(this);
43 
44  QHBoxLayout *buttonLayout = new QHBoxLayout();
45 
46  QStringList boList;
47  boList << tr("add") << tr("cube") << tr("cone") << tr("ellipse") << tr("cylinder");
48  m_addComboBox = new QComboBox();
49  m_addComboBox->addItems(boList);
50  m_addComboBox->setItemIcon(1, QIcon(":/QmitkWidgetsExt/btnCube.xpm"));
51  m_addComboBox->setItemIcon(2, QIcon(":/QmitkWidgetsExt/btnPyramid.xpm"));
52  m_addComboBox->setItemIcon(3, QIcon(":/QmitkWidgetsExt/btnEllipsoid.xpm"));
53  m_addComboBox->setItemIcon(4, QIcon(":/QmitkWidgetsExt/btnCylinder.xpm"));
54 
55  buttonLayout->addWidget(m_addComboBox);
56 
57  m_DelButton = new QPushButton("del");
58  buttonLayout->addWidget(m_DelButton);
59 
60  m_SaveButton = new QPushButton("save");
61  buttonLayout->addWidget(m_SaveButton);
62  m_SaveButton->setEnabled(false);
63 
64  m_LoadButton = new QPushButton("load");
65  buttonLayout->addWidget(m_LoadButton);
66  m_LoadButton->setEnabled(false);
67 
68  m_TreeWidget = new QTreeWidget(this);
69  m_TreeWidget->setColumnCount(3);
70  QStringList sList;
71  sList << tr("name") << tr("inverted") << tr("visible");
72  m_TreeWidget->setHeaderLabels(sList);
73  m_TreeWidget->setColumnWidth(0, 250);
74  m_TreeWidget->setColumnWidth(1, 50);
75  m_TreeWidget->setColumnWidth(2, 50);
76  m_TreeWidget->setAutoScroll(true);
77  m_TreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
78 
79  mainLayout->addWidget(m_TreeWidget);
80  mainLayout->addLayout(buttonLayout);
81 
82  connect(m_addComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(CreateBoundingObject(int)));
83  connect(m_TreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(SelectionChanged()));
84  connect(m_DelButton, SIGNAL(clicked()), this, SLOT(OnDelButtonClicked()));
85 
86  connect(m_TreeWidget,
87  SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
88  this,
89  SLOT(OnItemDoubleClicked(QTreeWidgetItem *, int)));
90  connect(
91  m_TreeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnItemDataChanged(QTreeWidgetItem *, int)));
92 }
93 
95 {
96 }
97 
99 {
100  ItemNodeMapType::iterator it = m_ItemNodeMap.begin();
101  while (it != m_ItemNodeMap.end())
102  {
103  mitk::DataNode *node = it->second;
104  QTreeWidgetItem *item = it->first;
105 
106  if (flag)
107  node->SetVisibility(item->checkState(2));
108  else
109  node->SetVisibility(flag);
110  ++it;
111  }
112 
113  QWidget::setEnabled(flag);
115 }
116 
118 {
119  QList<QTreeWidgetItem *> selectedItems = m_TreeWidget->selectedItems();
120  if (selectedItems.size() < 1)
121  return;
122 
123  QTreeWidgetItem *selectedItem = selectedItems.first();
124 
125  if (selectedItem == m_lastSelectedItem)
126  return;
127 
128  if (m_lastSelectedItem != nullptr)
129  {
130  m_TreeWidget->closePersistentEditor(m_lastSelectedItem, 0);
131 
132  ItemNodeMapType::iterator it = m_ItemNodeMap.find(m_lastSelectedItem);
133 
134  if (it != m_ItemNodeMap.end())
135  {
136  mitk::DataNode *last_node = it->second;
137 
138  // remove observer
139  last_node->RemoveObserver(m_lastAffineObserver);
140  last_node->SetDataInteractor(nullptr);
141  }
142  }
143 
144  ItemNodeMapType::iterator it = m_ItemNodeMap.find(selectedItem);
145  if (it == m_ItemNodeMap.end())
146  return;
147 
148  mitk::DataNode *new_node = it->second;
149 
151  affineDataInteractor->LoadStateMachine("AffineInteraction3D.xml", us::ModuleRegistry::GetModule("MitkDataTypesExt"));
152  affineDataInteractor->SetEventConfig("AffineConfig.xml", us::ModuleRegistry::GetModule("MitkDataTypesExt"));
153  affineDataInteractor->SetDataNode(new_node);
154  new_node->SetBoolProperty("pickable", true);
155 
156  // create observer for node
157  itk::ReceptorMemberCommand<QmitkBoundingObjectWidget>::Pointer command =
158  itk::ReceptorMemberCommand<QmitkBoundingObjectWidget>::New();
159  command->SetCallbackFunction(this, &QmitkBoundingObjectWidget::OnBoundingObjectModified);
160  m_lastAffineObserver = new_node->AddObserver(mitk::AffineInteractionEvent(), command);
161 
162  m_lastSelectedItem = selectedItem;
163 }
164 
166 {
167  mitk::BoundingObject *boundingObject;
168 
169  boundingObject = dynamic_cast<mitk::BoundingObject *>(node->GetData());
170 
171  std::string name;
172  node->GetStringProperty("name", name);
173 
174  if (boundingObject)
175  {
176  QTreeWidgetItem *item = new QTreeWidgetItem();
177  item->setData(0, Qt::EditRole, QString::fromLocal8Bit(name.c_str()));
178  item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
179 
180  // checkbox for positive flag
181  item->setData(1, Qt::CheckStateRole, tr(""));
182  item->setCheckState(1, Qt::Unchecked);
183 
184  // checkbox for visibleflag
185  item->setData(2, Qt::CheckStateRole, tr(""));
186  item->setCheckState(2, Qt::Checked);
187 
188  m_TreeWidget->addTopLevelItem(item);
189 
190  m_ItemNodeMap.insert(std::make_pair(item, node));
191 
192  m_TreeWidget->selectAll();
193  QList<QTreeWidgetItem *> items = m_TreeWidget->selectedItems();
194  for (int i = 0; i < items.size(); i++)
195  {
196  m_TreeWidget->setItemSelected(items.at(i), false);
197  }
198 
199  m_TreeWidget->setItemSelected(item, true);
200  }
201  else
202  MITK_ERROR << name << " is not a bounding object or does not exist in data storage" << endl;
203 }
204 
205 void QmitkBoundingObjectWidget::OnItemDoubleClicked(QTreeWidgetItem *item, int col)
206 {
207  if (col == 0)
208  {
209  m_TreeWidget->openPersistentEditor(item, col);
210  }
211 }
212 
213 void QmitkBoundingObjectWidget::OnItemDataChanged(QTreeWidgetItem *item, int col)
214 {
215  if (m_ItemNodeMap.size() < 1)
216  return;
217 
218  ItemNodeMapType::iterator it = m_ItemNodeMap.find(item);
219  if (it == m_ItemNodeMap.end())
220  return;
221 
222  mitk::DataNode *node = it->second;
223 
224  // name
225  if (col == 0)
226  {
227  m_TreeWidget->closePersistentEditor(item, col);
228  node->SetName(item->text(0).toLocal8Bit().data());
229  }
230  // positive
231  else if (col == 1)
232  {
233  mitk::BoundingObject *boundingObject = dynamic_cast<mitk::BoundingObject *>(node->GetData());
234  if (boundingObject)
235  boundingObject->SetPositive(!(item->checkState(1)));
236  emit BoundingObjectsChanged();
237  }
238  // visible
239  else if (col == 2)
240  {
241  node->SetVisibility(item->checkState(2));
242  }
243 
245 }
246 
248 {
249  // selection mode is set to single selection, so there should not be more than one selected item
250  QList<QTreeWidgetItem *> selectedItems = m_TreeWidget->selectedItems();
251  QTreeWidgetItem *item = selectedItems.first();
252  QString str = item->text(0);
253 
254  ItemNodeMapType::iterator it = m_ItemNodeMap.find(item);
255 
256  if (it == m_ItemNodeMap.end())
257  return;
258 
259  mitk::DataNode *node = it->second;
260  mitk::BoundingObject *boundingObject;
261 
262  if (node)
263  {
264  boundingObject = dynamic_cast<mitk::BoundingObject *>(node->GetData());
265  if (boundingObject)
266  {
267  // delete item;
268  m_TreeWidget->takeTopLevelItem(m_TreeWidget->indexOfTopLevelItem(item));
269  m_ItemNodeMap.erase(m_ItemNodeMap.find(item));
270  m_DataStorage->Remove(node);
271  }
272  }
273 }
274 
276 {
277  ItemNodeMapType::iterator it = m_ItemNodeMap.begin();
278 
279  while (it != m_ItemNodeMap.end())
280  {
281  m_TreeWidget->takeTopLevelItem(m_TreeWidget->indexOfTopLevelItem(it->first));
282  m_ItemNodeMap.erase(m_ItemNodeMap.find(it->first));
283 
284  ++it;
285  }
286 
288 }
289 
291 {
292  mitk::BoundingObject *boundingObject;
294 
295  if (node)
296  {
297  boundingObject = dynamic_cast<mitk::BoundingObject *>(node->GetData());
298  if (boundingObject)
299  return boundingObject;
300  }
301  return nullptr;
302 }
303 
305 {
306  m_DataStorage = dataStorage;
307 }
308 
310 {
311  return m_DataStorage;
312 }
313 
315 {
316  RemoveItem();
317 }
318 
320 {
321  // get cross position
322  mitk::Point3D pos;
325 
326  // hopefully we have the renderwindows in the "normal" order
327  const mitk::PlaneGeometry *plane1 =
328  mitk::BaseRenderer::GetInstance(windows.at(0))->GetSliceNavigationController()->GetCurrentPlaneGeometry();
329  const mitk::PlaneGeometry *plane2 =
330  mitk::BaseRenderer::GetInstance(windows.at(1))->GetSliceNavigationController()->GetCurrentPlaneGeometry();
331  const mitk::PlaneGeometry *plane3 =
332  mitk::BaseRenderer::GetInstance(windows.at(2))->GetSliceNavigationController()->GetCurrentPlaneGeometry();
333 
335  if ((plane1 != nullptr) && (plane2 != nullptr) && (plane1->IntersectionLine(plane2, line)))
336  {
337  if (!((plane3 != nullptr) && (plane3->IntersectionPoint(line, pos))))
338  {
339  return;
340  }
341  }
342 
343  if (type != 0)
344  {
345  mitk::BoundingObject::Pointer boundingObject;
346  QString name;
347  name.setNum(m_BoundingObjectCounter);
348 
349  switch (type - 1)
350  {
351  case CUBOID:
352  boundingObject = mitk::Cuboid::New();
353  name.prepend("Cube_");
354  break;
355  case CONE:
356  boundingObject = mitk::Cone::New();
357  name.prepend("Cone_");
358  break;
359  case ELLIPSOID:
360  boundingObject = mitk::Ellipsoid::New();
361  name.prepend("Ellipse_");
362  break;
363  case CYLINDER:
364  boundingObject = mitk::Cylinder::New();
365  name.prepend("Cylinder_");
366  break;
367  default:
368  return;
369  break;
370  }
372  m_addComboBox->setCurrentIndex(0);
373 
374  // set initial size
375  mitk::Vector3D size;
376  size.Fill(10);
377  boundingObject->GetGeometry()->SetSpacing(size);
378 
379  boundingObject->GetGeometry()->Translate(pos.GetVectorFromOrigin());
380  boundingObject->GetTimeGeometry()->Update();
381 
382  // create node
384  node->SetData(boundingObject);
385  node->SetProperty("name", mitk::StringProperty::New(name.toLocal8Bit().data()));
386  node->SetProperty("color", mitk::ColorProperty::New(0.0, 0.0, 1.0));
387  node->SetProperty("opacity", mitk::FloatProperty::New(0.7));
388  node->SetProperty("bounding object", mitk::BoolProperty::New(true));
389  node->SetProperty("helper object", mitk::BoolProperty::New(true));
390 
391  m_DataStorage->Add(node);
392 
394 
395  emit BoundingObjectsChanged();
396 
397  AddItem(node);
398  }
399 }
400 
402 {
403  mitk::DataNode::Pointer boundingObjectGroupNode = mitk::DataNode::New();
405  boundingObjectGroup->SetCSGMode(mitk::BoundingObjectGroup::Union);
406 
409  mitk::DataStorage::SetOfObjects::ConstPointer allBO = m_DataStorage->GetSubset(prop);
410 
411  for (mitk::DataStorage::SetOfObjects::const_iterator it = allBO->begin(); it != allBO->end(); ++it)
412  {
413  mitk::DataNode::Pointer node = *it;
414  mitk::BoundingObject::Pointer boundingObject = dynamic_cast<mitk::BoundingObject *>(node->GetData());
415  if (boundingObject)
416  boundingObjectGroup->AddBoundingObject(boundingObject);
417  }
418 
419  boundingObjectGroupNode->SetData(boundingObjectGroup);
420 
421  if (boundingObjectGroup->GetCount() > 0)
422  return boundingObjectGroupNode;
423 
424  return nullptr;
425 }
426 
428 {
429  QList<QTreeWidgetItem *> selectedItems = m_TreeWidget->selectedItems();
430  if (selectedItems.size() < 1)
431  return nullptr;
432 
433  QTreeWidgetItem *item = selectedItems.first();
434  mitk::DataNode *node = m_ItemNodeMap.find(item)->second;
435 
436  return node;
437 }
438 
440 {
441  emit BoundingObjectsChanged();
442 }
void AddItem(mitk::DataNode *node)
Descibes a line.
Definition: mitkLine.h:28
static char * line
Definition: svm.cpp:2870
Data management class that handles &#39;was created by&#39; relations.
static Pointer New()
void SetVisibility(bool visible, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="visible")
Convenience method for setting visibility properties (instances of BoolProperty)
static BaseRenderer * GetInstance(vtkRenderWindow *renWin)
bool GetStringProperty(const char *propertyKey, std::string &string, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for string properties (instances of StringProperty)
#define MITK_ERROR
Definition: mitkLogMacros.h:20
static Pointer New()
static Module * GetModule(long id)
mitk::DataNode::Pointer GetSelectedBoundingObjectNode()
bool IntersectionPoint(const Line3D &line, Point3D &intersectionPoint) const
Calculate intersection point between the plane and a line.
QmitkBoundingObjectWidget(QWidget *parent=nullptr, Qt::WindowFlags f=nullptr)
virtual void Add(DataNode *node, const DataStorage::SetOfObjects *parents=nullptr)=0
Adds a DataNode containing a data object to its internal storage.
void OnItemDoubleClicked(QTreeWidgetItem *item, int col)
static Pointer New()
static Pointer New()
superclass of all bounding objects (cylinder, cuboid,...)
bool IntersectionLine(const PlaneGeometry *plane, Line3D &crossline) const
Calculate the intersecting line of two planes.
virtual void SetPositive(bool _arg)
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
mitk::DataStorage::Pointer m_DataStorage
static Pointer New()
static Pointer New()
static RenderingManager * GetInstance()
mitk::BoundingObject::Pointer GetSelectedBoundingObject()
SetOfObjects::ConstPointer GetSubset(const NodePredicateBase *condition) const
returns a set of data objects that meet the given condition(s)
virtual void SetName(const char *name)
Extra convenience access method to set the name of an object.
Definition: mitkDataNode.h:404
std::vector< vtkRenderWindow * > RenderWindowVector
void OnBoundingObjectModified(const itk::EventObject &e)
static Pointer New(const char *_arg)
static Pointer New()
static Pointer New()
void SetBoolProperty(const char *propertyKey, bool boolValue, const mitk::BaseRenderer *renderer=nullptr)
Convenience method for setting boolean properties (instances of BoolProperty)
virtual void Remove(const DataNode *node)=0
Removes node from the DataStorage.
void OnItemDataChanged(QTreeWidgetItem *item, int col)
void SetDataStorage(mitk::DataStorage *dataStorage)
static Pointer New()
mitk::DataNode::Pointer GetAllBoundingObjects()
Describes a two-dimensional, rectangular plane.
virtual void SetDataInteractor(const DataInteractor::Pointer interactor)
Set the Interactor.
static Pointer New()
const RenderWindowVector & GetAllRegisteredRenderWindows()
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57