PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusDataCollector.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 // Local includes
8 #include "PlusConfigure.h"
9 #include "vtkPlusBuffer.h"
10 #include "vtkPlusChannel.h"
11 #include "vtkPlusDataCollector.h"
12 #include "vtkPlusDataSource.h"
13 #include "vtkPlusDevice.h"
14 #include "vtkPlusDeviceFactory.h"
15 #include "vtkPlusSavedDataSource.h"
16 
17 // vtkAddon includes
18 #include <vtkStreamingVolumeCodecFactory.h>
19 
20 // IGSIO includes
21 #include <igsioTrackedFrame.h>
22 #include <vtkIGSIOTrackedFrameList.h>
23 #if defined PLUS_USE_VP9
24  #include <vtkVP9VolumeCodec.h>
25 #endif
26 
27 // STD includes
28 #include <set>
29 
30 // VTK includes
31 #include <vtkObjectFactory.h>
32 #include <vtkXMLDataElement.h>
33 #include <vtksys/SystemTools.hxx>
34 
35 //----------------------------------------------------------------------------
36 
38 
39 //----------------------------------------------------------------------------
41  : vtkObject()
42  , StartupDelaySec(0.0)
43  , DeviceFactory(vtkSmartPointer<vtkPlusDeviceFactory>::New())
44  , Connected(false)
45  , Started(false)
46 {
47  vtkStreamingVolumeCodecFactory* factory = vtkStreamingVolumeCodecFactory::GetInstance();
48 #if defined PLUS_USE_VP9
49  vtkSmartPointer<vtkVP9VolumeCodec> vp9Codec = vtkSmartPointer<vtkVP9VolumeCodec>::New();
50  factory->RegisterStreamingCodec(vp9Codec);
51 #endif
52 }
53 
54 //----------------------------------------------------------------------------
56 {
57  LOG_TRACE("vtkPlusDataCollector::~vtkPlusDataCollector()");
58  if (this->Started)
59  {
60  this->Stop();
61  }
62  if (this->Connected)
63  {
64  this->Disconnect();
65  }
66 
67  for (DeviceCollectionIterator it = this->Devices.begin(); it != this->Devices.end(); ++it)
68  {
69  (*it)->Delete();
70  }
71  Devices.clear();
72 }
73 
74 //----------------------------------------------------------------------------
76 {
77  LOG_TRACE("vtkPlusDataCollector::ReadConfiguration()");
78 
79  if (aConfig == NULL)
80  {
81  LOG_ERROR("Unable to read configuration");
82  return PLUS_FAIL;
83  }
84 
85  if (this->Devices.size() > 0)
86  {
87  // ReadConfiguration is being called for the n-th time
88  LOG_ERROR("Repeated calls of vtkPlusDataCollector::ReadConfiguration are not permitted. Delete the data collector and re-create to connect to a different config file.");
89  return PLUS_FAIL;
90  }
91 
92  vtkXMLDataElement* dataCollectionElement = aConfig->FindNestedElementWithName("DataCollection");
93 
94  if (dataCollectionElement == NULL)
95  {
96  LOG_ERROR("Unable to find data collection element in XML tree!");
97  return PLUS_FAIL;
98  }
99 
100  // Read StartupDelaySec
101  double startupDelaySec(0.0);
102  if (dataCollectionElement->GetScalarAttribute("StartupDelaySec", startupDelaySec))
103  {
104  this->SetStartupDelaySec(startupDelaySec);
105  LOG_DEBUG("StartupDelaySec: " << std::fixed << startupDelaySec);
106  }
107 
108  std::set<std::string> existingDeviceIds;
109 
110  for (int i = 0; i < dataCollectionElement->GetNumberOfNestedElements(); ++i)
111  {
112  vtkXMLDataElement* deviceElement = dataCollectionElement->GetNestedElement(i);
113  if (deviceElement == NULL || STRCASECMP(deviceElement->GetName(), "Device") != 0)
114  {
115  // only process valid Device elements
116  continue;
117  }
118 
119  vtkPlusDevice* device = NULL;
120  const char* deviceId = deviceElement->GetAttribute("Id");
121  if (deviceId == NULL)
122  {
123  LOG_ERROR("Device of type " << (deviceElement->GetAttribute("Type") == NULL ? "UNDEFINED" : deviceElement->GetAttribute("Type")) << " has no Id attribute");
124  return PLUS_FAIL;
125  }
126 
127  if (existingDeviceIds.count(deviceId) > 0)
128  {
129  LOG_ERROR("Multiple devices exist with the same Id: \'" << deviceId << "\'");
130  return PLUS_FAIL;
131  }
132  existingDeviceIds.insert(deviceId);
133 
134  if (DeviceFactory->CreateInstance(deviceElement->GetAttribute("Type"), device, deviceElement->GetAttribute("Id")) == PLUS_FAIL)
135  {
136  LOG_ERROR("Unable to create device: " << deviceElement->GetAttribute("Type"));
137  continue;
138  }
139  device->SetDataCollector(this);
140  if (device->ReadConfiguration(aConfig) != PLUS_SUCCESS)
141  {
142  LOG_ERROR("Failed to read parameters of device: " << deviceElement->GetAttribute("Id") << " (type: " << deviceElement->GetAttribute("Type") << ")");
143  return PLUS_FAIL;
144  }
145  Devices.push_back(device);
146  }
147 
148  if (Devices.size() == 0)
149  {
150  LOG_ERROR("No devices created. Please verify configuration file and any error produced.");
151  return PLUS_FAIL;
152  }
153 
154  // Check output channels (at least one should exist and each id must be unique)
155  std::set<std::string> existingOutputChannelNames;
156  bool outputChannelFound = false;
157  for (DeviceCollectionIterator deviceIt = this->Devices.begin(); deviceIt != this->Devices.end(); ++deviceIt)
158  {
159  for (ChannelContainerConstIterator outputChannelIt = (*deviceIt)->GetOutputChannelsStart(); outputChannelIt != (*deviceIt)->GetOutputChannelsEnd(); ++outputChannelIt)
160  {
161  outputChannelFound = true;
162  const char* outputChannelId = (*outputChannelIt)->GetChannelId();
163  if (outputChannelId)
164  {
165  if (existingOutputChannelNames.count(outputChannelId) > 0)
166  {
167  LOG_ERROR("Same output channel Id is defined at multiple locations: " << outputChannelId);
168  return PLUS_FAIL;
169  }
170  existingOutputChannelNames.insert(outputChannelId);
171  }
172  }
173  }
174 
175  if (!outputChannelFound)
176  {
177  LOG_WARNING("No output channels defined. Unable to locate any for data collection.");
178  }
179 
180  // Connect any and all input streams to their corresponding output streams
181  for (int i = 0; i < dataCollectionElement->GetNumberOfNestedElements(); ++i)
182  {
183  vtkXMLDataElement* deviceElement = dataCollectionElement->GetNestedElement(i);
184  if (deviceElement == NULL || STRCASECMP(deviceElement->GetName(), "Device") != 0)
185  {
186  // not a valid Device element
187  continue;
188  }
189  vtkPlusDevice* thisDevice = NULL;
190  if (this->GetDevice(thisDevice, deviceElement->GetAttribute("Id")) != PLUS_SUCCESS)
191  {
192  LOG_ERROR("Device " << deviceElement->GetAttribute("Id") << " does not exist.");
193  return PLUS_FAIL;
194  }
195  vtkXMLDataElement* inputChannelsElement = deviceElement->FindNestedElementWithName("InputChannels");
196  if (inputChannelsElement == NULL)
197  {
198  // no input channels, nothing to connect
199  continue;
200  }
201  for (int i = 0; i < inputChannelsElement->GetNumberOfNestedElements(); ++i)
202  {
203  vtkXMLDataElement* inputChannelElement = inputChannelsElement->GetNestedElement(i);
204  if (STRCASECMP(inputChannelElement->GetName(), "InputChannel") == 0)
205  {
206  // We have an input channel, lets find it
207  const char* inputChannelId = inputChannelElement->GetAttribute("Id");
208  if (inputChannelId == NULL)
209  {
210  LOG_ERROR("Device " << deviceElement->GetAttribute("Id") << " has an input channel without Id attribute.");
211  return PLUS_FAIL;
212  }
213  vtkPlusChannel* aChannel = NULL;
214  for (DeviceCollectionIterator it = Devices.begin(); it != Devices.end(); ++it)
215  {
216  vtkPlusDevice* device = (*it);
217  if (device->GetOutputChannelByName(aChannel, inputChannelId) == PLUS_SUCCESS)
218  {
219  // Found it!
220  break;
221  }
222  }
223  if (aChannel == NULL)
224  {
225  LOG_ERROR("Device " << deviceElement->GetAttribute("Id") << " is specified to use channel " << inputChannelId << " as input, but an output channel by this Id does not exist");
226  return PLUS_FAIL;
227  }
228  if (thisDevice->AddInputChannel(aChannel) != PLUS_SUCCESS)
229  {
230  LOG_ERROR("Failed to add input channel " << inputChannelId << " to device " << deviceElement->GetAttribute("Id"));
231  return PLUS_FAIL;
232  }
233  }
234  }
235  }
236 
237  for (DeviceCollectionIterator it = this->Devices.begin(); it != this->Devices.end(); ++it)
238  {
239  if ((*it)->NotifyConfigured() != PLUS_SUCCESS)
240  {
241  LOG_ERROR("Device: " << (*it)->GetDeviceId() << " reports incorrect configuration. Please verify configuration.");
242  return PLUS_FAIL;
243  }
244  }
245 
246  return PLUS_SUCCESS;
247 }
248 
249 //----------------------------------------------------------------------------
251 {
252  vtkXMLDataElement* element = vtkPlusConfig::GetInstance()->CreateDeviceSetConfigurationFromFile(fileName);
253 
254  if (element == nullptr)
255  {
256  return PLUS_FAIL;
257  }
258 
261 
262  if (this->ReadConfiguration(element) != PLUS_SUCCESS)
263  {
264  LOG_ERROR("Datacollector failed to read configuration");
265  return PLUS_FAIL;
266  }
267 
268  return PLUS_SUCCESS;
269 }
270 
271 //----------------------------------------------------------------------------
273 {
274  LOG_TRACE("vtkPlusDataCollector::WriteConfiguration()");
275 
276  vtkXMLDataElement* dataCollectionConfig = igsioXmlUtils::GetNestedElementWithName(aConfig, "DataCollection");
277  if (dataCollectionConfig == NULL)
278  {
279  LOG_ERROR("Cannot find DataCollection element in XML tree!");
280  return PLUS_FAIL;
281  }
282 
283  dataCollectionConfig->SetDoubleAttribute("StartupDelaySec", GetStartupDelaySec());
284 
285  PlusStatus status = PLUS_SUCCESS;
286 
287  for (DeviceCollectionConstIterator it = Devices.begin(); it != Devices.end(); ++it)
288  {
289  vtkPlusDevice* device = (*it);
290 
291  if (device->WriteConfiguration(aConfig) != PLUS_SUCCESS)
292  {
293  LOG_ERROR("Failed to save device configuration " << device->GetDeviceId());
294  status = PLUS_FAIL;
295  }
296  }
297 
298  return status;
299 }
300 
301 //----------------------------------------------------------------------------
302 void vtkPlusDataCollector::SetDeviceFactory(vtkSmartPointer<vtkPlusDeviceFactory> factory)
303 {
304  if (factory != nullptr)
305  {
306  this->DeviceFactory = factory;
307  }
308 }
309 
310 //----------------------------------------------------------------------------
312 {
313  return *this->DeviceFactory.Get();
314 }
315 
316 //----------------------------------------------------------------------------
318 {
319  LOG_TRACE("vtkPlusDataCollector::Start()");
320 
321  PlusStatus status = PLUS_SUCCESS;
322 
323  const double startTime = vtkIGSIOAccurateTimer::GetSystemTime();
324 
325  for (DeviceCollectionIterator it = Devices.begin(); it != Devices.end(); ++ it)
326  {
327  vtkPlusDevice* device = *it;
328 
329  if (device->StartRecording() != PLUS_SUCCESS)
330  {
331  LOG_ERROR("Failed to start data acquisition for device " << device->GetDeviceId() << ".");
332  status = PLUS_FAIL;
333  }
334  device->SetStartTime(startTime);
335  }
336 
337  LOG_DEBUG("vtkPlusDataCollector::Start -- wait " << std::fixed << this->StartupDelaySec << " sec for buffer init...");
338 
339  vtkIGSIOAccurateTimer::DelayWithEventProcessing(this->StartupDelaySec);
340 
341  this->Started = true;
342 
343  return status;
344 }
345 
346 //----------------------------------------------------------------------------
348 {
349  LOG_TRACE("vtkPlusDataCollector::Stop()");
350 
351  this->Started = false;
352 
353  return PLUS_SUCCESS;
354 }
355 
356 //----------------------------------------------------------------------------
358 {
359  LOG_TRACE("vtkPlusDataCollector::Connect()");
360 
361  PlusStatus status = PLUS_SUCCESS;
362 
363  for (DeviceCollectionIterator it = Devices.begin(); it != Devices.end(); ++ it)
364  {
365  vtkPlusDevice* device = *it;
366 
367  if (device->Connect() != PLUS_SUCCESS)
368  {
369  LOG_ERROR("Unable to connect device: " << device->GetDeviceId() << ".");
370  status = PLUS_FAIL;
371  }
372  }
373 
374  if (status != PLUS_SUCCESS)
375  {
376  this->Disconnect();
377  status = PLUS_FAIL;
378  }
379 
380  if (this->SetLoopTimes() != PLUS_SUCCESS)
381  {
382  LOG_WARNING("Failed to set loop times!");
383  status = PLUS_FAIL;
384  }
385 
386  this->Connected = (status == PLUS_SUCCESS);
387  return status;
388 }
389 
390 //----------------------------------------------------------------------------
392 {
393  LOG_TRACE("vtkPlusDataCollector::Disconnect()");
394 
395  PlusStatus status = PLUS_SUCCESS;
396 
397  for (DeviceCollectionIterator it = Devices.begin(); it != Devices.end(); ++ it)
398  {
399  vtkPlusDevice* device = *it;
400 
401  if (device->Disconnect() != PLUS_SUCCESS)
402  {
403  LOG_ERROR("Unable to disconnect device: " << device->GetDeviceId() << ".");
404  status = PLUS_FAIL;
405  }
406  }
407 
408  Connected = false;
409  LOG_DEBUG("vtkPlusDataCollector::Disconnect: All devices have been disconnected");
410 
411  return status;
412 }
413 
414 //----------------------------------------------------------------------------
415 void vtkPlusDataCollector::PrintSelf(ostream& os, vtkIndent indent)
416 {
417  LOG_TRACE("vtkPlusDataCollector::PrintSelf()");
418 
419  this->Superclass::PrintSelf(os, indent);
420 
421  for (DeviceCollectionIterator it = Devices.begin(); it != Devices.end(); ++ it)
422  {
423  os << indent << "Device: " << std::endl;
424  (*it)->PrintSelf(os, indent);
425  }
426 }
427 
428 //----------------------------------------------------------------------------
429 PlusStatus vtkPlusDataCollector::GetDevice(vtkPlusDevice*& aDevice, const std::string& aDeviceId) const
430 {
431  LOG_TRACE("vtkPlusDataCollector::GetDevice( aDevice, " << aDeviceId << ")");
432 
433  for (DeviceCollectionConstIterator it = Devices.begin(); it != Devices.end(); ++it)
434  {
435  vtkPlusDevice* device = (*it);
436 
437  if (device->GetDeviceId() == aDeviceId)
438  {
439  aDevice = device;
440  return PLUS_SUCCESS;
441  }
442  }
443 
444  return PLUS_FAIL;
445 }
446 
447 //----------------------------------------------------------------------------
449 {
450  LOG_TRACE("vtkPlusDataCollector::GetDevices()");
451 
452  OutVector.clear();
453 
454  for (DeviceCollectionConstIterator it = Devices.begin(); it != Devices.end(); ++it)
455  {
456  OutVector.push_back(*it);
457  }
458 
459  return OutVector.size() > 0 ? PLUS_SUCCESS : PLUS_FAIL;
460 }
461 
462 //----------------------------------------------------------------------------
464 {
465  return this->Started;
466 }
467 
468 //----------------------------------------------------------------------------
470 {
471  return this->Connected;
472 }
473 
474 //----------------------------------------------------------------------------
476 {
477  LOG_TRACE("vtkPlusDataCollector::DumpBuffersToDirectory(" << aDirectory << ")");
478 
479  // Assemble file names
480  std::string dateAndTime = vtksys::SystemTools::GetCurrentDateTime("%Y%m%d_%H%M%S");
481 
482  for (DeviceCollectionIterator it = this->Devices.begin(); it != this->Devices.end(); ++it)
483  {
484  vtkPlusDevice* device = *it;
485 
486  std::string outputDeviceBufferSequenceFileName = vtkPlusConfig::GetInstance()->GetOutputPath(std::string("BufferDump_") + device->GetDeviceId() + "_" + dateAndTime + ".nrrd");
487 
488  LOG_INFO("Write device buffer to " << outputDeviceBufferSequenceFileName);
489  vtkPlusDataSource* aSource(NULL);
490  for (ChannelContainerIterator chanIt = device->GetOutputChannelsStart(); chanIt != device->GetOutputChannelsEnd(); ++chanIt)
491  {
492  if ((*chanIt)->GetVideoSource(aSource) != PLUS_SUCCESS)
493  {
494  LOG_ERROR("Unable to retrieve the video source in the device.");
495  return PLUS_FAIL;
496  }
497  aSource->WriteToSequenceFile(outputDeviceBufferSequenceFileName.c_str(), false);
498  }
499  }
500 
501  return PLUS_SUCCESS;
502 }
503 
504 //----------------------------------------------------------------------------
506 {
507  return this->Devices.begin();
508 }
509 
510 //----------------------------------------------------------------------------
512 {
513  return this->Devices.end();
514 }
515 
516 //----------------------------------------------------------------------------
517 PlusStatus vtkPlusDataCollector::GetTrackingData(vtkPlusChannel* aRequestedChannel, double& aTimestampFrom, vtkIGSIOTrackedFrameList* aTrackedFrameList)
518 {
519  LOG_TRACE("vtkPlusDataCollector::GetTrackingData(" << aRequestedChannel->GetChannelId() << ", " << aTimestampFrom << ")");
520 
521  if (aTrackedFrameList == NULL)
522  {
523  LOG_ERROR("Unable to get tracked frame list - output tracked frame list is NULL");
524  return PLUS_FAIL;
525  }
526 
527  // If the buffer is empty then don't display an error just return without adding any items to the output tracked frame list
528  if (!aRequestedChannel->GetTrackingEnabled())
529  {
530  LOG_ERROR("Unable to get tracked frame list - Tracking is not enabled");
531  return PLUS_FAIL;
532  }
533 
534  // Get the first tool, transforms will be returned at the timestamps of this first tool
535  vtkPlusDataSource* firstActiveTool = NULL;
536  if (aRequestedChannel->GetOwnerDevice()->GetFirstActiveTool(firstActiveTool) != PLUS_SUCCESS)
537  {
538  LOG_ERROR("Unable to get tracked frame list - there is no active tool!");
539  return PLUS_FAIL;
540  }
541 
542  if (firstActiveTool->GetNumberOfItems() == 0)
543  {
544  LOG_DEBUG("vtkPlusDataCollector::GetTrackingData: the tracking buffer is empty, no items will be returned");
545  return PLUS_SUCCESS;
546  }
547 
548  PlusStatus status = PLUS_SUCCESS;
549  BufferItemUidType oldestItemUid = firstActiveTool->GetOldestItemUidInBuffer();
550  BufferItemUidType latestItemUid = firstActiveTool->GetLatestItemUidInBuffer();
551  for (BufferItemUidType itemUid = oldestItemUid; itemUid <= latestItemUid; ++itemUid)
552  {
553  double itemTimestamp = 0;
554  if (firstActiveTool->GetTimeStamp(itemUid, itemTimestamp) != ITEM_OK)
555  {
556  // probably the buffer item is not available anymore
557  continue;
558  }
559  if (itemTimestamp <= aTimestampFrom)
560  {
561  // this item has been acquired before the requested start time
562  continue;
563  }
564  aTimestampFrom = itemTimestamp;
565  // Get tracked frame from buffer
566  igsioTrackedFrame* trackedFrame = new igsioTrackedFrame;
567  if (aRequestedChannel->GetTrackedFrame(itemTimestamp, *trackedFrame, false /* get tracking data only */) != PLUS_SUCCESS)
568  {
569  LOG_ERROR("Unable to get tracking data by time: " << std::fixed << itemTimestamp);
570  status = PLUS_FAIL;
571  }
572  // Add tracked frame to the list
573  if (aTrackedFrameList->TakeTrackedFrame(trackedFrame, vtkIGSIOTrackedFrameList::SKIP_INVALID_FRAME) != PLUS_SUCCESS)
574  {
575  LOG_ERROR("Unable to add tracking data to the list!");
576  status = PLUS_FAIL;
577  }
578  }
579 
580  return status;
581 }
582 
583 //----------------------------------------------------------------------------
584 PlusStatus vtkPlusDataCollector::GetVideoData(vtkPlusChannel* aRequestedChannel, double& aTimestampFrom, vtkIGSIOTrackedFrameList* aTrackedFrameList)
585 {
586  LOG_TRACE("vtkPlusDataCollector::GetVideoData(" << aRequestedChannel->GetChannelId() << ", " << aTimestampFrom << ")");
587 
588  if (aTrackedFrameList == NULL)
589  {
590  LOG_ERROR("Unable to get tracked frame list - output tracked frmae list is NULL");
591  return PLUS_FAIL;
592  }
593 
594  // If the buffer is empty then don't display an error just return without adding any items to the output tracked frame list
595  vtkPlusDataSource* aSource(NULL);
596  if (aRequestedChannel->GetVideoSource(aSource) == PLUS_SUCCESS && aSource->GetNumberOfItems() == 0)
597  {
598  LOG_DEBUG("vtkPlusDataCollector::GetVideoData: the video buffer is empty, no items will be returned");
599  return PLUS_SUCCESS;
600  }
601 
602  PlusStatus status = PLUS_SUCCESS;
603  BufferItemUidType oldestItemUid = aSource->GetOldestItemUidInBuffer();
604  BufferItemUidType latestItemUid = aSource->GetLatestItemUidInBuffer();
605  for (BufferItemUidType itemUid = oldestItemUid; itemUid <= latestItemUid; ++itemUid)
606  {
607  double itemTimestamp = 0;
608  if (aSource->GetTimeStamp(itemUid, itemTimestamp) != ITEM_OK)
609  {
610  // probably the buffer item is not available anymore
611  continue;
612  }
613  if (itemTimestamp <= aTimestampFrom)
614  {
615  // this item has been acquired before the requested start time
616  continue;
617  }
618  aTimestampFrom = itemTimestamp;
619  // Get tracked frame from buffer
620  igsioTrackedFrame* trackedFrame = new igsioTrackedFrame;
621  StreamBufferItem currentStreamBufferItem;
622  if (aSource->GetStreamBufferItem(itemUid, &currentStreamBufferItem) != ITEM_OK)
623  {
624  LOG_ERROR("Couldn't get video buffer item by frame UID: " << itemUid);
625  delete trackedFrame;
626  return PLUS_FAIL;
627  }
628 
629  // Copy frame
630  trackedFrame->SetImageData(currentStreamBufferItem.GetFrame());
631  trackedFrame->SetTimestamp(itemTimestamp);
632 
633  // Copy all custom fields
634  igsioFieldMapType fieldMap = currentStreamBufferItem.GetFrameFieldMap();
635  for (igsioFieldMapType::const_iterator fieldIterator = fieldMap.begin(); fieldIterator != fieldMap.end(); fieldIterator++)
636  {
637  trackedFrame->SetFrameField(fieldIterator->first, fieldIterator->second.second, fieldIterator->second.first);
638  }
639 
640  // Add tracked frame to the list
641  if (aTrackedFrameList->TakeTrackedFrame(trackedFrame, vtkIGSIOTrackedFrameList::SKIP_INVALID_FRAME) != PLUS_SUCCESS)
642  {
643  LOG_ERROR("Unable to add video data to the list!");
644  status = PLUS_FAIL;
645  }
646  }
647 
648  return status;
649 }
650 
651 //----------------------------------------------------------------------------
653 {
654  LOG_TRACE("vtkPlusDataCollector::SetLoopTimes");
655 
656  double latestLoopStartTime(0);
657  double earliestLoopStopTime(0);
658  bool isLoopStartStopTimeInitialized = false;
659 
660  for (DeviceCollectionIterator it = this->Devices.begin(); it != this->Devices.end(); ++it)
661  {
662  vtkPlusSavedDataSource* savedDataSource = dynamic_cast<vtkPlusSavedDataSource*>(*it);
663  if (savedDataSource == NULL)
664  {
665  // loops are only set for saved data sources
666  continue;
667  }
668  if (!savedDataSource->GetUseOriginalTimestamps())
669  {
670  LOG_DEBUG("The device " << savedDataSource->GetDeviceId() << " does not use original timestamps, therefore synchronization of loop time is not applicable");
671  continue;
672  }
673  double loopStartTime = 0;
674  double loopStopTime = 0;
675  savedDataSource->GetLoopTimeRange(loopStartTime, loopStopTime);
676  if (loopStartTime > latestLoopStartTime || !isLoopStartStopTimeInitialized)
677  {
678  latestLoopStartTime = loopStartTime;
679  }
680  if (loopStopTime < earliestLoopStopTime || !isLoopStartStopTimeInitialized)
681  {
682  earliestLoopStopTime = loopStopTime;
683  }
684  isLoopStartStopTimeInitialized = true;
685  }
686 
687  if (!isLoopStartStopTimeInitialized)
688  {
689  LOG_DEBUG("No saved data source devices were found that use original timestamps, so synchronization of loop times is not performed");
690  return PLUS_SUCCESS;
691  }
692 
693  if (latestLoopStartTime >= earliestLoopStopTime)
694  {
695  LOG_ERROR("Data sets in saved data source devices do not have a common time range. Synchronization of loop times is not possible.");
696  return PLUS_FAIL;
697  }
698 
699  // Set the common loop range for all saved data source devices
700  for (DeviceCollectionIterator it = this->Devices.begin(); it != this->Devices.end(); ++it)
701  {
702  vtkPlusSavedDataSource* savedDataSource = dynamic_cast<vtkPlusSavedDataSource*>(*it);
703  if (savedDataSource == NULL)
704  {
705  // loops are only set for saved data sources
706  continue;
707  }
708  savedDataSource->SetLoopTimeRange(latestLoopStartTime, earliestLoopStopTime);
709  }
710 
711  return PLUS_SUCCESS;
712 }
713 
714 //----------------------------------------------------------------------------
716 {
717  if (aDevice == nullptr)
718  {
719  LOG_ERROR("Null device sent to vtkPlusDataCollector::AddDevice");
720  return PLUS_FAIL;
721  }
722 
723  vtkPlusDevice* device(nullptr);
724  if (GetDevice(device, aDevice->GetDeviceId()) == PLUS_SUCCESS)
725  {
726  LOG_ERROR("Device with ID: " << aDevice->GetDeviceId() << " already exists.");
727  return PLUS_FAIL;
728  }
729 
730  aDevice->SetDataCollector(this);
731  Devices.push_back(aDevice);
732  return PLUS_SUCCESS;
733 }
734 
735 //----------------------------------------------------------------------------
736 PlusStatus vtkPlusDataCollector::GetChannel(vtkPlusChannel*& aChannel, const std::string& aChannelId) const
737 {
738  for (DeviceCollectionConstIterator it = this->Devices.begin(); it != this->Devices.end(); ++it)
739  {
740  if ((*it)->GetOutputChannelByName(aChannel, aChannelId.c_str()) == PLUS_SUCCESS)
741  {
742  return PLUS_SUCCESS;
743  }
744  }
745 
746  aChannel = NULL;
747  return PLUS_FAIL;
748 }
749 
750 //----------------------------------------------------------------------------
752 {
753  aChannel = NULL;
754 
755  if (this->Devices.size() == 0)
756  {
757  LOG_ERROR("Cannot return first device: No devices to return.");
758  return PLUS_FAIL;
759  }
760 
761  for (DeviceCollectionConstIterator it = this->Devices.begin(); it != this->Devices.end(); ++it)
762  {
763  if ((*it)->OutputChannelCount() == 0)
764  {
765  continue;
766  }
767 
768  aChannel = *(*it)->GetOutputChannelsStart();
769  return PLUS_SUCCESS;
770  }
771 
772  return PLUS_FAIL;
773 }
virtual BufferItemUidType GetLatestItemUidInBuffer()
PlusStatus GetDevices(DeviceCollection &OutVector) const
PlusStatus AddInputChannel(vtkPlusChannel *aChannel)
vtkXMLDataElement * CreateDeviceSetConfigurationFromFile(const std::string &aConfigFile)
std::string GetOutputPath(const std::string &subPath)
virtual PlusStatus WriteToSequenceFile(const char *filename, bool useCompression=false)
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
std::vector< vtkPlusDevice * >::const_iterator DeviceCollectionConstIterator
Definition: vtkPlusDevice.h:48
vtkSmartPointer< vtkPlusDeviceFactory > DeviceFactory
virtual ItemStatus GetStreamBufferItem(BufferItemUidType uid, StreamBufferItem *bufferItem)
PlusStatus GetDevice(vtkPlusDevice *&aDevice, const std::string &aDeviceId) const
virtual PlusStatus GetTrackedFrame(double timestamp, igsioTrackedFrame &trackedFrame, bool enableImageData=true)
virtual PlusStatus StartRecording()
igsioStatus PlusStatus
Definition: PlusCommon.h:40
virtual PlusStatus GetVideoData(vtkPlusChannel *aRequestedChannel, double &aTimestamp, vtkIGSIOTrackedFrameList *aTrackedFrameList)
virtual std::string GetDeviceId() const
void SetLoopTimeRange(double loopStartTime, double loopStopTime)
std::vector< vtkPlusDevice * > DeviceCollection
Definition: vtkPlusDevice.h:46
for i
vtkPlusDeviceFactory & GetDeviceFactory()
#define PLUS_FAIL
Definition: PlusCommon.h:43
static vtkPlusConfig * GetInstance()
DeviceCollectionConstIterator GetDeviceConstIteratorBegin() const
PlusStatus GetFirstChannel(vtkPlusChannel *&aChannel) const
igsioFieldMapType GetFrameFieldMap()
PlusStatus GetOutputChannelByName(vtkPlusChannel *&aChannel, const char *aChannelId)
virtual ItemStatus GetTimeStamp(BufferItemUidType uid, double &timestamp)
virtual PlusStatus Disconnect()
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *)
virtual bool GetUseOriginalTimestamps()
virtual PlusStatus SetLoopTimes()
PlusStatus GetFirstActiveTool(vtkPlusDataSource *&aTool) const
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *)
ChannelContainerConstIterator GetOutputChannelsEnd() const
DeviceCollectionConstIterator GetDeviceConstIteratorEnd() const
virtual BufferItemUidType GetOldestItemUidInBuffer()
Manages devices that record image or positional data.
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
ChannelContainerConstIterator GetOutputChannelsStart() const
virtual PlusStatus Connect()
ChannelContainer::const_iterator ChannelContainerConstIterator
Definition: vtkPlusDevice.h:35
PlusStatus ReadConfiguration(vtkXMLDataElement *aConfig)
void GetLoopTimeRange(double &loopStartTime, double &loopStopTime)
virtual double GetStartupDelaySec()
void SetDeviceFactory(vtkSmartPointer< vtkPlusDeviceFactory > factory)
virtual char * GetChannelId()
vtkStandardNewMacro(vtkPlusDataCollector)
PlusStatus GetTrackingData(vtkPlusChannel *aRequestedChannel, double &aTimestampFrom, vtkIGSIOTrackedFrameList *aTrackedFrameList)
igsioVideoFrame & GetFrame()
PlusStatus WriteConfiguration(vtkXMLDataElement *aConfig)
virtual void SetStartupDelaySec(double)
bool GetTrackingEnabled() const
Factory class of supported devices.
Class for providing VTK video input interface from sequence fileAttributes:
virtual void SetDataCollector(vtkPlusDataCollector *_arg)
std::vector< vtkPlusDevice * >::iterator DeviceCollectionIterator
Definition: vtkPlusDevice.h:47
PlusStatus AddDevice(vtkPlusDevice *aDevice)
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
virtual void SetStartTime(double startTime)
void SetDeviceSetConfigurationFileName(const std::string &aFilePath)
PlusStatus GetChannel(vtkPlusChannel *&aChannel, const std::string &aChannelId) const
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
PlusStatus GetVideoSource(vtkPlusDataSource *&aVideoSource) const
ChannelContainer::iterator ChannelContainerIterator
Definition: vtkPlusDevice.h:36
unsigned long long BufferItemUidType
vtkPlusDevice * GetOwnerDevice() const
PlusStatus DumpBuffersToDirectory(const char *aDirectory)
void SetDeviceSetConfigurationData(vtkXMLDataElement *deviceSetConfigurationData)
virtual int GetNumberOfItems()
Interface to a 3D positioning tool, video source, or generalized data stream.