/* * Copyright 2014 Google Inc. * * Licensed 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 com.google.maps.android.quadtree; import com.google.maps.android.geometry.Bounds; import com.google.maps.android.geometry.Point; import junit.framework.TestCase; import java.util.Collection; import java.util.Random; public class PointQuadTreeTest extends TestCase { private PointQuadTree<Item> mTree; public void setUp() { mTree = new PointQuadTree<Item>(0, 1, 0, 1); } public void testAddOnePoint() { Item item = new Item(0, 0); mTree.add(item); Collection<Item> items = searchAll(); assertEquals(1, items.size()); } public void testEmpty() { Collection<Item> items = searchAll(); assertEquals(0, items.size()); } public void testMultiplePoints() { Item item1 = new Item(0, 0); mTree.add(item1); Item item2 = new Item(.1, .1); mTree.add(item2); Item item3 = new Item(.2, .2); mTree.add(item3); Collection<Item> items = searchAll(); assertEquals(3, items.size()); assertTrue(items.contains(item1)); assertTrue(items.contains(item2)); assertTrue(items.contains(item3)); mTree.remove(item1); mTree.remove(item2); mTree.remove(item3); assertEquals(0, searchAll().size()); } public void testSameLocationDifferentPoint() { mTree.add(new Item(0, 0)); mTree.add(new Item(0, 0)); assertEquals(2, searchAll().size()); } public void testClear() { mTree.add(new Item(.1, .1)); mTree.add(new Item(.2, .2)); mTree.add(new Item(.3, .3)); mTree.clear(); assertEquals(0, searchAll().size()); } public void testSearch() { for (int i = 0; i < 10000; i++) { mTree.add(new Item(i / 20000.0, i / 20000.0)); } assertEquals(10000, searchAll().size()); assertEquals(1, mTree.search(new Bounds((double) 0, 0.00001, (double) 0, 0.00001)).size()); assertEquals(0, mTree.search(new Bounds(.7, .8, .7, .8)).size()); } public void testFourPoints() { mTree.add(new Item(0.2, 0.2)); mTree.add(new Item(0.7, 0.2)); mTree.add(new Item(0.2, 0.7)); mTree.add(new Item(0.7, 0.7)); assertEquals(2, mTree.search(new Bounds(0.0, 0.5, 0.0, 1.0)).size()); } /** * Tests 30,000 items at the same point. * Timing results are averaged. */ public void testVeryDeepTree() { for (int i = 0; i < 30000; i++) { mTree.add(new Item(0, 0)); } assertEquals(30000, searchAll().size()); assertEquals(30000, mTree.search(new Bounds(0, .1, 0, .1)).size()); assertEquals(0, mTree.search(new Bounds(.1, 1, .1, 1)).size()); mTree.clear(); } /** * Tests 400,000 points relatively uniformly distributed across the space. * Timing results are averaged. */ public void testManyPoints() { for (double i = 0; i < 200; i++) { for (double j = 0; j < 2000; j++) { mTree.add(new Item(i / 200.0, j / 2000.0)); } } // searching bounds that are exact subtrees of the main quadTree assertEquals(400000, searchAll().size()); assertEquals(100000, mTree.search(new Bounds(0, .5, 0, .5)).size()); assertEquals(100000, mTree.search(new Bounds(.5, 1, 0, .5)).size()); assertEquals(25000, mTree.search(new Bounds(0, .25, 0, .25)).size()); assertEquals(25000, mTree.search(new Bounds(.75, 1, .75, 1)).size()); // searching bounds that do not line up with main quadTree assertEquals(399800, mTree.search(new Bounds(0, 0.999, 0, 0.999)).size()); assertEquals(4221, mTree.search(new Bounds(0.8, 0.9, 0.8, 0.9)).size()); assertEquals(4200, mTree.search(new Bounds(0, 1, 0, 0.01)).size()); assertEquals(16441, mTree.search(new Bounds(0.4, 0.6, 0.4, 0.6)).size()); // searching bounds that are small / have very exact end points assertEquals(1, mTree.search(new Bounds(0, .001, 0, .0001)).size()); assertEquals(26617, mTree.search(new Bounds(0.356, 0.574, 0.678, 0.987)).size()); assertEquals(44689, mTree.search(new Bounds(0.123, 0.456, 0.456, 0.789)).size()); assertEquals(4906, mTree.search(new Bounds(0.111, 0.222, 0.333, 0.444)).size()); mTree.clear(); assertEquals(0, searchAll().size()); } /** * Runs a test with 100,000 points. * Timing results are averaged. */ public void testRandomPoints() { Random random = new Random(); for (int i = 0; i < 100000; i++) { mTree.add(new Item(random.nextDouble(), random.nextDouble())); } searchAll(); mTree.search(new Bounds(0, 0.5, 0, 0.5)); mTree.search(new Bounds(0, 0.25, 0, 0.25)); mTree.search(new Bounds(0, 0.125, 0, 0.125)); mTree.search(new Bounds(0, 0.999, 0, 0.999)); mTree.search(new Bounds(0, 1, 0, 0.01)); mTree.search(new Bounds(0.4, 0.6, 0.4, 0.6)); mTree.search(new Bounds(0.356, 0.574, 0.678, 0.987)); mTree.search(new Bounds(0.123, 0.456, 0.456, 0.789)); mTree.search(new Bounds(0.111, 0.222, 0.333, 0.444)); mTree.clear(); } private Collection<Item> searchAll() { return mTree.search(new Bounds(0, 1, 0, 1)); } private static class Item implements PointQuadTree.Item { private final Point mPoint; private Item(double x, double y) { this.mPoint = new Point(x, y); } @Override public Point getPoint() { return mPoint; } } }