/// <summary> /// Append the given block at the end of the current block. Pad with no-data if necessary /// </summary> /// <param name="block"></param> public void Append(TracingBlock block) { if (block == null) { throw new ArgumentNullException("block"); } if (block.TotalSeconds == 0) { return; } if (block.End <= this.End) { return; } // Align the blocks HR and UP signals this.AlignSignals(); block.AlignSignals(); // Preallocate to speed up the append this.Capacity = (int)Math.Ceiling((block.End - this.Start).TotalSeconds); // Check if block are adjascent int gap = (int)(block.Start - this.Start).TotalSeconds - this.TotalSeconds; // Fix gap by bridging with NO data while (gap > 0) { this.HRs.Add(TracingBlock.NoData); this.HRs.Add(TracingBlock.NoData); this.HRs.Add(TracingBlock.NoData); this.HRs.Add(TracingBlock.NoData); this.UPs.Add(TracingBlock.NoData); --gap; } // Check for overlap int overlap = Math.Abs(gap); // Too much overlap, just leave NOW if ((overlap > 0) && (overlap >= block.TotalSeconds)) { return; } // Append if (overlap > 0) { this.HRs.AddRange(block.HRs.SkipWhile((x, i) => i < (overlap * 4))); this.UPs.AddRange(block.UPs.SkipWhile((x, i) => i < overlap)); } else { this.HRs.AddRange(block.HRs); this.UPs.AddRange(block.UPs); } }
/// <summary> /// Merge blocks /// This does not modify the source blocks but create a copy of the blocks /// </summary> /// <param name="blocks">List of block to merged</param> /// <param name="maxBridgeableGap">Maximum duration (in seconds) that can be bridged between 2 blocks</param> /// <param name="maxMergedBlockSize">Maximum size of a merged block (if a block is already that big or even bigger, it just won't be merged with anything)</param> /// <returns></returns> public static List <TracingBlock> Merge(IEnumerable <TracingBlock> blocks, int maxBridgeableGap, int maxMergedBlockSize) { List <TracingBlock> result = new List <TracingBlock>(); // Safety first if (blocks == null) { return(result); } TracingBlock last = null; foreach (TracingBlock block in blocks) { // Skip empty blocks if (block.TotalSeconds == 0) { continue; } block.AlignSignals(); // First block? if (last == null) { last = new TracingBlock(block); result.Add(last); continue; } // Check if block are adjascent int gap = (int)(block.Start - last.End).TotalSeconds; // A gap that's not bridgeable or if the resulting merged block would be too big... if ((gap > maxBridgeableGap) || ((block.End - last.Start).TotalSeconds > maxMergedBlockSize)) { last = new TracingBlock(block); result.Add(last); continue; } last.Append(block); } // Optimize memory foreach (TracingBlock block in result) { block.HRs.TrimExcess(); block.UPs.TrimExcess(); } // Done return(result); }
/// <summary> /// Split a given block in multiple blocks so that each block duration is less than maxBlockSize /// </summary> /// <param name="maxBlockSize"></param> /// <returns></returns> public List <TracingBlock> Split(int maxBlockSize) { // To make sure HRs and UP are properly aligned... this.AlignSignals(); // Security System.Diagnostics.Debug.Assert(maxBlockSize > 0); maxBlockSize = Math.Max(1, maxBlockSize); // All fits in one block? var results = new List <TracingBlock>(); if (this.TotalSeconds <= maxBlockSize) { results.Add(this); return(results); } // Need to cut! var position = 0; var duration = this.TotalSeconds; var time = this.Start; while (position < duration) { var block_duration = Math.Min(duration - position, maxBlockSize); var block = new TracingBlock { Start = time, Capacity = block_duration }; for (int i = position; i < position + block_duration; ++i) { block.HRs.Add(this.HRs[(i * 4)]); block.HRs.Add(this.HRs[(i * 4) + 1]); block.HRs.Add(this.HRs[(i * 4) + 2]); block.HRs.Add(this.HRs[(i * 4) + 3]); block.UPs.Add(this.UPs[i]); } // If the block is pure no-data, just skip it... if (!block.IsCompleteNotData) { results.Add(block); } position += block_duration; time = time.AddSeconds(block_duration); } return(results); }