[BAEL-3485] - Java Range lookup problem
This commit is contained in:
		
							parent
							
								
									726d880d51
								
							
						
					
					
						commit
						bc463d59b4
					
				| @ -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 QuadTreeSearchTest { | ||||
|      | ||||
|     private static final Logger LOGGER = LoggerFactory.getLogger(QuadTreeSearchTest.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.debug("\n" + quadTree.printTree("")); | ||||
|         LOGGER.debug("=============================================="); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenQuadTree_whenSearchingForRange_thenReturn1MatchingItem() { | ||||
|         Region searchArea = new Region(200, 200, 250, 250); | ||||
|         List<Point> result = quadTree.search(searchArea, null, ""); | ||||
|         LOGGER.debug(result.toString()); | ||||
|         LOGGER.debug(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.debug(result.toString()); | ||||
|         LOGGER.debug(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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user