Пример #1
0
 /// <summary>
 /// Given a node object, calculate the node Minimum Bounding Rectangle from it's entries. Used in consistency checking
 /// </summary>
 /// <returns></returns>  
 internal Rectangle calculateMinimumBoundingRectangle()
 {
   minimumBoundingRectangle = new Rectangle(true);
   Update();
   for (int i = 0; i < entryCount; i++)
   {
     if (entries[i].Value.MinX < minimumBoundingRectangle.MinX)
     {
       minimumBoundingRectangle.MinX = entries[i].Value.MinX;
     }
     if (entries[i].Value.MinY < minimumBoundingRectangle.MinY)
     {
       minimumBoundingRectangle.MinY = entries[i].Value.MinY;
     }
     if (entries[i].Value.MaxX > minimumBoundingRectangle.MaxX)
     {
       minimumBoundingRectangle.MaxX = entries[i].Value.MaxX;
     }
     if (entries[i].Value.MaxY > minimumBoundingRectangle.MaxY)
     {
       minimumBoundingRectangle.MaxY = entries[i].Value.MaxY;
     }
   }
   return minimumBoundingRectangle;
 }
Пример #2
0
    /// <summary>
    /// Start at the Root Node
    /// Select the child that needs the least enlargement in order to fit the new geometry.
    /// Repeat until at a leaf node.
    /// If leaf node has available space insert Else split the entry into two nodes
    /// Update parent nodes
    /// Update the entry that pointed to the node with a new minimum bounding rectangle
    /// Add a new entry for the second new node
    /// If there is no space in the parent node, split and repeat
    /// </summary>
    /// <param name="r">the rectangle being added</param>
    public void Add(Rectangle r)
    {
      AddInternal(r);
      size++;
#if RtreeCheck
      checkConsistency();
#endif
    }
Пример #3
0
 internal void addEntry(ref Rectangle r)
 {
   Update();
   entries[entryCount++] = r;
   if (r.MinX < minimumBoundingRectangle.MinX)
     minimumBoundingRectangle.MinX = r.MinX;
   if (r.MinY < minimumBoundingRectangle.MinY)
     minimumBoundingRectangle.MinY = r.MinY;
   if (r.MaxX > minimumBoundingRectangle.MaxX)
     minimumBoundingRectangle.MaxX = r.MaxX;
   if (r.MaxY > minimumBoundingRectangle.MaxY)
     minimumBoundingRectangle.MaxY = r.MaxY;
 }
Пример #4
0
    internal Rectangle calculateMBR()
    {
      Rectangle mbr = new Rectangle(true);

      for (int i = 0; i < entryCount; i++)
      {
        if (entries[i].Value.MinX < mbr.MinX)
          mbr.MinX = entries[i].Value.MinX;
        if (entries[i].Value.MinY < mbr.MinY)
          mbr.MinY = entries[i].Value.MinY;
        if (entries[i].Value.MaxX > mbr.MaxX)
          mbr.MaxX = entries[i].Value.MaxX;
        if (entries[i].Value.MaxY > mbr.MaxY)
          mbr.MaxY = entries[i].Value.MaxY;
      }
      return mbr;
    }
Пример #5
0
 /// <summary>
 /// Computes the union of this rectangle and the passed rectangle, storing the result in this rectangle.
 /// </summary>
 /// <param name="r">Rectangle to add to this rectangle</param> 
 public void Add(Rectangle r)
 {
   if (r.minX < minX)
     minX = r.minX;
   if (r.maxX > maxX)
     maxX = r.maxX;
   if (r.minY < minY)
     minY = r.minY;
   if (r.maxY > maxY)
     maxY = r.maxY;
 }
Пример #6
0
    /// <summary>
    /// Calculate the area by which this rectangle would be enlarged if added to the passed rectangle. Neither rectangle is altered.
    /// </summary>
    /// <param name="r">Rectangle to union with this rectangle, in order to compute the difference in area of the union and the original rectangle</param>
    /// <returns>enlargement</returns> 
    public double Enlargement(ref Rectangle r)
    {
      double enlargedArea = (Math.Max(maxX, r.maxX) - Math.Min(minX, r.minX)) * (Math.Max(maxY, r.maxY) - Math.Min(minY, r.minY));

      return enlargedArea - Area;
    }
