/** Constructs a query to retrieve documents that fully contain the input envelope. */
 private Query makeWithin(Rectangle bbox) {
   BooleanQuery.Builder bq = new BooleanQuery.Builder();
   BooleanClause.Occur MUST = BooleanClause.Occur.MUST;
   if (bbox.getCrossesDateLine()) {
     // use null as performance trick since no data will be beyond the world bounds
     bq.add(rangeQuery(fieldNameX, null /*-180*/, bbox.getMaxX()), BooleanClause.Occur.SHOULD);
     bq.add(rangeQuery(fieldNameX, bbox.getMinX(), null /*+180*/), BooleanClause.Occur.SHOULD);
     bq.setMinimumNumberShouldMatch(1); // must match at least one of the SHOULD
   } else {
     bq.add(rangeQuery(fieldNameX, bbox.getMinX(), bbox.getMaxX()), MUST);
   }
   bq.add(rangeQuery(fieldNameY, bbox.getMinY(), bbox.getMaxY()), MUST);
   return bq.build();
 }
  protected Rectangle randomRectangle(Rectangle bounds) {
    double[] xNewStartAndWidth = randomSubRange(bounds.getMinX(), bounds.getWidth());
    double xMin = xNewStartAndWidth[0];
    double xMax = xMin + xNewStartAndWidth[1];
    if (bounds.getCrossesDateLine()) {
      xMin = DistanceUtils.normLonDEG(xMin);
      xMax = DistanceUtils.normLonDEG(xMax);
    }

    double[] yNewStartAndHeight = randomSubRange(bounds.getMinY(), bounds.getHeight());
    double yMin = yNewStartAndHeight[0];
    double yMax = yMin + yNewStartAndHeight[1];

    return ctx.makeRectangle(xMin, xMax, yMin, yMax);
  }