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