Пример #7
0
 /// <summary>
 /// Determine whether this rectangle is contained by the passed rectangle
 /// </summary>
 /// <param name="r">The rectangle that might contain this rectangle</param>
 /// <returns>return true if the passed rectangle contains this rectangle, false if it does not</returns> 
 public bool containedBy(Rectangle r)
 {
   return r.maxX >= maxX && r.minX <= minX && r.maxY >= maxY && r.minY <= minY;
 }
Пример #8
0
 /// <summary>
 /// Determine whether this rectangle intersects the passed rectangle
 /// </summary>
 /// <param name="r">The rectangle that might intersect this rectangle</param>
 /// <returns>return true if the rectangles intersect, false if they do not intersect</returns>
 public bool Intersects(ref Rectangle? r)
 {
   return maxX >= r.Value.minX && minX <= r.Value.maxX && maxY >= r.Value.minY && minY <= r.Value.maxY;
 }
Пример #9
0
 /// <summary>
 /// Determine whether an edge of this rectangle overlies the equivalent edge of the passed rectangle
 /// </summary>
 /// <param name="r"></param>
 /// <returns></returns>
 public bool edgeOverlaps(Rectangle r)
 {
   return minX == r.minX || maxX == r.maxX || minY == r.minY || maxY == r.maxY;
 }
Пример #10
0
    internal NodeLeaf splitNode(RTree rTree, Rectangle r)
    {
      // [Pick first entry for each group] Apply algorithm pickSeeds to 
      // choose two entries to be the first elements of the groups. Assign
      // each to a group.

      // debug code
      /*double initialArea = 0;
           if (log.isDebugEnabled())
           {
             double unionMinX = Math.Min(n.mbrMinX, newRectMinX);
             double unionMinY = Math.Min(n.mbrMinY, newRectMinY);
             double unionMaxX = Math.Max(n.mbrMaxX, newRectMaxX);
             double unionMaxY = Math.Max(n.mbrMaxY, newRectMaxY);

             initialArea = (unionMaxX - unionMinX) * (unionMaxY - unionMinY);
           }*/

      System.Array.Copy(rTree.initialEntryStatus, 0, rTree.entryStatus, 0, rTree.maxNodeEntries);
      Update();
      NodeLeaf newNode = null;
      newNode = new NodeLeaf(level, rTree.maxNodeEntries);

      pickSeeds(rTree, ref r, newNode); // this also sets the entryCount to 1

      // [Check if done] If all entries have been assigned, stop. If one group has so few entries that all the rest must be assigned to it in 
      // order for it to have the minimum number m, assign them and stop. 
      while (entryCount + newNode.entryCount < rTree.maxNodeEntries + 1)
      {
        if (rTree.maxNodeEntries + 1 - newNode.entryCount == rTree.minNodeEntries)
        {
          // assign all remaining entries to original node
          for (int i = 0; i < rTree.maxNodeEntries; i++)
          {
            if (rTree.entryStatus[i] == ((byte)RTree.EntryStatus.unassigned))
            {
              rTree.entryStatus[i] = ((byte)RTree.EntryStatus.assigned);

              if (entries[i].Value.MinX < minimumBoundingRectangle.MinX)
                minimumBoundingRectangle.MinX = entries[i].Value.MinX;
              if (entries[i].Value.MinY < minimumBoundingRectangle.MinY)
                minimumBoundingRectangle.MinY = entries[i].Value.MinY;
              if (entries[i].Value.MaxX > minimumBoundingRectangle.MaxX)
                minimumBoundingRectangle.MaxX = entries[i].Value.MaxX;
              if (entries[i].Value.MaxY > minimumBoundingRectangle.MaxY)
                minimumBoundingRectangle.MaxY = entries[i].Value.MaxY;
              entryCount++;
            }
          }
          break;
        }
        if (rTree.maxNodeEntries + 1 - entryCount == rTree.minNodeEntries)
        {
          // assign all remaining entries to new node
          for (int i = 0; i < rTree.maxNodeEntries; i++)
          {
            if (rTree.entryStatus[i] == ((byte)RTree.EntryStatus.unassigned))
            {
              rTree.entryStatus[i] = ((byte)RTree.EntryStatus.assigned);
              Rectangle entryR = entries[i].Value;
              newNode.addEntry(ref entryR);
              entries[i] = null;
            }
          }
          break;
        }

        // [Select entry to assign] Invoke algorithm pickNext to choose the next entry to assign. Add it to the group whose covering rectangle 
        // will have to be enlarged least to accommodate it. Resolve ties by adding the entry to the group with smaller area, then to the 
        // the one with fewer entries, then to either. Repeat from S2
        pickNext(rTree, newNode);
      }

      reorganize(rTree);

      // check that the MBR stored for each node is correct.
#if RtreeCheck
        if (!this.minimumBoundingRectangle.Equals(calculateMBR()))
        {
          throw new UnexpectedException("Error: splitNode old node MBR wrong");
        }
        if (!newNode.minimumBoundingRectangle.Equals(newNode.calculateMBR()))
        {
          throw new UnexpectedException("Error: splitNode new node MBR wrong");
        }
#endif

#if RtreeCheck
        double newArea = minimumBoundingRectangle.Area + newNode.minimumBoundingRectangle.Area;
        double percentageIncrease = (100 * (newArea - initialArea)) / initialArea;
        Console.WriteLine("Node " + this + " split. New area increased by " + percentageIncrease + "%");
#endif

      return newNode;
    }
