Package sil.rtree

Source Code of sil.rtree.Node$RstarSplitEntryComparatorHigh

// Spatial Index Library
//
// Copyright (C) 2002  Navel Ltd.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License aint with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Contact information:
//  Mailing address:
//    Marios Hadjieleftheriou
//    University of California, Riverside
//    Department of Computer Science
//    Surge Building, Room 310
//    Riverside, CA 92521
//
//  Email:
//    marioh@cs.ucr.edu

package sil.rtree;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Stack;

import sil.spatialindex.INode;
import sil.spatialindex.IShape;
import sil.spatialindex.SpatialIndex;
import sil.spatialindex.Region;

abstract class Node implements INode
{
  protected RTree m_pTree = null;
    // Parent of all nodes.

  protected int m_level = -1;
    // The level of the node in the tree.
    // Leaves are always at level 0.

  protected int m_identifier = -1;
    // The unique ID of this node.

  protected int m_children = 0;
    // The number of children pointed by this node.

  protected int m_capacity = -1;
    // Specifies the node capacity.

  protected Region m_nodeMBR = null;
    // The minimum bounding region enclosing all data contained in the node.

  protected byte[][] m_pData = null;
    // The data stored in the node.

  protected Region[] m_pMBR = null;
    // The corresponding data MBRs.

  protected int[] m_pIdentifier = null;
    // The corresponding data identifiers.

  protected int[] m_pDataLength = null;

  int m_totalDataLength = 0;

  //
  // Abstract methods
  //

  protected abstract Node chooseSubtree(Region mbr, int level, Stack pathBuffer);
  protected abstract Leaf findLeaf(Region mbr, int id, Stack pathBuffer);
  protected abstract Node[] split(byte[] pData, Region mbr, int id);

  //
  // IEntry interface
  //

  public int getIdentifier()
  {
    return m_identifier;
  }

  public IShape getShape()
  {
    return (IShape) m_nodeMBR.clone();
  }

  //
  // INode interface
  //

  public int getChildrenCount()
  {
    return m_children;
  }

  public int getChildIdentifier(int index) throws IndexOutOfBoundsException
  {
    if (index < 0 || index >= m_children) throw new IndexOutOfBoundsException("" + index);

    return m_pIdentifier[index];
  }

  public IShape getChildShape(int index) throws IndexOutOfBoundsException
  {
    if (index < 0 || index >= m_children) throw new IndexOutOfBoundsException("" + index);

    return new Region(m_pMBR[index]);
  }

  public int getLevel()
  {
    return m_level;
  }

  public boolean isLeaf()
  {
    return (m_level == 0);
  }

  public boolean isIndex()
  {
    return (m_level != 0);
  }

  //
  // Internal
  //

  protected Node(RTree pTree, int id, int level, int capacity)
  {
    m_pTree = pTree;
    m_level = level;
    m_identifier = id;
    m_capacity = capacity;
    m_nodeMBR = (Region) pTree.m_infiniteRegion.clone();

    m_pDataLength = new int[m_capacity + 1];
    m_pData = new byte[m_capacity + 1][];
    m_pMBR = new Region[m_capacity + 1];
    m_pIdentifier = new int[m_capacity + 1];
  }

  protected void insertEntry(byte[] pData, Region mbr, int id) throws IllegalStateException
  {
    if (m_children >= m_capacity) throw new IllegalStateException("m_children >= m_nodeCapacity");

    m_pDataLength[m_children] = (pData != null) ? pData.length : 0;
    m_pData[m_children] = pData;
    m_pMBR[m_children] = mbr;
    m_pIdentifier[m_children] = id;

    m_totalDataLength += m_pDataLength[m_children];
    m_children++;

    Region.combinedRegion(m_nodeMBR, mbr);
  }

  protected void deleteEntry(int index) throws IndexOutOfBoundsException
  {
    if (index < 0 || index >= m_children) throw new IndexOutOfBoundsException("" + index);

    boolean touches = m_nodeMBR.touches(m_pMBR[index]);

    m_totalDataLength -= m_pDataLength[index];
    m_pData[index] = null;

    if (m_children > 1 && index != m_children - 1)
    {
      m_pDataLength[index] = m_pDataLength[m_children - 1];
      m_pData[index] = m_pData[m_children - 1];
      m_pData[m_children - 1] = null;
      m_pMBR[index] = m_pMBR[m_children - 1];
      m_pMBR[m_children - 1] = null;
      m_pIdentifier[index] = m_pIdentifier[m_children - 1];
    }

    m_children--;

    if (m_children == 0)
    {
      m_nodeMBR = (Region) m_pTree.m_infiniteRegion.clone();
    }
    else if (touches)
    {
      for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++)
      {
        m_nodeMBR.m_pLow[cDim] = Double.POSITIVE_INFINITY;
        m_nodeMBR.m_pHigh[cDim] = Double.NEGATIVE_INFINITY;

        for (int cChild = 0; cChild < m_children; cChild++)
        {
          m_nodeMBR.m_pLow[cDim] = Math.min(m_nodeMBR.m_pLow[cDim], m_pMBR[cChild].m_pLow[cDim]);
          m_nodeMBR.m_pHigh[cDim] = Math.max(m_nodeMBR.m_pHigh[cDim], m_pMBR[cChild].m_pHigh[cDim]);
        }
      }
    }
  }

  protected boolean insertData(byte[] pData, Region mbr, int id, Stack pathBuffer, boolean[] overflowTable)
  {
    if (m_children < m_capacity)
    {
      boolean adjusted = false;
      boolean b = m_nodeMBR.contains(mbr);

      insertEntry(pData, mbr, id);
      m_pTree.writeNode(this);

      if (! b && ! pathBuffer.empty())
      {
        int cParent = ((Integer) pathBuffer.pop()).intValue();
        Index p = (Index) m_pTree.readNode(cParent);
        p.adjustTree(this, pathBuffer);
        adjusted = true;
      }

      return adjusted;
    }
    else if (m_pTree.m_treeVariant == SpatialIndex.RtreeVariantRstar && ! pathBuffer.empty() && overflowTable[m_level] == false)
    {
      overflowTable[m_level] = true;

      ArrayList vReinsert = new ArrayList(), vKeep = new ArrayList();
      reinsertData(pData, mbr, id, vReinsert, vKeep);

      int lReinsert = vReinsert.size();
      int lKeep = vKeep.size();

      byte[][] reinsertdata = new byte[lReinsert][];
      Region[] reinsertmbr = new Region[lReinsert];
      int[] reinsertid = new int[lReinsert];
      int[] reinsertlen = new int[lReinsert];
      byte[][] keepdata = new byte[m_capacity + 1][];
      Region[] keepmbr = new Region[m_capacity + 1];
      int[] keepid = new int[m_capacity + 1];
      int[] keeplen = new int[m_capacity + 1];

      int cIndex;

      for (cIndex = 0; cIndex < lReinsert; cIndex++)
      {
        int i = ((Integer) vReinsert.get(cIndex)).intValue();
        reinsertlen[cIndex] = m_pDataLength[i];
        reinsertdata[cIndex] = m_pData[i];
        reinsertmbr[cIndex] = m_pMBR[i];
        reinsertid[cIndex] = m_pIdentifier[i];
      }

      for (cIndex = 0; cIndex < lKeep; cIndex++)
      {
        int i = ((Integer) vKeep.get(cIndex)).intValue();
        keeplen[cIndex] = m_pDataLength[i];
        keepdata[cIndex] = m_pData[i];
        keepmbr[cIndex] = m_pMBR[i];
        keepid[cIndex] = m_pIdentifier[i];
      }

      m_pDataLength = keeplen;
      m_pData = keepdata;
      m_pMBR = keepmbr;
      m_pIdentifier = keepid;
      m_children = lKeep;
      m_totalDataLength = 0;
      for (int cChild = 0; cChild < m_children; cChild++) m_totalDataLength += m_pDataLength[cChild];

      for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++)
      {
        m_nodeMBR.m_pLow[cDim] = Double.POSITIVE_INFINITY;
        m_nodeMBR.m_pHigh[cDim] = Double.NEGATIVE_INFINITY;

        for (int cChild = 0; cChild < m_children; cChild++)
        {
          m_nodeMBR.m_pLow[cDim] = Math.min(m_nodeMBR.m_pLow[cDim], m_pMBR[cChild].m_pLow[cDim]);
          m_nodeMBR.m_pHigh[cDim] = Math.max(m_nodeMBR.m_pHigh[cDim], m_pMBR[cChild].m_pHigh[cDim]);
        }
      }

      m_pTree.writeNode(this);

      // Divertion from R*-Tree algorithm here. First adjust
      // the path to the root, then start reinserts, to avoid complicated handling
      // of changes to the same node from multiple insertions.
      int cParent = ((Integer) pathBuffer.pop()).intValue();
      Index p = (Index) m_pTree.readNode(cParent);
      p.adjustTree(this, pathBuffer);

      for (cIndex = 0; cIndex < lReinsert; cIndex++)
      {
        m_pTree.insertData_impl(reinsertdata[cIndex],
                                reinsertmbr[cIndex],
                                reinsertid[cIndex],
                                m_level, overflowTable);
      }

      return true;
    }
    else
    {
      Node[] nodes = split(pData, mbr, id);
      Node n = nodes[0];
      Node nn = nodes[1];

      if (pathBuffer.empty())
      {
        n.m_identifier = -1;
        nn.m_identifier = -1;
        m_pTree.writeNode(n);
        m_pTree.writeNode(nn);

        Index r = new Index(m_pTree, m_pTree.m_rootID, m_level + 1);

        r.insertEntry(null, (Region) n.m_nodeMBR.clone(), n.m_identifier);
        r.insertEntry(null, (Region) nn.m_nodeMBR.clone(), nn.m_identifier);

        m_pTree.writeNode(r);

        m_pTree.m_stats.m_nodesInLevel.set(m_level, new Integer(2));
        m_pTree.m_stats.m_nodesInLevel.add(new Integer(1));
        m_pTree.m_stats.m_treeHeight = m_level + 2;
      }
      else
      {
        n.m_identifier = m_identifier;
        nn.m_identifier = -1;

        m_pTree.writeNode(n);
        m_pTree.writeNode(nn);

        int cParent = ((Integer) pathBuffer.pop()).intValue();
        Index p = (Index) m_pTree.readNode(cParent);
        p.adjustTree(n, nn, pathBuffer, overflowTable);
      }

      return true;
    }
  }

  protected void reinsertData(byte[] pData, Region mbr, int id, ArrayList reinsert, ArrayList keep)
  {
    ReinsertEntry[] v = new ReinsertEntry[m_capacity + 1];

    m_pDataLength[m_children] = (pData != null) ? pData.length : 0;
    m_pData[m_children] = pData;
    m_pMBR[m_children] = mbr;
    m_pIdentifier[m_children] = id;

    double[] nc = m_nodeMBR.getCenter();

    for (int cChild = 0; cChild < m_capacity + 1; cChild++)
    {
      ReinsertEntry e = new ReinsertEntry(cChild, 0.0f);

      double[] c = m_pMBR[cChild].getCenter();

      // calculate relative distance of every entry from the node MBR (ignore square root.)
      for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++)
      {
        double d = nc[cDim] - c[cDim];
        e.m_dist += d * d;
      }

      v[cChild] = e;
    }

    // sort by increasing order of distances.
    Arrays.sort(v, new ReinsertEntryComparator());

    int cReinsert = (int) Math.floor((m_capacity + 1) * m_pTree.m_reinsertFactor);
    int cCount;

    for (cCount = 0; cCount < cReinsert; cCount++)
    {
      reinsert.add(new Integer(v[cCount].m_id));
    }

    for (cCount = cReinsert; cCount < m_capacity + 1; cCount++)
    {
      keep.add(new Integer(v[cCount].m_id));
    }
  }

  protected void rtreeSplit(byte[] pData, Region mbr, int id, ArrayList group1, ArrayList group2)
  {
    int cChild;
    int minimumLoad = (int) Math.floor(m_capacity * m_pTree.m_fillFactor);

    // use this mask array for marking visited entries.
    boolean[] mask = new boolean[m_capacity + 1];
    for (cChild = 0; cChild < m_capacity + 1; cChild++) mask[cChild] = false;

    // insert new data in the node for easier manipulation. Data arrays are always
    // by one larger than node capacity.
    m_pDataLength[m_capacity] = (pData != null) ? pData.length : 0;
    m_pData[m_capacity] = pData;
    m_pMBR[m_capacity] = mbr;
    m_pIdentifier[m_capacity] = id;

    // initialize each group with the seed entries.
    int[] seeds = pickSeeds();

    group1.add(new Integer(seeds[0]));
    group2.add(new Integer(seeds[1]));

    mask[seeds[0]] = true;
    mask[seeds[1]] = true;

    // find MBR of each group.
    Region mbr1 = (Region) m_pMBR[seeds[0]].clone();
    Region mbr2 = (Region) m_pMBR[seeds[1]].clone();

    // count how many entries are left unchecked (exclude the seeds here.)
    int cRemaining = m_capacity + 1 - 2;

    while (cRemaining > 0)
    {
      if (minimumLoad - group1.size() == cRemaining)
      {
        // all remaining entries must be assigned to group1 to comply with minimun load requirement.
        for (cChild = 0; cChild < m_capacity + 1; cChild++)
        {
          if (mask[cChild] == false)
          {
            group1.add(new Integer(cChild));
            mask[cChild] = true;
            cRemaining--;
          }
        }
      }
      else if (minimumLoad - group2.size() == cRemaining)
      {
        // all remaining entries must be assigned to group2 to comply with minimun load requirement.
        for (cChild = 0; cChild < m_capacity + 1; cChild++)
        {
          if (mask[cChild] == false)
          {
            group2.add(new Integer(cChild));
            mask[cChild] = true;
            cRemaining--;
          }
        }
      }
      else
      {
        // For all remaining entries compute the difference of the cost of grouping an
        // entry in either group. When done, choose the entry that yielded the maximum
        // difference. In case of linear split, select any entry (e.g. the first one.)
        int sel = -1;
        double md1 = 0.0f, md2 = 0.0f;
        double m = Double.NEGATIVE_INFINITY;
        double d1, d2, d;
        double a1 = mbr1.getArea();
        double a2 = mbr2.getArea();

        for (cChild = 0; cChild < m_capacity + 1; cChild++)
        {
          if (mask[cChild] == false)
          {
            Region a = mbr1.combinedRegion(m_pMBR[cChild]);
            d1 = a.getArea() - a1;
            Region b = mbr2.combinedRegion(m_pMBR[cChild]);
            d2 = b.getArea() - a2;
            d = Math.abs(d1 - d2);

            if (d > m)
            {
              m = d;
              md1 = d1; md2 = d2;
              sel = cChild;
              if (m_pTree.m_treeVariant== SpatialIndex.RtreeVariantLinear || m_pTree.m_treeVariant == SpatialIndex.RtreeVariantRstar) break;
            }
          }
        }

        // determine the group where we should add the new entry.
        int group = -1;

        if (md1 < md2)
        {
          group1.add(new Integer(sel));
          group = 1;
        }
        else if (md2 < md1)
        {
          group2.add(new Integer(sel));
          group = 2;
        }
        else if (a1 < a2)
        {
          group1.add(new Integer(sel));
          group = 1;
        }
        else if (a2 < a1)
        {
          group2.add(new Integer(sel));
          group = 2;
        }
        else if (group1.size() < group2.size())
        {
          group1.add(new Integer(sel));
          group = 1;
        }
        else if (group2.size() < group1.size())
        {
          group2.add(new Integer(sel));
          group = 2;
        }
        else
        {
          group1.add(new Integer(sel));
          group = 1;
        }
        mask[sel] = true;
        cRemaining--;
        if (group == 1)
        {
          Region.combinedRegion(mbr1, m_pMBR[sel]);
        }
        else
        {
          Region.combinedRegion(mbr2, m_pMBR[sel]);
        }
      }
    }
  }

  protected void rstarSplit(byte[] pData, Region mbr, int id, ArrayList group1, ArrayList group2)
  {
    RstarSplitEntry[] dataLow = new RstarSplitEntry[m_capacity + 1];;
    RstarSplitEntry[] dataHigh = new RstarSplitEntry[m_capacity + 1];;

    m_pDataLength[m_children] = (pData != null) ? pData.length : 0;
    m_pData[m_capacity] = pData;
    m_pMBR[m_capacity] = mbr;
    m_pIdentifier[m_capacity] = id;

    int nodeSPF = (int) (Math.floor((m_capacity + 1) * m_pTree.m_splitDistributionFactor));
    int splitDistribution = (m_capacity + 1) - (2 * nodeSPF) + 2;

    int cChild, cDim, cIndex;

    for (cChild = 0; cChild < m_capacity + 1; cChild++)
    {
      RstarSplitEntry e = new RstarSplitEntry(m_pMBR[cChild], cChild, 0);

      dataLow[cChild] = e;
      dataHigh[cChild] = e;
    }

    double minimumMargin = Double.POSITIVE_INFINITY;
    int splitAxis = -1;
    int sortOrder = -1;

    // chooseSplitAxis.
    for (cDim = 0; cDim < m_pTree.m_dimension; cDim++)
    {
      Arrays.sort(dataLow, new RstarSplitEntryComparatorLow());
      Arrays.sort(dataHigh, new RstarSplitEntryComparatorHigh());

      // calculate sum of margins and overlap for all distributions.
      double marginl = 0.0;
      double marginh = 0.0;

      for (cChild = 1; cChild <= splitDistribution; cChild++)
      {
        int l = nodeSPF - 1 + cChild;

        Region[] tl1 = new Region[l];
        Region[] th1 = new Region[l];

        for (cIndex = 0; cIndex < l; cIndex++)
        {
          tl1[cIndex] = dataLow[cIndex].m_pRegion;
          th1[cIndex] = dataHigh[cIndex].m_pRegion;
        }

        Region bbl1 = Region.combinedRegion(tl1);
        Region bbh1 = Region.combinedRegion(th1);

        Region[] tl2 = new Region[m_capacity + 1 - l];
        Region[] th2 = new Region[m_capacity + 1 - l];

        int tmpIndex = 0;
        for (cIndex = l; cIndex < m_capacity + 1; cIndex++)
        {
          tl2[tmpIndex] = dataLow[cIndex].m_pRegion;
          th2[tmpIndex] = dataHigh[cIndex].m_pRegion;
          tmpIndex++;
        }

        Region bbl2 = Region.combinedRegion(tl2);
        Region bbh2 = Region.combinedRegion(th2);

        marginl += bbl1.getMargin() + bbl2.getMargin();
        marginh += bbh1.getMargin() + bbh2.getMargin();
      } // for (cChild)

      double margin = Math.min(marginl, marginh);

      // keep minimum margin as split axis.
      if (margin < minimumMargin)
      {
        minimumMargin = margin;
        splitAxis = cDim;
        sortOrder = (marginl < marginh) ? 0 : 1;
      }

      // increase the dimension according to which the data entries should be sorted.
      for (cChild = 0; cChild < m_capacity + 1; cChild++)
      {
        dataLow[cChild].m_sortDim = cDim + 1;
      }
    } // for (cDim)

    for (cChild = 0; cChild < m_capacity + 1; cChild++)
    {
      dataLow[cChild].m_sortDim = splitAxis;
    }

    if (sortOrder == 0)
      Arrays.sort(dataLow, new RstarSplitEntryComparatorLow());
    else
      Arrays.sort(dataLow, new RstarSplitEntryComparatorHigh());

    double ma = Double.POSITIVE_INFINITY;
    double mo = Double.POSITIVE_INFINITY;
    int splitPoint = -1;

    for (cChild = 1; cChild <= splitDistribution; cChild++)
    {
      int l = nodeSPF - 1 + cChild;

      Region[] t1 = new Region[l];

      for (cIndex = 0; cIndex < l; cIndex++)
      {
        t1[cIndex] = dataLow[cIndex].m_pRegion;
      }

      Region bb1 = Region.combinedRegion(t1);

      Region[] t2 = new Region[m_capacity + 1 - l];

      int tmpIndex = 0;
      for (cIndex = l; cIndex < m_capacity + 1; cIndex++)
      {
        t2[tmpIndex] = dataLow[cIndex].m_pRegion;
        tmpIndex++;
      }

      Region bb2 = Region.combinedRegion(t2);

      double o = bb1.getIntersectingArea(bb2);

      if (o < mo)
      {
        splitPoint = cChild;
        mo = o;
        ma = bb1.getArea() + bb2.getArea();
      }
      else if (o == mo)
      {
        double a = bb1.getArea() + bb2.getArea();

        if (a < ma)
        {
          splitPoint = cChild;
          ma = a;
        }
      }
    } // for (cChild)

    int l1 = nodeSPF - 1 + splitPoint;

    for (cIndex = 0; cIndex < l1; cIndex++)
    {
      group1.add(new Integer(dataLow[cIndex].m_id));
    }

    for (cIndex = l1; cIndex <= m_capacity; cIndex++)
    {
      group2.add(new Integer(dataLow[cIndex].m_id));
    }
  }

  protected int[] pickSeeds()
  {
    double separation = Double.NEGATIVE_INFINITY;
    double inefficiency = Double.NEGATIVE_INFINITY;
    int cDim, cChild, cIndex, i1 = 0, i2 = 0;

    switch (m_pTree.m_treeVariant)
    {
      case SpatialIndex.RtreeVariantLinear:
      case SpatialIndex.RtreeVariantRstar:
        for (cDim = 0; cDim < m_pTree.m_dimension; cDim++)
        {
          double leastLower = m_pMBR[0].m_pLow[cDim];
          double greatestUpper = m_pMBR[0].m_pHigh[cDim];
          int greatestLower = 0;
          int leastUpper = 0;
          double width;

          for (cChild = 1; cChild < m_capacity + 1; cChild++)
          {
            if (m_pMBR[cChild].m_pLow[cDim] > m_pMBR[greatestLower].m_pLow[cDim]) greatestLower = cChild;
            if (m_pMBR[cChild].m_pHigh[cDim] < m_pMBR[leastUpper].m_pHigh[cDim]) leastUpper = cChild;

            leastLower = Math.min(m_pMBR[cChild].m_pLow[cDim], leastLower);
            greatestUpper = Math.max(m_pMBR[cChild].m_pHigh[cDim], greatestUpper);
          }

          width = greatestUpper - leastLower;
          if (width <= 0) width = 1;

          double f = (m_pMBR[greatestLower].m_pLow[cDim] - m_pMBR[leastUpper].m_pHigh[cDim]) / width;

          if (f > separation)
          {
            i1 = leastUpper;
            i2 = greatestLower;
            separation = f;
          }
        }  // for (cDim)

        if (i1 == i2)
        {
          i2 = (i2 != m_capacity) ? i2 + 1 : i2 - 1;
        }

        break;
      case SpatialIndex.RtreeVariantQuadratic:
        // for each pair of Regions (account for overflow Region too!)
        for (cChild = 0; cChild < m_capacity; cChild++)
        {
          double a = m_pMBR[cChild].getArea();

          for (cIndex = cChild + 1; cIndex < m_capacity + 1; cIndex++)
          {
            // get the combined MBR of those two entries.
            Region r = m_pMBR[cChild].combinedRegion(m_pMBR[cIndex]);

            // find the inefficiency of grouping these entries together.
            double d = r.getArea() - a - m_pMBR[cIndex].getArea();

            if (d > inefficiency)
            {
              inefficiency = d;
              i1 = cChild;
              i2 = cIndex;
            }
          }  // for (cIndex)
        } // for (cChild)

        break;
      default:
        throw new IllegalStateException("Unknown RTree variant.");
    }

    int[] ret = new int[2];
    ret[0] = i1;
    ret[1] = i2;
    return ret;
  }

  protected void condenseTree(Stack toReinsert, Stack pathBuffer)
  {
    int minimumLoad = (int) (Math.floor(m_capacity * m_pTree.m_fillFactor));

    if (pathBuffer.empty())
    {
      // eliminate root if it has only one child.
      if (m_level != 0 && m_children == 1)
      {
        Node n = m_pTree.readNode(m_pIdentifier[0]);
        m_pTree.deleteNode(n);
        n.m_identifier = m_pTree.m_rootID;
        m_pTree.writeNode(n);

        m_pTree.m_stats.m_nodesInLevel.remove(m_pTree.m_stats.m_nodesInLevel.size() - 1);
        m_pTree.m_stats.m_treeHeight -= 1;
        // HACK: pending deleteNode for deleted child will decrease nodesInLevel, later on.
        m_pTree.m_stats.m_nodesInLevel.set(m_pTree.m_stats.m_treeHeight - 1, new Integer(2));
      }
    }
    else
    {
      int cParent = ((Integer) pathBuffer.pop()).intValue();
      Index p = (Index) m_pTree.readNode(cParent);

      // find the entry in the parent, that points to this node.
      int child;

      for (child = 0; child != p.m_children; child++)
      {
        if (p.m_pIdentifier[child] == m_identifier) break;
      }

      if (m_children < minimumLoad)
      {
        // used space less than the minimum
        // 1. eliminate node entry from the parent. deleteEntry will fix the parent's MBR.
        p.deleteEntry(child);
        // 2. add this node to the stack in order to reinsert its entries.
        toReinsert.push(this);
      }
      else
      {
        // adjust the entry in 'p' to contain the new bounding region of this node.
        p.m_pMBR[child] = (Region) m_nodeMBR.clone();

        // global recalculation necessary since the MBR can only shrink in size,
        // due to data removal.
        for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++)
        {
          p.m_nodeMBR.m_pLow[cDim] = Double.POSITIVE_INFINITY;
          p.m_nodeMBR.m_pHigh[cDim] = Double.NEGATIVE_INFINITY;

          for (int cChild = 0; cChild < p.m_children; cChild++)
          {
            p.m_nodeMBR.m_pLow[cDim] = Math.min(p.m_nodeMBR.m_pLow[cDim], p.m_pMBR[cChild].m_pLow[cDim]);
            p.m_nodeMBR.m_pHigh[cDim] = Math.max(p.m_nodeMBR.m_pHigh[cDim], p.m_pMBR[cChild].m_pHigh[cDim]);
          }
        }
      }

      // write parent node back to storage.
      m_pTree.writeNode(p);

      p.condenseTree(toReinsert, pathBuffer);
    }
  }

  protected void load(byte[] data) throws IOException
  {
    m_nodeMBR = (Region) m_pTree.m_infiniteRegion.clone();

    DataInputStream ds = new DataInputStream(new ByteArrayInputStream(data));

    // skip the node type information, it is not needed.
    ds.readInt();

    m_level = ds.readInt();
    m_children = ds.readInt();

    for (int cChild = 0; cChild < m_children; cChild++)
    {
      m_pMBR[cChild] = new Region();
      m_pMBR[cChild].m_pLow = new double[m_pTree.m_dimension];
      m_pMBR[cChild].m_pHigh = new double[m_pTree.m_dimension];

      for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++)
      {
        m_pMBR[cChild].m_pLow[cDim] = ds.readDouble();
        m_pMBR[cChild].m_pHigh[cDim] = ds.readDouble();
      }

      m_pIdentifier[cChild] = ds.readInt();

      m_pDataLength[cChild] = ds.readInt();
      if (m_pDataLength[cChild] > 0)
      {
        m_totalDataLength += m_pDataLength[cChild];
        m_pData[cChild] = new byte[m_pDataLength[cChild]];
        ds.read(m_pData[cChild]);
      }
      else
      {
        m_pData[cChild] = null;
      }

      Region.combinedRegion(m_nodeMBR, m_pMBR[cChild]);
    }
  }

  protected byte[] store() throws IOException
  {
    ByteArrayOutputStream bs = new ByteArrayOutputStream();
    DataOutputStream ds = new DataOutputStream(bs);

    int type;
    if (m_level == 0) type = SpatialIndex.PersistentLeaf;
    else type = SpatialIndex.PersistentIndex;
    ds.writeInt(type);

    ds.writeInt(m_level);
    ds.writeInt(m_children);

    for (int cChild = 0; cChild < m_children; cChild++)
    {
      for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++)
      {
        ds.writeDouble(m_pMBR[cChild].m_pLow[cDim]);
        ds.writeDouble(m_pMBR[cChild].m_pHigh[cDim]);
      }

      ds.writeInt(m_pIdentifier[cChild]);

      ds.writeInt(m_pDataLength[cChild]);
      if (m_pDataLength[cChild] > 0) ds.write(m_pData[cChild]);
    }

    ds.flush();
    return bs.toByteArray();
  }

  class ReinsertEntry
  {
    int m_id;
    double m_dist;
    public ReinsertEntry(int id, double dist) { m_id = id; m_dist = dist; }
  } // ReinsertEntry

  class ReinsertEntryComparator implements Comparator
  {
    public int compare(Object o1, Object o2)
    {
      if (((ReinsertEntry) o1).m_dist < ((ReinsertEntry) o2).m_dist) return -1;
      if (((ReinsertEntry) o1).m_dist > ((ReinsertEntry) o2).m_dist) return 1;
      return 0;
    }
  } // ReinsertEntryComparator

  class RstarSplitEntry
  {
    Region m_pRegion;
    int m_id;
    int m_sortDim;

    RstarSplitEntry(Region r, int id, int dimension) { m_pRegion = r; m_id = id; m_sortDim = dimension; }
  }

  class RstarSplitEntryComparatorLow implements Comparator
  {
    public int compare(Object o1, Object o2)
    {
      RstarSplitEntry e1 = (RstarSplitEntry) o1;
      RstarSplitEntry e2 = (RstarSplitEntry) o2;

      if (e1.m_pRegion.m_pLow[e1.m_sortDim] < e2.m_pRegion.m_pLow[e2.m_sortDim]) return -1;
      if (e1.m_pRegion.m_pLow[e1.m_sortDim] > e2.m_pRegion.m_pLow[e2.m_sortDim]) return 1;
      return 0;
    }
  }

  class RstarSplitEntryComparatorHigh implements Comparator
  {
    public int compare(Object o1, Object o2)
    {
      RstarSplitEntry e1 = (RstarSplitEntry) o1;
      RstarSplitEntry e2 = (RstarSplitEntry) o2;

      if (e1.m_pRegion.m_pHigh[e1.m_sortDim] < e2.m_pRegion.m_pHigh[e2.m_sortDim]) return -1;
      if (e1.m_pRegion.m_pHigh[e1.m_sortDim] > e2.m_pRegion.m_pHigh[e2.m_sortDim]) return 1;
      return 0;
    }
  }
}
TOP

Related Classes of sil.rtree.Node$RstarSplitEntryComparatorHigh

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.