/** * @return A simple QuadTree with 6 entries for tests. */ private QuadTree<String> getTestTree() { QuadTree<String> qt = new QuadTree<>(-50.0, -50.0, +150.0, +150.0); qt.put(10.0, 10.0, "10.0, 10.0"); qt.put(15.0, 15.0, "15.0, 15.0"); qt.put(-15.0, 0.0, "-15.0, 0.0"); qt.put(20.0, 10.0, "20.0, 10.0"); qt.put(100.0, 0.0, "100.0, 0.0"); qt.put(15.0, 15.0, "15.0, 15.0 B"); return qt; }
@Test public void testGetXY_EntryOnDividingBorder() { QuadTree<String> qt = new QuadTree<>(0, 0, 40, 60); qt.put(10.0, 10.0, "10.0, 10.0"); qt.put(20.0, 20.0, "20.0, 20.0"); // on vertical border qt.put(20.0, 30.0, "20.0, 30.0"); // exactly on center qt.put(30.0, 30.0, "30.0, 30.0"); // on horizontal border assertEquals("20.0, 20.0", qt.getClosest(20.0, 20.0)); assertEquals("20.0, 30.0", qt.getClosest(20.0, 30.0)); assertEquals("30.0, 30.0", qt.getClosest(30.0, 30.0)); }
@Override double getMinX(double forY) { long factor = Math.round((forY - quadTree.getMinNorthing()) / getCentroidDistanceY()); if ((factor % 2) == 0) return quadTree.getMinEasting(); else return quadTree.getMinEasting() + horizontalCentroidDistance / 2; }
private void generateRow(final double y, final Supplier<T> initialValueSupplier, final Geometry bounds) { for (double x = getMinX(y); x <= quadTree.getMaxEasting(); x += getCentroidDistanceX()) { Coordinate coord = new Coordinate(x, y); if (bounds.contains(geometryFactory.createPoint(coord))) quadTree.put(x, y, new Cell<>(coord, initialValueSupplier.get())); } }
private Tuple<QuadTree<ActivityFacilityWithIndex>, ActivityFacilityImpl[]> getTuple(String activityType) { TreesBuilder treesBuilder = new TreesBuilder(CollectionUtils.stringToSet(activityType), this.scenario.getNetwork(), this.dccg); treesBuilder.setActTypeConverter(this.getConverter()); treesBuilder.createTrees(scenario.getActivityFacilities()); ActivityFacilityImpl[] facilities = treesBuilder.getFacilitiesOfType().get(activityType); /* * Create a copy of the treesBuilder.getQuadTreesOfType() outcome where the * ActivityFacility objects are replaced by ActivityFacilityWithIndex objects. * TODO: let the TreeBuilder use ActivityFacilityWithIndex objects directly? */ QuadTree<ActivityFacilityWithIndex> quadTree = null; QuadTree<ActivityFacility> qt = treesBuilder.getQuadTreesOfType().get(activityType); if (qt != null) { double minX = qt.getMinEasting(); double maxX = qt.getMaxEasting(); double minY = qt.getMinNorthing(); double maxY = qt.getMaxNorthing(); quadTree = new QuadTree<ActivityFacilityWithIndex>(minX, minY, maxX, maxY); for (ActivityFacility activityFacility : qt.values()) { quadTree.put(activityFacility.getCoord().getX(), activityFacility.getCoord().getY(), this.faciliesWithIndexMap.get(activityFacility.getId())); } } return new Tuple<QuadTree<ActivityFacilityWithIndex>, ActivityFacilityImpl[]>(quadTree, facilities); }
@Test public void testGetDistance_EntryOnOutsideBorder() { QuadTree<String> qt = new QuadTree<>(0.0, 0.0, 40.0, 60.0); // the 4 corners qt.put(0.0, 0.0, "SW"); qt.put(40.0, 0.0, "SE"); qt.put(0.0, 60.0, "NW"); qt.put(40.0, 60.0, "NE"); // the 4 sides qt.put(10.0, 60.0, "N"); qt.put(40.0, 10.0, "E"); qt.put(10.0, 0.0, "S"); qt.put(0.0, 10.0, "W"); assertContains(new String[] {"SW"}, qt.getDisk(3.0, 0.0, 3.0)); assertContains(new String[] {"SE"}, qt.getDisk(40.0, 3.0, 3.0)); assertContains(new String[] {"NW"}, qt.getDisk(3.0, 60.0, 3.0)); assertContains(new String[] {"NE"}, qt.getDisk(40.0, 57.0, 3.0)); assertContains(new String[] {"N"}, qt.getDisk(7.0, 60.0, 3.0)); assertContains(new String[] {"E"}, qt.getDisk(40.0, 13.0, 3.0)); assertContains(new String[] {"S"}, qt.getDisk(13.0, 0.0, 3.0)); assertContains(new String[] {"W"}, qt.getDisk(3.0, 10.0, 3.0)); }
/** * Test putting values into a QuadTree using {@link QuadTree#put(double, double, Object)}. */ @Test public void testPut() { QuadTree<String> qt = new QuadTree<>(-50.0, -50.0, +150.0, +150.0); assertEquals(0, qt.size()); qt.put(10.0, 10.0, "10.0, 10.0"); assertEquals(1, qt.size()); qt.put(15.0, 15.0, "15.0, 15.0"); assertEquals(2, qt.size()); qt.put(-15.0, 0.0, "-15.0, 0.0"); assertEquals(3, qt.size()); qt.put(20.0, 10.0, "20.0, 10.0"); assertEquals(4, qt.size()); qt.put(100.0, 0.0, "100.0, 0.0"); assertEquals(5, qt.size()); qt.put(15.0, 15.0, "15.0, 15.0"); // insert an object a second time, shouldn't be added assertEquals(5, qt.size()); qt.put(15.0, 15.0, "15.0, 15.0 B"); // insert a second object at an existing place assertEquals(6, qt.size()); }
if (Double.isInfinite(this.nodeQuadTree.getMinEasting())) { this.nodeQuadTree.clear(); this.nodeQuadTree = null; } else if (this.nodeQuadTree.getMinEasting() <= nn.getCoord().getX() && this.nodeQuadTree.getMaxEasting() > nn.getCoord().getX() && this.nodeQuadTree.getMinNorthing() <= nn.getCoord().getY() && this.nodeQuadTree.getMaxNorthing() > nn.getCoord().getY()) { this.nodeQuadTree.put(nn.getCoord().getX(), nn.getCoord().getY(), nn); } else { this.nodeQuadTree.clear(); this.nodeQuadTree = null;
@Test public void testGetRect() { QuadTree<String> qt = new QuadTree<>(0, 0, 1000, 1000); qt.put(100, 200, "node1"); qt.put(400, 900, "node2"); qt.put(700, 300, "node3"); qt.put(900, 400, "node4"); Collection<String> values = new ArrayList<>(); qt.getRectangle(new Rect(400, 300, 700, 900), values); Assert.assertEquals(2, values.size()); Assert.assertTrue(values.contains("node2")); Assert.assertTrue(values.contains("node3")); }
/** * retrieve cell for a given coordinate. Cell with closest centroid will be returne * * @param coordinate coordinate within a cell * @return Cell with closest centroid. */ public Cell<T> getCell(Coordinate coordinate) { return quadTree.getClosest(coordinate.x, coordinate.y); }
/** * Test {@link QuadTree#values()} that it returns the correct content. */ @Test public void testValues() { QuadTree<String> qt = getTestTree(); int size = qt.size(); assertEquals(6, size); // generic test valuesTester(qt.size(), qt.values()); // test that values() got updated after adding an object to the tree qt.put(80.0, 80.0, "80.0, 80.0"); assertEquals(size + 1, qt.size()); valuesTester(qt.size(), qt.values()); // test that values() got updated after removing an object to the tree assertTrue(qt.remove(80.0, 80.0, "80.0, 80.0")); assertEquals(size, qt.size()); valuesTester(qt.size(), qt.values()); // and remove one more... assertTrue(qt.remove(10.0, 10.0, "10.0, 10.0")); assertEquals(size - 1, qt.size()); valuesTester(qt.size(), qt.values()); // test the iterator Iterator<String> iter = qt.values().iterator(); iter.next(); try { iter.remove(); fail("expected UnsupportedOperationException, got none."); } catch (UnsupportedOperationException expected) {} }
/** * tests that also for a large number of entries, values() returns the correct result. */ @Test public void testGetValues() { double minX = -1000; double minY = -5000; double maxX = 20000; double maxY = 12000; Random r = new Random(20181017L); List<String> expected = new ArrayList<>(1000); QuadTree<String> qt = new QuadTree<>(minX, minY, maxX, maxY); for (int i = 0; i < 1000; i++) { double x = minX + r.nextDouble() * (maxX - minX); double y = minY + r.nextDouble() * (maxY - minY); String value = "ITEM_" + i; qt.put(x, y, value); expected.add(value); } List<String> items = new ArrayList<>(qt.values()); Assert.assertEquals(1000, items.size()); items.sort(String::compareTo); expected.sort(String::compareTo); for (int i = 0; i < 1000; i++) { Assert.assertEquals(expected.get(i), items.get(i)); } }
@Test public void testGetElliptical() { final Collection<Coord> all = new ArrayList<>(); QuadTree<Coord> qt = new QuadTree<>(0, 0, 40, 60); all.add(new Coord(10.0, 0.0)); all.add(new Coord(0.0, 10.0)); for ( Coord coord : all ) qt.put( coord.getX() , coord.getY() , coord ); qt.getElliptical( x1, y1, x2, y2,
QuadTree qt = new QuadTree(0, 0, 3, 3); qt.put(x, y, String.format("%s,%s", x, y)); Collection<String> result = qt.getRing(1, 1, 0, 1); assertEquals(result.contains("1,1"), true); assertEquals(result.contains("0,1"), true); result = qt.getRing(1, 1, 0.5, 1); assertEquals(result.contains("1,1"), false); assertEquals(result.contains("0,1"), true); result = qt.getRing(1, 1, 1.1, 1); assertEquals(result.size(), 0); result = qt.getRing(1, 1, 0, 0); assertEquals(result.size(), 1); assertEquals(result.contains("1,1"), true); result = qt.getRing(-1, 1, 1, 1.4); assertEquals(result.size(), 1); assertEquals(result.contains("0,1"), true); result = qt.getRing(-1, 1, 1, 1.5); assertEquals(result.size(), 3); assertEquals(result.contains("0,1"), true); result = qt.getRing(0, 0, Math.sqrt(18), Math.sqrt(18)); assertEquals(result.size(), 1);
assertEquals("10.0, 10.0", qt.getClosest(0.0, 0.0)); // test nearest assertEquals("-15.0, 0.0", qt.getClosest(-5.0, 0.0)); // test nearest assertEquals("20.0, 10.0", qt.getClosest(20.0, 10.0)); // test with exact coordinate String object = qt.getClosest(14.9, 14.9); assertTrue("15.0, 15.0".equals(object) || "15.0, 15.0 B".equals(object)); Collection<String> values = qt.getDisk(15.0, 15.0, 1.0); assertEquals(2, values.size()); assertTrue(values.contains("15.0, 15.0")); values = qt.getDisk(15.0, 15.0, 0.0); assertEquals(2, values.size()); assertTrue(values.contains("15.0, 15.0")); values = qt.getDisk(9.0, 9.0, 10.0); assertEquals(3, values.size()); assertTrue(values.contains("10.0, 10.0")); values = qt.getDisk(50.0, 0.0, 51.0); assertEquals(5, values.size()); assertTrue(values.contains("100.0, 0.0")); values = qt.getDisk(90.0, 0.0, 9.0); assertEquals("test with distance 9.0", 0, values.size()); values = qt.getDisk(90.0, 0.0, 9.999); assertEquals("test with distance 9.999", 0, values.size());
public void testRemove() { QuadTree<String> qt = getTestTree(); int size = qt.size(); assertTrue(qt.remove(10.0, 10.0, "10.0, 10.0")); assertEquals(size-1, qt.size()); assertFalse(qt.remove(10.0, 10.0, "10.0, 10.0")); assertEquals(size-1, qt.size()); assertFalse(qt.remove(14.9, 14.9, "15.0, 15.0")); assertEquals(size-1, qt.size()); assertTrue(qt.remove(15.0, 15.0, "15.0, 15.0")); assertEquals(size-2, qt.size()); assertEquals("15.0, 15.0 B", qt.getClosest(15.0, 15.0)); // the other object should still be there... assertTrue(qt.remove(15.0, 15.0, "15.0, 15.0 B")); assertEquals(size-1, qt.size()); assertEquals("15.0, 15.0", qt.getClosest(15.0, 15.0)); // the other object should still be there... assertFalse(qt.remove(10.0, 10.0, "10.0, 10.0 B")); assertEquals(size-1, qt.size());
@Test public void testValuesIterator_ConcurrentModification() { QuadTree<String> qt = getTestTree(); Iterator<String> iter = qt.values().iterator(); assertTrue(iter.hasNext()); assertNotNull(iter.next()); qt.put(39.0, 52.1, "39.0 52.1"); assertTrue(iter.hasNext()); // hasNext() should not yet provoke exception try { iter.next(); fail("missing exception."); } catch (ConcurrentModificationException e) { log.info("catched expected exception: ", e); } }
public void put( final Coord coord , final T element ) { elements.add( new Tuple< Coord , T >( coord , element ) ); if ( quadTree != null && inBounds( coord ) ) { quadTree.put( coord.getX() , coord.getY() , element ); } else { minX = Math.min( coord.getX() , minX ); minY = Math.min( coord.getY() , minY ); maxX = Math.max( coord.getX() , maxX ); maxY = Math.max( coord.getY() , maxY ); quadTree = null; } }
private void generateGrid(Supplier<T> initialValueSupplier, final Geometry bounds) { Envelope envelope = bounds.getEnvelopeInternal(); quadTree = new QuadTree<>(envelope.getMinX(), envelope.getMinY(), envelope.getMaxX(), envelope.getMaxY()); generateAllRows(initialValueSupplier, bounds); }