[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:
macroscopic64 2019-12-27 23:34:59 +05:30 committed by KevinGilmore
parent 5e2b3271d1
commit 8fab22b6e7
4 changed files with 278 additions and 0 deletions

View File

@ -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 + "]";
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}