Exemplo n.º 1
0
        /** return a new set containing all elements in this but not in other.
         *  Intervals may have to be broken up when ranges in this overlap
         *  with ranges in other.  other is assumed to be a subset of this;
         *  anything that is in other but not in this will be ignored.
         *
         *  Keep around, but 10-20-2005, I decided to make complement work w/o
         *  subtract and so then subtract can simply be a&~b
         */
        public IIntSet Subtract(IIntSet other)
        {
            if (other == null || !(other is IntervalSet))
            {
                return(null); // nothing in common with null set
            }

            IntervalSet diff = new IntervalSet();

            // iterate down both interval lists
            var      thisIter  = this.intervals.GetEnumerator();
            var      otherIter = ((IntervalSet)other).intervals.GetEnumerator();
            Interval mine      = null;
            Interval theirs    = null;

            if (thisIter.MoveNext())
            {
                mine = (Interval)thisIter.Current;
            }
            if (otherIter.MoveNext())
            {
                theirs = (Interval)otherIter.Current;
            }
            while (mine != null)
            {
                //[email protected]("mine="+mine+", theirs="+theirs);
                // CASE 1: nothing in theirs removes a chunk from mine
                if (theirs == null || mine.disjoint(theirs))
                {
                    // SUBCASE 1a: finished traversing theirs; keep adding mine now
                    if (theirs == null)
                    {
                        // add everything in mine to difference since theirs done
                        diff.add(mine);
                        mine = null;
                        if (thisIter.MoveNext())
                        {
                            mine = (Interval)thisIter.Current;
                        }
                    }
                    else
                    {
                        // SUBCASE 1b: mine is completely to the left of theirs
                        // so we can add to difference; move mine, but not theirs
                        if (mine.startsBeforeDisjoint(theirs))
                        {
                            diff.add(mine);
                            mine = null;
                            if (thisIter.MoveNext())
                            {
                                mine = (Interval)thisIter.Current;
                            }
                        }
                        // SUBCASE 1c: theirs is completely to the left of mine
                        else
                        {
                            // keep looking in theirs
                            theirs = null;
                            if (otherIter.MoveNext())
                            {
                                theirs = (Interval)otherIter.Current;
                            }
                        }
                    }
                }
                else
                {
                    // CASE 2: theirs breaks mine into two chunks
                    if (mine.properlyContains(theirs))
                    {
                        // must add two intervals: stuff to left and stuff to right
                        diff.add(mine.a, theirs.a - 1);
                        // don't actually add stuff to right yet as next 'theirs'
                        // might overlap with it
                        // The stuff to the right might overlap with next "theirs".
                        // so it is considered next
                        Interval right = new Interval(theirs.b + 1, mine.b);
                        mine = right;
                        // move theirs forward
                        theirs = null;
                        if (otherIter.MoveNext())
                        {
                            theirs = (Interval)otherIter.Current;
                        }
                    }

                    // CASE 3: theirs covers mine; nothing to add to diff
                    else if (theirs.properlyContains(mine))
                    {
                        // nothing to add, theirs forces removal totally of mine
                        // just move mine looking for an overlapping interval
                        mine = null;
                        if (thisIter.MoveNext())
                        {
                            mine = (Interval)thisIter.Current;
                        }
                    }

                    // CASE 4: non proper overlap
                    else
                    {
                        // overlap, but not properly contained
                        diff.add(mine.differenceNotProperlyContained(theirs));
                        // update iterators
                        bool moveTheirs = true;
                        if (mine.startsBeforeNonDisjoint(theirs) ||
                            theirs.b > mine.b)
                        {
                            // uh oh, right of theirs extends past right of mine
                            // therefore could overlap with next of mine so don't
                            // move theirs iterator yet
                            moveTheirs = false;
                        }
                        // always move mine
                        mine = null;
                        if (thisIter.MoveNext())
                        {
                            mine = (Interval)thisIter.Current;
                        }
                        if (moveTheirs)
                        {
                            theirs = null;
                            if (otherIter.MoveNext())
                            {
                                theirs = (Interval)otherIter.Current;
                            }
                        }
                    }
                }
            }
            return(diff);
        }