CustusX  16.5.0-rc9
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxProbeConfigWidget.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include <cxProbeConfigWidget.h>
34 #include <QGroupBox>
35 #include <QInputDialog>
36 #include <QMessageBox>
37 #include <QCheckBox>
39 #include "cxDoubleWidgets.h"
40 #include "cxToolProperty.h"
41 #include "cxVector3DWidget.h"
42 #include "cxDoubleSpanSlider.h"
43 #include "cxHelperWidgets.h"
44 #include "cxTypeConversions.h"
45 #include "cxDoublePairProperty.h"
46 #include "cxVisServices.h"
47 
48 namespace cx
49 {
50 
51 ProbeConfigWidget::ProbeConfigWidget(VisServicesPtr services, QWidget* parent) : BaseWidget(parent, "ProbeConfigWidget", "Probe Configuration")
52 {
53  mServices = services;
54  mUpdating = false;
55  this->setToolTip("Edit ultrasound probe configuration");
56 
57  QVBoxLayout* topLayout = new QVBoxLayout(this);
58  TrackingServicePtr ts = mServices->tracking();
59  mActiveProbeConfig = StringPropertyActiveProbeConfiguration::New(ts);
60  connect(mActiveProbeConfig.get(), &StringPropertyActiveProbeConfiguration::changed, this, &ProbeConfigWidget::activeProbeConfigurationChangedSlot);
61  mActiveProbeConfigWidget = new LabeledComboBoxWidget(this, mActiveProbeConfig);
62  topLayout->addWidget(mActiveProbeConfigWidget);
63 
64  mOrigin = Vector3DProperty::initialize("Origin",
65  "Origin",
66  "Origin of tool space in the probe image.\nUnits in pixels.",
67  Vector3D(0,0,0),
68  DoubleRange(-1000,1000,1),
69  1,
70  QDomNode());
71  connect(mOrigin.get(), SIGNAL(changed()), this, SLOT(guiOriginSettingsChanged()));
72 
73  // define origin group
74  Vector3DWidget* mOriginWidget = Vector3DWidget::createSmallHorizontal(this, mOrigin);
75  mOriginWidget->showDim(2, false);
76 
77  // define cropping group
78  QGroupBox* cropGroupBox = new QGroupBox("Crop Box", this);
79  cropGroupBox->setToolTip("Define cropping box for the probe image.\nUnits in pixels.");
80  QVBoxLayout* cropLayout = new QVBoxLayout(cropGroupBox);
81  topLayout->addWidget(cropGroupBox);
82 
83  QStringList bbCaptions = QStringList() << "X (pixels)" << "Y (pixels)";
84  mBBWidget = new BoundingBoxWidget(this, bbCaptions);
85  cropLayout->addWidget(mBBWidget);
86  connect(mBBWidget, &BoundingBoxWidget::changed, this, &ProbeConfigWidget::guiImageSettingsChanged);
87 
88  // create sector group
89  QGroupBox* sectorGroupBox = new QGroupBox("Sector");
90  sectorGroupBox->setToolTip("Define probe sector parameters.\nUnits in pixels and degrees.");
91  QVBoxLayout* sectorLayout = new QVBoxLayout(sectorGroupBox);
92  topLayout->addWidget(sectorGroupBox);
93 
94  sectorLayout->addWidget(mOriginWidget);
95  DoublePairPropertyPtr depthProperty = DoublePairProperty::initialize("Depth", "Depth", "Define probe depth.\nUnits in pixels.", DoubleRange(0, 1000, 1), 1);
96  mDepthWidget = new SliderRangeGroupWidget(this, depthProperty);
97  connect(mDepthWidget, SIGNAL(valueChanged(double, double)), this, SLOT(guiProbeSectorChanged()));
98  sectorLayout->addWidget(mDepthWidget);
99 
100  mWidth = DoubleProperty::initialize("width", "Width", "Width of probe sector", 0,
101  DoubleRange(0, M_PI, M_PI/180), 0);
102  mWidth->setInternal2Display(180.0/M_PI);
103  connect(mWidth.get(), SIGNAL(changed()), this, SLOT(guiProbeSectorChanged()));
104  sectorLayout->addWidget(new SpinBoxAndSliderGroupWidget(this, mWidth, 0, 0));
105 
106  // create buttons bar
107  QHBoxLayout* buttonsLayout = new QHBoxLayout;
108  topLayout->addLayout(buttonsLayout);
109 
110  mSyncBoxToSector = new QCheckBox("Sync Box to Sector", this);
111  mSyncBoxToSector->setChecked(true);
112  mSyncBoxToSector->setToolTip(""
113  "Synchronize Crop Box to Probe Sector,\n"
114  "changes in the sector will reset the crop box.");
115  connect(mSyncBoxToSector, SIGNAL(toggled(bool)), this, SLOT(syncBoxToSectorChanged()));
116  buttonsLayout->addWidget(mSyncBoxToSector);
117 
118  buttonsLayout->addStretch();
119  this->createAction(this,
120  QIcon(":/icons/preset_remove.png"),
121  "Delete the current probe config", "",
122  SLOT(deletePresetSlot()),
123  buttonsLayout);
124 
125  this->createAction(this,
126  QIcon(":/icons/preset_save.png"),
127  "Add the current setting as a probe config", "",
128  SLOT(savePresetSlot()),
129  buttonsLayout);
130 
131  topLayout->addStretch();
132 }
133 
135 {
136 }
137 
138 void ProbeConfigWidget::syncBoxToSectorChanged()
139 {
140 
141 }
142 
143 void ProbeConfigWidget::savePresetSlot()
144 {
145  if (!mActiveProbeConfig->getTool())
146  return;
147  ProbePtr probe = mActiveProbeConfig->getTool()->getProbe();
148 // ProbeImplPtr probe = boost::dynamic_pointer_cast<ProbeImpl>(mActiveProbeConfig->getTool()->getProbe());
149  if (!probe)
150  return;
151 
152  // use the previously selected config as a suggestion for new config name.
153  QString oldname = probe->getConfigName(probe->getConfigId());
154  if (oldname.isEmpty())
155  oldname = mLastKnownProbeConfigName;
156 
157  QString newName = QString("%1 (2)").arg(oldname);
158 
159  bool ok;
160  newName = QInputDialog::getText(this, "Save Config",
161  "Config Name", QLineEdit::Normal,
162  newName, &ok);
163  if (!ok || newName.isEmpty())
164  return;
165 
166  QStringList existingConfigs = probe->getConfigIdList();
167  QString newUid;
168 
169  // is name exists: overwrite.
170  for (int i=0; i<existingConfigs.size(); ++i)
171  {
172  if (newName==probe->getConfigName(existingConfigs[i]))
173  {
174  newUid = existingConfigs[i];
175  }
176  }
177 
178  if (newUid.isEmpty())
179  {
180  newUid = newName;
181 // Width: Max, Depth: 45 mm
182  newUid.remove(QRegExp("(:|\\s|\\(|\\)|,)")); // remove fancy characters from uid
183  QString root = newUid;
184  int i=2;
185  while (existingConfigs.contains(newUid))
186  {
187  newUid = QString("%1_%2").arg(root).arg(i++);
188  }
189  }
190 
191  probe->saveCurrentConfig(newUid, newName);
192 }
193 
194 void ProbeConfigWidget::deletePresetSlot()
195 {
196  ProbePtr probe = mActiveProbeConfig->getTool()->getProbe();
197 // ProbeImplPtr probe = boost::dynamic_pointer_cast<ProbeImpl>(mActiveProbeConfig->getTool()->getProbe());
198  if (!probe)
199  return;
200 
201  QString message = QString("Do you really want to delete configuration\n%1?").arg(probe->getConfigName(probe->getConfigId()));
202  if (QMessageBox::warning(this,
203  "Delete Config",
204  message,
205  QMessageBox::No | QMessageBox::Yes) != QMessageBox::Yes)
206  {
207  return;
208  }
209 
210  probe->removeCurrentConfig();
211 }
212 
213 
214 void ProbeConfigWidget::activeProbeConfigurationChangedSlot()
215 {
216  cx::ProbePtr probe = mActiveProbeConfig->getTool()->getProbe();
217  if (!probe)
218  return;
219  ProbeDefinition data = probe->getProbeDefinition();
220  mUpdating= true;
221 
222  DoubleBoundingBox3D range(0, data.getSize().width(), 0, data.getSize().height());
223  mBBWidget->setValue(data.getClipRect_p(), range);
224 
225  mOrigin->setValue(data.getOrigin_p());
226 
227  double sx = data.getSpacing()[0]; // mm/pix
228  double sy = data.getSpacing()[1];
229 
230  mDepthWidget->setValue(data.getDepthStart()/sy, data.getDepthEnd()/sy);
231  mDepthWidget->setRange(DoubleRange(0, range.range()[1]*1.5, 1));
232 
233  mWidth->setValue(data.getWidth());
234 
235  if (data.getType()== ProbeDefinition::tLINEAR)
236  {
237  mWidth->setValueRange(DoubleRange(0, range.range()[0]*1.5*sx, 1.0*sx));
238  mWidth->setInternal2Display(1.0/sx);
239  }
240  if (data.getType()== ProbeDefinition::tSECTOR)
241  {
242  mWidth->setValueRange(DoubleRange(0, M_PI, M_PI/180));
243  mWidth->setInternal2Display(180.0/M_PI);
244  }
245 
246  if (!probe->getConfigId().isEmpty())
247  {
248  mLastKnownProbeConfigName = probe->getConfigName(probe->getConfigId());
249  }
250  mUpdating= false;
251 }
252 
253 
254 void ProbeConfigWidget::guiProbeSectorChanged()
255 {
256  if (mUpdating)
257  return;
258  if(!mActiveProbeConfig->getTool())
259  return;
260  // need a cx probe here, in order to set data.
261  cx::ProbePtr probe = mActiveProbeConfig->getTool()->getProbe();
262  if (!probe)
263  return;
264  ProbeDefinition data = probe->getProbeDefinition();
265 
266 // double sx = data.getSpacing()[0]; // mm/pix
267  double sy = data.getSpacing()[1];
268 
269  data.setSector(mDepthWidget->getValue().first*sy, mDepthWidget->getValue().second*sy, mWidth->getValue());
270 
271  if (mSyncBoxToSector->isChecked())
272  data.updateClipRectFromSector();
273 
274  probe->setProbeDefinition(data);
275 }
276 
277 void ProbeConfigWidget::guiImageSettingsChanged()
278 {
279  if (mUpdating)
280  return;
281  // need a cx probe here, in order to set data.
282  if (!mActiveProbeConfig->getTool())
283  return;
284  cx::ProbePtr probe = mActiveProbeConfig->getTool()->getProbe();
285  if (!probe)
286  return;
287  ProbeDefinition data = probe->getProbeDefinition();
288 
289  data.setClipRect_p(mBBWidget->getValue());
290 
291  probe->setProbeDefinition(data);
292 }
293 
294 void ProbeConfigWidget::guiOriginSettingsChanged()
295 {
296  if (mUpdating)
297  return;
298  // need a cx probe here, in order to set data.
299  if (!mActiveProbeConfig->getTool())
300  return;
301  cx::ProbePtr probe = mActiveProbeConfig->getTool()->getProbe();
302  if (!probe)
303  return;
304  ProbeDefinition data = probe->getProbeDefinition();
305 
306  // if sync: move clip rect accordingly
307  if (mSyncBoxToSector->isChecked())
308  {
309  // shift
310  Vector3D shift = mOrigin->getValue() - data.getOrigin_p();
311  data.setClipRect_p(transform(createTransformTranslate(shift), data.getClipRect_p()));
312  }
313 
314  data.setOrigin_p(mOrigin->getValue());
315 
316  probe->setProbeDefinition(data);
317 }
318 
319 
320 
321 }
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
bool setValue(double lower, double upper)
Widget for displaying a Vector3D.
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:62
boost::shared_ptr< class TrackingService > TrackingServicePtr
US beam is emitted straight forward.
Utility class for describing a bounded numeric range.
Definition: cxDoubleRange.h:53
void setRange(const DoubleRange &range)
Widget displays/edits a BoundingBox3D.
static StringPropertyActiveProbeConfigurationPtr New(TrackingServicePtr trackingService)
Composite widget for string selection.
QAction * createAction(QObject *parent, QIcon iconName, QString text, QString tip, T slot, QLayout *layout=NULL, QToolButton *button=new QToolButton())
Definition: cxBaseWidget.h:149
boost::shared_ptr< Probe > ProbePtr
Definition: cxProbe.h:93
Composite widget for scalar data manipulation.
std::pair< double, double > getValue() const
US beam is emitted radially in a flat cone.
static Vector3DWidget * createSmallHorizontal(QWidget *parent, Vector3DPropertyBasePtr data)
static Vector3DPropertyPtr initialize(const QString &uid, QString name, QString help, Vector3D value, DoubleRange range, int decimals, QDomNode root=QDomNode())
DoubleBoundingBox3D getValue() const
Transform3D createTransformTranslate(const Vector3D &translation)
void changed()
emit when the underlying data value is changed: The user interface will be updated.
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
Interface for QWidget which handles widgets uniformly for the system.
Definition: cxBaseWidget.h:108
boost::shared_ptr< class DoublePairProperty > DoublePairPropertyPtr
static DoublePropertyPtr initialize(const QString &uid, QString name, QString help, double value, DoubleRange range, int decimals, QDomNode root=QDomNode())
void setValue(const DoubleBoundingBox3D &value, const DoubleBoundingBox3D &range)
static DoublePairPropertyPtr initialize(const QString &uid, QString name, QString help, DoubleRange range, int decimals, QDomNode root=QDomNode())
#define M_PI
ProbeConfigWidget(VisServicesPtr services, QWidget *parent=NULL)