/*******************************************************************************
* Copyright (c) 2015 David Smiley
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License, Version 2.0 which
* accompanies this distribution and is available at
* http://www.apache.org/licenses/LICENSE-2.0.txt
******************************************************************************/
package org.locationtech.spatial4j.shape.impl;
import com.carrotsearch.randomizedtesting.annotations.Repeat;
import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.shape.RandomizedShapeTest;
import org.locationtech.spatial4j.shape.Rectangle;
import org.locationtech.spatial4j.shape.SpatialRelation;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class BBoxCalculatorTest extends RandomizedShapeTest {
public BBoxCalculatorTest() {
super(SpatialContext.GEO);
}
// note: testing latitude would be so simple that's effectively the same code as the code to be tested. So I don't.
@Test @Repeat(iterations = 100)
public void testGeoLongitude() {
BBoxCalculator calc = new BBoxCalculator(ctx);
final int numShapes = randomIntBetween(1, 4);//inclusive
List<Rectangle> rects = new ArrayList<>(numShapes);
for (int i = 0; i < numShapes; i++) {
Rectangle rect = randomRectangle(30);// divisible by
rects.add(rect);
calc.expandRange(rect);
}
Rectangle boundary = calc.getBoundary();
if (numShapes == 1) {
assertEquals(rects.get(0), boundary);
return;
}
// If the boundary is the world-bounds, check that it's right.
if (boundary.getMinX() == -180 && boundary.getMaxX() == 180) {
// each longitude should be present in at least one shape:
for (int lon = -180; lon <= +180; lon++) {
assertTrue(atLeastOneRectHasLon(rects, lon));
}
return;
}
// Test that it contains all shapes:
for (Rectangle rect : rects) {
assertRelation(SpatialRelation.CONTAINS, boundary, rect);
}
// Test that the left & right are boundaries:
assertTrue(atLeastOneRectHasLon(rects, boundary.getMinX()));
assertFalse(atLeastOneRectHasLon(rects, normX(boundary.getMinX() - 0.5)));
assertTrue(atLeastOneRectHasLon(rects, boundary.getMaxX()));
assertFalse(atLeastOneRectHasLon(rects, normX(boundary.getMaxX() + 0.5)));
// Test that this is the smallest enclosing boundary by ensuring the gap (opposite the bbox) is
// the largest:
if (boundary.getWidth() > 180) { // conversely if wider than 180 then no wider gap is possible
double biggerGap = 360.0 - boundary.getWidth() + 0.5;
for (Rectangle rect : rects) {
// try to see if a bigger gap could lie to the right of this rect
double gapRectLeft = rect.getMaxX() + 0.25;
double gapRectRight = gapRectLeft + biggerGap;
Rectangle testGap = makeNormRect(gapRectLeft, gapRectRight, -90, 90);
boolean fits = true;
for (Rectangle rect2 : rects) {
if (rect2.relate(testGap).intersects()) {
fits = false;
break;
}
}
assertFalse(fits);//should never fit because it's larger than the biggest gap
}
}
}
private boolean atLeastOneRectHasLon(List<Rectangle> rects, double lon) {
for (Rectangle rect : rects) {
if (rect.relateXRange(lon, lon).intersects()) {
return true;
}
}
return false;
}
}