public void build(int numLevels, int cellSize) {
      if (numLevels == 0) return;

      if (this.m1 - this.m0 <= cellSize && this.n1 - this.n0 <= cellSize) return;

      this.children = this.split(this.m0, this.m1, this.n0, this.n1);
      for (Cell t : this.children) {
        t.build(numLevels - 1, cellSize);
      }
    }
    public void computeBounds(Dimension dim, float[] xs, float[] ys) {
      if (this.children != null) {
        for (Cell t : this.children) {
          t.computeBounds(dim, xs, ys);
        }

        this.computeExtremesFromChildren();
      } else {
        this.computeExtremesFromLocations(dim, xs, ys);
      }
    }
  protected ContainingCell findContainingCell(Cell cell, float x, float y) {
    if (!cell.intersects(x, y)) return null;

    if (cell.m1 - cell.m0 <= this.cellSize && cell.n1 - cell.n0 <= this.cellSize)
      return this.checkContainment(x, y, cell);

    Cell[] kids = cell.children != null ? cell.children : (Cell[]) this.kidCache.getObject(cell);
    if (kids == null) {
      kids = cell.split(cell.m0, cell.m1, cell.n0, cell.n1);
      for (Cell child : kids) {
        child.computeExtremesFromLocations(this.gridSize, this.xs, this.ys);
      }
      if (cell.children == null) this.kidCache.add(cell, kids, 4 * kids[0].getSizeInBytes());
    }

    for (Cell t : kids) {
      ContainingCell cellFound = this.findContainingCell(t, x, y);
      if (cellFound != null) return cellFound;
    }

    return null;
  }