Пример #11
0
 // Return the index of the found entry, or -1 if not found
 internal virtual int findEntry(ref Rectangle r)
 {
   for (int i = 0; i < entryCount; i++)
   {
     if (entries[i].Value.Equals(r))
       return i;
   }
   return -1;
 }
Пример #12
0
    private void pickSeeds(RTree rTree, ref Rectangle r, NodeLeaf newNode)
    {
      // Find extreme rectangles along all dimension. Along each dimension, find the entry whose rectangle has the highest low side, and the one 
      // with the lowest high side. Record the separation.
      double maxNormalizedSeparation = -1; // initialize to -1 so that even overlapping rectangles will be considered for the seeds
      int highestLowIndex = -1;
      int lowestHighIndex = -1;
      Update();
      // for the purposes of picking seeds, take the MBR of the node to include the new rectangle aswell.
      if (r.MinX < minimumBoundingRectangle.MinX)
        minimumBoundingRectangle.MinX = r.MinX;
      if (r.MinY < minimumBoundingRectangle.MinY)
        minimumBoundingRectangle.MinY = r.MinY;
      if (r.MaxX > minimumBoundingRectangle.MaxX)
        minimumBoundingRectangle.MaxX = r.MaxX;
      if (r.MaxY > minimumBoundingRectangle.MaxY)
        minimumBoundingRectangle.MaxY = r.MaxY;

      double mbrLenX = minimumBoundingRectangle.MaxX - minimumBoundingRectangle.MinX;
      double mbrLenY = minimumBoundingRectangle.MaxY - minimumBoundingRectangle.MinY;

#if RtreeCheck
        Console.WriteLine("pickSeeds(): Node = " + this);
#endif

      double tempHighestLow = r.MinX;
      int tempHighestLowIndex = -1; // -1 indicates the new rectangle is the seed

      double tempLowestHigh = r.MaxX;
      int tempLowestHighIndex = -1; // -1 indicates the new rectangle is the seed

      for (int i = 0; i < entryCount; i++)
      {
        double tempLow = entries[i].Value.MinX;
        if (tempLow >= tempHighestLow)
        {
          tempHighestLow = tempLow;
          tempHighestLowIndex = i;
        } // ensure that the same index cannot be both lowestHigh and highestLow
        else
        {
          double tempHigh = entries[i].Value.MaxX;
          if (tempHigh <= tempLowestHigh)
          {
            tempLowestHigh = tempHigh;
            tempLowestHighIndex = i;
          }
        }

        // PS2 [Adjust for shape of the rectangle cluster] Normalize the separations by dividing by the widths of the entire set along the corresponding dimension
        double normalizedSeparation = mbrLenX == 0 ? 1 : (tempHighestLow - tempLowestHigh) / mbrLenX;
        if (normalizedSeparation > 1 || normalizedSeparation < -1)
        {
          Console.WriteLine("Invalid normalized separation X");
        }

#if RtreeCheck
          Console.WriteLine("Entry " + i + ", dimension X: HighestLow = " + tempHighestLow + " (index " + tempHighestLowIndex + ")" + ", LowestHigh = " + tempLowestHigh + " (index " + tempLowestHighIndex + ", NormalizedSeparation = " + normalizedSeparation);
#endif
        // PS3 [Select the most extreme pair] Choose the pair with the greatest normalized separation along any dimension.
        // Note that if negative it means the rectangles overlapped. However still include overlapping rectangles if that is the only choice available.
        if (normalizedSeparation >= maxNormalizedSeparation)
        {
          highestLowIndex = tempHighestLowIndex;
          lowestHighIndex = tempLowestHighIndex;
          maxNormalizedSeparation = normalizedSeparation;
        }
      }

      // Repeat for the Y dimension
      tempHighestLow = r.MinY;
      tempHighestLowIndex = -1; // -1 indicates the new rectangle is the seed

      tempLowestHigh = r.MaxY;
      tempLowestHighIndex = -1; // -1 indicates the new rectangle is the seed

      for (int i = 0; i < entryCount; i++)
      {
        double tempLow = entries[i].Value.MinY;
        if (tempLow >= tempHighestLow)
        {
          tempHighestLow = tempLow;
          tempHighestLowIndex = i;
        } // ensure that the same index cannot be both lowestHigh and highestLow
        else
        {
          double tempHigh = entries[i].Value.MaxY;
          if (tempHigh <= tempLowestHigh)
          {
            tempLowestHigh = tempHigh;
            tempLowestHighIndex = i;
          }
        }

        // PS2 [Adjust for shape of the rectangle cluster] Normalize the separations by dividing by the widths of the entire set along the corresponding dimension
        double normalizedSeparation = mbrLenY == 0 ? 1 : (tempHighestLow - tempLowestHigh) / mbrLenY;
        if (normalizedSeparation > 1 || normalizedSeparation < -1)
        {
          throw new UnexpectedException("Invalid normalized separation Y");
        }
#if RtreeCheck
          Console.WriteLine("Entry " + i + ", dimension Y: HighestLow = " + tempHighestLow + " (index " + tempHighestLowIndex + ")" + ", LowestHigh = " + tempLowestHigh + " (index " + tempLowestHighIndex + ", NormalizedSeparation = " + normalizedSeparation);
#endif
        // PS3 [Select the most extreme pair] Choose the pair with the greatest normalized separation along any dimension.
        // Note that if negative it means the rectangles overlapped. However still include overlapping rectangles if that is the only choice available.
        if (normalizedSeparation >= maxNormalizedSeparation)
        {
          highestLowIndex = tempHighestLowIndex;
          lowestHighIndex = tempLowestHighIndex;
          maxNormalizedSeparation = normalizedSeparation;
        }
      }

      // At this point it is possible that the new rectangle is both highestLow and lowestHigh. This can happen if all rectangles in the node overlap the new rectangle.
      // Resolve this by declaring that the highestLowIndex is the lowest Y and, the lowestHighIndex is the largest X (but always a different rectangle)
      if (highestLowIndex == lowestHighIndex)
      {
        highestLowIndex = -1;
        double tempMinY = r.MinY;
        lowestHighIndex = 0;
        double tempMaxX = entries[0].Value.MaxX;

        for (int i = 1; i < entryCount; i++)
        {
          if (entries[i].Value.MinY < tempMinY)
          {
            tempMinY = entries[i].Value.MinY;
            highestLowIndex = i;
          }
          else if (entries[i].Value.MaxX > tempMaxX)
          {
            tempMaxX = entries[i].Value.MaxX;
            lowestHighIndex = i;
          }
        }
      }

      // highestLowIndex is the seed for the new node.
      if (highestLowIndex == -1)
        newNode.addEntry(ref r);
      else
      {
        Rectangle entryRectangle = entries[highestLowIndex].Value;
        newNode.addEntry(ref entryRectangle);
        entries[highestLowIndex] = r;  // move the new rectangle into the space vacated by the seed for the new node
      }

      // lowestHighIndex is the seed for the original node. 
      if (lowestHighIndex == -1)
        lowestHighIndex = highestLowIndex;

      rTree.entryStatus[lowestHighIndex] = ((byte)RTree.EntryStatus.assigned);
      entryCount = 1;
      minimumBoundingRectangle = entries[lowestHighIndex].Value;
    }
