PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusVirtualSwitcher.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2  Program: Plus
3  Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4  See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 #include "PlusConfigure.h"
8 #include "vtkObjectFactory.h"
9 #include "vtkPlusDataSource.h"
10 #include "vtkPlusVirtualSwitcher.h"
11 
12 //----------------------------------------------------------------------------
13 
15 
17 
18 //----------------------------------------------------------------------------
20 : vtkPlusDevice()
21 , CurrentActiveInputChannel(NULL)
22 , OutputChannel(NULL)
23 , FramesWhileInactive(0)
24 {
25  // The data capture thread will be used to regularly check the input devices and generate and update the output
28 }
29 
30 //----------------------------------------------------------------------------
32 {
33 }
34 
35 //----------------------------------------------------------------------------
36 void vtkPlusVirtualSwitcher::PrintSelf(ostream& os, vtkIndent indent)
37 {
38  this->Superclass::PrintSelf(os,indent);
39 
40  for( ChannelContainerIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it )
41  {
42  os << indent << "Input channel: \n";
43  (*it)->PrintSelf(os, indent);
44  }
45 
46  os << indent << "Active input channel: \n";
47  if( this->CurrentActiveInputChannel != NULL )
48  {
49  this->CurrentActiveInputChannel->PrintSelf(os, indent);
50  }
51 }
52 
53 //----------------------------------------------------------------------------
55 {
56  if( this->CurrentActiveInputChannel != NULL )
57  {
58  aChannel = this->CurrentActiveInputChannel;
59  return PLUS_SUCCESS;
60  }
61 
62  aChannel = NULL;
63  return PLUS_FAIL;
64 }
65 
66 //----------------------------------------------------------------------------
68 {
69  // if this device runs faster than input device, we might falsely detect that the device is not active because the latest timestamp hasn't changed
70  // correctly detect this situation and wait a few frames before switching
71  // if timestamp not changed within 'FRAME_COUNT_BEFORE_INACTIVE' frames, then do new stream check
72 
73  double latestCurrentTimestamp(0);
74  if( this->CurrentActiveInputChannel != NULL )
75  {
76  if( this->CurrentActiveInputChannel->GetLatestTimestamp(latestCurrentTimestamp) != PLUS_SUCCESS )
77  {
78  LOG_ERROR("Unable to retrieve timestamp from active stream.");
79  return PLUS_FAIL;
80  }
82  {
83  this->LastRecordedTimestampMap[this->CurrentActiveInputChannel] = latestCurrentTimestamp;
84  return PLUS_SUCCESS;
85  }
86 
87  if( latestCurrentTimestamp > this->LastRecordedTimestampMap[this->CurrentActiveInputChannel] )
88  {
89  // Device is still active
90  return PLUS_SUCCESS;
91  }
92  else
93  {
95  {
96  this->FramesWhileInactive = 0;
97  // Device is no longer active
98  if( this->SelectActiveChannel() == PLUS_FAIL )
99  {
100  // No active devices, don't copy anything!
101  return PLUS_SUCCESS;
102  }
103  }
104  else
105  {
107  }
108  }
109 
111  }
112 
113  return PLUS_SUCCESS;
114 }
115 
116 //----------------------------------------------------------------------------
118 {
119  std::vector<vtkPlusChannel*> ActiveChannels;
120 
121  for( ChannelContainerConstIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it )
122  {
123  vtkPlusChannel* aChannel = (*it);
124  double latestTimestamp(0);
125  if( aChannel->GetLatestTimestamp(latestTimestamp) != PLUS_SUCCESS )
126  {
127  LOG_ERROR("Unable to retrieve latest timestamp from stream.");
128  continue;
129  }
130  if( latestTimestamp > this->LastRecordedTimestampMap[aChannel] )
131  {
132  // It's got new data... it's active
133  this->LastRecordedTimestampMap[aChannel] = latestTimestamp;
134  ActiveChannels.push_back(aChannel);
135  }
136  }
137 
138  if( ActiveChannels.size() > 0 )
139  {
140  // For now, just choose the first... maybe in the future make it more elegant
141  this->SetCurrentActiveInputChannel(ActiveChannels[0]);
143 
144  // We will also now need to output the correct transform associated with the new stream
145  // Is there any way to make this generic?
146  // In config file, associate transform/image names to special prefix/postfixes?
147  // scan stream name, if postfix matches, output transform(s) with that postfix? eg stream id -- Output_depth:5cm, transform -- ImageToProbeTransform_5cm, etc...
148  // have base transform name(s) in the config eg: ImageToProbeTransform
149 
150  return PLUS_SUCCESS;
151  }
152 
153  this->SetCurrentActiveInputChannel(NULL);
154  return PLUS_FAIL;
155 }
156 
157 //----------------------------------------------------------------------------
159 {
160  vtkPlusChannel* aChannel = NULL;
161  if( this->GetChannel(aChannel) == PLUS_SUCCESS )
162  {
163  return aChannel->GetOwnerDevice()->GetAcquisitionRate();
164  }
165 
166  return this->AcquisitionRate;
167 }
168 
169 //----------------------------------------------------------------------------
170 PlusStatus vtkPlusVirtualSwitcher::ReadConfiguration( vtkXMLDataElement* rootConfigElement)
171 {
172  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
173 
174  if( this->OutputChannels.empty() )
175  {
176  LOG_ERROR("No output channels defined" );
177  return PLUS_FAIL;
178  }
179  vtkPlusChannel* outputChannel=this->OutputChannels[0];
180 
181  SetOutputChannel(outputChannel);
182 
183  return PLUS_SUCCESS;
184 }
185 
186 //----------------------------------------------------------------------------
188 {
189  this->LastRecordedTimestampMap.clear();
190 
191  for( ChannelContainerConstIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it )
192  {
193  vtkPlusChannel* aChannel = (*it);
194  this->LastRecordedTimestampMap[aChannel] = 0;
195  }
196 
197  return PLUS_SUCCESS;
198 }
199 
200 //----------------------------------------------------------------------------
202 {
203  // Only destroy if things have to change
204  if( this->CurrentActiveInputChannel != NULL )
205  {
206  // no need to do a deep copy, iterators are used to access data anyways
208  }
209 
210  return PLUS_SUCCESS;
211 }
static const int VIRTUAL_DEVICE_FRAME_RATE
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
virtual void ShallowCopy(vtkDataObject *)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
ChannelContainer InputChannels
vtkStandardNewMacro(vtkPlusVirtualSwitcher)
virtual PlusStatus InternalUpdate()
double AcquisitionRate
virtual PlusStatus GetLatestTimestamp(double &aTimestamp) const
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual PlusStatus NotifyConfigured()
PlusStatus GetChannel(vtkPlusChannel *&aChannel) const
virtual double GetAcquisitionRate() const
vtkPlusChannel * CurrentActiveInputChannel
virtual void SetOutputChannel(vtkPlusChannel *)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
ChannelContainer::const_iterator ChannelContainerConstIterator
Definition: vtkPlusDevice.h:35
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual double GetAcquisitionRate() const
const int FRAME_COUNT_BEFORE_INACTIVE
bool StartThreadForInternalUpdates
std::map< vtkPlusChannel *, double > LastRecordedTimestampMap
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
ChannelContainer OutputChannels
virtual void SetCurrentActiveInputChannel(vtkPlusChannel *)
ChannelContainer::iterator ChannelContainerIterator
Definition: vtkPlusDevice.h:36
vtkPlusDevice * GetOwnerDevice() const