PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusChannel.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 #ifdef PLUS_RENDERING_ENABLED
10 #include "PlusPlotter.h"
11 #endif
12 #include "vtkPlusBuffer.h"
13 #include "vtkPlusChannel.h"
14 #include "vtkPlusDataSource.h"
15 #include "vtkPlusHTMLGenerator.h"
16 #include "vtkIGSIOTrackedFrameList.h"
17 
18 // VTK includes
19 #include <vtkImageData.h>
20 #include <vtkMatrix4x4.h>
21 #include <vtkObjectFactory.h>
22 #include <vtkTable.h>
23 
24 //----------------------------------------------------------------------------
25 
27 
28 //----------------------------------------------------------------------------
29 // If a frame cannot be retrieved from the device buffers (because it was overwritten by new frames)
30 // then we skip a SAMPLING_SKIPPING_MARGIN_SEC long period to allow the application to catch up.
31 // This time should be long enough to comfortably retrieve a frame from the buffer.
32 static const double SAMPLING_SKIPPING_MARGIN_SEC = 0.1;
33 
34 //----------------------------------------------------------------------------
36  : VideoSource(NULL)
37  , OwnerDevice(NULL)
38  , ChannelId(NULL)
39  , RfProcessor(NULL)
40  , BlankImage(vtkImageData::New())
41  , SaveRfProcessingParameters(false)
42 {
43  // Default size for brightness frame
44  this->BrightnessFrameSize[0] = 640;
45  this->BrightnessFrameSize[1] = 480;
46  this->BrightnessFrameSize[2] = 1;
47 
48  this->TimestampMasterTool = NULL;
49 
50  // Create a blank image, it will be used as output if frames are not available
51  this->BlankImage->SetExtent(0, this->BrightnessFrameSize[0] - 1, 0, this->BrightnessFrameSize[1] - 1, 0, this->BrightnessFrameSize[2] - 1);
52  this->BlankImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
53 
54  unsigned long memorysize = this->BrightnessFrameSize[0] * this->BrightnessFrameSize[1] * this->BrightnessFrameSize[2] * this->BlankImage->GetScalarSize();
55  memset(this->BlankImage->GetScalarPointer(), 0, memorysize);
56 }
57 
58 //----------------------------------------------------------------------------
60 {
61  this->VideoSource = NULL;
62  this->Tools.clear();
63  this->FieldDataSources.clear();
64 
65  this->SetOwnerDevice(NULL);
66 
67  this->SetChannelId(nullptr);
68 
69  DELETE_IF_NOT_NULL(this->BlankImage);
70 
71  DELETE_IF_NOT_NULL(this->RfProcessor);
72 }
73 
74 //----------------------------------------------------------------------------
75 PlusStatus vtkPlusChannel::ReadConfiguration(vtkXMLDataElement* aChannelElement, bool RequireImageOrientationInChannelConfiguration)
76 {
77  // Read the stream element, build the stream
78  // If there are references to tools, request them from the owner device and keep a reference to them here
79  const char* id = aChannelElement->GetAttribute("Id");
80  if (id == NULL)
81  {
82  LOG_ERROR("No stream id defined. It is required for all streams.");
83  return PLUS_FAIL;
84  }
85  this->SetChannelId(id);
86 
87  if (this->OwnerDevice == NULL)
88  {
89  LOG_ERROR("Channel does not know about its parent device. Unable to configure.");
90  return PLUS_FAIL;
91  }
92 
93  vtkPlusDataSource* aSource = NULL;
94  for (int i = 0; i < aChannelElement->GetNumberOfNestedElements(); i++)
95  {
96  vtkXMLDataElement* aSourceElement = aChannelElement->GetNestedElement(i);
97  if (STRCASECMP(aSourceElement->GetName(), "DataSource") != 0)
98  {
99  // if this is not an data source element, skip it
100  continue;
101  }
102 
103  const char* id = aSourceElement->GetAttribute("Id");
104  if (id == NULL)
105  {
106  LOG_ERROR("No field \"Id\" defined in the source element " << this->GetChannelId() << ". Unable to add it to the channel.");
107  continue;
108  }
109 
110  igsioTransformName idName(id, this->OwnerDevice->GetToolReferenceFrameName());
111  if (this->OwnerDevice->GetDataSource(id, aSource) == PLUS_SUCCESS)
112  {
113  if (aSource->GetType() == DATA_SOURCE_TYPE_TOOL)
114  {
115  this->Tools[aSource->GetId()] = aSource;
116  }
117  else
118  {
119  this->FieldDataSources[aSource->GetId()] = aSource;
120  }
121  }
122  else if (this->OwnerDevice->GetDataSource(idName.GetTransformName().c_str(), aSource) == PLUS_SUCCESS)
123  {
124  this->Tools[aSource->GetId()] = aSource;
125  }
126  else
127  {
128  LOG_ERROR("Unable to find data source with Id=\'" << id << "\'.");
129  return PLUS_FAIL;
130  }
131  }
132 
133  if (aChannelElement->GetAttribute("VideoDataSourceId") != NULL && this->OwnerDevice->GetVideoSource(aChannelElement->GetAttribute("VideoDataSourceId"), aSource) == PLUS_SUCCESS)
134  {
135  this->VideoSource = aSource;
136  }
137  else if (aChannelElement->GetAttribute("VideoDataSourceId") != NULL)
138  {
139  LOG_ERROR("Unable to find video data source that matches Id: " << aChannelElement->GetAttribute("VideoDataSourceId"));
140  return PLUS_FAIL;
141  }
142 
143  vtkXMLDataElement* rfElement = aChannelElement->FindNestedElementWithName(vtkPlusRfProcessor::GetRfProcessorTagName());
144  if (rfElement != NULL)
145  {
147  this->RfProcessor->ReadConfiguration(rfElement);
148  this->SaveRfProcessingParameters = true;
149  }
150  else
151  {
152  if (this->RfProcessor)
153  {
154  this->RfProcessor->Delete();
155  this->RfProcessor = NULL;
156  }
157  }
158 
159  this->CustomAttributes.clear();
160  for (int i = 0; i < aChannelElement->GetNumberOfNestedElements(); i++)
161  {
162  vtkXMLDataElement* attrElement = aChannelElement->GetNestedElement(i);
163  if (STRCASECMP(attrElement->GetName(), "Attribute") != 0)
164  {
165  continue;
166  }
167  const char* id = attrElement->GetAttribute("Id");
168  if (id == NULL)
169  {
170  LOG_ERROR("No idea in channel attribute for channel " << this->GetChannelId());
171  continue;
172  }
173  const char* value = attrElement->GetCharacterData();
174  if (value == NULL)
175  {
176  LOG_ERROR("No value set for attribute: " << id);
177  continue;
178  }
179  std::string strId(id);
180  this->CustomAttributes[strId] = std::string(value);
181  }
182 
183  return PLUS_SUCCESS;
184 }
185 
186 //----------------------------------------------------------------------------
187 PlusStatus vtkPlusChannel::WriteConfiguration(vtkXMLDataElement* aChannelElement)
188 {
189  aChannelElement->SetAttribute("Id", this->GetChannelId());
190 
191  for (int i = 0; i < aChannelElement->GetNumberOfNestedElements(); i++)
192  {
193  vtkXMLDataElement* element = aChannelElement->GetNestedElement(i);
194  if (STRCASECMP(element->GetName(), "DataSource") != 0)
195  {
196  continue;
197  }
198  bool isEqual(false);
199  if (igsioCommon::XML::SafeCheckAttributeValueInsensitive(*element, "Type", vtkPlusDataSource::DATA_SOURCE_TYPE_VIDEO_TAG, isEqual) == PLUS_SUCCESS && isEqual)
200  {
201  if (this->HasVideoSource())
202  {
203  this->VideoSource->WriteConfiguration(element);
204  }
205  }
206  else if (igsioCommon::XML::SafeCheckAttributeValueInsensitive(*element, "Type", vtkPlusDataSource::DATA_SOURCE_TYPE_TOOL_TAG, isEqual) == PLUS_SUCCESS && isEqual)
207  {
208  vtkPlusDataSource* aTool = NULL;
209  if (element->GetAttribute("Id") == NULL || this->GetTool(aTool, element->GetAttribute("Id")) != PLUS_SUCCESS)
210  {
211  LOG_ERROR("Unable to retrieve tool when saving config.");
212  return PLUS_FAIL;
213  }
214  aTool->WriteCompactConfiguration(element);
215  }
216  else if (igsioCommon::XML::SafeCheckAttributeValueInsensitive(*element, "Type", vtkPlusDataSource::DATA_SOURCE_TYPE_FIELDDATA_TAG, isEqual) == PLUS_SUCCESS && isEqual)
217  {
218  vtkPlusDataSource* aSource = NULL;
219  if (element->GetAttribute("Id") == NULL || this->GetFieldDataSource(aSource, element->GetAttribute("Id")) != PLUS_SUCCESS)
220  {
221  LOG_ERROR("Unable to retrieve field data source when saving config.");
222  return PLUS_FAIL;
223  }
224  aSource->WriteCompactConfiguration(element);
225  }
226  }
227 
228  if (this->SaveRfProcessingParameters)
229  {
230  vtkXMLDataElement* rfElement = aChannelElement->FindNestedElementWithName("RfProcessing");
231  this->RfProcessor->WriteConfiguration(rfElement);
232  }
233 
234  return PLUS_SUCCESS;
235 }
236 
237 //----------------------------------------------------------------------------
238 PlusStatus vtkPlusChannel::GetTool(vtkPlusDataSource*& aTool, const std::string& toolSourceId)
239 {
240  if (toolSourceId.empty())
241  {
242  LOG_ERROR("vtkPlusChannel::GetTool failed: toolSourceId is invalid");
243  return PLUS_FAIL;
244  }
245 
246  for (DataSourceContainerIterator it = this->Tools.begin(); it != this->Tools.end(); ++it)
247  {
248  if (toolSourceId == it->second->GetId())
249  {
250  aTool = it->second;
251  return PLUS_SUCCESS;
252  }
253  }
254 
255  return PLUS_FAIL;
256 }
257 
258 //----------------------------------------------------------------------------
260 {
261  if (portName.empty())
262  {
263  LOG_ERROR("vtkPlusChannel::GetToolByPortName failed: portName is invalid");
264  return PLUS_FAIL;
265  }
266 
267  for (DataSourceContainerIterator it = this->Tools.begin(); it != this->Tools.end(); ++it)
268  {
269  if (portName == it->second->GetPortName())
270  {
271  aTool = it->second;
272  return PLUS_SUCCESS;
273  }
274  }
275 
276  return PLUS_FAIL;
277 }
278 
279 //----------------------------------------------------------------------------
281 {
282  if (aTool == NULL)
283  {
284  LOG_ERROR("Trying to add null tool to channel.");
285  return PLUS_FAIL;
286  }
287 
288  for (DataSourceContainerConstIterator it = this->Tools.begin(); it != this->Tools.end(); ++it)
289  {
290  if (it->second == aTool)
291  {
292  // tool has been already added
293  return PLUS_SUCCESS;
294  }
295  }
296 
297  this->Tools[aTool->GetId()] = aTool;
298  this->Tools[aTool->GetId()]->Register(this);
299 
300  if (this->TimestampMasterTool == NULL)
301  {
302  // the first added tool will be used as master tool
303  // (the first item in the std::map is not the first added tool but depends on the source ID)
304  this->TimestampMasterTool = aTool;
305  }
306 
307  return PLUS_SUCCESS;
308 }
309 
310 //----------------------------------------------------------------------------
311 PlusStatus vtkPlusChannel::RemoveTool(const std::string& toolSourceId)
312 {
313  if (toolSourceId.empty())
314  {
315  LOG_ERROR("vtkPlusChannel::RemoveTool failed: toolSourceId is invalid");
316  return PLUS_FAIL;
317  }
318 
319  for (DataSourceContainerIterator it = this->Tools.begin(); it != this->Tools.end(); ++it)
320  {
321  if (it->second->GetId() == toolSourceId)
322  {
323  this->Tools.erase(it);
324  if (this->TimestampMasterTool == it->second)
325  {
326  // the master tool has been deleted
327  this->TimestampMasterTool = NULL;
328  }
329  return PLUS_SUCCESS;
330  }
331  }
332 
333  return PLUS_FAIL;
334 }
335 
336 //----------------------------------------------------------------------------
338 {
339  this->Tools.clear();
340 
341  return PLUS_SUCCESS;
342 }
343 
344 //----------------------------------------------------------------------------
346 {
347  if (aSource == NULL)
348  {
349  LOG_ERROR("Trying to add null field data source to channel.");
350  return PLUS_FAIL;
351  }
352 
353  for (DataSourceContainerConstIterator it = this->FieldDataSources.begin(); it != this->FieldDataSources.end(); ++it)
354  {
355  if (it->second == aSource)
356  {
357  // source has been already added
358  return PLUS_SUCCESS;
359  }
360  }
361 
362  this->FieldDataSources[aSource->GetId()] = aSource;
363  this->FieldDataSources[aSource->GetId()]->Register(this);
364 
365  return PLUS_SUCCESS;
366 }
367 
368 //----------------------------------------------------------------------------
370 {
371  if (sourceId.empty())
372  {
373  LOG_ERROR("vtkPlusChannel::RemoveFieldDataSource failed: sourceId is invalid");
374  return PLUS_FAIL;
375  }
376 
377  for (DataSourceContainerIterator it = this->FieldDataSources.begin(); it != this->FieldDataSources.end(); ++it)
378  {
379  if (it->second->GetId() == sourceId)
380  {
381  this->FieldDataSources.erase(it);
382  return PLUS_SUCCESS;
383  }
384  }
385 
386  return PLUS_FAIL;
387 }
388 
389 //----------------------------------------------------------------------------
390 PlusStatus vtkPlusChannel::GetFieldDataSource(vtkPlusDataSource*& aSource, const std::string& sourceId)
391 {
392  if (sourceId.empty())
393  {
394  LOG_ERROR("vtkPlusChannel::GetFieldDataSource failed: sourceId is invalid");
395  return PLUS_FAIL;
396  }
397 
398  for (DataSourceContainerIterator it = this->FieldDataSources.begin(); it != this->FieldDataSources.end(); ++it)
399  {
400  if (sourceId == it->second->GetId())
401  {
402  aSource = it->second;
403  return PLUS_SUCCESS;
404  }
405  }
406 
407  return PLUS_FAIL;
408 }
409 
410 //----------------------------------------------------------------------------
412 {
413  this->FieldDataSources.clear();
414 
415  return PLUS_SUCCESS;
416 }
417 
418 //----------------------------------------------------------------------------
420 {
421  for (DataSourceContainerIterator it = this->Tools.begin(); it != this->Tools.end(); ++it)
422  {
423  it->second->Clear();
424  }
425  this->TimestampMasterTool = NULL;
426  if (this->VideoSource != NULL)
427  {
428  this->VideoSource->Clear();
429  }
430  for (DataSourceContainerIterator it = this->FieldDataSources.begin(); it != this->FieldDataSources.end(); ++it)
431  {
432  it->second->Clear();
433  }
434  return PLUS_SUCCESS;
435 }
436 
437 //----------------------------------------------------------------------------
439 {
440  aTimestamp = 0;
441 
442  if (this->HasVideoSource())
443  {
444  if (this->VideoSource->GetLatestTimeStamp(aTimestamp) != ITEM_OK)
445  {
446  LOG_ERROR("Unable to retrieve latest timestamp from the video source buffer.");
447  }
448  }
449 
451  {
452  vtkPlusDataSource* aTool = it->second;
453  double timestamp;
454  if (aTool->GetLatestTimeStamp(timestamp) == ITEM_OK)
455  {
456  if (timestamp > aTimestamp)
457  {
458  aTimestamp = timestamp;
459  }
460  }
461  }
462 
464  {
465  vtkPlusDataSource* aSource = it->second;
466  double timestamp;
467  if (aSource->GetLatestTimeStamp(timestamp) == ITEM_OK)
468  {
469  if (timestamp > aTimestamp)
470  {
471  aTimestamp = timestamp;
472  }
473  }
474  }
475 
476  return aTimestamp != 0 ? PLUS_SUCCESS : PLUS_FAIL;
477 }
478 
479 
480 //----------------------------------------------------------------------------
481 void vtkPlusChannel::ShallowCopy(vtkDataObject* otherObject)
482 {
483  if (otherObject == NULL)
484  {
485  return;
486  }
487 
488  vtkPlusChannel* channel = dynamic_cast<vtkPlusChannel*>(otherObject);
489  if (channel == NULL)
490  {
491  return;
492  }
493 
494  return this->ShallowCopy(*channel);
495 }
496 
497 //----------------------------------------------------------------------------
499 {
500  this->Clear();
501 
502  vtkPlusDataSource* aSource = NULL;
503  if (aChannel.HasVideoSource() && aChannel.GetVideoSource(aSource))
504  {
505  this->VideoSource = aSource;
506  }
507  for (DataSourceContainerConstIterator it = aChannel.GetToolsStartConstIterator(); it != aChannel.GetToolsEndConstIterator(); ++it)
508  {
509  if (this->AddTool(it->second) != PLUS_SUCCESS)
510  {
511  LOG_ERROR("Unable to add a tool when shallow copying a channel.");
512  continue;
513  }
514  }
516  {
517  if (this->AddFieldDataSource(it->second) != PLUS_SUCCESS)
518  {
519  LOG_ERROR("Unable to add a field data source when shallow copying a channel.");
520  continue;
521  }
522  }
523 }
524 
525 //----------------------------------------------------------------------------
527 {
528  this->VideoSource = aSource;
529 }
530 
531 //----------------------------------------------------------------------------
532 PlusStatus vtkPlusChannel::GetTrackedFrame(double timestamp, igsioTrackedFrame& aTrackedFrame, bool enableImageData/*=true*/)
533 {
534  int numberOfErrors(0);
535  double synchronizedTimestamp(0);
536 
537  // Get frame UID
538  if (this->HasVideoSource() && enableImageData)
539  {
540  if (this->VideoSource->GetNumberOfItems() < 1)
541  {
542  LOG_ERROR("Couldn't get tracked frame from video source, frames are not available yet");
543  return PLUS_FAIL;
544  }
545  BufferItemUidType frameUID = 0;
546  ItemStatus status = this->VideoSource->GetItemUidFromTime(timestamp, frameUID);
547  if (status != ITEM_OK)
548  {
549  if (status == ITEM_NOT_AVAILABLE_ANYMORE)
550  {
551  LOG_ERROR("Couldn't get frame UID from time (" << std::fixed << timestamp <<
552  ") - item not available anymore!");
553  }
554  else if (status == ITEM_NOT_AVAILABLE_YET)
555  {
556  LOG_ERROR("Couldn't get frame UID from time (" << std::fixed << timestamp <<
557  ") - item not available yet!");
558  }
559  else
560  {
561  LOG_ERROR("Couldn't get frame UID from time (" << std::fixed << timestamp << ")!");
562  }
563 
564  return PLUS_FAIL;
565  }
566 
567  StreamBufferItem CurrentStreamBufferItem;
568  if (this->VideoSource->GetStreamBufferItem(frameUID, &CurrentStreamBufferItem) != ITEM_OK)
569  {
570  LOG_ERROR("Couldn't get video buffer item by frame UID: " << frameUID);
571  return PLUS_FAIL;
572  }
573 
574  // Copy frame
575  igsioVideoFrame frame = CurrentStreamBufferItem.GetFrame();
576  aTrackedFrame.SetImageData(frame);
577 
578  // Copy all custom fields
579  igsioFieldMapType fieldMap = CurrentStreamBufferItem.GetFrameFieldMap();
580  for (igsioFieldMapType::const_iterator fieldIterator = fieldMap.begin(); fieldIterator != fieldMap.end(); fieldIterator++)
581  {
582  aTrackedFrame.SetFrameField((*fieldIterator).first, (*fieldIterator).second.second, fieldIterator->second.first);
583  }
584 
585  synchronizedTimestamp = CurrentStreamBufferItem.GetTimestamp(this->VideoSource->GetLocalTimeOffsetSec());
586  }
587 
588  if (synchronizedTimestamp == 0)
589  {
590  synchronizedTimestamp = timestamp;
591  }
592 
593  // Add main tool timestamp
594  aTrackedFrame.SetTimestamp(synchronizedTimestamp);
595 
596  for (DataSourceContainerConstIterator it = this->GetToolsStartIterator(); it != this->GetToolsEndIterator(); ++it)
597  {
598  vtkPlusDataSource* aTool = it->second;
599  igsioTransformName toolTransformName(aTool->GetId());
600  if (!toolTransformName.IsValid())
601  {
602  LOG_ERROR("Tool transform name is invalid!");
603  numberOfErrors++;
604  continue;
605  }
606 
607  StreamBufferItem bufferItem;
608  ItemStatus result = aTool->GetStreamBufferItemFromTime(synchronizedTimestamp, &bufferItem, vtkPlusBuffer::INTERPOLATED);
609  if (result != ITEM_OK)
610  {
611  double latestTimestamp(0);
612  if (aTool->GetLatestTimeStamp(latestTimestamp) != ITEM_OK)
613  {
614  LOG_ERROR("Failed to get latest timestamp!");
615  numberOfErrors++;
616  }
617 
618  double oldestTimestamp(0);
619  if (aTool->GetOldestTimeStamp(oldestTimestamp) != ITEM_OK)
620  {
621  LOG_ERROR("Failed to get oldest timestamp!");
622  numberOfErrors++;
623  }
624 
625  LOG_ERROR(aTool->GetId() << ": Failed to get tracker item from buffer by time: " << std::fixed << synchronizedTimestamp << " (Latest timestamp: " << latestTimestamp << " Oldest timestamp: " << oldestTimestamp << ").");
626  numberOfErrors++;
627  continue;
628  }
629 
630  vtkSmartPointer<vtkMatrix4x4> dMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
631  if (bufferItem.GetMatrix(dMatrix) != PLUS_SUCCESS)
632  {
633  LOG_ERROR("Failed to get matrix from buffer item for tool " << aTool->GetId());
634  numberOfErrors++;
635  continue;
636  }
637 
638  if (aTrackedFrame.SetFrameTransform(toolTransformName, dMatrix) != PLUS_SUCCESS)
639  {
640  LOG_ERROR("Failed to set transform for tool " << aTool->GetId());
641  numberOfErrors++;
642  continue;
643  }
644 
645  if (aTrackedFrame.SetFrameTransformStatus(toolTransformName, bufferItem.GetStatus()) != PLUS_SUCCESS)
646  {
647  LOG_ERROR("Failed to set transform status for tool " << aTool->GetId());
648  numberOfErrors++;
649  continue;
650  }
651 
652  // Copy all custom fields
653  igsioFieldMapType fieldMap = bufferItem.GetFrameFieldMap();
654  igsioFieldMapType::iterator fieldIterator;
655  for (igsioFieldMapType::const_iterator fieldIterator = fieldMap.begin(); fieldIterator != fieldMap.end(); fieldIterator++)
656  {
657  aTrackedFrame.SetFrameField(fieldIterator->first, fieldIterator->second.second, fieldIterator->second.first);
658  }
659 
660  synchronizedTimestamp = bufferItem.GetTimestamp(aTool->GetLocalTimeOffsetSec());
661  }
662 
664  {
665  vtkPlusDataSource* aSource = it->second;
666 
667  StreamBufferItem bufferItem;
668  ItemStatus result = aSource->GetStreamBufferItemFromTime(synchronizedTimestamp, &bufferItem, vtkPlusBuffer::CLOSEST_TIME);
669  if (result != ITEM_OK)
670  {
671  double latestTimestamp(0);
672  if (aSource->GetLatestTimeStamp(latestTimestamp) != ITEM_OK)
673  {
674  LOG_ERROR("Failed to get latest timestamp!");
675  numberOfErrors++;
676  }
677 
678  double oldestTimestamp(0);
679  if (aSource->GetOldestTimeStamp(oldestTimestamp) != ITEM_OK)
680  {
681  LOG_ERROR("Failed to get oldest timestamp!");
682  numberOfErrors++;
683  }
684 
685  LOG_ERROR(aSource->GetId() << ": Failed to get tracker item from buffer by time: " << std::fixed << synchronizedTimestamp << " (Latest timestamp: " << latestTimestamp << " Oldest timestamp: " << oldestTimestamp << ").");
686  numberOfErrors++;
687  continue;
688  }
689 
690  // Copy all custom fields
691  igsioFieldMapType fieldMap = bufferItem.GetFrameFieldMap();
692  for (igsioFieldMapType::const_iterator fieldIterator = fieldMap.begin(); fieldIterator != fieldMap.end(); fieldIterator++)
693  {
694  aTrackedFrame.SetFrameField(fieldIterator->first, fieldIterator->second.second, fieldIterator->second.first);
695  }
696 
697  synchronizedTimestamp = bufferItem.GetTimestamp(aSource->GetLocalTimeOffsetSec());
698  }
699 
700  // Copy frame timestamp
701  aTrackedFrame.SetTimestamp(synchronizedTimestamp);
702 
703  return (numberOfErrors == 0 ? PLUS_SUCCESS : PLUS_FAIL);
704 }
705 
706 //----------------------------------------------------------------------------
707 PlusStatus vtkPlusChannel::GetTrackedFrame(igsioTrackedFrame& trackedFrame)
708 {
709  double mostRecentFrameTimestamp(0);
710  RETURN_WITH_FAIL_IF(this->GetMostRecentTimestamp(mostRecentFrameTimestamp) != PLUS_SUCCESS,
711  "Failed to get most recent timestamp from the buffer!");
712 
713  return this->GetTrackedFrame(mostRecentFrameTimestamp, trackedFrame);
714 }
715 
716 //----------------------------------------------------------------------------
717 PlusStatus vtkPlusChannel::GetTrackedFrameList(double& aTimestampOfLastFrameAlreadyGot, vtkIGSIOTrackedFrameList* aTrackedFrameList, int aMaxNumberOfFramesToAdd)
718 {
719  LOG_TRACE("vtkPlusDevice::GetTrackedFrameList(" << aTimestampOfLastFrameAlreadyGot << ", " << aMaxNumberOfFramesToAdd << ")");
720 
721  if (aTrackedFrameList == NULL)
722  {
723  LOG_ERROR("Unable to get tracked frame list - output tracked frame list is NULL!");
724  return PLUS_FAIL;
725  }
726 
727  // If the buffer is empty then don't display an error just return without adding any items to the output tracked frame list
728  if (this->GetVideoDataAvailable())
729  {
730  if (this->VideoSource->GetNumberOfItems() == 0)
731  {
732  LOG_DEBUG("vtkPlusDataCollector::GetTrackedFrameList: the video buffer is empty, no items will be returned");
733  return PLUS_SUCCESS;
734  }
735  }
736 
737  if (this->GetTrackingEnabled())
738  {
739  vtkPlusDataSource* masterTool = NULL;
740  if (this->GetTimestampMasterTool(masterTool) != PLUS_SUCCESS)
741  {
742  LOG_ERROR("Failed to get timestamp master tool");
743  return PLUS_FAIL;
744  }
745  if (masterTool->GetNumberOfItems() == 0)
746  {
747  LOG_DEBUG("vtkPlusDataCollector::GetTrackedFrameList: the tracker buffer is empty, no items will be returned");
748  return PLUS_SUCCESS;
749  }
750  }
751 
752  // Get latest and oldest timestamp
753  double mostRecentTimestamp(0);
754  static vtkIGSIOLogHelper logHelper(60.0, 500000);
755  CUSTOM_RETURN_WITH_FAIL_IF(this->GetMostRecentTimestamp(mostRecentTimestamp) != PLUS_SUCCESS,
756  "Unable to get most recent timestamp!");
757 
758  PlusStatus status = PLUS_SUCCESS;
759  double oldestTimestamp(0);
760  if (this->GetOldestTimestamp(oldestTimestamp) != PLUS_SUCCESS)
761  {
762  LOG_ERROR("Failed to get oldest timestamp from buffer!");
763  return PLUS_FAIL;
764  }
765 
766  // If undefined starting timestamp is specified we assume that the acquisition starts from the most recent frame
767  double timestampFrom = aTimestampOfLastFrameAlreadyGot;
768  if (aTimestampOfLastFrameAlreadyGot == UNDEFINED_TIMESTAMP)
769  {
770  timestampFrom = mostRecentTimestamp;
771  }
772 
773  if (timestampFrom < oldestTimestamp)
774  {
775  LOG_ERROR("Items are requested from " << timestampFrom << ", but the oldest available data is acquired at " << oldestTimestamp);
776  return PLUS_FAIL;
777  }
778 
779  if (aMaxNumberOfFramesToAdd > 0)
780  {
781  if (this->GetVideoDataAvailable())
782  {
783  BufferItemUidType mostRecentVideoUid = 0;
784  if (this->VideoSource->GetItemUidFromTime(mostRecentTimestamp, mostRecentVideoUid) != ITEM_OK)
785  {
786  LOG_ERROR("Failed to get video buffer item by timestamp " << mostRecentTimestamp);
787  return PLUS_FAIL;
788  }
789  BufferItemUidType videoUidFrom = 0;
790  if (this->VideoSource->GetItemUidFromTime(timestampFrom, videoUidFrom) != ITEM_OK)
791  {
792  LOG_ERROR("Failed to get video buffer item by timestamp " << timestampFrom);
793  return PLUS_FAIL;
794  }
795 
796  BufferItemUidType firstVideoUidToAdd = videoUidFrom;
797  if (mostRecentVideoUid - videoUidFrom + 1 > aMaxNumberOfFramesToAdd)
798  {
799  // More frames are requested than the maximum allowed frames to add
800  firstVideoUidToAdd = mostRecentVideoUid - aMaxNumberOfFramesToAdd + 1; // +1: because most recent is needed too
801  }
802  else
803  {
804  LOG_TRACE("Number of frames in the video buffer is less than maxNumberOfFramesToAdd (more data is allowed to be recorded than it was provided by the data sources)");
805  }
806 
807  if (this->VideoSource->GetTimeStamp(firstVideoUidToAdd, timestampFrom) != ITEM_OK)
808  {
809  LOG_ERROR("Failed to get video buffer timestamp from UID: " << firstVideoUidToAdd);
810  return PLUS_FAIL;
811  }
812  }
813  else if (this->GetTrackingEnabled())
814  {
815  vtkPlusDataSource* masterTool = NULL;
816  if (this->GetTimestampMasterTool(masterTool) != PLUS_SUCCESS)
817  {
818  LOG_ERROR("Failed to get tracked frame list - there is no active tool!");
819  return PLUS_FAIL;
820  }
821 
822  BufferItemUidType mostRecentTrackerUid = 0;
823  if (masterTool->GetItemUidFromTime(mostRecentTimestamp, mostRecentTrackerUid) != ITEM_OK)
824  {
825  LOG_ERROR("Failed to get tracked buffer item by timestamp " << mostRecentTimestamp);
826  return PLUS_FAIL;
827  }
828  BufferItemUidType trackerUidFrom = 0;
829  ItemStatus status = masterTool->GetItemUidFromTime(timestampFrom, trackerUidFrom);
830  if (status != ITEM_OK)
831  {
832  switch (status)
833  {
835  LOG_ERROR("Failed to get tracker buffer item by timestamp " << timestampFrom << ". Item not available yet.");
836  break;
838  LOG_ERROR("Failed to get tracker buffer item by timestamp " << timestampFrom << ". Item not available anymore.");
839  break;
840  case ITEM_UNKNOWN_ERROR:
841  default:
842  LOG_ERROR("Failed to get tracker buffer item by timestamp " << timestampFrom);
843  break;
844  }
845  return PLUS_FAIL;
846  }
847 
848  BufferItemUidType firstTrackerUidToAdd = trackerUidFrom;
849  if (mostRecentTrackerUid - trackerUidFrom + 1 > aMaxNumberOfFramesToAdd)
850  {
851  // More frames are requested than the maximum allowed frames to add
852  firstTrackerUidToAdd = mostRecentTrackerUid - aMaxNumberOfFramesToAdd + 1; // +1: because most recent is needed too
853  }
854  else
855  {
856  LOG_TRACE("Number of frames in the tracker buffer is less than maxNumberOfFramesToAdd (more data is allowed to be recorded than it was provided by the data sources)");
857  }
858 
859  if (masterTool->GetTimeStamp(firstTrackerUidToAdd, timestampFrom) != ITEM_OK)
860  {
861  LOG_ERROR("Failed to get tracker buffer timestamp from UID: " << firstTrackerUidToAdd);
862  return PLUS_FAIL;
863  }
864  }
865  else if (this->GetFieldDataEnabled())
866  {
867  vtkPlusDataSource* aSource = this->FieldDataSources.begin()->second;
868 
869  BufferItemUidType mostRecentSourceUid = 0;
870  if (aSource->GetItemUidFromTime(mostRecentTimestamp, mostRecentSourceUid) != ITEM_OK)
871  {
872  LOG_ERROR("Failed to get tracked buffer item by timestamp " << mostRecentTimestamp);
873  return PLUS_FAIL;
874  }
875  BufferItemUidType sourceUidFrom = 0;
876  ItemStatus status = aSource->GetItemUidFromTime(timestampFrom, sourceUidFrom);
877  if (status != ITEM_OK)
878  {
879  switch (status)
880  {
882  LOG_ERROR("Failed to get field buffer item by timestamp " << timestampFrom << ". Item not available yet.");
883  break;
885  LOG_ERROR("Failed to get field buffer item by timestamp " << timestampFrom << ". Item not available anymore.");
886  break;
887  case ITEM_UNKNOWN_ERROR:
888  default:
889  LOG_ERROR("Failed to get field buffer item by timestamp " << timestampFrom);
890  break;
891  }
892  return PLUS_FAIL;
893  }
894 
895  BufferItemUidType firstSourceUidToAdd = sourceUidFrom;
896  if (mostRecentSourceUid - sourceUidFrom + 1 > aMaxNumberOfFramesToAdd)
897  {
898  // More frames are requested than the maximum allowed frames to add
899  firstSourceUidToAdd = mostRecentSourceUid - aMaxNumberOfFramesToAdd + 1; // +1: because most recent is needed too
900  }
901  else
902  {
903  LOG_TRACE("Number of frames in the field buffer is less than maxNumberOfFramesToAdd (more data is allowed to be recorded than it was provided by the data sources)");
904  }
905 
906  if (aSource->GetTimeStamp(firstSourceUidToAdd, timestampFrom) != ITEM_OK)
907  {
908  LOG_ERROR("Failed to get field buffer timestamp from UID: " << firstSourceUidToAdd);
909  return PLUS_FAIL;
910  }
911  }
912  }
913 
914  // Check input frameTimestamp to be in a valid range
915  if (timestampFrom > mostRecentTimestamp)
916  {
917  timestampFrom = mostRecentTimestamp;
918  }
919  else if (timestampFrom < oldestTimestamp)
920  {
921  timestampFrom = oldestTimestamp;
922  }
923 
924  // Determine how many frames to add
925  int numberOfFramesSinceTimestamp = GetNumberOfFramesBetweenTimestamps(timestampFrom, mostRecentTimestamp);
926 
927  int numberOfFramesToAdd = 0;
928  if (aMaxNumberOfFramesToAdd > 0)
929  {
930  numberOfFramesToAdd = std::min(aMaxNumberOfFramesToAdd, numberOfFramesSinceTimestamp);
931  }
932  else
933  {
934  numberOfFramesToAdd = numberOfFramesSinceTimestamp;
935  }
936 
937  LOG_TRACE("Number of added frames: " << numberOfFramesToAdd << " out of " << numberOfFramesSinceTimestamp);
938 
939  // If we couldn't find any frames (or one of the items were invalid)
940  // set the timestamp to the most recent one
941  if (numberOfFramesToAdd == 0)
942  {
943  timestampFrom = mostRecentTimestamp;
944  }
945 
946  for (int i = 0; i < numberOfFramesToAdd; ++i)
947  {
948  // Only add this frame if it has not been already added
949  if (timestampFrom > aTimestampOfLastFrameAlreadyGot || aTimestampOfLastFrameAlreadyGot == UNDEFINED_TIMESTAMP)
950  {
951  // Get tracked frame from buffer
952  igsioTrackedFrame* trackedFrame = new igsioTrackedFrame;
953 
954  if (this->GetTrackedFrame(timestampFrom, *trackedFrame) != PLUS_SUCCESS)
955  {
956  delete trackedFrame;
957  LOG_ERROR("Unable to get tracked frame by time: " << std::fixed << timestampFrom);
958  return PLUS_FAIL;
959  }
960 
961  // Add tracked frame to the list
962  aTimestampOfLastFrameAlreadyGot = trackedFrame->GetTimestamp();
963  if (aTrackedFrameList->TakeTrackedFrame(trackedFrame, vtkIGSIOTrackedFrameList::SKIP_INVALID_FRAME) != PLUS_SUCCESS)
964  {
965  LOG_ERROR("Unable to add tracked frame to the list!");
966  return PLUS_FAIL;
967  }
968  }
969 
970  // Get next timestamp
971  if (this->GetVideoDataAvailable() && i < numberOfFramesToAdd - 1)
972  {
973  BufferItemUidType videoUid(0);
974  if (this->VideoSource->GetItemUidFromTime(timestampFrom, videoUid) != ITEM_OK)
975  {
976  LOG_ERROR("Failed to get video buffer item UID from time: " << std::fixed << timestampFrom);
977  return PLUS_FAIL;
978  }
979 
980  if (videoUid >= this->VideoSource->GetLatestItemUidInBuffer())
981  {
982  LOG_WARNING("Requested video uid (" << videoUid + 1 << ") is not in the buffer yet!");
983  break;
984  }
985 
986  // Get the timestamp of the next item in the buffer
987  if (this->VideoSource->GetTimeStamp(++videoUid, timestampFrom) != ITEM_OK)
988  {
989  LOG_ERROR("Unable to get timestamp from video buffer by UID: " << videoUid);
990  return PLUS_FAIL;
991  }
992  }
993  else if (this->GetTrackingEnabled() && i < numberOfFramesToAdd - 1)
994  {
995  vtkPlusDataSource* masterTool = NULL;
996  if (this->GetTimestampMasterTool(masterTool) != PLUS_SUCCESS)
997  {
998  LOG_ERROR("Failed to get tracked frame list - there is no active tool!");
999  return PLUS_FAIL;
1000  }
1001 
1002  BufferItemUidType trackerUid(0);
1003  if (masterTool->GetItemUidFromTime(timestampFrom, trackerUid) != ITEM_OK)
1004  {
1005  LOG_ERROR("Failed to get tracker buffer item UID from time: " << std::fixed << timestampFrom);
1006  return PLUS_FAIL;
1007  }
1008 
1009  if (trackerUid >= masterTool->GetLatestItemUidInBuffer())
1010  {
1011  LOG_ERROR("Requested tracker uid (" << trackerUid + 1 << ") is not in the buffer yet!");
1012  break;
1013  }
1014 
1015  // Get the timestamp of the next item in the buffer
1016  if (masterTool->GetTimeStamp(++trackerUid, timestampFrom) != ITEM_OK)
1017  {
1018  LOG_WARNING("Unable to get timestamp from tracker buffer by UID: " << trackerUid);
1019  return PLUS_FAIL;
1020  }
1021  }
1022  else if (this->GetFieldDataAvailable() && i < numberOfFramesToAdd - 1)
1023  {
1024  vtkPlusDataSource* firstFieldDataSource = this->FieldDataSources.begin()->second;
1025 
1026  BufferItemUidType fieldUid(0);
1027  if (firstFieldDataSource->GetItemUidFromTime(timestampFrom, fieldUid) != ITEM_OK)
1028  {
1029  LOG_ERROR("Failed to get tracker buffer item UID from time: " << std::fixed << timestampFrom);
1030  return PLUS_FAIL;
1031  }
1032 
1033  if (fieldUid >= firstFieldDataSource->GetLatestItemUidInBuffer())
1034  {
1035  LOG_ERROR("Requested tracker uid (" << fieldUid + 1 << ") is not in the buffer yet!");
1036  break;
1037  }
1038 
1039  // Get the timestamp of the next item in the buffer
1040  if (firstFieldDataSource->GetTimeStamp(++fieldUid, timestampFrom) != ITEM_OK)
1041  {
1042  LOG_WARNING("Unable to get timestamp from field data buffer by UID: " << fieldUid);
1043  return PLUS_FAIL;
1044  }
1045  }
1046  }
1047 
1048  return status;
1049 }
1050 
1051 //----------------------------------------------------------------------------
1052 PlusStatus vtkPlusChannel::GetTrackedFrameListSampled(double& aTimestampOfLastFrameAlreadyGot, double& aTimestampOfNextFrameToBeAdded, vtkIGSIOTrackedFrameList* aTrackedFrameList, double aSamplingPeriodSec, double maxTimeLimitSec/*=-1*/)
1053 {
1054  LOG_TRACE("vtkPlusDataCollector::GetTrackedFrameListSampled: aTimestampOfLastFrameAlreadyGot=" << aTimestampOfLastFrameAlreadyGot << ", aTimestampOfNextFrameToBeAdded=" << aTimestampOfNextFrameToBeAdded << ", aSamplingPeriodSec=" << aSamplingPeriodSec);
1055 
1056  if (aTrackedFrameList == NULL)
1057  {
1058  LOG_ERROR("vtkPlusChannel::GetTrackedFrameListSampled failed: unable to get tracked frame list. Output tracked frame list is NULL.");
1059  return PLUS_FAIL;
1060  }
1061 
1062  double startTimeSec = vtkIGSIOAccurateTimer::GetSystemTime();
1063 
1064  double mostRecentTimestamp(0);
1065  RETURN_WITH_FAIL_IF(this->GetMostRecentTimestamp(mostRecentTimestamp) != PLUS_SUCCESS,
1066  "vtkPlusChannel::GetTrackedFrameListSampled failed: unable to get most recent timestamp. Probably no frames have been acquired yet.");
1067 
1068  PlusStatus status = PLUS_SUCCESS;
1069  // Add frames to input trackedFrameList
1070  for (; aTimestampOfNextFrameToBeAdded <= mostRecentTimestamp; aTimestampOfNextFrameToBeAdded += aSamplingPeriodSec)
1071  {
1072  // If the time that is allowed for adding of frames is expired then stop the processing now
1073  if (maxTimeLimitSec > 0 && vtkIGSIOAccurateTimer::GetSystemTime() - startTimeSec > maxTimeLimitSec)
1074  {
1075  LOG_DEBUG("Reached maximum time that is allowed for sampling frames");
1076  break;
1077  }
1078 
1079  // Make sure the next frame to be added is still in the buffer:
1080  // If the frame will be removed from the buffer really soon, then jump ahead in time (and skip some frames),
1081  // instead of trying to retrieve from the buffer (and then fail because the frame is not available anymore).
1082  double oldestTimestamp = 0;
1083  if (this->GetOldestTimestamp(oldestTimestamp) != PLUS_SUCCESS)
1084  {
1085  LOG_ERROR("vtkPlusChannel::GetTrackedFrameListSampled: Failed to get oldest timestamp from buffer. Probably no frames have been acquired yet.");
1086  return PLUS_FAIL;
1087  }
1088  if (aTimestampOfNextFrameToBeAdded < oldestTimestamp + SAMPLING_SKIPPING_MARGIN_SEC)
1089  {
1090  double newTimestampOfFrameToBeAdded = oldestTimestamp + SAMPLING_SKIPPING_MARGIN_SEC;
1091  LOG_WARNING("vtkPlusChannel::GetTrackedFrameListSampled: Frames in the buffer are not available any more at time: " << std::fixed << aTimestampOfNextFrameToBeAdded << ". Skipping " << newTimestampOfFrameToBeAdded - aTimestampOfNextFrameToBeAdded << " seconds from the recording to catch up. Increase the buffer size or decrease the acquisition rate to avoid this situation.");
1092  aTimestampOfNextFrameToBeAdded = newTimestampOfFrameToBeAdded;
1093  continue;
1094  }
1095 
1096  // Get the closest frame to the timestamp of the next frame to be added
1097  double closestTimestamp = GetClosestTrackedFrameTimestampByTime(aTimestampOfNextFrameToBeAdded);
1098  if (closestTimestamp == UNDEFINED_TIMESTAMP)
1099  {
1100  LOG_ERROR("vtkPlusChannel::GetTrackedFrameListSampled: Failed to get closest timestamp from buffer for the next frame. Probably no frames have been acquired yet.");
1101  return PLUS_FAIL;
1102  }
1103  if (aTimestampOfLastFrameAlreadyGot != UNDEFINED_TIMESTAMP && closestTimestamp <= aTimestampOfLastFrameAlreadyGot)
1104  {
1105  // This frame has been already added. Don't spend time with retrieving this frame, just jump to the next
1106  continue;
1107  }
1108  // Get tracked frame from buffer (actually copies pixel and field data)
1109  igsioTrackedFrame* trackedFrame = new igsioTrackedFrame;
1110  if (GetTrackedFrame(closestTimestamp, *trackedFrame) != PLUS_SUCCESS)
1111  {
1112  LOG_WARNING("vtkPlusChannel::GetTrackedFrameListSampled: Unable retrieve frame from the devices for time: " << std::fixed << aTimestampOfNextFrameToBeAdded << ", probably the item is not available in the buffers anymore. Frames may be lost.");
1113  delete trackedFrame;
1114  continue;
1115  }
1116  aTimestampOfLastFrameAlreadyGot = trackedFrame->GetTimestamp();
1117  // Add tracked frame to the list
1118  if (aTrackedFrameList->TakeTrackedFrame(trackedFrame, vtkIGSIOTrackedFrameList::SKIP_INVALID_FRAME) != PLUS_SUCCESS)
1119  {
1120  LOG_ERROR("vtkPlusChannel::GetTrackedFrameListSampled: Unable to add tracked frame to the list");
1121  status = PLUS_FAIL;
1122  }
1123  }
1124 
1125 
1126  return status;
1127 }
1128 
1129 //----------------------------------------------------------------------------
1131 {
1132  //LOG_TRACE("vtkPlusChannel::GetOldestTimestamp");
1133  ts = 0;
1134 
1135  // ********************* video timestamp **********************
1136  double oldestVideoTimestamp(std::numeric_limits<double>::max());
1137  if (this->GetVideoDataAvailable())
1138  {
1139  if (this->VideoSource->GetOldestTimeStamp(oldestVideoTimestamp) != ITEM_OK)
1140  {
1141  LOG_WARNING("Failed to get oldest timestamp from video buffer!");
1142  return PLUS_FAIL;
1143  }
1144  }
1145 
1146  // ********************* tracker timestamp **********************
1147  double oldestTrackerTimestamp(std::numeric_limits<double>::max());
1148  if (this->GetTrackingEnabled())
1149  {
1150  vtkPlusDataSource* masterTool = NULL;
1151  if (this->GetTimestampMasterTool(masterTool) != PLUS_SUCCESS)
1152  {
1153  LOG_ERROR("Failed to get oldest timestamp from tracker buffer - there is no active tool!");
1154  return PLUS_FAIL;
1155  }
1156 
1157  // Get the oldest valid timestamp from the tracker buffer
1158  if (masterTool->GetOldestTimeStamp(oldestTrackerTimestamp) != ITEM_OK)
1159  {
1160  LOG_WARNING("Unable to get timestamp from default tool tracker buffer");
1161  return PLUS_FAIL;
1162  }
1163  }
1164 
1165  // ********************* field data timestamp *******************
1166  double oldestFieldDataTimestamp(std::numeric_limits<double>::max());
1167  if (this->GetFieldDataEnabled())
1168  {
1169  vtkPlusDataSource* aSource = this->FieldDataSources.begin()->second;
1170 
1171  // Get the oldest valid timestamp from the tracker buffer
1172  if (aSource->GetOldestTimeStamp(oldestFieldDataTimestamp) != ITEM_OK)
1173  {
1174  LOG_WARNING("Unable to get timestamp from default field data buffer");
1175  return PLUS_FAIL;
1176  }
1177  }
1178 
1179  double oldestTimestamp = std::min(std::min(oldestFieldDataTimestamp, oldestTrackerTimestamp), oldestVideoTimestamp);
1180  if (!this->GetVideoDataAvailable())
1181  {
1182  oldestVideoTimestamp = oldestTimestamp;
1183  }
1184  if (!this->GetTrackingEnabled())
1185  {
1186  oldestTrackerTimestamp = oldestTimestamp;
1187  }
1188  if (!this->GetFieldDataEnabled())
1189  {
1190  oldestFieldDataTimestamp = oldestTimestamp;
1191  }
1192 
1193  // If the video timestamp is older (smaller) than the tracker timestamp, then use the earliest video timestamp that comes after the first tracker timestamp
1194  if (oldestVideoTimestamp < oldestTrackerTimestamp)
1195  {
1196  // Get the video timestamp that is closest to the oldest tracker timestamp
1197  BufferItemUidType videoUid(0);
1198  if (this->VideoSource->GetItemUidFromTime(oldestTrackerTimestamp, videoUid) != ITEM_OK)
1199  {
1200  LOG_ERROR("Failed to get video buffer item UID from time: " << std::fixed << oldestVideoTimestamp);
1201  return PLUS_FAIL;
1202  }
1203  if (oldestVideoTimestamp < oldestTrackerTimestamp)
1204  {
1205  // the closest video timestamp is still older (smaller) than the first tracking data,
1206  // so we need the next video timestamp (that should have a timestamp that is larger than the first tracking data)
1207  if (videoUid + 1 > this->VideoSource->GetLatestItemUidInBuffer())
1208  {
1209  // the next video item does not exist, so there is no overlap between the tracking and video data
1210  LOG_ERROR("Failed to get oldest timestamp: no overlap between tracking and video data");
1211  return PLUS_FAIL;
1212  }
1213  if (this->VideoSource->GetTimeStamp(videoUid + 1, oldestVideoTimestamp) != ITEM_OK)
1214  {
1215  LOG_ERROR("Failed to get video buffer timestamp from UID: " << videoUid);
1216  return PLUS_FAIL;
1217  }
1218  if (oldestVideoTimestamp < oldestTrackerTimestamp)
1219  {
1220  LOG_ERROR("Failed to get oldest timestamp: no overlap between tracking and video data");
1221  return PLUS_FAIL;
1222  }
1223  }
1224  }
1225 
1226  // If the video timestamp is older (smaller) than the field data timestamp, then use the earliest video timestamp that comes after the first field data timestamp
1227  if (oldestVideoTimestamp < oldestFieldDataTimestamp)
1228  {
1229  // Get the video timestamp that is closest to the oldest field data timestamp
1230  BufferItemUidType videoUid(0);
1231  if (this->VideoSource->GetItemUidFromTime(oldestFieldDataTimestamp, videoUid) != ITEM_OK)
1232  {
1233  LOG_ERROR("Failed to get video buffer item UID from time: " << std::fixed << oldestVideoTimestamp);
1234  return PLUS_FAIL;
1235  }
1236  if (oldestVideoTimestamp < oldestFieldDataTimestamp)
1237  {
1238  // the closest video timestamp is still older (smaller) than the first tracking data,
1239  // so we need the next video timestamp (that should have a timestamp that is larger than the first tracking data)
1240  if (videoUid + 1 > this->VideoSource->GetLatestItemUidInBuffer())
1241  {
1242  // the next video item does not exist, so there is no overlap between the field data and video data
1243  LOG_ERROR("Failed to get oldest timestamp: no overlap between field data and video data");
1244  return PLUS_FAIL;
1245  }
1246  if (this->VideoSource->GetTimeStamp(videoUid + 1, oldestVideoTimestamp) != ITEM_OK)
1247  {
1248  LOG_ERROR("Failed to get video buffer timestamp from UID: " << videoUid);
1249  return PLUS_FAIL;
1250  }
1251  if (oldestVideoTimestamp < oldestFieldDataTimestamp)
1252  {
1253  LOG_ERROR("Failed to get oldest timestamp: no overlap between field data and video data");
1254  return PLUS_FAIL;
1255  }
1256  }
1257  }
1258 
1259  ts = oldestVideoTimestamp;
1260 
1261  return PLUS_SUCCESS;
1262 }
1263 
1264 //----------------------------------------------------------------------------
1266 {
1267  ts = 0;
1268 
1269  double latestVideoTimestamp(0);
1270  // This can't check for data, only if there is a video source device...
1271  if (this->GetVideoDataAvailable())
1272  {
1273  // Get the most recent timestamp from the buffer
1274  RETURN_WITH_FAIL_IF(this->VideoSource->GetLatestTimeStamp(latestVideoTimestamp) != ITEM_OK,
1275  "Unable to get latest timestamp from video buffer!");
1276  }
1277 
1278  double latestTrackerTimestamp(0); // the latest tracker timestamp that is available for all tools
1279  if (this->GetTrackingEnabled())
1280  {
1281  double latestCommonTrackerTimestamp = 0;
1282  bool mostRecentTrackerTimestampRetrieved = false;
1283  for (DataSourceContainerIterator it = this->Tools.begin(); it != this->Tools.end(); ++it)
1284  {
1285  vtkPlusDataSource* tool = it->second;
1286  if (tool == NULL)
1287  {
1288  LOG_ERROR("Invalid tool " << it->first);
1289  continue;
1290  }
1291  // Get the most recent valid timestamp from the tracker buffer
1292  double latestTrackerTimestampForCurrentTool = 0;
1293  if (tool->GetLatestTimeStamp(latestTrackerTimestampForCurrentTool) != ITEM_OK)
1294  {
1295  LOG_WARNING("Unable to get timestamp from " << it->first << " tool tracker buffer for time: " << latestTrackerTimestampForCurrentTool);
1296  continue;
1297  }
1298  if (!mostRecentTrackerTimestampRetrieved)
1299  {
1300  // initialize with the first tool
1301  latestCommonTrackerTimestamp = latestTrackerTimestampForCurrentTool;
1302  mostRecentTrackerTimestampRetrieved = true;
1303  }
1304  else if (latestTrackerTimestampForCurrentTool < latestCommonTrackerTimestamp)
1305  {
1306  latestCommonTrackerTimestamp = latestTrackerTimestampForCurrentTool;
1307  }
1308  }
1309 
1310  if (!mostRecentTrackerTimestampRetrieved)
1311  {
1312  LOG_ERROR("Failed to get most recent timestamp from all the tracker tools");
1313  return PLUS_FAIL;
1314  }
1315 
1316  // The master tool determines the sampling times, the other tools are interpolated.
1317  vtkPlusDataSource* masterTool = NULL;
1318  if (this->GetTimestampMasterTool(masterTool) != PLUS_SUCCESS)
1319  {
1320  LOG_ERROR("Failed to get most recent timestamp from tracker buffer - there is no active tool");
1321  return PLUS_FAIL;
1322  }
1323 
1324  BufferItemUidType uid = 0;
1325  if (masterTool->GetItemUidFromTime(latestCommonTrackerTimestamp, uid) != ITEM_OK)
1326  {
1327  LOG_ERROR("Failed to get tracker buffer item UID from time: " << std::fixed << latestCommonTrackerTimestamp);
1328  return PLUS_FAIL;
1329  }
1330 
1331  double latestTrackerTimestampForMasterTool = 0;
1332  // Get the most recent valid timestamp from the tracker buffer
1333  if (masterTool->GetTimeStamp(uid, latestTrackerTimestampForMasterTool) != ITEM_OK)
1334  {
1335  LOG_WARNING("Unable to get timestamp from default tool tracker buffer with UID: " << uid);
1336  return PLUS_FAIL;
1337  }
1338 
1339  if (latestTrackerTimestampForMasterTool > latestCommonTrackerTimestamp)
1340  {
1341  // the closest master tracking timestamp is larger than the last common tracking data timestamp,
1342  // so we need the previous master tracker timestamp (that should have a timestamp that is smaller than the latest common timestamp)
1343  if (uid - 1 < masterTool->GetOldestItemUidInBuffer())
1344  {
1345  // the tracker buffer item does not exist, so there is no overlap between the tracking tools
1346  LOG_ERROR("Failed to get most recent timestamp: no time overlap between tracking tools");
1347  return PLUS_FAIL;
1348  }
1349  if (masterTool->GetTimeStamp(uid - 1, latestTrackerTimestampForMasterTool) != ITEM_OK)
1350  {
1351  LOG_ERROR("Failed to get tracker buffer timestamp from UID: " << uid - 1);
1352  return PLUS_FAIL;
1353  }
1354  if (latestTrackerTimestampForMasterTool > latestCommonTrackerTimestamp)
1355  {
1356  LOG_ERROR("Failed to get most recent timestamp: no time overlap between tracking tools data");
1357  return PLUS_FAIL;
1358  }
1359  }
1360 
1361  latestTrackerTimestamp = latestTrackerTimestampForMasterTool;
1362  }
1363 
1364  double latestFieldDataTimestamp(0); // the latest field data timestamp that is available
1365  if (this->GetFieldDataEnabled())
1366  {
1367  double latestCommonTimestamp(0);
1368  bool mostRecentSourceTimestampRetrieved(false);
1369  for (DataSourceContainerIterator it = this->FieldDataSources.begin(); it != this->FieldDataSources.end(); ++it)
1370  {
1371  vtkPlusDataSource* aSource = it->second;
1372  if (aSource == NULL)
1373  {
1374  LOG_ERROR("Invalid data source " << it->first);
1375  continue;
1376  }
1377  // Get the most recent valid timestamp from the field data buffer
1378  double latestTimestampForCurrentSource(0);
1379  if (aSource->GetLatestTimeStamp(latestTimestampForCurrentSource) != ITEM_OK)
1380  {
1381  LOG_WARNING("Unable to get timestamp from " << it->first << " field data buffer for time: " << latestTimestampForCurrentSource);
1382  continue;
1383  }
1384  if (!mostRecentSourceTimestampRetrieved)
1385  {
1386  // initialize with the first field data source
1387  latestCommonTimestamp = latestTimestampForCurrentSource;
1388  mostRecentSourceTimestampRetrieved = true;
1389  }
1390  else if (latestTimestampForCurrentSource < latestCommonTimestamp)
1391  {
1392  latestCommonTimestamp = latestTimestampForCurrentSource;
1393  }
1394  }
1395 
1396  if (!mostRecentSourceTimestampRetrieved)
1397  {
1398  LOG_ERROR("Failed to get most recent timestamp from all the field data sources");
1399  return PLUS_FAIL;
1400  }
1401 
1402  latestFieldDataTimestamp = latestCommonTimestamp;
1403  }
1404 
1405  if (!this->GetVideoDataAvailable())
1406  {
1407  latestVideoTimestamp = std::max(latestTrackerTimestamp, latestFieldDataTimestamp);
1408  }
1409 
1410  if (!this->GetTrackingEnabled())
1411  {
1412  latestTrackerTimestamp = std::max(latestVideoTimestamp, latestFieldDataTimestamp);
1413  }
1414 
1415  if (!this->GetFieldDataEnabled())
1416  {
1417  latestFieldDataTimestamp = std::max(latestVideoTimestamp, latestTrackerTimestamp);;
1418  }
1419 
1420  // If the video timestamp is newer than the tracker timestamp, then use the latest video timestamp that comes before the first tracker timestamp
1421  if (latestVideoTimestamp > latestTrackerTimestamp)
1422  {
1423  // Get the timestamp of the video item that is closest to the latest tracker item
1424  BufferItemUidType videoUid(0);
1425  static vtkIGSIOLogHelper logHelper(60.0, 500000);
1426  CUSTOM_RETURN_WITH_FAIL_IF(this->VideoSource->GetItemUidFromTime(latestTrackerTimestamp, videoUid) != ITEM_OK,
1427  "Failed to get video buffer item UID from time: " << std::fixed << latestVideoTimestamp);
1428  RETURN_WITH_FAIL_IF(this->VideoSource->GetTimeStamp(videoUid, latestVideoTimestamp) != ITEM_OK,
1429  "Failed to get video buffer timestamp from UID: " << videoUid);
1430  if (latestVideoTimestamp > latestTrackerTimestamp)
1431  {
1432  // the closest video timestamp is still larger than the last tracking data,
1433  // so we need the previous video timestamp (that should have a timestamp that is smaller than the first tracking data)
1434  if (videoUid - 1 < this->VideoSource->GetOldestItemUidInBuffer())
1435  {
1436  // the previous video item does not exist, so there is no overlap between the tracking and video data
1437  LOG_ERROR("Failed to get most recent timestamp: no overlap between tracking and video data");
1438  return PLUS_FAIL;
1439  }
1440  if (this->VideoSource->GetTimeStamp(videoUid - 1, latestVideoTimestamp) != ITEM_OK)
1441  {
1442  LOG_ERROR("Failed to get video buffer timestamp from UID: " << videoUid);
1443  return PLUS_FAIL;
1444  }
1445  if (latestVideoTimestamp > latestTrackerTimestamp)
1446  {
1447  LOG_ERROR("Failed to get most recent timestamp: no overlap between tracking and video data");
1448  return PLUS_FAIL;
1449  }
1450  }
1451  }
1452 
1453  // If the video timestamp is newer than the field data timestamp, then use the latest video timestamp that comes before the first field data timestamp
1454  if (latestVideoTimestamp > latestFieldDataTimestamp)
1455  {
1456  // Get the timestamp of the video item that is closest to the latest field data item
1457  BufferItemUidType videoUid(0);
1458  RETURN_WITH_FAIL_IF(this->VideoSource->GetItemUidFromTime(latestFieldDataTimestamp, videoUid) != ITEM_OK,
1459  "Failed to get video buffer item UID from time: " << std::fixed << latestVideoTimestamp);
1460  RETURN_WITH_FAIL_IF(this->VideoSource->GetTimeStamp(videoUid, latestVideoTimestamp) != ITEM_OK,
1461  "Failed to get video buffer timestamp from UID: " << videoUid);
1462  if (latestVideoTimestamp > latestFieldDataTimestamp)
1463  {
1464  // the closest video timestamp is still larger than the last field data,
1465  // so we need the previous video timestamp (that should have a timestamp that is smaller than the first field data)
1466  if (videoUid - 1 < this->VideoSource->GetOldestItemUidInBuffer())
1467  {
1468  // the previous video item does not exist, so there is no overlap between the field data and video data
1469  LOG_ERROR("Failed to get most recent timestamp: no overlap between field and video data");
1470  return PLUS_FAIL;
1471  }
1472  if (this->VideoSource->GetTimeStamp(videoUid - 1, latestVideoTimestamp) != ITEM_OK)
1473  {
1474  LOG_ERROR("Failed to get video buffer timestamp from UID: " << videoUid);
1475  return PLUS_FAIL;
1476  }
1477  if (latestVideoTimestamp > latestFieldDataTimestamp)
1478  {
1479  LOG_ERROR("Failed to get most recent timestamp: no overlap between field and video data");
1480  return PLUS_FAIL;
1481  }
1482  }
1483  }
1484 
1485  ts = latestVideoTimestamp;
1486 
1487  return PLUS_SUCCESS;
1488 }
1489 
1490 //----------------------------------------------------------------------------
1492 {
1493  vtkPlusDataSource* aSource = NULL;
1494  if (this->HasVideoSource() && this->GetVideoSource(aSource) == PLUS_SUCCESS)
1495  {
1496  if (aSource->GetLatestItemHasValidTransformData())
1497  {
1498  return true;
1499  }
1500  }
1501 
1502  // Now check any and all tool buffers
1503  for (DataSourceContainerConstIterator toolIt = this->GetToolsStartConstIterator(); toolIt != this->GetToolsEndConstIterator(); ++toolIt)
1504  {
1505  vtkPlusDataSource* tool = toolIt->second;
1507  {
1508  return true;
1509  }
1510  }
1511 
1512  return false;
1513 }
1514 
1515 //----------------------------------------------------------------------------
1517 {
1518  vtkPlusDataSource* aSource = NULL;
1519  if (this->GetVideoSource(aSource) != PLUS_SUCCESS)
1520  {
1521  return false;
1522  }
1523  return aSource->GetLatestItemHasValidVideoData();
1524 }
1525 
1526 //----------------------------------------------------------------------------
1528 {
1529  vtkPlusDataSource* aSource = NULL;
1530  if (this->HasVideoSource() && this->GetVideoSource(aSource) == PLUS_SUCCESS)
1531  {
1532  if (aSource->GetLatestItemHasValidFieldData())
1533  {
1534  return true;
1535  }
1536  }
1537 
1538  // Now check any and all field data buffers
1540  {
1541  vtkPlusDataSource* aSource = it->second;
1542  if (aSource->GetLatestItemHasValidFieldData())
1543  {
1544  return true;
1545  }
1546  }
1547 
1548  return false;
1549 }
1550 
1551 //----------------------------------------------------------------------------
1553 {
1554  return this->ToolCount() > 0;
1555 }
1556 
1557 //----------------------------------------------------------------------------
1559 {
1560  return this->HasVideoSource();
1561 }
1562 
1563 //----------------------------------------------------------------------------
1565 {
1566  return this->FieldCount() > 0;
1567 }
1568 
1569 //----------------------------------------------------------------------------
1571 {
1572  if (this->TimestampMasterTool == NULL)
1573  {
1574  // the timestamp master tool has not been set, either no tools have been added
1575  // or the timestamp master tool has been deleted
1577  if (dataSourceIt == this->GetToolsEndConstIterator())
1578  {
1579  LOG_ERROR("Failed to get the timestamp master tool - there is no active tool");
1580  return PLUS_FAIL;
1581  }
1582  this->TimestampMasterTool = dataSourceIt->second;
1583  if (this->TimestampMasterTool == NULL)
1584  {
1585  LOG_ERROR("Failed to get the timestamp master tool - the first active tool is invalid");
1586  return PLUS_FAIL;
1587  }
1588  }
1589  aTool = this->TimestampMasterTool;
1590  return PLUS_SUCCESS;
1591 }
1592 
1593 //----------------------------------------------------------------------------
1594 int vtkPlusChannel::GetNumberOfFramesBetweenTimestamps(double aTimestampFrom, double aTimestampTo)
1595 {
1596  int numberOfFrames = 0;
1597 
1598  if (this->GetVideoDataAvailable())
1599  {
1600  BufferItemUidType fromItemUid(0);
1601  if (this->VideoSource->GetItemUidFromTime(aTimestampFrom, fromItemUid) != ITEM_OK)
1602  {
1603  return 0;
1604  }
1605 
1606  BufferItemUidType toItemUid(0);
1607  if (this->VideoSource->GetItemUidFromTime(aTimestampTo, toItemUid) != ITEM_OK)
1608  {
1609  return 0;
1610  }
1611 
1612  numberOfFrames = abs((int)(toItemUid - fromItemUid));
1613  }
1614  else if (this->GetTrackingEnabled())
1615  {
1616  vtkPlusDataSource* masterTool = NULL;
1617  if (this->GetTimestampMasterTool(masterTool) != PLUS_SUCCESS)
1618  {
1619  LOG_ERROR("Failed to get number of frames between timestamps - there is no active tool!");
1620  return PLUS_FAIL;
1621  }
1622 
1623  BufferItemUidType fromItemUid(0);
1624  if (masterTool->GetItemUidFromTime(aTimestampFrom, fromItemUid) != ITEM_OK)
1625  {
1626  return 0;
1627  }
1628 
1629  BufferItemUidType toItemUid(0);
1630  if (masterTool->GetItemUidFromTime(aTimestampTo, toItemUid) != ITEM_OK)
1631  {
1632  return 0;
1633  }
1634 
1635  numberOfFrames = abs((int)(toItemUid - fromItemUid));
1636  }
1637  else if (this->GetFieldDataEnabled())
1638  {
1639  vtkPlusDataSource* firstSource = this->FieldDataSources.begin()->second;
1640 
1641  BufferItemUidType fromItemUid(0);
1642  if (firstSource->GetItemUidFromTime(aTimestampFrom, fromItemUid) != ITEM_OK)
1643  {
1644  return 0;
1645  }
1646 
1647  BufferItemUidType toItemUid(0);
1648  if (firstSource->GetItemUidFromTime(aTimestampTo, toItemUid) != ITEM_OK)
1649  {
1650  return 0;
1651  }
1652 
1653  numberOfFrames = abs((int)(toItemUid - fromItemUid));
1654  }
1655 
1656  return numberOfFrames + 1;
1657 }
1658 
1659 //----------------------------------------------------------------------------
1661 {
1662  if (this->GetVideoDataAvailable())
1663  {
1664  BufferItemUidType uid = 0;
1665  if (this->VideoSource->GetItemUidFromTime(time, uid) != ITEM_OK)
1666  {
1667  return UNDEFINED_TIMESTAMP;
1668  }
1669  double closestTimestamp = UNDEFINED_TIMESTAMP;
1670  if (this->VideoSource->GetTimeStamp(uid, closestTimestamp) != ITEM_OK)
1671  {
1672  return UNDEFINED_TIMESTAMP;
1673  }
1674  return closestTimestamp;
1675  }
1676 
1677  if (this->GetTrackingEnabled())
1678  {
1679  vtkPlusDataSource* masterTool = NULL;
1680  if (this->GetTimestampMasterTool(masterTool) != PLUS_SUCCESS)
1681  {
1682  // there is no active tool
1683  return UNDEFINED_TIMESTAMP;
1684  }
1685  BufferItemUidType uid = 0;
1686  if (masterTool->GetItemUidFromTime(time, uid) != ITEM_OK)
1687  {
1688  return UNDEFINED_TIMESTAMP;
1689  }
1690  double closestTimestamp = UNDEFINED_TIMESTAMP;
1691  if (masterTool->GetTimeStamp(uid, closestTimestamp) != ITEM_OK)
1692  {
1693  return UNDEFINED_TIMESTAMP;
1694  }
1695  return closestTimestamp;
1696  }
1697 
1698  if (this->GetFieldDataEnabled())
1699  {
1700  vtkPlusDataSource* firstSource = this->FieldDataSources.begin()->second;
1701  BufferItemUidType uid = 0;
1702  if (firstSource->GetItemUidFromTime(time, uid) != ITEM_OK)
1703  {
1704  return UNDEFINED_TIMESTAMP;
1705  }
1706  double closestTimestamp = UNDEFINED_TIMESTAMP;
1707  if (firstSource->GetTimeStamp(uid, closestTimestamp) != ITEM_OK)
1708  {
1709  return UNDEFINED_TIMESTAMP;
1710  }
1711  return closestTimestamp;
1712  }
1713 
1714  // neither tracker, nor video, nor field data available
1715  return UNDEFINED_TIMESTAMP;
1716 }
1717 
1718 //----------------------------------------------------------------------------
1720 {
1721  aDim = this->BrightnessFrameSize;
1722 
1723  return PLUS_SUCCESS;
1724 }
1725 
1726 //----------------------------------------------------------------------------
1728 {
1729  vtkImageData* resultImage = this->BlankImage;
1730  if (!this->HasVideoSource())
1731  {
1732  return resultImage;
1733  }
1734 
1735  if (this->VideoSource->GetLatestStreamBufferItem(&this->BrightnessOutputTrackedFrame) != ITEM_OK)
1736  {
1737  LOG_DEBUG("No video data available yet, return blank frame");
1738  }
1739  else if (this->BrightnessOutputTrackedFrame.GetFrame().GetImageType() == US_IMG_BRIGHTNESS)
1740  {
1741  // B-mode image already, just return as is
1742  resultImage = this->BrightnessOutputTrackedFrame.GetFrame().GetImage();
1743  }
1744  else if (this->BrightnessOutputTrackedFrame.GetFrame().GetImageType() == US_IMG_RGB_COLOR)
1745  {
1746  // Color image (Doppler, etc.), just return as is
1747  resultImage = this->BrightnessOutputTrackedFrame.GetFrame().GetImage();
1748  }
1749  else if (this->RfProcessor != NULL)
1750  {
1751  // RF frame, convert to B-mode frame
1752  this->RfProcessor->SetRfFrame(this->BrightnessOutputTrackedFrame.GetFrame().GetImage(), this->BrightnessOutputTrackedFrame.GetFrame().GetImageType());
1753  resultImage = this->RfProcessor->GetBrightnessScanConvertedImage();
1754 
1755  // RF processing parameters were used, so save them into the config file
1756  this->SaveRfProcessingParameters = true;
1757  }
1758  else
1759  {
1760  return NULL;
1761  }
1762 
1763  int* resultExtent = resultImage->GetExtent();
1764  this->BrightnessFrameSize[0] = resultExtent[1] - resultExtent[0] + 1;
1765  this->BrightnessFrameSize[1] = resultExtent[3] - resultExtent[2] + 1;
1766  this->BrightnessFrameSize[2] = resultExtent[5] - resultExtent[4] + 1;
1767 
1768  return resultImage;
1769 }
1770 
1771 //----------------------------------------------------------------------------
1772 PlusStatus vtkPlusChannel::GetCustomAttribute(const std::string& attributeId, std::string& output) const
1773 {
1774  if (this->CustomAttributes.find(attributeId) != this->CustomAttributes.end())
1775  {
1776  output = this->CustomAttributes.find(attributeId)->second;
1777  return PLUS_SUCCESS;
1778  }
1779 
1780  return PLUS_FAIL;
1781 }
1782 
1783 //----------------------------------------------------------------------------
1785 {
1786  for (CustomAttributeMapConstIterator it = this->CustomAttributes.begin(); it != this->CustomAttributes.end(); ++it)
1787  {
1788  output[it->first] = it->second;
1789  }
1790 
1791  return PLUS_SUCCESS;
1792 }
1793 
1794 //----------------------------------------------------------------------------
1795 PlusStatus vtkPlusChannel::SetCustomAttribute(const std::string& attributeId, const std::string& value)
1796 {
1797  std::string tempValue;
1798  if (this->GetCustomAttribute(attributeId, tempValue) == PLUS_SUCCESS)
1799  {
1800  LOG_WARNING("Attribute: " << attributeId << " will be overwritten with value: " << value);
1801  }
1802  this->CustomAttributes[attributeId] = value;
1803 
1804  return PLUS_SUCCESS;
1805 }
1806 
1807 //-----------------------------------------------------------------------------
1809 {
1810 #ifdef PLUS_RENDERING_ENABLED
1811  if (htmlReport == NULL)
1812  {
1813  LOG_ERROR("Caller should define HTML report generator before report generation!");
1814  return PLUS_FAIL;
1815  }
1816 
1817  vtkSmartPointer<vtkTable> timestampReportTable = vtkSmartPointer<vtkTable>::New();
1818 
1819  std::string reportText = std::string("Device: ") + this->GetOwnerDevice()->GetDeviceId() + " - Channel: " + this->GetChannelId();
1820  htmlReport->AddText(reportText.c_str(), vtkPlusHTMLGenerator::H1);
1821 
1822  std::string deviceAndChannelName = std::string(this->GetOwnerDevice()->GetDeviceId()) + "-" + this->GetChannelId();
1823 
1824  int imageSize[2] = {800, 400};
1825 
1826  // Video data
1827  vtkPlusDataSource* videoSource = NULL;
1828  if (this->GetVideoSource(videoSource) == PLUS_SUCCESS && videoSource != NULL)
1829  {
1830  if (videoSource->GetTimeStampReportTable(timestampReportTable) != PLUS_SUCCESS)
1831  {
1832  LOG_ERROR("Failed to get timestamp report table from video buffer!");
1833  return PLUS_FAIL;
1834  }
1835 
1836  std::string reportFile = vtkPlusConfig::GetInstance()->GetOutputPath(vtkPlusConfig::GetInstance()->GetApplicationStartTimestamp() + "-" + deviceAndChannelName + "-VideoBufferTimestamps.txt");
1837  PlusPlotter::WriteTableToFile(*timestampReportTable, reportFile.c_str());
1838 
1839  htmlReport->AddText("Video data", vtkPlusHTMLGenerator::H2);
1840  std::string imageFilePath = htmlReport->AddImageAutoFilename(std::string(deviceAndChannelName + "VideoBufferTimestamps.png").c_str(), "Video Data Acquisition Analysis");
1841  PlusPlotter::WriteLineChartToFile("Frame index", "Timestamp (s)", *timestampReportTable, 0, 1, 2, imageSize, imageFilePath.c_str());
1842 
1843  htmlReport->AddHorizontalLine();
1844  }
1845 
1846  // Tracker tools
1847  for (DataSourceContainerConstIterator it = this->GetToolsStartIterator(); it != this->GetToolsEndIterator(); ++it)
1848  {
1849  vtkPlusDataSource* tool = it->second;
1850 
1851  if (tool->GetTimeStampReportTable(timestampReportTable) != PLUS_SUCCESS)
1852  {
1853  LOG_ERROR("Failed to get timestamp report table from tool '" << tool->GetId() << "' buffer!");
1854  return PLUS_FAIL;
1855  }
1856 
1857  reportText = std::string("Tracking data - ") + tool->GetId();
1858  htmlReport->AddText(reportText.c_str(), vtkPlusHTMLGenerator::H2);
1859  std::string imageFilePath = htmlReport->AddImageAutoFilename(std::string(deviceAndChannelName + "-" + tool->GetId() + "-TrackerBufferTimestamps.png").c_str(), reportText.c_str());
1860  PlusPlotter::WriteLineChartToFile("Frame index", "Timestamp (s)", *timestampReportTable, 0, 1, 2, imageSize, imageFilePath.c_str());
1861 
1862  std::string reportFile = vtkPlusConfig::GetInstance()->GetOutputPath(vtkPlusConfig::GetInstance()->GetApplicationStartTimestamp() + "-" + deviceAndChannelName + "-" + tool->GetId() + "TrackerBufferTimestamps.txt");
1863  PlusPlotter::WriteTableToFile(*timestampReportTable, reportFile.c_str());
1864 
1865  htmlReport->AddHorizontalLine();
1866  }
1867 
1868  // Field data tools
1870  {
1871  vtkPlusDataSource* aSource = it->second;
1872 
1873  if (aSource->GetTimeStampReportTable(timestampReportTable) != PLUS_SUCCESS)
1874  {
1875  LOG_ERROR("Failed to get timestamp report table from source '" << aSource->GetId() << "' buffer!");
1876  return PLUS_FAIL;
1877  }
1878 
1879  reportText = std::string("Field data - ") + aSource->GetId();
1880  htmlReport->AddText(reportText.c_str(), vtkPlusHTMLGenerator::H2);
1881  std::string imageFilePath = htmlReport->AddImageAutoFilename(std::string(deviceAndChannelName + "-" + aSource->GetId() + "-FieldDataBufferTimestamps.png").c_str(), reportText.c_str());
1882  PlusPlotter::WriteLineChartToFile("Frame index", "Timestamp (s)", *timestampReportTable, 0, 1, 2, imageSize, imageFilePath.c_str());
1883 
1884  std::string reportFile = vtkPlusConfig::GetInstance()->GetOutputPath(vtkPlusConfig::GetInstance()->GetApplicationStartTimestamp() + "-" + deviceAndChannelName + "-" + aSource->GetId() + "FieldDataBufferTimestamps.txt");
1885  PlusPlotter::WriteTableToFile(*timestampReportTable, reportFile.c_str());
1886 
1887  htmlReport->AddHorizontalLine();
1888  }
1889 
1890  return PLUS_SUCCESS;
1891 #else
1892  LOG_WARNING("Cannot generate report when VTK_RENDERING_BACKEND is None!");
1893  return PLUS_FAIL;
1894 #endif
1895 }
1896 
1897 //-----------------------------------------------------------------------------
1899 {
1900  if (this->HasVideoSource())
1901  {
1902  vtkPlusDataSource* source(NULL);
1903  this->GetVideoSource(source);
1904  if (source->GetNumberOfItems() <= 0)
1905  {
1906  return false;
1907  }
1908  StreamBufferItem item;
1909  source->GetLatestStreamBufferItem(&item);
1910  int dims[3] = {0, 0, 0};
1911  item.GetFrame().GetImage()->GetDimensions(dims);
1912  if (dims[2] > 1)
1913  {
1914  return true;
1915  }
1916  else
1917  {
1918  return false;
1919  }
1920  }
1921  else
1922  {
1923  return false;
1924  }
1925 }
DataSourceContainer::const_iterator DataSourceContainerConstIterator
static const double SAMPLING_SKIPPING_MARGIN_SEC
virtual BufferItemUidType GetLatestItemUidInBuffer()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *rfElement)
PlusStatus GetDataSource(const char *aSourceId, vtkPlusDataSource *&aSource)
static PlusStatus WriteTableToFile(vtkTable &table, const std::string &filename)
int * channel
Definition: phidget22.h:1303
PlusStatus GetFieldDataSource(vtkPlusDataSource *&aSource, const std::string &sourceId)
ToolStatus GetStatus() const
virtual void AddText(const char *text, HEADINGS h, const char *style=NULL)
bool GetVideoEnabled() const
bool HasVideoSource() const
PlusStatus SetCustomAttribute(const std::string &attributeId, const std::string &value)
static vtkPlusRfProcessor * New()
std::string GetOutputPath(const std::string &subPath)
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *aChannelElement)
virtual void ShallowCopy(vtkDataObject *)
virtual double GetLocalTimeOffsetSec()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *toolElement)
const char * source
Definition: phidget22.h:2461
double * timestamp
Definition: phidget22.h:3432
bool GetVideoDataAvailable()
DataSourceContainerIterator GetToolsStartIterator()
virtual ItemStatus GetStreamBufferItem(BufferItemUidType uid, StreamBufferItem *bufferItem)
static PlusStatus WriteLineChartToFile(const std::string &chartTitle, const std::string &yAxisText, vtkTable &inputTable, int xColumnIndex, int y1ColumnIndex, int y2ColumnIndex, int imageSize[2], const std::string &outputImageFilename)
Definition: PlusPlotter.cxx:58
PlusStatus GetCustomAttribute(const std::string &attributeId, std::string &output) const
PlusStatus GetTool(vtkPlusDataSource *&aTool, const std::string &toolSourceId)
PlusStatus RemoveTool(const std::string &toolSourceId)
CustomAttributeMap::const_iterator CustomAttributeMapConstIterator
StreamBufferItem BrightnessOutputTrackedFrame
virtual PlusStatus GetTrackedFrame(double timestamp, igsioTrackedFrame &trackedFrame, bool enableImageData=true)
PlusStatus GetBrightnessFrameSize(FrameSizeType &aDim)
virtual ~vtkPlusChannel(void)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
DataSourceContainerConstIterator GetToolsEndConstIterator() const
DataSourceContainerIterator GetFieldDataSourcesStartIterator()
std::map< std::string, std::string > CustomAttributeMap
virtual std::string GetDeviceId() const
vtkImageData * GetBrightnessOutput()
virtual PlusStatus Clear()
bool GetTrackingDataAvailable()
vtkPlusDataSource * TimestampMasterTool
DataSourceContainerIterator GetToolsEndIterator()
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *rfElement)
for i
vtkPlusDevice * OwnerDevice
virtual bool GetLatestItemHasValidVideoData()
virtual vtkImageData * GetBrightnessScanConvertedImage()
DataSourceContainerConstIterator GetFieldDataSourcesStartConstIterator() const
virtual PlusStatus GetLatestTimestamp(double &aTimestamp) const
PlusStatus AddTool(vtkPlusDataSource *aTool)
#define PLUS_FAIL
Definition: PlusCommon.h:43
DataSourceContainer Tools
static std::string DATA_SOURCE_TYPE_FIELDDATA_TAG
static vtkPlusConfig * GetInstance()
bool GetFieldDataEnabled() const
virtual PlusStatus SetRfFrame(vtkImageData *rfFrame, US_IMAGE_TYPE imageType)
static std::string DATA_SOURCE_TYPE_VIDEO_TAG
igsioFieldMapType GetFrameFieldMap()
virtual ItemStatus GetTimeStamp(BufferItemUidType uid, double &timestamp)
DataSourceContainerConstIterator GetFieldDataSourcesEndConstIterator() const
DataSourceContainerConstIterator GetToolsStartConstIterator() const
DataSourceContainer FieldDataSources
PlusStatus GetCustomAttributeMap(CustomAttributeMap &output) const
virtual BufferItemUidType GetOldestItemUidInBuffer()
virtual PlusStatus GetTimeStampReportTable(vtkTable *timeStampReportTable)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
PhidgetGPS_Time * time
Definition: phidget22.h:3623
virtual void AddHorizontalLine()
bool GetFieldDataAvailable()
virtual PlusStatus GetMostRecentTimestamp(double &ts)
PlusStatus RemoveTools()
vtkStandardNewMacro(vtkPlusChannel)
PlusStatus RemoveFieldDataSource(const std::string &sourceId)
PlusStatus GetTrackedFrameList(double &aTimestampOfLastFrameAlreadyGot, vtkIGSIOTrackedFrameList *aTrackedFrameList, int aMaxNumberOfFramesToAdd)
PlusStatus GetTimestampMasterTool(vtkPlusDataSource *&aTool)
virtual int GetNumberOfFramesBetweenTimestamps(double aTimestampFrom, double aTimestampTo)
PlusStatus GetMatrix(vtkMatrix4x4 *outputMatrix)
virtual char * GetChannelId()
FrameSizeType BrightnessFrameSize
DataSourceContainer::iterator DataSourceContainerIterator
PlusStatus RemoveFieldDataSources()
igsioVideoFrame & GetFrame()
virtual ItemStatus GetLatestTimeStamp(double &latestTimestamp)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *aChannelElement, bool RequireImageOrientationInChannelConfiguration)
vtkPlusDataSource * VideoSource
bool GetTrackingEnabled() const
const char const char * value
Definition: phidget22.h:5111
void SetVideoSource(vtkPlusDataSource *aSource)
static std::string DATA_SOURCE_TYPE_TOOL_TAG
PlusStatus GetToolByPortName(vtkPlusDataSource *&aTool, const std::string &portName)
virtual PlusStatus GetTrackedFrameListSampled(double &aTimestampOfLastFrameAlreadyGot, double &aTimestampOfNextFrameToBeAdded, vtkIGSIOTrackedFrameList *aTrackedFrameList, double aSamplingPeriodSec, double maxTimeLimitSec=-1)
virtual ItemStatus GetLatestStreamBufferItem(StreamBufferItem *bufferItem)
virtual void SetChannelId(const char *)
vtkImageData * BlankImage
virtual PlusStatus GetOldestTimestamp(double &ts)
vtkPlusRfProcessor * RfProcessor
bool SaveRfProcessingParameters
virtual ItemStatus GetStreamBufferItemFromTime(double time, StreamBufferItem *bufferItem, vtkPlusBuffer::DataItemTemporalInterpolationType interpolation)
virtual std::string AddImageAutoFilename(const char *filenamePostfix, const char *description, const int widthPx=0, const int heightPx=0)
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
static const char * GetRfProcessorTagName()
bool IsVideoSource3D() const
virtual double GetClosestTrackedFrameTimestampByTime(double time)
std::string GetToolReferenceFrameName() const
virtual ItemStatus GetItemUidFromTime(double time, BufferItemUidType &uid)
PlusStatus GetVideoSource(vtkPlusDataSource *&aVideoSource) const
int ToolCount() const
int FieldCount() const
PlusStatus GetVideoSource(const char *aSourceId, vtkPlusDataSource *&aVideoSource)
class for generating basic html tags
unsigned long long BufferItemUidType
void SetOwnerDevice(vtkPlusDevice *_arg)
virtual ItemStatus GetOldestTimeStamp(double &oldestTimestamp)
vtkPlusDevice * GetOwnerDevice() const
virtual PlusStatus GenerateDataAcquisitionReport(vtkPlusHTMLGenerator *htmlReport)
CustomAttributeMap CustomAttributes
virtual PlusStatus WriteCompactConfiguration(vtkXMLDataElement *toolElement)
DataSourceContainerIterator GetFieldDataSourcesEndIterator()
PlusStatus AddFieldDataSource(vtkPlusDataSource *aSource)
virtual int GetNumberOfItems()
double GetTimestamp(double localTimeOffsetSec)
virtual bool GetLatestItemHasValidFieldData()
virtual bool GetLatestItemHasValidTransformData()
Interface to a 3D positioning tool, video source, or generalized data stream.