org.elasticsearch.common.geo.GeometryIO Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch - Open Source, Distributed, RESTful Search Engine
/*
* 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.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.unit.DistanceUnit;
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 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
*/
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();
return switch (type) {
case "geometrycollection" -> readGeometryCollection(in);
case "polygon" -> readPolygon(in);
case "point" -> readPoint(in);
case "linestring" -> readLine(in);
case "multilinestring" -> readMultiLine(in);
case "multipoint" -> readMultiPoint(in);
case "multipolygon" -> readMultiPolygon(in);
case "envelope" -> readRectangle(in);
case "circle" -> 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));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy