CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxShapeSensorWidget.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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 #include "cxShapeSensorWidget.h"
13 #include <QLabel>
14 #include <QVBoxLayout>
15 #include <QPushButton>
16 #include <QApplication>
17 #include <string>
18 #include <vtkRenderer.h>
19 #include <vtkPolyData.h>
20 #include "cxProfile.h"
21 #include "cxXmlOptionItem.h"
22 #include "cxDoubleWidgets.h"
23 #include "cxVisServices.h"
24 #include "cxHelperWidgets.h"
25 #include "cxStringProperty.h"
26 #include "cxDoubleProperty.h"
27 #include "cxLogger.h"
28 #include "cxViewService.h"
29 #include "cxActiveToolWidget.h"
30 #include "cxTrackingService.h"
31 
32 namespace cx
33 {
34 
36  BaseWidget(parent, "shape_sensor_widget", "Shape Sensor"),
37  mServices(services),
38  mVerticalLayout(new QVBoxLayout(this)),
39  mSocketConnection(new SocketConnection(this)),
40  mReadFbgsMessage(new ReadFbgsMessage(services))
41 {
42  SocketConnection::ConnectionInfo info = mSocketConnection->getConnectionInfo();
43  info.port = 5001;
44  mSocketConnection->setConnectionInfo(info);
45 
46 
47  XmlOptionFile mOptions;
48  mOptions = profile()->getXmlSettings().descend("shape");
49  QDomElement element = mOptions.getElement("shape");
50 
51  mIpAddress = this->getIPAddress(element);
52  mIpPort = this->getIPPort(element);
53  mShapePointLock = this->getShapePointLock(element);
54 
55  this->setWhatsThis(this->defaultWhatsThis());
56 
57  //Is tool selector needed?
58  ActiveToolWidget* activeToolWidget = new ActiveToolWidget(services->tracking(), this);
59  mSelector = activeToolWidget->getSelector();
60  connect(mSelector.get(), &StringPropertyBase::changed, this, &ShapeSensorWidget::toolChangedSlot);
61  //connect(services->tracking().get(), &TrackingService::activeToolChanged,this, &ShapeSensorWidget::activeToolChangedSlot);
62 
63  //Connect to tool
64  mTool = mServices->tracking()->getActiveTool();
65  connect(mTool.get(), &Tool::toolTransformAndTimestamp, this, &ShapeSensorWidget::receiveTransforms);
66 
67  mConnectButton = new QPushButton("Connect", this);
68  mShowShapeButton = new QPushButton("Hide shape", this);
69  mSaveShapeButton = new QPushButton("Save mesh snapshot to file", this);
70  mTestShapeButton = new QPushButton("Create test shape", this);
71 
72  connect(mConnectButton, &QPushButton::clicked, this, &ShapeSensorWidget::connectClickedSlot);
73  connect(mShowShapeButton, &QPushButton::clicked, this, &ShapeSensorWidget::showClickedSlot);
74  connect(mSaveShapeButton, &QPushButton::clicked, this, &ShapeSensorWidget::saveShapeClickedSlot);
75  connect(mTestShapeButton, &QPushButton::clicked, this, &ShapeSensorWidget::testShapeClickedSlot);
76  connect(mSocketConnection.get(), &SocketConnection::stateChanged, this, &ShapeSensorWidget::connectStateChangedSlot);
77  connect(mSocketConnection.get(), &SocketConnection::dataAvailable, this, &ShapeSensorWidget::dataAvailableSlot);
78  connect(mShapePointLock.get(), &Property::changed, this, &ShapeSensorWidget::shapePointLockChangedSlot);
79 
80  QWidget* addressWidget = sscCreateDataWidget(this, mIpAddress);
81  QWidget* portWidget = sscCreateDataWidget(this, mIpPort);
82  QWidget* shapePointLockWidget = sscCreateDataWidget(this, mShapePointLock);
83 
84  mVerticalLayout->addWidget(addressWidget);
85  mVerticalLayout->addWidget(portWidget);
86 
87  mVerticalLayout->addWidget(mConnectButton);
88  mVerticalLayout->addWidget(this->createHorizontalLine());
89  mVerticalLayout->addWidget(mShowShapeButton);
90  mVerticalLayout->addWidget(shapePointLockWidget);
91  mVerticalLayout->addWidget(activeToolWidget);
92  mVerticalLayout->addWidget(this->createHorizontalLine());
93  mVerticalLayout->addStretch(1);
94  mVerticalLayout->addWidget(mSaveShapeButton);
95  mVerticalLayout->addWidget(mTestShapeButton);
96  mVerticalLayout->addStretch();
97 
98  this->toolChangedSlot();
99 }
100 
102 {
103 }
104 
105 QString ShapeSensorWidget::defaultWhatsThis() const
106 {
107  return "<html>"
108  "<h3>Shape Sensor plugin.</h3>"
109  "<p>Widget for connecting to Fiber Bragg Shape Sensor/p>"
110  "</html>";
111 }
112 
113 StringPropertyBasePtr ShapeSensorWidget::getIPAddress(QDomElement root)
114 {
115  StringPropertyPtr retval;
116  QString defaultValue = "127.0.0.1";
117  retval = StringProperty::initialize("ip_address", "Address", "TCP/IP Address",
118  defaultValue, root);
119  retval->setGroup("Connection");
120  return retval;
121 }
122 
123 DoublePropertyBasePtr ShapeSensorWidget::getIPPort(QDomElement root)
124 {
125  DoublePropertyPtr retval;
126  retval = DoubleProperty::initialize("ip_port", "Port", "TCP/IP Port (default 5001)",
127  5001, DoubleRange(1024, 49151, 1), 0, root);
128  retval->setGuiRepresentation(DoublePropertyBase::grSPINBOX);
129  retval->setAdvanced(true);
130  retval->setGroup("Connection");
131  return retval;
132 }
133 
134 DoublePropertyPtr ShapeSensorWidget::getShapePointLock(QDomElement root)
135 {
136  DoublePropertyPtr retval;
137  retval = DoubleProperty::initialize("shape_point_lock", "Lock shape point number to tool",
138  "Lock a specific point in the shape to the position of the active tool ",
139  0, DoubleRange(0, 1000, 1), 0, root);
140  retval->setGuiRepresentation(DoublePropertyBase::grSPINBOX);
141  retval->setAdvanced(true);
142  retval->setGroup("Connection");
143  return retval;
144 }
145 
146 void ShapeSensorWidget::shapePointLockChangedSlot()
147 {
148  mReadFbgsMessage->setShapePointLock(mShapePointLock->getValue());
149 }
150 
151 void ShapeSensorWidget::updateShapePointLockRange()
152 {
153  int rangeMax = mReadFbgsMessage->getRangeMax();
154  if(rangeMax > 0)
155  {
156  DoubleRange range = mShapePointLock->getValueRange();
157  if (range.max() != rangeMax)
158  {
159  range.mMax = rangeMax;
160  mShapePointLock->setValueRange(range);
161  }
162  if (mShapePointLock->getValue() > rangeMax)
163  mShapePointLock->setValue(rangeMax);
164  }
165 }
166 
167 void ShapeSensorWidget::connectStateChangedSlot(CX_SOCKETCONNECTION_STATE status)
168 {
169  if(status == scsCONNECTED)
170  {
171  mConnectButton->setText("Disconnect");
172  }
173  else
174  {
175  mConnectButton->setText("Connect");
176  }
177 }
178 
179 void ShapeSensorWidget::connectClickedSlot()
180 {
181 
182  SocketConnection::ConnectionInfo info = mSocketConnection->getConnectionInfo();
183  info.port = mIpPort->getValue();
184  info.host = mIpAddress->getValue();
185  mSocketConnection->setConnectionInfo(info);
186 
187  if(mSocketConnection->getState() != scsCONNECTED)
188  mSocketConnection->requestConnect();
189  else
190  mSocketConnection->requestDisconnect();
191 
192  this->showShape();
193 }
194 
195 
196 void ShapeSensorWidget::showClickedSlot()
197 {
198  vtkPolyDataPtr polydata = mReadFbgsMessage->getPolyData();
199  if(mShowShape)
200  mShowShapeButton->setText("Show shape");
201  else
202  mShowShapeButton->setText("Hide shape");
203  mShowShape = !mShowShape;
204  this->showShape();
205 }
206 
207 void ShapeSensorWidget::showShape()
208 {
209  if(mShowShape)
210  mServices->view()->get3DView()->getRenderer()->AddActor(mReadFbgsMessage->getActor());
211  else
212  mServices->view()->get3DView()->getRenderer()->RemoveActor(mReadFbgsMessage->getActor());
213 }
214 
215 void ShapeSensorWidget::testShapeClickedSlot()
216 {
217  std::vector<double> *xAxis = mReadFbgsMessage->getAxisPosVector(ReadFbgsMessage::axisX);
218  std::vector<double> *yAxis = mReadFbgsMessage->getAxisPosVector(ReadFbgsMessage::axisY);
219  std::vector<double> *zAxis = mReadFbgsMessage->getAxisPosVector(ReadFbgsMessage::axisZ);
220  xAxis->push_back(0);
221  yAxis->push_back(0);
222  zAxis->push_back(0);
223  for(int i = 1; i < 100; ++i)
224  {
225  xAxis->push_back(i+std::rand()/((RAND_MAX + 1u)/3));
226  yAxis->push_back(i+std::rand()/((RAND_MAX + 1u)/3));
227  zAxis->push_back(i+std::rand()/((RAND_MAX + 1u)/3));
228  }
229  mReadFbgsMessage->createPolyData();
230 }
231 
232 void ShapeSensorWidget::saveShapeClickedSlot()
233 {
234  mReadFbgsMessage->saveMeshSnapshot();
235 }
236 
237 void ShapeSensorWidget::dataAvailableSlot()
238 {
239  this->processData();
240 }
241 
242 void ShapeSensorWidget::processData()
243 {
244  //This processing could cause the GUI to slow down. Especially opening new windows seems to fail
245  //Using prePaintEvent Don't work for rendering in 3D scene
246  //Could possibly use RenderLoop::preRender in ViewImplService
247  //Current solution is to first process all events in the QEventLoop:
248  qApp->processEvents();
249 
250  bool bufferUpdated = this->readBuffer();
251  if(!bufferUpdated)
252  return;
253 
254  mReadFbgsMessage->readBuffer(mBuffer);
255  this->updateShapePointLockRange();
256 }
257 
258 bool ShapeSensorWidget::readBuffer()
259 {
260  bool ok = this->readMessageLenght();
261  if(!ok)
262  return false;
263 
264  bool bufferUpdated = false;
265  int numberRead = 0;
266 
267  //Read messages until we get the latest
268 
269  QTime timer;
270  timer.start();
271  do
272  {
273  char *charBuffer = (char*)malloc(mDataLenght);
274  ok = mSocketConnection->socketReceive(charBuffer, mDataLenght);
275  if(ok)
276  {
277  bufferUpdated = true;
278  mDataLenght = 0;
279  mBuffer = QString(charBuffer);
280  ok = this->readMessageLenght();
281  if(ok)
282  numberRead++;
283  }
284  free(charBuffer);
285  }
286  while (ok);
287 // CX_LOG_DEBUG() << "Read " << numberRead << " tcp messages.";
288  return bufferUpdated;
289 }
290 
291 bool ShapeSensorWidget::readMessageLenght()
292 {
293  bool ok = true;
294  if(mDataLenght == 0)//Use previously read value, if not whole buffer could be read last time
295  {
296  unsigned char charSize[4];
297  ok = mSocketConnection->socketReceive(&charSize, 4);
298  if(!ok)
299  {
300  //CX_LOG_WARNING() << "ShapeSensorWidget::readMessageLenght: Cannot read 4 characters from TCP socket";
301  return false;
302  }
303  mDataLenght = int( ( (unsigned char)(charSize[0]) << 24 )
304  | ( (unsigned char)(charSize[1]) << 16 )
305  | ( (unsigned char)(charSize[2]) << 8 )
306  | ( (unsigned char)(charSize[3]) ) );
307  }
308  return true;
309 }
310 
311 void ShapeSensorWidget::toolChangedSlot()
312 {
313 // Alternative code for connecting to active tool instead of tool selector
314 // disconnect(mTool.get(), &Tool::toolTransformAndTimestamp, this, &ShapeSensorWidget::receiveTransforms);
315 // mTool = mServices->tracking()->getActiveTool();
316 // connect(mTool.get(), &Tool::toolTransformAndTimestamp, this, &ShapeSensorWidget::receiveTransforms);
317 
318  disconnect(mSelector.get(), &StringPropertyBase::changed, this, &ShapeSensorWidget::toolChangedSlot);
319  mTool = mServices->tracking()->getTool(mSelector->getValue());
320  connect(mSelector.get(), &StringPropertyBase::changed, this, &ShapeSensorWidget::toolChangedSlot);
321 }
322 
323 void ShapeSensorWidget::receiveTransforms(Transform3D prMt, double timestamp)
324 {
325  mReadFbgsMessage->set_prMt(prMt);
326 }
327 } /* namespace cx */
CX_SOCKETCONNECTION_STATE
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:160
double max() const
maximum value
Definition: cxDoubleRange.h:49
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
Utility class for describing a bounded numeric range.
Definition: cxDoubleRange.h:32
void toolTransformAndTimestamp(Transform3D matrix, double timestamp)
void stateChanged(CX_SOCKETCONNECTION_STATE status)
QDomElement getElement()
return the current element
boost::shared_ptr< class StringProperty > StringPropertyPtr
StringPropertyBasePtr getSelector()
boost::shared_ptr< class StringPropertyBase > StringPropertyBasePtr
static QFrame * createHorizontalLine()
Creates a horizontal line which can be inserted into widgets.
Widget that contains a select active tool combo box.
ShapeSensorWidget(VisServicesPtr services, QWidget *parent=0)
boost::shared_ptr< class DoublePropertyBase > DoublePropertyBasePtr
void changed()
emit when the underlying data value is changed: The user interface will be updated.
static StringPropertyPtr initialize(const QString &uid, QString name, QString help, QString value, QStringList range, QDomNode root=QDomNode())
vtkSmartPointer< vtkPolyData > vtkPolyDataPtr
boost::shared_ptr< class DoubleProperty > DoublePropertyPtr
Interface for QWidget which handles widgets uniformly for the system.
Definition: cxBaseWidget.h:88
static DoublePropertyPtr initialize(const QString &uid, QString name, QString help, double value, DoubleRange range, int decimals, QDomNode root=QDomNode())
QWidget * sscCreateDataWidget(QWidget *parent, PropertyPtr data, QGridLayout *gridLayout, int row)
Create a widget capable of displaying the input data.
Helper class for xml files used to store ssc/cx data.
Namespace for all CustusX production code.