/** * 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° 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 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); }
@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; }
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 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; }