Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkVirtualTrackingDevice.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 #include "mitkIGTTimeStamp.h"
19 #include "mitkIGTException.h"
20 
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <time.h>
24 #include <itksys/SystemTools.hxx>
25 #include <itkMutexLockHolder.h>
26 #include <random>
27 
29 
31 
33 m_AllTools(), m_ToolsMutex(NULL), m_MultiThreader(NULL), m_ThreadID(-1), m_RefreshRate(100), m_NumberOfControlPoints(20), m_GaussianNoiseEnabled(false),
34 m_MeanDistributionParam(0.0), m_DeviationDistributionParam(1.0)
35 {
37  m_Bounds[0] = m_Bounds[2] = m_Bounds[4] = -400.0; // initialize bounds to -400 ... +400 (mm) cube
38  m_Bounds[1] = m_Bounds[3] = m_Bounds[5] = 400.0;
40 }
41 
43 {
44  if (this->GetState() == Tracking)
45  {
46  this->StopTracking();
47  }
48  if (this->GetState() == Ready)
49  {
50  this->CloseConnection();
51  }
52  /* cleanup tracking thread */
53  if (m_MultiThreader.IsNotNull() && (m_ThreadID != -1))
54  {
55  m_MultiThreader->TerminateThread(m_ThreadID);
56  m_MultiThreader = NULL;
57  }
58  m_AllTools.clear();
59 }
60 
62 {
63  //if (this->GetState() == Tracking)
64  //{
65  // return NULL;
66  //}
68  t->SetToolName(toolName);
69  t->SetVelocity(0.1);
70  this->InitializeSpline(t);
71  MutexLockHolder lock(*m_ToolsMutex); // lock and unlock the mutex
72  m_AllTools.push_back(t);
73  return t;
74 }
75 
77 {
78  if (this->GetState() != Ready)
79  return false;
80  this->SetState(Tracking); // go to mode Tracking
81  this->m_StopTrackingMutex->Lock();
82  this->m_StopTracking = false;
83  this->m_StopTrackingMutex->Unlock();
84 
86 
87  if (m_MultiThreader.IsNotNull() && (m_ThreadID != -1))
88  m_MultiThreader->TerminateThread(m_ThreadID);
89  if (m_MultiThreader.IsNull())
90  m_MultiThreader = itk::MultiThreader::New();
91 
92  m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this); // start a new thread that executes the TrackTools() method
93  return true;
94 }
95 
97 {
98  if (this->GetState() == Tracking) // Only if the object is in the correct state
99  {
100  m_StopTrackingMutex->Lock(); // m_StopTracking is used by two threads, so we have to ensure correct thread handling
101  m_StopTracking = true;
102  m_StopTrackingMutex->Unlock();
103 
104  m_TrackingFinishedMutex->Lock();
105  this->SetState(Ready);
106  m_TrackingFinishedMutex->Unlock();
107  }
108 
110 
111  return true;
112 }
113 
115 {
116  MutexLockHolder lock(*m_ToolsMutex); // lock and unlock the mutex
117  return static_cast<unsigned int>(this->m_AllTools.size());
118 }
119 
121 {
122  MutexLockHolder lock(*m_ToolsMutex); // lock and unlock the mutex
123  if (toolNumber < m_AllTools.size())
124  return this->m_AllTools.at(toolNumber);
125  return NULL;
126 }
127 
129 {
130  if (m_NumberOfControlPoints < 1)
131  {
132  mitkThrowException(mitk::IGTException) << "to few control points for spline interpolation";
133  }
134  srand(time(NULL)); //Init random number generator
135 
136  this->SetState(Ready);
137  return true;
138 }
139 
141 {
142  if (t == NULL)
143  return;
144 
145  typedef mitk::VirtualTrackingTool::SplineType SplineType;
146  /* create random control points */
147  SplineType::ControlPointListType controlPoints;
148  controlPoints.reserve(m_NumberOfControlPoints + 1);
149 
150  controlPoints.push_back(this->GetRandomPoint()); // insert point 0
151  double length = 0.0; // estimate spline length by calculating line segments lengths
152  for (unsigned int i = 1; i < m_NumberOfControlPoints - 1; ++i) // set points 1..n-2
153  {
154  SplineType::ControlPointType pos;
155  pos = this->GetRandomPoint();
156  length += controlPoints.at(i - 1).EuclideanDistanceTo(pos);
157  controlPoints.push_back(pos);
158  }
159  controlPoints.push_back(controlPoints.at(0)); // close spline --> insert point last control point with same value as first control point
160  length += controlPoints.at(controlPoints.size() - 2).EuclideanDistanceTo(controlPoints.at(controlPoints.size() - 1));
161 
162  /* Create knot list. TODO: rethink knot list values and list size. Is there a better solution? */
163  SplineType::KnotListType knotList;
164  knotList.push_back(0.0);
165  for (unsigned int i = 1; i < controlPoints.size() + t->GetSpline()->GetSplineOrder() + 1; ++i)
166  knotList.push_back(i);
167  knotList.push_back(controlPoints.size() + t->GetSpline()->GetSplineOrder() + 1);
168 
169  t->GetSpline()->SetControlPoints(controlPoints);
170  t->GetSpline()->SetKnots(knotList);
171  t->SetSplineLength(length);
172 }
173 
175 {
176  bool returnValue = true;
177  if (this->GetState() == Setup)
178  return true;
179 
180  this->SetState(Setup);
181  return returnValue;
182 }
183 
185 {
186  mitk::VirtualTrackingTool* t = this->GetInternalTool(idx);
187  if (t != NULL)
188  return t->GetSplineLength();
189  else
190  throw std::invalid_argument("invalid index");
191 }
192 
193 void mitk::VirtualTrackingDevice::SetToolSpeed(unsigned int idx, mitk::ScalarType roundsPerSecond)
194 {
195  if (roundsPerSecond < 0.0001)
196  throw std::invalid_argument("Minimum tool speed is 0.0001 rounds per second");
197 
198  mitk::VirtualTrackingTool* t = this->GetInternalTool(idx);
199  if (t != NULL)
200  t->SetVelocity(roundsPerSecond);
201  else
202  throw std::invalid_argument("invalid index");
203 }
204 
206 {
207  MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex
208  if (idx < m_AllTools.size())
209  return m_AllTools.at(idx);
210  else
211  return NULL;
212 }
213 
215 {
216  /* lock the TrackingFinishedMutex to signal that the execution rights are now transfered to the tracking thread */
217  MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope
218 
219  if (this->GetState() != Tracking)
220  return;
221 
222  bool localStopTracking; // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here
223 
224  this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking
225  localStopTracking = this->m_StopTracking;
226  this->m_StopTrackingMutex->Unlock();
227 
228  mitk::ScalarType t = 0.0;
229  while ((this->GetState() == Tracking) && (localStopTracking == false))
230  {
231  //for (ToolContainer::iterator itAllTools = m_AllTools.begin(); itAllTools != m_AllTools.end(); itAllTools++)
232  for (unsigned int i = 0; i < this->GetToolCount(); ++i) // use mutexed methods to access tool container
233  {
234  mitk::VirtualTrackingTool::Pointer currentTool = this->GetInternalTool(i);
236  /* calculate tool position with spline interpolation */
237  pos = currentTool->GetSpline()->EvaluateSpline(t);
238  mitk::Point3D mp;
239  mitk::itk2vtk(pos, mp); // convert from SplineType::PointType to mitk::Point3D
240 
241  //Add Gaussian Noise to Tracking Coordinates if enabled
242  if (this->m_GaussianNoiseEnabled)
243  {
244  std::random_device rd;
245  std::mt19937 generator(rd());
246  std::normal_distribution<double> dist(this->m_MeanDistributionParam, this->m_DeviationDistributionParam);
247  double noise = dist(generator);
248  mp = mp + noise;
249  }
250 
251  currentTool->SetPosition(mp);
252  // Currently, a constant speed is used. TODO: use tool velocity setting
253  t += 0.001;
254  if (t >= 1.0)
255  t = 0.0;
256 
257  mitk::Quaternion quat;
258  /* fix quaternion rotation */
259  quat.x() = 0.0;
260  quat.y() = 0.0;
261  quat.z() = 0.0;
262  quat.r() = 1.0;
263  quat.normalize();
264  currentTool->SetOrientation(quat);
265  // TODO: rotate once per cycle around a fixed rotation vector
266 
267  currentTool->SetTrackingError(2 * (rand() / (RAND_MAX + 1.0))); // tracking error in 0 .. 2 Range
268  currentTool->SetDataValid(true);
269  currentTool->Modified();
270  }
271  itksys::SystemTools::Delay(m_RefreshRate);
272  /* Update the local copy of m_StopTracking */
273  this->m_StopTrackingMutex->Lock();
274  localStopTracking = m_StopTracking;
275  this->m_StopTrackingMutex->Unlock();
276  } // tracking ends if we pass this line
277 }
278 
279 ITK_THREAD_RETURN_TYPE mitk::VirtualTrackingDevice::ThreadStartTracking(void* pInfoStruct)
280 {
281  /* extract this pointer from Thread Info structure */
282  struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
283  if (pInfo == NULL)
284  {
285  return ITK_THREAD_RETURN_VALUE;
286  }
287  if (pInfo->UserData == NULL)
288  {
289  return ITK_THREAD_RETURN_VALUE;
290  }
291  VirtualTrackingDevice *trackingDevice = static_cast<VirtualTrackingDevice*>(pInfo->UserData);
292 
293  if (trackingDevice != NULL)
294  trackingDevice->TrackTools();
295 
296  trackingDevice->m_ThreadID = -1; // reset thread ID because we end the thread here
297  return ITK_THREAD_RETURN_VALUE;
298 }
299 
301 {
302  ControlPointType pos;
303  pos[0] = m_Bounds[0] + (m_Bounds[1] - m_Bounds[0]) * (rand() / (RAND_MAX + 1.0)); // X = xMin + xRange * (random number between 0 and 1)
304  pos[1] = m_Bounds[2] + (m_Bounds[3] - m_Bounds[2]) * (rand() / (RAND_MAX + 1.0)); // Y
305  pos[2] = m_Bounds[4] + (m_Bounds[5] - m_Bounds[4]) * (rand() / (RAND_MAX + 1.0)); // Z
306 
307  return pos;
308 }
309 
311 {
312  this->m_GaussianNoiseEnabled = true;
313 }
314 
316 {
317  this->m_GaussianNoiseEnabled = false;
318 }
319 
320 void mitk::VirtualTrackingDevice::SetParamsForGaussianNoise(double meanDistribution, double deviationDistribution)
321 {
322  this->m_MeanDistributionParam = meanDistribution;
323  this->m_DeviationDistributionParam = deviationDistribution;
324 }
325 
327 {
328  return m_DeviationDistributionParam;
329 }
330 
332 {
333  return m_MeanDistributionParam;
334 }
void EnableGaussianNoise()
enable addition of Gaussian Noise to tracking coordinates
Interface for all Tracking Tools.
itk::FastMutexLock::Pointer m_ToolsMutex
mutex for coordinated access of tool container
itk::SmartPointer< Self > Pointer
double GetDeviationDistribution()
returns the deviation distribution for the Gaussian Noise
void SetControlPoints(ControlPointListType &ctrlpts)
virtual SplineType * GetSpline()
static ITK_THREAD_RETURN_TYPE ThreadStartTracking(void *data)
static start method for tracking thread
TrackingTool * AddTool(const char *toolName)
Adds a tool to the tracking device.
double ScalarType
virtual mitk::ScalarType GetSplineLength()
TrackingTool * GetTool(unsigned int toolNumber) const override
An object of this class represents an exception of the MITK-IGT module.
DataCollection - Class to facilitate loading/accessing structured data.
void SetParamsForGaussianNoise(double meanDistribution, double deviationDistribution)
sets the mean distribution and the standard deviation for the Gaussian Noise
itk::MutexLockHolder< itk::FastMutexLock > MutexLockHolder
static Pointer New()
virtual void SetSplineLength(mitk::ScalarType _arg)
itk::Point< ScalarType, TDimension > PointType
void SetKnots(KnotListType &newKnots)
double GetMeanDistribution()
returns the mean distribution for the Gaussian Noise
void DisableGaussianNoise()
disable addition of Gaussian Noise to Trackin coordinates
mitk::VirtualTrackingTool * GetInternalTool(unsigned int idx)
virtual const unsigned int & GetSplineOrder()
BSpline with nonuniform knot spacing.
void TrackTools()
This method tracks tools as long as the variable m_Mode is set to "Tracking". Tracking tools means ge...
virtual bool CloseConnection() override
Closes the connection and clears all resources.
Interface for all Tracking Devices.
static IGTTimeStamp * GetInstance()
returns a pointer to the current instance of mitkTimeStamp
vnl_quaternion< ScalarType > Quaternion
void Start(itk::Object::Pointer device)
starts the time-acquisition
virtual bool OpenConnection() override
Opens the connection to the device. This have to be done before the tracking is started.
mitk::VirtualTrackingTool::SplineType::ControlPointType ControlPointType
virtual bool StartTracking() override
Starts the tracking.
void InitializeSpline(mitk::VirtualTrackingTool *t)
initializes the spline path of the tool t with random control points inside the current tracking volu...
TrackingDeviceData m_Data
current device Data
void itk2vtk(const Tin &in, Tout &out)
#define mitkThrowException(classname)
mitk::ScalarType m_Bounds[6]
bounding box of the tracking volume stored as {xMin, xMax, yMin, yMax, zMin, zMax} ...
virtual unsigned int GetToolCount() const override
void Stop(itk::Object::Pointer device)
stops the time-acqusition
virtual void SetVelocity(mitk::ScalarType _arg)
void SetToolSpeed(unsigned int idx, mitk::ScalarType roundsPerSecond)
sets the speed of the tool idx in rounds per second
static void Setup()
ControlPointType GetRandomPoint()
returns a random position inside the tracking volume (defined by m_Bounds)
implements TrackingTool interface
Class representing a tracking device which generates random positions / orientations. No hardware is needed for tracking device.
virtual bool StopTracking() override
Stops the tracking.
mitk::ScalarType GetSplineChordLength(unsigned int idx)
return the approximate length of the spline for tool with index idx in millimeter ...
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.