org.opensearch.common.geo.GeometryIO Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opensearch Show documentation
Show all versions of opensearch Show documentation
OpenSearch subproject :server
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
package org.opensearch.common.geo;
import org.opensearch.common.unit.DistanceUnit;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.geometry.Circle;
import org.opensearch.geometry.Geometry;
import org.opensearch.geometry.GeometryCollection;
import org.opensearch.geometry.GeometryVisitor;
import org.opensearch.geometry.Line;
import org.opensearch.geometry.LinearRing;
import org.opensearch.geometry.MultiLine;
import org.opensearch.geometry.MultiPoint;
import org.opensearch.geometry.MultiPolygon;
import org.opensearch.geometry.Point;
import org.opensearch.geometry.Polygon;
import org.opensearch.geometry.Rectangle;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Utility class for binary serializtion/deserialization of libs/geo classes
*
* @opensearch.internal
*/
public final class GeometryIO {
public static void writeGeometry(StreamOutput out, Geometry geometry) throws IOException {
out.writeString(GeoJson.getGeoJsonName(geometry).toLowerCase(Locale.ROOT));
geometry.visit(new GeometryVisitor() {
@Override
public Void visit(Circle circle) throws IOException {
writeCoordinate(circle.getLat(), circle.getLon(), circle.getAlt());
out.writeDouble(circle.getRadiusMeters());
DistanceUnit.METERS.writeTo(out);
return null;
}
@Override
public Void visit(GeometryCollection> collection) throws IOException {
out.writeVInt(collection.size());
for (Geometry shape : collection) {
writeGeometry(out, shape);
}
return null;
}
@Override
public Void visit(Line line) throws IOException {
writeCoordinates(line);
return null;
}
@Override
public Void visit(LinearRing ring) {
throw new UnsupportedOperationException("linear ring is not supported");
}
@Override
public Void visit(MultiLine multiLine) throws IOException {
out.writeVInt(multiLine.size());
for (Line line : multiLine) {
visit(line);
}
return null;
}
@Override
public Void visit(MultiPoint multiPoint) throws IOException {
out.writeVInt(multiPoint.size());
for (int i = 0; i < multiPoint.size(); i++) {
Point point = multiPoint.get(i);
writeCoordinate(point.getY(), point.getX(), point.getZ());
}
return null;
}
@Override
public Void visit(MultiPolygon multiPolygon) throws IOException {
out.writeBoolean(true); // Orientation for BWC with ShapeBuilder
out.writeVInt(multiPolygon.size());
for (int i = 0; i < multiPolygon.size(); i++) {
visit(multiPolygon.get(i));
}
return null;
}
@Override
public Void visit(Point point) throws IOException {
out.writeVInt(1); // Number of points For BWC with Shape Builder
writeCoordinate(point.getY(), point.getX(), point.getZ());
return null;
}
@Override
public Void visit(Polygon polygon) throws IOException {
writeCoordinates(polygon.getPolygon());
out.writeBoolean(true); // Orientation for BWC with ShapeBuilder
out.writeVInt(polygon.getNumberOfHoles());
for (int i = 0; i < polygon.getNumberOfHoles(); i++) {
writeCoordinates(polygon.getHole(i));
}
return null;
}
@Override
public Void visit(Rectangle rectangle) throws IOException {
writeCoordinate(rectangle.getMaxY(), rectangle.getMinX(), rectangle.getMinZ()); // top left
writeCoordinate(rectangle.getMinY(), rectangle.getMaxX(), rectangle.getMaxZ()); // bottom right
return null;
}
private void writeCoordinate(double lat, double lon, double alt) throws IOException {
out.writeDouble(lon);
out.writeDouble(lat);
out.writeOptionalDouble(Double.isNaN(alt) ? null : alt);
}
private void writeCoordinates(Line line) throws IOException {
out.writeVInt(line.length());
for (int i = 0; i < line.length(); i++) {
writeCoordinate(line.getY(i), line.getX(i), line.getZ(i));
}
}
});
}
public static Geometry readGeometry(StreamInput in) throws IOException {
String type = in.readString();
switch (type) {
case "geometrycollection":
return readGeometryCollection(in);
case "polygon":
return readPolygon(in);
case "point":
return readPoint(in);
case "linestring":
return readLine(in);
case "multilinestring":
return readMultiLine(in);
case "multipoint":
return readMultiPoint(in);
case "multipolygon":
return readMultiPolygon(in);
case "envelope":
return readRectangle(in);
case "circle":
return readCircle(in);
default:
throw new UnsupportedOperationException("unsupported shape type " + type);
}
}
private static GeometryCollection readGeometryCollection(StreamInput in) throws IOException {
int size = in.readVInt();
List shapes = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
shapes.add(readGeometry(in));
}
return new GeometryCollection<>(shapes);
}
private static Polygon readPolygon(StreamInput in) throws IOException {
double[][] shellComponents = readLineComponents(in);
boolean orientation = in.readBoolean();
LinearRing shell = buildLinearRing(shellComponents, orientation);
int numberOfHoles = in.readVInt();
if (numberOfHoles > 0) {
List holes = new ArrayList<>(numberOfHoles);
for (int i = 0; i < numberOfHoles; i++) {
holes.add(buildLinearRing(readLineComponents(in), orientation));
}
return new Polygon(shell, holes);
} else {
return new Polygon(shell);
}
}
private static double[][] readLineComponents(StreamInput in) throws IOException {
int len = in.readVInt();
double[] lat = new double[len];
double[] lon = new double[len];
double[] alt = new double[len];
for (int i = 0; i < len; i++) {
lon[i] = in.readDouble();
lat[i] = in.readDouble();
alt[i] = readAlt(in);
}
if (Double.isNaN(alt[0])) {
return new double[][] { lat, lon };
} else {
return new double[][] { lat, lon, alt };
}
}
private static void reverse(double[][] arr) {
for (double[] carr : arr) {
int len = carr.length;
for (int j = 0; j < len / 2; j++) {
double temp = carr[j];
carr[j] = carr[len - j - 1];
carr[len - j - 1] = temp;
}
}
}
private static LinearRing buildLinearRing(double[][] arr, boolean orientation) {
if (orientation == false) {
reverse(arr);
}
if (arr.length == 3) {
return new LinearRing(arr[1], arr[0], arr[2]);
} else {
return new LinearRing(arr[1], arr[0]);
}
}
private static Point readPoint(StreamInput in) throws IOException {
int size = in.readVInt(); // For BWC with Shape Builder
if (size != 1) {
throw new IOException("Unexpected point count " + size);
}
double lon = in.readDouble();
double lat = in.readDouble();
double alt = readAlt(in);
return new Point(lon, lat, alt);
}
private static Line readLine(StreamInput in) throws IOException {
double[][] coords = readLineComponents(in);
if (coords.length == 3) {
return new Line(coords[1], coords[0], coords[2]);
} else {
return new Line(coords[1], coords[0]);
}
}
private static MultiLine readMultiLine(StreamInput in) throws IOException {
int size = in.readVInt();
List lines = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
lines.add(readLine(in));
}
return new MultiLine(lines);
}
private static MultiPoint readMultiPoint(StreamInput in) throws IOException {
int size = in.readVInt();
List points = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
double lon = in.readDouble();
double lat = in.readDouble();
double alt = readAlt(in);
points.add(new Point(lon, lat, alt));
}
return new MultiPoint(points);
}
private static MultiPolygon readMultiPolygon(StreamInput in) throws IOException {
in.readBoolean(); // orientation for BWC
int size = in.readVInt();
List polygons = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
polygons.add(readPolygon(in));
}
return new MultiPolygon(polygons);
}
private static Rectangle readRectangle(StreamInput in) throws IOException {
// top left
double minLon = in.readDouble();
double maxLat = in.readDouble();
double minAlt = readAlt(in);
// bottom right
double maxLon = in.readDouble();
double minLat = in.readDouble();
double maxAlt = readAlt(in);
return new Rectangle(minLon, maxLon, maxLat, minLat, minAlt, maxAlt);
}
private static double readAlt(StreamInput in) throws IOException {
Double alt = in.readOptionalDouble();
if (alt == null) {
return Double.NaN;
} else {
return alt;
}
}
private static Circle readCircle(StreamInput in) throws IOException {
double lon = in.readDouble();
double lat = in.readDouble();
double alt = readAlt(in);
double radius = in.readDouble();
DistanceUnit distanceUnit = DistanceUnit.readFromStream(in);
return new Circle(lon, lat, alt, distanceUnit.toMeters(radius));
}
}