public List <Region> GetClipped(Region clipToRegion, List <Region> excludeRegions = null) { var clippedIntervals = new List <Region>(); if (!clipToRegion.IsValid()) { throw new ArgumentException(string.Format("Region {0} is not valid.", clipToRegion)); } for (var i = _lastIndexCleared + 1; i < Intervals.Count; i++) { var interval = Intervals[i]; if (interval.StartPosition > clipToRegion.EndPosition) { break; } if (!clipToRegion.Overlaps(interval)) { continue; } var clippedInterval = new Region(Math.Max(clipToRegion.StartPosition, interval.StartPosition), Math.Min(clipToRegion.EndPosition, interval.EndPosition)); if (excludeRegions == null) { clippedIntervals.Add(clippedInterval); } else { clippedIntervals.AddRange(GetMinus(clippedInterval, excludeRegions)); } } return(clippedIntervals); }
/// <summary> /// Get intervals for a region, minus an overlaps with the exclude regions. /// </summary> /// <param name="keepRegion">Region to keep</param> /// <param name="excludeRegions">List of regions to exclude from the final result. Assumes regions are sorted.</param> /// <returns></returns> public static List <Region> GetMinus(Region keepRegion, List <Region> excludeRegions) { var regions = new List <Region>(); if (keepRegion == null || !keepRegion.IsValid()) { throw new ArgumentException(string.Format("Region {0} is not valid.", keepRegion)); } if (excludeRegions == null) { regions.Add(keepRegion); return(regions); } var remainingRegion = new Region(keepRegion.StartPosition, keepRegion.EndPosition); foreach (var excludeRegion in excludeRegions) { if (excludeRegion == null || !excludeRegion.IsValid()) { throw new ArgumentException(string.Format("Region {0} is not valid.", excludeRegion)); } if (!remainingRegion.Overlaps(excludeRegion)) { continue; // no overlap, keep checking other excluded regions } if (excludeRegion.FullyContains(remainingRegion)) { remainingRegion = null; // done, fully excluded break; } if (remainingRegion.FullyContains(excludeRegion)) { // need to break up remaining region! var leftRegion = new Region(remainingRegion.StartPosition, excludeRegion.StartPosition - 1, false); var rightRegion = new Region(excludeRegion.EndPosition + 1, remainingRegion.EndPosition, false); if (leftRegion.IsValid()) { regions.Add(leftRegion); } if (!rightRegion.IsValid()) { remainingRegion = null; // done, nothing left on right side break; } remainingRegion = rightRegion; // pass right region on for more processing } else { remainingRegion = excludeRegion.ContainsPosition(remainingRegion.StartPosition) ? new Region(excludeRegion.EndPosition + 1, remainingRegion.EndPosition) // clip on left side : new Region(remainingRegion.StartPosition, excludeRegion.StartPosition - 1); } } if (remainingRegion != null) { regions.Add(remainingRegion); } return(regions); }