blob: 7db061ba952361fbdf1096f6b3cb4cfa6529197e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.
*/
package org.apache.lucene.geo;
import java.text.ParseException;
import org.apache.lucene.util.LuceneTestCase;
public class TestPolygon extends LuceneTestCase {
/** null polyLats not allowed */
public void testPolygonNullPolyLats() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new Polygon(null, new double[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage().contains("polyLats must not be null"));
}
/** null polyLons not allowed */
public void testPolygonNullPolyLons() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new Polygon(new double[] { 18, 18, 19, 19, 18 }, null);
});
assertTrue(expected.getMessage().contains("polyLons must not be null"));
}
/** polygon needs at least 3 vertices */
public void testPolygonLine() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new Polygon(new double[] { 18, 18, 18 }, new double[] { -66, -65, -66 });
});
assertTrue(expected.getMessage().contains("at least 4 polygon points required"));
}
/** polygon needs same number of latitudes as longitudes */
public void testPolygonBogus() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new Polygon(new double[] { 18, 18, 19, 19 }, new double[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage().contains("must be equal length"));
}
/** polygon must be closed */
public void testPolygonNotClosed() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new Polygon(new double[] { 18, 18, 19, 19, 19 }, new double[] { -66, -65, -65, -66, -67 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("it must close itself"));
}
public void testGeoJSONPolygon() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ]\n");
b.append("}\n");
Polygon[] polygons = Polygon.fromGeoJSON(b.toString());
assertEquals(1, polygons.length);
assertEquals(new Polygon(new double[] {0.0, 0.0, 1.0, 1.0, 0.0},
new double[] {100.0, 101.0, 101.0, 100.0, 100.0}), polygons[0]);
}
public void testGeoJSONPolygonWithHole() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ],\n");
b.append(" [ [100.5, 0.5], [100.5, 0.75], [100.75, 0.75], [100.75, 0.5], [100.5, 0.5]]\n");
b.append(" ]\n");
b.append("}\n");
Polygon hole = new Polygon(new double[] {0.5, 0.75, 0.75, 0.5, 0.5},
new double[] {100.5, 100.5, 100.75, 100.75, 100.5});
Polygon expected = new Polygon(new double[] {0.0, 0.0, 1.0, 1.0, 0.0},
new double[] {100.0, 101.0, 101.0, 100.0, 100.0}, hole);
Polygon[] polygons = Polygon.fromGeoJSON(b.toString());
assertEquals(1, polygons.length);
assertEquals(expected, polygons[0]);
}
// a MultiPolygon returns multiple Polygons
public void testGeoJSONMultiPolygon() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(" \"type\": \"MultiPolygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ],\n");
b.append(" [\n");
b.append(" [ [10.0, 2.0], [11.0, 2.0], [11.0, 3.0],\n");
b.append(" [10.0, 3.0], [10.0, 2.0] ]\n");
b.append(" ]\n");
b.append(" ],\n");
b.append("}\n");
Polygon[] polygons = Polygon.fromGeoJSON(b.toString());
assertEquals(2, polygons.length);
assertEquals(new Polygon(new double[] {0.0, 0.0, 1.0, 1.0, 0.0},
new double[] {100.0, 101.0, 101.0, 100.0, 100.0}), polygons[0]);
assertEquals(new Polygon(new double[] {2.0, 2.0, 3.0, 3.0, 2.0},
new double[] {10.0, 11.0, 11.0, 10.0, 10.0}), polygons[1]);
}
// make sure type can appear last (JSON allows arbitrary key/value order for objects)
public void testGeoJSONTypeComesLast() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ],\n");
b.append(" \"type\": \"Polygon\",\n");
b.append("}\n");
Polygon[] polygons = Polygon.fromGeoJSON(b.toString());
assertEquals(1, polygons.length);
assertEquals(new Polygon(new double[] {0.0, 0.0, 1.0, 1.0, 0.0},
new double[] {100.0, 101.0, 101.0, 100.0, 100.0}), polygons[0]);
}
// make sure Polygon inside a type: Feature also works
public void testGeoJSONPolygonFeature() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{ \"type\": \"Feature\",\n");
b.append(" \"geometry\": {\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ]\n");
b.append(" },\n");
b.append(" \"properties\": {\n");
b.append(" \"prop0\": \"value0\",\n");
b.append(" \"prop1\": {\"this\": \"that\"}\n");
b.append(" }\n");
b.append("}\n");
Polygon[] polygons = Polygon.fromGeoJSON(b.toString());
assertEquals(1, polygons.length);
assertEquals(new Polygon(new double[] {0.0, 0.0, 1.0, 1.0, 0.0},
new double[] {100.0, 101.0, 101.0, 100.0, 100.0}), polygons[0]);
}
// make sure MultiPolygon inside a type: Feature also works
public void testGeoJSONMultiPolygonFeature() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{ \"type\": \"Feature\",\n");
b.append(" \"geometry\": {\n");
b.append(" \"type\": \"MultiPolygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ],\n");
b.append(" [\n");
b.append(" [ [10.0, 2.0], [11.0, 2.0], [11.0, 3.0],\n");
b.append(" [10.0, 3.0], [10.0, 2.0] ]\n");
b.append(" ]\n");
b.append(" ]\n");
b.append(" },\n");
b.append(" \"properties\": {\n");
b.append(" \"prop0\": \"value0\",\n");
b.append(" \"prop1\": {\"this\": \"that\"}\n");
b.append(" }\n");
b.append("}\n");
Polygon[] polygons = Polygon.fromGeoJSON(b.toString());
assertEquals(2, polygons.length);
assertEquals(new Polygon(new double[] {0.0, 0.0, 1.0, 1.0, 0.0},
new double[] {100.0, 101.0, 101.0, 100.0, 100.0}), polygons[0]);
assertEquals(new Polygon(new double[] {2.0, 2.0, 3.0, 3.0, 2.0},
new double[] {10.0, 11.0, 11.0, 10.0, 10.0}), polygons[1]);
}
// FeatureCollection with one geometry is allowed:
public void testGeoJSONFeatureCollectionWithSinglePolygon() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{ \"type\": \"FeatureCollection\",\n");
b.append(" \"features\": [\n");
b.append(" { \"type\": \"Feature\",\n");
b.append(" \"geometry\": {\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ]\n");
b.append(" },\n");
b.append(" \"properties\": {\n");
b.append(" \"prop0\": \"value0\",\n");
b.append(" \"prop1\": {\"this\": \"that\"}\n");
b.append(" }\n");
b.append(" }\n");
b.append(" ]\n");
b.append("} \n");
Polygon expected = new Polygon(new double[] {0.0, 0.0, 1.0, 1.0, 0.0},
new double[] {100.0, 101.0, 101.0, 100.0, 100.0});
Polygon[] actual = Polygon.fromGeoJSON(b.toString());
assertEquals(1, actual.length);
assertEquals(expected, actual[0]);
}
// stuff after the object is not allowed
public void testIllegalGeoJSONExtraCrapAtEnd() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ]\n");
b.append("}\n");
b.append("foo\n");
Exception e = expectThrows(ParseException.class, () -> Polygon.fromGeoJSON(b.toString()));
assertTrue(e.getMessage().contains("unexpected character 'f' after end of GeoJSON object"));
}
public void testIllegalGeoJSONLinkedCRS() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ],\n");
b.append(" \"crs\": {\n");
b.append(" \"type\": \"link\",\n");
b.append(" \"properties\": {\n");
b.append(" \"href\": \"http://example.com/crs/42\",\n");
b.append(" \"type\": \"proj4\"\n");
b.append(" }\n");
b.append(" } \n");
b.append("}\n");
Exception e = expectThrows(ParseException.class, () -> Polygon.fromGeoJSON(b.toString()));
assertTrue(e.getMessage().contains("cannot handle linked crs"));
}
// FeatureCollection with more than one geometry is not supported:
public void testIllegalGeoJSONMultipleFeatures() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{ \"type\": \"FeatureCollection\",\n");
b.append(" \"features\": [\n");
b.append(" { \"type\": \"Feature\",\n");
b.append(" \"geometry\": {\"type\": \"Point\", \"coordinates\": [102.0, 0.5]},\n");
b.append(" \"properties\": {\"prop0\": \"value0\"}\n");
b.append(" },\n");
b.append(" { \"type\": \"Feature\",\n");
b.append(" \"geometry\": {\n");
b.append(" \"type\": \"LineString\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]\n");
b.append(" ]\n");
b.append(" },\n");
b.append(" \"properties\": {\n");
b.append(" \"prop0\": \"value0\",\n");
b.append(" \"prop1\": 0.0\n");
b.append(" }\n");
b.append(" },\n");
b.append(" { \"type\": \"Feature\",\n");
b.append(" \"geometry\": {\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ]\n");
b.append(" },\n");
b.append(" \"properties\": {\n");
b.append(" \"prop0\": \"value0\",\n");
b.append(" \"prop1\": {\"this\": \"that\"}\n");
b.append(" }\n");
b.append(" }\n");
b.append(" ]\n");
b.append("} \n");
Exception e = expectThrows(ParseException.class, () -> Polygon.fromGeoJSON(b.toString()));
assertTrue(e.getMessage().contains("can only handle type FeatureCollection (if it has a single polygon geometry), Feature, Polygon or MultiPolygon, but got Point"));
}
public void testPolygonPropertiesCanBeStringArrays() throws Exception {
StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(" \"type\": \"Polygon\",\n");
b.append(" \"coordinates\": [\n");
b.append(" [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n");
b.append(" [100.0, 1.0], [100.0, 0.0] ]\n");
b.append(" ],\n");
b.append(" \"properties\": {\n");
b.append(" \"array\": [ \"value\" ]\n");
b.append(" }\n");
b.append("}\n");
Polygon[] polygons = Polygon.fromGeoJSON(b.toString());
assertEquals(1, polygons.length);
}
}