@Override
  public List<STPoint> range(STRegion range) {
    SQLiteDatabase db = this.getReadableDatabase();

    String query = "SELECT id,minX,maxX,minY,maxY,minT,maxT from " + this.table_identifier + " ";

    STPoint mins = range.getMins();
    STPoint maxs = range.getMaxs();

    String prefix = " WHERE ";
    if (mins.hasX() && maxs.hasX()) {
      query +=
          prefix
              + " minX >= "
              + String.valueOf(mins.getX())
              + " AND maxX <= "
              + String.valueOf(maxs.getX());
      prefix = " AND ";
    }

    if (mins.hasY() && maxs.hasY()) {
      query +=
          prefix
              + " minY >= "
              + String.valueOf(mins.getY())
              + " AND maxY <= "
              + String.valueOf(maxs.getY());
      prefix = " AND ";
    }

    if (mins.hasT() && maxs.hasT()) {
      query +=
          prefix
              + " minT >= "
              + String.valueOf(mins.getT())
              + " AND maxT <= "
              + String.valueOf(maxs.getT());
      prefix = " AND ";
    }

    Cursor cur = db.rawQuery(query, null);

    List<STPoint> points = cursorToList(cur);
    db.close();
    return points;
  }
 @Override
 public void insert(STPoint point) {
   SQLiteDatabase db = this.getWritableDatabase();
   ContentValues values = new ContentValues();
   values.put("minX", point.getX());
   values.put("maxX", point.getX());
   values.put("minY", point.getY());
   values.put("maxY", point.getY());
   values.put("minT", point.getT());
   values.put("maxT", point.getT());
   db.insert(
       this.table_identifier, // table
       null, // nullColumnHack
       values); // key/value -> keys = column names/ values = column values
   db.close();
 }
  @Override
  public List<STPoint> nearestNeighbor(STPoint needle, STPoint boundValues, int n) {

    // TODO support more than one nearest neighbor
    if (n != 1) {
      throw new RuntimeException("Nearest Neighbor does not support N != 1");
    }

    List<STPoint> candPoints = new ArrayList<STPoint>();
    for (int i = 0; i < 20; i++) {
      try {
        STRegion miniRegion = GPSLib.getSpaceBoundQuick(needle, boundValues, SPATIAL_TYPE);
        candPoints = range(miniRegion);
        if (candPoints.size() >= n) {
          break;
        }
        int step = (int) Math.pow(i, 3);
        boundValues.setX(step * boundValues.getX());
        boundValues.setY(step * boundValues.getY());
        boundValues.setT(step * boundValues.getT());
      } catch (LSTFilterException e) {
        e.printStackTrace();
      }
    }

    STPoint minPoint = null;
    double minVal = Double.MAX_VALUE;
    for (STPoint point : candPoints) {
      // ToDo: optimize this since we use the same needle each time, some values should drop out of
      // dist calc.
      // ToDO: optimize by using squared values of distance instead of ones using sqrt (expensive)
      try {
        double distance = GPSLib.distanceBetween(needle, point, SPATIAL_TYPE);
        if (distance < minVal) {
          minVal = distance;
          minPoint = point;
        }
      } catch (LSTFilterException e) {
        e.printStackTrace();
      }
    }

    List<STPoint> minPoints = new ArrayList<STPoint>();
    minPoints.add(minPoint);
    return minPoints;
  }