/// <summary> /// Returns the difference of one interval to another. /// </summary> /// <typeparam name="T">The type of values included in the intervals.</typeparam> /// <param name="interval">The source interval.</param> /// <param name="other">The interval to exclude.</param> /// <returns>A set that contains every part of <paramref name="interval"/> that is not also contained by <paramref name="other"/>.</returns> public static IList <IInterval <T> > DifferenceWith <T>(this IInterval <T> interval, IInterval <T> other) where T : IComparable <T> { if (interval.IsEmpty()) { return(null); } var intersection = interval.IntersectWith(other); if (intersection.IsEmpty()) { return(new[] { interval }); } else if (intersection == interval) { return(null); } var intervals = new List <IInterval <T> >(); var startToStart = interval.Start.CompareTo(intersection.Start); if (startToStart != 0 || (interval.StartInclusive && !intersection.StartInclusive)) { intervals.Add(interval.Clone( interval.Start, interval.StartInclusive, intersection.Start, !intersection.StartInclusive)); } var endToEnd = interval.End.CompareTo(intersection.End); if (endToEnd != 0 || (interval.EndInclusive && !intersection.EndInclusive)) { intervals.Add(interval.Clone( intersection.End, !intersection.EndInclusive, interval.End, interval.EndInclusive)); } return(intervals); }
/// <summary> /// Add a list of objects to a given interval. /// </summary> /// <param name = "interval">The interval to store the object in.</param> /// <param name = "values">The list of objects to store.</param> public void Add(IInterval <TMath> interval, IList <TObject> values) { // Check for intersections with existing intervals. IList <IntervalValues> intersecting = FindIntersections(interval); if (intersecting.Count > 0) { // A list used to find remnants after cutting intersections. var remnants = new List <IInterval <TMath> > { (IInterval <TMath>)interval.Clone() }; // Split up all intersecting intervals. foreach (IntervalValues intersectingRange in intersecting) { IInterval <TMath> intersection = intersectingRange.Interval.Intersection(interval); SplitRemoveIntersection(intersectingRange, intersection); // Add intersection with objects of both intervals. var mergedObjects = new List <TObject>(intersectingRange.Values); mergedObjects.AddRange(values); _rangedObjects.Add(new IntervalValues(mergedObjects, intersection)); // Remove intersections from remnants. var newRemnants = new List <IInterval <TMath> >(); foreach (IInterval <TMath> remnant in remnants) { newRemnants.AddRange(remnant.Subtract(intersection)); } remnants = newRemnants; } // Add remnants of the newly added interval. foreach (IInterval <TMath> remnant in remnants) { _rangedObjects.Add(new IntervalValues(values, remnant)); } } else { // No intersections, just add. _rangedObjects.Add(new IntervalValues(values, interval)); } }
/// <summary> /// Returns the union of two intervals. /// </summary> /// <typeparam name="T">The type of values included in the intervals.</typeparam> /// <param name="interval">The first interval.</param> /// <param name="other">The second interval.</param> /// <returns>A set that contains both intervals.</returns> /// <remarks> /// If the intervals intersect, the result will be a set with a single interval. /// </remarks> public static IList <IInterval <T> > UnionWith <T>(this IInterval <T> interval, IInterval <T> other) where T : IComparable <T> { var intervalEmpty = interval.IsEmpty(); var otherEmpty = other.IsEmpty(); if (intervalEmpty && otherEmpty) { return(null); } else if (intervalEmpty) { return(new[] { other }); } else if (otherEmpty) { return(new[] { interval }); } int startToStart, endToEnd, startToEnd; T start, end; bool startInclusive, endInclusive; startToStart = interval.Start.CompareTo(other.Start); if (startToStart > 0) { start = interval.Start; startInclusive = interval.StartInclusive; } else if (startToStart < 0) { start = other.Start; startInclusive = other.StartInclusive; } else { start = interval.Start; startInclusive = interval.StartInclusive && other.StartInclusive; } endToEnd = interval.End.CompareTo(other.End); if (endToEnd < 0) { end = interval.End; endInclusive = interval.EndInclusive; } else if (endToEnd > 0) { end = other.End; endInclusive = other.EndInclusive; } else { end = interval.End; endInclusive = interval.EndInclusive && other.EndInclusive; } startToEnd = start.CompareTo(end); if (startToEnd > 0) { return(new[] { interval, other }); } else if (startToEnd == 0 && !(startInclusive || endInclusive)) { return(new[] { interval, other }); } bool startMatchesInterval = false, startMatchesOther = false, endMatchesInterval = false, endMatchesOther = false; if (startToStart < 0) { start = interval.Start; startInclusive = interval.StartInclusive; startMatchesInterval = true; } else if (startToStart > 0) { start = other.Start; startInclusive = other.StartInclusive; startMatchesOther = true; } else { start = interval.Start; startInclusive = interval.StartInclusive || other.StartInclusive; startMatchesInterval = startInclusive == interval.StartInclusive; startMatchesOther = startInclusive == other.StartInclusive; } if (endToEnd > 0) { end = interval.End; endInclusive = interval.EndInclusive; endMatchesInterval = true; } else if (endToEnd < 0) { end = other.End; endInclusive = other.EndInclusive; endMatchesOther = true; } else { end = interval.End; endInclusive = interval.EndInclusive || other.EndInclusive; endMatchesInterval = endInclusive == interval.EndInclusive; endMatchesOther = endInclusive == other.EndInclusive; } if (startMatchesInterval && endMatchesInterval) { return(new[] { interval }); } else if (startMatchesOther && endMatchesOther) { return(new[] { other }); } return(new[] { interval.Clone( start, startInclusive, end, endInclusive) }); }
/// <summary> /// Returns the intersection of two intervals. /// </summary> /// <typeparam name="T">The type of values included in the intervals.</typeparam> /// <param name="interval">The first interval.</param> /// <param name="other">The second interval.</param> /// <returns>An interval that represents the intersection of the intervals.</returns> public static IInterval <T> IntersectWith <T>(this IInterval <T> interval, IInterval <T> other) where T : IComparable <T> { if (interval.IsEmpty() || other.IsEmpty()) { return(null); } T start, end; bool startInclusive, endInclusive; bool startMatchesInterval = false, startMatchesOther = false, endMatchesInterval = false, endMatchesOther = false; var startToStart = interval.Start.CompareTo(other.Start); if (startToStart > 0) { start = interval.Start; startInclusive = interval.StartInclusive; startMatchesInterval = true; } else if (startToStart < 0) { start = other.Start; startInclusive = other.StartInclusive; startMatchesOther = true; } else { start = interval.Start; startInclusive = interval.StartInclusive && other.StartInclusive; startMatchesInterval = startInclusive == interval.StartInclusive; startMatchesOther = startInclusive == other.StartInclusive; } var endToEnd = interval.End.CompareTo(other.End); if (endToEnd < 0) { end = interval.End; endInclusive = interval.EndInclusive; endMatchesInterval = true; } else if (endToEnd > 0) { end = other.End; endInclusive = other.EndInclusive; endMatchesOther = true; } else { end = interval.End; endInclusive = interval.EndInclusive && other.EndInclusive; endMatchesInterval = endInclusive == interval.EndInclusive; endMatchesOther = endInclusive == other.EndInclusive; } var startToEnd = start.CompareTo(end); if (startToEnd > 0) { return(null); } else if (startToEnd == 0 && (!startInclusive || !endInclusive)) { return(null); } if (startMatchesInterval && endMatchesInterval) { return(interval); } else if (startMatchesOther && endMatchesOther) { return(other); } return(interval.Clone( start, startInclusive, end, endInclusive)); }