[BAEL-3485] - Java Range lookup problem (#8392)
* [BAEL-3485] - Java Range lookup problem * [BAEL-3485] - Java Range lookup problem * [BAEL-3485] - Java Range lookup problem
This commit is contained in:
parent
5e2b3271d1
commit
8fab22b6e7
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
public class Point {
|
||||
private float x;
|
||||
private float y;
|
||||
|
||||
public Point(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + x + " , " + y + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class QuadTree {
|
||||
private static final int MAX_POINTS = 3;
|
||||
private Region area;
|
||||
private List<Point> points = new ArrayList<>();
|
||||
private List<QuadTree> quadTrees = new ArrayList<>();
|
||||
private StringBuilder searchTraversePath;
|
||||
|
||||
public QuadTree(Region area) {
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
public boolean addPoint(Point point) {
|
||||
if (this.area.containsPoint(point)) {
|
||||
if (this.points.size() < MAX_POINTS) {
|
||||
this.points.add(point);
|
||||
return true;
|
||||
} else {
|
||||
if (this.quadTrees.size() == 0) {
|
||||
createQuadrants();
|
||||
}
|
||||
return addPointToOneQuadrant(point);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean addPointToOneQuadrant(Point point) {
|
||||
boolean isPointAdded;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
isPointAdded = this.quadTrees.get(i)
|
||||
.addPoint(point);
|
||||
if (isPointAdded)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createQuadrants() {
|
||||
Region region;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
region = this.area.getQuadrant(i);
|
||||
quadTrees.add(new QuadTree(region));
|
||||
}
|
||||
}
|
||||
|
||||
public List<Point> search(Region searchRegion, List<Point> matches, String depthIndicator) {
|
||||
searchTraversePath = new StringBuilder();
|
||||
if (matches == null) {
|
||||
matches = new ArrayList<Point>();
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Search Boundary =")
|
||||
.append(searchRegion)
|
||||
.append("\n");
|
||||
}
|
||||
if (!this.area.doesOverlap(searchRegion)) {
|
||||
return matches;
|
||||
} else {
|
||||
for (Point point : points) {
|
||||
if (searchRegion.containsPoint(point)) {
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Found match " + point)
|
||||
.append("\n");
|
||||
matches.add(point);
|
||||
}
|
||||
}
|
||||
if (this.quadTrees.size() > 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Q")
|
||||
.append(i)
|
||||
.append("-->")
|
||||
.append(quadTrees.get(i).area)
|
||||
.append("\n");
|
||||
quadTrees.get(i)
|
||||
.search(searchRegion, matches, depthIndicator + "\t");
|
||||
this.searchTraversePath.append(quadTrees.get(i)
|
||||
.printSearchTraversePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
public String printTree(String depthIndicator) {
|
||||
String str = "";
|
||||
if (depthIndicator == "") {
|
||||
str += "Root-->" + area.toString() + "\n";
|
||||
}
|
||||
|
||||
for (Point point : points) {
|
||||
str += depthIndicator + point.toString() + "\n";
|
||||
}
|
||||
for (int i = 0; i < quadTrees.size(); i++) {
|
||||
str += depthIndicator + "Q" + String.valueOf(i) + "-->" + quadTrees.get(i).area.toString() + "\n";
|
||||
str += quadTrees.get(i)
|
||||
.printTree(depthIndicator + "\t");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public String printSearchTraversePath() {
|
||||
return searchTraversePath.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
public class Region {
|
||||
private float x1;
|
||||
private float y1;
|
||||
private float x2;
|
||||
private float y2;
|
||||
|
||||
public Region(float x1, float y1, float x2, float y2) {
|
||||
if (x1 >= x2 || y1 >= y2)
|
||||
throw new IllegalArgumentException("(x1,y1) should be lesser than (x2,y2)");
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
public Region getQuadrant(int quadrantIndex) {
|
||||
float quadrantWidth = (this.x2 - this.x1) / 2;
|
||||
float quadrantHeight = (this.y2 - this.y1) / 2;
|
||||
|
||||
// 0=SW, 1=NW, 2=NE, 3=SE
|
||||
switch (quadrantIndex) {
|
||||
case 0:
|
||||
return new Region(x1, y1, x1 + quadrantWidth, y1 + quadrantHeight);
|
||||
case 1:
|
||||
return new Region(x1, y1 + quadrantHeight, x1 + quadrantWidth, y2);
|
||||
case 2:
|
||||
return new Region(x1 + quadrantWidth, y1 + quadrantHeight, x2, y2);
|
||||
case 3:
|
||||
return new Region(x1 + quadrantWidth, y1, x2, y1 + quadrantHeight);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean containsPoint(Point point) {
|
||||
// Consider left and top side to be inclusive for points on border
|
||||
return point.getX() >= this.x1
|
||||
&& point.getX() < this.x2
|
||||
&& point.getY() >= this.y1
|
||||
&& point.getY() < this.y2;
|
||||
}
|
||||
|
||||
public boolean doesOverlap(Region testRegion) {
|
||||
// Is test region completely to left of my region?
|
||||
if (testRegion.getX2() < this.getX1()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely to right of my region?
|
||||
if (testRegion.getX1() > this.getX2()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely above my region?
|
||||
if (testRegion.getY1() > this.getY2()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely below my region?
|
||||
if (testRegion.getY2() < this.getY1()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Region (x1=" + x1 + ", y1=" + y1 + "), (x2=" + x2 + ", y2=" + y2 + ")]";
|
||||
}
|
||||
|
||||
public float getX1() {
|
||||
return x1;
|
||||
}
|
||||
|
||||
public float getY1() {
|
||||
return y1;
|
||||
}
|
||||
|
||||
public float getX2() {
|
||||
return x2;
|
||||
}
|
||||
|
||||
public float getY2() {
|
||||
return y2;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class QuadTreeSearchUnitTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(QuadTreeSearchUnitTest.class);
|
||||
|
||||
private static QuadTree quadTree;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
Region area = new Region(0, 0, 400, 400);
|
||||
quadTree = new QuadTree(area);
|
||||
|
||||
float[][] points = new float[][] { { 21, 25 }, { 55, 53 }, { 70, 318 }, { 98, 302 },
|
||||
{ 49, 229 }, { 135, 229 }, { 224, 292 }, { 206, 321 }, { 197, 258 }, { 245, 238 } };
|
||||
|
||||
for (int i = 0; i < points.length; i++) {
|
||||
Point point = new Point(points[i][0], points[i][1]);
|
||||
quadTree.addPoint(point);
|
||||
}
|
||||
LOGGER.info("\n" + quadTree.printTree(""));
|
||||
LOGGER.info("==============================================");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenQuadTree_whenSearchingForRange_thenReturn1MatchingItem() {
|
||||
Region searchArea = new Region(200, 200, 250, 250);
|
||||
List<Point> result = quadTree.search(searchArea, null, "");
|
||||
LOGGER.info(result.toString());
|
||||
LOGGER.info(quadTree.printSearchTraversePath());
|
||||
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertArrayEquals(new float[] { 245, 238 },
|
||||
new float[]{result.get(0).getX(), result.get(0).getY() }, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenQuadTree_whenSearchingForRange_thenReturn2MatchingItems() {
|
||||
Region searchArea = new Region(0, 0, 100, 100);
|
||||
List<Point> result = quadTree.search(searchArea, null, "");
|
||||
LOGGER.info(result.toString());
|
||||
LOGGER.info(quadTree.printSearchTraversePath());
|
||||
|
||||
Assert.assertEquals(2, result.size());
|
||||
Assert.assertArrayEquals(new float[] { 21, 25 },
|
||||
new float[]{result.get(0).getX(), result.get(0).getY() }, 0);
|
||||
Assert.assertArrayEquals(new float[] { 55, 53 },
|
||||
new float[]{result.get(1).getX(), result.get(1).getY() }, 0);
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue