/**
   * Normalize the geo {@code Point} for the given coordinates to lie within their respective
   * normalized ranges.
   *
   * <p>You can control which coordinate gets normalized with the two flags.
   *
   * <p>Note: A shift of 180&deg; is applied in the longitude if necessary, in order to normalize
   * properly the latitude. If normalizing latitude but not longitude, it is assumed that the
   * longitude is in the form x+k*360, with x in ]-180;180], and k is meaningful to the application.
   * Therefore x will be adjusted while keeping k preserved.
   *
   * @param point The point to normalize in-place.
   * @param normLat Whether to normalize latitude or leave it as is.
   * @param normLon Whether to normalize longitude.
   */
  public static void normalizePoint(GeoPoint point, boolean normLat, boolean normLon) {
    double lat = point.lat();
    double lon = point.lon();

    normLat = normLat && (lat > 90 || lat <= -90);
    normLon = normLon && (lon > 180 || lon <= -180);

    if (normLat) {
      lat = centeredModulus(lat, 360);
      boolean shift = true;
      if (lat < -90) {
        lat = -180 - lat;
      } else if (lat > 90) {
        lat = 180 - lat;
      } else {
        // No need to shift the longitude, and the latitude is normalized
        shift = false;
      }
      if (shift) {
        if (normLon) {
          lon += 180;
        } else {
          // Longitude won't be normalized,
          // keep it in the form x+k*360 (with x in ]-180;180])
          // by only changing x, assuming k is meaningful for the user application.
          lon += normalizeLon(lon) > 0 ? -180 : 180;
        }
      }
    }
    if (normLon) {
      lon = centeredModulus(lon, 360);
    }
    point.reset(lat, lon);
  }
 private void assertGeoPointQuery(GeoDistanceRangeQueryBuilder queryBuilder, Query query)
     throws IOException {
   assertThat(query, instanceOf(XGeoPointDistanceRangeQuery.class));
   XGeoPointDistanceRangeQuery geoQuery = (XGeoPointDistanceRangeQuery) query;
   assertThat(geoQuery.getField(), equalTo(queryBuilder.fieldName()));
   if (queryBuilder.point() != null) {
     GeoPoint expectedPoint = new GeoPoint(queryBuilder.point());
     GeoUtils.normalizePoint(expectedPoint);
     assertThat(geoQuery.getCenterLat(), equalTo(expectedPoint.lat()));
     assertThat(geoQuery.getCenterLon(), equalTo(expectedPoint.lon()));
   }
   if (queryBuilder.from() != null && queryBuilder.from() instanceof Number) {
     double fromValue = ((Number) queryBuilder.from()).doubleValue();
     if (queryBuilder.unit() != null) {
       fromValue = queryBuilder.unit().toMeters(fromValue);
     }
     assertThat(geoQuery.getMinRadiusMeters(), closeTo(fromValue, 1E-5));
   }
   if (queryBuilder.to() != null && queryBuilder.to() instanceof Number) {
     double toValue = ((Number) queryBuilder.to()).doubleValue();
     if (queryBuilder.unit() != null) {
       toValue = queryBuilder.unit().toMeters(toValue);
     }
     assertThat(geoQuery.getMaxRadiusMeters(), closeTo(toValue, 1E-5));
   }
 }
 private void parsePointFromString(ParseContext context, GeoPoint sparse, String point)
     throws IOException {
   if (point.indexOf(',') < 0) {
     parse(context, sparse.resetFromGeoHash(point), point);
   } else {
     parse(context, sparse.resetFromString(point), null);
   }
 }
 /** parse a {@link GeoPoint} from a String */
 public static GeoPoint parseGeoPoint(String data, GeoPoint point) {
   int comma = data.indexOf(',');
   if (comma > 0) {
     double lat = Double.parseDouble(data.substring(0, comma).trim());
     double lon = Double.parseDouble(data.substring(comma + 1).trim());
     return point.reset(lat, lon);
   } else {
     return point.resetFromGeoHash(data);
   }
 }
 public void testSortModeSumIsRejectedInSetter() {
   GeoDistanceSortBuilder builder = new GeoDistanceSortBuilder("testname", -1, -1);
   GeoPoint point = RandomGeoGenerator.randomPoint(random());
   builder.point(point.getLat(), point.getLon());
   try {
     builder.sortMode(SortMode.SUM);
     fail("sort mode sum should not be supported");
   } catch (IllegalArgumentException e) {
     // all good
   }
 }
 private static boolean contains(GeoPoint point, List<GeoPoint> set, Distance precision) {
   for (GeoPoint r : set) {
     final double distance =
         GeoDistance.PLANE.calculate(
             point.getLat(), point.getLon(), r.getLat(), r.getLon(), DistanceUnit.METERS);
     if (new Distance(distance, DistanceUnit.METERS).compareTo(precision) <= 0) {
       return true;
     }
   }
   return false;
 }
 @Override
 public BytesRef binaryValue() {
   final byte[] bytes = new byte[points.size() * 16];
   int off = 0;
   for (Iterator<ObjectCursor<GeoPoint>> it = points.iterator(); it.hasNext(); ) {
     final GeoPoint point = it.next().value;
     ByteUtils.writeDoubleLE(point.getLat(), bytes, off);
     ByteUtils.writeDoubleLE(point.getLon(), bytes, off + 8);
     off += 16;
   }
   return new BytesRef(bytes);
 }
 @Override
 protected boolean matchDoc(int doc) {
   values.setDocument(doc);
   final int length = values.count();
   for (int i = 0; i < length; i++) {
     GeoPoint point = values.valueAt(i);
     if (pointInPolygon(points, point.lat(), point.lon())) {
       return true;
     }
   }
   return false;
 }
  public static GeoDistanceSortBuilder randomGeoDistanceSortBuilder() {
    String fieldName = randomAsciiOfLengthBetween(1, 10);
    GeoDistanceSortBuilder result = null;

    int id = randomIntBetween(0, 2);
    switch (id) {
      case 0:
        int count = randomIntBetween(1, 10);
        String[] geohashes = new String[count];
        for (int i = 0; i < count; i++) {
          geohashes[i] = RandomGeoGenerator.randomPoint(random()).geohash();
        }

        result = new GeoDistanceSortBuilder(fieldName, geohashes);
        break;
      case 1:
        GeoPoint pt = RandomGeoGenerator.randomPoint(random());
        result = new GeoDistanceSortBuilder(fieldName, pt.getLat(), pt.getLon());
        break;
      case 2:
        result = new GeoDistanceSortBuilder(fieldName, points(new GeoPoint[0]));
        break;
      default:
        throw new IllegalStateException("one of three geo initialisation strategies must be used");
    }
    if (randomBoolean()) {
      result.geoDistance(geoDistance(result.geoDistance()));
    }
    if (randomBoolean()) {
      result.unit(randomValueOtherThan(result.unit(), () -> randomFrom(DistanceUnit.values())));
    }
    if (randomBoolean()) {
      result.order(randomFrom(SortOrder.values()));
    }
    if (randomBoolean()) {
      result.sortMode(randomValueOtherThan(SortMode.SUM, () -> randomFrom(SortMode.values())));
    }
    if (randomBoolean()) {
      result.setNestedFilter(randomNestedFilter());
    }
    if (randomBoolean()) {
      result.setNestedPath(
          randomValueOtherThan(result.getNestedPath(), () -> randomAsciiOfLengthBetween(1, 10)));
    }
    if (randomBoolean()) {
      result.validation(
          randomValueOtherThan(
              result.validation(), () -> randomFrom(GeoValidationMethod.values())));
    }

    return result;
  }
  @Override
  public Mapper parse(ParseContext context) throws IOException {
    ContentPath.Type origPathType = context.path().pathType();
    context.path().pathType(pathType);
    context.path().add(simpleName());

    GeoPoint sparse = context.parseExternalValue(GeoPoint.class);

    if (sparse != null) {
      parse(context, sparse, null);
    } else {
      sparse = new GeoPoint();
      XContentParser.Token token = context.parser().currentToken();
      if (token == XContentParser.Token.START_ARRAY) {
        token = context.parser().nextToken();
        if (token == XContentParser.Token.START_ARRAY) {
          // its an array of array of lon/lat [ [1.2, 1.3], [1.4, 1.5] ]
          while (token != XContentParser.Token.END_ARRAY) {
            parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
            token = context.parser().nextToken();
          }
        } else {
          // its an array of other possible values
          if (token == XContentParser.Token.VALUE_NUMBER) {
            double lon = context.parser().doubleValue();
            token = context.parser().nextToken();
            double lat = context.parser().doubleValue();
            while ((token = context.parser().nextToken()) != XContentParser.Token.END_ARRAY) ;
            parse(context, sparse.reset(lat, lon), null);
          } else {
            while (token != XContentParser.Token.END_ARRAY) {
              if (token == XContentParser.Token.VALUE_STRING) {
                parsePointFromString(context, sparse, context.parser().text());
              } else {
                parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
              }
              token = context.parser().nextToken();
            }
          }
        }
      } else if (token == XContentParser.Token.VALUE_STRING) {
        parsePointFromString(context, sparse, context.parser().text());
      } else if (token != XContentParser.Token.VALUE_NULL) {
        parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
      }
    }

    context.path().remove();
    context.path().pathType(origPathType);
    return null;
  }
 private void assertLegacyQuery(GeoDistanceRangeQueryBuilder queryBuilder, Query query)
     throws IOException {
   assertThat(query, instanceOf(GeoDistanceRangeQuery.class));
   GeoDistanceRangeQuery geoQuery = (GeoDistanceRangeQuery) query;
   assertThat(geoQuery.fieldName(), equalTo(queryBuilder.fieldName()));
   if (queryBuilder.point() != null) {
     GeoPoint expectedPoint = new GeoPoint(queryBuilder.point());
     if (GeoValidationMethod.isCoerce(queryBuilder.getValidationMethod())) {
       GeoUtils.normalizePoint(expectedPoint, true, true);
     }
     assertThat(geoQuery.lat(), equalTo(expectedPoint.lat()));
     assertThat(geoQuery.lon(), equalTo(expectedPoint.lon()));
   }
   assertThat(geoQuery.geoDistance(), equalTo(queryBuilder.geoDistance()));
   if (queryBuilder.from() != null && queryBuilder.from() instanceof Number) {
     double fromValue = ((Number) queryBuilder.from()).doubleValue();
     if (queryBuilder.unit() != null) {
       fromValue = queryBuilder.unit().toMeters(fromValue);
     }
     if (queryBuilder.geoDistance() != null) {
       fromValue = queryBuilder.geoDistance().normalize(fromValue, DistanceUnit.DEFAULT);
     }
     double fromSlop = Math.abs(fromValue) / 1000;
     if (queryBuilder.includeLower() == false) {
       fromSlop =
           NumericUtils.sortableLongToDouble(
                   (NumericUtils.doubleToSortableLong(Math.abs(fromValue)) + 1L))
               / 1000.0;
     }
     assertThat(geoQuery.minInclusiveDistance(), closeTo(fromValue, fromSlop));
   }
   if (queryBuilder.to() != null && queryBuilder.to() instanceof Number) {
     double toValue = ((Number) queryBuilder.to()).doubleValue();
     if (queryBuilder.unit() != null) {
       toValue = queryBuilder.unit().toMeters(toValue);
     }
     if (queryBuilder.geoDistance() != null) {
       toValue = queryBuilder.geoDistance().normalize(toValue, DistanceUnit.DEFAULT);
     }
     double toSlop = Math.abs(toValue) / 1000;
     if (queryBuilder.includeUpper() == false) {
       toSlop =
           NumericUtils.sortableLongToDouble(
                   (NumericUtils.doubleToSortableLong(Math.abs(toValue)) - 1L))
               / 1000.0;
     }
     assertThat(geoQuery.maxInclusiveDistance(), closeTo(toValue, toSlop));
   }
 }
 @Override
 public GeoPoint value(Object value) {
   if (value instanceof GeoPoint) {
     return (GeoPoint) value;
   } else {
     return GeoPoint.parseFromLatLon(value.toString());
   }
 }
 @Override
 protected GeoDistanceSortBuilder mutate(GeoDistanceSortBuilder original) throws IOException {
   GeoDistanceSortBuilder result = new GeoDistanceSortBuilder(original);
   int parameter = randomIntBetween(0, 8);
   switch (parameter) {
     case 0:
       while (Arrays.deepEquals(original.points(), result.points())) {
         GeoPoint pt = RandomGeoGenerator.randomPoint(random());
         result.point(pt.getLat(), pt.getLon());
       }
       break;
     case 1:
       result.points(points(original.points()));
       break;
     case 2:
       result.geoDistance(geoDistance(original.geoDistance()));
       break;
     case 3:
       result.unit(randomValueOtherThan(result.unit(), () -> randomFrom(DistanceUnit.values())));
       break;
     case 4:
       result.order(randomValueOtherThan(original.order(), () -> randomFrom(SortOrder.values())));
       break;
     case 5:
       result.sortMode(
           randomValueOtherThanMany(
               Arrays.asList(SortMode.SUM, result.sortMode())::contains,
               () -> randomFrom(SortMode.values())));
       break;
     case 6:
       result.setNestedFilter(
           randomValueOtherThan(original.getNestedFilter(), () -> randomNestedFilter()));
       break;
     case 7:
       result.setNestedPath(
           randomValueOtherThan(result.getNestedPath(), () -> randomAsciiOfLengthBetween(1, 10)));
       break;
     case 8:
       result.validation(
           randomValueOtherThan(
               result.validation(), () -> randomFrom(GeoValidationMethod.values())));
       break;
   }
   return result;
 }
  private static void duelFieldDataGeoPoint(
      Random random,
      AtomicReaderContext context,
      IndexGeoPointFieldData left,
      IndexGeoPointFieldData right,
      Distance precision)
      throws Exception {
    AtomicGeoPointFieldData leftData =
        random.nextBoolean() ? left.load(context) : left.loadDirect(context);
    AtomicGeoPointFieldData rightData =
        random.nextBoolean() ? right.load(context) : right.loadDirect(context);

    int numDocs = context.reader().maxDoc();
    MultiGeoPointValues leftValues = leftData.getGeoPointValues();
    MultiGeoPointValues rightValues = rightData.getGeoPointValues();
    for (int i = 0; i < numDocs; ++i) {
      leftValues.setDocument(i);
      final int numValues = leftValues.count();
      rightValues.setDocument(i);
      ;
      assertEquals(numValues, rightValues.count());
      List<GeoPoint> leftPoints = Lists.newArrayList();
      List<GeoPoint> rightPoints = Lists.newArrayList();
      for (int j = 0; j < numValues; ++j) {
        GeoPoint l = leftValues.valueAt(j);
        leftPoints.add(new GeoPoint(l.getLat(), l.getLon()));
        GeoPoint r = rightValues.valueAt(j);
        rightPoints.add(new GeoPoint(r.getLat(), r.getLon()));
      }
      for (GeoPoint l : leftPoints) {
        assertTrue(
            "Couldn't find " + l + " among " + rightPoints, contains(l, rightPoints, precision));
      }
      for (GeoPoint r : rightPoints) {
        assertTrue(
            "Couldn't find " + r + " among " + leftPoints, contains(r, leftPoints, precision));
      }
    }
  }
 /**
  * Creates a query context for a given geo point with a boost of 1 and a precision of {@value
  * GeoContextMapping#DEFAULT_PRECISION}
  */
 public GeoQueryContext(GeoPoint geoPoint) {
   this(geoPoint.geohash());
 }
 /** Decode a geo point from the bits of the encoded latitude and longitudes. */
 public GeoPoint decode(long latBits, long lonBits, GeoPoint out) {
   final double lat = decodeCoordinate(latBits);
   final double lon = decodeCoordinate(lonBits);
   return out.reset(lat, lon);
 }
 /**
  * Decodes the given long-format geohash into a latitude and longitude
  *
  * @param geohash long format Geohash to decode
  * @param ret The Geopoint into which the latitude and longitude will be stored
  */
 public static void decode(long geohash, GeoPoint ret) {
   double[] interval = decodeCell(geohash);
   ret.reset((interval[0] + interval[1]) / 2D, (interval[2] + interval[3]) / 2D);
 }
 /**
  * Decodes the given geohash into a latitude and longitude
  *
  * @param geohash Geohash to decocde
  * @return the given {@link GeoPoint} reseted to the center of cell, given by the geohash
  */
 public static GeoPoint decode(String geohash, GeoPoint ret) {
   double[] interval = decodeCell(geohash);
   return ret.reset((interval[0] + interval[1]) / 2D, (interval[2] + interval[3]) / 2D);
 }
  @Override
  protected GeoDistanceRangeQueryBuilder doCreateTestQueryBuilder() {
    GeoDistanceRangeQueryBuilder builder;
    GeoPoint randomPoint = RandomGeoGenerator.randomPointIn(random(), -180.0, -89.9, 180.0, 89.9);
    if (randomBoolean()) {
      builder = new GeoDistanceRangeQueryBuilder(GEO_POINT_FIELD_NAME, randomPoint.geohash());
    } else {
      if (randomBoolean()) {
        builder = new GeoDistanceRangeQueryBuilder(GEO_POINT_FIELD_NAME, randomPoint);
      } else {
        builder =
            new GeoDistanceRangeQueryBuilder(
                GEO_POINT_FIELD_NAME, randomPoint.lat(), randomPoint.lon());
      }
    }
    GeoPoint point = builder.point();
    final double maxRadius = GeoUtils.maxRadialDistanceMeters(point.lat(), point.lon());
    final int fromValueMeters = randomInt((int) (maxRadius * 0.5));
    final int toValueMeters = randomIntBetween(fromValueMeters + 1, (int) maxRadius);
    DistanceUnit fromToUnits = randomFrom(DistanceUnit.values());
    final String fromToUnitsStr = fromToUnits.toString();
    final double fromValue =
        DistanceUnit.convert(fromValueMeters, DistanceUnit.DEFAULT, fromToUnits);
    final double toValue = DistanceUnit.convert(toValueMeters, DistanceUnit.DEFAULT, fromToUnits);

    if (randomBoolean()) {
      int branch = randomInt(2);
      fromToUnits = DistanceUnit.DEFAULT;
      switch (branch) {
        case 0:
          builder.from(fromValueMeters);
          break;
        case 1:
          builder.to(toValueMeters);
          break;
        case 2:
          builder.from(fromValueMeters);
          builder.to(toValueMeters);
          break;
      }
    } else {
      int branch = randomInt(2);
      switch (branch) {
        case 0:
          builder.from(fromValue + fromToUnitsStr);
          break;
        case 1:
          builder.to(toValue + fromToUnitsStr);
          break;
        case 2:
          builder.from(fromValue + fromToUnitsStr);
          builder.to(toValue + fromToUnitsStr);
          break;
      }
    }
    if (randomBoolean()) {
      builder.includeLower(randomBoolean());
    }
    if (randomBoolean()) {
      builder.includeUpper(randomBoolean());
    }
    if (randomBoolean()) {
      builder.geoDistance(randomFrom(GeoDistance.values()));
    }
    builder.unit(fromToUnits);
    if (randomBoolean()) {
      builder.setValidationMethod(randomFrom(GeoValidationMethod.values()));
    }

    if (randomBoolean()) {
      builder.ignoreUnmapped(randomBoolean());
    }
    return builder;
  }
  private void parse(ParseContext context, GeoPoint point, String geohash) throws IOException {
    if (fieldType().ignoreMalformed == false) {
      if (point.lat() > 90.0 || point.lat() < -90.0) {
        throw new IllegalArgumentException(
            "illegal latitude value [" + point.lat() + "] for " + name());
      }
      if (point.lon() > 180.0 || point.lon() < -180) {
        throw new IllegalArgumentException(
            "illegal longitude value [" + point.lon() + "] for " + name());
      }
    }

    if (fieldType().coerce) {
      // by setting coerce to false we are assuming all geopoints are already in a valid coordinate
      // system
      // thus this extra step can be skipped
      // LUCENE WATCH: This will be folded back into Lucene's GeoPointField
      GeoUtils.normalizePoint(point, true, true);
    }

    if (fieldType().indexOptions() != IndexOptions.NONE || fieldType().stored()) {
      Field field =
          new Field(
              fieldType().names().indexName(),
              Double.toString(point.lat()) + ',' + Double.toString(point.lon()),
              fieldType());
      context.doc().add(field);
    }
    if (fieldType().isGeohashEnabled()) {
      if (geohash == null) {
        geohash = GeoHashUtils.encode(point.lat(), point.lon());
      }
      addGeohashField(context, geohash);
    }
    if (fieldType().isLatLonEnabled()) {
      latMapper.parse(context.createExternalValueContext(point.lat()));
      lonMapper.parse(context.createExternalValueContext(point.lon()));
    }
    if (fieldType().hasDocValues()) {
      CustomGeoPointDocValuesField field =
          (CustomGeoPointDocValuesField) context.doc().getByKey(fieldType().names().indexName());
      if (field == null) {
        field =
            new CustomGeoPointDocValuesField(
                fieldType().names().indexName(), point.lat(), point.lon());
        context.doc().addWithKey(fieldType().names().indexName(), field);
      } else {
        field.add(point.lat(), point.lon());
      }
    }
    multiFields.parse(this, context);
  }
 public Builder(String field, GeoPoint point) {
   this(field, point == null ? null : point.geohash(), false);
 }
 public Builder point(GeoPoint point) {
   this.geohash = point.getGeohash();
   return this;
 }
  /**
   * Parse a {@link GeoPoint} with a {@link XContentParser}. A geopoint has one of the following
   * forms:
   *
   * <ul>
   *   <li>Object:
   *       <pre>
   *       {&quot;lat&quot;: <i>&lt;latitude&gt;</i>, &quot;lon&quot;: <i>&lt;longitude&gt;</i>}
   *       </pre>
   *   <li>String:
   *       <pre>&quot;<i>&lt;latitude&gt;</i>,<i>&lt;longitude&gt;</i>&quot;</pre>
   *   <li>Geohash:
   *       <pre>&quot;<i>&lt;geohash&gt;</i>&quot;</pre>
   *   <li>Array:
   *       <pre>[<i>&lt;longitude&gt;</i>,<i>&lt;latitude&gt;</i>]</pre>
   * </ul>
   *
   * @param parser {@link XContentParser} to parse the value from
   * @param point A {@link GeoPoint} that will be reset by the values parsed
   * @return new {@link GeoPoint} parsed from the parse
   * @throws IOException
   * @throws org.elasticsearch.ElasticsearchParseException
   */
  public static GeoPoint parseGeoPoint(XContentParser parser, GeoPoint point)
      throws IOException, ElasticsearchParseException {
    double lat = Double.NaN;
    double lon = Double.NaN;
    String geohash = null;

    if (parser.currentToken() == Token.START_OBJECT) {
      while (parser.nextToken() != Token.END_OBJECT) {
        if (parser.currentToken() == Token.FIELD_NAME) {
          String field = parser.text();
          if (LATITUDE.equals(field)) {
            parser.nextToken();
            switch (parser.currentToken()) {
              case VALUE_NUMBER:
              case VALUE_STRING:
                lat = parser.doubleValue(true);
                break;
              default:
                throw new ElasticsearchParseException("latitude must be a number");
            }
          } else if (LONGITUDE.equals(field)) {
            parser.nextToken();
            switch (parser.currentToken()) {
              case VALUE_NUMBER:
              case VALUE_STRING:
                lon = parser.doubleValue(true);
                break;
              default:
                throw new ElasticsearchParseException("longitude must be a number");
            }
          } else if (GEOHASH.equals(field)) {
            if (parser.nextToken() == Token.VALUE_STRING) {
              geohash = parser.text();
            } else {
              throw new ElasticsearchParseException("geohash must be a string");
            }
          } else {
            throw new ElasticsearchParseException(
                "field must be either [{}], [{}] or [{}]", LATITUDE, LONGITUDE, GEOHASH);
          }
        } else {
          throw new ElasticsearchParseException("token [{}] not allowed", parser.currentToken());
        }
      }

      if (geohash != null) {
        if (!Double.isNaN(lat) || !Double.isNaN(lon)) {
          throw new ElasticsearchParseException("field must be either lat/lon or geohash");
        } else {
          return point.resetFromGeoHash(geohash);
        }
      } else if (Double.isNaN(lat)) {
        throw new ElasticsearchParseException("field [{}] missing", LATITUDE);
      } else if (Double.isNaN(lon)) {
        throw new ElasticsearchParseException("field [{}] missing", LONGITUDE);
      } else {
        return point.reset(lat, lon);
      }

    } else if (parser.currentToken() == Token.START_ARRAY) {
      int element = 0;
      while (parser.nextToken() != Token.END_ARRAY) {
        if (parser.currentToken() == Token.VALUE_NUMBER) {
          element++;
          if (element == 1) {
            lon = parser.doubleValue();
          } else if (element == 2) {
            lat = parser.doubleValue();
          } else {
            throw new ElasticsearchParseException("only two values allowed");
          }
        } else {
          throw new ElasticsearchParseException("numeric value expected");
        }
      }
      return point.reset(lat, lon);
    } else if (parser.currentToken() == Token.VALUE_STRING) {
      String data = parser.text();
      return parseGeoPoint(data, point);
    } else {
      throw new ElasticsearchParseException("geo_point expected");
    }
  }
 /** Creates a query context for a given geo point with a provided boost */
 public GeoQueryContext(GeoPoint geoPoint, int boost) {
   this(geoPoint.geohash(), boost);
 }
 public GeoPoint(GeoPoint template) {
   this(template.getLat(), template.getLon());
 }
 /**
  * Creates a query context for a geo point with a provided boost and enables generating neighbours
  * at specified precisions
  */
 public GeoQueryContext(GeoPoint geoPoint, int boost, int precision, int... neighbours) {
   this(geoPoint.geohash(), boost, precision, neighbours);
 }