All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.common.geo.GeoShapeUtils Maven / Gradle / Ivy

There is a newer version: 8.14.0
Show newest version
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */
package org.elasticsearch.common.geo;

import org.apache.lucene.geo.GeoEncodingUtils;
import org.apache.lucene.geo.LatLonGeometry;
import org.elasticsearch.geometry.Circle;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.geometry.GeometryCollection;
import org.elasticsearch.geometry.GeometryVisitor;
import org.elasticsearch.geometry.Line;
import org.elasticsearch.geometry.LinearRing;
import org.elasticsearch.geometry.MultiLine;
import org.elasticsearch.geometry.MultiPoint;
import org.elasticsearch.geometry.MultiPolygon;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.query.QueryShardException;
import org.elasticsearch.index.query.SearchExecutionContext;

import java.util.ArrayList;
import java.util.List;

/**
 * Utility class that transforms Elasticsearch geometry objects to the Lucene representation
 */
public class GeoShapeUtils {

    public static org.apache.lucene.geo.Polygon toLucenePolygon(Polygon polygon) {
        org.apache.lucene.geo.Polygon[] holes = new org.apache.lucene.geo.Polygon[polygon.getNumberOfHoles()];
        for (int i = 0; i < holes.length; i++) {
            holes[i] = new org.apache.lucene.geo.Polygon(polygon.getHole(i).getY(), polygon.getHole(i).getX());
        }
        return new org.apache.lucene.geo.Polygon(polygon.getPolygon().getY(), polygon.getPolygon().getX(), holes);
    }

    public static org.apache.lucene.geo.Polygon toLucenePolygon(Rectangle r) {
        return new org.apache.lucene.geo.Polygon(
            new double[] { r.getMinLat(), r.getMinLat(), r.getMaxLat(), r.getMaxLat(), r.getMinLat() },
            new double[] { r.getMinLon(), r.getMaxLon(), r.getMaxLon(), r.getMinLon(), r.getMinLon() }
        );
    }

    public static org.apache.lucene.geo.Rectangle toLuceneRectangle(Rectangle r) {
        return new org.apache.lucene.geo.Rectangle(r.getMinLat(), r.getMaxLat(), r.getMinLon(), r.getMaxLon());
    }

    public static org.apache.lucene.geo.Point toLucenePoint(Point point) {
        // Quantize the points to match points in index.
        final double lon = GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(point.getLon()));
        final double lat = GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(point.getLat()));
        return new org.apache.lucene.geo.Point(lat, lon);
    }

    public static org.apache.lucene.geo.Line toLuceneLine(Line line) {
        return new org.apache.lucene.geo.Line(line.getLats(), line.getLons());
    }

    public static org.apache.lucene.geo.Circle toLuceneCircle(Circle circle) {
        return new org.apache.lucene.geo.Circle(circle.getLat(), circle.getLon(), circle.getRadiusMeters());
    }

    public static LatLonGeometry[] toLuceneGeometry(
        String name,
        SearchExecutionContext context,
        Geometry geometry,
        ShapeRelation relation
    ) {
        if (geometry == null) {
            return new LatLonGeometry[0];
        }
        final List geometries = new ArrayList<>();
        geometry.visit(new GeometryVisitor() {
            @Override
            public Void visit(Circle circle) {
                if (circle.isEmpty() == false) {
                    geometries.add(GeoShapeUtils.toLuceneCircle(circle));
                }
                return null;
            }

            @Override
            public Void visit(GeometryCollection collection) {
                if (collection.isEmpty() == false) {
                    for (Geometry shape : collection) {
                        shape.visit(this);
                    }
                }
                return null;
            }

            @Override
            public Void visit(org.elasticsearch.geometry.Line line) {
                if (line.isEmpty() == false) {
                    if (relation == ShapeRelation.WITHIN) {
                        // Line geometries and WITHIN relation is not supported by Lucene. Throw an error here
                        // to have same behavior for runtime fields.
                        throw new QueryShardException(context, "Field [" + name + "] found an unsupported shape Line");
                    }
                    geometries.add(GeoShapeUtils.toLuceneLine(line));
                }
                return null;
            }

            @Override
            public Void visit(LinearRing ring) {
                throw new QueryShardException(context, "Field [" + name + "] found an unsupported shape LinearRing");
            }

            @Override
            public Void visit(MultiLine multiLine) {
                if (multiLine.isEmpty() == false) {
                    for (Line line : multiLine) {
                        visit(line);
                    }
                }
                return null;
            }

            @Override
            public Void visit(MultiPoint multiPoint) {
                if (multiPoint.isEmpty() == false) {
                    for (Point point : multiPoint) {
                        visit(point);
                    }
                }
                return null;
            }

            @Override
            public Void visit(MultiPolygon multiPolygon) {
                if (multiPolygon.isEmpty() == false) {
                    for (Polygon polygon : multiPolygon) {
                        visit(polygon);
                    }
                }
                return null;
            }

            @Override
            public Void visit(Point point) {
                if (point.isEmpty() == false) {
                    geometries.add(toLucenePoint(point));
                }
                return null;

            }

            @Override
            public Void visit(org.elasticsearch.geometry.Polygon polygon) {
                if (polygon.isEmpty() == false) {
                    List collector = new ArrayList<>();
                    GeoPolygonDecomposer.decomposePolygon(polygon, true, collector);
                    collector.forEach((p) -> geometries.add(toLucenePolygon(p)));
                }
                return null;
            }

            @Override
            public Void visit(Rectangle r) {
                if (r.isEmpty() == false) {
                    geometries.add(toLuceneRectangle(r));
                }
                return null;
            }
        });
        return geometries.toArray(new LatLonGeometry[geometries.size()]);
    }

    private GeoShapeUtils() {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy