using System; using System.Collections.Generic; using System.Threading; namespace EyeTracking { /// /// Handles buffering and processing of eye tracking data with configurable buffer sizes /// and analysis capabilities for smooth data processing /// public class EyeTrackingBuffer { private readonly Queue _dataBuffer; private readonly object _bufferLock = new object(); private readonly int _maxBufferSize; private readonly int _minBufferSize; private readonly Func, EyeTrackingData> _analyzeChunkData; private readonly Action _processData; private readonly Func _canProcess; /// /// Initializes a new instance of the EyeTrackingBuffer class /// /// Maximum number of data points to buffer /// Minimum buffer size before processing begins /// Function to analyze chunk data and return processed data /// Action to process the analyzed data /// Function to check if processing is allowed (optional) public EyeTrackingBuffer( int maxBufferSize = 40, int minBufferSize = 10, Func, EyeTrackingData> analyzeChunkData = null, Action processData = null, Func canProcess = null) { _maxBufferSize = maxBufferSize; _minBufferSize = minBufferSize; _analyzeChunkData = analyzeChunkData ?? DefaultAnalyzeChunkData; _processData = processData ?? DefaultProcessData; _canProcess = canProcess ?? (() => true); _dataBuffer = new Queue(); } /// /// Adds new eye tracking data to the buffer and triggers processing if conditions are met /// /// Eye tracking data to add public void AddData(EyeTrackingData data) { lock (_bufferLock) { // Add new data to buffer _dataBuffer.Enqueue(data); // Remove oldest data if buffer exceeds maximum size while (_dataBuffer.Count > _maxBufferSize) { _dataBuffer.Dequeue(); } } ProcessBufferData(); } /// /// Processes buffered data if conditions are met /// public void ProcessBufferData() { if (!_canProcess()) return; bool shouldProcess = false; int bufferCount; lock (_bufferLock) { bufferCount = _dataBuffer.Count; shouldProcess = bufferCount >= _minBufferSize; } if (shouldProcess) { ProcessOneFrameFromBuffer(); } } /// /// Processes one frame from the buffer using the configured analysis function /// private void ProcessOneFrameFromBuffer() { EyeTrackingData dataToProcess = null; List currentBuffer = new List(); lock (_bufferLock) { if (_dataBuffer.Count > 0) { // Get the oldest data point to process dataToProcess = _dataBuffer.Dequeue(); // Create a copy of the remaining buffer for analysis currentBuffer = new List(_dataBuffer); } } if (dataToProcess != null) { // Analyze the current buffer context (including the frame we're about to process) // Add the frame we're processing to the analysis buffer currentBuffer.Insert(0, dataToProcess); EyeTrackingData processedData = _analyzeChunkData(currentBuffer); // Process the analyzed data _processData(processedData); } } /// /// Clears all buffered data /// public void Clear() { lock (_bufferLock) { _dataBuffer.Clear(); } } /// /// Gets the current number of items in the buffer /// public int Count { get { lock (_bufferLock) { return _dataBuffer.Count; } } } /// /// Default analysis function that returns the first frame unchanged /// /// List of eye tracking data /// The first frame from the chunk private static EyeTrackingData DefaultAnalyzeChunkData(List chunkData) { return chunkData.Count > 0 ? chunkData[0] : new EyeTrackingData(); } /// /// Default process function that does nothing /// /// Eye tracking data to process private static void DefaultProcessData(EyeTrackingData data) { // Default implementation does nothing } } }