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
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.