/*
* Copyright (c) 2016 Vivid Solutions.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jts.index.strtree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import junit.framework.TestCase;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.index.ItemVisitor;
import org.locationtech.jts.index.SpatialIndexTester;
import org.locationtech.jts.util.AssertionFailedException;
import test.jts.index.STRtreeDemo;
import test.jts.util.SerializationUtil;
/**
* @version 1.7
*/
public class STRtreeTest extends TestCase {
private GeometryFactory factory = new GeometryFactory();
public STRtreeTest(String Name_) {
super(Name_);
}
public static void main(String[] args) {
String[] testCaseName = {STRtreeTest.class.getName()};
junit.textui.TestRunner.main(testCaseName);
}
public void testEmptyTreeUsingListQuery()
{
STRtree tree = new STRtree();
List list = tree.query(new Envelope(0, 0, 1, 1));
assertTrue(list.isEmpty());
}
public void testEmptyTreeUsingItemVisitorQuery()
{
STRtree tree = new STRtree();
tree.query(new Envelope(0,0,1,1), new ItemVisitor() {
public void visitItem(Object item) {
assertTrue("Should never reach here", true);
}
});
}
public void testCreateParentsFromVerticalSlice() {
doTestCreateParentsFromVerticalSlice(3, 2, 2, 1);
doTestCreateParentsFromVerticalSlice(4, 2, 2, 2);
doTestCreateParentsFromVerticalSlice(5, 2, 2, 1);
}
public void testSpatialIndex()
throws Exception
{
SpatialIndexTester tester = new SpatialIndexTester();
tester.setSpatialIndex(new STRtree(4));
tester.init();
tester.run();
assertTrue(tester.isSuccess());
}
public void testSerialization()
throws Exception
{
SpatialIndexTester tester = new SpatialIndexTester();
tester.setSpatialIndex(new STRtree(4));
tester.init();
STRtree tree = (STRtree) tester.getSpatialIndex();
// create the index before serialization
tree.query(new Envelope());
byte[] data = SerializationUtil.serialize(tree);
tree = (STRtree) SerializationUtil.deserialize(data);
tester.setSpatialIndex(tree);
tester.run();
assertTrue(tester.isSuccess());
}
public void testDisallowedInserts() {
STRtree t = new STRtree(5);
t.insert(new Envelope(0, 0, 0, 0), new Object());
t.insert(new Envelope(0, 0, 0, 0), new Object());
t.query(new Envelope());
try {
t.insert(new Envelope(0, 0, 0, 0), new Object());
assertTrue(false);
}
catch (AssertionFailedException e) {
assertTrue(true);
}
}
public void testQuery() throws Throwable {
ArrayList geometries = new ArrayList();
geometries.add(factory.createLineString(new Coordinate[]{
new Coordinate(0, 0), new Coordinate(10, 10)}));
geometries.add(factory.createLineString(new Coordinate[]{
new Coordinate(20, 20), new Coordinate(30, 30)}));
geometries.add(factory.createLineString(new Coordinate[]{
new Coordinate(20, 20), new Coordinate(30, 30)}));
STRtreeDemo.TestTree t = new STRtreeDemo.TestTree(4);
for (Iterator i = geometries.iterator(); i.hasNext(); ) {
Geometry g = (Geometry) i.next();
t.insert(g.getEnvelopeInternal(), new Object());
}
t.build();
try {
assertEquals(1, t.query(new Envelope(5, 6, 5, 6)).size());
assertEquals(0, t.query(new Envelope(20, 30, 0, 10)).size());
assertEquals(2, t.query(new Envelope(25, 26, 25, 26)).size());
assertEquals(3, t.query(new Envelope(0, 100, 0, 100)).size());
}
catch (Throwable x) {
STRtreeDemo.printSourceData(geometries, System.out);
STRtreeDemo.printLevels(t, System.out);
throw x;
}
}
public void testVerticalSlices() {
doTestVerticalSlices(3, 2, 2, 1);
doTestVerticalSlices(4, 2, 2, 2);
doTestVerticalSlices(5, 3, 2, 1);
}
public void testRemove() {
STRtree tree = new STRtree();
tree.insert(new Envelope(0, 10, 0, 10), "1");
tree.insert(new Envelope(5, 15, 5, 15), "2");
tree.insert(new Envelope(10, 20, 10, 20), "3");
tree.insert(new Envelope(15, 25, 15, 25), "4");
tree.remove(new Envelope(10, 20, 10, 20), "4");
assertEquals(3, tree.size());
}
public void testKNearestNeighbors() {
int topK = 1000;
int totalRecords = 10000;
GeometryFactory geometryFactory = new GeometryFactory();
Coordinate coordinate = new Coordinate(10.1,-10.1);
Point queryCenter = geometryFactory.createPoint(coordinate);
int valueRange = 1000;
List<Geometry> testDataset = new ArrayList<Geometry>();
List<Geometry> correctData = new ArrayList<Geometry>();
Random random = new Random();
GeometryDistanceComparator distanceComparator = new GeometryDistanceComparator(queryCenter,true);
/*
* Generate the random test data set
*/
for(int i=0;i<totalRecords;i++)
{
coordinate = new Coordinate(-100+random.nextInt(valueRange)*1.1,random.nextInt(valueRange)*(-5.1));
Point spatialObject = geometryFactory.createPoint(coordinate);
testDataset.add(spatialObject);
}
/*
* Sort the original data set and make sure the elements are sorted in an ascending order
*/
Collections.sort(testDataset,distanceComparator);
/*
* Get the correct top K
*/
for(int i=0;i<topK;i++)
{
correctData.add(testDataset.get(i));
}
STRtree strtree = new STRtree();
for(int i=0;i<totalRecords;i++)
{
strtree.insert(testDataset.get(i).getEnvelopeInternal(), testDataset.get(i));
}
/*
* Shoot a random query to make sure the STR-Tree is built.
*/
strtree.query(new Envelope(1+0.1,1+0.1,2+0.1,2+0.1));
/*
* Issue the KNN query.
*/
Object[] testTopK = (Object[])strtree.nearestNeighbour(queryCenter.getEnvelopeInternal(), queryCenter, new GeometryItemDistance(), topK);
List topKList = Arrays.asList(testTopK);
Collections.sort(topKList,distanceComparator);
/*
* Check the difference between correct result and test result. The difference should be 0.
*/
int difference = 0;
for(int i = 0;i<topK;i++)
{
if(distanceComparator.compare(correctData.get(i), (Geometry)topKList.get(i))!=0)
{
difference++;
}
}
assertEquals(difference,0);
}
private void doTestCreateParentsFromVerticalSlice(int childCount,
int nodeCapacity, int expectedChildrenPerParentBoundable,
int expectedChildrenOfLastParent) {
STRtreeDemo.TestTree t = new STRtreeDemo.TestTree(nodeCapacity);
List parentBoundables
= t.createParentBoundablesFromVerticalSlice(itemWrappers(childCount), 0);
for (int i = 0; i < parentBoundables.size() - 1; i++) {//-1
AbstractNode parentBoundable = (AbstractNode) parentBoundables.get(i);
assertEquals(expectedChildrenPerParentBoundable, parentBoundable.getChildBoundables().size());
}
AbstractNode lastParent = (AbstractNode) parentBoundables.get(parentBoundables.size() - 1);
assertEquals(expectedChildrenOfLastParent, lastParent.getChildBoundables().size());
}
private void doTestVerticalSlices(int itemCount, int sliceCount,
int expectedBoundablesPerSlice, int expectedBoundablesOnLastSlice) {
STRtreeDemo.TestTree t = new STRtreeDemo.TestTree(2);
List[] slices =
t.verticalSlices(itemWrappers(itemCount), sliceCount);
assertEquals(sliceCount, slices.length);
for (int i = 0; i < sliceCount - 1; i++) {//-1
assertEquals(expectedBoundablesPerSlice, slices[i].size());
}
assertEquals(expectedBoundablesOnLastSlice, slices[sliceCount - 1].size());
}
private List itemWrappers(int size) {
ArrayList itemWrappers = new ArrayList();
for (int i = 0; i < size; i++) {
itemWrappers.add(new ItemBoundable(new Envelope(0, 0, 0, 0), new Object()));
}
return itemWrappers;
}
}