PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusTimestampedCircularBuffer.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 #include "PlusConfigure.h"
9 
10 #include "vtkDoubleArray.h"
11 #include "vtkIGSIORecursiveCriticalSection.h"
12 #include "vtkTable.h"
13 #include "vtkVariantArray.h"
14 
16 
17 //----------------------------------------------------------------------------
19  : Mutex(vtkIGSIORecursiveCriticalSection::New())
20  , NumberOfItems(0)
21  , WritePointer(0)
22  , CurrentTimeStamp(0.0)
23  , LocalTimeOffsetSec(0.0)
24  , LatestItemUid(0)
25  , AveragedItemsForFiltering(20)
26  , MaxAllowedFilteringTimeDifference(0.5)
27  , TimeStampReportTable(NULL)
28  , TimeStampReporting(false)
29  , TimeStampLogging(false)
30  , StartTime(0)
31  , NegligibleTimeDifferenceSec(1e-5)
32 {
33  this->BufferItemContainer.resize(0);
34  this->FilterContainerIndexVector.set_size(0);
35  this->FilterContainerTimestampVector.set_size(0);
38 }
39 
40 //----------------------------------------------------------------------------
42 {
43  this->BufferItemContainer.clear();
44 
45  this->NumberOfItems = 0;
46  if (this->Mutex != NULL)
47  {
48  this->Mutex->Delete();
49  this->Mutex = NULL;
50  }
51 
52  if (this->TimeStampReportTable != NULL)
53  {
54  this->TimeStampReportTable->Delete();
55  this->TimeStampReportTable = NULL;
56  }
57 
58 }
59 
60 //----------------------------------------------------------------------------
61 void vtkPlusTimestampedCircularBuffer::PrintSelf(ostream& os, vtkIndent indent)
62 {
63  //this->Superclass::PrintSelf(os,indent);
64 
65  os << indent << "BufferSize: " << this->GetBufferSize() << "\n";
66  os << indent << "NumberOfItems: " << this->NumberOfItems << "\n";
67  os << indent << "CurrentTimeStamp: " << this->CurrentTimeStamp << "\n";
68  os << indent << "Local time offset: " << this->LocalTimeOffsetSec << "\n";
69  os << indent << "Latest Item Uid: " << this->LatestItemUid << "\n";
70 }
71 
72 //----------------------------------------------------------------------------
74 {
75  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
76 
77  if (timestamp <= this->CurrentTimeStamp)
78  {
79  LOG_DEBUG("Need to skip newly added frame - new timestamp (" << std::fixed << timestamp << ") is not newer than the last one (" << this->CurrentTimeStamp << ")!");
80  return PLUS_FAIL;
81  }
82 
83  // Increase frame unique ID
84  newFrameUid = ++this->LatestItemUid;
85  bufferIndex = this->WritePointer;
86  this->CurrentTimeStamp = timestamp;
87 
88  this->NumberOfItems++;
89  if (this->NumberOfItems > this->GetBufferSize())
90  {
91  this->NumberOfItems = this->GetBufferSize();
92  }
93  // Increase the write pointer
94  if (++this->WritePointer >= this->GetBufferSize())
95  {
96  this->WritePointer = 0;
97  }
98 
99  return PLUS_SUCCESS;
100 }
101 
102 //----------------------------------------------------------------------------
103 // Sets the buffer size, and copies the maximum number of the most current old
104 // frames and timestamps
106 {
107  if (newBufferSize < 0)
108  {
109  LOG_ERROR("SetBufferSize: invalid buffer size");
110  return PLUS_FAIL;
111  }
112 
113  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
114 
115  if (newBufferSize == this->GetBufferSize() && newBufferSize != 0)
116  {
117  return PLUS_SUCCESS;
118  }
119 
120  if (this->GetBufferSize() == 0)
121  {
122  for (int i = 0; i < newBufferSize; i++)
123  {
124  StreamBufferItem emptyBufferItem;
125  this->BufferItemContainer.push_back(emptyBufferItem);
126  }
127  this->WritePointer = 0;
128  this->NumberOfItems = 0;
129  this->CurrentTimeStamp = 0.0;
130  }
131  // if the new buffer is bigger than the old buffer
132  else if (this->GetBufferSize() < newBufferSize)
133  {
134  std::deque<StreamBufferItem>::iterator it = this->BufferItemContainer.begin() + this->WritePointer;
135  const int numberOfNewBufferObjects = newBufferSize - this->GetBufferSize();
136  for (int i = 0; i < numberOfNewBufferObjects; ++i)
137  {
138  StreamBufferItem emptyBufferItem;
139  it = this->BufferItemContainer.insert(it, emptyBufferItem);
140  }
141  }
142  // if the new buffer is smaller than the old buffer
143  else if (this->GetBufferSize() > newBufferSize)
144  {
145  // delete the oldest buffer objects
146  int oldBufferSize = this->GetBufferSize();
147  for (int i = 0; i < oldBufferSize - newBufferSize; ++i)
148  {
149  std::deque<StreamBufferItem>::iterator it = this->BufferItemContainer.begin() + this->WritePointer;
150  this->BufferItemContainer.erase(it);
151  if (this->WritePointer >= this->GetBufferSize())
152  {
153  this->WritePointer = 0;
154  }
155  }
156  }
157 
158  // update the number of items
159  if (this->NumberOfItems > this->GetBufferSize())
160  {
161  this->NumberOfItems = this->GetBufferSize();
162  }
163 
164  this->Modified();
165 
166  return PLUS_SUCCESS;
167 }
168 
169 //----------------------------------------------------------------------------
171 {
172  // the caller must have locked the buffer
173  BufferItemUidType oldestUid = this->LatestItemUid - (this->NumberOfItems - 1);
174  if (uid < oldestUid)
175  {
176  LOG_WARNING("Buffer item is not in the buffer (Uid: " << uid << ")!");
177  itemPtr = NULL;
179  }
180  else if (uid > this->LatestItemUid)
181  {
182  LOG_WARNING("Buffer item is not in the buffer (Uid: " << uid << ")!");
183  itemPtr = NULL;
184  return ITEM_NOT_AVAILABLE_YET;
185  }
186  int bufferIndex = (this->WritePointer - 1) - (this->LatestItemUid - uid);
187  if (bufferIndex < 0)
188  {
189  bufferIndex += this->BufferItemContainer.size();
190  }
191  itemPtr = &this->BufferItemContainer[bufferIndex];
192  return ITEM_OK;
193 }
194 
195 //----------------------------------------------------------------------------
197 {
198  // the caller must have locked the buffer
199  if (this->GetBufferSize() <= 0
200  || bufferIndex >= this->GetBufferSize()
201  || bufferIndex < 0)
202  {
203  LOG_ERROR("Failed to get buffer item with buffer index - index is out of range (bufferIndex: " << bufferIndex << ").");
204  return NULL;
205  }
206  return &this->BufferItemContainer[bufferIndex];
207 }
208 
209 //----------------------------------------------------------------------------
211 {
212  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
213  StreamBufferItem* itemPtr = NULL;
214  ItemStatus status = GetBufferItemPointerFromUid(uid, itemPtr);
215  if (status != ITEM_OK)
216  {
217  filteredTimestamp = 0;
218  return status;
219  }
220  filteredTimestamp = itemPtr->GetFilteredTimestamp(this->LocalTimeOffsetSec);
221  return status;
222 }
223 
224 //----------------------------------------------------------------------------
226 {
227  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
228  StreamBufferItem* itemPtr = NULL;
229  ItemStatus status = GetBufferItemPointerFromUid(uid, itemPtr);
230  if (status != ITEM_OK)
231  {
232  unfilteredTimestamp = 0;
233  return status;
234  }
235  unfilteredTimestamp = itemPtr->GetUnfilteredTimestamp(this->LocalTimeOffsetSec);
236  return status;
237 }
238 
239 //----------------------------------------------------------------------------
241 {
242  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
243  if (this->NumberOfItems < 1)
244  {
245  return false;
246  }
247  int latestItemBufferIndex = (this->WritePointer > 0) ? (this->WritePointer - 1) : (this->BufferItemContainer.size() - 1);
248  return this->BufferItemContainer[latestItemBufferIndex].HasValidVideoData();
249 }
250 
251 //----------------------------------------------------------------------------
253 {
254  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
255  if (this->NumberOfItems < 1)
256  {
257  return false;
258  }
259  int latestItemBufferIndex = (this->WritePointer > 0) ? (this->WritePointer - 1) : (this->BufferItemContainer.size() - 1);
260  return this->BufferItemContainer[latestItemBufferIndex].HasValidTransformData();
261 }
262 
263 //----------------------------------------------------------------------------
265 {
266  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
267  if (this->NumberOfItems < 1)
268  {
269  return false;
270  }
271  int latestItemBufferIndex = (this->WritePointer > 0) ? (this->WritePointer - 1) : (this->BufferItemContainer.size() - 1);
272  return this->BufferItemContainer[latestItemBufferIndex].HasValidFieldData();
273 }
274 
275 //----------------------------------------------------------------------------
277 {
278  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
279  StreamBufferItem* itemPtr = NULL;
280  ItemStatus status = GetBufferItemPointerFromUid(uid, itemPtr);
281  if (status != ITEM_OK)
282  {
283  index = 0;
284  return status;
285  }
286  index = itemPtr->GetIndex();
287  return status;
288 }
289 
290 //----------------------------------------------------------------------------
292 {
293  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
294  bufferIndex = -1;
295 
296  BufferItemUidType itemUid = 0;
297  ItemStatus itemStatus = this->GetItemUidFromTime(time, itemUid);
298  if (itemStatus != ITEM_OK)
299  {
300  LOG_WARNING("Buffer item is not in the buffer (time: " << std::fixed << time << ")!");
301  return itemStatus;
302  }
303 
304  bufferIndex = (this->WritePointer - 1) - (this->LatestItemUid - itemUid);
305  if (bufferIndex < 0)
306  {
307  bufferIndex += this->BufferItemContainer.size();
308  }
309  return ITEM_OK;
310 }
311 
312 //----------------------------------------------------------------------------
313 // do a simple divide-and-conquer search for the transform
314 // that best matches the given timestamp
316 {
317  igsioLockGuard< vtkPlusTimestampedCircularBuffer > bufferGuardedLock(this);
318 
319  if (this->NumberOfItems == 1)
320  {
321  // There is only one item, it's the closest one to any timestamp
322  uid = this->LatestItemUid;
323  return ITEM_OK;
324  }
325 
326  BufferItemUidType lo = this->LatestItemUid - (this->NumberOfItems - 1); // oldest item UID
327  BufferItemUidType hi = this->LatestItemUid; // latest item UID
328 
329  // minimum time
330  // This method is called often, therefore instead of calling this->GetTimeStamp(lo, tlo) we perform low-level operations to get the timestamp
331  int loBufferIndex = (this->WritePointer - 1) - (this->LatestItemUid - lo);
332  if (loBufferIndex < 0)
333  {
334  loBufferIndex += this->BufferItemContainer.size();
335  }
336  double tlo = this->BufferItemContainer[loBufferIndex].GetFilteredTimestamp(this->LocalTimeOffsetSec);
337 
338  // This method is called often, therefore instead of calling this->GetTimeStamp(hi, thi) we perform low-level operations to get the timestamp
339  int hiBufferIndex = (this->WritePointer - 1) - (this->LatestItemUid - hi);
340  if (hiBufferIndex < 0)
341  {
342  hiBufferIndex += this->BufferItemContainer.size();
343  }
344  double thi = this->BufferItemContainer[hiBufferIndex].GetFilteredTimestamp(this->LocalTimeOffsetSec);
345 
346  // If the timestamp is slightly out of range then still accept it
347  // (due to errors in conversions there could be slight differences)
348  if (time < tlo - this->NegligibleTimeDifferenceSec)
349  {
351  }
352  else if (time > thi + this->NegligibleTimeDifferenceSec)
353  {
354  return ITEM_NOT_AVAILABLE_YET;
355  }
356 
357  for (;;)
358  {
359  if (hi - lo <= 1)
360  {
361  if (time - tlo > thi - time)
362  {
363  uid = hi;
364  return ITEM_OK;
365  }
366  else
367  {
368  uid = lo;
369  return ITEM_OK;
370  }
371  }
372 
373  int mid = (lo + hi) / 2;
374 
375  // This is a hot loop, therefore instead of calling this->GetTimeStamp(mid, tmid) we perform low-level operations to get the timestamp
376  int midBufferIndex = (this->WritePointer - 1) - (this->LatestItemUid - mid);
377  if (midBufferIndex < 0)
378  {
379  midBufferIndex += this->BufferItemContainer.size();
380  }
381  double tmid = this->BufferItemContainer[midBufferIndex].GetFilteredTimestamp(this->LocalTimeOffsetSec);
382 
383  if (time < tmid)
384  {
385  hi = mid;
386  thi = tmid;
387  }
388  else
389  {
390  lo = mid;
391  tlo = tmid;
392  }
393  }
394 
395 }
396 
397 //----------------------------------------------------------------------------
399 {
400  buffer->Lock();
401  this->Lock();
402  this->WritePointer = buffer->WritePointer;
403  this->NumberOfItems = buffer->NumberOfItems;
404  this->CurrentTimeStamp = buffer->CurrentTimeStamp;
405  this->LocalTimeOffsetSec = buffer->LocalTimeOffsetSec;
406  this->LatestItemUid = buffer->LatestItemUid;
407  this->StartTime = buffer->StartTime;
413 
415  this->Unlock();
416  buffer->Unlock();
417 }
418 
419 //----------------------------------------------------------------------------
421 {
422  this->Lock();
423  this->WritePointer = 0;
424  this->NumberOfItems = 0;
425  this->CurrentTimeStamp = 0;
426  this->LatestItemUid = 0;
427  this->Unlock();
428 }
429 
430 //----------------------------------------------------------------------------
431 double vtkPlusTimestampedCircularBuffer::GetFrameRate(bool ideal /*=false*/, double* framePeriodStdevSecPtr /* =NULL */)
432 {
433  // TODO: Start the frame rate computation from the latest frame UID with using a few seconds of items in the buffer
434  bool cannotComputeIdealFrameRateDueToInvalidFrameNumbers = false;
435 
436  std::vector<double> framePeriods;
437  for (BufferItemUidType frame = this->GetLatestItemUidInBuffer(); frame > this->GetOldestItemUidInBuffer(); --frame)
438  {
439  double time(0);
440  if (this->GetTimeStamp(frame, time) != ITEM_OK)
441  {
442  continue;
443  }
444 
445  unsigned long framenum(0);
446  if (this->GetIndex(frame, framenum) != ITEM_OK)
447  {
448  continue;
449  }
450 
451  double prevtime(0);
452  if (this->GetTimeStamp(frame - 1, prevtime) != ITEM_OK)
453  {
454  continue;
455  }
456 
457  unsigned long prevframenum(0);
458  if (this->GetIndex(frame - 1, prevframenum) != ITEM_OK)
459  {
460  continue;
461  }
462 
463  double frameperiod = (time - prevtime);
464  int frameDiff = framenum - prevframenum;
465 
466  if (ideal)
467  {
468  if (frameDiff > 0)
469  {
470  frameperiod /= (1.0 * frameDiff);
471  }
472  else
473  {
474  // the same frame number was set for different frame indexes; this should not happen (probably no frame number is available)
475  cannotComputeIdealFrameRateDueToInvalidFrameNumbers = true;
476  }
477  }
478 
479  if (frameperiod > 0)
480  {
481  framePeriods.push_back(frameperiod);
482  }
483  }
484 
485  if (cannotComputeIdealFrameRateDueToInvalidFrameNumbers)
486  {
487  LOG_WARNING("Cannot compute ideal frame rate acurately, as frame numbers are invalid or missing");
488  }
489 
490  const int numberOfFramePeriods = framePeriods.size();
491  if (numberOfFramePeriods < 1)
492  {
493  LOG_WARNING("Failed to compute frame rate. Not enough samples.");
494  return 0;
495  }
496 
497  double samplingPeriod(0);
498  for (int i = 0; i < numberOfFramePeriods; i++)
499  {
500  samplingPeriod += framePeriods[i];
501  }
502  samplingPeriod /= 1.0 * numberOfFramePeriods;
503 
504  double frameRate(0);
505  if (samplingPeriod != 0)
506  {
507  frameRate = 1.0 / samplingPeriod;
508  }
509 
510  if (framePeriodStdevSecPtr != NULL)
511  {
512  // Standard deviation of sampling period
513  // stdev = sqrt ( 1/N * sum[ (xi-mean)^2 ] ) = sqrt ( 1/N * sumOfXiMeanDiffSquare )
514  double sumOfXiMeanDiffSquare = 0;
515  for (int i = 0; i < numberOfFramePeriods; i++)
516  {
517  sumOfXiMeanDiffSquare += (framePeriods[i] - samplingPeriod) * (framePeriods[i] - samplingPeriod);
518  }
519  double framePeriodStdev = sqrt(sumOfXiMeanDiffSquare / numberOfFramePeriods);
520  (*framePeriodStdevSecPtr) = framePeriodStdev;
521  }
522 
523  return frameRate;
524 }
525 
526 //----------------------------------------------------------------------------
527 // for accurate timing of the frame: an exponential moving average
528 // is computed to smooth out the jitter in the times that are returned by the system clock:
529 PlusStatus vtkPlusTimestampedCircularBuffer::CreateFilteredTimeStampForItem(unsigned long itemIndex, double inUnfilteredTimestamp, double& outFilteredTimestamp, bool& filteredTimestampProbablyValid)
530 {
531  this->Lock();
532  filteredTimestampProbablyValid = true;
533 
534  if (this->FilterContainerIndexVector.size() != this->AveragedItemsForFiltering
536  {
537  // this call set elements to null
540  this->FilterContainersOldestIndex = 0;
542  }
543 
544  // We store the last AveragedItemsForFiltering unfiltered timestamp and item indexes, because these are used for computing the filtered timestamp.
545  if (this->AveragedItemsForFiltering > 1)
546  {
548  this->FilterContainerTimestampVector[this->FilterContainersOldestIndex] = inUnfilteredTimestamp;
551 
553  {
555  }
556 
558  {
559  this->FilterContainersOldestIndex = 0;
560  }
561  }
562 
563  // If we don't have enough unfiltered timestamps or we don't want to use afiltering then just use the unfiltered timestamps
564  if (this->AveragedItemsForFiltering < 2 || this->FilterContainersNumberOfValidElements < this->AveragedItemsForFiltering)
565  {
566  outFilteredTimestamp = inUnfilteredTimestamp;
567  AddToTimeStampReport(itemIndex, inUnfilteredTimestamp, outFilteredTimestamp);
568  this->Unlock();
569  return PLUS_SUCCESS;
570  }
571 
572  // The items are acquired periodically, with quite accurate frame periods. The data is not timestamped
573  // by the source, only Plus attaches a timestamp when it receives the data. The timestamp that Plus attaches
574  // (the unfiltered timestamp) may be inaccurate, due to random delays in transferring the data.
575  // Without the random delays (and if the acquisition frame rate is constant) the itemIndex vs. timestamp function would be a straight line.
576  // With the random delays small spikes appear on this line, causing inaccuracies.
577  // Get rid of the small spikes and get a smooth straight line by fitting a line (timestamp = itemIndex * framePeriod + timeOffset) to the
578  // itemIndex vs. unfiltered timestamp function and compute the current filtered timestamp
579  // by extrapolation of this line to the current item index.
580  // The line parameters computed by linear regression.
581  //
582  // timestamp = framePeriod * itemIndex+ timeOffset
583  // x = itemIndex
584  // y = timestamp
585  // a = framePeriod
586  // b = timeOffset
587  //
588  // Ordinary least squares estimation:
589  // y(i) = a * x(i) + b;
590  // a = sum( (x(i)-xMean) * (y(i)-yMean) ) / sum( (x(i)-xMean) * (x(i)-xMean) )
591  // b = yMean - a*xMean
592  //
593 
594  double xMean = this->FilterContainerIndexVector.mean();
595  double yMean = this->FilterContainerTimestampVector.mean();
596  double covarianceXY = 0;
597  double varianceX = 0;
598  for (int i = this->FilterContainerTimestampVector.size() - 1; i >= 0; i--)
599  {
600  double xiMinusXmean = (this->FilterContainerIndexVector(i) - xMean);
601  covarianceXY += xiMinusXmean * (this->FilterContainerTimestampVector(i) - yMean);
602  varianceX += xiMinusXmean * xiMinusXmean;
603  }
604  double a = covarianceXY / varianceX;
605  double b = yMean - a * xMean;
606 
607  outFilteredTimestamp = a * itemIndex + b;
608 
609  if (this->TimeStampLogging)
610  {
611  LOG_TRACE("timestamps = [" << std::fixed << this->FilterContainerTimestampVector << "];");
612  LOG_TRACE("frameindexes = [" << std::fixed << this->FilterContainerIndexVector << "];");
613  }
614 
615  AddToTimeStampReport(itemIndex, inUnfilteredTimestamp, outFilteredTimestamp);
616 
617  if (fabs(outFilteredTimestamp - inUnfilteredTimestamp) > this->MaxAllowedFilteringTimeDifference)
618  {
619  // Write current timestamps and frame indexes to the log to allow investigation of the problem
620  filteredTimestampProbablyValid = false;
621  LOG_DEBUG("Difference between unfiltered timestamp is larger than the threshold. The unfiltered timestamp may be incorrect."
622  << " Unfiltered timestamp: " << inUnfilteredTimestamp << ", filtered timestamp: " << outFilteredTimestamp << ", difference: " << fabs(outFilteredTimestamp - inUnfilteredTimestamp) << ", threshold: " << this->MaxAllowedFilteringTimeDifference << "."
623  << " timestamps = [" << std::fixed << this->FilterContainerTimestampVector << "];"
624  << " frameindexes = [" << std::fixed << this->FilterContainerIndexVector << "];");
625  }
626 
627  this->Unlock();
628  return PLUS_SUCCESS;
629 }
630 
631 //----------------------------------------------------------------------------
633 {
634  if (timeStampReportTable == NULL)
635  {
636  LOG_ERROR("Failed to get timestamp report table from buffer - input table is NULL!");
637  return PLUS_FAIL;
638  }
639 
640  if (this->TimeStampReportTable == NULL)
641  {
642  LOG_ERROR("Failed to get timestamp report table from buffer - table is NULL!");
643  return PLUS_FAIL;
644  }
645 
646  this->Lock();
647  timeStampReportTable->DeepCopy(this->TimeStampReportTable);
648  this->Unlock();
649 
650  return PLUS_SUCCESS;
651 }
652 
653 //----------------------------------------------------------------------------
654 void vtkPlusTimestampedCircularBuffer::AddToTimeStampReport(unsigned long itemIndex, double unfilteredTimestamp, double filteredTimestamp)
655 {
656  if (!this->TimeStampReporting)
657  {
658  // no reporting is needed
659  return;
660  }
661 
662  if (this->TimeStampReportTable == NULL)
663  {
664  this->TimeStampReportTable = vtkTable::New();
665 
666  const char* colFrameNumberName = "FrameNumber";
667  vtkSmartPointer<vtkDoubleArray> colFrameNumber = vtkSmartPointer<vtkDoubleArray>::New();
668  colFrameNumber->SetName(colFrameNumberName);
669  this->TimeStampReportTable->AddColumn(colFrameNumber);
670 
671  const char* colUnfilteredTimestampName = "UnfilteredTimestamp";
672  vtkSmartPointer<vtkDoubleArray> colUnfilteredTimestamp = vtkSmartPointer<vtkDoubleArray>::New();
673  colUnfilteredTimestamp->SetName(colUnfilteredTimestampName);
674  this->TimeStampReportTable->AddColumn(colUnfilteredTimestamp);
675 
676  const char* colFilteredTimestampName = "FilteredTimestamp";
677  vtkSmartPointer<vtkDoubleArray> colFilteredTimestamp = vtkSmartPointer<vtkDoubleArray>::New();
678  colFilteredTimestamp->SetName(colFilteredTimestampName);
679  this->TimeStampReportTable->AddColumn(colFilteredTimestamp);
680  }
681 
682  // create a new row for the timestamp report table
683  vtkSmartPointer<vtkVariantArray> timeStampReportTableRow = vtkSmartPointer<vtkVariantArray>::New();
684 
685  timeStampReportTableRow->InsertNextValue(itemIndex);
686  timeStampReportTableRow->InsertNextValue(unfilteredTimestamp - this->StartTime);
687  timeStampReportTableRow->InsertNextValue(filteredTimestamp - this->StartTime);
688 
689  this->TimeStampReportTable->InsertNextRow(timeStampReportTableRow);
690 
691 }
virtual BufferItemUidType GetOldestItemUidInBuffer()
virtual ItemStatus GetBufferItemPointerFromUid(const BufferItemUidType uid, StreamBufferItem *&itemPtr)
double * timestamp
Definition: phidget22.h:3432
vtkStandardNewMacro(vtkPlusTimestampedCircularBuffer)
vtkIGSIORecursiveCriticalSection * Mutex
virtual void DeepCopy(vtkPlusTimestampedCircularBuffer *buffer)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
virtual double GetFrameRate(bool ideal=false, double *framePeriodStdevSecPtr=NULL)
for i
virtual PlusStatus PrepareForNewItem(const double timestamp, BufferItemUidType &newFrameUid, int &bufferIndex)
This class stores an fixed number of timestamped items. It provides element retrieval based on timest...
#define PLUS_FAIL
Definition: PlusCommon.h:43
Initial rotation matrix b
Definition: algo3.m:25
virtual ItemStatus GetItemUidFromTime(const double time, BufferItemUidType &uid)
virtual PlusStatus CreateFilteredTimeStampForItem(unsigned long itemIndex, double inUnfilteredTimestamp, double &outFilteredTimestamp, bool &filteredTimestampProbablyValid)
double GetFilteredTimestamp(double localTimeOffsetSec)
virtual BufferItemUidType GetLatestItemUidInBuffer()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
void PrintSelf(ostream &os, vtkIndent indent)
PhidgetGPS_Time * time
Definition: phidget22.h:3623
PlusStatus GetTimeStampReportTable(vtkTable *timeStampReportTable)
unsigned long GetIndex()
void AddToTimeStampReport(unsigned long itemIndex, double unfilteredTimestamp, double filteredTimestamp)
double GetUnfilteredTimestamp(double localTimeOffsetSec)
virtual ItemStatus GetFilteredTimeStamp(const BufferItemUidType uid, double &filteredTimestamp)
std::deque< StreamBufferItem > BufferItemContainer
virtual ItemStatus GetBufferIndexFromTime(const double time, int &bufferIndex)
virtual StreamBufferItem * GetBufferItemPointerFromBufferIndex(const int bufferIndex)
virtual ItemStatus GetIndex(const BufferItemUidType uid, unsigned long &index)
virtual ItemStatus GetTimeStamp(const BufferItemUidType uid, double &timestamp)
virtual ItemStatus GetUnfilteredTimeStamp(const BufferItemUidType uid, double &unfilteredTimestamp)
unsigned long long BufferItemUidType