/*******************************************************************************
* Copyright (c) 2015 MITRE
* 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;
import org.locationtech.spatial4j.TestLog;
import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.context.SpatialContextFactory;
import org.locationtech.spatial4j.shape.impl.RectangleImpl;
import org.junit.Rule;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.locationtech.spatial4j.shape.SpatialRelation.CONTAINS;
public class ShapeCollectionTest extends RandomizedShapeTest {
public static final String WORLD180 = getLonRangeString(SpatialContext.GEO.getWorldBounds());
protected static String getLonRangeString(Rectangle bbox) {
return bbox.getMinX()+" "+bbox.getMaxX();
}
@Rule
public final TestLog testLog = TestLog.instance;
@Test
public void testBbox() {
validateWorld(-180, 180, -180, 180);
validateWorld(-180, 0, 0, +180);
validateWorld(-90, +90, +90, -90);
}
@Test
public void testBboxNotWorldWrap() {
ctx = SpatialContext.GEO;
//doesn't contain 102, thus shouldn't world-wrap
Rectangle r1 = ctx.makeRectangle(-92, 90, -10, 10);
Rectangle r2 = ctx.makeRectangle(130, 172, -10, 10);
Rectangle r3 = ctx.makeRectangle(172, -60, -10, 10);
ShapeCollection<Rectangle> s = new ShapeCollection<Rectangle>(Arrays.asList(r1,r2,r3), ctx);
assertEquals("130.0 90.0", getLonRangeString(s.getBoundingBox()));
// note: BBoxCalculatorTest thoroughly tests the longitude range
}
private void validateWorld(double r1MinX, double r1MaxX, double r2MinX, double r2MaxX) {
ctx = SpatialContext.GEO;
Rectangle r1 = ctx.makeRectangle(r1MinX, r1MaxX, -10, 10);
Rectangle r2 = ctx.makeRectangle(r2MinX, r2MaxX, -10, 10);
ShapeCollection<Rectangle> s = new ShapeCollection<Rectangle>(Arrays.asList(r1,r2), ctx);
assertEquals(WORLD180, getLonRangeString(s.getBoundingBox()));
//flip r1, r2 order
s = new ShapeCollection<Rectangle>(Arrays.asList(r2,r1), ctx);
assertEquals(WORLD180, getLonRangeString(s.getBoundingBox()));
}
@Test
public void testRectIntersect() {
SpatialContext ctx = new SpatialContextFactory()
{{geo = false; worldBounds = new RectangleImpl(-100, 100, -50, 50, null);}}.newSpatialContext();
new ShapeCollectionRectIntersectionTestHelper(ctx).testRelateWithRectangle();
}
@Test
public void testGeoRectIntersect() {
ctx = SpatialContext.GEO;
new ShapeCollectionRectIntersectionTestHelper(ctx).testRelateWithRectangle();
}
private class ShapeCollectionRectIntersectionTestHelper extends RectIntersectionTestHelper<ShapeCollection> {
private ShapeCollectionRectIntersectionTestHelper(SpatialContext ctx) {
super(ctx);
}
@Override
protected ShapeCollection generateRandomShape(Point nearP) {
testLog.log("Break on nearP.toString(): {}", nearP);
List<Rectangle> shapes = new ArrayList<Rectangle>();
int count = randomIntBetween(1,4);
for(int i = 0; i < count; i++) {
//1st 2 are near nearP, the others are anywhere
shapes.add(randomRectangle( i < 2 ? nearP : null));
}
ShapeCollection shapeCollection = new ShapeCollection<Rectangle>(shapes, ctx);
//test shapeCollection.getBoundingBox();
Rectangle msBbox = shapeCollection.getBoundingBox();
if (shapes.size() == 1) {
assertEquals(shapes.get(0), msBbox.getBoundingBox());
} else {
for (Rectangle shape : shapes) {
assertRelation("bbox contains shape", CONTAINS, msBbox, shape);
}
if (ctx.isGeo() && msBbox.getMinX() == -180 && msBbox.getMaxX() == 180) {
int lonTest = randomIntBetween(-180, 180);
boolean valid = false;
for (Rectangle shape : shapes) {
if (shape.relateXRange(lonTest, lonTest).intersects()) {
valid = true;
break;
}
}
if (!valid)
fail("ShapeCollection bbox world-wrap doesn't contain "+lonTest+" for shapes: "+shapes);
}
}
return shapeCollection;
}
protected Point randomPointInEmptyShape(ShapeCollection shape) {
Rectangle r = (Rectangle) shape.getShapes().get(0);
return randomPointIn(r);
}
}
}