/// <summary>
        /// Merges the segments at the specified indices.
        /// </summary>
        /// <param name="firstRowIndex">The first row index.</param>
        /// <param name="firstColumnIndex">The first column index.</param>
        /// <param name="secondRowIndex">The second row index.</param>
        /// <param name="secondColumnIndex">The second column index.</param>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// The first row index is less than 0.
        /// or
        /// The first row index is equal to or greater than the number of rows.
        /// or
        /// The first column index is less than 0.
        /// or
        /// The first column index is equal to or greater than the number of columns.
        /// or
        /// The second row index is less than 0.
        /// or
        /// The second row index is equal to or greater than the number of rows.
        /// or
        /// The second column index is less than 0.
        /// or
        /// The second column index is equal to or greater than the number of columns.
        /// </exception>
        public virtual void MergeSegments(Int32 firstRowIndex, Int32 firstColumnIndex, Int32 secondRowIndex, Int32 secondColumnIndex)
        {
            if (firstRowIndex < 0)
            {
                throw new ArgumentOutOfRangeException("firstRowIndex", "The first row index is less than 0.");
            }
            if (firstRowIndex >= Raster.NumberOfRows)
            {
                throw new ArgumentOutOfRangeException("firstRowIndex", "The first row index is equal to or greater than the number of rows.");
            }
            if (firstColumnIndex < 0)
            {
                throw new ArgumentOutOfRangeException("firstColumnIndex", "The first column index is less than 0.");
            }
            if (firstColumnIndex >= Raster.NumberOfColumns)
            {
                throw new ArgumentOutOfRangeException("firstColumnIndex", "The first column index is equal to or greater than the number of columns.");
            }
            if (secondRowIndex < 0)
            {
                throw new ArgumentOutOfRangeException("secondRowIndex", "The second row index is less than 0.");
            }
            if (secondRowIndex >= Raster.NumberOfRows)
            {
                throw new ArgumentOutOfRangeException("secondRowIndex", "The second row index is equal to or greater than the number of rows.");
            }
            if (secondColumnIndex < 0)
            {
                throw new ArgumentOutOfRangeException("secondColumnIndex", "The second column index is less than 0.");
            }
            if (secondColumnIndex >= Raster.NumberOfColumns)
            {
                throw new ArgumentOutOfRangeException("secondColumnIndex", "The second column index is equal to or greater than the number of columns.");
            }

            // query the sets
            Int32 firstIndex  = firstRowIndex * Raster.NumberOfColumns + firstColumnIndex;
            Int32 secondIndex = secondRowIndex * Raster.NumberOfColumns + secondColumnIndex;

            if (firstIndex == secondIndex)
            {
                return;
            }

            // apply merge on the available set
            if (!_indexToSegmentDictionary.ContainsKey(firstIndex))
            {
                if (!_indexToSegmentDictionary.ContainsKey(secondIndex))
                {
                    Segment segment = new Segment(Raster.GetFloatValues(firstRowIndex, firstColumnIndex), Statistics);
                    segment.AddFloatValues(Raster.GetFloatValues(secondRowIndex, secondColumnIndex));

                    _indexToSegmentDictionary.Add(firstIndex, segment);
                    _indexToSegmentDictionary.Add(secondIndex, segment);
                    _segmentToIndexDictionary.Add(segment, new List <Int32> {
                        firstIndex, secondIndex
                    });

                    Count--;
                }
                else
                {
                    ApplyMergeSegments(_indexToSegmentDictionary[secondIndex], firstIndex);
                }
            }
            else if (!_indexToSegmentDictionary.ContainsKey(secondIndex))
            {
                ApplyMergeSegments(_indexToSegmentDictionary[firstIndex], secondIndex);
            }
            else // or merge the sets
            {
                Segment firstSegment  = _indexToSegmentDictionary[firstIndex];
                Segment secondSegment = _indexToSegmentDictionary[secondIndex];
                if (firstSegment == secondSegment)
                {
                    return;
                }

                if (firstSegment.Count > secondSegment.Count)
                {
                    ApplyMergeSegments(firstSegment, secondSegment);
                }
                else
                {
                    ApplyMergeSegments(secondSegment, firstSegment);
                }
            }
        }
 /// <summary>
 /// Determines whether the collection contains the specified segment.
 /// </summary>
 /// <param name="segment">The segment.</param>
 /// <returns><c>true</c> if the collection contains the segment; otherwise <c>false</c>.</returns>
 public virtual Boolean Contains(Segment segment)
 {
     return(_segmentToIndexDictionary.ContainsKey(segment));
 }