GEO: Add support for z values to libs/geo classes (#38921)
Adds support for z-values to all Geometry objects in the libs/geo library.
This commit is contained in:
parent
8a314a36db
commit
4a42e408c5
|
@ -20,24 +20,32 @@
|
|||
package org.elasticsearch.geo.geometry;
|
||||
|
||||
/**
|
||||
* Circle geometry (not part of WKT standard, but used in elasticsearch)
|
||||
* Circle geometry (not part of WKT standard, but used in elasticsearch) defined by lat/lon coordinates of the center in degrees
|
||||
* and optional altitude in meters.
|
||||
*/
|
||||
public class Circle implements Geometry {
|
||||
public static final Circle EMPTY = new Circle();
|
||||
private final double lat;
|
||||
private final double lon;
|
||||
private final double alt;
|
||||
private final double radiusMeters;
|
||||
|
||||
private Circle() {
|
||||
lat = 0;
|
||||
lon = 0;
|
||||
alt = Double.NaN;
|
||||
radiusMeters = -1;
|
||||
}
|
||||
|
||||
public Circle(final double lat, final double lon, final double radiusMeters) {
|
||||
this(lat, lon, Double.NaN, radiusMeters);
|
||||
}
|
||||
|
||||
public Circle(final double lat, final double lon, final double alt, final double radiusMeters) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.radiusMeters = radiusMeters;
|
||||
this.alt = alt;
|
||||
if (radiusMeters < 0 ) {
|
||||
throw new IllegalArgumentException("Circle radius [" + radiusMeters + "] cannot be negative");
|
||||
}
|
||||
|
@ -62,6 +70,10 @@ public class Circle implements Geometry {
|
|||
return radiusMeters;
|
||||
}
|
||||
|
||||
public double getAlt() {
|
||||
return alt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -70,7 +82,8 @@ public class Circle implements Geometry {
|
|||
Circle circle = (Circle) o;
|
||||
if (Double.compare(circle.lat, lat) != 0) return false;
|
||||
if (Double.compare(circle.lon, lon) != 0) return false;
|
||||
return (Double.compare(circle.radiusMeters, radiusMeters) == 0);
|
||||
if (Double.compare(circle.radiusMeters, radiusMeters) != 0) return false;
|
||||
return (Double.compare(circle.alt, alt) == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,6 +96,8 @@ public class Circle implements Geometry {
|
|||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(radiusMeters);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(alt);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -98,7 +113,11 @@ public class Circle implements Geometry {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "lat=" + lat + ", lon=" + lon + ", radius=" + radiusMeters;
|
||||
return "lat=" + lat + ", lon=" + lon + ", radius=" + radiusMeters + (Double.isNaN(alt) ? ", alt=" + alt : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlt() {
|
||||
return Double.isNaN(alt) == false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,4 +29,8 @@ public interface Geometry {
|
|||
<T> T visit(GeometryVisitor<T> visitor);
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
default boolean hasAlt() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.geo.geometry;
|
|||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +32,8 @@ public class GeometryCollection<G extends Geometry> implements Geometry, Iterabl
|
|||
|
||||
private final List<G> shapes;
|
||||
|
||||
private boolean hasAlt;
|
||||
|
||||
public GeometryCollection() {
|
||||
shapes = Collections.emptyList();
|
||||
}
|
||||
|
@ -39,6 +42,12 @@ public class GeometryCollection<G extends Geometry> implements Geometry, Iterabl
|
|||
if (shapes == null || shapes.isEmpty()) {
|
||||
throw new IllegalArgumentException("the list of shapes cannot be null or empty");
|
||||
}
|
||||
hasAlt = shapes.get(0).hasAlt();
|
||||
for (G shape : shapes) {
|
||||
if (shape.hasAlt() != hasAlt) {
|
||||
throw new IllegalArgumentException("all elements of the collection should have the same number of dimension");
|
||||
}
|
||||
}
|
||||
this.shapes = shapes;
|
||||
}
|
||||
|
||||
|
@ -82,4 +91,18 @@ public class GeometryCollection<G extends Geometry> implements Geometry, Iterabl
|
|||
public Iterator<G> iterator() {
|
||||
return shapes.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlt() {
|
||||
return hasAlt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(type().name().toLowerCase(Locale.ROOT)).append("(shapes=");
|
||||
sb.append(shapes);
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,21 +22,28 @@ package org.elasticsearch.geo.geometry;
|
|||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represents a Line on the earth's surface in lat/lon decimal degrees.
|
||||
* Represents a Line on the earth's surface in lat/lon decimal degrees and optional altitude in meters.
|
||||
*/
|
||||
public class Line implements Geometry {
|
||||
public static final Line EMPTY = new Line();
|
||||
private final double[] lats;
|
||||
private final double[] lons;
|
||||
private final double[] alts;
|
||||
|
||||
protected Line() {
|
||||
lats = new double[0];
|
||||
lons = new double[0];
|
||||
alts = null;
|
||||
}
|
||||
|
||||
public Line(double[] lats, double[] lons) {
|
||||
this(lats, lons, null);
|
||||
}
|
||||
|
||||
public Line(double[] lats, double[] lons, double[] alts) {
|
||||
this.lats = lats;
|
||||
this.lons = lons;
|
||||
this.alts = alts;
|
||||
if (lats == null) {
|
||||
throw new IllegalArgumentException("lats must not be null");
|
||||
}
|
||||
|
@ -49,6 +56,9 @@ public class Line implements Geometry {
|
|||
if (lats.length < 2) {
|
||||
throw new IllegalArgumentException("at least two points in the line is required");
|
||||
}
|
||||
if (alts != null && alts.length != lats.length) {
|
||||
throw new IllegalArgumentException("alts and lats must be equal length");
|
||||
}
|
||||
for (int i = 0; i < lats.length; i++) {
|
||||
GeometryUtils.checkLatitude(lats[i]);
|
||||
GeometryUtils.checkLongitude(lons[i]);
|
||||
|
@ -67,6 +77,14 @@ public class Line implements Geometry {
|
|||
return lons[i];
|
||||
}
|
||||
|
||||
public double getAlt(int i) {
|
||||
if (alts != null) {
|
||||
return alts[i];
|
||||
} else {
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
public double[] getLats() {
|
||||
return lats.clone();
|
||||
}
|
||||
|
@ -75,6 +93,10 @@ public class Line implements Geometry {
|
|||
return lons.clone();
|
||||
}
|
||||
|
||||
public double[] getAlts() {
|
||||
return alts == null ? null : alts.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShapeType type() {
|
||||
return ShapeType.LINESTRING;
|
||||
|
@ -96,19 +118,26 @@ public class Line implements Geometry {
|
|||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Line line = (Line) o;
|
||||
return Arrays.equals(lats, line.lats) &&
|
||||
Arrays.equals(lons, line.lons);
|
||||
Arrays.equals(lons, line.lons) && Arrays.equals(alts, line.alts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Arrays.hashCode(lats);
|
||||
result = 31 * result + Arrays.hashCode(lons);
|
||||
result = 31 * result + Arrays.hashCode(alts);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlt() {
|
||||
return alts != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "lats=" + Arrays.toString(lats) +
|
||||
", lons=" + Arrays.toString(lons);
|
||||
", lons=" + Arrays.toString(lons) +
|
||||
(hasAlt() ? ", alts=" + Arrays.toString(alts) : "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
package org.elasticsearch.geo.geometry;
|
||||
|
||||
/**
|
||||
* Represents a closed line on the earth's surface in lat/lon decimal degrees.
|
||||
* Represents a closed line on the earth's surface in lat/lon decimal degrees and optional altitude in meters.
|
||||
* <p>
|
||||
* Cannot be serialized by WKT directly but used as a part of polygon
|
||||
*/
|
||||
|
@ -31,13 +31,20 @@ public class LinearRing extends Line {
|
|||
}
|
||||
|
||||
public LinearRing(double[] lats, double[] lons) {
|
||||
super(lats, lons);
|
||||
this(lats, lons, null);
|
||||
}
|
||||
|
||||
public LinearRing(double[] lats, double[] lons, double[] alts) {
|
||||
super(lats, lons, alts);
|
||||
if (lats.length < 2) {
|
||||
throw new IllegalArgumentException("linear ring cannot contain less than 2 points, found " + lats.length);
|
||||
}
|
||||
if (lats[0] != lats[lats.length - 1] || lons[0] != lons[lons.length - 1]) {
|
||||
throw new IllegalArgumentException("first and last points of the linear ring must be the same (it must close itself): lats[0]="
|
||||
+ lats[0] + " lats[" + (lats.length - 1) + "]=" + lats[lats.length - 1]);
|
||||
int last = lats.length - 1;
|
||||
if (lats[0] != lats[last] || lons[0] != lons[last] || (alts != null && alts[0] != alts[last])) {
|
||||
throw new IllegalArgumentException("first and last points of the linear ring must be the same (it must close itself):" +
|
||||
" lats[0]=" + lats[0] + " lats[" + last + "]=" + lats[last] +
|
||||
" lons[0]=" + lons[0] + " lons[" + last + "]=" + lons[last] +
|
||||
(alts == null ? "" : " alts[0]=" + alts[0] + " alts[" + last + "]=" + alts[last] ));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ package org.elasticsearch.geo.geometry;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a MultiPoint object on the earth's surface in decimal degrees.
|
||||
* Represents a MultiPoint object on the earth's surface in decimal degrees and optional altitude in meters.
|
||||
*/
|
||||
public class MultiPoint extends GeometryCollection<Point> {
|
||||
public static final MultiPoint EMPTY = new MultiPoint();
|
||||
|
|
|
@ -20,26 +20,33 @@
|
|||
package org.elasticsearch.geo.geometry;
|
||||
|
||||
/**
|
||||
* Represents a Point on the earth's surface in decimal degrees.
|
||||
* Represents a Point on the earth's surface in decimal degrees and optional altitude in meters.
|
||||
*/
|
||||
public class Point implements Geometry {
|
||||
public static final Point EMPTY = new Point();
|
||||
|
||||
private final double lat;
|
||||
private final double lon;
|
||||
private final double alt;
|
||||
private final boolean empty;
|
||||
|
||||
private Point() {
|
||||
lat = 0;
|
||||
lon = 0;
|
||||
alt = Double.NaN;
|
||||
empty = true;
|
||||
}
|
||||
|
||||
public Point(double lat, double lon) {
|
||||
this(lat, lon, Double.NaN);
|
||||
}
|
||||
|
||||
public Point(double lat, double lon, double alt) {
|
||||
GeometryUtils.checkLatitude(lat);
|
||||
GeometryUtils.checkLongitude(lon);
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.alt = alt;
|
||||
this.empty = false;
|
||||
}
|
||||
|
||||
|
@ -56,6 +63,10 @@ public class Point implements Geometry {
|
|||
return lon;
|
||||
}
|
||||
|
||||
public double getAlt() {
|
||||
return alt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -64,7 +75,8 @@ public class Point implements Geometry {
|
|||
Point point = (Point) o;
|
||||
if (point.empty != empty) return false;
|
||||
if (Double.compare(point.lat, lat) != 0) return false;
|
||||
return Double.compare(point.lon, lon) == 0;
|
||||
if (Double.compare(point.lon, lon) != 0) return false;
|
||||
return Double.compare(point.alt, alt) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,6 +87,8 @@ public class Point implements Geometry {
|
|||
result = (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(lon);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(alt);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -88,8 +102,13 @@ public class Point implements Geometry {
|
|||
return empty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlt() {
|
||||
return Double.isNaN(alt) == false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "lat=" + lat + ", lon=" + lon;
|
||||
return "lat=" + lat + ", lon=" + lon + (hasAlt() ? ", alt=" + alt : "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,12 @@ public final class Polygon implements Geometry {
|
|||
public static final Polygon EMPTY = new Polygon();
|
||||
private final LinearRing polygon;
|
||||
private final List<LinearRing> holes;
|
||||
private final boolean hasAlt;
|
||||
|
||||
private Polygon() {
|
||||
polygon = LinearRing.EMPTY;
|
||||
holes = Collections.emptyList();
|
||||
hasAlt = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,10 +47,15 @@ public final class Polygon implements Geometry {
|
|||
if (holes == null) {
|
||||
throw new IllegalArgumentException("holes must not be null");
|
||||
}
|
||||
boolean hasAlt = polygon.hasAlt();
|
||||
checkRing(polygon);
|
||||
for (LinearRing hole : holes) {
|
||||
if (hole.hasAlt() != hasAlt) {
|
||||
throw new IllegalArgumentException("holes must have the same number of dimensions as the polygon");
|
||||
}
|
||||
checkRing(hole);
|
||||
}
|
||||
this.hasAlt = hasAlt;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,6 +101,10 @@ public final class Polygon implements Geometry {
|
|||
return polygon.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlt() {
|
||||
return hasAlt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
package org.elasticsearch.geo.geometry;
|
||||
|
||||
/**
|
||||
* Represents a lat/lon rectangle in decimal degrees.
|
||||
* Represents a lat/lon rectangle in decimal degrees and optional altitude in meters.
|
||||
*/
|
||||
public class Rectangle implements Geometry {
|
||||
public static final Rectangle EMPTY = new Rectangle();
|
||||
|
@ -32,6 +32,10 @@ public class Rectangle implements Geometry {
|
|||
* minimum longitude value (in degrees)
|
||||
*/
|
||||
private final double minLon;
|
||||
/**
|
||||
* maximum altitude value (in meters)
|
||||
*/
|
||||
private final double minAlt;
|
||||
/**
|
||||
* maximum latitude value (in degrees)
|
||||
*/
|
||||
|
@ -40,6 +44,10 @@ public class Rectangle implements Geometry {
|
|||
* minimum latitude value (in degrees)
|
||||
*/
|
||||
private final double maxLon;
|
||||
/**
|
||||
* minimum altitude value (in meters)
|
||||
*/
|
||||
private final double maxAlt;
|
||||
|
||||
private final boolean empty;
|
||||
|
||||
|
@ -48,6 +56,8 @@ public class Rectangle implements Geometry {
|
|||
minLon = 0;
|
||||
maxLat = 0;
|
||||
maxLon = 0;
|
||||
minAlt = Double.NaN;
|
||||
maxAlt = Double.NaN;
|
||||
empty = true;
|
||||
}
|
||||
|
||||
|
@ -55,6 +65,12 @@ public class Rectangle implements Geometry {
|
|||
* Constructs a bounding box by first validating the provided latitude and longitude coordinates
|
||||
*/
|
||||
public Rectangle(double minLat, double maxLat, double minLon, double maxLon) {
|
||||
this(minLat, maxLat, minLon, maxLon, Double.NaN, Double.NaN);
|
||||
}
|
||||
/**
|
||||
* Constructs a bounding box by first validating the provided latitude and longitude coordinates
|
||||
*/
|
||||
public Rectangle(double minLat, double maxLat, double minLon, double maxLon, double minAlt, double maxAlt) {
|
||||
GeometryUtils.checkLatitude(minLat);
|
||||
GeometryUtils.checkLatitude(maxLat);
|
||||
GeometryUtils.checkLongitude(minLon);
|
||||
|
@ -63,10 +79,15 @@ public class Rectangle implements Geometry {
|
|||
this.maxLon = maxLon;
|
||||
this.minLat = minLat;
|
||||
this.maxLat = maxLat;
|
||||
this.minAlt = minAlt;
|
||||
this.maxAlt = maxAlt;
|
||||
empty = false;
|
||||
if (maxLat < minLat) {
|
||||
throw new IllegalArgumentException("max lat cannot be less than min lat");
|
||||
}
|
||||
if (Double.isNaN(minAlt) != Double.isNaN(maxAlt)) {
|
||||
throw new IllegalArgumentException("only one altitude value is specified");
|
||||
}
|
||||
}
|
||||
|
||||
public double getWidth() {
|
||||
|
@ -88,6 +109,11 @@ public class Rectangle implements Geometry {
|
|||
return minLon;
|
||||
}
|
||||
|
||||
|
||||
public double getMinAlt() {
|
||||
return minAlt;
|
||||
}
|
||||
|
||||
public double getMaxLat() {
|
||||
return maxLat;
|
||||
}
|
||||
|
@ -96,6 +122,10 @@ public class Rectangle implements Geometry {
|
|||
return maxLon;
|
||||
}
|
||||
|
||||
public double getMaxAlt() {
|
||||
return maxAlt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShapeType type() {
|
||||
return ShapeType.ENVELOPE;
|
||||
|
@ -115,6 +145,12 @@ public class Rectangle implements Geometry {
|
|||
if (maxLon < minLon) {
|
||||
b.append(" [crosses dateline!]");
|
||||
}
|
||||
if (hasAlt()) {
|
||||
b.append(" alt=");
|
||||
b.append(minAlt);
|
||||
b.append(" TO ");
|
||||
b.append(maxAlt);
|
||||
}
|
||||
b.append(")");
|
||||
|
||||
return b.toString();
|
||||
|
@ -137,7 +173,9 @@ public class Rectangle implements Geometry {
|
|||
if (Double.compare(rectangle.minLat, minLat) != 0) return false;
|
||||
if (Double.compare(rectangle.minLon, minLon) != 0) return false;
|
||||
if (Double.compare(rectangle.maxLat, maxLat) != 0) return false;
|
||||
return Double.compare(rectangle.maxLon, maxLon) == 0;
|
||||
if (Double.compare(rectangle.maxLon, maxLon) != 0) return false;
|
||||
if (Double.compare(rectangle.minAlt, minAlt) != 0) return false;
|
||||
return Double.compare(rectangle.maxAlt, maxAlt) == 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -153,6 +191,10 @@ public class Rectangle implements Geometry {
|
|||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(maxLon);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(minAlt);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(maxAlt);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -165,4 +207,9 @@ public class Rectangle implements Geometry {
|
|||
public boolean isEmpty() {
|
||||
return empty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlt() {
|
||||
return Double.isNaN(maxAlt) == false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,9 +72,13 @@ public class WellKnownText {
|
|||
@Override
|
||||
public Void visit(Circle circle) {
|
||||
sb.append(LPAREN);
|
||||
visitPoint(circle.getLon(), circle.getLat());
|
||||
visitPoint(circle.getLon(), circle.getLat(), Double.NaN);
|
||||
sb.append(SPACE);
|
||||
sb.append(circle.getRadiusMeters());
|
||||
if (circle.hasAlt()) {
|
||||
sb.append(SPACE);
|
||||
sb.append(circle.getAlt());
|
||||
}
|
||||
sb.append(RPAREN);
|
||||
return null;
|
||||
}
|
||||
|
@ -98,11 +102,11 @@ public class WellKnownText {
|
|||
@Override
|
||||
public Void visit(Line line) {
|
||||
sb.append(LPAREN);
|
||||
visitPoint(line.getLon(0), line.getLat(0));
|
||||
visitPoint(line.getLon(0), line.getLat(0), line.getAlt(0));
|
||||
for (int i = 1; i < line.length(); ++i) {
|
||||
sb.append(COMMA);
|
||||
sb.append(SPACE);
|
||||
visitPoint(line.getLon(i), line.getLat(i));
|
||||
visitPoint(line.getLon(i), line.getLat(i), line.getAlt(i));
|
||||
}
|
||||
sb.append(RPAREN);
|
||||
return null;
|
||||
|
@ -127,12 +131,12 @@ public class WellKnownText {
|
|||
}
|
||||
// walk through coordinates:
|
||||
sb.append(LPAREN);
|
||||
visitPoint(multiPoint.get(0).getLon(), multiPoint.get(0).getLat());
|
||||
visitPoint(multiPoint.get(0).getLon(), multiPoint.get(0).getLat(), multiPoint.get(0).getAlt());
|
||||
for (int i = 1; i < multiPoint.size(); ++i) {
|
||||
sb.append(COMMA);
|
||||
sb.append(SPACE);
|
||||
Point point = multiPoint.get(i);
|
||||
visitPoint(point.getLon(), point.getLat());
|
||||
visitPoint(point.getLon(), point.getLat(), point.getAlt());
|
||||
}
|
||||
sb.append(RPAREN);
|
||||
return null;
|
||||
|
@ -150,14 +154,17 @@ public class WellKnownText {
|
|||
sb.append(EMPTY);
|
||||
} else {
|
||||
sb.append(LPAREN);
|
||||
visitPoint(point.getLon(), point.getLat());
|
||||
visitPoint(point.getLon(), point.getLat(), point.getAlt());
|
||||
sb.append(RPAREN);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void visitPoint(double lon, double lat) {
|
||||
private void visitPoint(double lon, double lat, double alt) {
|
||||
sb.append(lon).append(SPACE).append(lat);
|
||||
if (Double.isNaN(alt) == false) {
|
||||
sb.append(SPACE).append(alt);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitCollection(GeometryCollection<?> collection) {
|
||||
|
@ -191,6 +198,7 @@ public class WellKnownText {
|
|||
public Void visit(Rectangle rectangle) {
|
||||
sb.append(LPAREN);
|
||||
// minX, maxX, maxY, minY
|
||||
// TODO: Add 3D support
|
||||
sb.append(rectangle.getMinLon());
|
||||
sb.append(COMMA);
|
||||
sb.append(SPACE);
|
||||
|
@ -278,28 +286,33 @@ public class WellKnownText {
|
|||
}
|
||||
double lon = nextNumber(stream);
|
||||
double lat = nextNumber(stream);
|
||||
Point pt = new Point(lat, lon);
|
||||
if (isNumberNext(stream) == true) {
|
||||
nextNumber(stream);
|
||||
Point pt;
|
||||
if (isNumberNext(stream)) {
|
||||
pt = new Point(lat, lon, nextNumber(stream));
|
||||
} else {
|
||||
pt = new Point(lat, lon);
|
||||
}
|
||||
nextCloser(stream);
|
||||
return pt;
|
||||
}
|
||||
|
||||
private static void parseCoordinates(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons)
|
||||
private static void parseCoordinates(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons, ArrayList<Double> alts)
|
||||
throws IOException, ParseException {
|
||||
parseCoordinate(stream, lats, lons);
|
||||
parseCoordinate(stream, lats, lons, alts);
|
||||
while (nextCloserOrComma(stream).equals(COMMA)) {
|
||||
parseCoordinate(stream, lats, lons);
|
||||
parseCoordinate(stream, lats, lons, alts);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseCoordinate(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons)
|
||||
private static void parseCoordinate(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons, ArrayList<Double> alts)
|
||||
throws IOException, ParseException {
|
||||
lons.add(nextNumber(stream));
|
||||
lats.add(nextNumber(stream));
|
||||
if (isNumberNext(stream)) {
|
||||
nextNumber(stream);
|
||||
alts.add(nextNumber(stream));
|
||||
}
|
||||
if (alts.isEmpty() == false && alts.size() != lons.size()) {
|
||||
throw new ParseException("coordinate dimensions do not match: " + tokenString(stream), stream.lineno());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,10 +323,15 @@ public class WellKnownText {
|
|||
}
|
||||
ArrayList<Double> lats = new ArrayList<>();
|
||||
ArrayList<Double> lons = new ArrayList<>();
|
||||
ArrayList<Double> alts = new ArrayList<>();
|
||||
ArrayList<Point> points = new ArrayList<>();
|
||||
parseCoordinates(stream, lats, lons);
|
||||
parseCoordinates(stream, lats, lons, alts);
|
||||
for (int i = 0; i < lats.size(); i++) {
|
||||
points.add(new Point(lats.get(i), lons.get(i)));
|
||||
if (alts.isEmpty()) {
|
||||
points.add(new Point(lats.get(i), lons.get(i)));
|
||||
} else {
|
||||
points.add(new Point(lats.get(i), lons.get(i), alts.get(i)));
|
||||
}
|
||||
}
|
||||
return new MultiPoint(Collections.unmodifiableList(points));
|
||||
}
|
||||
|
@ -325,8 +343,13 @@ public class WellKnownText {
|
|||
}
|
||||
ArrayList<Double> lats = new ArrayList<>();
|
||||
ArrayList<Double> lons = new ArrayList<>();
|
||||
parseCoordinates(stream, lats, lons);
|
||||
return new Line(lats.stream().mapToDouble(i -> i).toArray(), lons.stream().mapToDouble(i -> i).toArray());
|
||||
ArrayList<Double> alts = new ArrayList<>();
|
||||
parseCoordinates(stream, lats, lons, alts);
|
||||
if (alts.isEmpty()) {
|
||||
return new Line(toArray(lats), toArray(lons));
|
||||
} else {
|
||||
return new Line(toArray(lats), toArray(lons), toArray(alts));
|
||||
}
|
||||
}
|
||||
|
||||
private static MultiLine parseMultiLine(StreamTokenizer stream) throws IOException, ParseException {
|
||||
|
@ -346,8 +369,13 @@ public class WellKnownText {
|
|||
nextOpener(stream);
|
||||
ArrayList<Double> lats = new ArrayList<>();
|
||||
ArrayList<Double> lons = new ArrayList<>();
|
||||
parseCoordinates(stream, lats, lons);
|
||||
return new LinearRing(lats.stream().mapToDouble(i -> i).toArray(), lons.stream().mapToDouble(i -> i).toArray());
|
||||
ArrayList<Double> alts = new ArrayList<>();
|
||||
parseCoordinates(stream, lats, lons, alts);
|
||||
if (alts.isEmpty()) {
|
||||
return new LinearRing(toArray(lats), toArray(lons));
|
||||
} else {
|
||||
return new LinearRing(toArray(lats), toArray(lons), toArray(alts));
|
||||
}
|
||||
}
|
||||
|
||||
private static Polygon parsePolygon(StreamTokenizer stream) throws IOException, ParseException {
|
||||
|
@ -357,17 +385,22 @@ public class WellKnownText {
|
|||
nextOpener(stream);
|
||||
ArrayList<Double> lats = new ArrayList<>();
|
||||
ArrayList<Double> lons = new ArrayList<>();
|
||||
parseCoordinates(stream, lats, lons);
|
||||
ArrayList<Double> alts = new ArrayList<>();
|
||||
parseCoordinates(stream, lats, lons, alts);
|
||||
ArrayList<LinearRing> holes = new ArrayList<>();
|
||||
while (nextCloserOrComma(stream).equals(COMMA)) {
|
||||
holes.add(parsePolygonHole(stream));
|
||||
}
|
||||
if (holes.isEmpty()) {
|
||||
return new Polygon(new LinearRing(lats.stream().mapToDouble(i -> i).toArray(), lons.stream().mapToDouble(i -> i).toArray()));
|
||||
LinearRing shell;
|
||||
if (alts.isEmpty()) {
|
||||
shell = new LinearRing(toArray(lats), toArray(lons));
|
||||
} else {
|
||||
return new Polygon(
|
||||
new LinearRing(lats.stream().mapToDouble(i -> i).toArray(), lons.stream().mapToDouble(i -> i).toArray()),
|
||||
Collections.unmodifiableList(holes));
|
||||
shell = new LinearRing(toArray(lats), toArray(lons), toArray(alts));
|
||||
}
|
||||
if (holes.isEmpty()) {
|
||||
return new Polygon(shell);
|
||||
} else {
|
||||
return new Polygon(shell, Collections.unmodifiableList(holes));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,6 +421,7 @@ public class WellKnownText {
|
|||
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
||||
return Rectangle.EMPTY;
|
||||
}
|
||||
// TODO: Add 3D support
|
||||
double minLon = nextNumber(stream);
|
||||
nextComma(stream);
|
||||
double maxLon = nextNumber(stream);
|
||||
|
@ -407,10 +441,11 @@ public class WellKnownText {
|
|||
double lon = nextNumber(stream);
|
||||
double lat = nextNumber(stream);
|
||||
double radius = nextNumber(stream);
|
||||
Circle circle = new Circle(lat, lon, radius);
|
||||
double alt = Double.NaN;
|
||||
if (isNumberNext(stream) == true) {
|
||||
nextNumber(stream);
|
||||
alt = nextNumber(stream);
|
||||
}
|
||||
Circle circle = new Circle(lat, lon, alt, radius);
|
||||
nextCloser(stream);
|
||||
return circle;
|
||||
}
|
||||
|
@ -561,4 +596,8 @@ public class WellKnownText {
|
|||
});
|
||||
}
|
||||
|
||||
private static double[] toArray(ArrayList<Double> doubles) {
|
||||
return doubles.stream().mapToDouble(i -> i).toArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,10 +30,20 @@ import java.text.ParseException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.Function;
|
||||
|
||||
abstract class BaseGeometryTestCase<T extends Geometry> extends AbstractWireTestCase<T> {
|
||||
|
||||
@Override
|
||||
protected final T createTestInstance() {
|
||||
boolean hasAlt = randomBoolean();
|
||||
T obj = createTestInstance(hasAlt);
|
||||
assertEquals(hasAlt, obj.hasAlt());
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected abstract T createTestInstance(boolean hasAlt);
|
||||
|
||||
@Override
|
||||
protected Writeable.Reader<T> instanceReader() {
|
||||
throw new IllegalStateException("shouldn't be called in this test");
|
||||
|
@ -127,48 +137,86 @@ abstract class BaseGeometryTestCase<T extends Geometry> extends AbstractWireTest
|
|||
return randomDoubleBetween(-180, 180, true);
|
||||
}
|
||||
|
||||
public static Circle randomCircle() {
|
||||
return new Circle(randomDoubleBetween(-90, 90, true), randomDoubleBetween(-180, 180, true), randomDoubleBetween(0, 100, false));
|
||||
public static Circle randomCircle(boolean hasAlt) {
|
||||
if (hasAlt) {
|
||||
return new Circle(randomDoubleBetween(-90, 90, true), randomDoubleBetween(-180, 180, true), randomDouble(),
|
||||
randomDoubleBetween(0, 100, false));
|
||||
} else {
|
||||
return new Circle(randomDoubleBetween(-90, 90, true), randomDoubleBetween(-180, 180, true), randomDoubleBetween(0, 100, false));
|
||||
}
|
||||
}
|
||||
|
||||
public static Line randomLine() {
|
||||
return randomLine(randomBoolean());
|
||||
}
|
||||
|
||||
public static Line randomLine(boolean hasAlts) {
|
||||
int size = randomIntBetween(2, 10);
|
||||
double[] lats = new double[size];
|
||||
double[] lons = new double[size];
|
||||
double[] alts = hasAlts ? new double[size] : null;
|
||||
for (int i = 0; i < size; i++) {
|
||||
lats[i] = randomLat();
|
||||
lons[i] = randomLon();
|
||||
if (hasAlts) {
|
||||
alts[i] = randomDouble();
|
||||
}
|
||||
}
|
||||
if (hasAlts) {
|
||||
return new Line(lats, lons, alts);
|
||||
}
|
||||
return new Line(lats, lons);
|
||||
}
|
||||
|
||||
public static Point randomPoint() {
|
||||
return new Point(randomLat(), randomLon());
|
||||
return randomPoint(randomBoolean());
|
||||
}
|
||||
|
||||
public static LinearRing randomLinearRing() {
|
||||
public static Point randomPoint(boolean hasAlt) {
|
||||
if (hasAlt) {
|
||||
return new Point(randomLat(), randomLon(), randomDouble());
|
||||
} else {
|
||||
return new Point(randomLat(), randomLon());
|
||||
}
|
||||
}
|
||||
|
||||
public static LinearRing randomLinearRing(boolean hasAlt) {
|
||||
int size = randomIntBetween(3, 10);
|
||||
double[] lats = new double[size + 1];
|
||||
double[] lons = new double[size + 1];
|
||||
double[] alts;
|
||||
if (hasAlt) {
|
||||
alts = new double[size + 1];
|
||||
} else {
|
||||
alts = null;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
lats[i] = randomLat();
|
||||
lons[i] = randomLon();
|
||||
if (hasAlt) {
|
||||
alts[i] = randomDouble();
|
||||
}
|
||||
}
|
||||
lats[size] = lats[0];
|
||||
lons[size] = lons[0];
|
||||
return new LinearRing(lats, lons);
|
||||
if (hasAlt) {
|
||||
alts[size] = alts[0];
|
||||
return new LinearRing(lats, lons, alts);
|
||||
} else {
|
||||
return new LinearRing(lats, lons);
|
||||
}
|
||||
}
|
||||
|
||||
public static Polygon randomPolygon() {
|
||||
public static Polygon randomPolygon(boolean hasAlt) {
|
||||
int size = randomIntBetween(0, 10);
|
||||
List<LinearRing> holes = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
holes.add(randomLinearRing());
|
||||
holes.add(randomLinearRing(hasAlt));
|
||||
}
|
||||
if (holes.size() > 0) {
|
||||
return new Polygon(randomLinearRing(), holes);
|
||||
return new Polygon(randomLinearRing(hasAlt), holes);
|
||||
} else {
|
||||
return new Polygon(randomLinearRing());
|
||||
return new Polygon(randomLinearRing(hasAlt));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,23 +228,23 @@ abstract class BaseGeometryTestCase<T extends Geometry> extends AbstractWireTest
|
|||
return new Rectangle(Math.min(lat1, lat2), Math.max(lat1, lat2), minLon, maxLon);
|
||||
}
|
||||
|
||||
public static GeometryCollection<Geometry> randomGeometryCollection() {
|
||||
return randomGeometryCollection(0);
|
||||
public static GeometryCollection<Geometry> randomGeometryCollection(boolean hasAlt) {
|
||||
return randomGeometryCollection(0, hasAlt);
|
||||
}
|
||||
|
||||
private static GeometryCollection<Geometry> randomGeometryCollection(int level) {
|
||||
private static GeometryCollection<Geometry> randomGeometryCollection(int level, boolean hasAlt) {
|
||||
int size = randomIntBetween(1, 10);
|
||||
List<Geometry> shapes = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
@SuppressWarnings("unchecked") Supplier<Geometry> geometry = randomFrom(
|
||||
@SuppressWarnings("unchecked") Function<Boolean, Geometry> geometry = randomFrom(
|
||||
BaseGeometryTestCase::randomCircle,
|
||||
BaseGeometryTestCase::randomLine,
|
||||
BaseGeometryTestCase::randomPoint,
|
||||
BaseGeometryTestCase::randomPolygon,
|
||||
BaseGeometryTestCase::randomRectangle,
|
||||
level < 3 ? () -> randomGeometryCollection(level + 1) : BaseGeometryTestCase::randomPoint // don't build too deep
|
||||
hasAlt ? BaseGeometryTestCase::randomPoint : (b) -> randomRectangle(),
|
||||
level < 3 ? (b) -> randomGeometryCollection(level + 1, b) : BaseGeometryTestCase::randomPoint // don't build too deep
|
||||
);
|
||||
shapes.add(geometry.get());
|
||||
shapes.add(geometry.apply(hasAlt));
|
||||
}
|
||||
return new GeometryCollection<>(shapes);
|
||||
}
|
||||
|
|
|
@ -26,14 +26,22 @@ import java.text.ParseException;
|
|||
|
||||
public class CircleTests extends BaseGeometryTestCase<Circle> {
|
||||
@Override
|
||||
protected Circle createTestInstance() {
|
||||
return new Circle(randomDoubleBetween(-90, 90, true), randomDoubleBetween(-180, 180, true), randomDoubleBetween(0, 100, false));
|
||||
protected Circle createTestInstance(boolean hasAlt) {
|
||||
if (hasAlt) {
|
||||
return new Circle(randomDoubleBetween(-90, 90, true), randomDoubleBetween(-180, 180, true), randomDouble(),
|
||||
randomDoubleBetween(0, 100, false));
|
||||
} else {
|
||||
return new Circle(randomDoubleBetween(-90, 90, true), randomDoubleBetween(-180, 180, true), randomDoubleBetween(0, 100, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void testBasicSerialization() throws IOException, ParseException {
|
||||
assertEquals("circle (20.0 10.0 15.0)", WellKnownText.toWKT(new Circle(10, 20, 15)));
|
||||
assertEquals(new Circle(10, 20, 15), WellKnownText.fromWKT("circle (20.0 10.0 15.0)"));
|
||||
|
||||
assertEquals("circle (20.0 10.0 15.0 25.0)", WellKnownText.toWKT(new Circle(10, 20, 25, 15)));
|
||||
assertEquals(new Circle(10, 20, 25, 15), WellKnownText.fromWKT("circle (20.0 10.0 15.0 25.0)"));
|
||||
|
||||
assertEquals("circle EMPTY", WellKnownText.toWKT(Circle.EMPTY));
|
||||
assertEquals(Circle.EMPTY, WellKnownText.fromWKT("circle EMPTY)"));
|
||||
}
|
||||
|
|
|
@ -28,10 +28,12 @@ import java.util.Collections;
|
|||
|
||||
public class GeometryCollectionTests extends BaseGeometryTestCase<GeometryCollection<Geometry>> {
|
||||
@Override
|
||||
protected GeometryCollection<Geometry> createTestInstance() {
|
||||
return randomGeometryCollection();
|
||||
protected GeometryCollection<Geometry> createTestInstance(boolean hasAlt) {
|
||||
return randomGeometryCollection(hasAlt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testBasicSerialization() throws IOException, ParseException {
|
||||
assertEquals("geometrycollection (point (20.0 10.0),point EMPTY)",
|
||||
WellKnownText.toWKT(new GeometryCollection<Geometry>(Arrays.asList(new Point(10, 20), Point.EMPTY))));
|
||||
|
@ -50,5 +52,9 @@ public class GeometryCollectionTests extends BaseGeometryTestCase<GeometryCollec
|
|||
|
||||
ex = expectThrows(IllegalArgumentException.class, () -> new GeometryCollection<>(null));
|
||||
assertEquals("the list of shapes cannot be null or empty", ex.getMessage());
|
||||
|
||||
ex = expectThrows(IllegalArgumentException.class, () -> new GeometryCollection<>(
|
||||
Arrays.asList(new Point(10, 20), new Point(10, 20, 30))));
|
||||
assertEquals("all elements of the collection should have the same number of dimension", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,14 +26,19 @@ import java.text.ParseException;
|
|||
|
||||
public class LineTests extends BaseGeometryTestCase<Line> {
|
||||
@Override
|
||||
protected Line createTestInstance() {
|
||||
return randomLine();
|
||||
protected Line createTestInstance(boolean hasAlt) {
|
||||
return randomLine(hasAlt);
|
||||
}
|
||||
|
||||
public void testBasicSerialization() throws IOException, ParseException {
|
||||
assertEquals("linestring (3.0 1.0, 4.0 2.0)", WellKnownText.toWKT(new Line(new double[]{1, 2}, new double[]{3, 4})));
|
||||
assertEquals(new Line(new double[]{1, 2}, new double[]{3, 4}), WellKnownText.fromWKT("linestring (3 1, 4 2)"));
|
||||
|
||||
assertEquals("linestring (3.0 1.0 5.0, 4.0 2.0 6.0)", WellKnownText.toWKT(new Line(new double[]{1, 2}, new double[]{3, 4},
|
||||
new double[]{5, 6})));
|
||||
assertEquals(new Line(new double[]{1, 2}, new double[]{3, 4}, new double[]{6, 5}),
|
||||
WellKnownText.fromWKT("linestring (3 1 6, 4 2 5)"));
|
||||
|
||||
assertEquals("linestring EMPTY", WellKnownText.toWKT(Line.EMPTY));
|
||||
assertEquals(Line.EMPTY, WellKnownText.fromWKT("linestring EMPTY)"));
|
||||
}
|
||||
|
|
|
@ -33,7 +33,14 @@ public class LinearRingTests extends ESTestCase {
|
|||
public void testInitValidation() {
|
||||
IllegalArgumentException ex = expectThrows(IllegalArgumentException.class,
|
||||
() -> new LinearRing(new double[]{1, 2, 3}, new double[]{3, 4, 5}));
|
||||
assertEquals("first and last points of the linear ring must be the same (it must close itself): lats[0]=1.0 lats[2]=3.0",
|
||||
assertEquals("first and last points of the linear ring must be the same (it must close itself): lats[0]=1.0 lats[2]=3.0 " +
|
||||
"lons[0]=3.0 lons[2]=5.0",
|
||||
ex.getMessage());
|
||||
|
||||
ex = expectThrows(IllegalArgumentException.class,
|
||||
() -> new LinearRing(new double[]{1, 2, 1}, new double[]{3, 4, 3}, new double[]{1, 2, 3}));
|
||||
assertEquals("first and last points of the linear ring must be the same (it must close itself): lats[0]=1.0 lats[2]=1.0 " +
|
||||
"lons[0]=3.0 lons[2]=3.0 alts[0]=1.0 alts[2]=3.0",
|
||||
ex.getMessage());
|
||||
|
||||
ex = expectThrows(IllegalArgumentException.class, () -> new LinearRing(new double[]{1}, new double[]{3}));
|
||||
|
|
|
@ -30,11 +30,11 @@ import java.util.List;
|
|||
public class MultiLineTests extends BaseGeometryTestCase<MultiLine> {
|
||||
|
||||
@Override
|
||||
protected MultiLine createTestInstance() {
|
||||
protected MultiLine createTestInstance(boolean hasAlt) {
|
||||
int size = randomIntBetween(1, 10);
|
||||
List<Line> arr = new ArrayList<Line>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr.add(randomLine());
|
||||
arr.add(randomLine(hasAlt));
|
||||
}
|
||||
return new MultiLine(arr);
|
||||
}
|
||||
|
|
|
@ -24,17 +24,18 @@ import org.elasticsearch.geo.utils.WellKnownText;
|
|||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MultiPointTests extends BaseGeometryTestCase<MultiPoint> {
|
||||
|
||||
@Override
|
||||
protected MultiPoint createTestInstance() {
|
||||
protected MultiPoint createTestInstance(boolean hasAlt) {
|
||||
int size = randomIntBetween(1, 10);
|
||||
List<Point> arr = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr.add(randomPoint());
|
||||
arr.add(randomPoint(hasAlt));
|
||||
}
|
||||
return new MultiPoint(arr);
|
||||
}
|
||||
|
@ -45,6 +46,16 @@ public class MultiPointTests extends BaseGeometryTestCase<MultiPoint> {
|
|||
assertEquals(new MultiPoint(Collections.singletonList(new Point(1 ,2))),
|
||||
WellKnownText.fromWKT("multipoint (2 1)"));
|
||||
|
||||
assertEquals("multipoint (2.0 1.0, 3.0 4.0)",
|
||||
WellKnownText.toWKT(new MultiPoint(Arrays.asList(new Point(1, 2), new Point(4, 3)))));
|
||||
assertEquals(new MultiPoint(Arrays.asList(new Point(1, 2), new Point(4, 3))),
|
||||
WellKnownText.fromWKT("multipoint (2 1, 3 4)"));
|
||||
|
||||
assertEquals("multipoint (2.0 1.0 10.0, 3.0 4.0 20.0)",
|
||||
WellKnownText.toWKT(new MultiPoint(Arrays.asList(new Point(1, 2, 10), new Point(4, 3, 20)))));
|
||||
assertEquals(new MultiPoint(Arrays.asList(new Point(1, 2, 10), new Point(4, 3, 20))),
|
||||
WellKnownText.fromWKT("multipoint (2 1 10, 3 4 20)"));
|
||||
|
||||
assertEquals("multipoint EMPTY", WellKnownText.toWKT(MultiPoint.EMPTY));
|
||||
assertEquals(MultiPoint.EMPTY, WellKnownText.fromWKT("multipoint EMPTY)"));
|
||||
}
|
||||
|
|
|
@ -30,11 +30,11 @@ import java.util.List;
|
|||
public class MultiPolygonTests extends BaseGeometryTestCase<MultiPolygon> {
|
||||
|
||||
@Override
|
||||
protected MultiPolygon createTestInstance() {
|
||||
protected MultiPolygon createTestInstance(boolean hasAlt) {
|
||||
int size = randomIntBetween(1, 10);
|
||||
List<Polygon> arr = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr.add(randomPolygon());
|
||||
arr.add(randomPolygon(hasAlt));
|
||||
}
|
||||
return new MultiPolygon(arr);
|
||||
}
|
||||
|
|
|
@ -26,14 +26,17 @@ import java.text.ParseException;
|
|||
|
||||
public class PointTests extends BaseGeometryTestCase<Point> {
|
||||
@Override
|
||||
protected Point createTestInstance() {
|
||||
return randomPoint();
|
||||
protected Point createTestInstance(boolean hasAlt) {
|
||||
return randomPoint(hasAlt);
|
||||
}
|
||||
|
||||
public void testBasicSerialization() throws IOException, ParseException {
|
||||
assertEquals("point (20.0 10.0)", WellKnownText.toWKT(new Point(10, 20)));
|
||||
assertEquals(new Point(10, 20), WellKnownText.fromWKT("point (20.0 10.0)"));
|
||||
|
||||
assertEquals("point (20.0 10.0 100.0)", WellKnownText.toWKT(new Point(10, 20, 100)));
|
||||
assertEquals(new Point(10, 20, 100), WellKnownText.fromWKT("point (20.0 10.0 100.0)"));
|
||||
|
||||
assertEquals("point EMPTY", WellKnownText.toWKT(Point.EMPTY));
|
||||
assertEquals(Point.EMPTY, WellKnownText.fromWKT("point EMPTY)"));
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@ import org.elasticsearch.geo.utils.WellKnownText;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collections;
|
||||
|
||||
public class PolygonTests extends BaseGeometryTestCase<Polygon> {
|
||||
@Override
|
||||
protected Polygon createTestInstance() {
|
||||
return randomPolygon();
|
||||
protected Polygon createTestInstance(boolean hasAlt) {
|
||||
return randomPolygon(hasAlt);
|
||||
}
|
||||
|
||||
public void testBasicSerialization() throws IOException, ParseException {
|
||||
|
@ -36,6 +37,11 @@ public class PolygonTests extends BaseGeometryTestCase<Polygon> {
|
|||
assertEquals(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3})),
|
||||
WellKnownText.fromWKT("polygon ((3 1, 4 2, 5 3, 3 1))"));
|
||||
|
||||
assertEquals("polygon ((3.0 1.0 5.0, 4.0 2.0 4.0, 5.0 3.0 3.0, 3.0 1.0 5.0))",
|
||||
WellKnownText.toWKT(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}, new double[]{5, 4, 3, 5}))));
|
||||
assertEquals(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}, new double[]{5, 4, 3, 5})),
|
||||
WellKnownText.fromWKT("polygon ((3 1 5, 4 2 4, 5 3 3, 3 1 5))"));
|
||||
|
||||
assertEquals("polygon EMPTY", WellKnownText.toWKT(Polygon.EMPTY));
|
||||
assertEquals(Polygon.EMPTY, WellKnownText.fromWKT("polygon EMPTY)"));
|
||||
}
|
||||
|
@ -48,5 +54,10 @@ public class PolygonTests extends BaseGeometryTestCase<Polygon> {
|
|||
ex = expectThrows(IllegalArgumentException.class,
|
||||
() -> new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}), null));
|
||||
assertEquals("holes must not be null", ex.getMessage());
|
||||
|
||||
ex = expectThrows(IllegalArgumentException.class,
|
||||
() -> new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}, new double[]{5, 4, 3, 5}),
|
||||
Collections.singletonList(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}))));
|
||||
assertEquals("holes must have the same number of dimensions as the polygon", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ import java.text.ParseException;
|
|||
|
||||
public class RectangleTests extends BaseGeometryTestCase<Rectangle> {
|
||||
@Override
|
||||
protected Rectangle createTestInstance() {
|
||||
protected Rectangle createTestInstance(boolean hasAlt) {
|
||||
assumeFalse("3rd dimension is not supported yet", hasAlt);
|
||||
return randomRectangle();
|
||||
}
|
||||
|
||||
|
@ -47,5 +48,8 @@ public class RectangleTests extends BaseGeometryTestCase<Rectangle> {
|
|||
|
||||
ex = expectThrows(IllegalArgumentException.class, () -> new Rectangle(2, 1, 2, 3));
|
||||
assertEquals("max lat cannot be less than min lat", ex.getMessage());
|
||||
|
||||
ex = expectThrows(IllegalArgumentException.class, () -> new Rectangle(1, 2, 2, 3, 5, Double.NaN));
|
||||
assertEquals("only one altitude value is specified", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue