JtsShapeFactoryTest.java
/*
* 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.locationtech.spatial4j.shape.jts;
import org.junit.Assert;
import org.junit.Test;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.context.jts.JtsSpatialContext;
import org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory;
import org.locationtech.spatial4j.distance.DistanceUtils;
import org.locationtech.spatial4j.distance.GeodesicSphereDistCalc;
import org.locationtech.spatial4j.shape.Circle;
import org.locationtech.spatial4j.shape.Point;
import org.locationtech.spatial4j.shape.Shape;
import org.locationtech.spatial4j.shape.impl.GeoCircle;
import org.locationtech.spatial4j.shape.impl.PointImpl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class JtsShapeFactoryTest {
@Test
public void testIndex() {
JtsSpatialContextFactory ctxFactory = new JtsSpatialContextFactory();
ctxFactory.autoIndex = true;
Geometry g = ctxFactory.getGeometryFactory().createPoint(new Coordinate(0,0)).buffer(0.1);
JtsSpatialContext ctx = ctxFactory.newSpatialContext();
JtsGeometry jtsGeom1 = (JtsGeometry) ctx.getShapeFactory().makeShapeFromGeometry(g);
assertTrue(jtsGeom1.isIndexed());
JtsGeometry jtsGeom2 = ctx.getShapeFactory().makeShape(g);
assertTrue(jtsGeom2.isIndexed());
}
@Test
public void testEmptyPoint() {
JtsSpatialContextFactory jtsCtxFactory = new JtsSpatialContextFactory();
JtsSpatialContext jtsCtx = jtsCtxFactory.newSpatialContext();
GeometryFactory geometryFactory = jtsCtxFactory.getGeometryFactory();
final org.locationtech.jts.geom.Point point = geometryFactory.createPoint();//empty
final Shape shape = jtsCtx.getShapeFactory().makeShapeFromGeometry(point); // don't throw
assertTrue(shape.isEmpty());
}
@Test
public void testCircleGeometryConversions() {
// Hawaii (Far West)
circleGeometryConversionTest(-155.84, 19.74, 50);
// Nunavat (Far North)
circleGeometryConversionTest(-83.10, 70.30, 100);
// Sydney (South East)
circleGeometryConversionTest(151.21, 33.87, 1);
}
private void circleGeometryConversionTest(double x, double y, double radiusKm) {
Point circleCenter = new PointImpl(x, y, SpatialContext.GEO);
double radiusDeg = DistanceUtils.dist2Degrees(radiusKm, DistanceUtils.EARTH_EQUATORIAL_RADIUS_KM);
GeoCircle geoCircle = new GeoCircle(circleCenter, radiusDeg, SpatialContext.GEO);
JtsShapeFactory shapeFactory = JtsSpatialContext.GEO.getShapeFactory();
// Let's ensure the circle-to-polygon conversion is accurate accounting for geodesics.
Geometry geometry = shapeFactory.getGeometryFrom(geoCircle);
Assert.assertTrue(geometry instanceof Polygon);
Polygon polygon = (Polygon) geometry;
Coordinate[] coordinates = polygon.getExteriorRing().getCoordinates();
int size = coordinates.length;
Assert.assertTrue(size >= 100);
GeodesicSphereDistCalc distCalc = new GeodesicSphereDistCalc.Haversine();
double maxDeltaKm = radiusKm / 100; // allow 1% inaccuracy
for (Coordinate coordinate : coordinates) {
// Check distance from center of each point
Point point = new PointImpl(coordinate.x, coordinate.y, SpatialContext.GEO);
double distance = distCalc.distance(point, circleCenter);
double distanceKm = DistanceUtils.degrees2Dist(distance, DistanceUtils.EARTH_MEAN_RADIUS_KM);
assertEquals(String.format("Distance from point to center: %.2f km. Expected: %.2f km", distanceKm,
radiusKm), radiusKm, distanceKm, maxDeltaKm);
}
}
@Test
public void testCircleDateLineWrapping() {
// left wrapping (-180)
circleGeometryConversionDateLineTest(-179.99, 51.22, 5);
// right wrapping (+180)
circleGeometryConversionDateLineTest(179.99, -35.6, 10);
}
private void circleGeometryConversionDateLineTest(double lon, double lat, double radiusKm) {
JtsShapeFactory shapeFactory = JtsSpatialContext.GEO.getShapeFactory();
Circle circle = shapeFactory.circle(lon, lat, DistanceUtils.dist2Degrees(radiusKm, DistanceUtils.EARTH_MEAN_RADIUS_KM));
Geometry geom = shapeFactory.getGeometryFrom(circle);
assertTrue(circle.getBoundingBox().getCrossesDateLine());
assertEquals("MultiPolygon", geom.getGeometryType());
GeodesicSphereDistCalc distCalc = new GeodesicSphereDistCalc.Haversine();
double maxDeltaKm = radiusKm / 100; // allow 1% inaccuracy
for (Coordinate c : geom.getCoordinates()) {
// Check distance from center of each point
Point point = new PointImpl(c.x, c.y, SpatialContext.GEO);
double distance = distCalc.distance(point, lon, lat);
double distanceKm = DistanceUtils.degrees2Dist(distance, DistanceUtils.EARTH_MEAN_RADIUS_KM);
assertEquals(String.format("Distance from point to center: %.2f km. Expected: %.2f km", distanceKm,
radiusKm), radiusKm, distanceKm, maxDeltaKm);
}
}
}