Search in sources :

Example 26 with Point

use of org.opensearch.geometry.Point in project OpenSearch by opensearch-project.

the class GeoPolygonDecomposer method holes.

private static Point[][] holes(Edge[] holes, int numHoles) {
    if (numHoles == 0) {
        return new Point[0][];
    }
    final Point[][] points = new Point[numHoles][];
    for (int i = 0; i < numHoles; i++) {
        double[] partitionPoint = new double[3];
        // mark as visited by inverting the sign
        int length = component(holes[i], -(i + 1), null, partitionPoint);
        points[i] = coordinates(holes[i], new Point[length + 1], partitionPoint);
    }
    return points;
}
Also used : Point(org.opensearch.geometry.Point) Point(org.opensearch.geometry.Point)

Example 27 with Point

use of org.opensearch.geometry.Point in project OpenSearch by opensearch-project.

the class GeoPolygonDecomposer method buildPolygon.

private static Polygon buildPolygon(List<Point[]> polygon) {
    List<LinearRing> holes;
    Point[] shell = polygon.get(0);
    if (polygon.size() > 1) {
        holes = new ArrayList<>(polygon.size() - 1);
        for (int i = 1; i < polygon.size(); ++i) {
            Point[] coords = polygon.get(i);
            // We do not have holes on the dateline as they get eliminated
            // when breaking the polygon around it.
            double[] x = new double[coords.length];
            double[] y = new double[coords.length];
            for (int c = 0; c < coords.length; ++c) {
                x[c] = normalizeLon(coords[c].getX());
                y[c] = normalizeLat(coords[c].getY());
            }
            holes.add(new LinearRing(x, y));
        }
    } else {
        holes = Collections.emptyList();
    }
    double[] x = new double[shell.length];
    double[] y = new double[shell.length];
    for (int i = 0; i < shell.length; ++i) {
        // Lucene Tessellator treats different +180 and -180 and we should keep the sign.
        // normalizeLon method excludes -180.
        x[i] = normalizeLonMinus180Inclusive(shell[i].getX());
        y[i] = normalizeLat(shell[i].getY());
    }
    return new Polygon(new LinearRing(x, y), holes);
}
Also used : Point(org.opensearch.geometry.Point) LinearRing(org.opensearch.geometry.LinearRing) Polygon(org.opensearch.geometry.Polygon) MultiPolygon(org.opensearch.geometry.MultiPolygon) Point(org.opensearch.geometry.Point)

Example 28 with Point

use of org.opensearch.geometry.Point in project OpenSearch by opensearch-project.

the class GeoPolygonDecomposer method component.

/**
 * This method sets the component id of all edges in a ring to a given id and shifts the
 * coordinates of this component according to the dateline
 *
 * @param edge  An arbitrary edge of the component
 * @param id    id to apply to the component
 * @param edges a list of edges to which all edges of the component will be added (could be <code>null</code>)
 * @return number of edges that belong to this component
 */
private static int component(final Edge edge, final int id, final ArrayList<Edge> edges, double[] partitionPoint) {
    // find a coordinate that is not part of the dateline
    Edge any = edge;
    while (any.coordinate.getX() == +DATELINE || any.coordinate.getX() == -DATELINE) {
        if ((any = any.next) == edge) {
            break;
        }
    }
    double shiftOffset = any.coordinate.getX() > DATELINE ? DATELINE : (any.coordinate.getX() < -DATELINE ? -DATELINE : 0);
    // run along the border of the component, collect the
    // edges, shift them according to the dateline and
    // update the component id
    int length = 0, connectedComponents = 0;
    // if there are two connected components, splitIndex keeps track of where to split the edge array
    // start at 1 since the source coordinate is shared
    int splitIndex = 1;
    Edge current = edge;
    Edge prev = edge;
    // bookkeep the source and sink of each visited coordinate
    HashMap<Point, Tuple<Edge, Edge>> visitedEdge = new HashMap<>();
    do {
        current.coordinate = shift(current.coordinate, shiftOffset);
        current.component = id;
        if (edges != null) {
            // found a closed loop - we have two connected components so we need to slice into two distinct components
            if (visitedEdge.containsKey(current.coordinate)) {
                partitionPoint[0] = current.coordinate.getX();
                partitionPoint[1] = current.coordinate.getY();
                partitionPoint[2] = current.coordinate.getZ();
                if (connectedComponents > 0 && current.next != edge) {
                    throw new InvalidShapeException("Shape contains more than one shared point");
                }
                // a negative id flags the edge as visited for the edges(...) method.
                // since we're splitting connected components, we want the edges method to visit
                // the newly separated component
                final int visitID = -id;
                Edge firstAppearance = visitedEdge.get(current.coordinate).v2();
                // correct the graph pointers by correcting the 'next' pointer for both the
                // first appearance and this appearance of the edge
                Edge temp = firstAppearance.next;
                firstAppearance.next = current.next;
                current.next = temp;
                current.component = visitID;
                // a non-visited value (anything positive)
                do {
                    prev.component = visitID;
                    prev = visitedEdge.get(prev.coordinate).v1();
                    ++splitIndex;
                } while (!current.coordinate.equals(prev.coordinate));
                ++connectedComponents;
            } else {
                visitedEdge.put(current.coordinate, new Tuple<Edge, Edge>(prev, current));
            }
            edges.add(current);
            prev = current;
        }
        length++;
    } while (connectedComponents == 0 && (current = current.next) != edge);
    return (splitIndex != 1) ? length - splitIndex : length;
}
Also used : InvalidShapeException(org.locationtech.spatial4j.exception.InvalidShapeException) HashMap(java.util.HashMap) Point(org.opensearch.geometry.Point) Point(org.opensearch.geometry.Point) Tuple(org.opensearch.common.collect.Tuple)

Example 29 with Point

use of org.opensearch.geometry.Point in project OpenSearch by opensearch-project.

the class GeometryParser method parseGeometry.

/**
 * Parses the value as a {@link Geometry}. The following types of values are supported:
 * <p>
 * Object: has to contain either lat and lon or geohash fields
 * <p>
 * String: expected to be in "latitude, longitude" format, a geohash or WKT
 * <p>
 * Array: two or more elements, the first element is longitude, the second is latitude, the rest is ignored if ignoreZValue is true
 * <p>
 * Json structure: valid geojson definition
 */
public Geometry parseGeometry(Object value) throws OpenSearchParseException {
    if (value instanceof List) {
        List<?> values = (List<?>) value;
        if (values.size() == 2 && values.get(0) instanceof Number) {
            GeoPoint point = GeoUtils.parseGeoPoint(values, ignoreZValue);
            return new Point(point.lon(), point.lat());
        } else {
            List<Geometry> geometries = new ArrayList<>(values.size());
            for (Object object : values) {
                geometries.add(parseGeometry(object));
            }
            return new GeometryCollection<>(geometries);
        }
    }
    try (XContentParser parser = new MapXContentParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, Collections.singletonMap("null_value", value), null)) {
        // start object
        parser.nextToken();
        // field name
        parser.nextToken();
        // field value
        parser.nextToken();
        if (isPoint(value)) {
            GeoPoint point = GeoUtils.parseGeoPoint(parser, new GeoPoint(), ignoreZValue);
            return new Point(point.lon(), point.lat());
        } else {
            return parse(parser);
        }
    } catch (IOException | ParseException ex) {
        throw new OpenSearchParseException("error parsing geometry ", ex);
    }
}
Also used : MapXContentParser(org.opensearch.common.xcontent.support.MapXContentParser) ArrayList(java.util.ArrayList) Point(org.opensearch.geometry.Point) IOException(java.io.IOException) Geometry(org.opensearch.geometry.Geometry) GeometryCollection(org.opensearch.geometry.GeometryCollection) OpenSearchParseException(org.opensearch.OpenSearchParseException) ArrayList(java.util.ArrayList) List(java.util.List) OpenSearchParseException(org.opensearch.OpenSearchParseException) ParseException(java.text.ParseException) MapXContentParser(org.opensearch.common.xcontent.support.MapXContentParser) XContentParser(org.opensearch.common.xcontent.XContentParser)

Example 30 with Point

use of org.opensearch.geometry.Point in project OpenSearch by opensearch-project.

the class GeoPolygonDecomposer method decomposePolygon.

/**
 * Splits the specified polygon by datelines and adds them to the supplied polygon array
 */
public static void decomposePolygon(Polygon polygon, boolean orientation, List<Polygon> collector) {
    if (polygon.isEmpty()) {
        return;
    }
    // Last point is repeated
    int numEdges = polygon.getPolygon().length() - 1;
    for (int i = 0; i < polygon.getNumberOfHoles(); i++) {
        numEdges += polygon.getHole(i).length() - 1;
        validateHole(polygon.getPolygon(), polygon.getHole(i));
    }
    Edge[] edges = new Edge[numEdges];
    Edge[] holeComponents = new Edge[polygon.getNumberOfHoles()];
    final AtomicBoolean translated = new AtomicBoolean(false);
    int offset = createEdges(0, orientation, polygon.getPolygon(), null, edges, 0, translated);
    for (int i = 0; i < polygon.getNumberOfHoles(); i++) {
        int length = createEdges(i + 1, orientation, polygon.getPolygon(), polygon.getHole(i), edges, offset, translated);
        holeComponents[i] = edges[offset];
        offset += length;
    }
    int numHoles = holeComponents.length;
    numHoles = merge(edges, 0, intersections(+DATELINE, edges), holeComponents, numHoles);
    numHoles = merge(edges, 0, intersections(-DATELINE, edges), holeComponents, numHoles);
    compose(edges, holeComponents, numHoles, collector);
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Point(org.opensearch.geometry.Point)

Aggregations

Point (org.opensearch.geometry.Point)34 MultiPoint (org.opensearch.geometry.MultiPoint)14 XContentBuilder (org.opensearch.common.xcontent.XContentBuilder)9 ArrayList (java.util.ArrayList)6 Geometry (org.opensearch.geometry.Geometry)5 IOException (java.io.IOException)4 InvalidShapeException (org.locationtech.spatial4j.exception.InvalidShapeException)4 XContentParser (org.opensearch.common.xcontent.XContentParser)4 Line (org.opensearch.geometry.Line)4 LinearRing (org.opensearch.geometry.LinearRing)4 Polygon (org.opensearch.geometry.Polygon)4 OpenSearchParseException (org.opensearch.OpenSearchParseException)3 GeometryCollection (org.opensearch.geometry.GeometryCollection)3 PointBuilder (org.opensearch.common.geo.builders.PointBuilder)2 MultiLine (org.opensearch.geometry.MultiLine)2 ParseException (java.text.ParseException)1 Collection (java.util.Collection)1 Collections.singletonMap (java.util.Collections.singletonMap)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1