PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusVirtualMixer.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 "vtkPlusChannel.h"
10 #include "vtkPlusDataSource.h"
11 #include "vtkPlusVirtualMixer.h"
12 
13 //----------------------------------------------------------------------------
14 
16 
17 //----------------------------------------------------------------------------
19  : vtkPlusDevice()
20 {
22 
23  // No need for StartThreadForInternalUpdates, as capturing is performed in other devices, here we just collect references to buffers
24 }
25 
26 //----------------------------------------------------------------------------
28 {
29  // Clear reference to rf processor
30  if (!this->OutputChannels.empty())
31  {
32  vtkPlusChannel* outputChannel = this->OutputChannels[0];
33  if (outputChannel != NULL && outputChannel->GetRfProcessor() != NULL)
34  {
35  outputChannel->SetRfProcessor(NULL);
36  }
37  }
38 
39  // Mixer fakes an output channel to enable "GetTrackedFrame" functionality
40  // We don't want the plus device destructor destroying sources in output channels it doesn't own
41  // So clear it before it runs (see #756)
42  this->OutputChannels.clear();
43 }
44 
45 //----------------------------------------------------------------------------
46 void vtkPlusVirtualMixer::PrintSelf(ostream& os, vtkIndent indent)
47 {
48  this->Superclass::PrintSelf(os, indent);
49 }
50 
51 //----------------------------------------------------------------------------
52 PlusStatus vtkPlusVirtualMixer::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
53 {
54  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
55 
56  if (this->OutputChannels.empty())
57  {
58  LOG_WARNING("vtkPlusVirtualMixer device " << this->GetDeviceId() << " does not have any output channels");
59  vtkSmartPointer<vtkPlusChannel> aChannel = vtkSmartPointer<vtkPlusChannel>::New();
60  std::ostringstream ss;
61  ss << "aMixerId_" << vtkIGSIOAccurateTimer::GetSystemTime();
62  aChannel->SetChannelId(ss.str().c_str());
63  this->AddOutputChannel(aChannel);
64  }
65 
66  return PLUS_SUCCESS;
67 }
68 
69 //----------------------------------------------------------------------------
71 {
72  // Determine frame rate from the video input device with the lowest frame rate
73  bool lowestRateKnown = false;
74  double lowestRate = 30; // just a usual value (FPS)
75 
76  for (ChannelContainerConstIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it)
77  {
78  vtkPlusChannel* anInputChannel = (*it);
79 
80  // Get the lowest rate from all image streams
81  if (anInputChannel->HasVideoSource())
82  {
83  lowestRate = anInputChannel->GetOwnerDevice()->GetAcquisitionRate();
84  lowestRateKnown = true;
85  }
86 
87  if (anInputChannel->GetOwnerDevice()->GetAcquisitionRate() < lowestRate || !lowestRateKnown)
88  {
89  lowestRate = anInputChannel->GetOwnerDevice()->GetAcquisitionRate();
90  lowestRateKnown = true;
91  }
92  }
93 
94  if (!lowestRateKnown)
95  {
96  // Couldn't determine the lowest acquisition rate, so just use the one that was set by default
97  lowestRate = this->AcquisitionRate;
98  }
99  return lowestRate;
100 }
101 
102 //----------------------------------------------------------------------------
104 {
105  // First, empty whatever is there, because this can be called at any point after a configuration
106  if (this->OutputChannels.empty())
107  {
108  LOG_ERROR("No output channels defined");
109  return PLUS_FAIL;
110  }
111  vtkPlusChannel* outputChannel = this->OutputChannels[0];
112 
113  outputChannel->RemoveTools();
114  outputChannel->RemoveFieldDataSources();
115  outputChannel->Clear();
116 
117  for (ChannelContainerIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it)
118  {
119  vtkPlusChannel* anInputChannel = (*it);
120  vtkPlusDataSource* aSource = NULL;
121 
122  if (anInputChannel->HasVideoSource() && anInputChannel->GetVideoSource(aSource) == PLUS_SUCCESS)
123  {
124  outputChannel->SetVideoSource(aSource);
125  this->AddVideoSource(aSource);
126  }
127 
128  for (DataSourceContainerConstIterator fieldSourceIter = anInputChannel->GetToolsStartConstIterator(); fieldSourceIter != anInputChannel->GetToolsEndConstIterator(); ++fieldSourceIter)
129  {
130  vtkPlusDataSource* anInputTool = fieldSourceIter->second;
131 
132  bool found = false;
133  for (DataSourceContainerConstIterator outputToolIt = outputChannel->GetToolsStartConstIterator(); outputToolIt != outputChannel->GetToolsEndConstIterator(); ++outputToolIt)
134  {
135  vtkPlusDataSource* anOutputTool = outputToolIt->second;
136  // Check for double adds or name conflicts
137  if (anInputTool == anOutputTool)
138  {
139  found = true;
140  LOG_ERROR("Tool already exists in the output stream. Somehow the same tool is part of two input streams. Consider using a virtual device to resolve them first.");
141  break;
142  }
143  else if (anInputTool->GetId() == anOutputTool->GetId())
144  {
145  found = true;
146  LOG_ERROR("Name collision! Two tools are outputting the same transform. Consider using a virtual device to resolve them first.");
147  break;
148  }
149  }
150 
151  if (!found)
152  {
153  outputChannel->AddTool(anInputTool);
154  if (this->AddTool(anInputTool, false) != PLUS_SUCCESS)
155  {
156  LOG_ERROR("Unable to add tool " << anInputTool->GetId() << " to device " << this->GetDeviceId());
157  }
158  }
159  }
160 
161  for (DataSourceContainerConstIterator fieldSourceIter = anInputChannel->GetFieldDataSourcesStartConstIterator(); fieldSourceIter != anInputChannel->GetFieldDataSourcesEndConstIterator(); ++fieldSourceIter)
162  {
163  vtkPlusDataSource* inputFieldSource = fieldSourceIter->second;
164 
165  bool found = false;
166  for (DataSourceContainerConstIterator outputFieldSourceIter = outputChannel->GetFieldDataSourcesStartConstIterator(); outputFieldSourceIter != outputChannel->GetFieldDataSourcesEndConstIterator(); ++outputFieldSourceIter)
167  {
168  vtkPlusDataSource* outputFieldSource = outputFieldSourceIter->second;
169  // Check for double adds or name conflicts
170  if (inputFieldSource == outputFieldSource)
171  {
172  found = true;
173  LOG_ERROR("Field data source already exists in the output stream. Somehow the same data field is part of two input streams. Consider using a virtual device to resolve them first.");
174  break;
175  }
176  else if (inputFieldSource->GetId() == outputFieldSource->GetId())
177  {
178  found = true;
179  LOG_ERROR("Name collision! Two field sources are outputting the same data. Consider using a virtual device to resolve them first.");
180  break;
181  }
182  }
183 
184  if (!found)
185  {
186  outputChannel->AddFieldDataSource(inputFieldSource);
187  if (this->AddFieldDataSource(inputFieldSource) != PLUS_SUCCESS)
188  {
189  LOG_ERROR("Unable to add field data source " << inputFieldSource->GetId() << " to device " << this->GetDeviceId());
190  }
191  }
192  }
193 
194  if (anInputChannel->GetRfProcessor() != NULL && outputChannel->GetRfProcessor() == NULL)
195  {
196  outputChannel->SetRfProcessor(anInputChannel->GetRfProcessor());
197  }
198  else if (anInputChannel->GetRfProcessor() != NULL && outputChannel->GetRfProcessor() != NULL)
199  {
200  LOG_WARNING("Multiple RfProcessors defined in InputChannels to mixer: " << this->GetDeviceId() << ". Check input configuration.");
201  }
202  }
203 
204  return PLUS_SUCCESS;
205 }
206 
207 //----------------------------------------------------------------------------
209 {
210  for (ChannelContainerConstIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it)
211  {
212  vtkPlusChannel* aChannel = *it;
213  if (aChannel->GetOwnerDevice()->IsTracker())
214  {
215  return true;
216  }
217  }
218 
219  return false;
220 }
221 
222 //----------------------------------------------------------------------------
224 {
225  int numErrors(0);
226  for (ChannelContainerConstIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it)
227  {
228  vtkPlusChannel* aChannel = *it;
229  if (aChannel->GetOwnerDevice()->Reset() != PLUS_SUCCESS)
230  {
231  numErrors++;
232  }
233  }
234 
235  return numErrors == 0 ? PLUS_SUCCESS : PLUS_FAIL;
236 }
237 
238 //----------------------------------------------------------------------------
240 {
241  for (ChannelContainerConstIterator it = this->InputChannels.begin(); it != this->InputChannels.end(); ++it)
242  {
243  vtkPlusChannel* aChannel = *it;
244  if (aChannel->GetOwnerDevice()->IsResettable())
245  {
246  return true;
247  }
248  }
249 
250  return false;
251 }
252 
253 //----------------------------------------------------------------------------
255 {
256  return this->OutputChannels[0];
257 }
DataSourceContainer::const_iterator DataSourceContainerConstIterator
virtual vtkPlusRfProcessor * GetRfProcessor()
vtkStandardNewMacro(vtkPlusVirtualMixer)
static const int VIRTUAL_DEVICE_FRAME_RATE
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual double GetAcquisitionRate() const
PlusStatus AddVideoSource(vtkPlusDataSource *anImage)
bool HasVideoSource() const
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
DataSourceContainerConstIterator GetToolsEndConstIterator() const
ChannelContainer InputChannels
virtual std::string GetDeviceId() const
virtual bool IsTracker() const
PlusStatus AddTool(vtkPlusDataSource *tool, bool requireUniquePortName=true)
virtual PlusStatus Clear()
double AcquisitionRate
DataSourceContainerConstIterator GetFieldDataSourcesStartConstIterator() const
PlusStatus AddTool(vtkPlusDataSource *aTool)
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual double GetAcquisitionRate() const
DataSourceContainerConstIterator GetFieldDataSourcesEndConstIterator() const
PlusStatus AddOutputChannel(vtkPlusChannel *aChannel)
DataSourceContainerConstIterator GetToolsStartConstIterator() const
virtual PlusStatus Reset()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
PlusStatus AddFieldDataSource(vtkPlusDataSource *aSource)
virtual PlusStatus NotifyConfigured()
PlusStatus RemoveTools()
ChannelContainer::const_iterator ChannelContainerConstIterator
Definition: vtkPlusDevice.h:35
virtual void SetRfProcessor(vtkPlusRfProcessor *)
virtual bool IsTracker() const
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
vtkPlusChannel * GetChannel() const
PlusStatus RemoveFieldDataSources()
void SetVideoSource(vtkPlusDataSource *aSource)
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
ChannelContainer OutputChannels
virtual PlusStatus Reset()
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
PlusStatus GetVideoSource(vtkPlusDataSource *&aVideoSource) const
ChannelContainer::iterator ChannelContainerIterator
Definition: vtkPlusDevice.h:36
vtkPlusDevice * GetOwnerDevice() const
PlusStatus AddFieldDataSource(vtkPlusDataSource *aSource)
virtual bool IsResettable()
Interface to a 3D positioning tool, video source, or generalized data stream.