/**
   * Builds a ball tree middle out from the portion of the master index array given by supplied
   * start and end index.
   *
   * @param startIdx The start of the portion in master index array.
   * @param endIdx the end of the portion in master index array.
   * @return The root node of the built tree.
   * @throws Exception If there is some problem building the tree.
   */
  protected BallNode buildTreeMiddleOut(int startIdx, int endIdx) throws Exception {

    Instance pivot;
    double radius;
    Vector<TempNode> anchors;
    int numInsts = endIdx - startIdx + 1;
    int numAnchors = (int) Math.round(Math.sqrt(numInsts));

    // create anchor's hierarchy
    if (numAnchors > 1) {
      pivot = BallNode.calcCentroidPivot(startIdx, endIdx, m_InstList, m_Instances);
      radius =
          BallNode.calcRadius(startIdx, endIdx, m_InstList, m_Instances, pivot, m_DistanceFunction);
      if (numInsts <= m_MaxInstancesInLeaf
          || (rootRadius == 0
              ? true
              : radius / rootRadius
                  < m_MaxRelLeafRadius)) { // just make a leaf don't make anchors hierarchy
        BallNode node = new BallNode(startIdx, endIdx, m_NumNodes, pivot, radius);
        return node;
      }
      anchors = new Vector<TempNode>(numAnchors);
      createAnchorsHierarchy(anchors, numAnchors, startIdx, endIdx);

      BallNode node = mergeNodes(anchors, startIdx, endIdx);

      buildLeavesMiddleOut(node);

      return node;
    } // end anchors hierarchy
    else {
      BallNode node =
          new BallNode(
              startIdx,
              endIdx,
              m_NumNodes,
              (pivot = BallNode.calcCentroidPivot(startIdx, endIdx, m_InstList, m_Instances)),
              BallNode.calcRadius(
                  startIdx, endIdx, m_InstList, m_Instances, pivot, m_DistanceFunction));
      return node;
    }
  }
 /**
  * Builds a ball tree middle out.
  *
  * @return The root node of the tree.
  * @throws Exception If there is problem building the tree.
  */
 public BallNode buildTree() throws Exception {
   m_NumNodes = m_MaxDepth = m_NumLeaves = 0;
   if (rootRadius == -1) {
     rootRadius =
         BallNode.calcRadius(
             m_InstList,
             m_Instances,
             BallNode.calcCentroidPivot(m_InstList, m_Instances),
             m_DistanceFunction);
   }
   BallNode root = buildTreeMiddleOut(0, m_Instances.numInstances() - 1);
   return root;
 }
  /**
   * Returns an anchor point which is furthest from the mean point for a given set of points
   * (instances) (The anchor instance is chosen from the given set of points).
   *
   * @param startIdx The start index of the points for which anchor point is required.
   * @param endIdx The end index of the points for which anchor point is required.
   * @return The furthest point/instance from the mean of given set of points.
   */
  protected TempNode getFurthestFromMeanAnchor(int startIdx, int endIdx) {
    TempNode anchor = new TempNode();
    Instance centroid = BallNode.calcCentroidPivot(startIdx, endIdx, m_InstList, m_Instances);
    Instance temp;
    double tmpr;
    anchor.radius = Double.NEGATIVE_INFINITY;
    for (int i = startIdx; i <= endIdx; i++) {
      temp = m_Instances.instance(m_InstList[i]);
      tmpr = m_DistanceFunction.distance(centroid, temp);
      if (tmpr > anchor.radius) {
        anchor.idx = m_InstList[i];
        anchor.anchor = temp;
        anchor.radius = tmpr;
      }
    }

    setPoints(anchor, startIdx, endIdx, m_InstList);
    return anchor;
  }