Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.