| /* |
| * 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); |
| } |
| } |