Пример #13
0
    internal virtual void recalculateMBR()
    {
      Update();
      minimumBoundingRectangle = entries[0].Value;

      for (int i = 1; i < entryCount; i++)
      {
        if (entries[i].Value.MinX < minimumBoundingRectangle.MinX)
          minimumBoundingRectangle.MinX = entries[i].Value.MinX;
        if (entries[i].Value.MinY < minimumBoundingRectangle.MinY)
          minimumBoundingRectangle.MinY = entries[i].Value.MinY;
        if (entries[i].Value.MaxX > minimumBoundingRectangle.MaxX)
          minimumBoundingRectangle.MaxX = entries[i].Value.MaxX;
        if (entries[i].Value.MaxY > minimumBoundingRectangle.MaxY)
          minimumBoundingRectangle.MaxY = entries[i].Value.MaxY;
      }
    }
Пример #14
0
    /// <summary>
    /// Adds a new entry at a specified level in the tree
    /// </summary>
    /// <param name="r">the rectangle added</param>
    internal void AddInternal(Rectangle r)
    {
      // I1 [Find position for new record] Invoke ChooseLeaf to select a leaf node L in which to place r
      NodeLeaf n = (NodeLeaf) chooseNode(r, 1);
      NodeLeaf newLeaf = null;

      // I2 [Add record to leaf node] If L has room for another entry, install E. Otherwise invoke SplitNode to obtain L and LL containing E and all the old entries of L
      if (n.entryCount < maxNodeEntries)
        n.addEntry(ref r);
      else
        newLeaf = n.splitNode(this, r);

      // I3 [Propagate changes upwards] Invoke AdjustTree on L, also passing LL if a split was performed
      NodeBase newNode = n.adjustTree(this, newLeaf);

      // I4 [Grow tree taller] If node split propagation caused the root to split, create a new root whose children are the two resulting nodes.
      if (newNode != null)
      {
        NodeBase oldRoot = rootNode;
        NodeInternal root = new NodeInternal(++treeHeight, maxNodeEntries);
        rootNode = root;
        root.addEntry(ref newNode.minimumBoundingRectangle, newNode);
        root.addEntry(ref oldRoot.minimumBoundingRectangle, oldRoot);
      }
    }
