[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