// Copyright 2017 JanusGraph Authors
//
// Licensed 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.janusgraph.graphdb.attribute;
import com.spatial4j.core.context.jts.JtsSpatialContext;
import org.janusgraph.core.attribute.Geoshape;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;
import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
import org.janusgraph.core.attribute.JtsGeoshapeHelper;
import org.junit.Test;
import java.util.Arrays;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
/**
* @author Matthias Broecheler (me@matthiasb.com)
*/
public class GeoshapeTest {
private static final JtsGeoshapeHelper HELPER = new JtsGeoshapeHelper();
private static final GeometryFactory GF = new GeometryFactory();
@Test
public void testDistance() {
Geoshape p1 = Geoshape.point(37.759, -122.536);
Geoshape p2 = Geoshape.point(35.714, -105.938);
double distance = 1496;
assertEquals(distance,p1.getPoint().distance(p2.getPoint()),5.0);
}
@Test
public void testIntersection() {
for (int i=0;i<50;i++) {
Geoshape point = Geoshape.point(i,i);
Geoshape line = Geoshape.line(Arrays.asList(new double[][] {{i-1,i-1},{i,i},{i+1,i+1}}));
Geoshape polygon = Geoshape.polygon(Arrays.asList(new double[][] {{i-1,i-1},{i,i-1},{i+1,i-i},{i+1,i+1},{i-1,i+1},{i-1,i-1}}));
Geoshape circle = Geoshape.circle(0.0,0.0,point.getPoint().distance(Geoshape.point(0,0).getPoint())+10);
assertTrue(circle.intersect(point));
assertTrue(point.intersect(circle));
assertTrue(circle.intersect(circle));
assertTrue(polygon.intersect(circle));
assertTrue(circle.intersect(polygon));
assertTrue(line.intersect(circle));
assertTrue(circle.intersect(line));
}
}
@Test
public void testEquality() {
Geoshape c = Geoshape.circle(10.0,12.5,100);
Geoshape b = Geoshape.box(20.0, 22.5, 40.5, 60.5);
Geoshape l = Geoshape.line(Arrays.asList(new double[][] {{10.5,20.5},{10.5,22.5},{12.5,22.5}}));
Geoshape p = Geoshape.polygon(Arrays.asList(new double[][] {{10.5,20.5},{8.0,21.75},{10.5,22.5},{11.75,25.0},{12.5,22.5},{15.0,21.0},{12.5,20.5},{11.75,18.0},{10.5,20.5}}));
assertEquals(Geoshape.circle(10.0,12.5,100),c);
assertEquals(Geoshape.box(20.0,22.5,40.5,60.5),b);
assertEquals(Geoshape.line(Arrays.asList(new double[][] {{10.5,20.5},{10.5,22.5},{12.5,22.5}})),l);
assertEquals(Geoshape.polygon(Arrays.asList(new double[][] {{10.5,20.5},{8.0,21.75},{10.5,22.5},{11.75,25.0},{12.5,22.5},{15.0,21.0},{12.5,20.5},{11.75,18.0},{10.5,20.5}})),p);
assertEquals(Geoshape.circle(10.0,12.5,100).hashCode(),c.hashCode());
assertEquals(Geoshape.box(20.0,22.5,40.5,60.5).hashCode(),b.hashCode());
assertEquals(Geoshape.line(Arrays.asList(new double[][] {{10.5,20.5},{10.5,22.5},{12.5,22.5}})).hashCode(),l.hashCode());
assertEquals(Geoshape.polygon(Arrays.asList(new double[][] {{10.5,20.5},{8.0,21.75},{10.5,22.5},{11.75,25.0},{12.5,22.5},{15.0,21.0},{12.5,20.5},{11.75,18.0},{10.5,20.5}})).hashCode(),p.hashCode());
assertNotSame(c.hashCode(),b.hashCode());
assertNotSame(c.hashCode(),l.hashCode());
assertNotSame(c.hashCode(),p.hashCode());
assertNotSame(b.hashCode(),l.hashCode());
assertNotSame(b.hashCode(),p.hashCode());
assertNotSame(l.hashCode(),p.hashCode());
assertNotSame(c,b);
assertNotSame(c,l);
assertNotSame(c,p);
assertNotSame(b,l);
assertNotSame(b,p);
assertNotSame(l,p);
}
@Test
public void testParseCollection() {
Geoshape.GeoshapeSerializer serializer = new Geoshape.GeoshapeSerializer();
assertEquals(Geoshape.point(10, 20), serializer.convert(Arrays.asList(10, 20)));
assertEquals(Geoshape.circle(10, 20, 30), serializer.convert(Arrays.asList(10, 20, 30)));
assertEquals(Geoshape.box(10, 20, 30, 40), serializer.convert(Arrays.asList(10, 20, 30, 40)));
}
@Test(expected = IllegalArgumentException.class)
public void testFailParseCollection() {
Geoshape.GeoshapeSerializer serializer = new Geoshape.GeoshapeSerializer();
serializer.convert(Arrays.asList(10, "Foo"));
}
@Test
public void testGeoJsonPoint() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Point\",\n" +
" \"coordinates\": [20.5, 10.5]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
assertEquals(Geoshape.point(10.5, 20.5), s.convert(json));
}
@Test(expected = IllegalArgumentException.class)
public void testGeoJsonPointUnparseable() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Point\",\n" +
" \"coordinates\": [20.5, \"10.5\"]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
s.convert(json);
}
@Test
public void testGeoJsonCircle() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Circle\",\n" +
" \"radius\": 30.5, " +
" \"coordinates\": [20.5, 10.5]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
assertEquals(Geoshape.circle(10.5, 20.5, 30.5), s.convert(json));
}
@Test(expected = IllegalArgumentException.class)
public void testGeoJsonCircleMissingRadius() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Circle\",\n" +
" \"coordinates\": [20.5, 10.5]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
s.convert(json);
}
@Test
public void testGeoJsonBox() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Polygon\",\n" +
" \"coordinates\": [[20.5, 10.5],[22.5, 10.5],[22.5, 12.5],[20.5, 12.5]]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
assertEquals(Geoshape.box(10.5, 20.5, 12.5, 22.5), s.convert(json));
//Try the reverse order points
json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Polygon\",\n" +
" \"coordinates\": [[20.5, 12.5],[22.5, 12.5],[22.5, 10.5],[20.5, 10.5]]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
assertEquals(Geoshape.box(10.5, 20.5, 12.5, 22.5), s.convert(json));
}
@Test(expected = IllegalArgumentException.class)
public void testGeoJsonInvalidBox1() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Polygon\",\n" +
" \"coordinates\": [[20.5, 12.5],[22.5, 12.5],[22.5, 10.5],[20.5, 10.6]]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
s.convert(json);
}
@Test(expected = IllegalArgumentException.class)
public void testGeoJsonInvalidBox2() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Polygon\",\n" +
" \"coordinates\": [[20.5, 10.5],[22.5, 10.5],[22.5, 12.5]]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
s.convert(json);
}
@Test
public void testGeoJsonLine() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"LineString\",\n" +
" \"coordinates\": [[20.5, 10.5],[22.5, 10.5],[22.5, 12.5]]\n" +
" },\n" +
" \"properties\": {\n" +
" \"name\": \"Dinagat Islands\"\n" +
" }\n" +
"}", HashMap.class);
assertEquals(Geoshape.line(Arrays.asList(new double[][] {{20.5,10.5},{22.5,10.5},{22.5,12.5}})), s.convert(json));
}
@Test
public void testGeoJsonPolygon() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"Polygon\",\n" +
" \"coordinates\": [[[20.5,10.5],[21.75,8.0],[22.5,10.5],[25.0,11.75],[22.5,12.5],[21.0,15.0],[20.5,12.5],[18.0,11.75],[20.5,10.5]]]\n" +
" }" +
"}", HashMap.class);
assertEquals(Geoshape.polygon(Arrays.asList(new double[][] {{20.5,10.5},{21.75,8.0},{22.5,10.5},{25.0,11.75},{22.5,12.5},{21.0,15.0},{20.5,12.5},{18.0,11.75},{20.5,10.5}})), s.convert(json));
}
@Test
public void testGeoJsonMultiPoint() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"MultiPoint\",\n" +
" \"coordinates\": [[100.0, 0.0],[101.0, 1.0]]\n" +
" }" +
"}", HashMap.class);
assertEquals(HELPER.geoshape(GF.createMultiPoint(new Coordinate[] {new Coordinate(100,0), new Coordinate(101,1)})), s.convert(json));
}
@Test
public void testGeoJsonMultiLineString() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"MultiLineString\",\n" +
" \"coordinates\": [[[100.0,0.0],[101.0, 1.0]],[[102.0,2.0],[103.0,3.0]]]\n" +
" }" +
"}", HashMap.class);
assertEquals(HELPER.geoshape(GF.createMultiLineString(new LineString[] {
GF.createLineString(new Coordinate[] {new Coordinate(100,0), new Coordinate(101,1)}),
GF.createLineString(new Coordinate[] {new Coordinate(102,2), new Coordinate(103,3)})})), s.convert(json));
}
@Test
public void testGeoJsonMultiPolygon() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Feature\",\n" +
" \"geometry\": {\n" +
" \"type\": \"MultiPolygon\",\n" +
" \"coordinates\": [[[[102.0,2.0],[103.0,2.0],[103.0,3.0],[102.0,3.0],[102.0,2.0]]]," +
"[[[100.0,0.0],[101.0,0.0],[101.0,1.0],[100.0,1.0],[100.0,0.0]],[[100.2,0.2],[100.8,0.2],[100.8,0.8],[100.2,0.8],[100.2,0.2]]]]\n" +
" }" +
"}", HashMap.class);
assertEquals(HELPER.geoshape(GF.createMultiPolygon(new Polygon[] {
GF.createPolygon(new Coordinate[] {new Coordinate(102,2), new Coordinate(103,2), new Coordinate(103,3), new Coordinate(102,3), new Coordinate(102,2)}),
GF.createPolygon(GF.createLinearRing(new Coordinate[] {new Coordinate(100,0), new Coordinate(101,0), new Coordinate(101,1), new Coordinate(100,1), new Coordinate(100,0)}),
new LinearRing[] { GF.createLinearRing(new Coordinate[] {new Coordinate(100.2,0.2), new Coordinate(100.8,0.2), new Coordinate(100.8,0.8), new Coordinate(100.2,0.8), new Coordinate(100.2,0.2)
})})})), s.convert(json));
}
@Test
public void testGeoJsonGeometry() throws IOException {
Geoshape.GeoshapeSerializer s = new Geoshape.GeoshapeSerializer();
Map json = new ObjectMapper().readValue("{\n" +
" \"type\": \"Point\",\n" +
" \"coordinates\": [20.5, 10.5]\n" +
"}", HashMap.class);
assertEquals(Geoshape.point(10.5, 20.5), s.convert(json));
}
@Test
public void testGeoJsonSerialization() throws IOException {
SimpleModule module = new SimpleModule();
module.addSerializer(new Geoshape.GeoshapeGsonSerializer());
final ObjectMapper om = new ObjectMapper();
om.registerModule(module);
JtsSpatialContext context = (JtsSpatialContext) Geoshape.getSpatialContext();
assertEquals("{\"type\":\"Point\",\"coordinates\":[20.5,10.5]}", om.writeValueAsString(Geoshape.point(10.5, 20.5)));
assertEquals("{\"type\":\"Polygon\",\"coordinates\": [[[20.5,10.5],[20.5,12.5],[22.5,12.5],[22.5,10.5],[20.5,10.5]]]}", om.writeValueAsString(Geoshape.box(10.5, 20.5, 12.5, 22.5)));
assertEquals("{\"type\":\"Circle\",\"coordinates\":[20.5,10.5],\"radius\":30.5,\"properties\":{\"radius_units\":\"km\"}}", om.writeValueAsString(Geoshape.circle(10.5, 20.5, 30.5)));
assertEquals("{\"type\":\"LineString\",\"coordinates\":[[20.5,10.5],[22.5,10.5],[22.5,12.5]]}", om.writeValueAsString(Geoshape.line(Arrays.asList(new double[][] {{20.5,10.5},{22.5,10.5},{22.5,12.5}}))));
assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[20.5,10.5],[21.75,8],[22.5,10.5],[25,11.75],[22.5,12.5],[21,15],[20.5,12.5],[18,11.75],[20.5,10.5]]]}",
om.writeValueAsString(Geoshape.polygon(Arrays.asList(new double[][] {{20.5,10.5},{21.75,8},{22.5,10.5},{25,11.75},{22.5,12.5},{21,15},{20.5,12.5},{18,11.75},{20.5,10.5}}))));
assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[[100,0],[101,1]]}",
om.writeValueAsString(Geoshape.geoshape(context.makeShape(GF.createMultiPoint(new Coordinate[] {new Coordinate(100,0), new Coordinate(101,1)})))));
assertEquals("{\"type\":\"MultiLineString\",\"coordinates\":[[[100,0],[101,1]],[[102,2],[103,3]]]}",
om.writeValueAsString(Geoshape.geoshape(context.makeShape(GF.createMultiLineString(new LineString[] {
GF.createLineString(new Coordinate[] {new Coordinate(100,0), new Coordinate(101,1)}),
GF.createLineString(new Coordinate[] {new Coordinate(102,2), new Coordinate(103,3)})})))));
assertEquals("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[102,2],[103,2],[103,3],[102,3],[102,2]]],[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.8,0.2],[100.8,0.8],[100.2,0.8],[100.2,0.2]]]]}",
om.writeValueAsString(Geoshape.geoshape(context.makeShape(GF.createMultiPolygon(new Polygon[] {
GF.createPolygon(new Coordinate[] {new Coordinate(102,2), new Coordinate(103,2), new Coordinate(103,3), new Coordinate(102,3), new Coordinate(102,2)}),
GF.createPolygon(GF.createLinearRing(new Coordinate[] {new Coordinate(100,0), new Coordinate(101,0), new Coordinate(101,1), new Coordinate(100,1), new Coordinate(100,0)}),
new LinearRing[] { GF.createLinearRing(new Coordinate[] {new Coordinate(100.2,0.2), new Coordinate(100.8,0.2),
new Coordinate(100.8,0.8), new Coordinate(100.2,0.8), new Coordinate(100.2,0.2)})})})))));
}
}