Пример #15
0
    /// <summary>
    /// Removes a rectangle from the Rtree
    /// </summary>
    /// <param name="r">the rectangle to delete</param>
    /// <returns>true if rectangle deleted otherwise false</returns>
    public bool Remove(Rectangle r)
    {
      // FindLeaf algorithm inlined here. Note the "official" algorithm searches all overlapping entries. This seems inefficient, 
      // as an entry is only worth searching if it contains (NOT overlaps) the rectangle we are searching for.

      // FL1 [Search subtrees] If root is not a leaf, check each entry to determine if it contains r. For each entry found, invoke
      // findLeaf on the node pointed to by the entry, until r is found or all entries have been checked.
      parents.Clear();
      parents.Push(rootNode);

      parentsEntry.Clear();
      parentsEntry.Push(-1);
      NodeBase n = null;
      int foundIndex = -1; // index of entry to be deleted in leaf

      while (foundIndex == -1 && parents.Count > 0)
      {
        n = parents.Peek();
        int startIndex = parentsEntry.Peek() + 1;

        if (!n.IsLeaf)
        {
          NodeInternal internalNode = n as NodeInternal;
          bool Contains = false;
          for (int i = startIndex; i < n.entryCount; i++)
          {
            if (n.entries[i].Value.Contains(r))
            {
              parents.Push(internalNode.childNodes[i]);
              parentsEntry.Pop();
              parentsEntry.Push(i); // this becomes the start index when the child has been searched
              parentsEntry.Push(-1);
              Contains = true;
              break; // ie go to next iteration of while()
            }
          }
          if (Contains)
            continue;
        }
        else
        {
          NodeLeaf leaf = n as NodeLeaf;
          foundIndex = leaf.findEntry(ref r);
        }

        parents.Pop();
        parentsEntry.Pop();
      } // while not found

      if (foundIndex != -1)
      {
        NodeLeaf leaf = n as NodeLeaf;
        leaf.deleteEntry(foundIndex);
        leaf.condenseTree(this);
        size--;
      }

      // shrink the tree if possible (i.e. if root node has exactly one entry, and that entry is not a leaf node, delete the root (it's entry becomes the new root)
      NodeBase root = rootNode;
      while (root.entryCount == 1 && treeHeight > 1)
      {
        NodeInternal rootInternal = root as NodeInternal;
        root.entryCount = 0;
        rootNode = rootInternal.childNodes[0];
        treeHeight--;     
      }

      // if the tree is now empty, then set the MBR of the root node back to it's original state (this is only needed when the tree is empty,
      // as this is the only state where an empty node is not eliminated)
      if (size == 0)
        rootNode.minimumBoundingRectangle = new Rectangle(true);

#if RtreeCheck
      checkConsistency();
#endif

      return (foundIndex != -1);
    }
Пример #16
0
 /// <summary>
 /// Sets the size of this rectangle to equal the passed rectangle.
 /// </summary>
 /// <param name="r"></param>  
 public void set(Rectangle r)
 {
   minX = r.minX;
   minY = r.minY;
   maxX = r.maxX;
   maxY = r.maxY;
 }
Пример #17
0
 /// <summary>
 /// Finds all rectangles that intersect the passed rectangle.
 /// </summary>
 /// <param name="r">the rectangle we are intersecting with</param>
 /// <param name="v">if returns true, search containues else search is ended</param>
 /// <returns>true if at least one intersection was found and v returns true</returns>
 public bool Intersects(Rectangle r, Func<Rectangle, bool> v)
 {
   return intersects(r, v, rootNode);
 }
Пример #18
0
 public bool Equals(Rectangle r)
 {
   return minX == r.minX && minY == r.minY && maxX == r.maxX && maxY == r.maxY;
 }
Пример #19
0
    /// <summary>
    /// Finds all rectangles contained by the passed rectangle
    /// </summary>
    /// <param name="r">The rectangle for which this method finds contained rectangles.</param>
    /// <param name="v">if return true, continue seach</param>
    public void Contains(Rectangle r, Func<Rectangle, bool> v)
    {
      // find all rectangles in the tree that are contained by the passed rectangle written to be non-recursive (should model other searches on this?)
      parents.Clear();
      parents.Push(rootNode);

      parentsEntry.Clear();
      parentsEntry.Push(-1);

      // TODO: possible shortcut here - could test for intersection with the MBR of the root node. If no intersection, return immediately.
      while (parents.Count > 0)
      {
        NodeBase n = parents.Peek();
        int startIndex = parentsEntry.Peek() + 1;

        if (!n.IsLeaf)
        {
          NodeInternal nodeInternal = n as NodeInternal;
          // go through every entry in the index node to check if it intersects the passed rectangle. If so, it could contain entries that are contained.
          bool intersects = false;
          for (int i = startIndex; i < n.entryCount; i++)
          {
            if (r.Intersects(ref n.entries[i]))
            {
              parents.Push(nodeInternal.childNodes[i]);
              parentsEntry.Pop();
              parentsEntry.Push(i); // this becomes the start index when the child has been searched
              parentsEntry.Push(-1);
              intersects = true;
              break; // ie go to next iteration of while()
            }
          }
          if (intersects)
          {
            continue;
          }
        }
        else
        {
          // go through every entry in the leaf to check if it is contained by the passed rectangle
          for (int i = 0; i < n.entryCount; i++)
          {
            if (r.Contains(n.entries[i].Value))
            {
              if (!v(n.entries[i].Value))
              {
                return;
              }
            }
          }
        }
        parents.Pop();
        parentsEntry.Pop();
      }
    }
Пример #20
0
 /// <summary>
 /// Determine whether this rectangle contains the passed rectangle
 /// </summary>
 /// <param name="r">The rectangle that might be contained by this rectangle</param>
 /// <returns>return true if this rectangle contains the passed rectangle, false if it does not</returns>
 public bool Contains(Rectangle r)
 {
   return maxX >= r.maxX && minX <= r.minX && maxY >= r.maxY && minY <= r.minY;
 }
Пример #21
0
 /// <summary>
 /// Recursively searches the tree for all intersecting entries.
 /// Calls the passed function when a matching entry is found. Return if the passed function returns false;
 /// </summary>
 /// <param name="r"></param>
 /// <param name="v"></param>
 /// <param name="n"></param>
 /// <returns></returns>
 // TODO rewrite this to be non-recursive.
 private bool intersects(Rectangle r, Func<Rectangle, bool> v, NodeBase n)
 {
   for (int i = 0; i < n.entryCount; i++)
   {
     if (r.Intersects(ref n.entries[i]))
     {
       if (n.IsLeaf)
       {
         if (!v(n.entries[i].Value))
         {
           return false;
         }
       }
       else
       {
         NodeInternal nodeInternal = n as NodeInternal;
         NodeInternal childNode = nodeInternal.childNodes[i] as NodeInternal;
         if (!intersects(r, v, childNode))
         {
           return false;
         }
       }
     }
   }
   return true;
 }
Пример #22
0
 /// <summary>
 /// Return the distance between this rectangle and the passed rectangle. If the rectangles overlap, the distance is zero.
 /// </summary>
 /// <param name="r">Rectangle to find the distance to</param>
 /// <returns>return distance between this rectangle and the passed rectangle</returns>
 public double Distance(Rectangle r)
 {
   double distanceSquared = 0;
   double greatestMin = Math.Max(minX, r.minX);
   double leastMax = Math.Min(maxX, r.maxX);
   if (greatestMin > leastMax)
   {
     distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax));
   }
   greatestMin = Math.Max(minY, r.minY);
   leastMax = Math.Min(maxY, r.maxY);
   if (greatestMin > leastMax)
   {
     distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax));
   }
   return (double)Math.Sqrt(distanceSquared);
 }
Пример #23
0
    /// <summary>
    /// Used by add(). Chooses a leaf to add the rectangle to.
    /// </summary>
    /// <param name="r"></param>
    /// <param name="level"></param>
    /// <returns></returns> 
    private NodeBase chooseNode(Rectangle r, int level)
    {
      // CL1 [Initialize] Set N to be the root node
      NodeBase n = rootNode;
      parents.Clear();
      parentsEntry.Clear();

      // CL2 [Leaf check] If N is a leaf, return N
      while (true)
      {
        if (n == null)
          throw new UnexpectedException("Could not get root node (" + rootNode + ")");

        if (n.level == level)
          return n;

        NodeInternal nodeInternal = n as NodeInternal;
        // CL3 [Choose subtree] If N is not at the desired level, let F be the entry in N whose rectangle FI needs least enlargement to include EI. Resolve
        // ties by choosing the entry with the rectangle of smaller area.
        double leastEnlargement = n.entries[0].Value.Enlargement(ref r);
        int index = 0; // index of rectangle in subtree
        for (int i = 1; i < n.entryCount; i++)
        {
          double tempEnlargement = n.entries[i].Value.Enlargement(ref r);
          if (tempEnlargement < leastEnlargement || (tempEnlargement == leastEnlargement && n.entries[i].Value.Area < n.entries[index].Value.Area))
          {
            index = i;
            leastEnlargement = tempEnlargement;
          }
        }

        parents.Push(n);
        parentsEntry.Push(index);

        // CL4 [Descend until a leaf is reached] Set N to be the child node pointed to by Fp and repeat from CL2
        n = nodeInternal.childNodes[index];
      }
    }
