package com.revolsys.geometry.test.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.measure.Measure;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import org.junit.Assert;
import org.junit.Test;
import com.revolsys.collection.list.Lists;
import com.revolsys.geometry.cs.CoordinateSystem;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.Lineal;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.model.Punctual;
import com.revolsys.geometry.model.impl.BoundingBoxDoubleXY;
import com.revolsys.geometry.model.impl.PointDouble;
import com.revolsys.geometry.test.TestConstants;
import com.revolsys.geometry.util.BoundingBoxUtil;
import com.revolsys.util.number.Doubles;
// TODO
//clipToCoordinateSystem()
//clone()
//covers(Geometry)
//covers(Point)
//convert(GeometryFactory)
//covers(BoundingBox)
//covers(Point)
//covers(double, double)
//distance(BoundingBox)
//distance(Geometry)
//equals(Object)
//expand(Point)
//expand(double)
//expand(double, double)
//expandPercent(double)
//expandPercent(double, double)
//expandToInclude(BoundingBox)
//expandToInclude(Record)
//expandToInclude(Geometry)
//expandToInclude(Point)
//getBottomLeftPoint()
//getBottomRightPoint()
//getCentre()
//getCentreX()
//getCentreY()
//getCornerPoint(int)
//getCornerPoints()
//getTopLeftPoint()
//getTopRightPoint()
//hashCode()
//intersection(BoundingBox)
//intersects(BoundingBox)
//intersects(Point)
//intersects(double, double)
//intersects(Geometry)
//move(double, double)
//toGeometry()
//toPolygon()
//toPolygon(GeometryFactory)
//toPolygon(GeometryFactory, int)
//toPolygon(GeometryFactory, int, int)
//toPolygon(int)
//toPolygon(int, int)
public class BoundingBoxTest implements TestConstants {
private static final List<GeometryFactory> GEOMETRY_FACTORIES = Arrays
.asList(GeometryFactory.DEFAULT_3D.convertAxisCount(2), GeometryFactory.fixed(3005, 1.0, 1.0));
private static final double[] NULL_BOUNDS = null;
@SuppressWarnings({
"rawtypes", "unchecked"
})
private void assertBoundingBox(final Geometry geometry, final BoundingBox boundingBox,
final GeometryFactory geometryFactory, final boolean empty, final int axisCount,
final double... bounds) {
Assert.assertEquals("Geometry Factory", geometryFactory, boundingBox.getGeometryFactory());
Assert.assertEquals("Empty", empty, boundingBox.isEmpty());
Assert.assertEquals("Axis Count", axisCount, boundingBox.getAxisCount());
Assert.assertEquals("Bounds", Lists.newArray(bounds),
Lists.newArray(boundingBox.getMinMaxValues()));
Unit unit = SI.METRE;
Unit lengthUnit = SI.METRE;
final StringBuilder wkt = new StringBuilder();
final int srid = boundingBox.getCoordinateSystemId();
if (geometryFactory == GeometryFactory.DEFAULT_3D) {
Assert.assertEquals("coordinateSystem", null, boundingBox.getCoordinateSystem());
Assert.assertEquals("srid", 0, srid);
} else {
if (srid > 0) {
wkt.append("SRID=");
wkt.append(srid);
wkt.append(";");
}
Assert.assertEquals("srid", geometryFactory.getCoordinateSystemId(), srid);
final CoordinateSystem coordinateSystem = geometryFactory.getCoordinateSystem();
Assert.assertEquals("coordinateSystem", coordinateSystem, boundingBox.getCoordinateSystem());
if (coordinateSystem != null) {
unit = coordinateSystem.getUnit();
lengthUnit = coordinateSystem.getLengthUnit();
}
}
wkt.append("BBOX");
assertMinMax(boundingBox, -1, Double.NaN, Double.NaN);
assertMinMax(boundingBox, axisCount + 1, Double.NaN, Double.NaN);
double width = 0;
double height = 0;
double minX = Double.NaN;
double maxX = Double.NaN;
double minY = Double.NaN;
double maxY = Double.NaN;
double area = 0;
if (bounds == null) {
wkt.append(" EMPTY");
} else {
minX = bounds[0];
maxX = bounds[axisCount];
if (axisCount > 1) {
minY = bounds[1];
maxY = bounds[axisCount + 1];
width = Math.abs(maxX - minX);
height = Math.abs(maxY - minY);
area = width * height;
} else {
area = 0;
}
if (axisCount == 3) {
wkt.append(" Z");
} else if (axisCount == 4) {
wkt.append(" ZM");
} else if (axisCount != 2) {
wkt.append(" ");
wkt.append(axisCount);
}
wkt.append("(");
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
if (axisIndex > 0) {
wkt.append(',');
}
wkt.append(Doubles.toString(bounds[axisIndex]));
}
wkt.append(' ');
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
if (axisIndex > 0) {
wkt.append(',');
}
wkt.append(Doubles.toString(bounds[axisCount + axisIndex]));
}
wkt.append(')');
for (int i = 0; i < axisCount; i++) {
assertMinMax(boundingBox, i, bounds[i], bounds[axisCount + i]);
Assert.assertEquals("Minimum " + i, Measure.valueOf(bounds[i], unit),
boundingBox.getMinimum(i));
Assert.assertEquals("Maximum" + i, Measure.valueOf(bounds[axisCount + i], unit),
boundingBox.getMaximum(i));
Assert.assertEquals("Minimum " + i, bounds[i], boundingBox.getMinimum(i, unit), 0);
Assert.assertEquals("Maximum " + i, bounds[axisCount + i], boundingBox.getMaximum(i, unit),
0);
}
}
Assert.assertEquals("MinX", minX, boundingBox.getMinX(), 0);
Assert.assertEquals("MaxX", maxX, boundingBox.getMaxX(), 0);
Assert.assertEquals("MinimumX", Measure.valueOf(minX, unit), boundingBox.getMinimum(0));
Assert.assertEquals("MaximumX", Measure.valueOf(maxX, unit), boundingBox.getMaximum(0));
Assert.assertEquals("MinimumX", minX, boundingBox.getMinimum(0, unit), 0);
Assert.assertEquals("MaximumX", maxX, boundingBox.getMaximum(0, unit), 0);
Assert.assertEquals("MinY", minY, boundingBox.getMinY(), 0);
Assert.assertEquals("MaxY", maxY, boundingBox.getMaxY(), 0);
Assert.assertEquals("MinimumY", Measure.valueOf(minY, unit), boundingBox.getMinimum(1));
Assert.assertEquals("MaximumY", Measure.valueOf(maxY, unit), boundingBox.getMaximum(1));
Assert.assertEquals("MinimumY", minY, boundingBox.getMinimum(1, unit), 0);
Assert.assertEquals("MaximumY", maxY, boundingBox.getMaximum(1, unit), 0);
Assert.assertEquals("WKT", wkt.toString(), boundingBox.toString());
Assert.assertEquals("Area", area, boundingBox.getArea(), 0);
Assert.assertEquals("Width", width, boundingBox.getWidth(), 0);
Assert.assertEquals("Width", width, boundingBox.getWidthLength().doubleValue(lengthUnit), 0);
Assert.assertEquals("Width", Measure.valueOf(width, lengthUnit), boundingBox.getWidthLength());
Assert.assertEquals("Height", height, boundingBox.getHeight(), 0);
Assert.assertEquals("Height", height, boundingBox.getHeightLength().doubleValue(lengthUnit), 0);
Assert.assertEquals("Height", Measure.valueOf(height, lengthUnit),
boundingBox.getHeightLength());
Assert.assertEquals("Aspect Ratio", width / height, boundingBox.getAspectRatio(), 0);
if (geometry != null) {
if (geometry.isEmpty()) {
final boolean intersects = geometry.intersects(boundingBox);
Assert.assertFalse("Bounding Box Intersects Empty", intersects);
} else {
final boolean intersects = geometry.intersects(boundingBox);
Assert.assertTrue("Bounding Box Intersects", intersects);
// Test outside
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(-100, -100)));
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(-100, 0)));
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(-100, 100)));
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(0, -100)));
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(0, 100)));
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(100, -100)));
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(100, 0)));
Assert.assertFalse("Bounding Box Intersects",
geometry.intersects(boundingBox.move(100, 100)));
}
}
}
private void assertIntersects(final boolean intersectsExpected, final double minX1,
final double minY1, final double maxX1, final double maxY1, final double minX2,
final double minY2, final double maxX2, final double maxY2) {
{
final BoundingBox boundingBox1 = new BoundingBoxDoubleXY(minX1, minY1, maxX1, maxY1);
final BoundingBox boundingBox2 = new BoundingBoxDoubleXY(minX2, minY2, maxX2, maxY2);
final boolean intersectsActual = boundingBox1.intersects(boundingBox2);
Assert.assertEquals("Intersects", intersectsExpected, intersectsActual);
}
{
final BoundingBox boundingBox1 = new BoundingBoxDoubleXY(minX1, minY1, maxX1, maxY1);
final BoundingBox boundingBox2 = new BoundingBoxDoubleXY(minX2, minY2, maxX2, maxY2);
final boolean intersectsActual = boundingBox1.intersects(boundingBox2);
Assert.assertEquals("Intersects", intersectsExpected, intersectsActual);
}
}
private void assertMinMax(final BoundingBox boundingBox, final int axisIndex,
final double expectedMin, final double expectedMax) {
final double min = boundingBox.getMin(axisIndex);
Assert.assertEquals("Min " + axisIndex, expectedMin, min, 0);
final double max = boundingBox.getMax(axisIndex);
Assert.assertEquals("Max " + axisIndex, expectedMax, max, 0);
}
@Test
public void testConstructorCoordinatesArray() {
final BoundingBox emptyList = BoundingBoxDoubleXY.newBoundingBox(new Point[0]);
assertBoundingBox(null, emptyList, GeometryFactory.DEFAULT_3D, true, 2, NULL_BOUNDS);
// Different number of axis and values
for (int axisCount = 2; axisCount < 6; axisCount++) {
for (int valueCount = 1; valueCount < 10; valueCount++) {
Point[] points = new Point[valueCount];
final double[] bounds = BoundingBoxUtil.newBounds(axisCount);
for (int i = 0; i < valueCount; i++) {
final double[] values = new double[axisCount];
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
final double value = Math.random() * 360 - 180;
values[axisIndex] = value;
final double min = bounds[axisIndex];
if (Double.isNaN(min) || value < min) {
bounds[axisIndex] = value;
}
final double max = bounds[axisCount + axisIndex];
if (Double.isNaN(max) || value > max) {
bounds[axisCount + axisIndex] = value;
}
}
points[i] = new PointDouble(values);
}
final GeometryFactory noGf = GeometryFactory.DEFAULT_3D.convertAxisCount(axisCount);
final BoundingBox noGeometryFactory = noGf.newBoundingBox(axisCount, points);
assertBoundingBox(null, noGeometryFactory, noGf, false, axisCount, bounds);
final GeometryFactory gfFloating = GeometryFactory.floating(4326, axisCount);
assertBoundingBox(null, gfFloating.newBoundingBox(axisCount, points), gfFloating, false,
axisCount, bounds);
final GeometryFactory gfFixed = GeometryFactory.fixed(4326, axisCount, 10.0, 10.0, 10.0);
points = gfFixed.getPrecise(points);
final double[] boundsPrecise = gfFixed.copyPrecise(bounds);
assertBoundingBox(null, gfFixed.newBoundingBox(axisCount, points), gfFixed, false,
axisCount, boundsPrecise);
}
}
}
@Test
public void testConstructorEmpty() {
final BoundingBox empty = BoundingBox.empty();
assertBoundingBox(null, empty, GeometryFactory.DEFAULT_3D, true, 2, NULL_BOUNDS);
final BoundingBox emptyNullGeometryFactory = BoundingBox.empty();
assertBoundingBox(null, emptyNullGeometryFactory, GeometryFactory.DEFAULT_3D, true, 2,
NULL_BOUNDS);
final BoundingBox emptyWithGeometryFactory = UTM10_GF_2_FLOATING.newBoundingBoxEmpty();
assertBoundingBox(null, emptyWithGeometryFactory, UTM10_GF_2_FLOATING, true, 2, NULL_BOUNDS);
}
@Test
public void testConstructorIterable() {
final BoundingBox emptyNull = BoundingBoxDoubleXY.newBoundingBox((Iterable<Point>)null);
assertBoundingBox(null, emptyNull, GeometryFactory.DEFAULT_3D, true, 2, NULL_BOUNDS);
final BoundingBox emptyList = BoundingBoxDoubleXY.newBoundingBox(new ArrayList<Point>());
assertBoundingBox(null, emptyList, GeometryFactory.DEFAULT_3D, true, 2, NULL_BOUNDS);
final BoundingBox emptyListWithNulls = BoundingBoxDoubleXY
.newBoundingBox(Collections.<Point> singleton(null));
assertBoundingBox(null, emptyListWithNulls, GeometryFactory.DEFAULT_3D, true, 2, NULL_BOUNDS);
final BoundingBox emptyNullCoordinatesList = BoundingBoxDoubleXY
.newBoundingBox((Iterable<Point>)null);
assertBoundingBox(null, emptyNullCoordinatesList, GeometryFactory.DEFAULT_3D, true, 2,
NULL_BOUNDS);
final BoundingBox emptyCoordinatesList = BoundingBoxDoubleXY
.newBoundingBox(new ArrayList<Point>());
assertBoundingBox(null, emptyCoordinatesList, GeometryFactory.DEFAULT_3D, true, 2, NULL_BOUNDS);
// Different number of axis and values
for (int axisCount = 2; axisCount < 6; axisCount++) {
for (int valueCount = 1; valueCount < 10; valueCount++) {
final List<Point> points = new ArrayList<>();
final double[] bounds = BoundingBoxUtil.newBounds(axisCount);
for (int i = 0; i < valueCount; i++) {
final double[] values = new double[axisCount];
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
final double value = Math.random() * 360 - 180;
values[axisIndex] = value;
final double min = bounds[axisIndex];
if (Double.isNaN(min) || value < min) {
bounds[axisIndex] = value;
}
final double max = bounds[axisCount + axisIndex];
if (Double.isNaN(max) || value > max) {
bounds[axisCount + axisIndex] = value;
}
}
points.add(new PointDouble(values));
}
final GeometryFactory noGf = GeometryFactory.DEFAULT_3D.convertAxisCount(axisCount);
final BoundingBox noGeometryFactory = noGf.newBoundingBox(axisCount, points);
assertBoundingBox(null, noGeometryFactory, noGf, false, axisCount, bounds);
final GeometryFactory gfFloating = GeometryFactory.floating(4326, axisCount);
assertBoundingBox(null, gfFloating.newBoundingBox(axisCount, points), gfFloating, false,
axisCount, bounds);
final GeometryFactory gfFixed = GeometryFactory.fixed(4326, axisCount, 10.0, 10.0, 10.0);
final double[] boundsPrecise = gfFixed.copyPrecise(bounds);
assertBoundingBox(null, gfFixed.newBoundingBox(axisCount, points), gfFixed, false,
axisCount, boundsPrecise);
}
}
}
@Test
public void testIntersects() {
assertIntersects(//
true, //
0, 0, 10, 10, //
0, 0, 10, 10 //
);
assertIntersects(//
true, //
0, 0, 10, 10, //
2, 2, 4, 4//
);
assertIntersects(//
true, //
0, 0, 10, 10, //
10, 10, 11, 11//
);
assertIntersects(//
true, //
0, 0, 10, 10, //
-1, -1, 0, 0//
);
assertIntersects(//
true, //
0, 0, 10, 10, //
-1, 10, 0, 11//
);
assertIntersects(//
false, //
0, 0, 10, 10, //
12, 12, 14, 14//
);
}
@Test
public void testLineString() {
for (final GeometryFactory geometryFactory : GEOMETRY_FACTORIES) {
final LineString empty = geometryFactory.lineString();
final BoundingBox boundingBoxEmpty = empty.getBoundingBox();
assertBoundingBox(empty, boundingBoxEmpty, geometryFactory, true, 2, NULL_BOUNDS);
final LineString geometry1 = geometryFactory.lineString(2, 3.0, 4.0, 1.0, 2.0);
final BoundingBox boundingBox1 = geometry1.getBoundingBox();
assertBoundingBox(geometry1, boundingBox1, geometryFactory, false, 2, 1.0, 2.0, 3.0, 4.0);
}
}
@Test
public void testMultiLineString() {
for (final GeometryFactory geometryFactory : GEOMETRY_FACTORIES) {
final Lineal empty = geometryFactory.lineal();
final BoundingBox boundingBoxEmpty = empty.getBoundingBox();
assertBoundingBox(empty, boundingBoxEmpty, geometryFactory, true, 2, NULL_BOUNDS);
final Lineal geometry1 = geometryFactory.lineal(2, new double[][] {
{
3.0, 4.0, 1.0, 2.0
}, {
7.0, 8.0, 5.0, 6.0
}
});
final BoundingBox boundingBox1 = geometry1.getBoundingBox();
assertBoundingBox(geometry1, boundingBox1, geometryFactory, false, 2, 1.0, 2.0, 7.0, 8.0);
}
}
@Test
public void testMultiPoint() {
for (final GeometryFactory geometryFactory : GEOMETRY_FACTORIES) {
final Punctual empty = geometryFactory.punctual();
final BoundingBox boundingBoxEmpty = empty.getBoundingBox();
assertBoundingBox(empty, boundingBoxEmpty, geometryFactory, true, 2, NULL_BOUNDS);
final Punctual geometry1 = geometryFactory.punctual(2, 3.0, 4.0, 1.0, 2.0);
final BoundingBox boundingBox1 = geometry1.getBoundingBox();
assertBoundingBox(geometry1, boundingBox1, geometryFactory, false, 2, 1.0, 2.0, 3.0, 4.0);
}
}
@Test
public void testPoint() {
for (final GeometryFactory geometryFactory : GEOMETRY_FACTORIES) {
final Point empty = geometryFactory.point();
final BoundingBox boundingBoxEmpty = empty.getBoundingBox();
assertBoundingBox(empty, boundingBoxEmpty, geometryFactory, true, 2, NULL_BOUNDS);
final Point geometry1 = geometryFactory.point(1, 2);
final BoundingBox boundingBox10 = geometry1.getBoundingBox();
assertBoundingBox(geometry1, boundingBox10, geometryFactory, false, 2, 1.0, 2.0, 1.0, 2.0);
}
}
}