Пример #24
0
    /// <summary>
    /// Calculate the area by which a rectangle would be enlarged if added to the passed rectangle
    /// </summary>
    /// <param name="r1">minimum X coordinate of rectangle 1</param>
    /// <param name="r2">minimum X coordinate of rectangle 2</param>
    /// <returns>return enlargement</returns> 
    public static double enlargement(Rectangle r1, Rectangle r2)
    {
      double r1Area = (r1.maxX - r1.minX) * (r1.maxY - r1.minY);

      if (r1Area == double.PositiveInfinity)
        return 0; // cannot enlarge an infinite rectangle...

      double r1r2UnionArea = Math.Max(r1.maxX, r2.maxX) - Math.Min(r1.minX, r2.minX) * (Math.Max(r1.maxY, r2.maxY) - Math.Min(r1.minY, r2.minY));

      if (r1r2UnionArea == double.PositiveInfinity)        
        return double.PositiveInfinity;  // if a finite rectangle is enlarged and becomes infinite, then the enlargement must be infinite.
      return r1r2UnionArea - r1Area;
    }
Пример #25
0
    private bool checkConsistency(NodeBase n, int expectedLevel, Rectangle? expectedMBR)
    {
      // go through the tree, and check that the internal data structures of the tree are not corrupted.        

      if (n == null)
        throw new UnexpectedException("Error: Could not read node " + this);

      // if tree is empty, then there should be exactly one node, at level 1
      // TODO: also check the MBR is as for a new node
      if (n == rootNode && Count == 0)
      {
        if (n.level != 1)
          throw new UnexpectedException("Error: tree is empty but root node is not at level 1");
      }

      if (n.level != expectedLevel)
        throw new UnexpectedException("Error: Node " + this + ", expected level " + expectedLevel + ", actual level " + n.level);

      Rectangle calculatedMBR = n.calculateMinimumBoundingRectangle();
      Rectangle actualMBR = n.minimumBoundingRectangle;
      if (!actualMBR.Equals(calculatedMBR))
      {
        if (actualMBR.MinX != n.minimumBoundingRectangle.MinX)
          throw new UnexpectedException("  actualMinX=" + actualMBR.MinX + ", calc=" + calculatedMBR.MinX);
        if (actualMBR.MinY != n.minimumBoundingRectangle.MinY)
          throw new UnexpectedException("  actualMinY=" + actualMBR.MinY + ", calc=" + calculatedMBR.MinY);
        if (actualMBR.MaxX != n.minimumBoundingRectangle.MaxX)
          throw new UnexpectedException("  actualMaxX=" + actualMBR.MaxX + ", calc=" + calculatedMBR.MaxX);
        if (actualMBR.MaxY != n.minimumBoundingRectangle.MaxY)
          throw new UnexpectedException("  actualMaxY=" + actualMBR.MaxY + ", calc=" + calculatedMBR.MaxY);
        throw new UnexpectedException("Error: Node " + this + ", calculated MBR does not equal stored MBR");
      }

      if (expectedMBR != null && !actualMBR.Equals(expectedMBR))
        throw new UnexpectedException("Error: Node " + this + ", expected MBR (from parent) does not equal stored MBR");

      for (int i = 0; i < n.entryCount; i++)
      {
        if (n.level > 1) // if not a leaf
        {
          NodeInternal nodeInternal = n as NodeInternal;
          if (nodeInternal.childNodes[i] == null)
            throw new UnexpectedException("Error: Node " + this + ", Entry " + i + " is null");
          if (!checkConsistency(nodeInternal.childNodes[i], n.level - 1, n.entries[i]))
          {
            return false;
          }
        }
      }
      return true;
    }
Пример #26
0
 /// <summary>
 /// Find the the union of this rectangle and the passed rectangle.Neither rectangle is altered
 /// </summary>
 /// <param name="r">The rectangle to union with this rectangle</param>
 /// <returns></returns>
 public Rectangle union(Rectangle r)
 {
   Rectangle union = this;
   union.Add(r);
   return union;
 }
Пример #27
0
 // deletedMin/MaxX/Y is a rectangle that has just been deleted or made smaller. Thus, the MBR is only recalculated if the deleted rectangle influenced the old MBR
 internal virtual void recalculateMBRIfInfluencedBy(ref Rectangle r)
 {
   if (minimumBoundingRectangle.MinX == r.MinX || minimumBoundingRectangle.MinY == r.MinY || minimumBoundingRectangle.MaxX == r.MaxX || minimumBoundingRectangle.MaxY == r.MaxY)
     recalculateMBR();
 }